diff --git a/OTX_ETX/bw128x64/SRC/yaapu7.lua b/OTX_ETX/bw128x64/SRC/yaapu7.lua index 61ea6cc6..8b338cbe 100644 --- a/OTX_ETX/bw128x64/SRC/yaapu7.lua +++ b/OTX_ETX/bw128x64/SRC/yaapu7.lua @@ -221,6 +221,9 @@ status.showMinMaxValues = false status.terrainLastData = getTime() status.terrainEnabled = 0 status.airspeedEnabled = 0 +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- 00 05 10 15 20 25 30 40 50 60 70 80 90 -- MIN MAX @@ -563,6 +566,11 @@ local function reset() noTelemetryData = 1 hideNoTelemetry = false --------------- + -- READY TO ARM (RDY sensor) + --------------- + status.readyToArm = false + status.lastPassthroughTime = 0 + --------------- -- FLIGHT TIME --------------- lastTimerStart = 0 @@ -655,7 +663,20 @@ local function resetHash() hashByteIndex = 0 end +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if string.find(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif string.find(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId, value, now) + -- RDY sensor: track link freshness, a passthrough frame was just decoded + status.lastPassthroughTime = now if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] telemetry.roll = (math.min(bit32.extract(value,0,11),1800) - 900) * 0.2 @@ -740,6 +761,7 @@ local function processTelemetry(appId, value, now) if msgEnd then -- push and display message local severity = (bit32.extract(value,7,1) * 1) + (bit32.extract(value,15,1) * 2) + (bit32.extract(value,23,1) * 4) + checkReadyToArmMessage(msgBuffer) pushMessage( severity, msgBuffer) playHash() resetHash() @@ -813,6 +835,7 @@ local function crossfirePop() -- hash support updateHash(data[i]) end + checkReadyToArmMessage(msgBuffer) pushMessage(severity, msgBuffer) -- hash audio support playHash() @@ -1117,7 +1140,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not telemetryEnabled() then return end @@ -1416,6 +1458,14 @@ local function background() end -- SLOW: this runs at 4Hz (every 250ms) if (bgclock % 4 == 0) then + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() updateTotalDist(now) end diff --git a/OTX_ETX/bw212x64_f2/SRC/yaapu9.lua b/OTX_ETX/bw212x64_f2/SRC/yaapu9.lua index 5521a8e4..69580410 100644 --- a/OTX_ETX/bw212x64_f2/SRC/yaapu9.lua +++ b/OTX_ETX/bw212x64_f2/SRC/yaapu9.lua @@ -211,6 +211,9 @@ status.flightTime = 0 -- updated from model timer 3 status.timerRunning = 0 -- triggered by landcomplete from AP status.showMinMaxValues = false status.airspeedEnabled = 0 +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- 00 05 10 15 20 25 30 40 50 60 70 80 90 -- MIN MAX @@ -551,6 +554,11 @@ local function reset() noTelemetryData = 1 hideNoTelemetry = false --------------- + -- READY TO ARM (RDY sensor) + --------------- + status.readyToArm = false + status.lastPassthroughTime = 0 + --------------- -- FLIGHT TIME --------------- lastTimerStart = 0 @@ -643,7 +651,20 @@ local function resetHash() hashByteIndex = 0 end +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if string.find(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif string.find(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId, value, now) + -- RDY sensor: track link freshness, a passthrough frame was just decoded + status.lastPassthroughTime = now if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] telemetry.roll = (math.min(bit32.extract(value,0,11),1800) - 900) * 0.2 @@ -726,6 +747,7 @@ local function processTelemetry(appId, value, now) if msgEnd then -- push and display message local severity = (bit32.extract(value,7,1) * 1) + (bit32.extract(value,15,1) * 2) + (bit32.extract(value,23,1) * 4) + checkReadyToArmMessage(msgBuffer) pushMessage( severity, msgBuffer) playHash() resetHash() @@ -788,6 +810,7 @@ local function crossfirePop() -- hash support updateHash(data[i]) end + checkReadyToArmMessage(msgBuffer) pushMessage(severity, msgBuffer) -- hash audio support playHash() @@ -1086,7 +1109,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not telemetryEnabled() then return end @@ -1380,6 +1422,14 @@ local function background() end -- SLOW: this runs at 4Hz (every 250ms) if (bgclock % 4 == 0) then + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() updateTotalDist(now) end diff --git a/OTX_ETX/bw212x64_f4/SRC/yaapu9.lua b/OTX_ETX/bw212x64_f4/SRC/yaapu9.lua index 45481a1d..29648a41 100644 --- a/OTX_ETX/bw212x64_f4/SRC/yaapu9.lua +++ b/OTX_ETX/bw212x64_f4/SRC/yaapu9.lua @@ -221,6 +221,9 @@ status.showMinMaxValues = false status.terrainLastData = getTime() status.terrainEnabled = 0 status.airspeedEnabled = 0 +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- 00 05 10 15 20 25 30 40 50 60 70 80 90 -- MIN MAX @@ -563,6 +566,11 @@ local function reset() noTelemetryData = 1 hideNoTelemetry = false --------------- + -- READY TO ARM (RDY sensor) + --------------- + status.readyToArm = false + status.lastPassthroughTime = 0 + --------------- -- FLIGHT TIME --------------- lastTimerStart = 0 @@ -655,7 +663,20 @@ local function resetHash() hashByteIndex = 0 end +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if string.find(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif string.find(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId, value, now) + -- RDY sensor: track link freshness, a passthrough frame was just decoded + status.lastPassthroughTime = now if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] telemetry.roll = (math.min(bit32.extract(value,0,11),1800) - 900) * 0.2 @@ -740,6 +761,7 @@ local function processTelemetry(appId, value, now) if msgEnd then -- push and display message local severity = (bit32.extract(value,7,1) * 1) + (bit32.extract(value,15,1) * 2) + (bit32.extract(value,23,1) * 4) + checkReadyToArmMessage(msgBuffer) pushMessage( severity, msgBuffer) playHash() resetHash() @@ -813,6 +835,7 @@ local function crossfirePop() -- hash support updateHash(data[i]) end + checkReadyToArmMessage(msgBuffer) pushMessage(severity, msgBuffer) -- hash audio support playHash() @@ -1117,7 +1140,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not telemetryEnabled() then return end @@ -1416,6 +1458,14 @@ local function background() end -- SLOW: this runs at 4Hz (every 250ms) if (bgclock % 4 == 0) then + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() updateTotalDist(now) end diff --git a/OTX_ETX/c320x240/SD/WIDGETS/yaapu/main.lua b/OTX_ETX/c320x240/SD/WIDGETS/yaapu/main.lua index 46c61d81..1f2dd9c1 100644 --- a/OTX_ETX/c320x240/SD/WIDGETS/yaapu/main.lua +++ b/OTX_ETX/c320x240/SD/WIDGETS/yaapu/main.lua @@ -321,6 +321,9 @@ status.noTelemetryData = 1 status.hideNoTelemetry = false status.showDualBattery = false status.showMinMaxValues = false +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- MAP status.screenTogglePage = 1 status.mapZoomLevel = 1 @@ -1270,12 +1273,26 @@ end -- Lookup table for 10^x local POW10 = {[0]=1, [1]=10, [2]=100, [3]=1000} +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if sFind(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif sFind(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId,value,now) -- local global tables cache local t = telemetry local s = status local c = conf + -- RDY sensor: track link freshness, a passthrough frame was just decoded + s.lastPassthroughTime = now + if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] t.roll = (m_min(b_extract(value,0,11),1800) - 900) * 0.2 @@ -1360,6 +1377,7 @@ local function processTelemetry(appId,value,now) s.msgBuffer = (s.msgBuffer or "")..t_concat(chunk) if msgEnd then local severity = (b_extract(value,7,1) * 1) + (b_extract(value,15,1) * 2) + (b_extract(value,23,1) * 4) + checkReadyToArmMessage(s.msgBuffer) utils.pushMessage( severity, s.msgBuffer) playHash() resetHash() @@ -1800,6 +1818,9 @@ local function resetTelemetry() -- RSSI telemetry.rssi = 0 telemetry.rssiCRSF = 0 + -- READY TO ARM (RDY sensor) + status.readyToArm = false + status.lastPassthroughTime = 0 end local function resetStatus() @@ -1959,7 +1980,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not utils.telemetryEnabled() then return end @@ -2351,6 +2391,7 @@ local function crossfirePop() updateHash(data[i]) end status.msgBuffer = table.concat(msg) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage(severity, status.msgBuffer) -- hash audio support playHash() @@ -2491,6 +2532,14 @@ local function task2HzB(widget, now) updateCog = 1 end end + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() calcFlightTime() -- update gps telemetry data diff --git a/OTX_ETX/c320x480/SD/WIDGETS/yaapu/main.lua b/OTX_ETX/c320x480/SD/WIDGETS/yaapu/main.lua index ee0b355b..b2535f93 100644 --- a/OTX_ETX/c320x480/SD/WIDGETS/yaapu/main.lua +++ b/OTX_ETX/c320x480/SD/WIDGETS/yaapu/main.lua @@ -321,6 +321,9 @@ status.noTelemetryData = 1 status.hideNoTelemetry = false status.showDualBattery = false status.showMinMaxValues = false +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- MAP status.screenTogglePage = 1 status.mapZoomLevel = 1 @@ -1091,7 +1094,20 @@ local function wrap360(angle) return res end +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if string.find(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif string.find(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId,value,now) + -- RDY sensor: track link freshness, a passthrough frame was just decoded + status.lastPassthroughTime = now if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] telemetry.roll = (math.min(bit32.extract(value,0,11),1800) - 900) * 0.2 @@ -1176,6 +1192,7 @@ local function processTelemetry(appId,value,now) status.msgBuffer = status.msgBuffer..table.concat(chunk) if msgEnd then local severity = (bit32.extract(value,7,1) * 1) + (bit32.extract(value,15,1) * 2) + (bit32.extract(value,23,1) * 4) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage( severity, status.msgBuffer) playHash() resetHash() @@ -1625,6 +1642,9 @@ local function resetTelemetry() -- RSSI telemetry.rssi = 0 telemetry.rssiCRSF = 0 + -- READY TO ARM (RDY sensor) + status.readyToArm = false + status.lastPassthroughTime = 0 end local function resetStatus() @@ -1784,7 +1804,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not utils.telemetryEnabled() then return end @@ -2170,6 +2209,7 @@ local function crossfirePop() updateHash(data[i]) end status.msgBuffer = table.concat(msg) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage(severity, status.msgBuffer) -- hash audio support playHash() @@ -2310,6 +2350,14 @@ local function task2HzB(widget, now) updateCog = 1 end end + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() calcFlightTime() -- update gps telemetry data diff --git a/OTX_ETX/c480x272/SD/WIDGETS/yaapu/main.lua b/OTX_ETX/c480x272/SD/WIDGETS/yaapu/main.lua index 9383e35e..b68eb53a 100644 --- a/OTX_ETX/c480x272/SD/WIDGETS/yaapu/main.lua +++ b/OTX_ETX/c480x272/SD/WIDGETS/yaapu/main.lua @@ -321,6 +321,9 @@ status.noTelemetryData = 1 status.hideNoTelemetry = false status.showDualBattery = false status.showMinMaxValues = false +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- MAP status.screenTogglePage = 1 status.mapZoomLevel = 1 @@ -1091,7 +1094,20 @@ local function wrap360(angle) return res end +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if string.find(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif string.find(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId,value,now) + -- RDY sensor: track link freshness, a passthrough frame was just decoded + status.lastPassthroughTime = now if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] telemetry.roll = (math.min(bit32.extract(value,0,11),1800) - 900) * 0.2 @@ -1176,6 +1192,7 @@ local function processTelemetry(appId,value,now) status.msgBuffer = status.msgBuffer..table.concat(chunk) if msgEnd then local severity = (bit32.extract(value,7,1) * 1) + (bit32.extract(value,15,1) * 2) + (bit32.extract(value,23,1) * 4) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage( severity, status.msgBuffer) playHash() resetHash() @@ -1625,6 +1642,9 @@ local function resetTelemetry() -- RSSI telemetry.rssi = 0 telemetry.rssiCRSF = 0 + -- READY TO ARM (RDY sensor) + status.readyToArm = false + status.lastPassthroughTime = 0 end local function resetStatus() @@ -1784,7 +1804,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not utils.telemetryEnabled() then return end @@ -2177,6 +2216,7 @@ local function crossfirePop() updateHash(data[i]) end status.msgBuffer = table.concat(msg) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage(severity, status.msgBuffer) -- hash audio support playHash() @@ -2317,6 +2357,14 @@ local function task2HzB(widget, now) updateCog = 1 end end + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() calcFlightTime() -- update gps telemetry data diff --git a/OTX_ETX/c480x320/SD/WIDGETS/yaapu/main.lua b/OTX_ETX/c480x320/SD/WIDGETS/yaapu/main.lua index 9383e35e..b68eb53a 100644 --- a/OTX_ETX/c480x320/SD/WIDGETS/yaapu/main.lua +++ b/OTX_ETX/c480x320/SD/WIDGETS/yaapu/main.lua @@ -321,6 +321,9 @@ status.noTelemetryData = 1 status.hideNoTelemetry = false status.showDualBattery = false status.showMinMaxValues = false +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- MAP status.screenTogglePage = 1 status.mapZoomLevel = 1 @@ -1091,7 +1094,20 @@ local function wrap360(angle) return res end +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if string.find(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif string.find(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId,value,now) + -- RDY sensor: track link freshness, a passthrough frame was just decoded + status.lastPassthroughTime = now if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] telemetry.roll = (math.min(bit32.extract(value,0,11),1800) - 900) * 0.2 @@ -1176,6 +1192,7 @@ local function processTelemetry(appId,value,now) status.msgBuffer = status.msgBuffer..table.concat(chunk) if msgEnd then local severity = (bit32.extract(value,7,1) * 1) + (bit32.extract(value,15,1) * 2) + (bit32.extract(value,23,1) * 4) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage( severity, status.msgBuffer) playHash() resetHash() @@ -1625,6 +1642,9 @@ local function resetTelemetry() -- RSSI telemetry.rssi = 0 telemetry.rssiCRSF = 0 + -- READY TO ARM (RDY sensor) + status.readyToArm = false + status.lastPassthroughTime = 0 end local function resetStatus() @@ -1784,7 +1804,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not utils.telemetryEnabled() then return end @@ -2177,6 +2216,7 @@ local function crossfirePop() updateHash(data[i]) end status.msgBuffer = table.concat(msg) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage(severity, status.msgBuffer) -- hash audio support playHash() @@ -2317,6 +2357,14 @@ local function task2HzB(widget, now) updateCog = 1 end end + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() calcFlightTime() -- update gps telemetry data diff --git a/OTX_ETX/c800x480/SD/WIDGETS/yaapu/main.lua b/OTX_ETX/c800x480/SD/WIDGETS/yaapu/main.lua index fe11a6c4..fc788c76 100644 --- a/OTX_ETX/c800x480/SD/WIDGETS/yaapu/main.lua +++ b/OTX_ETX/c800x480/SD/WIDGETS/yaapu/main.lua @@ -321,6 +321,9 @@ status.noTelemetryData = 1 status.hideNoTelemetry = false status.showDualBattery = false status.showMinMaxValues = false +-- READY TO ARM (RDY sensor) +status.readyToArm = false +status.lastPassthroughTime = 0 -- MAP status.screenTogglePage = 1 status.mapZoomLevel = 1 @@ -1270,12 +1273,26 @@ end -- Lookup table for 10^x local POW10 = {[0]=1, [1]=10, [2]=100, [3]=1000} +-- RDY sensor: the ready to arm evidence is scoped to the current FC power cycle +local function checkReadyToArmMessage(msg) + if sFind(msg, "ArduCopter V", 1, true) ~= nil then + -- FC boot banner, a new power cycle invalidates any previous evidence + status.readyToArm = false + elseif sFind(msg, "using GPS", 1, true) ~= nil then + -- "EKF3 IMUx is using GPS", the FC has a GPS aided EKF solution + status.readyToArm = true + end +end + local function processTelemetry(appId,value,now) -- local global tables cache local t = telemetry local s = status local c = conf + -- RDY sensor: track link freshness, a passthrough frame was just decoded + s.lastPassthroughTime = now + if appId == 0x5006 then -- ROLLPITCH -- roll [0,1800] ==> [-180,180] t.roll = (m_min(b_extract(value,0,11),1800) - 900) * 0.2 @@ -1360,6 +1377,7 @@ local function processTelemetry(appId,value,now) s.msgBuffer = (s.msgBuffer or "")..t_concat(chunk) if msgEnd then local severity = (b_extract(value,7,1) * 1) + (b_extract(value,15,1) * 2) + (b_extract(value,23,1) * 4) + checkReadyToArmMessage(s.msgBuffer) utils.pushMessage( severity, s.msgBuffer) playHash() resetHash() @@ -1800,6 +1818,9 @@ local function resetTelemetry() -- RSSI telemetry.rssi = 0 telemetry.rssiCRSF = 0 + -- READY TO ARM (RDY sensor) + status.readyToArm = false + status.lastPassthroughTime = 0 end local function resetStatus() @@ -1959,7 +1980,26 @@ local function calcFlightTime() status.flightTime = model.getTimer(2).value end +-- RDY sensor: 100 when the FC is effectively ready to arm, 0 otherwise +local function getReadyToArmValue() + -- no recent passthrough frame, the FC is powered down or the link is gone + if status.lastPassthroughTime == 0 then + return 0 + end + -- authoritative, the FC announced a GPS aided EKF solution this power cycle + if status.readyToArm == true then + return 100 + end + -- fallback composite from the repeating 0x5002 GPS STATUS frame + if (telemetry.gpsStatus or 0) >= 3 and (telemetry.gpsHdopC or 100) <= 14 and (telemetry.numSats or 0) >= 10 then + return 100 + end + return 0 +end + local function setSensorValues() + -- RDY is published even without a live link so it can always fall back to 0 + setTelemetryValue(0x060F, 0, 2, getReadyToArmValue(), 0 , 0 , "RDY") if not utils.telemetryEnabled() then return end @@ -2355,6 +2395,7 @@ local function crossfirePop() updateHash(data[i]) end status.msgBuffer = table.concat(msg) + checkReadyToArmMessage(status.msgBuffer) utils.pushMessage(severity, status.msgBuffer) -- hash audio support playHash() @@ -2495,6 +2536,14 @@ local function task2HzB(widget, now) updateCog = 1 end end + -- RDY sensor: expire the ready to arm state 8s after the last passthrough frame + if status.lastPassthroughTime ~= 0 then + local elapsed = now - status.lastPassthroughTime + if elapsed > 800 or elapsed < 0 then + status.readyToArm = false + status.lastPassthroughTime = 0 + end + end setSensorValues() calcFlightTime() -- update gps telemetry data