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:
Andrey G 2022-11-12 01:25:02 +03:00 committed by GitHub
parent 79ca66cf5c
commit 64be738874
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61403 additions and 34 deletions

View File

@ -37,10 +37,6 @@
/* Decoder configuration */
/*==========================================================================*/
/* Maximum slow shannel mailboxes, DO NOT CHANGE */
#define SENT_SLOW_CHANNELS_MAX 16
/*==========================================================================*/
/* Decoder */
/*==========================================================================*/
@ -62,7 +58,8 @@ void sent_channel::restart(void)
{
state = SENT_STATE_CALIB;
pulseCounter = 0;
initStatePulseCounter = 0;
currentStatePulseCounter = 0;
hasPausePulse = false;
tickPerUnit = 0;
/* reset slow channels */
@ -83,22 +80,37 @@ void sent_channel::restart(void)
int sent_channel::Decoder(uint16_t clocks)
{
int ret = 0;
int interval;
pulseCounter++;
/* special case - tick time calculation */
if (state == SENT_STATE_CALIB) {
/* Find longes pulse */
if (clocks > tickPerUnit) {
tickPerUnit = clocks;
}
/* ...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) /
if (tickPerUnit == 0) {
/* no tickPerUnit calculated yet
* lets assume this is sync pulse... */
tickPerUnit = (clocks + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) /
(SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL);
pulseCounter = 0;
state = SENT_STATE_INIT;
} else {
/* 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;
}
@ -110,16 +122,22 @@ int sent_channel::Decoder(uint16_t clocks)
if (((100 * clocks) >= (syncClocks * 80)) &&
((100 * clocks) <= (syncClocks * 120))) {
initStatePulseCounter = 0;
/* adjust unit time */
tickPerUnit = (clocks + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) /
(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 */
currentStatePulseCounter = 0;
state = SENT_STATE_STATUS;
} else {
initStatePulseCounter++;
currentStatePulseCounter++;
/* 3 frames skipped, no SYNC detected - recalibrate */
if (initStatePulseCounter >= (9 * 3)) {
if (currentStatePulseCounter >= (9 * 3)) {
restart();
}
}
@ -127,7 +145,7 @@ int sent_channel::Decoder(uint16_t clocks)
return 0;
}
int interval = (clocks + tickPerUnit / 2) / tickPerUnit - SENT_OFFSET_INTERVAL;
interval = (clocks + tickPerUnit / 2) / tickPerUnit - SENT_OFFSET_INTERVAL;
if (interval < 0) {
#if SENT_STATISTIC_COUNTERS
@ -213,7 +231,7 @@ int sent_channel::Decoder(uint16_t clocks)
#endif // SENT_STATISTIC_COUNTERS
ret = -1;
}
state = SENT_STATE_SYNC;
state = hasPausePulse ? SENT_STATE_PAUSE : SENT_STATE_SYNC;
}
}
else
@ -226,6 +244,9 @@ int sent_channel::Decoder(uint16_t clocks)
ret = -1;
}
break;
case SENT_STATE_PAUSE:
state = SENT_STATE_SYNC;
break;
}
if (ret > 0) {

View File

@ -8,6 +8,9 @@
#define SENT_CHANNELS_NUM 4 // Number of sent channels
#endif
/* Maximum slow shannel mailboxes, DO NOT CHANGE */
#define SENT_SLOW_CHANNELS_MAX 16
/* collect statistic */
#define SENT_STATISTIC_COUNTERS 1
@ -24,6 +27,7 @@ typedef enum
SENT_STATE_SIG2_DATA2,
SENT_STATE_SIG2_DATA3,
SENT_STATE_CRC,
SENT_STATE_PAUSE,
} SENT_STATE_enum;
struct sent_channel_stat {
@ -42,8 +46,9 @@ private:
/* Unit interval in timer clocks - adjusted on SYNC */
uint32_t tickPerUnit = 0;
uint32_t pulseCounter = 0;
/* pulses skipped in init state while waiting for SYNC */
uint32_t initStatePulseCounter = 0;
/* pulses skipped in init or calibration state while waiting for SYNC */
uint32_t currentStatePulseCounter = 0;
bool hasPausePulse = false;
/* fast channel shift register*/
uint32_t rxReg;
@ -70,7 +75,7 @@ public:
struct {
uint16_t data;
uint8_t id;
} scMsg[16];
} scMsg[SENT_SLOW_CHANNELS_MAX];
/* 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

View File

@ -2,14 +2,13 @@
#include "logicdata_csv_reader.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);
reader.open("tests/sent/resources/ford-sent-idle.csv");
sent_channel channel;
int lineCount = 0;
reader.open(file);
double prevTimeStamp;
@ -19,18 +18,89 @@ TEST(sent, testFordIdle) {
lineCount++;
if (lineCount == 1) {
// get first timestamp
prevTimeStamp = stamp;
continue;
}
double diff = stamp - prevTimeStamp;
// we care only about falling edges
if (value < 0.5) {
double diff = stamp - prevTimeStamp;
// todo: proper mult
channel.Decoder(diff * 10'000'000);
// On STM32 we are running timer on 1/4 of cpu clock. Cpu clock is 168 MHz
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);
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
}