From fa1e6f087cddcd634f28fcc0a00d44ab40f933ed Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 30 May 2020 12:11:36 +0200 Subject: [PATCH] Graupner HoTT: full telemetry (#7627) --- .../horus/SCRIPTS/TOOLS/Graupner HoTT.lua | 87 ++- .../SCRIPTS/TOOLS/Graupner HoTT.lua | 87 ++- .../SCRIPTS/TOOLS/Graupner HoTT.lua | 87 ++- radio/src/pulses/multi.cpp | 2 +- radio/src/telemetry/frsky_d.cpp | 6 +- radio/src/telemetry/frsky_sport.cpp | 2 + radio/src/telemetry/hott.cpp | 596 ++++++++++++++++-- radio/src/telemetry/multi.cpp | 3 +- radio/src/telemetry/telemetry_holders.h | 1 + radio/src/telemetry/telemetry_sensors.cpp | 2 + radio/src/telemetry/telemetry_sensors.h | 2 +- 11 files changed, 742 insertions(+), 133 deletions(-) diff --git a/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua index ff6a3254c..d0a7d4af8 100644 --- a/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua +++ b/radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -21,19 +21,41 @@ -- To start operation: -- Write "HoTT" at address 0..3 -- Write 0xFF at address 4 will request the buffer to be cleared --- Write 0xDF at address 5 +-- Write 0x0F at address 5 -- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters -- by 8 lines --- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, --- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page, +-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor +-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM -- Write at address 4 the value 0xFF will request the buffer to be cleared -- !! Before exiting the script must write 0 at address 0 for normal operation !! --############################################################################### +HoTT_Sensor = 0 +Timer_128 = 100 + local function HoTT_Release() multiBuffer( 0, 0 ) end +local function HoTT_Send(button) + multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button) +end + +local function HoTT_Sensor_Inc() + local detected_sensors=multiBuffer( 4 ) + local a + if detected_sensors ~= 0xFF then + repeat + HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor + if HoTT_Sensor ~= 0 then + a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right + end + until HoTT_Sensor==0 or a % 2 == 1 + HoTT_Send( 0x0F ) + end +end + local function HoTT_Draw_LCD() local i local value @@ -41,12 +63,14 @@ local function HoTT_Draw_LCD() local result local offset=0 + local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" } + lcd.clear() if LCD_W == 480 then --Draw title lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR) --Draw RX Menu if multiBuffer( 4 ) == 0xFF then lcd.drawText(10,50,"No HoTT telemetry...", BLINK) @@ -56,9 +80,9 @@ local function HoTT_Draw_LCD() value=multiBuffer( line*21+6+i ) if value > 0x80 then value = value - 0x80 - lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS) else - lcd.drawText(10+i*16,32+16*line,string.char(value)) + lcd.drawText(10+i*16,32+20*line,string.char(value)) end end end @@ -68,14 +92,23 @@ local function HoTT_Draw_LCD() if multiBuffer( 4 ) == 0xFF then lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) else - for line = 0, 7, 1 do - for i = 0, 21-1, 1 do - value=multiBuffer( line*21+6+i ) - if value > 0x80 then - value = value - 0x80 - lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) - else - lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + if Timer_128 ~= 0 then + --Intro page + Timer_128 = Timer_128 - 1 + lcd.drawScreenTitle("Graupner Hott",0,0) + lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE) + lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE) + else + --Menu page + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end end end end @@ -98,7 +131,10 @@ local function HoTT_Init() --Request init of the RX buffer multiBuffer( 4, 0xFF ) --Request RX to send the config menu - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) + HoTT_Sensor = 0; + HoTT_Detected_Sensors=0; + Timer_128 = 100 end -- Main @@ -111,18 +147,21 @@ local function HoTT_Run(event) return 2 else if event == EVT_VIRTUAL_PREV_PAGE then - killEvents(event); - multiBuffer( 5, 0xD7 ) - elseif event == EVT_VIRTUAL_NEXT_PAGE then - multiBuffer( 5, 0xDE ) + killEvents(event) + HoTT_Send( 0x07 ) elseif event == EVT_VIRTUAL_ENTER then - multiBuffer( 5, 0xD9 ) - elseif event == EVT_VIRTUAL_NEXT then - multiBuffer( 5, 0xDD ) + HoTT_Send( 0x09 ) elseif event == EVT_VIRTUAL_PREV then - multiBuffer( 5, 0xDB ) + HoTT_Send( 0x0B ) + elseif event == EVT_VIRTUAL_NEXT then + HoTT_Send( 0x0D ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + HoTT_Send( 0x0E ) + elseif event == EVT_VIRTUAL_MENU then + Timer_128 = 100 + HoTT_Sensor_Inc() else - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) end HoTT_Draw_LCD() return 0 diff --git a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua index ff6a3254c..d0a7d4af8 100644 --- a/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua +++ b/radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -21,19 +21,41 @@ -- To start operation: -- Write "HoTT" at address 0..3 -- Write 0xFF at address 4 will request the buffer to be cleared --- Write 0xDF at address 5 +-- Write 0x0F at address 5 -- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters -- by 8 lines --- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, --- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page, +-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor +-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM -- Write at address 4 the value 0xFF will request the buffer to be cleared -- !! Before exiting the script must write 0 at address 0 for normal operation !! --############################################################################### +HoTT_Sensor = 0 +Timer_128 = 100 + local function HoTT_Release() multiBuffer( 0, 0 ) end +local function HoTT_Send(button) + multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button) +end + +local function HoTT_Sensor_Inc() + local detected_sensors=multiBuffer( 4 ) + local a + if detected_sensors ~= 0xFF then + repeat + HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor + if HoTT_Sensor ~= 0 then + a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right + end + until HoTT_Sensor==0 or a % 2 == 1 + HoTT_Send( 0x0F ) + end +end + local function HoTT_Draw_LCD() local i local value @@ -41,12 +63,14 @@ local function HoTT_Draw_LCD() local result local offset=0 + local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" } + lcd.clear() if LCD_W == 480 then --Draw title lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR) --Draw RX Menu if multiBuffer( 4 ) == 0xFF then lcd.drawText(10,50,"No HoTT telemetry...", BLINK) @@ -56,9 +80,9 @@ local function HoTT_Draw_LCD() value=multiBuffer( line*21+6+i ) if value > 0x80 then value = value - 0x80 - lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS) else - lcd.drawText(10+i*16,32+16*line,string.char(value)) + lcd.drawText(10+i*16,32+20*line,string.char(value)) end end end @@ -68,14 +92,23 @@ local function HoTT_Draw_LCD() if multiBuffer( 4 ) == 0xFF then lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) else - for line = 0, 7, 1 do - for i = 0, 21-1, 1 do - value=multiBuffer( line*21+6+i ) - if value > 0x80 then - value = value - 0x80 - lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) - else - lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + if Timer_128 ~= 0 then + --Intro page + Timer_128 = Timer_128 - 1 + lcd.drawScreenTitle("Graupner Hott",0,0) + lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE) + lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE) + else + --Menu page + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end end end end @@ -98,7 +131,10 @@ local function HoTT_Init() --Request init of the RX buffer multiBuffer( 4, 0xFF ) --Request RX to send the config menu - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) + HoTT_Sensor = 0; + HoTT_Detected_Sensors=0; + Timer_128 = 100 end -- Main @@ -111,18 +147,21 @@ local function HoTT_Run(event) return 2 else if event == EVT_VIRTUAL_PREV_PAGE then - killEvents(event); - multiBuffer( 5, 0xD7 ) - elseif event == EVT_VIRTUAL_NEXT_PAGE then - multiBuffer( 5, 0xDE ) + killEvents(event) + HoTT_Send( 0x07 ) elseif event == EVT_VIRTUAL_ENTER then - multiBuffer( 5, 0xD9 ) - elseif event == EVT_VIRTUAL_NEXT then - multiBuffer( 5, 0xDD ) + HoTT_Send( 0x09 ) elseif event == EVT_VIRTUAL_PREV then - multiBuffer( 5, 0xDB ) + HoTT_Send( 0x0B ) + elseif event == EVT_VIRTUAL_NEXT then + HoTT_Send( 0x0D ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + HoTT_Send( 0x0E ) + elseif event == EVT_VIRTUAL_MENU then + Timer_128 = 100 + HoTT_Sensor_Inc() else - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) end HoTT_Draw_LCD() return 0 diff --git a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua index ff6a3254c..d0a7d4af8 100644 --- a/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua +++ b/radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -21,19 +21,41 @@ -- To start operation: -- Write "HoTT" at address 0..3 -- Write 0xFF at address 4 will request the buffer to be cleared --- Write 0xDF at address 5 +-- Write 0x0F at address 5 -- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters -- by 8 lines --- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page, --- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev +-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page, +-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor +-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM -- Write at address 4 the value 0xFF will request the buffer to be cleared -- !! Before exiting the script must write 0 at address 0 for normal operation !! --############################################################################### +HoTT_Sensor = 0 +Timer_128 = 100 + local function HoTT_Release() multiBuffer( 0, 0 ) end +local function HoTT_Send(button) + multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button) +end + +local function HoTT_Sensor_Inc() + local detected_sensors=multiBuffer( 4 ) + local a + if detected_sensors ~= 0xFF then + repeat + HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor + if HoTT_Sensor ~= 0 then + a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right + end + until HoTT_Sensor==0 or a % 2 == 1 + HoTT_Send( 0x0F ) + end +end + local function HoTT_Draw_LCD() local i local value @@ -41,12 +63,14 @@ local function HoTT_Draw_LCD() local result local offset=0 + local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" } + lcd.clear() if LCD_W == 480 then --Draw title lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR) + lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR) --Draw RX Menu if multiBuffer( 4 ) == 0xFF then lcd.drawText(10,50,"No HoTT telemetry...", BLINK) @@ -56,9 +80,9 @@ local function HoTT_Draw_LCD() value=multiBuffer( line*21+6+i ) if value > 0x80 then value = value - 0x80 - lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS) + lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS) else - lcd.drawText(10+i*16,32+16*line,string.char(value)) + lcd.drawText(10+i*16,32+20*line,string.char(value)) end end end @@ -68,14 +92,23 @@ local function HoTT_Draw_LCD() if multiBuffer( 4 ) == 0xFF then lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) else - for line = 0, 7, 1 do - for i = 0, 21-1, 1 do - value=multiBuffer( line*21+6+i ) - if value > 0x80 then - value = value - 0x80 - lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) - else - lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + if Timer_128 ~= 0 then + --Intro page + Timer_128 = Timer_128 - 1 + lcd.drawScreenTitle("Graupner Hott",0,0) + lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE) + lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE) + else + --Menu page + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end end end end @@ -98,7 +131,10 @@ local function HoTT_Init() --Request init of the RX buffer multiBuffer( 4, 0xFF ) --Request RX to send the config menu - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) + HoTT_Sensor = 0; + HoTT_Detected_Sensors=0; + Timer_128 = 100 end -- Main @@ -111,18 +147,21 @@ local function HoTT_Run(event) return 2 else if event == EVT_VIRTUAL_PREV_PAGE then - killEvents(event); - multiBuffer( 5, 0xD7 ) - elseif event == EVT_VIRTUAL_NEXT_PAGE then - multiBuffer( 5, 0xDE ) + killEvents(event) + HoTT_Send( 0x07 ) elseif event == EVT_VIRTUAL_ENTER then - multiBuffer( 5, 0xD9 ) - elseif event == EVT_VIRTUAL_NEXT then - multiBuffer( 5, 0xDD ) + HoTT_Send( 0x09 ) elseif event == EVT_VIRTUAL_PREV then - multiBuffer( 5, 0xDB ) + HoTT_Send( 0x0B ) + elseif event == EVT_VIRTUAL_NEXT then + HoTT_Send( 0x0D ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + HoTT_Send( 0x0E ) + elseif event == EVT_VIRTUAL_MENU then + Timer_128 = 100 + HoTT_Sensor_Inc() else - multiBuffer( 5, 0xDF ) + HoTT_Send( 0x0F ) end HoTT_Draw_LCD() return 0 diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 9fe10113c..cfcff15d0 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -393,7 +393,7 @@ void sendSport(uint8_t moduleIdx) void sendHott(uint8_t moduleIdx) { - if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0 && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) { + if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0 && (Multi_Buffer[5] & 0x80) && (Multi_Buffer[5] & 0x0F) >= 0x07) { // HoTT Lua script is running sendMulti(moduleIdx, Multi_Buffer[5]); } diff --git a/radio/src/telemetry/frsky_d.cpp b/radio/src/telemetry/frsky_d.cpp index 67445c193..c1ad3f9d5 100644 --- a/radio/src/telemetry/frsky_d.cpp +++ b/radio/src/telemetry/frsky_d.cpp @@ -227,6 +227,8 @@ void processHubPacket(uint8_t id, int16_t value) else if (id == VOLTS_ID) { unit = UNIT_CELLS; uint32_t cellData = (uint32_t)data; + if (((cellData & 0x00F0) >> 4) >= MAX_CELLS) + return; data = ((cellData & 0x00F0) << 12) + (((((cellData & 0xFF00) >> 8) + ((cellData & 0x000F) << 8))) / 5); } else if (id == GPS_DAY_MONTH_ID) { @@ -264,7 +266,7 @@ void processHubPacket(uint8_t id, int16_t value) data *= 10; } } - + setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, id, 0, 0, data, unit, precision); } @@ -326,4 +328,4 @@ void frskyDSetDefault(int index, uint16_t id) } storageDirty(EE_MODEL); -} +} \ No newline at end of file diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index 0e4f3920c..d5215e300 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -139,6 +139,8 @@ void sportProcessTelemetryPacket(uint16_t id, uint8_t subId, uint8_t instance, u if (unit == UNIT_CELLS) { uint8_t cellsCount = (data & 0xF0) >> 4; uint8_t cellIndex = (data & 0x0F); + if (cellIndex >= MAX_CELLS) + return; uint32_t mask = (cellsCount << 24) + (cellIndex << 16); setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0x000FFF00) >> 8) / 5), unit, precision); if (cellIndex+1 < cellsCount) { diff --git a/radio/src/telemetry/hott.cpp b/radio/src/telemetry/hott.cpp index f36236add..98b3c54cc 100644 --- a/radio/src/telemetry/hott.cpp +++ b/radio/src/telemetry/hott.cpp @@ -16,26 +16,27 @@ #include "opentx.h" /* Telemetry -packet[0] = TX RSSI value -packet[1] = TX LQI value -packet[2] = frame number -packet[3-12] telemetry data +packet[0] = TX RSSI value +packet[1] = TX LQI value +packet[2] = Telemetry type +packet[3] = Telemetry page +packet[4-13] = Telemetry data -The frame number takes the following values: 0x00, 0x01, 0x02, 0x03 and 0x04. The frames can be present or not, they also do not have to follow each others. -Here is a description of the telemetry data for each frame number: -- frame 0x00 -[3] = [12] = ?? -[4] = RX_Voltage*10 in V -[5] = Temperature-20 in °C -[6] = RX_RSSI -[7] = RX_LQI ?? -[8] = RX_STR ?? -[9,10] = [10]*256+[9]=max lost packet time in ms, max value seems 2s=0x7D0 -[11] = 0x00 ?? -- frame 0x01 Unknown -- frame 0x02 Unknown -- frame 0x03 Unknown -- frame 0x04 Unknown +Telemetry type: 0x00 RX, 0x09 Vario, 0x0A GPS, 0x0B not seen, 0x0C ESC, 0x0D GAM, 0x0E EAM, 0x80 Text config mode +Telemetry page: 0x00..0x04 for all telemetry except Text config mode which is 0x00..0x12. The pages can be present or not, they also do not have to follow each others. + +Here is a description of the RX telemetry: + [2] = 0x00 -> Telemetry type RX + [3] = 0x00 -> Telemetry page 0 + [4] = ?? looks to be a copy of [7] + [5] = RX_Voltage*10 in V + [6] = Temperature-20 in °C + [7] = RX_RSSI CC2500 formated (a<128:a/2-71dBm, a>=128:(a-256)/2-71dBm) + [8] = RX_LQI in % + [9] = RX_MIN_Voltage*10 in V + [10,11] = [11]*256+[10]=max lost packet time in ms, max value seems 2s=0x7D0 + [12] = 0x00 ?? + [13] = ?? looks to be a copy of [7] */ struct HottSensor @@ -49,22 +50,54 @@ struct HottSensor // telemetry frames enum { - HOTT_FRAME_00 = 0x00, - HOTT_FRAME_01 = 0x01, - HOTT_FRAME_02 = 0x02, - HOTT_FRAME_03 = 0x03, - HOTT_FRAME_04 = 0x04, + HOTT_PAGE_00 = 0x00, + HOTT_PAGE_01 = 0x01, + HOTT_PAGE_02 = 0x02, + HOTT_PAGE_03 = 0x03, + HOTT_PAGE_04 = 0x04, }; -#define HOTT_TELEM_NORMAL 0x00 -#define HOTT_TELEM_BIND 0x40 -#define HOTT_TELEM_MENU 0x80 +enum +{ + HOTT_TELEM_RX = 0x00, + HOTT_TELEM_VARIO = 0x09, + HOTT_TELEM_GPS = 0x0A, + HOTT_TELEM_ESC = 0x0C, + HOTT_TELEM_GAM = 0x0D, + HOTT_TELEM_EAM = 0x0E, + HOTT_TELEM_TEXT = 0x80, +}; // telemetry sensors ID enum { HOTT_ID_RX_VOLTAGE = 0x0004, // RX_Batt Voltage HOTT_ID_TEMP1 = 0x0005, // RX Temperature sensor + HOTT_ID_VARIO = 0x0006, // Vario sensor + HOTT_ID_ALT = 0x0007, // Alt sensor + HOTT_ID_HDG = 0x0008, // Heading sensor + HOTT_ID_GSPD = 0x0008, // Ground speed sensor + HOTT_ID_GPS_LAT_LONG = 0x0009, // GPS sensor + HOTT_ID_GPS_COUNT = 0x000A, // GPS sat count + HOTT_ID_CELS = 0x000B, // Cels L sensor + HOTT_ID_CELS_H = 0x000C, // Cels H sensor + HOTT_ID_VOLT1 = 0x000D, // Voltage sensor + HOTT_ID_VOLT2 = 0x000E, // Voltage sensor + HOTT_ID_AMP1 = 0x000F, // Amp sensor + HOTT_ID_AMP2 = 0x0010, // Amp sensor + HOTT_ID_RPM1 = 0x0011, // RPM sensor + HOTT_ID_RPM2 = 0x0012, // RPM sensor + HOTT_ID_ESC_VIN = 0x0013, // ESC Volt + HOTT_ID_ESC_CUR = 0x0014, // ESC Amp + HOTT_ID_ESC_TBEC = 0x0015, // BEC Temp + HOTT_ID_ESC_BCUR = 0x0016, // BEC Cur + HOTT_ID_ESC_VBEC = 0x0017, // BEC Volt + HOTT_ID_BCAPA = 0x0018, // Batt capacity + HOTT_ID_TEMP2 = 0x0019, // Temperature sensor 2 + HOTT_ID_AIR_SPEED = 0x001A, + HOTT_ID_VOLT3 = 0x001B, // Voltage sensor + HOTT_ID_FUEL = 0x001C, // Fuel percentage + HOTT_TX_RSSI_ID = 0xFF00, // Pseudo id outside 1 byte range of Hott sensors HOTT_TX_LQI_ID = 0xFF01, // Pseudo id outside 1 byte range of Hott sensors HOTT_RX_RSSI_ID = 0xFF02, // Pseudo id outside 1 byte range of Hott sensors @@ -72,18 +105,39 @@ enum }; const HottSensor hottSensors[] = { - //frame 00 - {HOTT_ID_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1}, // RX_Batt Voltage - {HOTT_ID_TEMP1, ZSTR_TEMP1, UNIT_CELSIUS, 0}, // RX Temperature sensor - //frame 01 - //frame 02 - //frame 03 - //frame 04 - {HOTT_TX_RSSI_ID, ZSTR_TX_RSSI, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors - {HOTT_TX_LQI_ID, ZSTR_TX_QUALITY, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors - {HOTT_RX_RSSI_ID, ZSTR_RSSI, UNIT_DB, 0}, // RX RSSI - {HOTT_RX_LQI_ID, ZSTR_RX_QUALITY, UNIT_RAW, 0}, // RX LQI - {0x00, NULL, UNIT_RAW, 0}, // sentinel + //HOTT_TELEM_RX + {HOTT_ID_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1}, // RX_Batt Voltage + {HOTT_ID_TEMP1, ZSTR_TEMP1, UNIT_CELSIUS, 0}, // Temperature sensor 1 + {HOTT_ID_TEMP2, ZSTR_TEMP2, UNIT_CELSIUS, 0}, // Temperature sensor 2 + {HOTT_ID_VARIO, ZSTR_VSPD, UNIT_METERS_PER_SECOND, 2}, // Vario sensor + {HOTT_ID_ALT, ZSTR_ALT, UNIT_METERS, 0}, // Alt sensor + {HOTT_ID_HDG, ZSTR_HDG, UNIT_DEGREE, 0}, // Heading sensor + {HOTT_ID_GSPD, ZSTR_GSPD, UNIT_KMH, 0}, // Ground speed sensor + {HOTT_ID_GPS_LAT_LONG, ZSTR_GPS, UNIT_GPS, 0}, // GPS position + {HOTT_ID_GPS_COUNT, ZSTR_SATELLITES, UNIT_RAW, 0}, // GPS sat count + {HOTT_ID_VOLT1, ZSTR_A1, UNIT_VOLTS, 1}, // Voltage sensor 1 + {HOTT_ID_VOLT2, ZSTR_A2, UNIT_VOLTS, 1}, // Voltage sensor 2 + {HOTT_ID_VOLT3, ZSTR_A3, UNIT_VOLTS, 1}, // Voltage sensor 3 + {HOTT_ID_AMP1, ZSTR_CURR, UNIT_AMPS, 1}, // Amp sensor 1 + {HOTT_ID_AMP2, ZSTR_CURR, UNIT_AMPS, 1}, // Amp sensor 2 + {HOTT_ID_RPM1, ZSTR_RPM, UNIT_RPMS, 0}, // RPM1 + {HOTT_ID_RPM2, ZSTR_RPM2, UNIT_RPMS, 0}, // RPM2 + {HOTT_ID_ESC_VIN, ZSTR_ESC_VIN, UNIT_VOLTS, 1}, // ESC VIN + {HOTT_ID_BCAPA, ZSTR_SMART_BAT_CAPACITY, UNIT_MAH, 2}, // Batt Capa + {HOTT_ID_ESC_CUR, ZSTR_ESC_CUR, UNIT_AMPS, 1}, // ESC Amp + {HOTT_ID_ESC_TBEC, ZSTR_ESC_TBEC, UNIT_CELSIUS, 0}, // ESC BEC Temp + {HOTT_ID_ESC_BCUR, ZSTR_ESC_BCUR, UNIT_AMPS, 1}, // ESC BEC Amp + {HOTT_ID_ESC_VBEC, ZSTR_ESC_VBEC, UNIT_VOLTS, 1}, // ESC BEC Volt + {HOTT_ID_CELS, ZSTR_CELLS, UNIT_CELLS, 2}, // Batt cells + {HOTT_ID_CELS_H, ZSTR_CELLS, UNIT_CELLS, 2}, // Batt H cells + {HOTT_ID_AIR_SPEED, ZSTR_ASPD, UNIT_KMH, 0}, // Air speed + {HOTT_ID_FUEL, ZSTR_FUEL, UNIT_PERCENT, 0}, // Fuel + + {HOTT_TX_RSSI_ID, ZSTR_TX_RSSI, UNIT_DB, 0}, // Pseudo id outside 1 byte range of Hott sensors + {HOTT_TX_LQI_ID, ZSTR_TX_QUALITY, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors + {HOTT_RX_RSSI_ID, ZSTR_RSSI, UNIT_DB, 0}, // RX RSSI + {HOTT_RX_LQI_ID, ZSTR_RX_QUALITY, UNIT_RAW, 0}, // RX LQI + {0x00, NULL, UNIT_RAW, 0}, // sentinel }; const HottSensor * getHottSensor(uint16_t id) @@ -95,22 +149,30 @@ const HottSensor * getHottSensor(uint16_t id) return nullptr; } +int16_t processHoTTdBm(uint8_t value) +{ + if (value >= 128) { + value = 256 - value; + } + return value / 2 -71; +} + void processHottPacket(const uint8_t * packet) { // Set TX RSSI Value - setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_TX_RSSI_ID, 0, 0, packet[0]>>1, UNIT_RAW, 0); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_TX_RSSI_ID, 0, 0, processHoTTdBm(packet[0]), UNIT_RAW, 0); // Set TX LQI Value setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_TX_LQI_ID, 0, 0, packet[1], UNIT_RAW, 0); #if defined(LUA) - #define HOTT_MENU_NBR_PAGE 0x13 +#define HOTT_MENU_NBR_PAGE 0x13 // Config menu consists of the different telem pages put all together // [3] = config mennu page 0x00 to 0x12. // Page X [4] = seems like all the telem pages with the same value are going together to make the full config menu text. Seen so far 'a', 'b', 'c', 'd' // Page X [5..13] = 9 ascii chars to be displayed, char is highlighted when ascii|0x80 // Screen display is 21 characters large which means that once the first 21 chars are filled go to the begining of the next line // Menu commands are sent through TX packets: - // packet[28]= 0xXF=>no key press, 0xXD=>down, 0xXB=>up, 0xX9=>enter, 0xXE=>right, 0xX7=>left with X=0 or D + // packet[28]= 0xXF=>no key press, 0xXD=>down, 0xXB=>up, 0xX9=>enter, 0xXE=>right, 0xX7=>left with X=0, 9=Vario, A=GPS, B=Unknown, C=ESC, D=GAM, or E=EAM // packet[29]= 0xX1/0xX9 with X=0 or X counting 0,1,1,2,2,..,9,9 if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0) { // HoTT Lua script is running @@ -118,21 +180,31 @@ void processHottPacket(const uint8_t * packet) // Init memset(&Multi_Buffer[6], ' ', HOTT_MENU_NBR_PAGE * 9); // Clear text buffer } - - if (packet[3] < HOTT_MENU_NBR_PAGE && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) { - Multi_Buffer[4] = packet[4]; // Store current menu being received + + if (packet[2] == HOTT_TELEM_TEXT && packet[3] < HOTT_MENU_NBR_PAGE && (Multi_Buffer[5] & 0x80) && (Multi_Buffer[5] & 0x0F) >= 0x07) { + Multi_Buffer[4] = packet[4]; // Store detected sensors memcpy(&Multi_Buffer[6 + packet[3] * 9], &packet[5], 9); // Store the received page in the buffer } return; } #endif + struct HottGPSMinutes + { + uint16_t value: 14; + uint16_t isNegative: 1; + uint16_t spare: 1; + }; + const HottSensor * sensor; int32_t value; + static uint8_t prev_page = 0, prev_value = 0; + static HottGPSMinutes min = {}; + int16_t deg = 0, sec = 0; - if (packet[2] == HOTT_TELEM_NORMAL) { - switch (packet[3]) { - case HOTT_FRAME_00: + switch (packet[2]) { // Telemetry type + case HOTT_TELEM_RX: + if (packet[3] == 0) { // Telemetry page: only page 0 is for RX // RX_VOLT value = packet[5]; sensor = getHottSensor(HOTT_ID_RX_VOLTAGE); @@ -142,21 +214,433 @@ void processHottPacket(const uint8_t * packet) sensor = getHottSensor(HOTT_ID_TEMP1); setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, 0, value, sensor->unit, sensor->precision); // RX_RSSI - setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_RX_RSSI_ID, 0, 0, packet[7], UNIT_DB, 0); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_RX_RSSI_ID, 0, 0, processHoTTdBm(packet[7]), UNIT_DB, 0); // RX_LQI telemetryData.rssi.set(packet[8]); if (packet[8] > 0) telemetryStreaming = TELEMETRY_TIMEOUT10ms; setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_RX_LQI_ID, 0, 0, packet[8], UNIT_RAW, 0); - break; + } + break; - default: - // unknown - value = (packet[7] << 24) | (packet[6] << 16) | (packet[5] << 8) | packet[4]; - setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, 0xFE00 | packet[3], 0, 0, value, UNIT_RAW, 0); - break; - } + case HOTT_TELEM_VARIO: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L240 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + // packet[6 ] uint8_t altitude_L; //#06 Altitude low uint8_t. In meters. A value of 500 means 0m + // packet[7 ] uint8_t altitude_H; //#07 Altitude high uint8_t + value = packet[6] + (packet[7] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_VARIO, value, sensor->unit, sensor->precision); + + // packet[12] uint8_t climbrate_L; //#12 Climb rate in m/s. Steps of 0.01m/s. Value of 30000 = 0.00 m/s + // packet[13] uint8_t climbrate_H; //#13 Climb rate in m/s + value = packet[12] + (packet[13] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_VARIO, value, sensor->unit, sensor->precision); + break; + case HOTT_PAGE_02: + // packet[12] uint8_t compass_direction; //#42 Compass heading in 2� steps. 1 = 2� + value = packet[12] * 2; + sensor = getHottSensor(HOTT_ID_HDG); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_HDG, 0, HOTT_TELEM_VARIO, value, sensor->unit, sensor->precision); + break; + case HOTT_PAGE_03: + break; + case HOTT_PAGE_04: + break; + } + break; + + case HOTT_TELEM_GPS: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L378 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + // packet[7 ] uint8_t flight_direction; //#07 flight direction in 2 degreees/step (1 = 2degrees); + value = packet[7] * 2; + sensor = getHottSensor(HOTT_ID_HDG); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_HDG, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + + // packet[8 ] uint8_t gps_speed_L; //08 km/h + // packet[9 ] uint8_t gps_speed_H; //#09 + value = packet[8] + (packet[9] << 8); + sensor = getHottSensor(HOTT_ID_GSPD); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GSPD, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + + // packet[10] uint8_t pos_NS; //#10 north = 0, south = 1 + // packet[11] uint8_t pos_NS_dm_L; //#11 degree minutes ie N48�39�988 + // packet[12] uint8_t pos_NS_dm_H; //#12 + // packet[13] uint8_t pos_NS_sec_L; //#13 position seconds + min.value = (int16_t) (packet[11] + (packet[12] << 8)); + if (packet[10] == 1) { + min.isNegative = true; + } + break; + + case HOTT_PAGE_02: + if (prev_page == ((HOTT_TELEM_GPS << 4) | HOTT_PAGE_01)) { + // packet[4 ] uint8_t pos_NS_sec_H; //#14 + deg = min.value / 100; + min.value = min.value - deg * 100; + sec = prev_value + (packet[4] << 8); + value = deg * 1000000 + (min.value * 1000000 + sec * 100) / 60; + if (min.isNegative) { + value = -value; + } + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GPS_LAT_LONG, 0, HOTT_TELEM_GPS, value, UNIT_GPS_LATITUDE, 0); + } + + // packet[5 ] uint8_t pos_EW; //#15 east = 0, west = 1 + // packet[6 ] uint8_t pos_EW_dm_L; //#16 degree minutes ie. E9�25�9360 + // packet[7 ] uint8_t pos_EW_dm_H; //#17 + // packet[8 ] uint8_t pos_EW_sec_L; //#18 position seconds + // packet[9 ] uint8_t pos_EW_sec_H; //#19 + min.value = (int16_t) (packet[6] + (packet[7] << 8)); + sec = (int16_t) (packet[8] + (packet[9] << 8)); + deg = min.value / 100; + min.value = min.value - deg * 100; + value = deg * 1000000 + (min.value * 1000000 + sec * 100) / 60; + if (packet[5] == 1) { + value = -value; + } + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GPS_LAT_LONG, 0, HOTT_TELEM_GPS, value, UNIT_GPS_LONGITUDE, 0); + // packet[10] uint8_t home_distance_L; //#20 meters + // packet[11] uint8_t home_distance_H; //#21 + + // packet[12] uint8_t altitude_L; //#22 meters. Value of 500 = 0m + // packet[13] uint8_t altitude_H; //#23 + value = packet[12] + (packet[13] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_03: + // packet[4 ] uint8_t climbrate_L; //#24 m/s 0.01m/s resolution. Value of 30000 = 0.00 m/s + // packet[5 ] uint8_t climbrate_H; //#25 + value = packet[4] + (packet[5] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_GPS, value, sensor->unit, sensor->precision); + + // packet[6 ] uint8_t climbrate3s; //#26 climbrate in m/3s resolution, value of 120 = 0 m/3s + // packet[7 ] uint8_t gps_satelites; //#27 sat count + sensor = getHottSensor(HOTT_ID_GPS_COUNT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_GPS_COUNT, 0, HOTT_TELEM_GPS, packet[7], sensor->unit, sensor->precision); + // packet[8 ] uint8_t gps_fix_char; //#28 GPS fix character. display, 'D' = DGPS, '2' = 2D, '3' = 3D, '-' = no fix. Where appears this char??? + // packet[9 ] uint8_t home_direction;//#29 direction from starting point to Model position (2 degree steps) + // packet[10] uint8_t angle_roll; //#30 angle roll in 2 degree steps + // packet[11] uint8_t angle_nick; //#31 angle in 2degree steps + // packet[12] uint8_t angle_compass; //#32 angle in 2degree steps. 1 = 2�, 255 = - 2� (1 uint8_t) North = 0� + // packet[13] uint8_t gps_time_h; //#33 UTC time hours + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t gps_time_m; //#34 UTC time minutes + // packet[5 ] uint8_t gps_time_s; //#35 UTC time seconds + // packet[6 ] uint8_t gps_time_sss; //#36 UTC time milliseconds + // packet[7 ] uint8_t msl_altitude_L;//#37 mean sea level altitude + // packet[8 ] uint8_t msl_altitude_H;//#38 + // packet[9 ] uint8_t vibration; //#39 vibrations level in % + // packet[10] uint8_t free_char1; //#40 appears right to home distance + // packet[11] uint8_t free_char2; //#41 appears right to home direction + // packet[12] uint8_t free_char3; //#42 GPS ASCII D=DGPS 2=2D 3=3D -=No Fix + break; + } + break; + + case HOTT_TELEM_ESC: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L454 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + // packet[7 ] uint8_t input_v_L; //#07 Input voltage low byte + // packet[8 ] uint8_t input_v_H; //#08 + value = packet[7] + (packet[8] << 8); + sensor = getHottSensor(HOTT_ID_ESC_VIN); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_VIN, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[11] uint8_t batt_cap_L; //#11 battery capacity in 10mAh steps + // packet[12] uint8_t batt_cap_H; //#12 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_BCAPA); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[13] uint8_t esc_temp; //#13 ESC temperature + value = packet[13] - 20; + sensor = getHottSensor(HOTT_ID_TEMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_02: + // packet[5 ] uint8_t current_L; //#15 Current in 0.1 steps + // packet[6 ] uint8_t current_H; //#16 + value = packet[5] + (packet[6] << 8); + sensor = getHottSensor(HOTT_ID_ESC_CUR); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_CUR, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t rpm_L; //#19 RPM in 10U/min steps + // packet[10] uint8_t rpm_H; //#20 + value = (packet[9] + (packet[10] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM1, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_03: + // packet[8 ] uint8_t bec_v; //#28 BEC voltage + value = packet[8]; + sensor = getHottSensor(HOTT_ID_ESC_VBEC); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_VBEC, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[10] uint8_t bec_current; //#30 BEC current + value = packet[10]; + sensor = getHottSensor(HOTT_ID_ESC_BCUR); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_BCUR, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t bec_temp; //#34 BEC temperature + value = packet[4] - 20; + sensor = getHottSensor(HOTT_ID_ESC_TBEC); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ESC_TBEC, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t motor_temp; //#36 Motor or external sensor temperature + value = packet[6] - 20; + sensor = getHottSensor(HOTT_ID_TEMP2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP2, 0, HOTT_TELEM_ESC, value, sensor->unit, sensor->precision); + break; + } + break; + + case HOTT_TELEM_GAM: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L151 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + sensor = getHottSensor(HOTT_ID_CELS); + // packet[7 ] uint8_t cell1_L; //#07 cell 1 voltage lower value. 0.02V steps, 124=2.48V + value = packet[7] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 0 << 16 | value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t cell2_L; //#08 + value = packet[8] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 1 << 16 | value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t cell3_L; //#09 + value = packet[9] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 2 << 16 | value, sensor->unit, sensor->precision); + // packet[10] uint8_t cell4_L; //#10 + value = packet[10] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 3 << 16 | value, sensor->unit, sensor->precision); + // packet[11] uint8_t cell5_L; //#11 + value = packet[11] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 4 << 16 | value, sensor->unit, sensor->precision); + // packet[12] uint8_t cell6_L; //#12 + value = packet[12] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 5 << 16 | value, sensor->unit, sensor->precision); + // packet[13] uint8_t batt1_L; //#13 battery 1 voltage LSB value. 0.1V steps. 50 = 5.5V + break; + + case HOTT_PAGE_02: + if (prev_page == ((HOTT_TELEM_GAM << 4) | HOTT_PAGE_01)) { + // packet[4 ] uint8_t batt1_H; //#14 + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_VOLT2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT2, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + } + // packet[5 ] uint8_t batt2_L; //#15 battery 2 voltage LSB value. 0.1V steps. 50 = 5.5V + // packet[6 ] uint8_t batt2_H; //#16 + value = packet[5] + (packet[6] << 8); + sensor = getHottSensor(HOTT_ID_VOLT3); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT3, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[7 ] uint8_t temperature1; //#17 temperature 1. offset of 20. a value of 20 = 0�C + value = packet[7] - 20; + sensor = getHottSensor(HOTT_ID_TEMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t temperature2; //#18 temperature 2. offset of 20. a value of 20 = 0�C + value = packet[8] - 20; + sensor = getHottSensor(HOTT_ID_TEMP2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP2, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t fuel_procent; //#19 Fuel capacity in %. Values 0--100, graphical display ranges: 0-25% 50% 75% 100% + value = packet[9]; + sensor = getHottSensor(HOTT_ID_FUEL); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_FUEL, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[10] uint8_t fuel_ml_L; //#20 Fuel in ml scale. Full = 65535! + // packet[11] uint8_t fuel_ml_H; //#21 + // packet[12] uint8_t rpm_L; //#22 RPM in 10 RPM steps. 300 = 3000rpm + // packet[13] uint8_t rpm_H; //#23 + value = (packet[12] + (packet[13] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_03: + // packet[4 ] uint8_t altitude_L; //#24 altitude in meters. offset of 500, 500 = 0m + // packet[5 ] uint8_t altitude_H; //#25 + value = packet[4] + (packet[5] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t climbrate_L; //#26 climb rate in 0.01m/s. Value of 30000 = 0.00 m/s + // packet[7 ] uint8_t climbrate_H; //#27 + value = packet[6] + (packet[7] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t climbrate3s; //#28 climb rate in m/3sec. Value of 120 = 0m/3sec + // packet[9 ] uint8_t current_L; //#29 current in 0.1A steps + // packet[10] uint8_t current_H; //#30 + value = packet[9] + (packet[10] << 8); + sensor = getHottSensor(HOTT_ID_AMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AMP1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[11] uint8_t main_voltage_L; //#31 Main power voltage using 0.1V steps + // packet[12] uint8_t main_voltage_H; //#32 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_VOLT1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT1, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[13] uint8_t batt_cap_L; //#33 used battery capacity in 10mAh steps + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t batt_cap_H; //#34 + if (prev_page == ((HOTT_TELEM_GAM << 4) | HOTT_PAGE_03)) { + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_BCAPA); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + } + // packet[5 ] uint8_t speed_L; //#35 (air?) speed in km/h(?) we are using ground speed here per default + // packet[6 ] uint8_t speed_H; //#36 + value = packet[5] + (packet[6] << 8); + sensor = getHottSensor(HOTT_ID_AIR_SPEED); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AIR_SPEED, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[7 ] uint8_t min_cell_volt; //#37 minimum cell voltage in 2mV steps. 124 = 2,48V + // packet[8 ] uint8_t min_cell_volt_num; //#38 number of the cell with the lowest voltage + // packet[9 ] uint8_t rpm2_L; //#39 RPM in 10 RPM steps. 300 = 3000rpm + // packet[10] uint8_t rpm2_H; //#40 + value = (packet[9] + (packet[10] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM2, 0, HOTT_TELEM_GAM, value, sensor->unit, sensor->precision); + // packet[11] uint8_t general_error_number;//#41 Voice error == 12. TODO: more docu + // packet[12] uint8_t pressure; //#42 Pressure up to 16bar. 0,1bar scale. 20 = 2bar + break; + } + break; + + case HOTT_TELEM_EAM: + // https://github.com/betaflight/betaflight/blob/1d8a0e9fd61cf01df7b34805e84365df72d9d68d/src/main/telemetry/hott.h#L288 + switch (packet[3]) { // Telemetry page 1,2,3,4 + case HOTT_PAGE_01: + sensor = getHottSensor(HOTT_ID_CELS); + // packet[7 ] uint8_t cell1_L; //#07 cell 1 voltage lower value. 0.02V steps, 124=2.48V + value = packet[7] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 0 << 16 | value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t cell2_L; //#08 + value = packet[8] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 1 << 16 | value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t cell3_L; //#09 + value = packet[9] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 2 << 16 | value, sensor->unit, sensor->precision); + // packet[10] uint8_t cell4_L; //#10 + value = packet[10] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 3 << 16 | value, sensor->unit, sensor->precision); + // packet[11] uint8_t cell5_L; //#11 + value = packet[11] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 4 << 16 | value, sensor->unit, sensor->precision); + // packet[12] uint8_t cell6_L; //#12 + value = packet[12] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 5 << 16 | value, sensor->unit, sensor->precision); + // packet[13] uint8_t cell7_L; //#13 + // value = packet[13] << 1; + // if(value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 6 << 16 | value, sensor->unit, sensor->precision); + break; + + case HOTT_PAGE_02: + sensor = getHottSensor(HOTT_ID_CELS); + // packet[4 ] uint8_t cell1_H; //#14 cell 1 voltage high value. 0.02V steps, 124=2.48V + value = packet[4] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 0 << 16 | value, sensor->unit, sensor->precision); + // packet[5 ] uint8_t cell2_H; //#15 + value = packet[5] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 1 << 16 | value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t cell3_H; //#16 + value = packet[6] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 2 << 16 | value, sensor->unit, sensor->precision); + // packet[7 ] uint8_t cell4_H; //#17 + value = packet[7] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 3 << 16 | value, sensor->unit, sensor->precision); + // packet[8 ] uint8_t cell5_H; //#18 + value = packet[8] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 4 << 16 | value, sensor->unit, sensor->precision); + // packet[9 ] uint8_t cell6_H; //#19 + value = packet[9] << 1; + if (value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS_H, 0, HOTT_TELEM_EAM, 5 << 16 | value, sensor->unit, sensor->precision); + // packet[10] uint8_t cell7_H; //#20 + //value = packet[10] << 1; + //if(value) setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_CELS, 0, HOTT_TELEM_EAM, 13 << 16 | value, sensor->unit, sensor->precision); + // packet[11] uint8_t batt1_voltage_L; //#21 battery 1 voltage lower value in 100mv steps, 50=5V. optionally cell8_L value 0.02V steps + // packet[12] uint8_t batt1_voltage_H; //#22 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_VOLT2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT2, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[13] uint8_t batt2_voltage_L; //#23 battery 2 voltage lower value in 100mv steps, 50=5V. optionally cell8_H value. 0.02V steps + break; + + case HOTT_PAGE_03: + if (prev_page == ((HOTT_TELEM_EAM << 4) | HOTT_PAGE_02)) { + // packet[4 ] uint8_t batt2_voltage_H; //#24 + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_VOLT3); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT3, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + } + // packet[5 ] uint8_t temp1; //#25 Temperature sensor 1. 20=0�, 46=26� - offset of 20. + value = packet[5] - 20; + sensor = getHottSensor(HOTT_ID_TEMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[6 ] uint8_t temp2; //#26 temperature sensor 2 + value = packet[6] - 20; + sensor = getHottSensor(HOTT_ID_TEMP2); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP2, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[7 ] uint8_t altitude_L; //#27 Attitude lower value. unit: meters. Value of 500 = 0m + // packet[8 ] uint8_t altitude_H; //#28 + value = packet[7] + (packet[8] << 8) - 500; + sensor = getHottSensor(HOTT_ID_ALT); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_ALT, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[9 ] uint8_t current_L; //#29 Current in 0.1 steps + // packet[10] uint8_t current_H; //#30 + value = packet[9] + (packet[10] << 8); + sensor = getHottSensor(HOTT_ID_AMP1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AMP1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[11] uint8_t main_voltage_L; //#31 Main power voltage (drive) in 0.1V steps + // packet[12] uint8_t main_voltage_H; //#32 + value = packet[11] + (packet[12] << 8); + sensor = getHottSensor(HOTT_ID_VOLT1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VOLT1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[13] uint8_t batt_cap_L; //#33 used battery capacity in 10mAh steps + break; + + case HOTT_PAGE_04: + // packet[4 ] uint8_t batt_cap_H; //#34 + if (prev_page == ((HOTT_TELEM_EAM << 4) | HOTT_PAGE_03)) { + value = prev_value + (packet[4] << 8); + sensor = getHottSensor(HOTT_ID_BCAPA); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_BCAPA, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + } + + // packet[5 ] uint8_t climbrate_L; //#35 climb rate in 0.01m/s. Value of 30000 = 0.00 m/s + // packet[6 ] uint8_t climbrate_H; //#36 + value = packet[5] + (packet[6] << 8) - 30000; + sensor = getHottSensor(HOTT_ID_VARIO); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_VARIO, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + + // packet[7 ] uint8_t climbrate3s; //#37 climbrate in m/3sec. Value of 120 = 0m/3sec + // packet[8 ] uint8_t rpm_L; //#38 RPM. Steps: 10 U/min + // packet[9 ] uint8_t rpm_H; //#39 + value = (packet[8] + (packet[9] << 8)) * 10; + sensor = getHottSensor(HOTT_ID_RPM1); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RPM1, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + // packet[10] uint8_t electric_min; //#40 Electric minutes. Time does start, when motor current is > 3 A + // packet[11] uint8_t electric_sec; //#41 + // packet[12] uint8_t speed_L; //#42 (air?) speed in km/h. Steps 1km/h + // packet[13] uint8_t speed_H; //#43 + value = packet[12] + (packet[13] << 8); + sensor = getHottSensor(HOTT_ID_AIR_SPEED); + setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_AIR_SPEED, 0, HOTT_TELEM_EAM, value, sensor->unit, sensor->precision); + break; + } + break; } + prev_page = (packet[2] << 4) | packet[3]; // concatenate telemetry type and page + prev_value = packet[13]; // page overflow } void hottSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance) diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index 55f09eed3..42f612d57 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -21,6 +21,7 @@ #include "telemetry.h" #include "multi.h" +constexpr int32_t MULTI_DESIRED_VERSION = (1 << 24) | (3 << 16) | (1 << 8) | 1; #define MULTI_CHAN_BITS 11 extern uint8_t g_moduleIdx; @@ -561,7 +562,7 @@ void MultiModuleStatus::getStatusString(char * statusText) const return; } - if (major <= 1 && minor <= 3 && revision <= 0 && patch < 91 && SLOW_BLINK_ON_PHASE) { + if ((((major << 24) | (minor << 16) | (revision << 8) | patch) < MULTI_DESIRED_VERSION) && SLOW_BLINK_ON_PHASE) { strcpy(statusText, STR_MODULE_UPGRADE); } else { diff --git a/radio/src/telemetry/telemetry_holders.h b/radio/src/telemetry/telemetry_holders.h index 9db8d629f..3e99b27f4 100644 --- a/radio/src/telemetry/telemetry_holders.h +++ b/radio/src/telemetry/telemetry_holders.h @@ -27,6 +27,7 @@ #define TELEMETRY_AVERAGE_COUNT 3 // we actually average one more reading! #define RAW_FRSKY_MINMAX(v) v.values[TELEMETRY_AVERAGE_COUNT-1] +#define MAX_CELLS 6 class TelemetryValue { public: diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index 66b0e2255..1d0eb89b6 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -90,6 +90,8 @@ void TelemetryItem::setValue(const TelemetrySensor & sensor, int32_t val, uint32 uint32_t data = uint32_t(newVal); uint8_t cellsCount = (data >> 24); uint8_t cellIndex = ((data >> 16) & 0x0F); + if (cellIndex >= MAX_CELLS) + return; uint16_t cellValue = (data & 0xFFFF); if (cellsCount == 0) { cellsCount = (cellIndex >= cells.count ? cellIndex + 1 : cells.count); diff --git a/radio/src/telemetry/telemetry_sensors.h b/radio/src/telemetry/telemetry_sensors.h index def941861..6ca1c0c97 100644 --- a/radio/src/telemetry/telemetry_sensors.h +++ b/radio/src/telemetry/telemetry_sensors.h @@ -57,7 +57,7 @@ class TelemetryItem } consumption; struct { uint8_t count; - CellValue values[6]; + CellValue values[MAX_CELLS]; } cells; struct { uint16_t year; // full year (4 digits)