283 lines
8.0 KiB
C++
283 lines
8.0 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* opentx - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "gtests.h"
|
|
#include "telemetry/telemetry.h"
|
|
|
|
#if defined(CROSSFIRE)
|
|
|
|
uint8_t createCrossfireChannelsFrame(uint8_t moduleIdx, uint8_t * frame, int16_t * pulses);
|
|
TEST(Crossfire, createCrossfireChannelsFrame)
|
|
{
|
|
int16_t pulsesStart[MAX_TRAINER_CHANNELS];
|
|
uint8_t crossfire[CROSSFIRE_FRAME_MAXLEN];
|
|
|
|
memset(crossfire, 0, sizeof(crossfire));
|
|
for (int i=0; i<MAX_TRAINER_CHANNELS; i++) {
|
|
pulsesStart[i] = -1024 + (2048 / MAX_TRAINER_CHANNELS) * i;
|
|
}
|
|
|
|
createCrossfireChannelsFrame(EXTERNAL_MODULE, crossfire, pulsesStart);
|
|
|
|
// TODO check
|
|
}
|
|
|
|
TEST(Crossfire, crc8)
|
|
{
|
|
uint8_t frame[] = { 0x00, 0x0C, 0x14, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x03, 0x00, 0x00, 0x00, 0xF4 };
|
|
uint8_t crc = crc8(&frame[2], frame[1]-1);
|
|
ASSERT_EQ(frame[frame[1]+1], crc);
|
|
}
|
|
|
|
#if defined(HARDWARE_EXTERNAL_MODULE)
|
|
#include "pulses/crossfire.h"
|
|
|
|
struct crsf_frame_test {
|
|
void* ctx = nullptr;
|
|
|
|
uint8_t buffer[TELEMETRY_RX_PACKET_SIZE];
|
|
uint8_t len = 0;
|
|
|
|
crsf_frame_test()
|
|
{
|
|
ctx = CrossfireDriver.init(EXTERNAL_MODULE);
|
|
if (!luaInputTelemetryFifo) {
|
|
luaInputTelemetryFifo =
|
|
new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
|
|
assert(luaInputTelemetryFifo != nullptr);
|
|
} else {
|
|
luaInputTelemetryFifo->clear();
|
|
}
|
|
}
|
|
|
|
template<unsigned Len>
|
|
void process(uint8_t (&frame)[Len]) {
|
|
CrossfireDriver.processFrame(ctx, frame, Len, buffer, &len);
|
|
}
|
|
|
|
~crsf_frame_test()
|
|
{
|
|
if (ctx != nullptr) {
|
|
CrossfireDriver.deinit(ctx);
|
|
}
|
|
}
|
|
};
|
|
|
|
static uint8_t incomplete_frame[] = {
|
|
// first frame
|
|
0xEA, 0x14, 0xFF, 0x11, 0xFD, 0x05, 0x00, 0x00, 0x13, 0x01, 0x01,
|
|
0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x5D, 0x98, 0xB4,
|
|
// second frame
|
|
0xEA, 0x21, 0xFF, 0x1E, 0xFD, 0x12, 0x00, 0x00, 0x14, 0x01, 0x01,
|
|
0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x8F, 0xC2, 0x35, 0x3F, 0xFD, 0xC7, 0xD1, 0x3C, 0x4C, 0x01, 0x92,
|
|
0x3F, 0x31,
|
|
// incomplete third frame
|
|
0xEA, 0x1F, 0xFF, 0x1C, 0xFD, 0x10, 0x00,
|
|
};
|
|
|
|
static uint8_t cont_frame[] = {
|
|
0x00, 0x15, 0x01, 0x01, 0x24, 0x00, 0x00, 0x35, 0x7D, 0xF2, 0x40,
|
|
0xE8, 0x03, 0xE8, 0x03, 0xDC, 0x05, 0xDC, 0x05, 0xE1, 0x05, 0xE1,
|
|
0x05, 0x2A, 0xFE, 0x5F,
|
|
//next trailing packet start
|
|
0xEA, 0x0A, 0x0B
|
|
};
|
|
|
|
TEST(Crossfire, frameParser_incompleteFrames)
|
|
{
|
|
crsf_frame_test ft;
|
|
if (!ft.ctx) return;
|
|
|
|
ft.process(incomplete_frame);
|
|
EXPECT_EQ(ft.len, 7);
|
|
EXPECT_EQ(ft.buffer[0], 0xEA);
|
|
EXPECT_EQ(ft.buffer[1], 0x1F);
|
|
|
|
ft.process(cont_frame);
|
|
EXPECT_EQ(ft.len, 3);
|
|
EXPECT_EQ(ft.buffer[0], 0xEA);
|
|
EXPECT_EQ(ft.buffer[1], 0x0A);
|
|
|
|
uint8_t* lua_buffer = luaInputTelemetryFifo->buffer();
|
|
EXPECT_EQ(luaInputTelemetryFifo->size(), 0x14 + 0x21 + 0x1F);
|
|
|
|
unsigned offset = 0;
|
|
EXPECT_EQ(lua_buffer[offset], 0x14);
|
|
offset += 0x14;
|
|
|
|
EXPECT_EQ(lua_buffer[offset], 0x21);
|
|
offset += 0x21;
|
|
|
|
EXPECT_EQ(lua_buffer[offset], 0x1F);
|
|
EXPECT_EQ(lua_buffer[offset + 0x1F - 1], 0xFE);
|
|
}
|
|
|
|
static uint8_t length_error[] = {
|
|
0x2A, 0xFE, 0x5F, 0x00,
|
|
};
|
|
|
|
static uint8_t length_error2[] = {
|
|
// first frame
|
|
0xEA, 0x09, 0xFF, 0x11, 0xFD, 0x05, 0x00, 0x00, 0x13, 0x01, 0x8C,
|
|
// 2nd incomplete frame
|
|
0xEA, 0xFE, 0x5F, 0x00,
|
|
};
|
|
|
|
static uint8_t length_error3[] = {
|
|
// first frame
|
|
0xEA, 0x09, 0xFF, 0x11, 0xFD, 0x05, 0x00, 0x00, 0x13, 0x01, 0x8C,
|
|
// invalid: invalid frame start
|
|
0x2A, 0x09, 0x5F, 0x00,
|
|
// 2nd valid frame
|
|
0xEA, 0x09, 0xFF, 0x11, 0xFD, 0x05, 0x00, 0x00, 0x13, 0x01, 0x8C,
|
|
};
|
|
|
|
|
|
TEST(Crossfire, frameParser_length)
|
|
{
|
|
crsf_frame_test ft;
|
|
if (!ft.ctx) return;
|
|
|
|
uint8_t* lua_buffer = luaInputTelemetryFifo->buffer();
|
|
|
|
// Check that a frame that is too big is rejected even if incomplete
|
|
ft.process(length_error);
|
|
EXPECT_EQ(ft.len, 0);
|
|
|
|
// Check that a frame that is too big is rejected if positioned
|
|
// after a complete frame
|
|
ft.process(length_error2);
|
|
EXPECT_EQ(ft.len, 0);
|
|
|
|
// the first complete frame should have been processed
|
|
EXPECT_EQ(luaInputTelemetryFifo->size(), 0x09);
|
|
|
|
ft.process(length_error3);
|
|
EXPECT_EQ(ft.len, 0);
|
|
|
|
// only the first frame has been processed, as the rest
|
|
// of the input buffer is thrown away due to length error
|
|
EXPECT_EQ(luaInputTelemetryFifo->size(), 0x09 + 0x09 + 0x09);
|
|
|
|
// check all 3 frames
|
|
unsigned offset = 0;
|
|
for (int i = 0; i < 3; i++) {
|
|
EXPECT_EQ(lua_buffer[offset], 0x09);
|
|
EXPECT_EQ(lua_buffer[offset + 0x09 - 1], 0x01);
|
|
offset += 0x09;
|
|
}
|
|
}
|
|
|
|
static uint8_t invalid_frames[] = {
|
|
// first frame
|
|
0xEA, 0x14, 0xFF, 0x11, 0xFD, 0x05, 0x00, 0x00, 0x13, 0x01, 0x01,
|
|
0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x5D, 0x98, 0xB4,
|
|
// random bytes
|
|
0x00, 0x35, 0xA4,
|
|
// second frame
|
|
0xEA, 0x21, 0xFF, 0x1E, 0xFD, 0x12, 0x00, 0x00, 0x14, 0x01, 0x01,
|
|
0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x8F, 0xC2, 0x35, 0x3F, 0xFD, 0xC7, 0xD1, 0x3C, 0x4C, 0x01, 0x92,
|
|
0x3F, 0x31,
|
|
// invalid CRC frame
|
|
0xEA, 0x02, 0x00, 0x01,
|
|
// third frame
|
|
0xEA, 0x1F, 0xFF, 0x1C, 0xFD, 0x10, 0x00,0x00, 0x15, 0x01, 0x01, 0x24, 0x00, 0x00, 0x35, 0x7D, 0xF2, 0x40,
|
|
0xE8, 0x03, 0xE8, 0x03, 0xDC, 0x05, 0xDC, 0x05, 0xE1, 0x05, 0xE1,
|
|
0x05, 0x2A, 0xFE, 0x5F,
|
|
};
|
|
|
|
TEST(Crossfire, frameParser_badFrames)
|
|
{
|
|
//check if frameParser correctly skips bad frames (too long, bad CRC) and does't lose following packets
|
|
crsf_frame_test ft;
|
|
if (!ft.ctx) return;
|
|
|
|
ft.process(invalid_frames);
|
|
EXPECT_EQ(ft.len,0);
|
|
|
|
uint8_t* lua_buffer = luaInputTelemetryFifo->buffer();
|
|
EXPECT_EQ(luaInputTelemetryFifo->size(), 0x14 + 0x21 + 0x1F);
|
|
|
|
unsigned offset = 0;
|
|
EXPECT_EQ(lua_buffer[offset], 0x14);
|
|
offset += 0x14;
|
|
|
|
EXPECT_EQ(lua_buffer[offset], 0x21);
|
|
offset += 0x21;
|
|
|
|
EXPECT_EQ(lua_buffer[offset], 0x1F);
|
|
EXPECT_EQ(lua_buffer[offset + 0x1F - 1], 0xFE);
|
|
}
|
|
|
|
static uint8_t jumboFrame1[]={
|
|
0xEA, 0x3E, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB
|
|
};
|
|
static uint8_t jumboFrame2[]={ //jumbo frame 2
|
|
0x8D, 0xEA, 0x3D, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x57
|
|
};
|
|
|
|
TEST(Crossfire, frameParser_multipleJumboFrames)
|
|
{
|
|
crsf_frame_test ft;
|
|
if (!ft.ctx) return;
|
|
|
|
ft.process(jumboFrame1);
|
|
EXPECT_EQ(ft.len, 63);
|
|
EXPECT_EQ(ft.buffer[0], 0xEA);
|
|
EXPECT_EQ(ft.buffer[1], 0x3E);
|
|
|
|
ft.process(jumboFrame2);
|
|
EXPECT_EQ(ft.len,0);
|
|
|
|
uint8_t* lua_buffer = luaInputTelemetryFifo->buffer();
|
|
EXPECT_EQ(luaInputTelemetryFifo->size(), 62 + 61);
|
|
|
|
unsigned offset = 0;
|
|
EXPECT_EQ(lua_buffer[offset], 0x3E);
|
|
EXPECT_EQ(lua_buffer[offset + 0x3E - 1], 0xFB);
|
|
|
|
EXPECT_EQ(lua_buffer[offset], 0x3E);
|
|
offset += 0x3E;
|
|
|
|
EXPECT_EQ(lua_buffer[offset], 0x3D);
|
|
EXPECT_EQ(lua_buffer[offset + 0x3D - 1], 0xF0);
|
|
}
|
|
#endif // HARDWARE_EXTERNAL_MODULE
|
|
#endif
|
|
|