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/>.
23 #include "common/utils.h"
25 #include "drivers/serial.h"
26 #include "io/serial.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"
41 #include "unittest_macros.h"
42 #include "gtest/gtest.h"
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
;
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)
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)
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)
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
];
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
,
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
)
181 return telemetryDetermineEnabledState_stub_retval
;
185 bool telemetryIsSensorEnabled(sensor_e sensor
) {
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
);
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
,
216 portOptions_e options
219 openSerial_called
= true;
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
;
254 //printf("serialRxBytesWaiting: %d\n", 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
++];
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
299 serialTestResetPort();
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
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
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
351 //when initializing and polling ibus
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
366 serialTestResetPort();
367 telemetryConfigMutable()->report_cell_voltage
= false;
368 serialTestResetBuffers();
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
;
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
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
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
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
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
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
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);