SENT unit tests (#4769)
* unit_tests: sent: zero-init * sent: SENT_SLOW_CHANNELS_MAX to header * unit_tests: sent: clock, falling edges * SENT: support and autodetect if device sends pause pulse Also rework tick time calculation * unit_tests: SENT: verbose debug on request * unit_tests: SENT: actual checks * unit_tests: SENT: extract common code for reuse * unit_test: SENT: add test with fuel pressue captured data * unit_test: SENT: add test with Ford ETB CLOSED captured data
This commit is contained in:
parent
79ca66cf5c
commit
64be738874
|
@ -37,10 +37,6 @@
|
||||||
/* Decoder configuration */
|
/* Decoder configuration */
|
||||||
/*==========================================================================*/
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
/* Maximum slow shannel mailboxes, DO NOT CHANGE */
|
|
||||||
#define SENT_SLOW_CHANNELS_MAX 16
|
|
||||||
|
|
||||||
/*==========================================================================*/
|
/*==========================================================================*/
|
||||||
/* Decoder */
|
/* Decoder */
|
||||||
/*==========================================================================*/
|
/*==========================================================================*/
|
||||||
|
@ -62,7 +58,8 @@ void sent_channel::restart(void)
|
||||||
{
|
{
|
||||||
state = SENT_STATE_CALIB;
|
state = SENT_STATE_CALIB;
|
||||||
pulseCounter = 0;
|
pulseCounter = 0;
|
||||||
initStatePulseCounter = 0;
|
currentStatePulseCounter = 0;
|
||||||
|
hasPausePulse = false;
|
||||||
tickPerUnit = 0;
|
tickPerUnit = 0;
|
||||||
|
|
||||||
/* reset slow channels */
|
/* reset slow channels */
|
||||||
|
@ -83,22 +80,37 @@ void sent_channel::restart(void)
|
||||||
int sent_channel::Decoder(uint16_t clocks)
|
int sent_channel::Decoder(uint16_t clocks)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int interval;
|
||||||
|
|
||||||
pulseCounter++;
|
pulseCounter++;
|
||||||
|
|
||||||
/* special case - tick time calculation */
|
/* special case - tick time calculation */
|
||||||
if (state == SENT_STATE_CALIB) {
|
if (state == SENT_STATE_CALIB) {
|
||||||
/* Find longes pulse */
|
if (tickPerUnit == 0) {
|
||||||
if (clocks > tickPerUnit) {
|
/* no tickPerUnit calculated yet
|
||||||
tickPerUnit = clocks;
|
* lets assume this is sync pulse... */
|
||||||
}
|
tickPerUnit = (clocks + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) /
|
||||||
/* ...this should be SYNC pulse */
|
|
||||||
if (pulseCounter >= SENT_CALIBRATION_PULSES) {
|
|
||||||
/* calculate Unit time from SYNC pulse */
|
|
||||||
tickPerUnit = (tickPerUnit + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) /
|
|
||||||
(SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL);
|
(SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL);
|
||||||
pulseCounter = 0;
|
} else {
|
||||||
state = SENT_STATE_INIT;
|
/* some tickPerUnit calculated...
|
||||||
|
* Check next 1 + 6 + 1 pulses if they are valid with current tickPerUnit */
|
||||||
|
interval = (clocks + tickPerUnit / 2) / tickPerUnit - SENT_OFFSET_INTERVAL;
|
||||||
|
if ((interval >= 0) && (interval <= SENT_MAX_INTERVAL)) {
|
||||||
|
currentStatePulseCounter++;
|
||||||
|
if (currentStatePulseCounter == SENT_MSG_PAYLOAD_SIZE) {
|
||||||
|
pulseCounter = 0;
|
||||||
|
currentStatePulseCounter = 0;
|
||||||
|
state = SENT_STATE_INIT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentStatePulseCounter = 0;
|
||||||
|
tickPerUnit = (clocks + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) /
|
||||||
|
(SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pulseCounter >= SENT_CALIBRATION_PULSES) {
|
||||||
|
/* failed to calculate valid tickPerUnit, restart */
|
||||||
|
restart();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -110,16 +122,22 @@ int sent_channel::Decoder(uint16_t clocks)
|
||||||
|
|
||||||
if (((100 * clocks) >= (syncClocks * 80)) &&
|
if (((100 * clocks) >= (syncClocks * 80)) &&
|
||||||
((100 * clocks) <= (syncClocks * 120))) {
|
((100 * clocks) <= (syncClocks * 120))) {
|
||||||
initStatePulseCounter = 0;
|
|
||||||
/* adjust unit time */
|
/* adjust unit time */
|
||||||
tickPerUnit = (clocks + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) /
|
tickPerUnit = (clocks + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) /
|
||||||
(SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL);
|
(SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL);
|
||||||
|
/* we get here from calibration phase. calibration phase end with CRC nibble
|
||||||
|
* if we had to skip ONE pulse before we get sync - that means device sends pause
|
||||||
|
* pulses in between of messages */
|
||||||
|
if (currentStatePulseCounter == 1) {
|
||||||
|
hasPausePulse = true;
|
||||||
|
}
|
||||||
/* next state */
|
/* next state */
|
||||||
|
currentStatePulseCounter = 0;
|
||||||
state = SENT_STATE_STATUS;
|
state = SENT_STATE_STATUS;
|
||||||
} else {
|
} else {
|
||||||
initStatePulseCounter++;
|
currentStatePulseCounter++;
|
||||||
/* 3 frames skipped, no SYNC detected - recalibrate */
|
/* 3 frames skipped, no SYNC detected - recalibrate */
|
||||||
if (initStatePulseCounter >= (9 * 3)) {
|
if (currentStatePulseCounter >= (9 * 3)) {
|
||||||
restart();
|
restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +145,7 @@ int sent_channel::Decoder(uint16_t clocks)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int interval = (clocks + tickPerUnit / 2) / tickPerUnit - SENT_OFFSET_INTERVAL;
|
interval = (clocks + tickPerUnit / 2) / tickPerUnit - SENT_OFFSET_INTERVAL;
|
||||||
|
|
||||||
if (interval < 0) {
|
if (interval < 0) {
|
||||||
#if SENT_STATISTIC_COUNTERS
|
#if SENT_STATISTIC_COUNTERS
|
||||||
|
@ -213,7 +231,7 @@ int sent_channel::Decoder(uint16_t clocks)
|
||||||
#endif // SENT_STATISTIC_COUNTERS
|
#endif // SENT_STATISTIC_COUNTERS
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
state = SENT_STATE_SYNC;
|
state = hasPausePulse ? SENT_STATE_PAUSE : SENT_STATE_SYNC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -226,6 +244,9 @@ int sent_channel::Decoder(uint16_t clocks)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SENT_STATE_PAUSE:
|
||||||
|
state = SENT_STATE_SYNC;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
#define SENT_CHANNELS_NUM 4 // Number of sent channels
|
#define SENT_CHANNELS_NUM 4 // Number of sent channels
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Maximum slow shannel mailboxes, DO NOT CHANGE */
|
||||||
|
#define SENT_SLOW_CHANNELS_MAX 16
|
||||||
|
|
||||||
/* collect statistic */
|
/* collect statistic */
|
||||||
#define SENT_STATISTIC_COUNTERS 1
|
#define SENT_STATISTIC_COUNTERS 1
|
||||||
|
|
||||||
|
@ -24,6 +27,7 @@ typedef enum
|
||||||
SENT_STATE_SIG2_DATA2,
|
SENT_STATE_SIG2_DATA2,
|
||||||
SENT_STATE_SIG2_DATA3,
|
SENT_STATE_SIG2_DATA3,
|
||||||
SENT_STATE_CRC,
|
SENT_STATE_CRC,
|
||||||
|
SENT_STATE_PAUSE,
|
||||||
} SENT_STATE_enum;
|
} SENT_STATE_enum;
|
||||||
|
|
||||||
struct sent_channel_stat {
|
struct sent_channel_stat {
|
||||||
|
@ -42,8 +46,9 @@ private:
|
||||||
/* Unit interval in timer clocks - adjusted on SYNC */
|
/* Unit interval in timer clocks - adjusted on SYNC */
|
||||||
uint32_t tickPerUnit = 0;
|
uint32_t tickPerUnit = 0;
|
||||||
uint32_t pulseCounter = 0;
|
uint32_t pulseCounter = 0;
|
||||||
/* pulses skipped in init state while waiting for SYNC */
|
/* pulses skipped in init or calibration state while waiting for SYNC */
|
||||||
uint32_t initStatePulseCounter = 0;
|
uint32_t currentStatePulseCounter = 0;
|
||||||
|
bool hasPausePulse = false;
|
||||||
|
|
||||||
/* fast channel shift register*/
|
/* fast channel shift register*/
|
||||||
uint32_t rxReg;
|
uint32_t rxReg;
|
||||||
|
@ -70,7 +75,7 @@ public:
|
||||||
struct {
|
struct {
|
||||||
uint16_t data;
|
uint16_t data;
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
} scMsg[16];
|
} scMsg[SENT_SLOW_CHANNELS_MAX];
|
||||||
|
|
||||||
/* Statistic counters */
|
/* Statistic counters */
|
||||||
#if SENT_STATISTIC_COUNTERS
|
#if SENT_STATISTIC_COUNTERS
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -2,14 +2,13 @@
|
||||||
#include "logicdata_csv_reader.h"
|
#include "logicdata_csv_reader.h"
|
||||||
#include "sent_logic.h"
|
#include "sent_logic.h"
|
||||||
|
|
||||||
TEST(sent, testFordIdle) {
|
static int sentTest_feedWithFile(sent_channel &channel, const char *file)
|
||||||
|
{
|
||||||
|
int lineCount = 0;
|
||||||
|
int printDebug = 0;
|
||||||
CsvReader reader(1, 0);
|
CsvReader reader(1, 0);
|
||||||
|
|
||||||
reader.open("tests/sent/resources/ford-sent-idle.csv");
|
reader.open(file);
|
||||||
|
|
||||||
sent_channel channel;
|
|
||||||
|
|
||||||
int lineCount = 0;
|
|
||||||
|
|
||||||
double prevTimeStamp;
|
double prevTimeStamp;
|
||||||
|
|
||||||
|
@ -19,18 +18,89 @@ TEST(sent, testFordIdle) {
|
||||||
lineCount++;
|
lineCount++;
|
||||||
|
|
||||||
if (lineCount == 1) {
|
if (lineCount == 1) {
|
||||||
|
// get first timestamp
|
||||||
prevTimeStamp = stamp;
|
prevTimeStamp = stamp;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double diff = stamp - prevTimeStamp;
|
// we care only about falling edges
|
||||||
|
if (value < 0.5) {
|
||||||
|
double diff = stamp - prevTimeStamp;
|
||||||
|
|
||||||
// todo: proper mult
|
// On STM32 we are running timer on 1/4 of cpu clock. Cpu clock is 168 MHz
|
||||||
channel.Decoder(diff * 10'000'000);
|
channel.Decoder(diff * 168'000'000 / 4);
|
||||||
|
|
||||||
prevTimeStamp = stamp;
|
prevTimeStamp = stamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((lineCount % 100) == 0) && (printDebug)) {
|
||||||
|
int ret;
|
||||||
|
uint8_t stat;
|
||||||
|
uint16_t sig0, sig1;
|
||||||
|
|
||||||
|
ret = channel.GetSignals(&stat, &sig0, &sig1);
|
||||||
|
if (ret == 0) {
|
||||||
|
printf("SENT status 0x%01x, signals: 0x%03x, 0x%03x\n", stat, sig0, sig1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("testFordIdle: Got %d lines\n", lineCount);
|
printf("testFordIdle: Got %d lines\n", lineCount);
|
||||||
|
|
||||||
ASSERT_TRUE(lineCount > 100);
|
if (printDebug) {
|
||||||
|
uint8_t stat;
|
||||||
|
uint16_t sig0, sig1;
|
||||||
|
|
||||||
|
if (channel.GetSignals(&stat, &sig0, &sig1) == 0) {
|
||||||
|
printf("Last valid fast msg Status 0x%01x Sig0 0x%03x Sig1 0x%03x\n", stat, sig0, sig1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Slow channels:\n");
|
||||||
|
for (int i = 0; i < SENT_SLOW_CHANNELS_MAX; i++) {
|
||||||
|
//if (scMsgFlags & BIT(i)) {
|
||||||
|
printf(" ID %d: %d\n", channel.scMsg[i].id, channel.scMsg[i].data);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SENT_STATISTIC_COUNTERS
|
||||||
|
sent_channel_stat &statistic = channel.statistic;
|
||||||
|
printf("Restarts %d\n", statistic.RestartCnt);
|
||||||
|
printf("Interval errors %d short, %d long\n", statistic.ShortIntervalErr, statistic.LongIntervalErr);
|
||||||
|
printf("Total frames %d with CRC error %d (%f%%)\n", statistic.FrameCnt, statistic.CrcErrCnt, statistic.CrcErrCnt * 100.0 / statistic.FrameCnt);
|
||||||
|
printf("Sync errors %d\n", statistic.SyncErr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return lineCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(sent, testFordIdle) {
|
||||||
|
static sent_channel channel;
|
||||||
|
int lineCount = sentTest_feedWithFile(channel, "tests/sent/resources/ford-sent-idle.csv");
|
||||||
|
ASSERT_TRUE(lineCount > 100);
|
||||||
|
#if SENT_STATISTIC_COUNTERS
|
||||||
|
sent_channel_stat &statistic = channel.statistic;
|
||||||
|
ASSERT_TRUE(statistic.RestartCnt == 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sent, testFordClosed) {
|
||||||
|
static sent_channel channel;
|
||||||
|
int lineCount = sentTest_feedWithFile(channel, "tests/sent/resources/ford-sent-closed.csv");
|
||||||
|
ASSERT_TRUE(lineCount > 100);
|
||||||
|
#if SENT_STATISTIC_COUNTERS
|
||||||
|
sent_channel_stat &statistic = channel.statistic;
|
||||||
|
/* TODO: bad captured data or real problem? */
|
||||||
|
ASSERT_TRUE(statistic.RestartCnt <= 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sent, testFuelPressure) {
|
||||||
|
static sent_channel channel;
|
||||||
|
int lineCount = sentTest_feedWithFile(channel, "tests/sent/resources/SENT-fuel-pressure.csv");
|
||||||
|
ASSERT_TRUE(lineCount > 100);
|
||||||
|
#if SENT_STATISTIC_COUNTERS
|
||||||
|
sent_channel_stat &statistic = channel.statistic;
|
||||||
|
ASSERT_TRUE(statistic.RestartCnt == 0);
|
||||||
|
/* TODO: add more checks? Check data? */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue