From 3b8c5bbeb152b9a47e0b673632f8244f8e3927fb Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Sat, 5 Mar 2016 15:44:42 +0100 Subject: [PATCH] Code formatting --- radio/src/tests/crossfire.cpp | 30 +- radio/src/tests/eeprom.cpp | 312 +++-- radio/src/tests/frsky.cpp | 1036 +++++++++-------- radio/src/tests/gtests.cpp | 122 +- radio/src/tests/gtests.h | 26 +- radio/src/tests/lcd.cpp | 938 ++++++++------- radio/src/tests/lua.cpp | 352 +++--- radio/src/tests/mixer.cpp | 2038 ++++++++++++++++----------------- radio/src/tests/switches.cpp | 30 +- radio/src/tests/timers.cpp | 494 ++++---- 10 files changed, 2627 insertions(+), 2751 deletions(-) diff --git a/radio/src/tests/crossfire.cpp b/radio/src/tests/crossfire.cpp index 8862c0683..cc7f69e14 100644 --- a/radio/src/tests/crossfire.cpp +++ b/radio/src/tests/crossfire.cpp @@ -1,27 +1,12 @@ /* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer + * Copyright (C) OpenTX * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * Based on code named + * 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 @@ -31,7 +16,6 @@ * 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 "gtests.h" diff --git a/radio/src/tests/eeprom.cpp b/radio/src/tests/eeprom.cpp index 1ad3bddbe..6e7f806bf 100644 --- a/radio/src/tests/eeprom.cpp +++ b/radio/src/tests/eeprom.cpp @@ -1,164 +1,148 @@ -/* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer - * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ - * - * 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 "gtests.h" - -#if !defined(PCBSKY9X) -TEST(Eeprom, 100_random_writes) -{ - eepromFile = NULL; // in memory - RlcFile f; - uint8_t buf[1000]; - uint8_t buf2[1000]; - - storageFormat(); - - for(int i=0; i<100; i++) { - int size = rand()%800; - for(int j=0; j - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer - * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ - * - * 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 "gtests.h" - -void frskyDProcessPacket(uint8_t *packet); - -#if defined(FRSKY_SPORT) -bool checkSportPacket(uint8_t *packet); -void processSportPacket(uint8_t *packet); -bool checkSportPacket(uint8_t *packet); -void frskyCalculateCellStats(void); -void displayVoltagesScreen(); -#endif - -#if defined(FRSKY) && !defined(CPUARM) -TEST(FrSky, gpsNfuel) -{ - g_model.frsky.usrProto = 1; - frskyData.hub.gpsFix = 1; - - uint8_t pkt1[] = { 0xfd, 0x07, 0x00, 0x5e, 0x14, 0x2c, 0x00, 0x5e, 0x1c, 0x03 }; - uint8_t pkt2[] = { 0xfd, 0x07, 0x00, 0x00, 0x5e, 0x13, 0x38, 0x0c, 0x5e, 0x1b }; - uint8_t pkt3[] = { 0xfd, 0x07, 0x00, 0xc9, 0x06, 0x5e, 0x23, 0x4e, 0x00, 0x5e }; - uint8_t pkt4[] = { 0xfd, 0x07, 0x00, 0x12, 0xef, 0x2e, 0x5e, 0x1a, 0x98, 0x26 }; - uint8_t pkt5[] = { 0xfd, 0x07, 0x00, 0x5e, 0x22, 0x45, 0x00, 0x5e, 0x11, 0x02 }; - uint8_t pkt6[] = { 0xfd, 0x07, 0x00, 0x00, 0x5e, 0x19, 0x93, 0x00, 0x5e, 0x04 }; - uint8_t pkt7[] = { 0xfd, 0x03, 0x00, 0x64, 0x00, 0x5e }; - frskyDProcessPacket(pkt1); - frskyDProcessPacket(pkt2); - frskyDProcessPacket(pkt3); - frskyDProcessPacket(pkt4); - frskyDProcessPacket(pkt5); - frskyDProcessPacket(pkt6); - frskyDProcessPacket(pkt7); - EXPECT_EQ(frskyData.hub.gpsCourse_bp, 44); - EXPECT_EQ(frskyData.hub.gpsCourse_ap, 03); - EXPECT_EQ(frskyData.hub.gpsLongitude_bp / 100, 120); - EXPECT_EQ(frskyData.hub.gpsLongitude_bp % 100, 15); - EXPECT_EQ(frskyData.hub.gpsLongitude_ap, 0x2698); - EXPECT_EQ(frskyData.hub.gpsLatitudeNS, 'N'); - EXPECT_EQ(frskyData.hub.gpsLongitudeEW, 'E'); - EXPECT_EQ(frskyData.hub.fuelLevel, 100); -} - -TEST(FrSky, dateNtime) -{ - uint8_t pkt1[] = { 0xfd, 0x07, 0x00, 0x5e, 0x15, 0x0f, 0x07, 0x5e, 0x16, 0x0b }; - uint8_t pkt2[] = { 0xfd, 0x07, 0x00, 0x00, 0x5e, 0x17, 0x06, 0x12, 0x5e, 0x18 }; - uint8_t pkt3[] = { 0xfd, 0x03, 0x00, 0x32, 0x00, 0x5e }; - frskyDProcessPacket(pkt1); - frskyDProcessPacket(pkt2); - frskyDProcessPacket(pkt3); - EXPECT_EQ(frskyData.hub.day, 15); - EXPECT_EQ(frskyData.hub.month, 07); - EXPECT_EQ(frskyData.hub.year, 11); - EXPECT_EQ(frskyData.hub.hour, 06); - EXPECT_EQ(frskyData.hub.min, 18); - EXPECT_EQ(frskyData.hub.sec, 50); -} -#endif - -#if defined(FRSKY) && defined(CPUARM) -TEST(FrSky, FrskyValueWithMinAveraging) -{ - /* - The following expected[] array is filled - with values that correspond to 4 elements - long averaging buffer. - If length of averaging buffer is changed, this - values must be adjusted - */ - uint8_t expected[] = { 10, 12, 17, 25, 35, 45, 55, 65, 75, 85, 92, 97, 100, 100, 100, 100, 100}; - int testPos = 0; - //test of averaging - FrskyValueWithMin testVal; - testVal.value = 0; - testVal.set(10); - EXPECT_EQ(RAW_FRSKY_MINMAX(testVal), 10); - EXPECT_EQ(testVal.value, expected[testPos++]); - for(int n=2; n<10; ++n) { - testVal.set(n*10); - EXPECT_EQ(RAW_FRSKY_MINMAX(testVal), n*10); - EXPECT_EQ(testVal.value, expected[testPos++]); - } - for(int n=2; n<10; ++n) { - testVal.set(100); - EXPECT_EQ(RAW_FRSKY_MINMAX(testVal), 100); - EXPECT_EQ(testVal.value, expected[testPos++]); - } -} - -TEST(FrSky, Vfas_0x39_HiPrecision) -{ - MODEL_RESET(); - TELEMETRY_RESET(); - EXPECT_EQ(telemetryItems[0].value, 0); - - allowNewSensors = true; - - // normal precision, resolution 0.1V - processHubPacket(VFAS_ID, 1234); // set value of 123.4V - EXPECT_EQ(telemetryItems[0].value, 12340); // stored value has resolution of 0.01V - - // now high precision, resolution 0.01V - processHubPacket(VFAS_ID, VFAS_D_HIPREC_OFFSET); // set value of 0V - EXPECT_EQ(telemetryItems[0].value, 0); - processHubPacket(VFAS_ID, VFAS_D_HIPREC_OFFSET + 12345); // set value of 123.45V - EXPECT_EQ(telemetryItems[0].value, 12345); - processHubPacket(VFAS_ID, VFAS_D_HIPREC_OFFSET + 30012); // set value of 300.12V - EXPECT_EQ(telemetryItems[0].value, 30012); -} - -TEST(FrSky, HubAltNegative) -{ - MODEL_RESET(); - TELEMETRY_RESET(); - EXPECT_EQ(telemetryItems[0].value, 0); - - allowNewSensors = true; - - // altimeter auto offset - processHubPacket(BARO_ALT_BP_ID, 0); - processHubPacket(BARO_ALT_AP_ID, 0); - EXPECT_EQ(telemetryItems[0].value, 0); - - // low precision altimeter, bp always less than 10 - processHubPacket(BARO_ALT_BP_ID, 12); // set value of 12.3m - processHubPacket(BARO_ALT_AP_ID, 3); - EXPECT_EQ(telemetryItems[0].value, 123); // altitude stored has resolution of 0.1m - - processHubPacket(BARO_ALT_BP_ID, -12); // set value of -12.3m - processHubPacket(BARO_ALT_AP_ID, 3); - EXPECT_EQ(telemetryItems[0].value, -123); - - // hi precision altimeter, bp can be two decimals - MODEL_RESET(); - TELEMETRY_RESET(); - - // altimeter auto offset - processHubPacket(BARO_ALT_BP_ID, 0); - processHubPacket(BARO_ALT_AP_ID, 0); - EXPECT_EQ(telemetryItems[0].value, 0); - - // first trigger hi precision, by setting AP above 9 - processHubPacket(BARO_ALT_BP_ID, -1); // set value of -1.35m - processHubPacket(BARO_ALT_AP_ID, 35); - EXPECT_EQ(telemetryItems[0].value, -13); - - processHubPacket(BARO_ALT_BP_ID, 12); // set value of 12.35m - processHubPacket(BARO_ALT_AP_ID, 35); - EXPECT_EQ(telemetryItems[0].value, 123); - - // now test with the AP less than 10 to check if hiprecision is still active - processHubPacket(BARO_ALT_BP_ID, 12); // set value of 12.05m - processHubPacket(BARO_ALT_AP_ID, 05); - EXPECT_EQ(telemetryItems[0].value, 120); -} -#endif // #if defined(FRSKY) && defined(CPUARM) - -#if defined(FRSKY_SPORT) -TEST(FrSkySPORT, checkCrc) -{ - // uint8_t pkt[] = { 0x7E, 0x98, 0x10, 0x10, 0x00, 0x7D, 0x5E, 0x02, 0x00, 0x00, 0x5F }; - uint8_t pkt[] = { 0x7E, 0x98, 0x10, 0x10, 0x00, 0x7E, 0x02, 0x00, 0x00, 0x5F }; - EXPECT_EQ(checkSportPacket(pkt+1), true); -} - -void setSportPacketCrc(uint8_t * packet) -{ - short crc = 0; - for (int i=1; i> 8; //0-100 - crc &= 0x00ff; - crc += crc >> 8; //0-0FF - crc &= 0x00ff; - } - packet[FRSKY_SPORT_PACKET_SIZE-1] = 0xFF - (crc & 0x00ff); - //TRACE("crc set: %x", packet[FRSKY_SPORT_PACKET_SIZE-1]); -} - -void generateSportCellPacket(uint8_t * packet, uint8_t cells, uint8_t battnumber, uint16_t cell1, uint16_t cell2, uint8_t sensorId=DATA_ID_FLVSS) -{ - packet[0] = sensorId; - packet[1] = 0x10; //DATA_FRAME - *((uint16_t *)(packet+2)) = 0x0300; //CELLS_FIRST_ID - uint32_t data = 0; - data += (cells << 4) + battnumber; - data += ((cell1 * 5) & 0xFFF) << 8; - data += ((cell2 * 5) & 0xFFF) << 20; - *((int32_t *)(packet+4)) = data; - setSportPacketCrc(packet); -} - -#define _V(volts) (volts/TELEMETRY_CELL_VOLTAGE_MUTLIPLIER) - -TEST(FrSkySPORT, FrSkyDCells) -{ - MODEL_RESET(); - TELEMETRY_RESET(); - uint8_t pkt1[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x12 }; - EXPECT_EQ(checkSportPacket(pkt1+1), true); - processSportPacket(pkt1+1); - uint8_t pkt2[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x17, 0xD0, 0x00, 0x00, 0x02 }; - EXPECT_EQ(checkSportPacket(pkt2+1), true); - processSportPacket(pkt2+1); - uint8_t pkt3[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x27, 0xD0, 0x00, 0x00, 0xF1 }; - EXPECT_EQ(checkSportPacket(pkt3+1), true); - processSportPacket(pkt3+1); - processSportPacket(pkt1+1); - processSportPacket(pkt2+1); - processSportPacket(pkt3+1); - EXPECT_EQ(telemetryItems[0].cells.count, 3); - EXPECT_EQ(telemetryItems[0].value, 1200); - for (int i=0; i<3; i++) { - EXPECT_EQ(telemetryItems[0].cells.values[i].state, 1); - EXPECT_EQ(telemetryItems[0].cells.values[i].value, 400); - } -} - -TEST(FrSkySPORT, frskySetCellVoltage) -{ - uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; - - MODEL_RESET(); - TELEMETRY_RESET(); - - // test that simulates 3 cell battery - generateSportCellPacket(packet, 3, 0, _V(410), _V(420)); processSportPacket(packet); - EXPECT_EQ(checkSportPacket(packet), true) << "Bad CRC generation in setSportPacketCrc()"; - generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); - - generateSportCellPacket(packet, 3, 0, _V(405), _V(300)); processSportPacket(packet); - generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); - - EXPECT_EQ(telemetryItems[0].cells.count, 3); - EXPECT_EQ(telemetryItems[0].cells.values[0].value, 405); - EXPECT_EQ(telemetryItems[0].cells.values[1].value, 300); - EXPECT_EQ(telemetryItems[0].cells.values[2].value, 430); - EXPECT_EQ(telemetryItems[0].cells.values[4].value, 0); - EXPECT_EQ(telemetryItems[0].value, 1135); - EXPECT_EQ(telemetryItems[0].valueMin, 1135); - EXPECT_EQ(telemetryItems[0].valueMax, 1260); - - generateSportCellPacket(packet, 3, 0, _V(405), _V(250)); processSportPacket(packet); - generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); - - generateSportCellPacket(packet, 3, 0, _V(410), _V(420)); processSportPacket(packet); - generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); - - EXPECT_EQ(telemetryItems[0].cells.count, 3); - EXPECT_EQ(telemetryItems[0].cells.values[0].value, 410); - EXPECT_EQ(telemetryItems[0].cells.values[1].value, 420); - EXPECT_EQ(telemetryItems[0].cells.values[2].value, 430); - EXPECT_EQ(telemetryItems[0].cells.values[4].value, 0); - EXPECT_EQ(telemetryItems[0].value, 1260); - EXPECT_EQ(telemetryItems[0].valueMin, 1085); - EXPECT_EQ(telemetryItems[0].valueMax, 1260); - - //add another two cells - 5 cell battery - generateSportCellPacket(packet, 5, 0, _V(418), _V(408)); processSportPacket(packet); - generateSportCellPacket(packet, 5, 2, _V(415), _V(420)); processSportPacket(packet); - generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); - - EXPECT_EQ(telemetryItems[0].cells.count, 5); - EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); - EXPECT_EQ(telemetryItems[0].cells.values[1].value, 408); - EXPECT_EQ(telemetryItems[0].cells.values[2].value, 415); - EXPECT_EQ(telemetryItems[0].cells.values[3].value, 420); - EXPECT_EQ(telemetryItems[0].cells.values[4].value, 410); - EXPECT_EQ(telemetryItems[0].cells.values[5].value, 0); - EXPECT_EQ(telemetryItems[0].value, 2071); - EXPECT_EQ(telemetryItems[0].valueMin, 2071); - EXPECT_EQ(telemetryItems[0].valueMax, 2071); - - //simulate very low voltage for cell 3 - generateSportCellPacket(packet, 5, 0, _V(418), _V(408)); processSportPacket(packet); - generateSportCellPacket(packet, 5, 2, _V(100), _V(420)); processSportPacket(packet); - generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); - - EXPECT_EQ(telemetryItems[0].cells.count, 5); - EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); - EXPECT_EQ(telemetryItems[0].cells.values[1].value, 408); - EXPECT_EQ(telemetryItems[0].cells.values[2].value, 100); - EXPECT_EQ(telemetryItems[0].cells.values[3].value, 420); - EXPECT_EQ(telemetryItems[0].cells.values[4].value, 410); - EXPECT_EQ(telemetryItems[0].cells.values[5].value, 0); - EXPECT_EQ(telemetryItems[0].value, 1756); - EXPECT_EQ(telemetryItems[0].valueMin, 1756); - EXPECT_EQ(telemetryItems[0].valueMax, 2071); - - //back to normal (but with reversed order of packets) - generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); - generateSportCellPacket(packet, 5, 0, _V(418), _V(408)); processSportPacket(packet); - generateSportCellPacket(packet, 5, 2, _V(412), _V(420)); processSportPacket(packet); - generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); - - EXPECT_EQ(telemetryItems[0].cells.count, 5); - EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); - EXPECT_EQ(telemetryItems[0].cells.values[1].value, 408); - EXPECT_EQ(telemetryItems[0].cells.values[2].value, 412); - EXPECT_EQ(telemetryItems[0].cells.values[3].value, 420); - EXPECT_EQ(telemetryItems[0].cells.values[4].value, 410); - EXPECT_EQ(telemetryItems[0].cells.values[5].value, 0); - EXPECT_EQ(telemetryItems[0].value, 2068); - EXPECT_EQ(telemetryItems[0].valueMin, 1756); - EXPECT_EQ(telemetryItems[0].valueMax, 2071); - - //display test - lcdClear(); - g_model.frsky.voltsSource = FRSKY_VOLTS_SOURCE_A1; -} - -TEST(FrSkySPORT, StrangeCellsBug) -{ - MODEL_RESET(); - TELEMETRY_RESET(); - - uint8_t pkt[] = { 0x7E, 0x48, 0x10, 0x00, 0x03, 0x30, 0x15, 0x50, 0x81, 0xD5 }; - EXPECT_EQ(checkSportPacket(pkt+1), true); - processSportPacket(pkt+1); - EXPECT_EQ(telemetryItems[0].cells.count, 3); - EXPECT_EQ(telemetryItems[0].cells.values[0].value, 0); // now we ignore such low values - EXPECT_EQ(telemetryItems[0].cells.values[1].value, 413); -} - -TEST(FrSkySPORT, frskySetCellVoltageTwoSensors) -{ - uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; - - MODEL_RESET(); - TELEMETRY_RESET(); - - //sensor 1: 3 cell battery - generateSportCellPacket(packet, 3, 0, _V(418), _V(416)); processSportPacket(packet); - generateSportCellPacket(packet, 3, 2, _V(415), _V( 0)); processSportPacket(packet); - - EXPECT_EQ(telemetryItems[0].cells.count, 3); - EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); - EXPECT_EQ(telemetryItems[0].cells.values[1].value, 416); - EXPECT_EQ(telemetryItems[0].cells.values[2].value, 415); - EXPECT_EQ(telemetryItems[0].cells.values[3].value, 0); - EXPECT_EQ(telemetryItems[0].value, 1249); - EXPECT_EQ(telemetryItems[0].valueMin, 1249); - EXPECT_EQ(telemetryItems[0].valueMax, 1249); - - //sensor 2: 4 cell battery - generateSportCellPacket(packet, 4, 0, _V(410), _V(420), DATA_ID_FLVSS+1); processSportPacket(packet); - generateSportCellPacket(packet, 4, 2, _V(400), _V(405), DATA_ID_FLVSS+1); processSportPacket(packet); - - EXPECT_EQ(telemetryItems[1].cells.count, 4); - EXPECT_EQ(telemetryItems[1].cells.values[0].value, 410); - EXPECT_EQ(telemetryItems[1].cells.values[1].value, 420); - EXPECT_EQ(telemetryItems[1].cells.values[2].value, 400); - EXPECT_EQ(telemetryItems[1].cells.values[3].value, 405); - EXPECT_EQ(telemetryItems[1].value, 1635); - EXPECT_EQ(telemetryItems[1].valueMin, 1635); - EXPECT_EQ(telemetryItems[1].valueMax, 1635); - - g_model.telemetrySensors[2].type = TELEM_TYPE_CALCULATED; - g_model.telemetrySensors[2].formula = TELEM_FORMULA_ADD; - g_model.telemetrySensors[2].prec = 1; - g_model.telemetrySensors[2].calc.sources[0] = 1; - g_model.telemetrySensors[2].calc.sources[1] = 2; - - telemetryWakeup(); - - EXPECT_EQ(telemetryItems[2].value, 287); - EXPECT_EQ(telemetryItems[2].valueMin, 287); - EXPECT_EQ(telemetryItems[2].valueMax, 287); - - //now change some voltages - generateSportCellPacket(packet, 3, 2, _V(415), _V( 0)); processSportPacket(packet); - generateSportCellPacket(packet, 4, 2, _V(390), _V(370), DATA_ID_FLVSS+1); processSportPacket(packet); - generateSportCellPacket(packet, 3, 0, _V(420), _V(410)); processSportPacket(packet); - generateSportCellPacket(packet, 4, 0, _V(410), _V(420), DATA_ID_FLVSS+1); processSportPacket(packet); - - telemetryWakeup(); - - EXPECT_EQ(telemetryItems[2].value, 283); - EXPECT_EQ(telemetryItems[2].valueMin, 283); - EXPECT_EQ(telemetryItems[2].valueMax, 287); - - //display test - lcdClear(); - g_model.frsky.voltsSource = FRSKY_VOLTS_SOURCE_A1; -} - -void generateSportFasVoltagePacket(uint8_t * packet, uint32_t voltage) -{ - packet[0] = 0x22; //DATA_ID_FAS - packet[1] = 0x10; //DATA_FRAME - *((uint16_t *)(packet+2)) = 0x0210; //VFAS_FIRST_ID - *((int32_t *)(packet+4)) = voltage; // unit 10mV - setSportPacketCrc(packet); -} - -TEST(FrSkySPORT, frskyVfas) -{ - uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; - - MODEL_RESET(); - TELEMETRY_RESET(); - - // tests for Vfas - generateSportFasVoltagePacket(packet, 5000); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 5000); - EXPECT_EQ(telemetryItems[0].valueMin, 5000); - EXPECT_EQ(telemetryItems[0].valueMax, 5000); - - generateSportFasVoltagePacket(packet, 6524); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 6524); - EXPECT_EQ(telemetryItems[0].valueMin, 6524); // the batt was changed (val > old max) - EXPECT_EQ(telemetryItems[0].valueMax, 6524); - - generateSportFasVoltagePacket(packet, 1248); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 1248); - EXPECT_EQ(telemetryItems[0].valueMin, 1248); - EXPECT_EQ(telemetryItems[0].valueMax, 6524); - - generateSportFasVoltagePacket(packet, 2248); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 2248); - EXPECT_EQ(telemetryItems[0].valueMin, 1248); - EXPECT_EQ(telemetryItems[0].valueMax, 6524); -} - -void generateSportFasCurrentPacket(uint8_t * packet, uint32_t current) -{ - packet[0] = 0x22; //DATA_ID_FAS - packet[1] = 0x10; //DATA_FRAME - *((uint16_t *)(packet+2)) = 0x0200; //CURR_FIRST_ID - *((int32_t *)(packet+4)) = current; - setSportPacketCrc(packet); -} - -TEST(FrSkySPORT, frskyCurrent) -{ - uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; - - MODEL_RESET(); - TELEMETRY_RESET(); - - // tests for Curr - generateSportFasCurrentPacket(packet, 0); processSportPacket(packet); - g_model.telemetrySensors[0].custom.offset = -5; /* unit: 1/10 amps */ - generateSportFasCurrentPacket(packet, 0); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 0); - EXPECT_EQ(telemetryItems[0].valueMin, 0); - EXPECT_EQ(telemetryItems[0].valueMax, 0); - - // measured current less then offset - value should be zero - generateSportFasCurrentPacket(packet, 4); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 0); - EXPECT_EQ(telemetryItems[0].valueMin, 0); - EXPECT_EQ(telemetryItems[0].valueMax, 0); - - generateSportFasCurrentPacket(packet, 10); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 5); - EXPECT_EQ(telemetryItems[0].valueMin, 0); - EXPECT_EQ(telemetryItems[0].valueMax, 5); - - generateSportFasCurrentPacket(packet, 500); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 495); - EXPECT_EQ(telemetryItems[0].valueMin, 0); - EXPECT_EQ(telemetryItems[0].valueMax, 495); - - generateSportFasCurrentPacket(packet, 200); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 195); - EXPECT_EQ(telemetryItems[0].valueMin, 0); - EXPECT_EQ(telemetryItems[0].valueMax, 495); - - // test with positive offset - TELEMETRY_RESET(); - g_model.telemetrySensors[0].custom.offset = +5; /* unit: 1/10 amps */ - - generateSportFasCurrentPacket(packet, 0); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 5); - EXPECT_EQ(telemetryItems[0].valueMin, 5); - EXPECT_EQ(telemetryItems[0].valueMax, 5); - - generateSportFasCurrentPacket(packet, 500); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 505); - EXPECT_EQ(telemetryItems[0].valueMin, 5); - EXPECT_EQ(telemetryItems[0].valueMax, 505); - - generateSportFasCurrentPacket(packet, 200); processSportPacket(packet); - EXPECT_EQ(telemetryItems[0].value, 205); - EXPECT_EQ(telemetryItems[0].valueMin, 5); - EXPECT_EQ(telemetryItems[0].valueMax, 505); -} - -#endif //#if defined(FRSKY_SPORT) +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "gtests.h" + +void frskyDProcessPacket(uint8_t *packet); + +#if defined(FRSKY_SPORT) +bool checkSportPacket(uint8_t *packet); +void processSportPacket(uint8_t *packet); +bool checkSportPacket(uint8_t *packet); +void frskyCalculateCellStats(void); +void displayVoltagesScreen(); +#endif + +#if defined(FRSKY) && !defined(CPUARM) +TEST(FrSky, gpsNfuel) +{ + g_model.frsky.usrProto = 1; + frskyData.hub.gpsFix = 1; + + uint8_t pkt1[] = { 0xfd, 0x07, 0x00, 0x5e, 0x14, 0x2c, 0x00, 0x5e, 0x1c, 0x03 }; + uint8_t pkt2[] = { 0xfd, 0x07, 0x00, 0x00, 0x5e, 0x13, 0x38, 0x0c, 0x5e, 0x1b }; + uint8_t pkt3[] = { 0xfd, 0x07, 0x00, 0xc9, 0x06, 0x5e, 0x23, 0x4e, 0x00, 0x5e }; + uint8_t pkt4[] = { 0xfd, 0x07, 0x00, 0x12, 0xef, 0x2e, 0x5e, 0x1a, 0x98, 0x26 }; + uint8_t pkt5[] = { 0xfd, 0x07, 0x00, 0x5e, 0x22, 0x45, 0x00, 0x5e, 0x11, 0x02 }; + uint8_t pkt6[] = { 0xfd, 0x07, 0x00, 0x00, 0x5e, 0x19, 0x93, 0x00, 0x5e, 0x04 }; + uint8_t pkt7[] = { 0xfd, 0x03, 0x00, 0x64, 0x00, 0x5e }; + frskyDProcessPacket(pkt1); + frskyDProcessPacket(pkt2); + frskyDProcessPacket(pkt3); + frskyDProcessPacket(pkt4); + frskyDProcessPacket(pkt5); + frskyDProcessPacket(pkt6); + frskyDProcessPacket(pkt7); + EXPECT_EQ(frskyData.hub.gpsCourse_bp, 44); + EXPECT_EQ(frskyData.hub.gpsCourse_ap, 03); + EXPECT_EQ(frskyData.hub.gpsLongitude_bp / 100, 120); + EXPECT_EQ(frskyData.hub.gpsLongitude_bp % 100, 15); + EXPECT_EQ(frskyData.hub.gpsLongitude_ap, 0x2698); + EXPECT_EQ(frskyData.hub.gpsLatitudeNS, 'N'); + EXPECT_EQ(frskyData.hub.gpsLongitudeEW, 'E'); + EXPECT_EQ(frskyData.hub.fuelLevel, 100); +} + +TEST(FrSky, dateNtime) +{ + uint8_t pkt1[] = { 0xfd, 0x07, 0x00, 0x5e, 0x15, 0x0f, 0x07, 0x5e, 0x16, 0x0b }; + uint8_t pkt2[] = { 0xfd, 0x07, 0x00, 0x00, 0x5e, 0x17, 0x06, 0x12, 0x5e, 0x18 }; + uint8_t pkt3[] = { 0xfd, 0x03, 0x00, 0x32, 0x00, 0x5e }; + frskyDProcessPacket(pkt1); + frskyDProcessPacket(pkt2); + frskyDProcessPacket(pkt3); + EXPECT_EQ(frskyData.hub.day, 15); + EXPECT_EQ(frskyData.hub.month, 07); + EXPECT_EQ(frskyData.hub.year, 11); + EXPECT_EQ(frskyData.hub.hour, 06); + EXPECT_EQ(frskyData.hub.min, 18); + EXPECT_EQ(frskyData.hub.sec, 50); +} +#endif + +#if defined(FRSKY) && defined(CPUARM) +TEST(FrSky, FrskyValueWithMinAveraging) +{ + /* + The following expected[] array is filled + with values that correspond to 4 elements + long averaging buffer. + If length of averaging buffer is changed, this + values must be adjusted + */ + uint8_t expected[] = { 10, 12, 17, 25, 35, 45, 55, 65, 75, 85, 92, 97, 100, 100, 100, 100, 100}; + int testPos = 0; + //test of averaging + FrskyValueWithMin testVal; + testVal.value = 0; + testVal.set(10); + EXPECT_EQ(RAW_FRSKY_MINMAX(testVal), 10); + EXPECT_EQ(testVal.value, expected[testPos++]); + for(int n=2; n<10; ++n) { + testVal.set(n*10); + EXPECT_EQ(RAW_FRSKY_MINMAX(testVal), n*10); + EXPECT_EQ(testVal.value, expected[testPos++]); + } + for(int n=2; n<10; ++n) { + testVal.set(100); + EXPECT_EQ(RAW_FRSKY_MINMAX(testVal), 100); + EXPECT_EQ(testVal.value, expected[testPos++]); + } +} + +TEST(FrSky, Vfas_0x39_HiPrecision) +{ + MODEL_RESET(); + TELEMETRY_RESET(); + EXPECT_EQ(telemetryItems[0].value, 0); + + allowNewSensors = true; + + // normal precision, resolution 0.1V + processHubPacket(VFAS_ID, 1234); // set value of 123.4V + EXPECT_EQ(telemetryItems[0].value, 12340); // stored value has resolution of 0.01V + + // now high precision, resolution 0.01V + processHubPacket(VFAS_ID, VFAS_D_HIPREC_OFFSET); // set value of 0V + EXPECT_EQ(telemetryItems[0].value, 0); + processHubPacket(VFAS_ID, VFAS_D_HIPREC_OFFSET + 12345); // set value of 123.45V + EXPECT_EQ(telemetryItems[0].value, 12345); + processHubPacket(VFAS_ID, VFAS_D_HIPREC_OFFSET + 30012); // set value of 300.12V + EXPECT_EQ(telemetryItems[0].value, 30012); +} + +TEST(FrSky, HubAltNegative) +{ + MODEL_RESET(); + TELEMETRY_RESET(); + EXPECT_EQ(telemetryItems[0].value, 0); + + allowNewSensors = true; + + // altimeter auto offset + processHubPacket(BARO_ALT_BP_ID, 0); + processHubPacket(BARO_ALT_AP_ID, 0); + EXPECT_EQ(telemetryItems[0].value, 0); + + // low precision altimeter, bp always less than 10 + processHubPacket(BARO_ALT_BP_ID, 12); // set value of 12.3m + processHubPacket(BARO_ALT_AP_ID, 3); + EXPECT_EQ(telemetryItems[0].value, 123); // altitude stored has resolution of 0.1m + + processHubPacket(BARO_ALT_BP_ID, -12); // set value of -12.3m + processHubPacket(BARO_ALT_AP_ID, 3); + EXPECT_EQ(telemetryItems[0].value, -123); + + // hi precision altimeter, bp can be two decimals + MODEL_RESET(); + TELEMETRY_RESET(); + + // altimeter auto offset + processHubPacket(BARO_ALT_BP_ID, 0); + processHubPacket(BARO_ALT_AP_ID, 0); + EXPECT_EQ(telemetryItems[0].value, 0); + + // first trigger hi precision, by setting AP above 9 + processHubPacket(BARO_ALT_BP_ID, -1); // set value of -1.35m + processHubPacket(BARO_ALT_AP_ID, 35); + EXPECT_EQ(telemetryItems[0].value, -13); + + processHubPacket(BARO_ALT_BP_ID, 12); // set value of 12.35m + processHubPacket(BARO_ALT_AP_ID, 35); + EXPECT_EQ(telemetryItems[0].value, 123); + + // now test with the AP less than 10 to check if hiprecision is still active + processHubPacket(BARO_ALT_BP_ID, 12); // set value of 12.05m + processHubPacket(BARO_ALT_AP_ID, 05); + EXPECT_EQ(telemetryItems[0].value, 120); +} +#endif // #if defined(FRSKY) && defined(CPUARM) + +#if defined(FRSKY_SPORT) +TEST(FrSkySPORT, checkCrc) +{ + // uint8_t pkt[] = { 0x7E, 0x98, 0x10, 0x10, 0x00, 0x7D, 0x5E, 0x02, 0x00, 0x00, 0x5F }; + uint8_t pkt[] = { 0x7E, 0x98, 0x10, 0x10, 0x00, 0x7E, 0x02, 0x00, 0x00, 0x5F }; + EXPECT_EQ(checkSportPacket(pkt+1), true); +} + +void setSportPacketCrc(uint8_t * packet) +{ + short crc = 0; + for (int i=1; i> 8; //0-100 + crc &= 0x00ff; + crc += crc >> 8; //0-0FF + crc &= 0x00ff; + } + packet[FRSKY_SPORT_PACKET_SIZE-1] = 0xFF - (crc & 0x00ff); + //TRACE("crc set: %x", packet[FRSKY_SPORT_PACKET_SIZE-1]); +} + +void generateSportCellPacket(uint8_t * packet, uint8_t cells, uint8_t battnumber, uint16_t cell1, uint16_t cell2, uint8_t sensorId=DATA_ID_FLVSS) +{ + packet[0] = sensorId; + packet[1] = 0x10; //DATA_FRAME + *((uint16_t *)(packet+2)) = 0x0300; //CELLS_FIRST_ID + uint32_t data = 0; + data += (cells << 4) + battnumber; + data += ((cell1 * 5) & 0xFFF) << 8; + data += ((cell2 * 5) & 0xFFF) << 20; + *((int32_t *)(packet+4)) = data; + setSportPacketCrc(packet); +} + +#define _V(volts) (volts/TELEMETRY_CELL_VOLTAGE_MUTLIPLIER) + +TEST(FrSkySPORT, FrSkyDCells) +{ + MODEL_RESET(); + TELEMETRY_RESET(); + uint8_t pkt1[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x12 }; + EXPECT_EQ(checkSportPacket(pkt1+1), true); + processSportPacket(pkt1+1); + uint8_t pkt2[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x17, 0xD0, 0x00, 0x00, 0x02 }; + EXPECT_EQ(checkSportPacket(pkt2+1), true); + processSportPacket(pkt2+1); + uint8_t pkt3[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x27, 0xD0, 0x00, 0x00, 0xF1 }; + EXPECT_EQ(checkSportPacket(pkt3+1), true); + processSportPacket(pkt3+1); + processSportPacket(pkt1+1); + processSportPacket(pkt2+1); + processSportPacket(pkt3+1); + EXPECT_EQ(telemetryItems[0].cells.count, 3); + EXPECT_EQ(telemetryItems[0].value, 1200); + for (int i=0; i<3; i++) { + EXPECT_EQ(telemetryItems[0].cells.values[i].state, 1); + EXPECT_EQ(telemetryItems[0].cells.values[i].value, 400); + } +} + +TEST(FrSkySPORT, frskySetCellVoltage) +{ + uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; + + MODEL_RESET(); + TELEMETRY_RESET(); + + // test that simulates 3 cell battery + generateSportCellPacket(packet, 3, 0, _V(410), _V(420)); processSportPacket(packet); + EXPECT_EQ(checkSportPacket(packet), true) << "Bad CRC generation in setSportPacketCrc()"; + generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); + + generateSportCellPacket(packet, 3, 0, _V(405), _V(300)); processSportPacket(packet); + generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); + + EXPECT_EQ(telemetryItems[0].cells.count, 3); + EXPECT_EQ(telemetryItems[0].cells.values[0].value, 405); + EXPECT_EQ(telemetryItems[0].cells.values[1].value, 300); + EXPECT_EQ(telemetryItems[0].cells.values[2].value, 430); + EXPECT_EQ(telemetryItems[0].cells.values[4].value, 0); + EXPECT_EQ(telemetryItems[0].value, 1135); + EXPECT_EQ(telemetryItems[0].valueMin, 1135); + EXPECT_EQ(telemetryItems[0].valueMax, 1260); + + generateSportCellPacket(packet, 3, 0, _V(405), _V(250)); processSportPacket(packet); + generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); + + generateSportCellPacket(packet, 3, 0, _V(410), _V(420)); processSportPacket(packet); + generateSportCellPacket(packet, 3, 2, _V(430), _V( 0)); processSportPacket(packet); + + EXPECT_EQ(telemetryItems[0].cells.count, 3); + EXPECT_EQ(telemetryItems[0].cells.values[0].value, 410); + EXPECT_EQ(telemetryItems[0].cells.values[1].value, 420); + EXPECT_EQ(telemetryItems[0].cells.values[2].value, 430); + EXPECT_EQ(telemetryItems[0].cells.values[4].value, 0); + EXPECT_EQ(telemetryItems[0].value, 1260); + EXPECT_EQ(telemetryItems[0].valueMin, 1085); + EXPECT_EQ(telemetryItems[0].valueMax, 1260); + + //add another two cells - 5 cell battery + generateSportCellPacket(packet, 5, 0, _V(418), _V(408)); processSportPacket(packet); + generateSportCellPacket(packet, 5, 2, _V(415), _V(420)); processSportPacket(packet); + generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); + + EXPECT_EQ(telemetryItems[0].cells.count, 5); + EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); + EXPECT_EQ(telemetryItems[0].cells.values[1].value, 408); + EXPECT_EQ(telemetryItems[0].cells.values[2].value, 415); + EXPECT_EQ(telemetryItems[0].cells.values[3].value, 420); + EXPECT_EQ(telemetryItems[0].cells.values[4].value, 410); + EXPECT_EQ(telemetryItems[0].cells.values[5].value, 0); + EXPECT_EQ(telemetryItems[0].value, 2071); + EXPECT_EQ(telemetryItems[0].valueMin, 2071); + EXPECT_EQ(telemetryItems[0].valueMax, 2071); + + //simulate very low voltage for cell 3 + generateSportCellPacket(packet, 5, 0, _V(418), _V(408)); processSportPacket(packet); + generateSportCellPacket(packet, 5, 2, _V(100), _V(420)); processSportPacket(packet); + generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); + + EXPECT_EQ(telemetryItems[0].cells.count, 5); + EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); + EXPECT_EQ(telemetryItems[0].cells.values[1].value, 408); + EXPECT_EQ(telemetryItems[0].cells.values[2].value, 100); + EXPECT_EQ(telemetryItems[0].cells.values[3].value, 420); + EXPECT_EQ(telemetryItems[0].cells.values[4].value, 410); + EXPECT_EQ(telemetryItems[0].cells.values[5].value, 0); + EXPECT_EQ(telemetryItems[0].value, 1756); + EXPECT_EQ(telemetryItems[0].valueMin, 1756); + EXPECT_EQ(telemetryItems[0].valueMax, 2071); + + //back to normal (but with reversed order of packets) + generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); + generateSportCellPacket(packet, 5, 0, _V(418), _V(408)); processSportPacket(packet); + generateSportCellPacket(packet, 5, 2, _V(412), _V(420)); processSportPacket(packet); + generateSportCellPacket(packet, 5, 4, _V(410), _V( 0)); processSportPacket(packet); + + EXPECT_EQ(telemetryItems[0].cells.count, 5); + EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); + EXPECT_EQ(telemetryItems[0].cells.values[1].value, 408); + EXPECT_EQ(telemetryItems[0].cells.values[2].value, 412); + EXPECT_EQ(telemetryItems[0].cells.values[3].value, 420); + EXPECT_EQ(telemetryItems[0].cells.values[4].value, 410); + EXPECT_EQ(telemetryItems[0].cells.values[5].value, 0); + EXPECT_EQ(telemetryItems[0].value, 2068); + EXPECT_EQ(telemetryItems[0].valueMin, 1756); + EXPECT_EQ(telemetryItems[0].valueMax, 2071); + + //display test + lcdClear(); + g_model.frsky.voltsSource = FRSKY_VOLTS_SOURCE_A1; +} + +TEST(FrSkySPORT, StrangeCellsBug) +{ + MODEL_RESET(); + TELEMETRY_RESET(); + + uint8_t pkt[] = { 0x7E, 0x48, 0x10, 0x00, 0x03, 0x30, 0x15, 0x50, 0x81, 0xD5 }; + EXPECT_EQ(checkSportPacket(pkt+1), true); + processSportPacket(pkt+1); + EXPECT_EQ(telemetryItems[0].cells.count, 3); + EXPECT_EQ(telemetryItems[0].cells.values[0].value, 0); // now we ignore such low values + EXPECT_EQ(telemetryItems[0].cells.values[1].value, 413); +} + +TEST(FrSkySPORT, frskySetCellVoltageTwoSensors) +{ + uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; + + MODEL_RESET(); + TELEMETRY_RESET(); + + //sensor 1: 3 cell battery + generateSportCellPacket(packet, 3, 0, _V(418), _V(416)); processSportPacket(packet); + generateSportCellPacket(packet, 3, 2, _V(415), _V( 0)); processSportPacket(packet); + + EXPECT_EQ(telemetryItems[0].cells.count, 3); + EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); + EXPECT_EQ(telemetryItems[0].cells.values[1].value, 416); + EXPECT_EQ(telemetryItems[0].cells.values[2].value, 415); + EXPECT_EQ(telemetryItems[0].cells.values[3].value, 0); + EXPECT_EQ(telemetryItems[0].value, 1249); + EXPECT_EQ(telemetryItems[0].valueMin, 1249); + EXPECT_EQ(telemetryItems[0].valueMax, 1249); + + //sensor 2: 4 cell battery + generateSportCellPacket(packet, 4, 0, _V(410), _V(420), DATA_ID_FLVSS+1); processSportPacket(packet); + generateSportCellPacket(packet, 4, 2, _V(400), _V(405), DATA_ID_FLVSS+1); processSportPacket(packet); + + EXPECT_EQ(telemetryItems[1].cells.count, 4); + EXPECT_EQ(telemetryItems[1].cells.values[0].value, 410); + EXPECT_EQ(telemetryItems[1].cells.values[1].value, 420); + EXPECT_EQ(telemetryItems[1].cells.values[2].value, 400); + EXPECT_EQ(telemetryItems[1].cells.values[3].value, 405); + EXPECT_EQ(telemetryItems[1].value, 1635); + EXPECT_EQ(telemetryItems[1].valueMin, 1635); + EXPECT_EQ(telemetryItems[1].valueMax, 1635); + + g_model.telemetrySensors[2].type = TELEM_TYPE_CALCULATED; + g_model.telemetrySensors[2].formula = TELEM_FORMULA_ADD; + g_model.telemetrySensors[2].prec = 1; + g_model.telemetrySensors[2].calc.sources[0] = 1; + g_model.telemetrySensors[2].calc.sources[1] = 2; + + telemetryWakeup(); + + EXPECT_EQ(telemetryItems[2].value, 287); + EXPECT_EQ(telemetryItems[2].valueMin, 287); + EXPECT_EQ(telemetryItems[2].valueMax, 287); + + //now change some voltages + generateSportCellPacket(packet, 3, 2, _V(415), _V( 0)); processSportPacket(packet); + generateSportCellPacket(packet, 4, 2, _V(390), _V(370), DATA_ID_FLVSS+1); processSportPacket(packet); + generateSportCellPacket(packet, 3, 0, _V(420), _V(410)); processSportPacket(packet); + generateSportCellPacket(packet, 4, 0, _V(410), _V(420), DATA_ID_FLVSS+1); processSportPacket(packet); + + telemetryWakeup(); + + EXPECT_EQ(telemetryItems[2].value, 283); + EXPECT_EQ(telemetryItems[2].valueMin, 283); + EXPECT_EQ(telemetryItems[2].valueMax, 287); + + //display test + lcdClear(); + g_model.frsky.voltsSource = FRSKY_VOLTS_SOURCE_A1; +} + +void generateSportFasVoltagePacket(uint8_t * packet, uint32_t voltage) +{ + packet[0] = 0x22; //DATA_ID_FAS + packet[1] = 0x10; //DATA_FRAME + *((uint16_t *)(packet+2)) = 0x0210; //VFAS_FIRST_ID + *((int32_t *)(packet+4)) = voltage; // unit 10mV + setSportPacketCrc(packet); +} + +TEST(FrSkySPORT, frskyVfas) +{ + uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; + + MODEL_RESET(); + TELEMETRY_RESET(); + + // tests for Vfas + generateSportFasVoltagePacket(packet, 5000); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 5000); + EXPECT_EQ(telemetryItems[0].valueMin, 5000); + EXPECT_EQ(telemetryItems[0].valueMax, 5000); + + generateSportFasVoltagePacket(packet, 6524); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 6524); + EXPECT_EQ(telemetryItems[0].valueMin, 6524); // the batt was changed (val > old max) + EXPECT_EQ(telemetryItems[0].valueMax, 6524); + + generateSportFasVoltagePacket(packet, 1248); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 1248); + EXPECT_EQ(telemetryItems[0].valueMin, 1248); + EXPECT_EQ(telemetryItems[0].valueMax, 6524); + + generateSportFasVoltagePacket(packet, 2248); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 2248); + EXPECT_EQ(telemetryItems[0].valueMin, 1248); + EXPECT_EQ(telemetryItems[0].valueMax, 6524); +} + +void generateSportFasCurrentPacket(uint8_t * packet, uint32_t current) +{ + packet[0] = 0x22; //DATA_ID_FAS + packet[1] = 0x10; //DATA_FRAME + *((uint16_t *)(packet+2)) = 0x0200; //CURR_FIRST_ID + *((int32_t *)(packet+4)) = current; + setSportPacketCrc(packet); +} + +TEST(FrSkySPORT, frskyCurrent) +{ + uint8_t packet[FRSKY_SPORT_PACKET_SIZE]; + + MODEL_RESET(); + TELEMETRY_RESET(); + + // tests for Curr + generateSportFasCurrentPacket(packet, 0); processSportPacket(packet); + g_model.telemetrySensors[0].custom.offset = -5; /* unit: 1/10 amps */ + generateSportFasCurrentPacket(packet, 0); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 0); + EXPECT_EQ(telemetryItems[0].valueMin, 0); + EXPECT_EQ(telemetryItems[0].valueMax, 0); + + // measured current less then offset - value should be zero + generateSportFasCurrentPacket(packet, 4); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 0); + EXPECT_EQ(telemetryItems[0].valueMin, 0); + EXPECT_EQ(telemetryItems[0].valueMax, 0); + + generateSportFasCurrentPacket(packet, 10); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 5); + EXPECT_EQ(telemetryItems[0].valueMin, 0); + EXPECT_EQ(telemetryItems[0].valueMax, 5); + + generateSportFasCurrentPacket(packet, 500); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 495); + EXPECT_EQ(telemetryItems[0].valueMin, 0); + EXPECT_EQ(telemetryItems[0].valueMax, 495); + + generateSportFasCurrentPacket(packet, 200); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 195); + EXPECT_EQ(telemetryItems[0].valueMin, 0); + EXPECT_EQ(telemetryItems[0].valueMax, 495); + + // test with positive offset + TELEMETRY_RESET(); + g_model.telemetrySensors[0].custom.offset = +5; /* unit: 1/10 amps */ + + generateSportFasCurrentPacket(packet, 0); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 5); + EXPECT_EQ(telemetryItems[0].valueMin, 5); + EXPECT_EQ(telemetryItems[0].valueMax, 5); + + generateSportFasCurrentPacket(packet, 500); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 505); + EXPECT_EQ(telemetryItems[0].valueMin, 5); + EXPECT_EQ(telemetryItems[0].valueMax, 505); + + generateSportFasCurrentPacket(packet, 200); processSportPacket(packet); + EXPECT_EQ(telemetryItems[0].value, 205); + EXPECT_EQ(telemetryItems[0].valueMin, 5); + EXPECT_EQ(telemetryItems[0].valueMax, 505); +} + +#endif //#if defined(FRSKY_SPORT) diff --git a/radio/src/tests/gtests.cpp b/radio/src/tests/gtests.cpp index 857b9bf9e..c8be129a3 100644 --- a/radio/src/tests/gtests.cpp +++ b/radio/src/tests/gtests.cpp @@ -1,69 +1,53 @@ -/* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer - * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ - * - * 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 -#include "gtests.h" - -int32_t lastAct = 0; -uint16_t anaInValues[NUM_STICKS+NUM_POTS] = { 0 }; -uint16_t anaIn(uint8_t chan) -{ - if (chan < NUM_STICKS+NUM_POTS) - return anaInValues[chan]; - else - return 0; -} - -static char _zchar2stringResult[200]; -const char * zchar2string(const char * zstring, int size) -{ - if (size > (int)sizeof(_zchar2stringResult) ) { - return 0; - } - zchar2str(_zchar2stringResult, zstring, size); - return _zchar2stringResult; -} - -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); - simuInit(); - StartEepromThread(NULL); - menuLevel = 0; - menuHandlers[0] = menuMainView; - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 +#include "gtests.h" + +int32_t lastAct = 0; +uint16_t anaInValues[NUM_STICKS+NUM_POTS] = { 0 }; +uint16_t anaIn(uint8_t chan) +{ + if (chan < NUM_STICKS+NUM_POTS) + return anaInValues[chan]; + else + return 0; +} + +static char _zchar2stringResult[200]; +const char * zchar2string(const char * zstring, int size) +{ + if (size > (int)sizeof(_zchar2stringResult) ) { + return 0; + } + zchar2str(_zchar2stringResult, zstring, size); + return _zchar2stringResult; +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + simuInit(); + StartEepromThread(NULL); + menuLevel = 0; + menuHandlers[0] = menuMainView; + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/radio/src/tests/gtests.h b/radio/src/tests/gtests.h index a73bd0893..dfc5dd8d5 100644 --- a/radio/src/tests/gtests.h +++ b/radio/src/tests/gtests.h @@ -1,5 +1,25 @@ -#ifndef __GTESTS_H -#define __GTESTS_H +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#ifndef _GTESTS_H_ +#define _GTESTS_H_ #include #include @@ -71,4 +91,4 @@ inline void TELEMETRY_RESET() bool checkScreenshot(QString test); -#endif +#endif // _GTESTS_H_ diff --git a/radio/src/tests/lcd.cpp b/radio/src/tests/lcd.cpp index b5ebb93c7..1f27bad18 100644 --- a/radio/src/tests/lcd.cpp +++ b/radio/src/tests/lcd.cpp @@ -1,477 +1,461 @@ -/* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer - * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ - * - * 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 -#include -#include -#include -#include -#include - -#define SWAP_DEFINED -#include "opentx.h" -#include "location.h" - -void doPaint(QPainter & p) -{ - QRgb rgb = qRgb(161, 161, 161); - - p.setBackground(QBrush(rgb)); - p.eraseRect(0, 0, LCD_W, LCD_H); - - if (1) { -#if !defined(PCBTARANIS) - rgb = qRgb(0, 0, 0); - p.setPen(rgb); - p.setBrush(QBrush(rgb)); -#endif - -#if defined(PCBTARANIS) - unsigned int previousDepth = 0xFF; -#endif - - for (int y=0; y> 4) : (simuLcdBuf[idx] & 0x0F); - if (z) { - if (z != previousDepth) { - previousDepth = z; - rgb = qRgb(161-(z*161)/15, 161-(z*161)/15, 161-(z*161)/15); - p.setPen(rgb); - p.setBrush(QBrush(rgb)); - } - p.drawPoint(x, y); - } -#endif - } - } - } -} - -bool checkScreenshot(const QString & test) -{ - lcdRefresh(); - QImage buffer(LCD_W, LCD_H, QImage::Format_RGB32); - QPainter p(&buffer); - doPaint(p); - QString filename(QString("%1_%2x%3.png").arg(test).arg(LCD_W).arg(LCD_H)); - buffer.save("/tmp/" + filename); - QFile screenshot("/tmp/" + filename); - if (!screenshot.open(QIODevice::ReadOnly)) - return false; - QFile reference( TESTS_PATH "/tests/" + filename); - if (!reference.open(QIODevice::ReadOnly)) - return false; - if (reference.readAll() != screenshot.readAll()) - return false; - screenshot.remove(); - return true; -} - -TEST(outdezNAtt, test_unsigned) -{ - lcdClear(); - lcdDrawNumber(0, 0, 65530, LEFT|UNSIGN); - EXPECT_TRUE(checkScreenshot("unsigned")) << "Unsigned numbers will be bad displayed"; -} - -#if defined(CPUARM) -TEST(outdezNAtt, testBigNumbers) -{ - lcdClear(); - lcdDrawNumber(0, 0, 1234567, LEFT); - lcdDrawNumber(0, FH, -1234567, LEFT); - EXPECT_TRUE(checkScreenshot("big_numbers")); -} -#endif // #if defined(CPUARM) - - -TEST(Lcd, Invers_0_0) -{ - lcdClear(); - lcdDrawText(0, 0, "Test", INVERS); - EXPECT_TRUE(checkScreenshot("invers_0_0")); -} - -TEST(Lcd, Invers_0_1) -{ - lcdClear(); - lcdDrawText(0, 1, "Test", INVERS); - EXPECT_TRUE(checkScreenshot("invers_0_1")); -} - -TEST(Lcd, Prec2_Left) -{ - lcdClear(); - lcdDrawNumber(0, 0, 2, PREC2|LEFT); - EXPECT_TRUE(checkScreenshot("prec2_left")); -} - -TEST(Lcd, Prec2_Right) -{ - lcdClear(); - lcdDrawNumber(LCD_W, LCD_H-FH, 2, PREC2); - EXPECT_TRUE(checkScreenshot("prec2_right")); -} - -#if defined(CPUARM) -TEST(Lcd, Prec1_Dblsize_Invers) -{ - lcdClear(); - lcdDrawNumber(LCD_W, 10, 51, PREC1|DBLSIZE|INVERS); - EXPECT_TRUE(checkScreenshot("prec1_dblsize_invers")); -} -#endif - -TEST(Lcd, Line_Wrap) -{ - lcdClear(); - lcdDrawText(LCD_W-10, 0, "TEST"); - EXPECT_TRUE(checkScreenshot("line_wrap")); -} - -TEST(Lcd, DblsizeBottomRight) -{ - lcdClear(); - lcdDrawText(LCD_W-20, LCD_H-16, "TEST", DBLSIZE); - EXPECT_TRUE(checkScreenshot("dblsize_bottom_right")); -} - -#if defined(CPUARM) -TEST(Lcd, Smlsize_drawStringWithIndex) -{ - lcdClear(); - drawStringWithIndex(0, 0, "FM", 0, SMLSIZE); - EXPECT_TRUE(checkScreenshot("smlsize_drawstringwithindex")); -} -#endif - -TEST(Lcd, vline) -{ - lcdClear(); - for (int x=0; x<100; x+=2) { - lcdDrawSolidVerticalLine(x, x/2, 12); - } - EXPECT_TRUE(checkScreenshot("vline")); -} - -#if defined(CPUARM) -TEST(Lcd, vline_x_lt0) -{ - lcdClear(); - lcdDrawSolidVerticalLine(50, -10, 12); - lcdDrawSolidVerticalLine(100, -10, 1); - EXPECT_TRUE(checkScreenshot("vline_lt0")); -} -#endif - -#if defined(CPUARM) -TEST(Lcd, Smlsize) -{ - lcdClear(); - lcdDrawText(0, 0, "TESTgy,", SMLSIZE); - lcdDrawText(10, 22, "TESTgy,", SMLSIZE|INVERS); - lcdDrawFilledRect(8, 40, 100, 20); - lcdDrawText(10, 42, "TESTgy,", SMLSIZE); - - bool invert = false; - for(int i=0; i<3; i++) { - lcdDrawText(40+(4*i), 0+(4*i), "ABC", SMLSIZE|(invert?INVERS:0)); - invert = !invert; - } - - EXPECT_TRUE(checkScreenshot("smlsize")); -} - -TEST(Lcd, Stdsize) -{ - lcdClear(); - lcdDrawText(0, 0, "TEST", 0); - lcdDrawText(10, 22, "TEST", INVERS); - lcdDrawFilledRect(8, 40, 100, 20); - lcdDrawText(10, 42, "TEST", 0); - - bool invert = false; - for(int i=0; i<3; i++) { - lcdDrawText(40+(4*i), 0+(4*i), "ABC", (invert?INVERS:0)); - invert = !invert; - } - - EXPECT_TRUE(checkScreenshot("stdsize")); -} - -TEST(Lcd, Midsize) -{ - lcdClear(); - lcdDrawText(0, 0, "TEST", MIDSIZE); - lcdDrawText(10, 22, "TEST", MIDSIZE|INVERS); - lcdDrawFilledRect(8, 40, 100, 20); - lcdDrawText(10, 42, "TEST", MIDSIZE); - - bool invert = false; - for(int i=0; i<3; i++) { - lcdDrawText(40+(4*i), 0+(4*i), "ABC", MIDSIZE|(invert?INVERS:0)); - invert = !invert; - } - - EXPECT_TRUE(checkScreenshot("midsize")); -} - -TEST(Lcd, Dblsize) -{ - lcdClear(); - lcdDrawText(2, 10, "TST", DBLSIZE); - lcdDrawText(42, 10, "TST", DBLSIZE|INVERS); - lcdDrawFilledRect(80, 8, 46, 24); - lcdDrawText(82, 10, "TST", DBLSIZE); - - bool invert = false; - for(int i=0; i<3; i++) { - lcdDrawText(10+(4*i), 30+(4*i), "ABC", DBLSIZE|(invert?INVERS:0)); - invert = !invert; - } - - EXPECT_TRUE(checkScreenshot("dblsize")); -} -#endif - -#if defined(PCBTARANIS) -TEST(Lcd, DrawSwitch) -{ - lcdClear(); - putsSwitches(0, 10, SWSRC_SA0, 0); - putsSwitches(30, 10, SWSRC_SA0, SMLSIZE); - // putsSwitches(60, 10, SWSRC_SA0, MIDSIZE); missing arrows in this font - putsSwitches(90, 10, SWSRC_SA0, DBLSIZE); - EXPECT_TRUE(checkScreenshot("drawswitch")); -} -#endif - -#if defined(PCBTARANIS) -TEST(Lcd, BMPWrapping) -{ - lcdClear(); - uint8_t bitmap[2+40*40/2]; - lcdLoadBitmap(bitmap, TESTS_PATH "/tests/plane.bmp", 40, 40); - lcdDrawBitmap(200, 0, bitmap); - lcdDrawBitmap(200, 60, bitmap); - lcdDrawBitmap(240, 60, bitmap); // x too big - lcdDrawBitmap(20, 200, bitmap); // y too big - EXPECT_TRUE(checkScreenshot("bmpwrapping")); -} -#endif - -#if defined(PCBTARANIS) -TEST(Lcd, lcdDrawHorizontalLine) -{ - lcdClear(); - lcdDrawHorizontalLine(0, 10, LCD_W, DOTTED); - lcdDrawHorizontalLine(0, 20, LCD_W, SOLID); - lcdDrawHorizontalLine(50, 30, LCD_W, 0xEE); //too wide - lcdDrawHorizontalLine(50, LCD_H + 10, 20, SOLID); //too low - lcdDrawHorizontalLine(250, 30, LCD_W, SOLID); //x outside display - EXPECT_TRUE(checkScreenshot("lcdDrawHorizontalLine")); -} -#endif - -#if defined(PCBTARANIS) -TEST(Lcd, lcdDrawVerticalLine) -{ - lcdClear(); - lcdDrawVerticalLine(10, 0, LCD_H, DOTTED); - lcdDrawVerticalLine(20, 0, LCD_H, SOLID); - lcdDrawVerticalLine(30, 30, LCD_H, 0xEE); //too high - lcdDrawVerticalLine(40, LCD_H + 10, 20, SOLID); //too low - lcdDrawVerticalLine(250, LCD_H + 10, LCD_H, SOLID); //x outside display - EXPECT_TRUE(checkScreenshot("lcdDrawVerticalLine")); -} -#endif - -template class TestBuffer -{ -private: - uint8_t * buf; - uint32_t size; -public: - TestBuffer(uint32_t size) : buf(0), size(size) { - buf = new uint8_t[size + padding * 2]; - memset(buf, 0xA5, padding); - memset(buf+padding, 0x00, size); - memset(buf+padding+size, 0x5A, padding); - }; - ~TestBuffer() { if (buf) delete[] buf; }; - uint8_t * buffer() { return buf + padding; }; - void leakCheck() const { - uint8_t paddingCompareBuf[padding]; - memset(paddingCompareBuf, 0xA5, padding); - if (memcmp(buf, paddingCompareBuf, padding) != 0) { - ADD_FAILURE() << "buffer leaked low"; - }; - memset(paddingCompareBuf, 0x5A, padding); - if (memcmp(buf+padding+size, paddingCompareBuf, padding) != 0) { - ADD_FAILURE() << "buffer leaked high"; - } - }; -}; - -#if defined(PCBTARANIS) -TEST(Lcd, lcdDrawBitmapLoadAndDisplay) -{ - lcdClear(); - // Test proper BMP files, they should display correctly - { - TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(7, 32)); - EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_7x32.bmp", 7, 32) != NULL); - bitmap.leakCheck(); - lcdDrawBitmap(10, 2, bitmap.buffer()); - } - { - TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(6, 32)); - EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_6x32.bmp", 6, 32) != NULL); - bitmap.leakCheck(); - lcdDrawBitmap(20, 2, bitmap.buffer()); - } - { - TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(31, 31)); - EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_31x31.bmp", 31, 31) != NULL); - bitmap.leakCheck(); - lcdDrawBitmap(30, 2, bitmap.buffer()); - } - { - TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(39, 32)); - EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 39, 32) != NULL); - bitmap.leakCheck(); - lcdDrawBitmap(70, 2, bitmap.buffer()); - } - { - TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(20, 20)); - EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_20x20.bmp", 20, 20) != NULL); - bitmap.leakCheck(); - lcdDrawBitmap(120, 2, bitmap.buffer()); - } - EXPECT_TRUE(checkScreenshot("lcdDrawBitmapLoadAndDisplay")); - - // Test various bad BMP files, they should not display - { - TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(LCD_W+1, 32)); - EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), "", LCD_W+1, 32) == NULL) << "to wide"; - bitmap.leakCheck(); - } - { - TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(10, 10)); - EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 10, 10) == NULL) << "to small buffer"; - bitmap.leakCheck(); - } -} -#endif - -#if defined(PCBTARANIS) -TEST(Lcd, lcdDrawLine) -{ - int start, length, xOffset; - uint8_t pattern; - - lcdClear(); - - start = 5; - pattern = SOLID; - length = 40; - xOffset = 0; - lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); - lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); - - start = 10; - pattern = DOTTED; - length = 40; - xOffset = 0; - lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); - lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); - - start = 55; - pattern = SOLID; - length = -40; - xOffset = 80; - lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); - lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); - - start = 50; - pattern = DOTTED; - length = -40; - xOffset = 80; - lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); - lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); - - // 45 deg lines - lcdDrawLine( 35, 40, 45, 40, SOLID, FORCE ); - lcdDrawLine( 40, 35, 40, 45, SOLID, FORCE ); - - lcdDrawLine( 20, 40, 40, 20, SOLID, FORCE ); - lcdDrawLine( 40, 20, 60, 40, SOLID, FORCE ); - lcdDrawLine( 60, 40, 40, 60, SOLID, FORCE ); - lcdDrawLine( 40, 60, 20, 40, SOLID, FORCE ); - - lcdDrawLine( 31, 39, 39, 31, SOLID, FORCE ); - lcdDrawLine( 41, 31, 49, 39, SOLID, FORCE ); - lcdDrawLine( 49, 41, 41, 49, SOLID, FORCE ); - lcdDrawLine( 39, 49, 31, 41, SOLID, FORCE ); - - // slanted lines - lcdDrawLine( 150, 10, 190, 10, SOLID, FORCE ); - lcdDrawLine( 150, 10, 190, 20, SOLID, FORCE ); - lcdDrawLine( 150, 10, 190, 30, SOLID, FORCE ); - lcdDrawLine( 150, 10, 190, 40, SOLID, FORCE ); - lcdDrawLine( 150, 10, 190, 50, SOLID, FORCE ); - - lcdDrawLine( 150, 10, 190, 50, SOLID, FORCE ); - lcdDrawLine( 150, 10, 180, 50, SOLID, FORCE ); - lcdDrawLine( 150, 10, 170, 50, SOLID, FORCE ); - lcdDrawLine( 150, 10, 160, 50, SOLID, FORCE ); - lcdDrawLine( 150, 10, 150, 50, SOLID, FORCE ); - - EXPECT_TRUE(checkScreenshot("lcdDrawLine")); -} -#endif +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 +#include +#include +#include +#include +#include + +#define SWAP_DEFINED +#include "opentx.h" +#include "location.h" + +void doPaint(QPainter & p) +{ + QRgb rgb = qRgb(161, 161, 161); + + p.setBackground(QBrush(rgb)); + p.eraseRect(0, 0, LCD_W, LCD_H); + + if (1) { +#if !defined(PCBTARANIS) + rgb = qRgb(0, 0, 0); + p.setPen(rgb); + p.setBrush(QBrush(rgb)); +#endif + +#if defined(PCBTARANIS) + unsigned int previousDepth = 0xFF; +#endif + + for (int y=0; y> 4) : (simuLcdBuf[idx] & 0x0F); + if (z) { + if (z != previousDepth) { + previousDepth = z; + rgb = qRgb(161-(z*161)/15, 161-(z*161)/15, 161-(z*161)/15); + p.setPen(rgb); + p.setBrush(QBrush(rgb)); + } + p.drawPoint(x, y); + } +#endif + } + } + } +} + +bool checkScreenshot(const QString & test) +{ + lcdRefresh(); + QImage buffer(LCD_W, LCD_H, QImage::Format_RGB32); + QPainter p(&buffer); + doPaint(p); + QString filename(QString("%1_%2x%3.png").arg(test).arg(LCD_W).arg(LCD_H)); + buffer.save("/tmp/" + filename); + QFile screenshot("/tmp/" + filename); + if (!screenshot.open(QIODevice::ReadOnly)) + return false; + QFile reference( TESTS_PATH "/tests/" + filename); + if (!reference.open(QIODevice::ReadOnly)) + return false; + if (reference.readAll() != screenshot.readAll()) + return false; + screenshot.remove(); + return true; +} + +TEST(outdezNAtt, test_unsigned) +{ + lcdClear(); + lcdDrawNumber(0, 0, 65530, LEFT|UNSIGN); + EXPECT_TRUE(checkScreenshot("unsigned")) << "Unsigned numbers will be bad displayed"; +} + +#if defined(CPUARM) +TEST(outdezNAtt, testBigNumbers) +{ + lcdClear(); + lcdDrawNumber(0, 0, 1234567, LEFT); + lcdDrawNumber(0, FH, -1234567, LEFT); + EXPECT_TRUE(checkScreenshot("big_numbers")); +} +#endif // #if defined(CPUARM) + + +TEST(Lcd, Invers_0_0) +{ + lcdClear(); + lcdDrawText(0, 0, "Test", INVERS); + EXPECT_TRUE(checkScreenshot("invers_0_0")); +} + +TEST(Lcd, Invers_0_1) +{ + lcdClear(); + lcdDrawText(0, 1, "Test", INVERS); + EXPECT_TRUE(checkScreenshot("invers_0_1")); +} + +TEST(Lcd, Prec2_Left) +{ + lcdClear(); + lcdDrawNumber(0, 0, 2, PREC2|LEFT); + EXPECT_TRUE(checkScreenshot("prec2_left")); +} + +TEST(Lcd, Prec2_Right) +{ + lcdClear(); + lcdDrawNumber(LCD_W, LCD_H-FH, 2, PREC2); + EXPECT_TRUE(checkScreenshot("prec2_right")); +} + +#if defined(CPUARM) +TEST(Lcd, Prec1_Dblsize_Invers) +{ + lcdClear(); + lcdDrawNumber(LCD_W, 10, 51, PREC1|DBLSIZE|INVERS); + EXPECT_TRUE(checkScreenshot("prec1_dblsize_invers")); +} +#endif + +TEST(Lcd, Line_Wrap) +{ + lcdClear(); + lcdDrawText(LCD_W-10, 0, "TEST"); + EXPECT_TRUE(checkScreenshot("line_wrap")); +} + +TEST(Lcd, DblsizeBottomRight) +{ + lcdClear(); + lcdDrawText(LCD_W-20, LCD_H-16, "TEST", DBLSIZE); + EXPECT_TRUE(checkScreenshot("dblsize_bottom_right")); +} + +#if defined(CPUARM) +TEST(Lcd, Smlsize_drawStringWithIndex) +{ + lcdClear(); + drawStringWithIndex(0, 0, "FM", 0, SMLSIZE); + EXPECT_TRUE(checkScreenshot("smlsize_drawstringwithindex")); +} +#endif + +TEST(Lcd, vline) +{ + lcdClear(); + for (int x=0; x<100; x+=2) { + lcdDrawSolidVerticalLine(x, x/2, 12); + } + EXPECT_TRUE(checkScreenshot("vline")); +} + +#if defined(CPUARM) +TEST(Lcd, vline_x_lt0) +{ + lcdClear(); + lcdDrawSolidVerticalLine(50, -10, 12); + lcdDrawSolidVerticalLine(100, -10, 1); + EXPECT_TRUE(checkScreenshot("vline_lt0")); +} +#endif + +#if defined(CPUARM) +TEST(Lcd, Smlsize) +{ + lcdClear(); + lcdDrawText(0, 0, "TESTgy,", SMLSIZE); + lcdDrawText(10, 22, "TESTgy,", SMLSIZE|INVERS); + lcdDrawFilledRect(8, 40, 100, 20); + lcdDrawText(10, 42, "TESTgy,", SMLSIZE); + + bool invert = false; + for(int i=0; i<3; i++) { + lcdDrawText(40+(4*i), 0+(4*i), "ABC", SMLSIZE|(invert?INVERS:0)); + invert = !invert; + } + + EXPECT_TRUE(checkScreenshot("smlsize")); +} + +TEST(Lcd, Stdsize) +{ + lcdClear(); + lcdDrawText(0, 0, "TEST", 0); + lcdDrawText(10, 22, "TEST", INVERS); + lcdDrawFilledRect(8, 40, 100, 20); + lcdDrawText(10, 42, "TEST", 0); + + bool invert = false; + for(int i=0; i<3; i++) { + lcdDrawText(40+(4*i), 0+(4*i), "ABC", (invert?INVERS:0)); + invert = !invert; + } + + EXPECT_TRUE(checkScreenshot("stdsize")); +} + +TEST(Lcd, Midsize) +{ + lcdClear(); + lcdDrawText(0, 0, "TEST", MIDSIZE); + lcdDrawText(10, 22, "TEST", MIDSIZE|INVERS); + lcdDrawFilledRect(8, 40, 100, 20); + lcdDrawText(10, 42, "TEST", MIDSIZE); + + bool invert = false; + for(int i=0; i<3; i++) { + lcdDrawText(40+(4*i), 0+(4*i), "ABC", MIDSIZE|(invert?INVERS:0)); + invert = !invert; + } + + EXPECT_TRUE(checkScreenshot("midsize")); +} + +TEST(Lcd, Dblsize) +{ + lcdClear(); + lcdDrawText(2, 10, "TST", DBLSIZE); + lcdDrawText(42, 10, "TST", DBLSIZE|INVERS); + lcdDrawFilledRect(80, 8, 46, 24); + lcdDrawText(82, 10, "TST", DBLSIZE); + + bool invert = false; + for(int i=0; i<3; i++) { + lcdDrawText(10+(4*i), 30+(4*i), "ABC", DBLSIZE|(invert?INVERS:0)); + invert = !invert; + } + + EXPECT_TRUE(checkScreenshot("dblsize")); +} +#endif + +#if defined(PCBTARANIS) +TEST(Lcd, DrawSwitch) +{ + lcdClear(); + putsSwitches(0, 10, SWSRC_SA0, 0); + putsSwitches(30, 10, SWSRC_SA0, SMLSIZE); + // putsSwitches(60, 10, SWSRC_SA0, MIDSIZE); missing arrows in this font + putsSwitches(90, 10, SWSRC_SA0, DBLSIZE); + EXPECT_TRUE(checkScreenshot("drawswitch")); +} +#endif + +#if defined(PCBTARANIS) +TEST(Lcd, BMPWrapping) +{ + lcdClear(); + uint8_t bitmap[2+40*40/2]; + lcdLoadBitmap(bitmap, TESTS_PATH "/tests/plane.bmp", 40, 40); + lcdDrawBitmap(200, 0, bitmap); + lcdDrawBitmap(200, 60, bitmap); + lcdDrawBitmap(240, 60, bitmap); // x too big + lcdDrawBitmap(20, 200, bitmap); // y too big + EXPECT_TRUE(checkScreenshot("bmpwrapping")); +} +#endif + +#if defined(PCBTARANIS) +TEST(Lcd, lcdDrawHorizontalLine) +{ + lcdClear(); + lcdDrawHorizontalLine(0, 10, LCD_W, DOTTED); + lcdDrawHorizontalLine(0, 20, LCD_W, SOLID); + lcdDrawHorizontalLine(50, 30, LCD_W, 0xEE); //too wide + lcdDrawHorizontalLine(50, LCD_H + 10, 20, SOLID); //too low + lcdDrawHorizontalLine(250, 30, LCD_W, SOLID); //x outside display + EXPECT_TRUE(checkScreenshot("lcdDrawHorizontalLine")); +} +#endif + +#if defined(PCBTARANIS) +TEST(Lcd, lcdDrawVerticalLine) +{ + lcdClear(); + lcdDrawVerticalLine(10, 0, LCD_H, DOTTED); + lcdDrawVerticalLine(20, 0, LCD_H, SOLID); + lcdDrawVerticalLine(30, 30, LCD_H, 0xEE); //too high + lcdDrawVerticalLine(40, LCD_H + 10, 20, SOLID); //too low + lcdDrawVerticalLine(250, LCD_H + 10, LCD_H, SOLID); //x outside display + EXPECT_TRUE(checkScreenshot("lcdDrawVerticalLine")); +} +#endif + +template class TestBuffer +{ +private: + uint8_t * buf; + uint32_t size; +public: + TestBuffer(uint32_t size) : buf(0), size(size) { + buf = new uint8_t[size + padding * 2]; + memset(buf, 0xA5, padding); + memset(buf+padding, 0x00, size); + memset(buf+padding+size, 0x5A, padding); + }; + ~TestBuffer() { if (buf) delete[] buf; }; + uint8_t * buffer() { return buf + padding; }; + void leakCheck() const { + uint8_t paddingCompareBuf[padding]; + memset(paddingCompareBuf, 0xA5, padding); + if (memcmp(buf, paddingCompareBuf, padding) != 0) { + ADD_FAILURE() << "buffer leaked low"; + }; + memset(paddingCompareBuf, 0x5A, padding); + if (memcmp(buf+padding+size, paddingCompareBuf, padding) != 0) { + ADD_FAILURE() << "buffer leaked high"; + } + }; +}; + +#if defined(PCBTARANIS) +TEST(Lcd, lcdDrawBitmapLoadAndDisplay) +{ + lcdClear(); + // Test proper BMP files, they should display correctly + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(7, 32)); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_7x32.bmp", 7, 32) != NULL); + bitmap.leakCheck(); + lcdDrawBitmap(10, 2, bitmap.buffer()); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(6, 32)); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_6x32.bmp", 6, 32) != NULL); + bitmap.leakCheck(); + lcdDrawBitmap(20, 2, bitmap.buffer()); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(31, 31)); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_31x31.bmp", 31, 31) != NULL); + bitmap.leakCheck(); + lcdDrawBitmap(30, 2, bitmap.buffer()); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(39, 32)); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 39, 32) != NULL); + bitmap.leakCheck(); + lcdDrawBitmap(70, 2, bitmap.buffer()); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(20, 20)); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_20x20.bmp", 20, 20) != NULL); + bitmap.leakCheck(); + lcdDrawBitmap(120, 2, bitmap.buffer()); + } + EXPECT_TRUE(checkScreenshot("lcdDrawBitmapLoadAndDisplay")); + + // Test various bad BMP files, they should not display + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(LCD_W+1, 32)); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), "", LCD_W+1, 32) == NULL) << "to wide"; + bitmap.leakCheck(); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(10, 10)); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 10, 10) == NULL) << "to small buffer"; + bitmap.leakCheck(); + } +} +#endif + +#if defined(PCBTARANIS) +TEST(Lcd, lcdDrawLine) +{ + int start, length, xOffset; + uint8_t pattern; + + lcdClear(); + + start = 5; + pattern = SOLID; + length = 40; + xOffset = 0; + lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); + lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); + + start = 10; + pattern = DOTTED; + length = 40; + xOffset = 0; + lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); + lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); + + start = 55; + pattern = SOLID; + length = -40; + xOffset = 80; + lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); + lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); + + start = 50; + pattern = DOTTED; + length = -40; + xOffset = 80; + lcdDrawLine(start+(length>0?1:-1)+xOffset, start, start+(length>0?1:-1)+xOffset+length, start, pattern, 0); + lcdDrawLine(start+xOffset, start+(length>0?1:-1), start+xOffset, start+(length>0?1:-1)+length, pattern, 0); + + // 45 deg lines + lcdDrawLine( 35, 40, 45, 40, SOLID, FORCE ); + lcdDrawLine( 40, 35, 40, 45, SOLID, FORCE ); + + lcdDrawLine( 20, 40, 40, 20, SOLID, FORCE ); + lcdDrawLine( 40, 20, 60, 40, SOLID, FORCE ); + lcdDrawLine( 60, 40, 40, 60, SOLID, FORCE ); + lcdDrawLine( 40, 60, 20, 40, SOLID, FORCE ); + + lcdDrawLine( 31, 39, 39, 31, SOLID, FORCE ); + lcdDrawLine( 41, 31, 49, 39, SOLID, FORCE ); + lcdDrawLine( 49, 41, 41, 49, SOLID, FORCE ); + lcdDrawLine( 39, 49, 31, 41, SOLID, FORCE ); + + // slanted lines + lcdDrawLine( 150, 10, 190, 10, SOLID, FORCE ); + lcdDrawLine( 150, 10, 190, 20, SOLID, FORCE ); + lcdDrawLine( 150, 10, 190, 30, SOLID, FORCE ); + lcdDrawLine( 150, 10, 190, 40, SOLID, FORCE ); + lcdDrawLine( 150, 10, 190, 50, SOLID, FORCE ); + + lcdDrawLine( 150, 10, 190, 50, SOLID, FORCE ); + lcdDrawLine( 150, 10, 180, 50, SOLID, FORCE ); + lcdDrawLine( 150, 10, 170, 50, SOLID, FORCE ); + lcdDrawLine( 150, 10, 160, 50, SOLID, FORCE ); + lcdDrawLine( 150, 10, 150, 50, SOLID, FORCE ); + + EXPECT_TRUE(checkScreenshot("lcdDrawLine")); +} +#endif diff --git a/radio/src/tests/lua.cpp b/radio/src/tests/lua.cpp index a0e3cad58..ddb249f53 100644 --- a/radio/src/tests/lua.cpp +++ b/radio/src/tests/lua.cpp @@ -1,184 +1,168 @@ -/* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer - * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ - * - * 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 -#include "gtests.h" - -#if defined(LUA) - -#define SWAP_DEFINED -#include "opentx.h" - -extern const char * zchar2string(const char * zstring, int size); -#define EXPECT_ZSTREQ(c_string, z_string) EXPECT_STREQ(c_string, zchar2string(z_string, sizeof(z_string))) - -::testing::AssertionResult __luaExecStr(const char * str) -{ - extern lua_State * L; - if (!L) luaInit(); - if (!L) return ::testing::AssertionFailure() << "No Lua state!"; - if (luaL_dostring(L, str)) { - return ::testing::AssertionFailure() << "lua error: " << lua_tostring(L, -1); - } - return ::testing::AssertionSuccess(); -} - -#define luaExecStr(test) EXPECT_TRUE(__luaExecStr(test)) - -TEST(Lua, testSetModelInfo) -{ - luaExecStr("info = model.getInfo()"); - // luaExecStr("print('model name: '..info.name..' id: '..info.id)"); - luaExecStr("info.name = 'modelA'"); - luaExecStr("model.setInfo(info)"); - // luaExecStr("print('model name: '..info.name..' id: '..info.id)"); - EXPECT_ZSTREQ("modelA", g_model.header.name); - - luaExecStr("info.name = 'Model 1'"); - luaExecStr("model.setInfo(info)"); - // luaExecStr("print('model name: '..info.name..' id: '..info.id)"); - EXPECT_ZSTREQ("Model 1", g_model.header.name); -} - -TEST(Lua, testPanicProtection) -{ - bool passed = false; - PROTECT_LUA() { - PROTECT_LUA() { - //simulate panic - longjmp(global_lj->b, 1); - } - else { - //we should come here - passed = true; - } - UNPROTECT_LUA(); - } - else { - // an not here - // TRACE("testLuaProtection: test 1 FAILED"); - FAIL() << "Failed test 1"; - } - UNPROTECT_LUA() - - EXPECT_EQ(passed, true); - - passed = false; - - PROTECT_LUA() { - PROTECT_LUA() { - int a = 5; - a = a; // avoids the warning - } - else { - //we should not come here - // TRACE("testLuaProtection: test 2 FAILED"); - FAIL() << "Failed test 2"; - } - UNPROTECT_LUA() - //simulate panic - longjmp(global_lj->b, 1); - } - else { - // we should come here - passed = true; - } - UNPROTECT_LUA() - - EXPECT_EQ(passed, true); -} - -TEST(Lua, testModelInputs) -{ - MODEL_RESET(); - luaExecStr("noInputs = model.getInputsCount(0)"); - luaExecStr("if noInputs > 0 then error('getInputsCount()') end"); - - // add one line on Input4 - luaExecStr("model.insertInput(3, 0, {name='test1', source=MIXSRC_Thr, weight=56, offset=3, switch=2})"); - EXPECT_EQ(3, (int)g_model.expoData[0].chn); - EXPECT_ZSTREQ("test1", g_model.expoData[0].name); - EXPECT_EQ(MIXSRC_Thr, g_model.expoData[0].srcRaw); - EXPECT_EQ(56, g_model.expoData[0].weight); - EXPECT_EQ(3, g_model.expoData[0].offset); - EXPECT_EQ(2, g_model.expoData[0].swtch); - - // add another one before existing line on Input4 - luaExecStr("model.insertInput(3, 0, {name='test2', source=MIXSRC_Rud, weight=-56})"); - EXPECT_EQ(3, (int)g_model.expoData[0].chn); - EXPECT_ZSTREQ("test2", g_model.expoData[0].name); - EXPECT_EQ(MIXSRC_Rud, g_model.expoData[0].srcRaw); - EXPECT_EQ(-56, g_model.expoData[0].weight); - EXPECT_EQ(0, g_model.expoData[0].offset); - EXPECT_EQ(0, g_model.expoData[0].swtch); - - EXPECT_EQ(3, (int)g_model.expoData[1].chn); - EXPECT_ZSTREQ("test1", g_model.expoData[1].name); - EXPECT_EQ(MIXSRC_Thr, g_model.expoData[1].srcRaw); - EXPECT_EQ(56, g_model.expoData[1].weight); - EXPECT_EQ(3, g_model.expoData[1].offset); - EXPECT_EQ(2, g_model.expoData[1].swtch); - - // add another line after existing lines on Input4 - luaExecStr("model.insertInput(3, model.getInputsCount(3), {name='test3', source=MIXSRC_Ail, weight=100})"); - EXPECT_EQ(3, (int)g_model.expoData[0].chn); - EXPECT_ZSTREQ("test2", g_model.expoData[0].name); - EXPECT_EQ(MIXSRC_Rud, g_model.expoData[0].srcRaw); - EXPECT_EQ(-56, g_model.expoData[0].weight); - EXPECT_EQ(0, g_model.expoData[0].offset); - EXPECT_EQ(0, g_model.expoData[0].swtch); - - EXPECT_EQ(3, (int)g_model.expoData[1].chn); - EXPECT_ZSTREQ("test1", g_model.expoData[1].name); - EXPECT_EQ(MIXSRC_Thr, g_model.expoData[1].srcRaw); - EXPECT_EQ(56, g_model.expoData[1].weight); - EXPECT_EQ(3, g_model.expoData[1].offset); - EXPECT_EQ(2, g_model.expoData[1].swtch); - - EXPECT_EQ(3, (int)g_model.expoData[2].chn); - EXPECT_ZSTREQ("test3", g_model.expoData[2].name); - EXPECT_EQ(MIXSRC_Ail, g_model.expoData[2].srcRaw); - EXPECT_EQ(100, g_model.expoData[2].weight); - EXPECT_EQ(0, g_model.expoData[2].offset); - EXPECT_EQ(0, g_model.expoData[2].swtch); - - // verify number of lines for Input4 - luaExecStr("noInputs = model.getInputsCount(3)"); - luaExecStr("if noInputs ~= 3 then error('getInputsCount()') end"); - -} - -#endif // #if defined(LUA) +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 +#include "gtests.h" + +#if defined(LUA) + +#define SWAP_DEFINED +#include "opentx.h" + +extern const char * zchar2string(const char * zstring, int size); +#define EXPECT_ZSTREQ(c_string, z_string) EXPECT_STREQ(c_string, zchar2string(z_string, sizeof(z_string))) + +::testing::AssertionResult __luaExecStr(const char * str) +{ + extern lua_State * L; + if (!L) luaInit(); + if (!L) return ::testing::AssertionFailure() << "No Lua state!"; + if (luaL_dostring(L, str)) { + return ::testing::AssertionFailure() << "lua error: " << lua_tostring(L, -1); + } + return ::testing::AssertionSuccess(); +} + +#define luaExecStr(test) EXPECT_TRUE(__luaExecStr(test)) + +TEST(Lua, testSetModelInfo) +{ + luaExecStr("info = model.getInfo()"); + // luaExecStr("print('model name: '..info.name..' id: '..info.id)"); + luaExecStr("info.name = 'modelA'"); + luaExecStr("model.setInfo(info)"); + // luaExecStr("print('model name: '..info.name..' id: '..info.id)"); + EXPECT_ZSTREQ("modelA", g_model.header.name); + + luaExecStr("info.name = 'Model 1'"); + luaExecStr("model.setInfo(info)"); + // luaExecStr("print('model name: '..info.name..' id: '..info.id)"); + EXPECT_ZSTREQ("Model 1", g_model.header.name); +} + +TEST(Lua, testPanicProtection) +{ + bool passed = false; + PROTECT_LUA() { + PROTECT_LUA() { + //simulate panic + longjmp(global_lj->b, 1); + } + else { + //we should come here + passed = true; + } + UNPROTECT_LUA(); + } + else { + // an not here + // TRACE("testLuaProtection: test 1 FAILED"); + FAIL() << "Failed test 1"; + } + UNPROTECT_LUA() + + EXPECT_EQ(passed, true); + + passed = false; + + PROTECT_LUA() { + PROTECT_LUA() { + int a = 5; + a = a; // avoids the warning + } + else { + //we should not come here + // TRACE("testLuaProtection: test 2 FAILED"); + FAIL() << "Failed test 2"; + } + UNPROTECT_LUA() + //simulate panic + longjmp(global_lj->b, 1); + } + else { + // we should come here + passed = true; + } + UNPROTECT_LUA() + + EXPECT_EQ(passed, true); +} + +TEST(Lua, testModelInputs) +{ + MODEL_RESET(); + luaExecStr("noInputs = model.getInputsCount(0)"); + luaExecStr("if noInputs > 0 then error('getInputsCount()') end"); + + // add one line on Input4 + luaExecStr("model.insertInput(3, 0, {name='test1', source=MIXSRC_Thr, weight=56, offset=3, switch=2})"); + EXPECT_EQ(3, (int)g_model.expoData[0].chn); + EXPECT_ZSTREQ("test1", g_model.expoData[0].name); + EXPECT_EQ(MIXSRC_Thr, g_model.expoData[0].srcRaw); + EXPECT_EQ(56, g_model.expoData[0].weight); + EXPECT_EQ(3, g_model.expoData[0].offset); + EXPECT_EQ(2, g_model.expoData[0].swtch); + + // add another one before existing line on Input4 + luaExecStr("model.insertInput(3, 0, {name='test2', source=MIXSRC_Rud, weight=-56})"); + EXPECT_EQ(3, (int)g_model.expoData[0].chn); + EXPECT_ZSTREQ("test2", g_model.expoData[0].name); + EXPECT_EQ(MIXSRC_Rud, g_model.expoData[0].srcRaw); + EXPECT_EQ(-56, g_model.expoData[0].weight); + EXPECT_EQ(0, g_model.expoData[0].offset); + EXPECT_EQ(0, g_model.expoData[0].swtch); + + EXPECT_EQ(3, (int)g_model.expoData[1].chn); + EXPECT_ZSTREQ("test1", g_model.expoData[1].name); + EXPECT_EQ(MIXSRC_Thr, g_model.expoData[1].srcRaw); + EXPECT_EQ(56, g_model.expoData[1].weight); + EXPECT_EQ(3, g_model.expoData[1].offset); + EXPECT_EQ(2, g_model.expoData[1].swtch); + + // add another line after existing lines on Input4 + luaExecStr("model.insertInput(3, model.getInputsCount(3), {name='test3', source=MIXSRC_Ail, weight=100})"); + EXPECT_EQ(3, (int)g_model.expoData[0].chn); + EXPECT_ZSTREQ("test2", g_model.expoData[0].name); + EXPECT_EQ(MIXSRC_Rud, g_model.expoData[0].srcRaw); + EXPECT_EQ(-56, g_model.expoData[0].weight); + EXPECT_EQ(0, g_model.expoData[0].offset); + EXPECT_EQ(0, g_model.expoData[0].swtch); + + EXPECT_EQ(3, (int)g_model.expoData[1].chn); + EXPECT_ZSTREQ("test1", g_model.expoData[1].name); + EXPECT_EQ(MIXSRC_Thr, g_model.expoData[1].srcRaw); + EXPECT_EQ(56, g_model.expoData[1].weight); + EXPECT_EQ(3, g_model.expoData[1].offset); + EXPECT_EQ(2, g_model.expoData[1].swtch); + + EXPECT_EQ(3, (int)g_model.expoData[2].chn); + EXPECT_ZSTREQ("test3", g_model.expoData[2].name); + EXPECT_EQ(MIXSRC_Ail, g_model.expoData[2].srcRaw); + EXPECT_EQ(100, g_model.expoData[2].weight); + EXPECT_EQ(0, g_model.expoData[2].offset); + EXPECT_EQ(0, g_model.expoData[2].swtch); + + // verify number of lines for Input4 + luaExecStr("noInputs = model.getInputsCount(3)"); + luaExecStr("if noInputs ~= 3 then error('getInputsCount()') end"); + +} + +#endif // #if defined(LUA) diff --git a/radio/src/tests/mixer.cpp b/radio/src/tests/mixer.cpp index 8d21d4f32..1ffa3ff95 100644 --- a/radio/src/tests/mixer.cpp +++ b/radio/src/tests/mixer.cpp @@ -1,1027 +1,1011 @@ -/* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer - * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ - * - * 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 "gtests.h" -#include "../templates.h" - -#define CHECK_NO_MOVEMENT(channel, value, duration) \ - for (int i=1; i<=(duration); i++) { \ - evalFlightModeMixes(e_perout_mode_normal, 1); \ - EXPECT_EQ(chans[(channel)], (value)); \ - } - -#define CHECK_SLOW_MOVEMENT(channel, sign, duration) \ - do { \ - for (int i=1; i<=(duration); i++) { \ - evalFlightModeMixes(e_perout_mode_normal, 1); \ - lastAct = lastAct + (sign) * (1<<19)/500; /* 100 on ARM */ \ - EXPECT_EQ(chans[(channel)], 256 * (lastAct >> 8)); \ - } \ - } while (0) - -#define CHECK_DELAY(channel, duration) \ - do { \ - int32_t value = chans[(channel)]; \ - for (int i=1; i<=(duration); i++) { \ - evalFlightModeMixes(e_perout_mode_normal, 1); \ - EXPECT_EQ(chans[(channel)], value); \ - } \ - } while (0) - -TEST(Trims, throttleTrim) -{ - SYSTEM_RESET(); - MODEL_RESET(); - modelDefault(0); - g_model.thrTrim = 1; - // stick max + trim max - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1024); - // stick max + trim min - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1024); - // stick min + trim max - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+500); - // stick min + trim mid - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+250); - // stick min + trim min - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024); - - // now the same tests with extended Trims - g_model.extendedTrims = 1; - // stick max + trim max - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1024); - // stick max + trim min - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1024); - // stick min + trim max - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+2000); - // stick min + trim mid - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+1000); - // stick min + trim min - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024); - -} - -TEST(Trims, invertedThrottlePlusThrottleTrim) -{ - MODEL_RESET(); - modelDefault(0); - g_model.throttleReversed = 1; - g_model.thrTrim = 1; - // stick max + trim max - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024); - // stick max + trim mid - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+250); - // stick max + trim min - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+500); - // stick min + trim max - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], +1024); - // stick min + trim min - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], +1024); - - // now the same tests with extended Trims - g_model.extendedTrims = 1; - // stick max + trim max - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024); - // stick max + trim mid - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+1000); - // stick max + trim min - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], -1024+2000); - // stick min + trim max - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], +1024); - // stick min + trim min - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], +1024); -} - -TEST(Trims, throttleTrimWithZeroWeightOnThrottle) -{ - MODEL_RESET(); - modelDefault(0); - g_model.thrTrim = 1; -#if defined(PCBTARANIS) - // the input already exists - ExpoData *expo = expoAddress(THR_STICK); -#else - ExpoData *expo = expoAddress(0); - expo->mode = 3; - expo->chn = THR_STICK; -#endif - expo->weight = 0; - // stick max + trim max - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 250); - // stick max + trim mid - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_LE(abs(channelOutputs[2] - 125), 1); //can't use precise comparison here because of lower precision math on 9X - // stick max + trim min - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - // stick min + trim max - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 250); - // stick min + trim mid - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_LE(abs(channelOutputs[2] - 125), 1); - // stick min + trim min - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - - // now some tests with extended Trims - g_model.extendedTrims = 1; - // trim min + various stick positions = should always be same value - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); - anaInValues[THR_STICK] = -1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - anaInValues[THR_STICK] = -300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - anaInValues[THR_STICK] = +300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - anaInValues[THR_STICK] = +1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - - // trim max + various stick positions = should always be same value - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); - anaInValues[THR_STICK] = -1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); - anaInValues[THR_STICK] = -300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); - anaInValues[THR_STICK] = +300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); - anaInValues[THR_STICK] = +1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); -} - -TEST(Trims, invertedThrottlePlusthrottleTrimWithZeroWeightOnThrottle) -{ - MODEL_RESET(); - modelDefault(0); - g_model.throttleReversed = 1; - g_model.thrTrim = 1; -#if defined(PCBTARANIS) - // the input already exists - ExpoData *expo = expoAddress(THR_STICK); -#else - ExpoData *expo = expoAddress(0); - expo->mode = 3; - expo->chn = THR_STICK; -#endif - expo->weight = 0; - // stick max + trim max - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - // stick max + trim mid - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_LE(abs(channelOutputs[2] - 125), 1); - // stick max + trim min - anaInValues[THR_STICK] = +1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 250); - // stick min + trim max - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MAX); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - // stick min + trim mid - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, 0); - evalMixes(1); - EXPECT_LE(abs(channelOutputs[2] - 125), 1); - // stick min + trim min - anaInValues[THR_STICK] = -1024; - setTrimValue(0, THR_STICK, TRIM_MIN); - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 250); - - // now some tests with extended Trims - g_model.extendedTrims = 1; - // trim min + various stick positions = should always be same value - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); - anaInValues[THR_STICK] = -1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); - anaInValues[THR_STICK] = -300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); - anaInValues[THR_STICK] = +300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); - anaInValues[THR_STICK] = +1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 1000); - - // trim max + various stick positions = should always be same value - setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); - anaInValues[THR_STICK] = -1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - anaInValues[THR_STICK] = -300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - anaInValues[THR_STICK] = +300; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); - anaInValues[THR_STICK] = +1024; - evalMixes(1); - EXPECT_EQ(channelOutputs[2], 0); -} - -#if !defined(PCBTARANIS) -TEST(Trims, greaterTrimLink) -{ - MODEL_RESET(); - setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP3 trim - setTrimValue(3, RUD_STICK, 32); - EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(1, RUD_STICK), RUD_STICK), 32); -} - -TEST(Trims, chainedTrims) -{ - MODEL_RESET(); - setTrimValue(0, RUD_STICK, 32); - setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+1); // link to FP0 trim - setTrimValue(2, RUD_STICK, TRIM_EXTENDED_MAX+2); // link to FP1 trim - EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(0, RUD_STICK), RUD_STICK), 32); -} - -TEST(Trims, infiniteChainedTrims) -{ - MODEL_RESET(); - setTrimValue(0, RUD_STICK, 32); - setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP3 trim - setTrimValue(2, RUD_STICK, TRIM_EXTENDED_MAX+2); // link to FP1 trim - setTrimValue(3, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP2 trim - EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(0, RUD_STICK), RUD_STICK), 32); -} -#endif - -TEST(Trims, CopyTrimsToOffset) -{ - MODEL_RESET(); - modelDefault(0); - setTrimValue(0, ELE_STICK, -100); // -100 on elevator -#if defined(CPUARM) - evalFunctions(g_model.customFn, modelFunctionsContext); // it disables all safety channels - copyTrimsToOffset(1); - EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged - EXPECT_EQ(g_model.limitData[1].offset, -195); -#else - evalFunctions(); // it disables all safety channels - copyTrimsToOffset(1); - EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged - EXPECT_EQ(g_model.limitData[1].offset, -200); -#endif -} - -TEST(Trims, CopySticksToOffset) -{ - MODEL_RESET(); - modelDefault(0); - anaInValues[ELE_STICK] = -100; -#if defined(CPUARM) - doMixerCalculations(); -#else - perMain(); -#endif - copySticksToOffset(1); - EXPECT_EQ(g_model.limitData[1].offset, -97); -} - -TEST(Trims, InstantTrim) -{ - MODEL_RESET(); - modelDefault(0); - anaInValues[AIL_STICK] = 50; - instantTrim(); - EXPECT_EQ(25, getTrimValue(0, AIL_STICK)); -} - -#if defined(PCBTARANIS) -TEST(Trims, InstantTrimNegativeCurve) -{ - MODEL_RESET(); - modelDefault(0); - ExpoData *expo = expoAddress(AIL_STICK); - expo->curve.type = CURVE_REF_CUSTOM; - expo->curve.value = 1; - g_model.points[0] = -100; - g_model.points[1] = -75; - g_model.points[2] = -50; - g_model.points[3] = -25; - g_model.points[4] = 0; - anaInValues[AIL_STICK] = 512; - instantTrim(); - EXPECT_EQ(128, getTrimValue(0, AIL_STICK)); -} -#endif - -TEST(Curves, LinearIntpol) -{ - MODEL_RESET(); - for (int8_t i=-2; i<=2; i++) { - g_model.points[2+i] = 50*i; - } - EXPECT_EQ(applyCustomCurve(-1024, 0), -1024); - EXPECT_EQ(applyCustomCurve(0, 0), 0); - EXPECT_EQ(applyCustomCurve(1024, 0), 1024); - EXPECT_EQ(applyCustomCurve(-192, 0), -192); -} - - -#if !defined(CPUARM) -TEST(FlightModes, nullFadeOut_posFadeIn) -{ - MODEL_RESET(); - g_model.flightModeData[1].swtch = SWSRC_ID1; - g_model.flightModeData[1].fadeIn = 15; - perMain(); - simuSetSwitch(3, 0); - perMain(); -} - -TEST(Mixer, R2029Comment) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].srcRaw = MIXSRC_CH2; - g_model.mixData[0].swtch = -SWSRC_THR; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 1; - g_model.mixData[1].srcRaw = MIXSRC_Thr; - g_model.mixData[1].swtch = SWSRC_THR; - g_model.mixData[1].weight = 100; - anaInValues[THR_STICK] = 1024; - simuSetSwitch(0, 1); - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); - EXPECT_EQ(chans[1], CHANNEL_MAX); - simuSetSwitch(0, 0); - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); - EXPECT_EQ(chans[1], 0); - simuSetSwitch(0, 1); - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); - EXPECT_EQ(chans[1], CHANNEL_MAX); -} - -TEST(Mixer, Cascaded3Channels) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].srcRaw = MIXSRC_CH2; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 1; - g_model.mixData[1].srcRaw = MIXSRC_CH3; - g_model.mixData[1].weight = 100; - g_model.mixData[2].destCh = 2; - g_model.mixData[2].srcRaw = MIXSRC_THR; - g_model.mixData[2].weight = 100; - simuSetSwitch(0, 1); - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], CHANNEL_MAX); - EXPECT_EQ(chans[1], CHANNEL_MAX); - EXPECT_EQ(chans[2], CHANNEL_MAX); -} - -TEST(Mixer, CascadedOrderedChannels) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].srcRaw = MIXSRC_THR; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 1; - g_model.mixData[1].srcRaw = MIXSRC_CH1; - g_model.mixData[1].weight = 100; - simuSetSwitch(0, 1); - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], CHANNEL_MAX); - EXPECT_EQ(chans[1], CHANNEL_MAX); -} - -TEST(Mixer, Cascaded5Channels) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].srcRaw = MIXSRC_CH2; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 1; - g_model.mixData[1].srcRaw = MIXSRC_CH3; - g_model.mixData[1].weight = 100; - g_model.mixData[2].destCh = 2; - g_model.mixData[2].srcRaw = MIXSRC_CH4; - g_model.mixData[2].weight = 100; - g_model.mixData[3].destCh = 3; - g_model.mixData[3].srcRaw = MIXSRC_CH5; - g_model.mixData[3].weight = 100; - g_model.mixData[4].destCh = 4; - g_model.mixData[4].srcRaw = MIXSRC_THR; - g_model.mixData[4].weight = 100; - for (uint8_t i=0; i<10; i++) { - simuSetSwitch(0, 1); - doMixerCalculations(); - EXPECT_EQ(chans[0], CHANNEL_MAX); - EXPECT_EQ(chans[1], CHANNEL_MAX); - EXPECT_EQ(chans[2], CHANNEL_MAX); - EXPECT_EQ(chans[3], CHANNEL_MAX); - EXPECT_EQ(chans[4], CHANNEL_MAX); - simuSetSwitch(0, 0); - doMixerCalculations(); - EXPECT_EQ(chans[0], -CHANNEL_MAX); - EXPECT_EQ(chans[1], -CHANNEL_MAX); - EXPECT_EQ(chans[2], -CHANNEL_MAX); - EXPECT_EQ(chans[3], -CHANNEL_MAX); - EXPECT_EQ(chans[4], -CHANNEL_MAX); - } -} -#endif - -TEST(Mixer, InfiniteRecursiveChannels) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].srcRaw = MIXSRC_CH2; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 1; - g_model.mixData[1].srcRaw = MIXSRC_CH3; - g_model.mixData[1].weight = 100; - g_model.mixData[2].destCh = 2; - g_model.mixData[2].srcRaw = MIXSRC_CH1; - g_model.mixData[2].weight = 100; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[2], 0); - EXPECT_EQ(chans[1], 0); - EXPECT_EQ(chans[0], 0); -} - -TEST(Mixer, BlockingChannel) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].srcRaw = MIXSRC_CH1; - g_model.mixData[0].weight = 100; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); -} - -TEST(Mixer, RecursiveAddChannel) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 50; - g_model.mixData[1].destCh = 0; - g_model.mixData[1].mltpx = MLTPX_ADD; - g_model.mixData[1].srcRaw = MIXSRC_CH2; - g_model.mixData[1].weight = 100; - g_model.mixData[2].destCh = 1; - g_model.mixData[2].srcRaw = MIXSRC_Rud; - g_model.mixData[2].weight = 100; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], CHANNEL_MAX/2); - EXPECT_EQ(chans[1], 0); -} - -TEST(Mixer, RecursiveAddChannelAfterInactivePhase) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.flightModeData[1].swtch = SWSRC_ID1; - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_CH2; - g_model.mixData[0].flightModes = 0b11110; - g_model.mixData[0].weight = 50; - g_model.mixData[1].destCh = 0; - g_model.mixData[1].mltpx = MLTPX_ADD; - g_model.mixData[1].srcRaw = MIXSRC_MAX; - g_model.mixData[1].flightModes = 0b11101; - g_model.mixData[1].weight = 50; - g_model.mixData[2].destCh = 1; - g_model.mixData[2].srcRaw = MIXSRC_MAX; - g_model.mixData[2].weight = 100; - simuSetSwitch(3, -1); -#if defined(CPUARM) - doMixerCalculations(); -#else - perMain(); -#endif - EXPECT_EQ(chans[0], CHANNEL_MAX/2); - EXPECT_EQ(chans[1], CHANNEL_MAX); - simuSetSwitch(3, 0); -#if defined(CPUARM) - doMixerCalculations(); -#else - perMain(); -#endif - EXPECT_EQ(chans[0], CHANNEL_MAX/2); - EXPECT_EQ(chans[1], CHANNEL_MAX); -} - -#if !defined(CPUARM) -TEST(Mixer, SlowOnSwitch) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 100; - g_model.mixData[0].swtch = SWSRC_THR; - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = SLOW_STEP*5; - - s_mixer_first_run_done = true; - - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); - - simuSetSwitch(0, 1); - CHECK_SLOW_MOVEMENT(0, +1, 250); - - simuSetSwitch(0, -1); - CHECK_SLOW_MOVEMENT(0, -1, 250); -} - -TEST(Mixer, SlowUpOnSwitch) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 100; - g_model.mixData[0].swtch = SWSRC_THR; - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = 0; - - simuSetSwitch(0, 0); - evalFlightModeMixes(e_perout_mode_normal, 0); - s_mixer_first_run_done = true; - EXPECT_EQ(chans[0], 0); - - simuSetSwitch(0, 1); - CHECK_SLOW_MOVEMENT(0, +1, 250); - - simuSetSwitch(0, 0); - evalFlightModeMixes(e_perout_mode_normal, 1); - EXPECT_EQ(chans[0], 0); - - lastAct = 0; - simuSetSwitch(0, 1); - CHECK_SLOW_MOVEMENT(0, +1, 100); -} -#endif - -TEST(Mixer, SlowOnPhase) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.flightModeData[1].swtch = TR(SWSRC_THR, SWSRC_SA0); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 100; - g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 /*only enabled in phase 0*/; - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = SLOW_STEP*5; - - s_mixer_first_run_done = true; - mixerCurrentFlightMode = 0; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); - - CHECK_SLOW_MOVEMENT(0, +1, 250); - - mixerCurrentFlightMode = 1; - CHECK_SLOW_MOVEMENT(0, -1, 250); -} - -#if !defined(CPUARM) -TEST(Mixer, SlowOnSwitchAndPhase) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.flightModeData[1].swtch = TR(SWSRC_THR, SWSRC_SA0); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 100; - g_model.mixData[0].swtch = TR(SWSRC_THR, SWSRC_SA0); -#if defined(CPUARM) - g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 + 0x20 + 0x40 + 0x80 + 0x100 /*only enabled in phase 0*/; -#else - g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 /*only enabled in phase 0*/; -#endif - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = SLOW_STEP*5; - - s_mixer_first_run_done = true; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); - - simuSetSwitch(0, 1); - mixerCurrentFlightMode = 0; - CHECK_SLOW_MOVEMENT(0, +1, 250); - - simuSetSwitch(0, -1); - mixerCurrentFlightMode = 1; - CHECK_SLOW_MOVEMENT(0, -1, 250); -} -#endif - -TEST(Mixer, SlowOnSwitchSource) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = TR(MIXSRC_THR, MIXSRC_SA); - g_model.mixData[0].weight = 100; - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = SLOW_STEP*5; -#if defined(PCBTARANIS) - g_eeGeneral.switchConfig = 0x03; -#endif - - s_mixer_first_run_done = true; - - simuSetSwitch(0, -1); - CHECK_SLOW_MOVEMENT(0, -1, 250); - EXPECT_EQ(chans[0], -CHANNEL_MAX); - - simuSetSwitch(0, 1); - CHECK_SLOW_MOVEMENT(0, +1, 500); -} - -TEST(Mixer, SlowDisabledOnStartup) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 100; - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = SLOW_STEP*5; - - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], CHANNEL_MAX); -} - -TEST(Mixer, DelayOnSwitch) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 100; - g_model.mixData[0].swtch = TR(SWSRC_THR, SWSRC_SA2); - g_model.mixData[0].delayUp = DELAY_STEP*5; - g_model.mixData[0].delayDown = DELAY_STEP*5; - - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], 0); - - simuSetSwitch(0, 1); - CHECK_DELAY(0, 500); - - evalFlightModeMixes(e_perout_mode_normal, 1); - EXPECT_EQ(chans[0], CHANNEL_MAX); - - simuSetSwitch(0, 0); - CHECK_DELAY(0, 500); - - evalFlightModeMixes(e_perout_mode_normal, 1); - EXPECT_EQ(chans[0], 0); -} - -#if !defined(CPUARM) -TEST(Mixer, SlowAndDelayOnReplace3POSSource) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_REP; - g_model.mixData[0].srcRaw = MIXSRC_3POS; - g_model.mixData[0].weight = 100; - g_model.mixData[0].delayUp = 10; - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = SLOW_STEP*5; - - s_mixer_first_run_done = true; - - simuSetSwitch(3, -1); - CHECK_SLOW_MOVEMENT(0, -1, 250); - EXPECT_EQ(chans[0], -CHANNEL_MAX); - - simuSetSwitch(3, 0); - CHECK_DELAY(0, 500); - CHECK_SLOW_MOVEMENT(0, +1, 250/*half course*/); - EXPECT_EQ(chans[0], 0); - - simuSetSwitch(3, 1); - CHECK_DELAY(0, 500); - CHECK_SLOW_MOVEMENT(0, +1, 250); -} -#endif - -#if !defined(CPUARM) -TEST(Mixer, SlowOnSwitchReplace) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 50; - g_model.mixData[1].destCh = 0; - g_model.mixData[1].mltpx = MLTPX_REP; - g_model.mixData[1].srcRaw = MIXSRC_MAX; - g_model.mixData[1].weight = 100; - g_model.mixData[1].swtch = SWSRC_THR; - g_model.mixData[1].speedDown = SLOW_STEP*5; - - simuSetSwitch(0, 0); - evalFlightModeMixes(e_perout_mode_normal, 1); - EXPECT_EQ(chans[0], CHANNEL_MAX/2); - - simuSetSwitch(0, 1); - evalFlightModeMixes(e_perout_mode_normal, 1); - // slow is not applied, but it's better than the first mix not applied at all! - EXPECT_EQ(chans[0], CHANNEL_MAX); - - simuSetSwitch(0, 0); - evalFlightModeMixes(e_perout_mode_normal, 1); - // slow is not applied, but it's better than the first mix not applied at all! - EXPECT_EQ(chans[0], CHANNEL_MAX/2); -} -#endif - -#if !defined(PCBTARANIS) -TEST(Mixer, NoTrimOnInactiveMix) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_Thr; - g_model.mixData[0].weight = 100; - g_model.mixData[0].swtch = SWSRC_THR; - g_model.mixData[0].speedUp = SLOW_STEP*5; - g_model.mixData[0].speedDown = SLOW_STEP*5; - setTrimValue(0, 2, 256); - - s_mixer_first_run_done = true; - - simuSetSwitch(0, 1); - CHECK_SLOW_MOVEMENT(0, 1, 100); - - simuSetSwitch(0, -1); - CHECK_SLOW_MOVEMENT(0, -1, 100); -} -#endif - -TEST(Mixer, SlowOnMultiply) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_MAX; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 0; - g_model.mixData[1].mltpx = MLTPX_MUL; - g_model.mixData[1].srcRaw = MIXSRC_MAX; - g_model.mixData[1].weight = 100; - g_model.mixData[1].swtch = TR(SWSRC_THR, SWSRC_SA0); - g_model.mixData[1].speedUp = SLOW_STEP*5; - g_model.mixData[1].speedDown = SLOW_STEP*5; - - s_mixer_first_run_done = true; - - simuSetSwitch(0, 1); - CHECK_SLOW_MOVEMENT(0, 1, 250); - - simuSetSwitch(0, -1); - CHECK_NO_MOVEMENT(0, CHANNEL_MAX, 250); - - simuSetSwitch(0, 1); - CHECK_NO_MOVEMENT(0, CHANNEL_MAX, 250); -} - - -#if defined(HELI) && defined(VIRTUALINPUTS) -TEST(Heli, BasicTest) -{ - MODEL_RESET(); - applyDefaultTemplate(); - g_model.swashR.collectiveSource = MIXSRC_Thr; - g_model.swashR.elevatorSource = MIXSRC_Ele; - g_model.swashR.aileronSource = MIXSRC_Ail; - g_model.swashR.collectiveWeight = 100; - g_model.swashR.elevatorWeight = 100; - g_model.swashR.aileronWeight = 100; - g_model.swashR.type = SWASH_TYPE_120; - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_CYC1; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 1; - g_model.mixData[1].mltpx = MLTPX_ADD; - g_model.mixData[1].srcRaw = MIXSRC_CYC2; - g_model.mixData[1].weight = 100; - g_model.mixData[2].destCh = 2; - g_model.mixData[2].mltpx = MLTPX_ADD; - g_model.mixData[2].srcRaw = MIXSRC_CYC3; - g_model.mixData[2].weight = 100; - anaInValues[ELE_STICK] = 1024; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], -CHANNEL_MAX); - EXPECT_EQ(chans[1], CHANNEL_MAX/2); - EXPECT_EQ(chans[2], CHANNEL_MAX/2); -} - -TEST(Heli, Mode2Test) -{ - MODEL_RESET(); - g_eeGeneral.templateSetup = 2; - applyDefaultTemplate(); - g_model.swashR.collectiveSource = MIXSRC_Thr; - g_model.swashR.elevatorSource = MIXSRC_Ele; - g_model.swashR.aileronSource = MIXSRC_Ail; - g_model.swashR.collectiveWeight = 100; - g_model.swashR.elevatorWeight = 100; - g_model.swashR.aileronWeight = 100; - g_model.swashR.type = SWASH_TYPE_120; - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_CYC1; - g_model.mixData[0].weight = 100; - g_model.mixData[1].destCh = 1; - g_model.mixData[1].mltpx = MLTPX_ADD; - g_model.mixData[1].srcRaw = MIXSRC_CYC2; - g_model.mixData[1].weight = 100; - g_model.mixData[2].destCh = 2; - g_model.mixData[2].mltpx = MLTPX_ADD; - g_model.mixData[2].srcRaw = MIXSRC_CYC3; - g_model.mixData[2].weight = 100; - anaInValues[ELE_STICK] = 1024; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], -CHANNEL_MAX); - EXPECT_EQ(chans[1], CHANNEL_MAX/2); - EXPECT_EQ(chans[2], CHANNEL_MAX/2); -} -#endif - -#if defined(HELI) && !defined(PCBTARANIS) -TEST(Heli, SimpleTest) -{ - MODEL_RESET(); - applyTemplate(TMPL_HELI_SETUP); - anaInValues[ELE_STICK] = 1024; - evalFlightModeMixes(e_perout_mode_normal, 0); - EXPECT_EQ(chans[0], -CHANNEL_MAX); - EXPECT_EQ(chans[1], CHANNEL_MAX/2); - EXPECT_EQ(chans[1], CHANNEL_MAX/2); -} -#endif - -TEST(Trainer, UnpluggedTest) -{ - MODEL_RESET(); - MIXER_RESET(); - g_model.mixData[0].destCh = 0; - g_model.mixData[0].mltpx = MLTPX_ADD; - g_model.mixData[0].srcRaw = MIXSRC_FIRST_TRAINER; - g_model.mixData[0].weight = 100; - g_model.mixData[0].delayUp = DELAY_STEP*5; - g_model.mixData[0].delayDown = DELAY_STEP*5; - ppmInputValidityTimer = 0; - ppmInput[0] = 1024; - CHECK_DELAY(0, 5000); -} +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "gtests.h" +#include "../templates.h" + +#define CHECK_NO_MOVEMENT(channel, value, duration) \ + for (int i=1; i<=(duration); i++) { \ + evalFlightModeMixes(e_perout_mode_normal, 1); \ + EXPECT_EQ(chans[(channel)], (value)); \ + } + +#define CHECK_SLOW_MOVEMENT(channel, sign, duration) \ + do { \ + for (int i=1; i<=(duration); i++) { \ + evalFlightModeMixes(e_perout_mode_normal, 1); \ + lastAct = lastAct + (sign) * (1<<19)/500; /* 100 on ARM */ \ + EXPECT_EQ(chans[(channel)], 256 * (lastAct >> 8)); \ + } \ + } while (0) + +#define CHECK_DELAY(channel, duration) \ + do { \ + int32_t value = chans[(channel)]; \ + for (int i=1; i<=(duration); i++) { \ + evalFlightModeMixes(e_perout_mode_normal, 1); \ + EXPECT_EQ(chans[(channel)], value); \ + } \ + } while (0) + +TEST(Trims, throttleTrim) +{ + SYSTEM_RESET(); + MODEL_RESET(); + modelDefault(0); + g_model.thrTrim = 1; + // stick max + trim max + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1024); + // stick max + trim min + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1024); + // stick min + trim max + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+500); + // stick min + trim mid + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+250); + // stick min + trim min + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024); + + // now the same tests with extended Trims + g_model.extendedTrims = 1; + // stick max + trim max + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1024); + // stick max + trim min + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1024); + // stick min + trim max + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+2000); + // stick min + trim mid + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+1000); + // stick min + trim min + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024); + +} + +TEST(Trims, invertedThrottlePlusThrottleTrim) +{ + MODEL_RESET(); + modelDefault(0); + g_model.throttleReversed = 1; + g_model.thrTrim = 1; + // stick max + trim max + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024); + // stick max + trim mid + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+250); + // stick max + trim min + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+500); + // stick min + trim max + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], +1024); + // stick min + trim min + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], +1024); + + // now the same tests with extended Trims + g_model.extendedTrims = 1; + // stick max + trim max + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024); + // stick max + trim mid + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+1000); + // stick max + trim min + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], -1024+2000); + // stick min + trim max + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], +1024); + // stick min + trim min + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], +1024); +} + +TEST(Trims, throttleTrimWithZeroWeightOnThrottle) +{ + MODEL_RESET(); + modelDefault(0); + g_model.thrTrim = 1; +#if defined(PCBTARANIS) + // the input already exists + ExpoData *expo = expoAddress(THR_STICK); +#else + ExpoData *expo = expoAddress(0); + expo->mode = 3; + expo->chn = THR_STICK; +#endif + expo->weight = 0; + // stick max + trim max + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 250); + // stick max + trim mid + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_LE(abs(channelOutputs[2] - 125), 1); //can't use precise comparison here because of lower precision math on 9X + // stick max + trim min + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + // stick min + trim max + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 250); + // stick min + trim mid + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_LE(abs(channelOutputs[2] - 125), 1); + // stick min + trim min + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + + // now some tests with extended Trims + g_model.extendedTrims = 1; + // trim min + various stick positions = should always be same value + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); + anaInValues[THR_STICK] = -1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + anaInValues[THR_STICK] = -300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + anaInValues[THR_STICK] = +300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + anaInValues[THR_STICK] = +1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + + // trim max + various stick positions = should always be same value + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); + anaInValues[THR_STICK] = -1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); + anaInValues[THR_STICK] = -300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); + anaInValues[THR_STICK] = +300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); + anaInValues[THR_STICK] = +1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); +} + +TEST(Trims, invertedThrottlePlusthrottleTrimWithZeroWeightOnThrottle) +{ + MODEL_RESET(); + modelDefault(0); + g_model.throttleReversed = 1; + g_model.thrTrim = 1; +#if defined(PCBTARANIS) + // the input already exists + ExpoData *expo = expoAddress(THR_STICK); +#else + ExpoData *expo = expoAddress(0); + expo->mode = 3; + expo->chn = THR_STICK; +#endif + expo->weight = 0; + // stick max + trim max + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + // stick max + trim mid + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_LE(abs(channelOutputs[2] - 125), 1); + // stick max + trim min + anaInValues[THR_STICK] = +1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 250); + // stick min + trim max + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MAX); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + // stick min + trim mid + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, 0); + evalMixes(1); + EXPECT_LE(abs(channelOutputs[2] - 125), 1); + // stick min + trim min + anaInValues[THR_STICK] = -1024; + setTrimValue(0, THR_STICK, TRIM_MIN); + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 250); + + // now some tests with extended Trims + g_model.extendedTrims = 1; + // trim min + various stick positions = should always be same value + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN); + anaInValues[THR_STICK] = -1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); + anaInValues[THR_STICK] = -300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); + anaInValues[THR_STICK] = +300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); + anaInValues[THR_STICK] = +1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 1000); + + // trim max + various stick positions = should always be same value + setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX); + anaInValues[THR_STICK] = -1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + anaInValues[THR_STICK] = -300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + anaInValues[THR_STICK] = +300; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); + anaInValues[THR_STICK] = +1024; + evalMixes(1); + EXPECT_EQ(channelOutputs[2], 0); +} + +#if !defined(PCBTARANIS) +TEST(Trims, greaterTrimLink) +{ + MODEL_RESET(); + setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP3 trim + setTrimValue(3, RUD_STICK, 32); + EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(1, RUD_STICK), RUD_STICK), 32); +} + +TEST(Trims, chainedTrims) +{ + MODEL_RESET(); + setTrimValue(0, RUD_STICK, 32); + setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+1); // link to FP0 trim + setTrimValue(2, RUD_STICK, TRIM_EXTENDED_MAX+2); // link to FP1 trim + EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(0, RUD_STICK), RUD_STICK), 32); +} + +TEST(Trims, infiniteChainedTrims) +{ + MODEL_RESET(); + setTrimValue(0, RUD_STICK, 32); + setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP3 trim + setTrimValue(2, RUD_STICK, TRIM_EXTENDED_MAX+2); // link to FP1 trim + setTrimValue(3, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP2 trim + EXPECT_EQ(getRawTrimValue(getTrimFlightPhase(0, RUD_STICK), RUD_STICK), 32); +} +#endif + +TEST(Trims, CopyTrimsToOffset) +{ + MODEL_RESET(); + modelDefault(0); + setTrimValue(0, ELE_STICK, -100); // -100 on elevator +#if defined(CPUARM) + evalFunctions(g_model.customFn, modelFunctionsContext); // it disables all safety channels + copyTrimsToOffset(1); + EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged + EXPECT_EQ(g_model.limitData[1].offset, -195); +#else + evalFunctions(); // it disables all safety channels + copyTrimsToOffset(1); + EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged + EXPECT_EQ(g_model.limitData[1].offset, -200); +#endif +} + +TEST(Trims, CopySticksToOffset) +{ + MODEL_RESET(); + modelDefault(0); + anaInValues[ELE_STICK] = -100; +#if defined(CPUARM) + doMixerCalculations(); +#else + perMain(); +#endif + copySticksToOffset(1); + EXPECT_EQ(g_model.limitData[1].offset, -97); +} + +TEST(Trims, InstantTrim) +{ + MODEL_RESET(); + modelDefault(0); + anaInValues[AIL_STICK] = 50; + instantTrim(); + EXPECT_EQ(25, getTrimValue(0, AIL_STICK)); +} + +#if defined(PCBTARANIS) +TEST(Trims, InstantTrimNegativeCurve) +{ + MODEL_RESET(); + modelDefault(0); + ExpoData *expo = expoAddress(AIL_STICK); + expo->curve.type = CURVE_REF_CUSTOM; + expo->curve.value = 1; + g_model.points[0] = -100; + g_model.points[1] = -75; + g_model.points[2] = -50; + g_model.points[3] = -25; + g_model.points[4] = 0; + anaInValues[AIL_STICK] = 512; + instantTrim(); + EXPECT_EQ(128, getTrimValue(0, AIL_STICK)); +} +#endif + +TEST(Curves, LinearIntpol) +{ + MODEL_RESET(); + for (int8_t i=-2; i<=2; i++) { + g_model.points[2+i] = 50*i; + } + EXPECT_EQ(applyCustomCurve(-1024, 0), -1024); + EXPECT_EQ(applyCustomCurve(0, 0), 0); + EXPECT_EQ(applyCustomCurve(1024, 0), 1024); + EXPECT_EQ(applyCustomCurve(-192, 0), -192); +} + + +#if !defined(CPUARM) +TEST(FlightModes, nullFadeOut_posFadeIn) +{ + MODEL_RESET(); + g_model.flightModeData[1].swtch = SWSRC_ID1; + g_model.flightModeData[1].fadeIn = 15; + perMain(); + simuSetSwitch(3, 0); + perMain(); +} + +TEST(Mixer, R2029Comment) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].srcRaw = MIXSRC_CH2; + g_model.mixData[0].swtch = -SWSRC_THR; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 1; + g_model.mixData[1].srcRaw = MIXSRC_Thr; + g_model.mixData[1].swtch = SWSRC_THR; + g_model.mixData[1].weight = 100; + anaInValues[THR_STICK] = 1024; + simuSetSwitch(0, 1); + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); + EXPECT_EQ(chans[1], CHANNEL_MAX); + simuSetSwitch(0, 0); + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); + EXPECT_EQ(chans[1], 0); + simuSetSwitch(0, 1); + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); + EXPECT_EQ(chans[1], CHANNEL_MAX); +} + +TEST(Mixer, Cascaded3Channels) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].srcRaw = MIXSRC_CH2; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 1; + g_model.mixData[1].srcRaw = MIXSRC_CH3; + g_model.mixData[1].weight = 100; + g_model.mixData[2].destCh = 2; + g_model.mixData[2].srcRaw = MIXSRC_THR; + g_model.mixData[2].weight = 100; + simuSetSwitch(0, 1); + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], CHANNEL_MAX); + EXPECT_EQ(chans[1], CHANNEL_MAX); + EXPECT_EQ(chans[2], CHANNEL_MAX); +} + +TEST(Mixer, CascadedOrderedChannels) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].srcRaw = MIXSRC_THR; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 1; + g_model.mixData[1].srcRaw = MIXSRC_CH1; + g_model.mixData[1].weight = 100; + simuSetSwitch(0, 1); + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], CHANNEL_MAX); + EXPECT_EQ(chans[1], CHANNEL_MAX); +} + +TEST(Mixer, Cascaded5Channels) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].srcRaw = MIXSRC_CH2; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 1; + g_model.mixData[1].srcRaw = MIXSRC_CH3; + g_model.mixData[1].weight = 100; + g_model.mixData[2].destCh = 2; + g_model.mixData[2].srcRaw = MIXSRC_CH4; + g_model.mixData[2].weight = 100; + g_model.mixData[3].destCh = 3; + g_model.mixData[3].srcRaw = MIXSRC_CH5; + g_model.mixData[3].weight = 100; + g_model.mixData[4].destCh = 4; + g_model.mixData[4].srcRaw = MIXSRC_THR; + g_model.mixData[4].weight = 100; + for (uint8_t i=0; i<10; i++) { + simuSetSwitch(0, 1); + doMixerCalculations(); + EXPECT_EQ(chans[0], CHANNEL_MAX); + EXPECT_EQ(chans[1], CHANNEL_MAX); + EXPECT_EQ(chans[2], CHANNEL_MAX); + EXPECT_EQ(chans[3], CHANNEL_MAX); + EXPECT_EQ(chans[4], CHANNEL_MAX); + simuSetSwitch(0, 0); + doMixerCalculations(); + EXPECT_EQ(chans[0], -CHANNEL_MAX); + EXPECT_EQ(chans[1], -CHANNEL_MAX); + EXPECT_EQ(chans[2], -CHANNEL_MAX); + EXPECT_EQ(chans[3], -CHANNEL_MAX); + EXPECT_EQ(chans[4], -CHANNEL_MAX); + } +} +#endif + +TEST(Mixer, InfiniteRecursiveChannels) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].srcRaw = MIXSRC_CH2; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 1; + g_model.mixData[1].srcRaw = MIXSRC_CH3; + g_model.mixData[1].weight = 100; + g_model.mixData[2].destCh = 2; + g_model.mixData[2].srcRaw = MIXSRC_CH1; + g_model.mixData[2].weight = 100; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[2], 0); + EXPECT_EQ(chans[1], 0); + EXPECT_EQ(chans[0], 0); +} + +TEST(Mixer, BlockingChannel) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].srcRaw = MIXSRC_CH1; + g_model.mixData[0].weight = 100; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); +} + +TEST(Mixer, RecursiveAddChannel) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 50; + g_model.mixData[1].destCh = 0; + g_model.mixData[1].mltpx = MLTPX_ADD; + g_model.mixData[1].srcRaw = MIXSRC_CH2; + g_model.mixData[1].weight = 100; + g_model.mixData[2].destCh = 1; + g_model.mixData[2].srcRaw = MIXSRC_Rud; + g_model.mixData[2].weight = 100; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], CHANNEL_MAX/2); + EXPECT_EQ(chans[1], 0); +} + +TEST(Mixer, RecursiveAddChannelAfterInactivePhase) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.flightModeData[1].swtch = SWSRC_ID1; + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_CH2; + g_model.mixData[0].flightModes = 0b11110; + g_model.mixData[0].weight = 50; + g_model.mixData[1].destCh = 0; + g_model.mixData[1].mltpx = MLTPX_ADD; + g_model.mixData[1].srcRaw = MIXSRC_MAX; + g_model.mixData[1].flightModes = 0b11101; + g_model.mixData[1].weight = 50; + g_model.mixData[2].destCh = 1; + g_model.mixData[2].srcRaw = MIXSRC_MAX; + g_model.mixData[2].weight = 100; + simuSetSwitch(3, -1); +#if defined(CPUARM) + doMixerCalculations(); +#else + perMain(); +#endif + EXPECT_EQ(chans[0], CHANNEL_MAX/2); + EXPECT_EQ(chans[1], CHANNEL_MAX); + simuSetSwitch(3, 0); +#if defined(CPUARM) + doMixerCalculations(); +#else + perMain(); +#endif + EXPECT_EQ(chans[0], CHANNEL_MAX/2); + EXPECT_EQ(chans[1], CHANNEL_MAX); +} + +#if !defined(CPUARM) +TEST(Mixer, SlowOnSwitch) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 100; + g_model.mixData[0].swtch = SWSRC_THR; + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = SLOW_STEP*5; + + s_mixer_first_run_done = true; + + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); + + simuSetSwitch(0, 1); + CHECK_SLOW_MOVEMENT(0, +1, 250); + + simuSetSwitch(0, -1); + CHECK_SLOW_MOVEMENT(0, -1, 250); +} + +TEST(Mixer, SlowUpOnSwitch) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 100; + g_model.mixData[0].swtch = SWSRC_THR; + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = 0; + + simuSetSwitch(0, 0); + evalFlightModeMixes(e_perout_mode_normal, 0); + s_mixer_first_run_done = true; + EXPECT_EQ(chans[0], 0); + + simuSetSwitch(0, 1); + CHECK_SLOW_MOVEMENT(0, +1, 250); + + simuSetSwitch(0, 0); + evalFlightModeMixes(e_perout_mode_normal, 1); + EXPECT_EQ(chans[0], 0); + + lastAct = 0; + simuSetSwitch(0, 1); + CHECK_SLOW_MOVEMENT(0, +1, 100); +} +#endif + +TEST(Mixer, SlowOnPhase) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.flightModeData[1].swtch = TR(SWSRC_THR, SWSRC_SA0); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 100; + g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 /*only enabled in phase 0*/; + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = SLOW_STEP*5; + + s_mixer_first_run_done = true; + mixerCurrentFlightMode = 0; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); + + CHECK_SLOW_MOVEMENT(0, +1, 250); + + mixerCurrentFlightMode = 1; + CHECK_SLOW_MOVEMENT(0, -1, 250); +} + +#if !defined(CPUARM) +TEST(Mixer, SlowOnSwitchAndPhase) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.flightModeData[1].swtch = TR(SWSRC_THR, SWSRC_SA0); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 100; + g_model.mixData[0].swtch = TR(SWSRC_THR, SWSRC_SA0); +#if defined(CPUARM) + g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 + 0x20 + 0x40 + 0x80 + 0x100 /*only enabled in phase 0*/; +#else + g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 /*only enabled in phase 0*/; +#endif + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = SLOW_STEP*5; + + s_mixer_first_run_done = true; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); + + simuSetSwitch(0, 1); + mixerCurrentFlightMode = 0; + CHECK_SLOW_MOVEMENT(0, +1, 250); + + simuSetSwitch(0, -1); + mixerCurrentFlightMode = 1; + CHECK_SLOW_MOVEMENT(0, -1, 250); +} +#endif + +TEST(Mixer, SlowOnSwitchSource) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = TR(MIXSRC_THR, MIXSRC_SA); + g_model.mixData[0].weight = 100; + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = SLOW_STEP*5; +#if defined(PCBTARANIS) + g_eeGeneral.switchConfig = 0x03; +#endif + + s_mixer_first_run_done = true; + + simuSetSwitch(0, -1); + CHECK_SLOW_MOVEMENT(0, -1, 250); + EXPECT_EQ(chans[0], -CHANNEL_MAX); + + simuSetSwitch(0, 1); + CHECK_SLOW_MOVEMENT(0, +1, 500); +} + +TEST(Mixer, SlowDisabledOnStartup) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 100; + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = SLOW_STEP*5; + + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], CHANNEL_MAX); +} + +TEST(Mixer, DelayOnSwitch) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 100; + g_model.mixData[0].swtch = TR(SWSRC_THR, SWSRC_SA2); + g_model.mixData[0].delayUp = DELAY_STEP*5; + g_model.mixData[0].delayDown = DELAY_STEP*5; + + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], 0); + + simuSetSwitch(0, 1); + CHECK_DELAY(0, 500); + + evalFlightModeMixes(e_perout_mode_normal, 1); + EXPECT_EQ(chans[0], CHANNEL_MAX); + + simuSetSwitch(0, 0); + CHECK_DELAY(0, 500); + + evalFlightModeMixes(e_perout_mode_normal, 1); + EXPECT_EQ(chans[0], 0); +} + +#if !defined(CPUARM) +TEST(Mixer, SlowAndDelayOnReplace3POSSource) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_REP; + g_model.mixData[0].srcRaw = MIXSRC_3POS; + g_model.mixData[0].weight = 100; + g_model.mixData[0].delayUp = 10; + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = SLOW_STEP*5; + + s_mixer_first_run_done = true; + + simuSetSwitch(3, -1); + CHECK_SLOW_MOVEMENT(0, -1, 250); + EXPECT_EQ(chans[0], -CHANNEL_MAX); + + simuSetSwitch(3, 0); + CHECK_DELAY(0, 500); + CHECK_SLOW_MOVEMENT(0, +1, 250/*half course*/); + EXPECT_EQ(chans[0], 0); + + simuSetSwitch(3, 1); + CHECK_DELAY(0, 500); + CHECK_SLOW_MOVEMENT(0, +1, 250); +} +#endif + +#if !defined(CPUARM) +TEST(Mixer, SlowOnSwitchReplace) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 50; + g_model.mixData[1].destCh = 0; + g_model.mixData[1].mltpx = MLTPX_REP; + g_model.mixData[1].srcRaw = MIXSRC_MAX; + g_model.mixData[1].weight = 100; + g_model.mixData[1].swtch = SWSRC_THR; + g_model.mixData[1].speedDown = SLOW_STEP*5; + + simuSetSwitch(0, 0); + evalFlightModeMixes(e_perout_mode_normal, 1); + EXPECT_EQ(chans[0], CHANNEL_MAX/2); + + simuSetSwitch(0, 1); + evalFlightModeMixes(e_perout_mode_normal, 1); + // slow is not applied, but it's better than the first mix not applied at all! + EXPECT_EQ(chans[0], CHANNEL_MAX); + + simuSetSwitch(0, 0); + evalFlightModeMixes(e_perout_mode_normal, 1); + // slow is not applied, but it's better than the first mix not applied at all! + EXPECT_EQ(chans[0], CHANNEL_MAX/2); +} +#endif + +#if !defined(PCBTARANIS) +TEST(Mixer, NoTrimOnInactiveMix) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_Thr; + g_model.mixData[0].weight = 100; + g_model.mixData[0].swtch = SWSRC_THR; + g_model.mixData[0].speedUp = SLOW_STEP*5; + g_model.mixData[0].speedDown = SLOW_STEP*5; + setTrimValue(0, 2, 256); + + s_mixer_first_run_done = true; + + simuSetSwitch(0, 1); + CHECK_SLOW_MOVEMENT(0, 1, 100); + + simuSetSwitch(0, -1); + CHECK_SLOW_MOVEMENT(0, -1, 100); +} +#endif + +TEST(Mixer, SlowOnMultiply) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_MAX; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 0; + g_model.mixData[1].mltpx = MLTPX_MUL; + g_model.mixData[1].srcRaw = MIXSRC_MAX; + g_model.mixData[1].weight = 100; + g_model.mixData[1].swtch = TR(SWSRC_THR, SWSRC_SA0); + g_model.mixData[1].speedUp = SLOW_STEP*5; + g_model.mixData[1].speedDown = SLOW_STEP*5; + + s_mixer_first_run_done = true; + + simuSetSwitch(0, 1); + CHECK_SLOW_MOVEMENT(0, 1, 250); + + simuSetSwitch(0, -1); + CHECK_NO_MOVEMENT(0, CHANNEL_MAX, 250); + + simuSetSwitch(0, 1); + CHECK_NO_MOVEMENT(0, CHANNEL_MAX, 250); +} + + +#if defined(HELI) && defined(VIRTUALINPUTS) +TEST(Heli, BasicTest) +{ + MODEL_RESET(); + applyDefaultTemplate(); + g_model.swashR.collectiveSource = MIXSRC_Thr; + g_model.swashR.elevatorSource = MIXSRC_Ele; + g_model.swashR.aileronSource = MIXSRC_Ail; + g_model.swashR.collectiveWeight = 100; + g_model.swashR.elevatorWeight = 100; + g_model.swashR.aileronWeight = 100; + g_model.swashR.type = SWASH_TYPE_120; + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_CYC1; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 1; + g_model.mixData[1].mltpx = MLTPX_ADD; + g_model.mixData[1].srcRaw = MIXSRC_CYC2; + g_model.mixData[1].weight = 100; + g_model.mixData[2].destCh = 2; + g_model.mixData[2].mltpx = MLTPX_ADD; + g_model.mixData[2].srcRaw = MIXSRC_CYC3; + g_model.mixData[2].weight = 100; + anaInValues[ELE_STICK] = 1024; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], -CHANNEL_MAX); + EXPECT_EQ(chans[1], CHANNEL_MAX/2); + EXPECT_EQ(chans[2], CHANNEL_MAX/2); +} + +TEST(Heli, Mode2Test) +{ + MODEL_RESET(); + g_eeGeneral.templateSetup = 2; + applyDefaultTemplate(); + g_model.swashR.collectiveSource = MIXSRC_Thr; + g_model.swashR.elevatorSource = MIXSRC_Ele; + g_model.swashR.aileronSource = MIXSRC_Ail; + g_model.swashR.collectiveWeight = 100; + g_model.swashR.elevatorWeight = 100; + g_model.swashR.aileronWeight = 100; + g_model.swashR.type = SWASH_TYPE_120; + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_CYC1; + g_model.mixData[0].weight = 100; + g_model.mixData[1].destCh = 1; + g_model.mixData[1].mltpx = MLTPX_ADD; + g_model.mixData[1].srcRaw = MIXSRC_CYC2; + g_model.mixData[1].weight = 100; + g_model.mixData[2].destCh = 2; + g_model.mixData[2].mltpx = MLTPX_ADD; + g_model.mixData[2].srcRaw = MIXSRC_CYC3; + g_model.mixData[2].weight = 100; + anaInValues[ELE_STICK] = 1024; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], -CHANNEL_MAX); + EXPECT_EQ(chans[1], CHANNEL_MAX/2); + EXPECT_EQ(chans[2], CHANNEL_MAX/2); +} +#endif + +#if defined(HELI) && !defined(PCBTARANIS) +TEST(Heli, SimpleTest) +{ + MODEL_RESET(); + applyTemplate(TMPL_HELI_SETUP); + anaInValues[ELE_STICK] = 1024; + evalFlightModeMixes(e_perout_mode_normal, 0); + EXPECT_EQ(chans[0], -CHANNEL_MAX); + EXPECT_EQ(chans[1], CHANNEL_MAX/2); + EXPECT_EQ(chans[1], CHANNEL_MAX/2); +} +#endif + +TEST(Trainer, UnpluggedTest) +{ + MODEL_RESET(); + MIXER_RESET(); + g_model.mixData[0].destCh = 0; + g_model.mixData[0].mltpx = MLTPX_ADD; + g_model.mixData[0].srcRaw = MIXSRC_FIRST_TRAINER; + g_model.mixData[0].weight = 100; + g_model.mixData[0].delayUp = DELAY_STEP*5; + g_model.mixData[0].delayDown = DELAY_STEP*5; + ppmInputValidityTimer = 0; + ppmInput[0] = 1024; + CHECK_DELAY(0, 5000); +} diff --git a/radio/src/tests/switches.cpp b/radio/src/tests/switches.cpp index f61f8b6ee..19499ed55 100644 --- a/radio/src/tests/switches.cpp +++ b/radio/src/tests/switches.cpp @@ -1,27 +1,12 @@ /* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer + * Copyright (C) OpenTX * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * Based on code named + * 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 @@ -31,7 +16,6 @@ * 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 "gtests.h" diff --git a/radio/src/tests/timers.cpp b/radio/src/tests/timers.cpp index 5b526afb2..1b2e89186 100644 --- a/radio/src/tests/timers.cpp +++ b/radio/src/tests/timers.cpp @@ -1,255 +1,239 @@ -/* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - Thomas Husterer - * - * opentx is based on code named - * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, - * er9x by Erez Raviv: http://code.google.com/p/er9x/, - * and the original (and ongoing) project by - * Thomas Husterer, th9x: http://code.google.com/p/th9x/ - * - * 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 "gtests.h" -#include "opentx.h" -#include "timers.h" - -#if !defined(CPUARM) -#undef timerSet -void timerSet(int idx, int16_t val) -{ - TimerState & timerState = timersStates[idx]; - timerState.state = TMR_OFF; // is changed to RUNNING dep from mode - timerState.val = val; - timerState.val_10ms = 0 ; -} -#endif // #if !defined(CPUARM) - -#if defined(ACCURAT_THROTTLE_TIMER) - #define THR_100 128 // approximately 10% full throttle - #define THR_50 64 // approximately 10% full throttle - #define THR_10 13 // approximately 10% full throttle -#else - #define THR_100 32 // approximately 10% full throttle - #define THR_50 16 // approximately 10% full throttle - #define THR_10 3 // approximately 10% full throttle -#endif - - -#define TEST_AB_EQUAL(a, b) if (a != b) { return ::testing::AssertionFailure() << \ - #a "= " << (uint32_t)a << ", " << #b "= " << (uint32_t)b; }; - -void initModelTimer(uint32_t idx, uint8_t mode, int16_t start = 0) -{ - g_model.timers[0].mode = mode; - g_model.timers[0].start = start; - g_model.timers[0].countdownBeep = COUNTDOWN_SILENT; - g_model.timers[0].minuteBeep = 0; - g_model.timers[0].spare = 0; -#if defined(CPUARM) || defined(CPUM2560) - g_model.timers[0].persistent = 0; - g_model.timers[0].value = 0; -#endif -} - -/* - Run timers for n seconds and test the end state -*/ -::testing::AssertionResult evalTimersForNSecondsAndTest(unsigned int n, uint8_t throttle, uint32_t idx, uint8_t state, int value) -{ - unsigned int noLoops = n * 100; - while (noLoops--) { - evalTimers(throttle, 1); - } - TEST_AB_EQUAL(timersStates[idx].state, state); - TEST_AB_EQUAL(timersStates[idx].val, value); - return ::testing::AssertionSuccess(); -} - -TEST(Timers, timerReset) -{ - initModelTimer(0, TMRMODE_THR_REL, 200); - timerReset(0); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 200)); - - initModelTimer(1, TMRMODE_THR_REL, 0); - timerReset(1); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 0)); -} - -#if defined(CPUARM) -TEST(Timers, timerSet) -{ - timerSet(0, 500); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500)); - - timerSet(1, 300); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 300)); -} - -TEST(Timers, timerGreaterThan9hours) -{ - initModelTimer(0, TMRMODE_ABS, 0); - timerSet(0, 0); - // test with 24 hours - EXPECT_TRUE(evalTimersForNSecondsAndTest(24*3600, THR_100, 0, TMR_RUNNING, 24*3600)); -} -#endif // #if defined(CPUARM) - -#if defined(CPUARM) || defined(CPUM2560) -TEST(Timers, saveRestoreTimers) -{ - g_model.timers[0].persistent = 1; - g_model.timers[1].persistent = 1; - timerSet(0, 500); - timerSet(1, 1500); - saveTimers(); - EXPECT_EQ(g_model.timers[0].value, 500); - EXPECT_EQ(g_model.timers[1].value, 1500); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 1500)); - - timerReset(0); - timerReset(1); - restoreTimers(); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 1500)); -} -#endif - -TEST(Timers, timerOff) -{ - initModelTimer(0, TMRMODE_NONE, 0); - timerReset(0); - - EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 0)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(10, THR_100, 0, TMR_OFF, 0)); -} - -TEST(Timers, timerAbsolute) -{ - initModelTimer(0, TMRMODE_ABS, 0); - timerReset(0); - - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 1)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 101)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 201)); - - // max timer value test - timerSet(0, TIMER_MAX-10); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, TIMER_MAX-9)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, TIMER_MAX)); - - // test down-running - g_model.timers[0].start = 200; - timerReset(0); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_NEGATIVE, -1)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED, -101)); - -#if !defined(CPUARM) - // min timer value test - timerSet(0, TIMER_MIN+10); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, TIMER_MIN+9)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, TIMER_MIN)); -#endif -} - -TEST(Timers, timerThrottle) -{ - initModelTimer(0, TMRMODE_THR, 0); - timerReset(0); - - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 0)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 200)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 200)); - - // test down-running - g_model.timers[0].start = 200; - timerReset(0); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 199)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_NEGATIVE, -1)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-101)); -} - -TEST(Timers, timerThrottleRelative) -{ - initModelTimer(0, TMRMODE_THR_REL, 0); - - timerReset(0); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 0)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_RUNNING, 150)); // 50% throttle == 50s -#if defined(ACCURAT_THROTTLE_TIMER) - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 160)); // 10% throttle == 10s - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 160)); -#else - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 159)); // 10% throttle == 10s - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 159)); -#endif - - // test down-running - initModelTimer(0, TMRMODE_THR_REL, 200); - timerReset(0); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 199)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(200, THR_50, 0, TMR_NEGATIVE, -1)); // 50% throttle == 100s -#if defined(ACCURAT_THROTTLE_TIMER) - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_NEGATIVE,-11)); // 10% throttle == 10s - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-111)); -#else - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_NEGATIVE,-10)); // 10% throttle == 10s - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-110)); -#endif -} - -TEST(Timers, timerThrottleTriggered) -{ - initModelTimer(0, TMRMODE_THR_TRG, 0); - - timerReset(0); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_OFF, 0)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10-1, 0, TMR_OFF, 0)); // below threshold - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_RUNNING, 100)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 200)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 300)); - - // test down-running - initModelTimer(0, TMRMODE_THR_TRG, 200); - timerReset(0); - EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_OFF, 200)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10-1, 0, TMR_OFF, 200)); // below threshold - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(101, THR_50, 0, TMR_NEGATIVE, -1)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(10, 0, 0, TMR_NEGATIVE,-11)); - EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_STOPPED,-111)); -} +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "gtests.h" +#include "opentx.h" +#include "timers.h" + +#if !defined(CPUARM) +#undef timerSet +void timerSet(int idx, int16_t val) +{ + TimerState & timerState = timersStates[idx]; + timerState.state = TMR_OFF; // is changed to RUNNING dep from mode + timerState.val = val; + timerState.val_10ms = 0 ; +} +#endif // #if !defined(CPUARM) + +#if defined(ACCURAT_THROTTLE_TIMER) + #define THR_100 128 // approximately 10% full throttle + #define THR_50 64 // approximately 10% full throttle + #define THR_10 13 // approximately 10% full throttle +#else + #define THR_100 32 // approximately 10% full throttle + #define THR_50 16 // approximately 10% full throttle + #define THR_10 3 // approximately 10% full throttle +#endif + + +#define TEST_AB_EQUAL(a, b) if (a != b) { return ::testing::AssertionFailure() << \ + #a "= " << (uint32_t)a << ", " << #b "= " << (uint32_t)b; }; + +void initModelTimer(uint32_t idx, uint8_t mode, int16_t start = 0) +{ + g_model.timers[0].mode = mode; + g_model.timers[0].start = start; + g_model.timers[0].countdownBeep = COUNTDOWN_SILENT; + g_model.timers[0].minuteBeep = 0; + g_model.timers[0].spare = 0; +#if defined(CPUARM) || defined(CPUM2560) + g_model.timers[0].persistent = 0; + g_model.timers[0].value = 0; +#endif +} + +/* + Run timers for n seconds and test the end state +*/ +::testing::AssertionResult evalTimersForNSecondsAndTest(unsigned int n, uint8_t throttle, uint32_t idx, uint8_t state, int value) +{ + unsigned int noLoops = n * 100; + while (noLoops--) { + evalTimers(throttle, 1); + } + TEST_AB_EQUAL(timersStates[idx].state, state); + TEST_AB_EQUAL(timersStates[idx].val, value); + return ::testing::AssertionSuccess(); +} + +TEST(Timers, timerReset) +{ + initModelTimer(0, TMRMODE_THR_REL, 200); + timerReset(0); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 200)); + + initModelTimer(1, TMRMODE_THR_REL, 0); + timerReset(1); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 0)); +} + +#if defined(CPUARM) +TEST(Timers, timerSet) +{ + timerSet(0, 500); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500)); + + timerSet(1, 300); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 300)); +} + +TEST(Timers, timerGreaterThan9hours) +{ + initModelTimer(0, TMRMODE_ABS, 0); + timerSet(0, 0); + // test with 24 hours + EXPECT_TRUE(evalTimersForNSecondsAndTest(24*3600, THR_100, 0, TMR_RUNNING, 24*3600)); +} +#endif // #if defined(CPUARM) + +#if defined(CPUARM) || defined(CPUM2560) +TEST(Timers, saveRestoreTimers) +{ + g_model.timers[0].persistent = 1; + g_model.timers[1].persistent = 1; + timerSet(0, 500); + timerSet(1, 1500); + saveTimers(); + EXPECT_EQ(g_model.timers[0].value, 500); + EXPECT_EQ(g_model.timers[1].value, 1500); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 1500)); + + timerReset(0); + timerReset(1); + restoreTimers(); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 1500)); +} +#endif + +TEST(Timers, timerOff) +{ + initModelTimer(0, TMRMODE_NONE, 0); + timerReset(0); + + EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 0)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(10, THR_100, 0, TMR_OFF, 0)); +} + +TEST(Timers, timerAbsolute) +{ + initModelTimer(0, TMRMODE_ABS, 0); + timerReset(0); + + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 1)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 101)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 201)); + + // max timer value test + timerSet(0, TIMER_MAX-10); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, TIMER_MAX-9)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, TIMER_MAX)); + + // test down-running + g_model.timers[0].start = 200; + timerReset(0); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_NEGATIVE, -1)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED, -101)); + +#if !defined(CPUARM) + // min timer value test + timerSet(0, TIMER_MIN+10); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, TIMER_MIN+9)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, TIMER_MIN)); +#endif +} + +TEST(Timers, timerThrottle) +{ + initModelTimer(0, TMRMODE_THR, 0); + timerReset(0); + + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 0)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 200)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 200)); + + // test down-running + g_model.timers[0].start = 200; + timerReset(0); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 199)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_NEGATIVE, -1)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-101)); +} + +TEST(Timers, timerThrottleRelative) +{ + initModelTimer(0, TMRMODE_THR_REL, 0); + + timerReset(0); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 0)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_RUNNING, 150)); // 50% throttle == 50s +#if defined(ACCURAT_THROTTLE_TIMER) + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 160)); // 10% throttle == 10s + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 160)); +#else + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 159)); // 10% throttle == 10s + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 159)); +#endif + + // test down-running + initModelTimer(0, TMRMODE_THR_REL, 200); + timerReset(0); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 199)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(200, THR_50, 0, TMR_NEGATIVE, -1)); // 50% throttle == 100s +#if defined(ACCURAT_THROTTLE_TIMER) + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_NEGATIVE,-11)); // 10% throttle == 10s + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-111)); +#else + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_NEGATIVE,-10)); // 10% throttle == 10s + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-110)); +#endif +} + +TEST(Timers, timerThrottleTriggered) +{ + initModelTimer(0, TMRMODE_THR_TRG, 0); + + timerReset(0); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_OFF, 0)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10-1, 0, TMR_OFF, 0)); // below threshold + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_RUNNING, 100)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 200)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 300)); + + // test down-running + initModelTimer(0, TMRMODE_THR_TRG, 200); + timerReset(0); + EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_OFF, 200)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10-1, 0, TMR_OFF, 200)); // below threshold + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(101, THR_50, 0, TMR_NEGATIVE, -1)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(10, 0, 0, TMR_NEGATIVE,-11)); + EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_STOPPED,-111)); +}