updated reference website link
[betaflight.git] / src / test / unit / telemetry_ibus_unittest.cc
blobb4340b73f39d32fbff1edc8b5de23eefbd692d87
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdint.h>
19 #include <string.h>
21 extern "C" {
22 #include "platform.h"
23 #include "common/utils.h"
24 #include "pg/pg.h"
25 #include "drivers/serial.h"
26 #include "io/serial.h"
27 #include "io/gps.h"
28 #include "flight/imu.h"
29 #include "config/config.h"
30 #include "fc/rc_controls.h"
31 #include "telemetry/telemetry.h"
32 #include "telemetry/ibus.h"
33 #include "sensors/gyro.h"
34 #include "sensors/battery.h"
35 #include "sensors/barometer.h"
36 #include "sensors/acceleration.h"
37 #include "scheduler/scheduler.h"
38 #include "fc/tasks.h"
41 #include "unittest_macros.h"
42 #include "gtest/gtest.h"
45 extern "C" {
46 uint8_t armingFlags = 0;
47 uint8_t stateFlags = 0;
48 uint16_t flightModeFlags = 0;
49 uint8_t testBatteryCellCount =3;
50 float rcCommand[4] = {0, 0, 0, 0};
51 telemetryConfig_t telemetryConfig_System;
52 batteryConfig_s batteryConfig_System;
53 attitudeEulerAngles_t attitude = EULER_INITIALIZE;
54 acc_t acc;
55 baro_t baro;
56 gpsSolutionData_t gpsSol;
57 uint16_t GPS_distanceToHome;
60 static int16_t gyroTemperature;
61 int16_t gyroGetTemperature(void) {
62 return gyroTemperature;
65 static uint16_t vbat = 1000;
66 uint16_t getVbat(void)
68 return vbat;
71 extern "C" {
72 static int32_t amperage = 100;
73 static int32_t estimatedVario = 0;
74 static uint8_t batteryRemaining = 0;
75 static throttleStatus_e throttleStatus = THROTTLE_HIGH;
76 static uint32_t definedFeatures = 0;
77 static uint32_t definedSensors = SENSOR_GYRO | SENSOR_ACC | SENSOR_MAG | SENSOR_SONAR | SENSOR_GPS | SENSOR_GPSMAG;
78 static uint16_t testBatteryVoltage = 1000;
80 int32_t getAmperage(void)
82 return amperage;
85 int32_t getEstimatedVario(void)
87 return estimatedVario;
90 uint8_t calculateBatteryPercentageRemaining(void)
92 return batteryRemaining;
95 uint16_t getBatteryAverageCellVoltage(void)
97 return testBatteryVoltage / testBatteryCellCount;
100 int32_t getMAhDrawn(void)
102 return 0;
105 throttleStatus_e calculateThrottleStatus(void)
107 return throttleStatus;
110 bool featureIsEnabled(uint32_t mask)
112 return (definedFeatures & mask) != 0;
115 bool sensors(sensors_e sensor)
117 return (definedSensors & sensor) != 0;
121 #define SERIAL_BUFFER_SIZE 256
123 typedef struct serialPortStub_s {
124 uint8_t buffer[SERIAL_BUFFER_SIZE];
125 int pos = 0;
126 int end = 0;
127 } serialPortStub_t;
130 uint16_t getBatteryVoltage(void)
132 return testBatteryVoltage;
135 uint8_t getBatteryCellCount(void) {
136 return testBatteryCellCount;
139 static serialPortStub_t serialWriteStub;
140 static serialPortStub_t serialReadStub;
142 #define SERIAL_PORT_DUMMY_IDENTIFIER (serialPortIdentifier_e)0x12
143 serialPort_t serialTestInstance;
144 serialPortConfig_t serialTestInstanceConfig = {
145 .identifier = SERIAL_PORT_DUMMY_IDENTIFIER,
146 .functionMask = 0
149 static serialPortConfig_t *findSerialPortConfig_stub_retval;
150 static portSharing_e determinePortSharing_stub_retval;
151 static bool portIsShared = false;
152 static bool openSerial_called = false;
153 static bool telemetryDetermineEnabledState_stub_retval;
155 void rescheduleTask(taskId_e taskId, timeDelta_t newPeriodUs)
157 EXPECT_EQ(TASK_TELEMETRY, taskId);
158 EXPECT_EQ(1000, newPeriodUs);
163 const serialPortConfig_t *findSerialPortConfig(serialPortFunction_e function)
165 EXPECT_EQ(FUNCTION_TELEMETRY_IBUS, function);
166 return findSerialPortConfig_stub_retval;
170 portSharing_e determinePortSharing(const serialPortConfig_t *portConfig, serialPortFunction_e function)
172 EXPECT_EQ(findSerialPortConfig_stub_retval, portConfig);
173 EXPECT_EQ(FUNCTION_TELEMETRY_IBUS, function);
174 return PORTSHARING_UNUSED;
178 bool telemetryDetermineEnabledState(portSharing_e portSharing)
180 (void) portSharing;
181 return telemetryDetermineEnabledState_stub_retval;
185 bool telemetryIsSensorEnabled(sensor_e sensor) {
186 UNUSED(sensor);
187 return true;
191 bool isSerialPortShared(const serialPortConfig_t *portConfig,
192 uint16_t functionMask,
193 serialPortFunction_e sharedWithFunction)
195 EXPECT_EQ(findSerialPortConfig_stub_retval, portConfig);
196 EXPECT_EQ(FUNCTION_RX_SERIAL, functionMask);
197 EXPECT_EQ(FUNCTION_TELEMETRY_IBUS, sharedWithFunction);
198 return portIsShared;
202 serialPortConfig_t *findSerialPortConfig(uint16_t mask)
204 EXPECT_EQ(FUNCTION_TELEMETRY_IBUS, mask);
205 return findSerialPortConfig_stub_retval ;
209 serialPort_t *openSerialPort(
210 serialPortIdentifier_e identifier,
211 serialPortFunction_e function,
212 serialReceiveCallbackPtr callback,
213 void *callbackData,
214 uint32_t baudrate,
215 portMode_e mode,
216 portOptions_e options
219 openSerial_called = true;
220 UNUSED(callback);
221 UNUSED(callbackData);
222 EXPECT_EQ(SERIAL_PORT_DUMMY_IDENTIFIER, identifier);
223 EXPECT_EQ(SERIAL_BIDIR, options);
224 EXPECT_EQ(FUNCTION_TELEMETRY_IBUS, function);
225 EXPECT_EQ(115200, baudrate);
226 EXPECT_EQ(MODE_RXTX, mode);
227 return &serialTestInstance;
230 void closeSerialPort(serialPort_t *serialPort)
232 EXPECT_EQ(&serialTestInstance, serialPort);
236 void serialWrite(serialPort_t *instance, uint8_t ch)
238 EXPECT_EQ(&serialTestInstance, instance);
239 EXPECT_LT(serialWriteStub.pos, sizeof(serialWriteStub.buffer));
240 serialWriteStub.buffer[serialWriteStub.pos++] = ch;
241 serialReadStub.buffer[serialReadStub.end++] = ch; //characters echoes back on the shared wire
242 //printf("w: %02d 0x%02x\n", serialWriteStub.pos, ch);
246 uint32_t serialRxBytesWaiting(const serialPort_t *instance)
248 EXPECT_EQ(&serialTestInstance, instance);
249 EXPECT_GE(serialReadStub.end, serialReadStub.pos);
250 int ret = serialReadStub.end - serialReadStub.pos;
251 if (ret < 0) {
252 ret = 0;
254 //printf("serialRxBytesWaiting: %d\n", ret);
255 return ret;
259 uint8_t serialRead(serialPort_t *instance)
261 EXPECT_EQ(&serialTestInstance, instance);
262 EXPECT_LT(serialReadStub.pos, serialReadStub.end);
263 const uint8_t ch = serialReadStub.buffer[serialReadStub.pos++];
264 return ch;
268 void serialTestResetBuffers()
270 memset(&serialReadStub, 0, sizeof(serialReadStub));
271 memset(&serialWriteStub, 0, sizeof(serialWriteStub));
274 void setTestSensors()
276 telemetryConfig_System.flysky_sensors[0] = 0x03;
277 telemetryConfig_System.flysky_sensors[1] = 0x01;
278 telemetryConfig_System.flysky_sensors[2] = 0x02;
279 telemetryConfig_System.flysky_sensors[3] = 0x00;
282 void serialTestResetPort()
284 portIsShared = false;
285 openSerial_called = false;
286 determinePortSharing_stub_retval = PORTSHARING_UNUSED;
287 telemetryDetermineEnabledState_stub_retval = true;
289 serialTestResetBuffers();
294 class IbusTelemteryInitUnitTest : public ::testing::Test
296 protected:
297 virtual void SetUp()
299 serialTestResetPort();
300 setTestSensors();
305 TEST_F(IbusTelemteryInitUnitTest, Test_IbusInitNotEnabled)
307 findSerialPortConfig_stub_retval = NULL;
308 telemetryDetermineEnabledState_stub_retval = false;
310 //given stuff in serial read
311 serialReadStub.end++;
313 //when initializing and polling ibus
314 initIbusTelemetry();
315 checkIbusTelemetryState();
316 handleIbusTelemetry();
318 //then nothing is read from serial port
319 EXPECT_NE(serialReadStub.pos, serialReadStub.end);
320 EXPECT_FALSE(openSerial_called);
324 TEST_F(IbusTelemteryInitUnitTest, Test_IbusInitEnabled)
326 findSerialPortConfig_stub_retval = &serialTestInstanceConfig;
328 //given stuff in serial read
329 serialReadStub.end++;
331 //when initializing and polling ibus
332 initIbusTelemetry();
333 checkIbusTelemetryState();
334 handleIbusTelemetry();
336 //then all is read from serial port
337 EXPECT_EQ(serialReadStub.end, serialReadStub.pos);
338 EXPECT_TRUE(openSerial_called);
342 TEST_F(IbusTelemteryInitUnitTest, Test_IbusInitSerialRxAndTelemetryEnabled)
344 findSerialPortConfig_stub_retval = &serialTestInstanceConfig;
346 //given stuff in serial read
347 serialReadStub.end++;
348 //and serial rx enabled too
349 portIsShared = true;
351 //when initializing and polling ibus
352 initIbusTelemetry();
353 checkIbusTelemetryState();
354 handleIbusTelemetry();
356 //then all is read from serial port
357 EXPECT_NE(serialReadStub.pos, serialReadStub.end);
358 EXPECT_FALSE(openSerial_called);
361 class IbusTelemetryProtocolUnitTestBase : public ::testing::Test
363 protected:
364 virtual void SetUp()
366 serialTestResetPort();
367 telemetryConfigMutable()->report_cell_voltage = false;
368 serialTestResetBuffers();
369 initIbusTelemetry();
370 checkIbusTelemetryState();
373 void checkResponseToCommand(const char *rx, uint8_t rxCnt, const char *expectedTx, uint8_t expectedTxCnt)
375 serialTestResetBuffers();
377 memcpy(serialReadStub.buffer, rx, rxCnt);
378 serialReadStub.end += rxCnt;
380 //when polling ibus
381 for (int i = 0; i<10; i++) {
382 handleIbusTelemetry();
385 EXPECT_EQ(expectedTxCnt, serialWriteStub.pos);
386 EXPECT_EQ(0, memcmp(serialWriteStub.buffer, expectedTx, expectedTxCnt));
389 void setupBaseAddressOne(void)
391 checkResponseToCommand("\x04\x81\x7a\xff", 4, "\x04\x81\x7a\xff", 4);
392 serialTestResetBuffers();
395 void setupBaseAddressThree(void)
397 checkResponseToCommand("\x04\x83\x78\xff", 4, "\x04\x83\x78\xff", 4);
398 serialTestResetBuffers();
404 class IbusTelemteryProtocolUnitTest : public ::IbusTelemetryProtocolUnitTestBase
406 protected:
407 virtual void SetUp()
409 IbusTelemetryProtocolUnitTestBase::SetUp();
410 setupBaseAddressOne();
415 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusNoRespondToDiscoveryCrcErr)
417 //Given ibus command: Hello sensor at address 1, are you there (with bad crc)?
418 //then we do not respond
419 checkResponseToCommand("\x04\x81\x00\x00", 4, NULL, 0);
423 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToDiscovery)
425 //Given ibus command: Hello sensor at address 1, are you there?
426 //then we respond with: Yes, i'm here, hello!
427 checkResponseToCommand("\x04\x81\x7a\xff", 4, "\x04\x81\x7A\xFF", 4);
431 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToSensorTypeQueryVbatt)
433 //Given ibus command: Sensor at address 1, what type are you?
434 //then we respond with: I'm a voltage sensor
435 checkResponseToCommand("\x04\x91\x6A\xFF", 4, "\x06\x91\x03\x02\x63\xFF", 6);
439 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToSensorTypeQueryTemperature)
441 //Given ibus command: Sensor at address 1, what type are you?
442 //then we respond with: I'm a thermometer
443 checkResponseToCommand("\x04\x92\x69\xFF", 4, "\x06\x92\x01\x02\x64\xFF", 6);
447 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToSensorTypeQueryRpm)
449 //Given ibus command: Sensor at address 3, what type are you?
450 //then we respond with: I'm a rpm sensor
451 checkResponseToCommand("\x04\x93\x68\xFF", 4, "\x06\x93\x02\x02\x62\xFF", 6);
455 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToGetMeasurementVbattZero)
457 //Given ibus command: Sensor at address 1, please send your measurement
458 //then we respond with: I'm reading 0 volts
459 testBatteryVoltage = 0;
460 checkResponseToCommand("\x04\xA1\x5a\xff", 4, "\x06\xA1\x00\x00\x58\xFF", 6);
463 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToGetMeasurementVbattCellVoltage)
465 telemetryConfigMutable()->report_cell_voltage = true;
467 //Given ibus command: Sensor at address 1, please send your measurement
468 //then we respond with: I'm reading 0.1 volts
469 testBatteryCellCount =3;
470 testBatteryVoltage = 300;
471 checkResponseToCommand("\x04\xA1\x5a\xff", 4, "\x06\xA1\x64\x00\xf4\xFe", 6);
473 //Given ibus command: Sensor at address 1, please send your measurement
474 //then we respond with: I'm reading 0.1 volts
475 testBatteryCellCount =1;
476 testBatteryVoltage = 100;
477 checkResponseToCommand("\x04\xA1\x5a\xff", 4, "\x06\xA1\x64\x00\xf4\xFe", 6);
480 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToGetMeasurementVbattPackVoltage)
482 telemetryConfigMutable()->report_cell_voltage = false;
484 //Given ibus command: Sensor at address 1, please send your measurement
485 //then we respond with: I'm reading 0.1 volts
486 testBatteryCellCount =3;
487 testBatteryVoltage = 100;
488 checkResponseToCommand("\x04\xA1\x5a\xff", 4, "\x06\xA1\x64\x00\xf4\xFe", 6);
490 //Given ibus command: Sensor at address 1, please send your measurement
491 //then we respond with: I'm reading 0.1 volts
492 testBatteryCellCount =1;
493 testBatteryVoltage = 100;
494 checkResponseToCommand("\x04\xA1\x5a\xff", 4, "\x06\xA1\x64\x00\xf4\xFe", 6);
498 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToGetMeasurementTemperature)
500 //Given ibus command: Sensor at address 2, please send your measurement
501 //then we respond
502 gyroTemperature = 50;
503 checkResponseToCommand("\x04\xA2\x59\xff", 4, "\x06\xA2\x84\x03\xd0\xfe", 6);
505 //Given ibus command: Sensor at address 2, please send your measurement
506 //then we respond
507 gyroTemperature = 59; //test integer rounding
508 checkResponseToCommand("\x04\xA2\x59\xff", 4, "\x06\xA2\xde\x03\x76\xfe", 6);
510 //Given ibus command: Sensor at address 2, please send your measurement
511 //then we respond
512 gyroTemperature = 150;
513 checkResponseToCommand("\x04\xA2\x59\xff", 4, "\x06\xA2\x6c\x07\xe4\xfe", 6);
517 TEST_F(IbusTelemteryProtocolUnitTest, Test_IbusRespondToGetMeasurementRpm)
519 //Given ibus command: Sensor at address 3, please send your measurement
520 //then we respond with: I'm reading 0 rpm
521 rcCommand[THROTTLE] = 0;
522 checkResponseToCommand("\x04\xA3\x58\xff", 4, "\x06\xA3\x00\x00\x56\xFF", 6);
524 //Given ibus command: Sensor at address 3, please send your measurement
525 //then we respond with: I'm reading 100 rpm
526 rcCommand[THROTTLE] = 100;
527 checkResponseToCommand("\x04\xA3\x58\xff", 4, "\x06\xA3\x64\x00\xf2\xFe", 6);
532 class IbusTelemteryProtocolUnitTestDaisyChained : public ::IbusTelemetryProtocolUnitTestBase
534 protected:
535 virtual void SetUp()
537 IbusTelemetryProtocolUnitTestBase::SetUp();
538 setupBaseAddressThree();
543 TEST_F(IbusTelemteryProtocolUnitTestDaisyChained, Test_IbusRespondToDiscoveryBaseAddressThree)
545 //Given ibus commands: Hello sensor at address 3, 4, 5 are you there?
546 //then we respond with: Yes, we're here, hello!
547 checkResponseToCommand("\x04\x83\x78\xff", 4, "\x04\x83\x78\xff", 4);
548 checkResponseToCommand("\x04\x84\x77\xff", 4, "\x04\x84\x77\xff", 4);
549 checkResponseToCommand("\x04\x85\x76\xff", 4, "\x04\x85\x76\xff", 4);
553 TEST_F(IbusTelemteryProtocolUnitTestDaisyChained, Test_IbusRespondToSensorTypeQueryWrongAddress)
555 //Given ibus commands: Sensor at address 1, 2, 6, what type are you?
556 //then we do not respond
557 checkResponseToCommand("\x04\x91\x6A\xFF", 4, "", 0);
558 checkResponseToCommand("\x04\x92\x69\xFF", 4, "", 0);
560 checkResponseToCommand("\x04\x96\x65\xFF", 4, "", 0);
564 TEST_F(IbusTelemteryProtocolUnitTestDaisyChained, Test_IbusRespondToSensorTypeQueryVbattBaseThree)
566 //Given ibus commands: Sensor at address 3, 4, 5, what type are you?
567 //then we respond with: I'm a voltage sensor
568 checkResponseToCommand("\x04\x93\x68\xFF", 4, "\x06\x93\x03\x02\x61\xFF", 6);
569 //then we respond with: I'm a thermometer
570 checkResponseToCommand("\x04\x94\x67\xFF", 4, "\x06\x94\x01\x02\x62\xFF", 6);
571 //then we respond with: I'm a rpm sensor
572 checkResponseToCommand("\x04\x95\x66\xFF", 4, "\x06\x95\x02\x02\x60\xFF", 6);
576 TEST_F(IbusTelemteryProtocolUnitTestDaisyChained, Test_IbusRespondToGetMeasurementsBaseThree)
578 //Given ibus command: Sensor at address 3, please send your measurement
579 //then we respond with: I'm reading 0.1 volts
580 testBatteryCellCount = 1;
581 testBatteryVoltage = 100;
582 checkResponseToCommand("\x04\xA3\x58\xff", 4, "\x06\xA3\x64\x00\xf2\xfe", 6);
584 //Given ibus command: Sensor at address 4, please send your measurement
585 //then we respond
586 gyroTemperature = 150;
587 checkResponseToCommand("\x04\xA4\x57\xff", 4, "\x06\xA4\x6c\x07\xe2\xfe", 6);
589 //Given ibus command: Sensor at address 5, please send your measurement
590 //then we respond with: I'm reading 100 rpm
591 rcCommand[THROTTLE] = 100;
592 checkResponseToCommand("\x04\xA5\x56\xff", 4, "\x06\xA5\x64\x00\xf0\xFe", 6);