diff --git a/HORUS/IMAGES/horus_wstep15.png b/HORUS/IMAGES/horus_wstep15.png index 78d2c364..588ce9d1 100644 Binary files a/HORUS/IMAGES/horus_wstep15.png and b/HORUS/IMAGES/horus_wstep15.png differ diff --git a/HORUS/IMAGES/horus_wstep16.png b/HORUS/IMAGES/horus_wstep16.png index 67965183..6ee6a6ba 100644 Binary files a/HORUS/IMAGES/horus_wstep16.png and b/HORUS/IMAGES/horus_wstep16.png differ diff --git a/HORUS/IMAGES/horus_wstep17.png b/HORUS/IMAGES/horus_wstep17.png index cfc62eff..31e44f25 100644 Binary files a/HORUS/IMAGES/horus_wstep17.png and b/HORUS/IMAGES/horus_wstep17.png differ diff --git a/HORUS/IMAGES/horus_wstep20.png b/HORUS/IMAGES/horus_wstep20.png index 44eab6d8..a97f6828 100644 Binary files a/HORUS/IMAGES/horus_wstep20.png and b/HORUS/IMAGES/horus_wstep20.png differ diff --git a/HORUS/IMAGES/horus_wstep22.png b/HORUS/IMAGES/horus_wstep22.png index fd05f67b..a6ef7594 100644 Binary files a/HORUS/IMAGES/horus_wstep22.png and b/HORUS/IMAGES/horus_wstep22.png differ diff --git a/HORUS/IMAGES/horus_wstep27.png b/HORUS/IMAGES/horus_wstep27.png index a8838f46..5072bc95 100644 Binary files a/HORUS/IMAGES/horus_wstep27.png and b/HORUS/IMAGES/horus_wstep27.png differ diff --git a/HORUS/IMAGES/horus_wstep28.png b/HORUS/IMAGES/horus_wstep28.png index cdf53e54..a6ef7594 100644 Binary files a/HORUS/IMAGES/horus_wstep28.png and b/HORUS/IMAGES/horus_wstep28.png differ diff --git a/HORUS/IMAGES/horus_wstep7.png b/HORUS/IMAGES/horus_wstep7.png index 52dcd77d..588ce9d1 100644 Binary files a/HORUS/IMAGES/horus_wstep7.png and b/HORUS/IMAGES/horus_wstep7.png differ diff --git a/HORUS/IMAGES/horus_wstep8.png b/HORUS/IMAGES/horus_wstep8.png index fc8e0fbd..6ee6a6ba 100644 Binary files a/HORUS/IMAGES/horus_wstep8.png and b/HORUS/IMAGES/horus_wstep8.png differ diff --git a/HORUS/IMAGES/x10.png b/HORUS/IMAGES/x10.png index 165c704a..47d71447 100644 Binary files a/HORUS/IMAGES/x10.png and b/HORUS/IMAGES/x10.png differ diff --git a/HORUS/IMAGES/x10displayinfo.png b/HORUS/IMAGES/x10displayinfo.png index d45199c9..4ec92642 100644 Binary files a/HORUS/IMAGES/x10displayinfo.png and b/HORUS/IMAGES/x10displayinfo.png differ diff --git a/HORUS/IMAGES/x10dualbattery.png b/HORUS/IMAGES/x10dualbattery.png index a76ef015..ad07673e 100644 Binary files a/HORUS/IMAGES/x10dualbattery.png and b/HORUS/IMAGES/x10dualbattery.png differ diff --git a/HORUS/IMAGES/x10menu.png b/HORUS/IMAGES/x10menu.png index 2e915d2f..5072bc95 100644 Binary files a/HORUS/IMAGES/x10menu.png and b/HORUS/IMAGES/x10menu.png differ diff --git a/HORUS/IMAGES/x10messages.png b/HORUS/IMAGES/x10messages.png index 4dd1405b..c316a2f4 100644 Binary files a/HORUS/IMAGES/x10messages.png and b/HORUS/IMAGES/x10messages.png differ diff --git a/HORUS/IMAGES/x10minmax.png b/HORUS/IMAGES/x10minmax.png index 8ec93a90..092bd102 100644 Binary files a/HORUS/IMAGES/x10minmax.png and b/HORUS/IMAGES/x10minmax.png differ diff --git a/HORUS/IMAGES/x12displayinfo.png b/HORUS/IMAGES/x12displayinfo.png index fe7efb1d..4ec92642 100644 Binary files a/HORUS/IMAGES/x12displayinfo.png and b/HORUS/IMAGES/x12displayinfo.png differ diff --git a/HORUS/SD/README.md b/HORUS/SD/README.md new file mode 100644 index 00000000..5fadf553 --- /dev/null +++ b/HORUS/SD/README.md @@ -0,0 +1 @@ +copy the content of this folder to your radio SD card \ No newline at end of file diff --git a/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/flvss_sensors.lua b/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/flvss_sensors.lua new file mode 100644 index 00000000..9838e7fe --- /dev/null +++ b/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/flvss_sensors.lua @@ -0,0 +1,105 @@ +---------------------------------------- +-- custom sensors configuration file +---------------------------------------- +local sensors = { + -- Sensor 1 +[1]= { + "Celm", -- label + "Celm", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, + + -- Sensor 2 +[2]= { + "Celd", -- label + "Celd", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, + + -- Sensor 3 +[3]= { + "Cel4", -- label + "Cel4", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 4 +[4]= { + "Cel3", -- label + "Cel3", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 5 +[5]= { + "Cel2", -- label + "Cel2", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 6 +[6]= { + "Cell", -- label + "Cel1", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, +} +------------------------------------------------------ +-- the script can optionally look up values here +-- for each sensor and display the corresponding text instead +-- as an example to associate a lookup table to sensor 3 declare it like +-- +--local lookups = { +-- [3] = { +-- [-10] = "ERR", +-- [0] = "OK", +-- [10] = "CRIT", +-- } +-- } +-- this would display the sensor value except when the value corresponds to one +-- of entered above +-- +local lookups = { +} + +collectgarbage() + +return { + sensors=sensors,lookups=lookups +} diff --git a/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/gsuite_sensors.lua b/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/gsuite_sensors.lua new file mode 100644 index 00000000..7d1a2137 --- /dev/null +++ b/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/gsuite_sensors.lua @@ -0,0 +1,132 @@ +---------------------------------------- +-- custom sensors configuration file +---------------------------------------- +--[[ +GRPc - residual percent +GFlo - flow mL/min +GMFl - max flow mL/min +GAFl - avg flow mL/min +GTp1 - temp 1 C° +GTp2 - temp 2 C° +GRPM - RPM + +--]] +local sensors = { + -- Sensor 1 +[1]= { + "Eng", -- label + "GRPM", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "rpm", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, + -- Sensor 2 +[2]= { + "Temp1", -- label + "GTp1", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "C", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, + + -- Sensor 3 +[3]= { + "Temp2", -- label + "GTp2", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "C", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, + + -- Sensor 4 +[4]= { + "Flow", -- label + "GFlo", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "mL", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, + + -- Sensor 5 +[5]= { + "AFlow", -- label + "GAFl", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "mL", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, + + -- Sensor 6 +[6]= { + "Fuel", -- label + "GRpc", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "%", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + nil, -- warning level (nil is do not use feature) + nil, -- critical level (nil is do not use feature) + }, +} +------------------------------------------------------ +-- the script can optionally look up values here +-- for each sensor and display the corresponding text instead +-- as an example to associate a lookup table to sensor 3 declare it like +-- +-- [3] = { +-- [-10] = "ERR", +-- [0] = "OK", +-- [10] = "CRIT", +-- } +-- this would display the sensor value except when the value corresponds to one +-- of entered above +-- +local lookups = { + -- lookup 2 + --[[ + [6] = { + [-30] = "ERROR", + [-20] = "OFF", + [-10] = "COOL", + [-1] = "LOCK", + [0] = "STOP", + [10] = "RUN", + [20] = "REL", + [25] = "GLOW", + [30] = "SPIN", + [40] = "FIRE", + [45] = "IGNT", + [50] = "HEAT", + [60] = "ACCE", + [65] = "CAL", + [70] = "IDLE", + }, + --]] +} + +collectgarbage() + +return { + sensors=sensors,lookups=lookups +} \ No newline at end of file diff --git a/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/kerojet_sensors.lua b/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/kerojet_sensors.lua new file mode 100644 index 00000000..7a9422b6 --- /dev/null +++ b/HORUS/SD/SCRIPTS/YAAPU/CFG/examples/kerojet_sensors.lua @@ -0,0 +1,129 @@ +---------------------------------------- +-- custom sensors configuration file +---------------------------------------- +--[[ +S1:Pump,A4,2,V,1,+,1, +S2:Fuel,Fuel,0,ml,1,+,1, +S3:ENG,RPM,0,krpm,100,+,1, +S4:EGT,Tmp1,0,C,1,+,1, +S5:THRO,Thro,0,%,1,+,1, +S6:Status,Tmp2,0,C,1,-,1 +--]] +local sensors = { + -- Sensor 1 + { + "Pump", -- label + "A4", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 1, -- font size 1=small, 2=big + 5, -- warning level (nil is do not use feature) + 10, -- critical level (nil is do not use feature) + }, + + -- Sensor 2 + { + "Fuel", -- label + "Fuel", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "mL", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values + 1, -- font size 1=small, 2=big + 1000, -- warning level + 2000, -- critical level + }, + + -- Sensor 3 + { + "ENG", -- label + "RPM", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "krpm", -- label for unit of measure + 0.001, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 1000, -- warning level + 2000, -- critical value + }, + + -- Sensor 4 + { + "EGT", -- label + "Tmp1", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "C", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 100, -- warning level + 200, -- critical level + }, + + -- Sensor 5 + { + "THRO", -- label + "Thro", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "%", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 90, -- warning level + 100, -- critical level + }, + + -- Sensor 6 + { + "Status", -- label + "Tmp2", -- OpenTX sensor name + 0, -- precision: number of decimals 0,1,2 + "", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "+", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 100, -- warning level + 100, -- critical level + }, +} +------------------------------------------------------ +-- the script can optionally look up values here +-- for each sensor and display the corresponding text instead +-- as an example to associate a lookup table to sensor 3 declare it like +-- +-- [3] = { +-- [-10] = "ERR", +-- [0] = "OK", +-- [10] = "CRIT", +-- } +-- this would display the sensor value except when the value corresponds to one +-- of entered above +-- +local lookups = { + -- lookup 2 + [6] = { + [-30] = "ERROR", + [-20] = "OFF", + [-10] = "COOL", + [-1] = "LOCK", + [0] = "STOP", + [10] = "RUN", + [20] = "REL", + [25] = "GLOW", + [30] = "SPIN", + [40] = "FIRE", + [45] = "IGNT", + [50] = "HEAT", + [60] = "ACCE", + [65] = "CAL", + [70] = "IDLE", + }, +} + +collectgarbage() + +return { + sensors=sensors,lookups=lookups +} \ No newline at end of file diff --git a/HORUS/SD/SCRIPTS/YAAPU/CFG/yaapudev.cfg b/HORUS/SD/SCRIPTS/YAAPU/CFG/yaapudev.cfg index 40b8a896..40cd18e0 100644 --- a/HORUS/SD/SCRIPTS/YAAPU/CFG/yaapudev.cfg +++ b/HORUS/SD/SCRIPTS/YAAPU/CFG/yaapudev.cfg @@ -1 +1 @@ -L1:2,V1:375,V2:350,B1:0,B2:0,S1:1,S2:1,S3:1,VS:1,T1:0,A1:0,A2:0,D1:0,T2:10,CC:0,RM:0,SVS:1,HS:2 \ No newline at end of file +L1:1,V1:375,V2:350,B1:300,B2:0,S1:1,S2:1,VIBR:1,VS:1,T1:0,A1:0,A2:0,D1:0,T2:10,BC:1,CC:0,CC2:0,RM:0,SVS:1,HSPD:1,VSPD:1,WL:1,CPANE:3,RPANE:1,LPANE:1,PX4:1 \ No newline at end of file diff --git a/HORUS/SD/SCRIPTS/YAAPU/CFG/yaapudev_sensors.lua b/HORUS/SD/SCRIPTS/YAAPU/CFG/yaapudev_sensors.lua new file mode 100644 index 00000000..520ba753 --- /dev/null +++ b/HORUS/SD/SCRIPTS/YAAPU/CFG/yaapudev_sensors.lua @@ -0,0 +1,105 @@ +---------------------------------------- +-- custom sensors configuration file +---------------------------------------- +local sensors = { + -- Sensor 1 +[1]= { + "Cel6", -- label + "Cel6", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 2 +[2]= { + "Cel5", -- label + "Cel5", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 3 +[3]= { + "Cel4", -- label + "Cel4", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 4 +[4]= { + "Cel3", -- label + "Cel3", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 5 +[5]= { + "Cel2", -- label + "Cel2", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, + + -- Sensor 6 +[6]= { + "Cell", -- label + "Cel1", -- OpenTX sensor name + 2, -- precision: number of decimals 0,1,2 + "V", -- label for unit of measure + 1, -- multiplier if < 1 than divides + "-", -- "+" track max values, "-" track min values with + 2, -- font size 1=small, 2=big + 3.65, -- warning level (nil is do not use feature) + 3.30, -- critical level (nil is do not use feature) + }, +} +------------------------------------------------------ +-- the script can optionally look up values here +-- for each sensor and display the corresponding text instead +-- as an example to associate a lookup table to sensor 3 declare it like +-- +--local lookups = { +-- [3] = { +-- [-10] = "ERR", +-- [0] = "OK", +-- [10] = "CRIT", +-- } +-- } +-- this would display the sensor value except when the value corresponds to one +-- of entered above +-- +local lookups = { +} + +collectgarbage() + +return { + sensors=sensors,lookups=lookups +} diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/battbox_small.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/battbox_small.png new file mode 100644 index 00000000..92e14348 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/battbox_small.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange.png index 1a134e35..8f5a3b07 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_86x30.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_86x30.png new file mode 100644 index 00000000..21029321 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_86x30.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_blink.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_blink.png new file mode 100644 index 00000000..aec9595c Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_blink.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_blink_86x30.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_blink_86x30.png new file mode 100644 index 00000000..25704747 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_blink_86x30.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_grey.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_grey.png new file mode 100644 index 00000000..9526391d Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_grey.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_small.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_small.png new file mode 100644 index 00000000..1638e861 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_small.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_small_blink.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_small_blink.png new file mode 100644 index 00000000..c1c062b9 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_orange_small_blink.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red.png index a42d09d8..b42f2856 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_86x30.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_86x30.png new file mode 100644 index 00000000..1af846f6 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_86x30.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_blink.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_blink.png new file mode 100644 index 00000000..b0b55880 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_blink.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_blink_86x30.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_blink_86x30.png new file mode 100644 index 00000000..98ef4201 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_blink_86x30.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_grey.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_grey.png new file mode 100644 index 00000000..5e9399a6 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_grey.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_small.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_small.png new file mode 100644 index 00000000..40020c59 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/cell_red_small.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/downarrow.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/downarrow.png index 714fc06e..f3141344 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/downarrow.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/downarrow.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg.png index 523032de..10dbc4be 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_grey.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_grey.png new file mode 100644 index 00000000..e4f09a48 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_grey.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_small.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_small.png new file mode 100644 index 00000000..1e60169c Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_small.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_white.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_white.png new file mode 100644 index 00000000..a3c61f8a Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/gauge_bg_white.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_140x110.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_140x110.png new file mode 100644 index 00000000..b50ea0d1 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_140x110.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_140x120.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_140x120.png new file mode 100644 index 00000000..93709cd3 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_140x120.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90.png new file mode 100644 index 00000000..8a988da1 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90_rus.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90_rus.png new file mode 100644 index 00000000..d2f2996f Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90_rus.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90c.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90c.png new file mode 100644 index 00000000..d063da4f Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_160x90c.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_280x134.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_280x134.png new file mode 100644 index 00000000..9c565d82 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_280x134.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_280x140.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_280x140.png new file mode 100644 index 00000000..9cf0d8ff Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_280x140.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_bg.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_bg.png deleted file mode 100644 index 63b66d1b..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/hud_bg.png and /dev/null differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/kmh.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/kmh.png new file mode 100644 index 00000000..5fce20f7 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/kmh.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/kmh_b.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/kmh_b.png new file mode 100644 index 00000000..5c838430 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/kmh_b.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/left_empty.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/left_empty.png new file mode 100644 index 00000000..d63224e4 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/left_empty.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/minmax.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/minmax.png new file mode 100644 index 00000000..511ca635 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/minmax.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nogpsicon.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nogpsicon.png index 62f94cd9..c19f2ae6 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nogpsicon.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nogpsicon.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nolockicon.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nolockicon.png index 84b39535..99072439 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nolockicon.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/nolockicon.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/notelemetry.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/notelemetry.png new file mode 100644 index 00000000..79c6d48b Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/notelemetry.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/spd.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/spd.png new file mode 100644 index 00000000..eb90251c Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/spd.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/spd_b.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/spd_b.png new file mode 100644 index 00000000..de7ab9f6 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/spd_b.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/uparrow.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/uparrow.png index b33422d8..c13a14d6 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/uparrow.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/uparrow.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/variogauge_90.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/variogauge_90.png new file mode 100644 index 00000000..6d9c103a Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/variogauge_90.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/variogauge_big.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/variogauge_big.png index f92a380f..8109318f 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/variogauge_big.png and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/variogauge_big.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/IMAGES/warn.png b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/warn.png new file mode 100644 index 00000000..a896dc22 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/IMAGES/warn.png differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/copter.lua b/HORUS/SD/SCRIPTS/YAAPU/LIB/copter.lua deleted file mode 100644 index d7aa8532..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/copter.lua and /dev/null differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/copter.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/copter.luac index d7aa8532..f517670b 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/copter.luac and b/HORUS/SD/SCRIPTS/YAAPU/LIB/copter.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/copter_px4.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/copter_px4.luac new file mode 100644 index 00000000..13dccdaa Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/copter_px4.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/draw.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/draw.luac new file mode 100644 index 00000000..5fa9da3a Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/draw.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_1.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_1.luac new file mode 100644 index 00000000..55a80cbd Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_1.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_2.luac new file mode 100644 index 00000000..61b3feef Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_russian_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_russian_2.luac new file mode 100644 index 00000000..f0eba311 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_russian_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_small_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_small_2.luac new file mode 100644 index 00000000..e56d14ed Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/hud_small_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/init.lua b/HORUS/SD/SCRIPTS/YAAPU/LIB/init.lua deleted file mode 100644 index 47139757..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/init.lua and /dev/null differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/init.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/init.luac deleted file mode 100644 index 47139757..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/init.luac and /dev/null differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/layout_1.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/layout_1.luac new file mode 100644 index 00000000..875e56cd Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/layout_1.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/layout_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/layout_2.luac new file mode 100644 index 00000000..71697a57 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/layout_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/left_1.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_1.luac new file mode 100644 index 00000000..3a94096b Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_1.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/left_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_2.luac new file mode 100644 index 00000000..0c083d11 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/left_m2f_1.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_m2f_1.luac new file mode 100644 index 00000000..c7acdae9 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_m2f_1.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/left_m2f_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_m2f_2.luac new file mode 100644 index 00000000..24967486 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/left_m2f_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/plane.lua b/HORUS/SD/SCRIPTS/YAAPU/LIB/plane.lua deleted file mode 100644 index 49e2b77b..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/plane.lua and /dev/null differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/plane.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/plane.luac index 49e2b77b..7929ad7b 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/plane.luac and b/HORUS/SD/SCRIPTS/YAAPU/LIB/plane.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/plane_px4.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/plane_px4.luac new file mode 100644 index 00000000..13dccdaa Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/plane_px4.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/reset.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/reset.luac new file mode 100644 index 00000000..cdfd3fdf Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/reset.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/right_1.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/right_1.luac new file mode 100644 index 00000000..e76f1611 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/right_1.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/right_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/right_2.luac new file mode 100644 index 00000000..ef9e570a Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/right_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/right_custom_2.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/right_custom_2.luac new file mode 100644 index 00000000..7f8a0262 Binary files /dev/null and b/HORUS/SD/SCRIPTS/YAAPU/LIB/right_custom_2.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/rover.lua b/HORUS/SD/SCRIPTS/YAAPU/LIB/rover.lua deleted file mode 100644 index b3e9204f..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/rover.lua and /dev/null differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/LIB/rover.luac b/HORUS/SD/SCRIPTS/YAAPU/LIB/rover.luac index b3e9204f..7f2218b0 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/LIB/rover.luac and b/HORUS/SD/SCRIPTS/YAAPU/LIB/rover.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/menu.lua b/HORUS/SD/SCRIPTS/YAAPU/menu.lua index 7fe035c9..4124bd4d 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/menu.lua and b/HORUS/SD/SCRIPTS/YAAPU/menu.lua differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/menu.luac b/HORUS/SD/SCRIPTS/YAAPU/menu.luac index 7fe035c9..4124bd4d 100644 Binary files a/HORUS/SD/SCRIPTS/YAAPU/menu.luac and b/HORUS/SD/SCRIPTS/YAAPU/menu.luac differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/yaapux.lua b/HORUS/SD/SCRIPTS/YAAPU/yaapux.lua deleted file mode 100644 index 6162ea1b..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/yaapux.lua and /dev/null differ diff --git a/HORUS/SD/SCRIPTS/YAAPU/yaapux.luac b/HORUS/SD/SCRIPTS/YAAPU/yaapux.luac deleted file mode 100644 index 57250591..00000000 Binary files a/HORUS/SD/SCRIPTS/YAAPU/yaapux.luac and /dev/null differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1008001424.wav b/HORUS/SD/SOUNDS/yaapu0/en/1008001424.wav new file mode 100644 index 00000000..4dbeb9b2 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1008001424.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/116655276.wav b/HORUS/SD/SOUNDS/yaapu0/en/116655276.wav new file mode 100644 index 00000000..859868cd Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/116655276.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1204090832.wav b/HORUS/SD/SOUNDS/yaapu0/en/1204090832.wav new file mode 100644 index 00000000..b06f6ead Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1204090832.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1249672288.wav b/HORUS/SD/SOUNDS/yaapu0/en/1249672288.wav new file mode 100644 index 00000000..4fd515c4 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1249672288.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1309405592.wav b/HORUS/SD/SOUNDS/yaapu0/en/1309405592.wav new file mode 100644 index 00000000..c94bc715 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1309405592.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1396289024.wav b/HORUS/SD/SOUNDS/yaapu0/en/1396289024.wav new file mode 100644 index 00000000..cf13b872 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1396289024.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1535290648.wav b/HORUS/SD/SOUNDS/yaapu0/en/1535290648.wav new file mode 100644 index 00000000..e57387ef Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1535290648.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1809087708.wav b/HORUS/SD/SOUNDS/yaapu0/en/1809087708.wav new file mode 100644 index 00000000..8a469803 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1809087708.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1834616480.wav b/HORUS/SD/SOUNDS/yaapu0/en/1834616480.wav new file mode 100644 index 00000000..c081bdd6 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1834616480.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/1997782032.wav b/HORUS/SD/SOUNDS/yaapu0/en/1997782032.wav new file mode 100644 index 00000000..65f0f228 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/1997782032.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/2310179660.wav b/HORUS/SD/SOUNDS/yaapu0/en/2310179660.wav new file mode 100644 index 00000000..f1bdd88a Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/2310179660.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/2386213680.wav b/HORUS/SD/SOUNDS/yaapu0/en/2386213680.wav new file mode 100644 index 00000000..a8740c0c Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/2386213680.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/264977348.wav b/HORUS/SD/SOUNDS/yaapu0/en/264977348.wav new file mode 100644 index 00000000..919dcb82 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/264977348.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/2664106240.wav b/HORUS/SD/SOUNDS/yaapu0/en/2664106240.wav new file mode 100644 index 00000000..fd74c55b Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/2664106240.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/2890289840.wav b/HORUS/SD/SOUNDS/yaapu0/en/2890289840.wav new file mode 100644 index 00000000..2eab10f3 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/2890289840.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3025044912.wav b/HORUS/SD/SOUNDS/yaapu0/en/3025044912.wav new file mode 100644 index 00000000..38889305 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3025044912.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3311875476.wav b/HORUS/SD/SOUNDS/yaapu0/en/3311875476.wav new file mode 100644 index 00000000..61a8d73b Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3311875476.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3417557720.wav b/HORUS/SD/SOUNDS/yaapu0/en/3417557720.wav new file mode 100644 index 00000000..d06f19ab Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3417557720.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3602501704.wav b/HORUS/SD/SOUNDS/yaapu0/en/3602501704.wav new file mode 100644 index 00000000..5f88ec8c Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3602501704.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3708582640.wav b/HORUS/SD/SOUNDS/yaapu0/en/3708582640.wav new file mode 100644 index 00000000..6ee0d5ed Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3708582640.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3721120084.wav b/HORUS/SD/SOUNDS/yaapu0/en/3721120084.wav new file mode 100644 index 00000000..ac9622ad Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3721120084.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3879875148.wav b/HORUS/SD/SOUNDS/yaapu0/en/3879875148.wav new file mode 100644 index 00000000..ac9622ad Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3879875148.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/3956583920.wav b/HORUS/SD/SOUNDS/yaapu0/en/3956583920.wav new file mode 100644 index 00000000..c94bc715 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/3956583920.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/4019153925.wav b/HORUS/SD/SOUNDS/yaapu0/en/4019153925.wav new file mode 100644 index 00000000..434cf073 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/4019153925.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/4091124880.wav b/HORUS/SD/SOUNDS/yaapu0/en/4091124880.wav new file mode 100644 index 00000000..69a12b3c Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/4091124880.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/4137200300.wav b/HORUS/SD/SOUNDS/yaapu0/en/4137200300.wav new file mode 100644 index 00000000..64b83240 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/4137200300.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/554623408.wav b/HORUS/SD/SOUNDS/yaapu0/en/554623408.wav new file mode 100644 index 00000000..757cbbe8 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/554623408.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/656739232.wav b/HORUS/SD/SOUNDS/yaapu0/en/656739232.wav new file mode 100644 index 00000000..fd526aee Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/656739232.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/956150328.wav b/HORUS/SD/SOUNDS/yaapu0/en/956150328.wav new file mode 100644 index 00000000..ac9622ad Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/956150328.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/986165592.wav b/HORUS/SD/SOUNDS/yaapu0/en/986165592.wav new file mode 100644 index 00000000..434cf073 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/986165592.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/alt.wav b/HORUS/SD/SOUNDS/yaapu0/en/alt.wav new file mode 100644 index 00000000..e987fd64 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/alt.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/altctl.wav b/HORUS/SD/SOUNDS/yaapu0/en/altctl.wav new file mode 100644 index 00000000..2639b341 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/altctl.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/dist.wav b/HORUS/SD/SOUNDS/yaapu0/en/dist.wav new file mode 100644 index 00000000..1ce31839 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/dist.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/follow_r.wav b/HORUS/SD/SOUNDS/yaapu0/en/follow_r.wav new file mode 100644 index 00000000..17ced008 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/follow_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/initializing_r.wav b/HORUS/SD/SOUNDS/yaapu0/en/initializing_r.wav new file mode 100644 index 00000000..31fe6bb7 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/initializing_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/loiter_r.wav b/HORUS/SD/SOUNDS/yaapu0/en/loiter_r.wav new file mode 100644 index 00000000..e67309c5 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/loiter_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/mission.wav b/HORUS/SD/SOUNDS/yaapu0/en/mission.wav new file mode 100644 index 00000000..c6dfb111 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/mission.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/offboard.wav b/HORUS/SD/SOUNDS/yaapu0/en/offboard.wav new file mode 100644 index 00000000..d49f619c Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/offboard.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/posctl.wav b/HORUS/SD/SOUNDS/yaapu0/en/posctl.wav new file mode 100644 index 00000000..7546ce34 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/posctl.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/precland.wav b/HORUS/SD/SOUNDS/yaapu0/en/precland.wav new file mode 100644 index 00000000..6ce9260f Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/precland.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/qautotune.wav b/HORUS/SD/SOUNDS/yaapu0/en/qautotune.wav new file mode 100644 index 00000000..92b9ea6e Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/qautotune.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/rattitude.wav b/HORUS/SD/SOUNDS/yaapu0/en/rattitude.wav new file mode 100644 index 00000000..97f93824 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/rattitude.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/ready.wav b/HORUS/SD/SOUNDS/yaapu0/en/ready.wav new file mode 100644 index 00000000..1789959e Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/ready.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/rtgs.wav b/HORUS/SD/SOUNDS/yaapu0/en/rtgs.wav new file mode 100644 index 00000000..0d31a331 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/rtgs.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/simple.wav b/HORUS/SD/SOUNDS/yaapu0/en/simple.wav new file mode 100644 index 00000000..d4c3a91f Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/simple.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/simple_r.wav b/HORUS/SD/SOUNDS/yaapu0/en/simple_r.wav new file mode 100644 index 00000000..42a0a702 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/simple_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/takeoff.wav b/HORUS/SD/SOUNDS/yaapu0/en/takeoff.wav new file mode 100644 index 00000000..bd19ad5d Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/takeoff.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/en/zigzag.wav b/HORUS/SD/SOUNDS/yaapu0/en/zigzag.wav new file mode 100644 index 00000000..f32820eb Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/en/zigzag.wav differ diff --git a/HORUS/SOURCES/english.psv b/HORUS/SD/SOUNDS/yaapu0/english.psv similarity index 91% rename from HORUS/SOURCES/english.psv rename to HORUS/SD/SOUNDS/yaapu0/english.psv index a9a0e811..f158c07f 100644 --- a/HORUS/SOURCES/english.psv +++ b/HORUS/SD/SOUNDS/yaapu0/english.psv @@ -32,6 +32,7 @@ SOUNDS/yaapu0/en|flowhold|flow position hold flight mode SOUNDS/yaapu0/en|flybywirea|Fly by wire a flight mode SOUNDS/yaapu0/en|flybywireb|Fly by wire b flight mode SOUNDS/yaapu0/en|follow|follow flight mode +SOUNDS/yaapu0/en|follow_r|follow mode SOUNDS/yaapu0/en|gpsfix|GPS 3D fix lock SOUNDS/yaapu0/en|gpsnofix|No gps SOUNDS/yaapu0/en|guided|Guided flight mode @@ -39,9 +40,11 @@ SOUNDS/yaapu0/en|guided_r|Guided mode SOUNDS/yaapu0/en|guidednogps|Guided no gps flight mode SOUNDS/yaapu0/en|hold_r|Hold mode SOUNDS/yaapu0/en|initializing|Initializing +SOUNDS/yaapu0/en|initializing_r|Initializing SOUNDS/yaapu0/en|land|Land flight mode SOUNDS/yaapu0/en|landing|Landing complete SOUNDS/yaapu0/en|loiter|Loiter flight mode +SOUNDS/yaapu0/en|loiter_r|Loiter mode SOUNDS/yaapu0/en|lowbat|Low battery SOUNDS/yaapu0/en|manual|Manual flight mode SOUNDS/yaapu0/en|manual_r|Manual mode @@ -49,6 +52,8 @@ SOUNDS/yaapu0/en|maxalt|Max altitude alert SOUNDS/yaapu0/en|maxdist|Max distance alert SOUNDS/yaapu0/en|minalt|Low altitude alert SOUNDS/yaapu0/en|poshold|Position hold flight mode +SOUNDS/yaapu0/en|qacro|Q acro flight mode +SOUNDS/yaapu0/en|qautotune|Q autotune flight mode SOUNDS/yaapu0/en|qhover|Q hover flight mode SOUNDS/yaapu0/en|qland|Q land flight mode SOUNDS/yaapu0/en|qloiter|Q loiter flight mode @@ -56,6 +61,7 @@ SOUNDS/yaapu0/en|qrtl|Q return to home flight mode SOUNDS/yaapu0/en|qstabilize|Q stabilize flight mode SOUNDS/yaapu0/en|rtl|Return to home SOUNDS/yaapu0/en|rtl_r|Return to home mode +SOUNDS/yaapu0/en|simple_r|simple mode SOUNDS/yaapu0/en|simpleoff|simple mode disabled SOUNDS/yaapu0/en|simpleon|simple mode enabled SOUNDS/yaapu0/en|smartrtl|Smart return to home flight mode @@ -68,5 +74,6 @@ SOUNDS/yaapu0/en|steering_r|Steering mode SOUNDS/yaapu0/en|throw|Throw flight mode SOUNDS/yaapu0/en|timealert|Timer alert SOUNDS/yaapu0/en|training|Training flight mode +SOUNDS/yaapu0/en|zigzag|Zigzag flight mode SOUNDS/yaapu0/en|yaapu|Yaa-pu telemetry ready diff --git a/HORUS/SD/SOUNDS/yaapu0/english_msg_hash.psv b/HORUS/SD/SOUNDS/yaapu0/english_msg_hash.psv new file mode 100644 index 00000000..16b52e11 --- /dev/null +++ b/HORUS/SD/SOUNDS/yaapu0/english_msg_hash.psv @@ -0,0 +1,30 @@ +/SOUNDS/yaapu0/en|264977348|PreArming: Need 3D Fix +/SOUNDS/yaapu0/en|1834616480|Smart RTL Unavailable +/SOUNDS/yaapu0/en|2386213680|EKF variance +/SOUNDS/yaapu0/en|2310179660|GPS Glitch cleared +/SOUNDS/yaapu0/en|4137200300|GPS Glitch +/SOUNDS/yaapu0/en|2664106240|Parachute: Released +/SOUNDS/yaapu0/en|656739232|Flight plan received +/SOUNDS/yaapu0/en|3708582640|Mission complete +/SOUNDS/yaapu0/en|1809087708|Geofence triggered +/SOUNDS/yaapu0/en|116655276|Flight mode change failed +/SOUNDS/yaapu0/en|1008001424|AutoTune: Success +/SOUNDS/yaapu0/en|1396289024|AutoTune: Failed +/SOUNDS/yaapu0/en|986165592|Transition done +/SOUNDS/yaapu0/en|1249672288|Transition started +/SOUNDS/yaapu0/en|4019153925|Transition done +/SOUNDS/yaapu0/en|3417557720|Transition VTOL done +/SOUNDS/yaapu0/en|1204090832|Land descend started +/SOUNDS/yaapu0/en|2890289840|Land final started +/SOUNDS/yaapu0/en|1535290648|Soaring: forcing RTL +/SOUNDS/yaapu0/en|3602501704|Soaring: Thermal detected +/SOUNDS/yaapu0/en|3721120084|Soaring: Thermal ended +/SOUNDS/yaapu0/en|956150328|Soaring: Thermal ended +/SOUNDS/yaapu0/en|3879875148|Soaring: Thermal ended +/SOUNDS/yaapu0/en|4091124880|reached command: +/SOUNDS/yaapu0/en|3311875476|reached waypoint: +/SOUNDS/yaapu0/en|1997782032|Passed waypoint +/SOUNDS/yaapu0/en|554623408|Takeoff complete +/SOUNDS/yaapu0/en|3025044912|Smart RTL deactivated +/SOUNDS/yaapu0/en|3956583920|GPS home acquired +/SOUNDS/yaapu0/en|1309405592|GPS home acquired diff --git a/HORUS/SD/SOUNDS/yaapu0/english_px4.psv b/HORUS/SD/SOUNDS/yaapu0/english_px4.psv new file mode 100644 index 00000000..9338e918 --- /dev/null +++ b/HORUS/SD/SOUNDS/yaapu0/english_px4.psv @@ -0,0 +1,10 @@ +SOUNDS/yaapu0/en|altctl|Altitude control mode +SOUNDS/yaapu0/en|posctl|Position control mode +SOUNDS/yaapu0/en|ready|ready +SOUNDS/yaapu0/en|takeoff|Auto takeoff mode +SOUNDS/yaapu0/en|mission|Auto mission mode +SOUNDS/yaapu0/en|rtgs|link loss failsafe mode +SOUNDS/yaapu0/en|precland|Precision landing mode +SOUNDS/yaapu0/en|offboard|Offboard mode +SOUNDS/yaapu0/en|rattitude|rate attitude mode +SOUNDS/yaapu0/en|simple|simple mode diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1008001424.wav b/HORUS/SD/SOUNDS/yaapu0/it/1008001424.wav new file mode 100644 index 00000000..f24fe173 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1008001424.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/116655276.wav b/HORUS/SD/SOUNDS/yaapu0/it/116655276.wav new file mode 100644 index 00000000..cca333a5 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/116655276.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1204090832.wav b/HORUS/SD/SOUNDS/yaapu0/it/1204090832.wav new file mode 100644 index 00000000..090b20da Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1204090832.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1249672288.wav b/HORUS/SD/SOUNDS/yaapu0/it/1249672288.wav new file mode 100644 index 00000000..d8db8351 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1249672288.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1309405592.wav b/HORUS/SD/SOUNDS/yaapu0/it/1309405592.wav new file mode 100644 index 00000000..a9c85ff4 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1309405592.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1396289024.wav b/HORUS/SD/SOUNDS/yaapu0/it/1396289024.wav new file mode 100644 index 00000000..fe53dfe2 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1396289024.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1535290648.wav b/HORUS/SD/SOUNDS/yaapu0/it/1535290648.wav new file mode 100644 index 00000000..3bac47f4 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1535290648.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1809087708.wav b/HORUS/SD/SOUNDS/yaapu0/it/1809087708.wav new file mode 100644 index 00000000..5fb959d3 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1809087708.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1834616480.wav b/HORUS/SD/SOUNDS/yaapu0/it/1834616480.wav new file mode 100644 index 00000000..752f68dd Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1834616480.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/1997782032.wav b/HORUS/SD/SOUNDS/yaapu0/it/1997782032.wav new file mode 100644 index 00000000..a0ebfdb6 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/1997782032.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/2310179660.wav b/HORUS/SD/SOUNDS/yaapu0/it/2310179660.wav new file mode 100644 index 00000000..fb2281c5 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/2310179660.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/2386213680.wav b/HORUS/SD/SOUNDS/yaapu0/it/2386213680.wav new file mode 100644 index 00000000..1ee39406 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/2386213680.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/264977348.wav b/HORUS/SD/SOUNDS/yaapu0/it/264977348.wav new file mode 100644 index 00000000..c0807a9a Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/264977348.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/2664106240.wav b/HORUS/SD/SOUNDS/yaapu0/it/2664106240.wav new file mode 100644 index 00000000..d15e1b74 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/2664106240.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/2890289840.wav b/HORUS/SD/SOUNDS/yaapu0/it/2890289840.wav new file mode 100644 index 00000000..532d7711 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/2890289840.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3025044912.wav b/HORUS/SD/SOUNDS/yaapu0/it/3025044912.wav new file mode 100644 index 00000000..7a4c3b1b Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3025044912.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3311875476.wav b/HORUS/SD/SOUNDS/yaapu0/it/3311875476.wav new file mode 100644 index 00000000..2f5eb2fd Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3311875476.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3417557720.wav b/HORUS/SD/SOUNDS/yaapu0/it/3417557720.wav new file mode 100644 index 00000000..e65ea26b Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3417557720.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3602501704.wav b/HORUS/SD/SOUNDS/yaapu0/it/3602501704.wav new file mode 100644 index 00000000..c54f8cd0 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3602501704.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3708582640.wav b/HORUS/SD/SOUNDS/yaapu0/it/3708582640.wav new file mode 100644 index 00000000..c99347b1 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3708582640.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3721120084.wav b/HORUS/SD/SOUNDS/yaapu0/it/3721120084.wav new file mode 100644 index 00000000..943303ea Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3721120084.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3879875148.wav b/HORUS/SD/SOUNDS/yaapu0/it/3879875148.wav new file mode 100644 index 00000000..943303ea Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3879875148.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/3956583920.wav b/HORUS/SD/SOUNDS/yaapu0/it/3956583920.wav new file mode 100644 index 00000000..a9c85ff4 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/3956583920.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/4019153925.wav b/HORUS/SD/SOUNDS/yaapu0/it/4019153925.wav new file mode 100644 index 00000000..e65ea26b Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/4019153925.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/4091124880.wav b/HORUS/SD/SOUNDS/yaapu0/it/4091124880.wav new file mode 100644 index 00000000..3db20be7 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/4091124880.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/4137200300.wav b/HORUS/SD/SOUNDS/yaapu0/it/4137200300.wav new file mode 100644 index 00000000..988a46b0 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/4137200300.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/554623408.wav b/HORUS/SD/SOUNDS/yaapu0/it/554623408.wav new file mode 100644 index 00000000..a62c6d72 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/554623408.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/656739232.wav b/HORUS/SD/SOUNDS/yaapu0/it/656739232.wav new file mode 100644 index 00000000..76790559 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/656739232.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/956150328.wav b/HORUS/SD/SOUNDS/yaapu0/it/956150328.wav new file mode 100644 index 00000000..943303ea Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/956150328.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/986165592.wav b/HORUS/SD/SOUNDS/yaapu0/it/986165592.wav new file mode 100644 index 00000000..e65ea26b Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/986165592.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/alt.wav b/HORUS/SD/SOUNDS/yaapu0/it/alt.wav new file mode 100644 index 00000000..059f0255 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/alt.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/altctl.wav b/HORUS/SD/SOUNDS/yaapu0/it/altctl.wav new file mode 100644 index 00000000..3d947cef Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/altctl.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/dist.wav b/HORUS/SD/SOUNDS/yaapu0/it/dist.wav new file mode 100644 index 00000000..133bd37e Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/dist.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/follow_r.wav b/HORUS/SD/SOUNDS/yaapu0/it/follow_r.wav new file mode 100644 index 00000000..e93dfa51 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/follow_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/initializing_r.wav b/HORUS/SD/SOUNDS/yaapu0/it/initializing_r.wav new file mode 100644 index 00000000..e7fa259b Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/initializing_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/loiter_r.wav b/HORUS/SD/SOUNDS/yaapu0/it/loiter_r.wav new file mode 100644 index 00000000..f33f9939 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/loiter_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/mission.wav b/HORUS/SD/SOUNDS/yaapu0/it/mission.wav new file mode 100644 index 00000000..3131d74f Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/mission.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/offboard.wav b/HORUS/SD/SOUNDS/yaapu0/it/offboard.wav new file mode 100644 index 00000000..e19f7d5d Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/offboard.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/posctl.wav b/HORUS/SD/SOUNDS/yaapu0/it/posctl.wav new file mode 100644 index 00000000..15eda649 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/posctl.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/precland.wav b/HORUS/SD/SOUNDS/yaapu0/it/precland.wav new file mode 100644 index 00000000..69fb26ca Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/precland.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/qautotune.wav b/HORUS/SD/SOUNDS/yaapu0/it/qautotune.wav new file mode 100644 index 00000000..6cb25f8f Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/qautotune.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/qhover.wav b/HORUS/SD/SOUNDS/yaapu0/it/qhover.wav index 8fc6a2cb..2b9ec133 100644 Binary files a/HORUS/SD/SOUNDS/yaapu0/it/qhover.wav and b/HORUS/SD/SOUNDS/yaapu0/it/qhover.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/qland.wav b/HORUS/SD/SOUNDS/yaapu0/it/qland.wav index 2634e51c..b2ad1aee 100644 Binary files a/HORUS/SD/SOUNDS/yaapu0/it/qland.wav and b/HORUS/SD/SOUNDS/yaapu0/it/qland.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/qloiter.wav b/HORUS/SD/SOUNDS/yaapu0/it/qloiter.wav index 672ecf1b..4ab05b86 100644 Binary files a/HORUS/SD/SOUNDS/yaapu0/it/qloiter.wav and b/HORUS/SD/SOUNDS/yaapu0/it/qloiter.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/qrtl.wav b/HORUS/SD/SOUNDS/yaapu0/it/qrtl.wav index cce9418a..a1c19d3f 100644 Binary files a/HORUS/SD/SOUNDS/yaapu0/it/qrtl.wav and b/HORUS/SD/SOUNDS/yaapu0/it/qrtl.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/qstabilize.wav b/HORUS/SD/SOUNDS/yaapu0/it/qstabilize.wav index 91680de5..c736025f 100644 Binary files a/HORUS/SD/SOUNDS/yaapu0/it/qstabilize.wav and b/HORUS/SD/SOUNDS/yaapu0/it/qstabilize.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/rattitude.wav b/HORUS/SD/SOUNDS/yaapu0/it/rattitude.wav new file mode 100644 index 00000000..9759ae52 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/rattitude.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/ready.wav b/HORUS/SD/SOUNDS/yaapu0/it/ready.wav new file mode 100644 index 00000000..ec96b76d Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/ready.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/rtgs.wav b/HORUS/SD/SOUNDS/yaapu0/it/rtgs.wav new file mode 100644 index 00000000..f300d092 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/rtgs.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/simple.wav b/HORUS/SD/SOUNDS/yaapu0/it/simple.wav new file mode 100644 index 00000000..78bca5b4 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/simple.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/simple_r.wav b/HORUS/SD/SOUNDS/yaapu0/it/simple_r.wav new file mode 100644 index 00000000..3cea5a56 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/simple_r.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/takeoff.wav b/HORUS/SD/SOUNDS/yaapu0/it/takeoff.wav new file mode 100644 index 00000000..145cf30f Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/takeoff.wav differ diff --git a/HORUS/SD/SOUNDS/yaapu0/it/zigzag.wav b/HORUS/SD/SOUNDS/yaapu0/it/zigzag.wav new file mode 100644 index 00000000..351f0539 Binary files /dev/null and b/HORUS/SD/SOUNDS/yaapu0/it/zigzag.wav differ diff --git a/HORUS/SD/WIDGETS/Yaapu/main.lua b/HORUS/SD/WIDGETS/Yaapu/main.lua index 891f65a5..25ebc003 100644 Binary files a/HORUS/SD/WIDGETS/Yaapu/main.lua and b/HORUS/SD/WIDGETS/Yaapu/main.lua differ diff --git a/HORUS/SD/WIDGETS/Yaapu/main.luac b/HORUS/SD/WIDGETS/Yaapu/main.luac index 4796cd5a..25ebc003 100644 Binary files a/HORUS/SD/WIDGETS/Yaapu/main.luac and b/HORUS/SD/WIDGETS/Yaapu/main.luac differ diff --git a/HORUS/SOURCES/PP/copter.lua b/HORUS/SOURCES/PP/copter.lua deleted file mode 100644 index d89ad800..00000000 --- a/HORUS/SOURCES/PP/copter.lua +++ /dev/null @@ -1,29 +0,0 @@ - local flightModes = {} - -- copter flight modes - flightModes[0]="" - flightModes[1]="Stabilize" - flightModes[2]="Acro" - flightModes[3]="AltHold" - flightModes[4]="Auto" - flightModes[5]="Guided" - flightModes[6]="Loiter" - flightModes[7]="RTL" - flightModes[8]="Circle" - flightModes[9]="" - flightModes[10]="Land" - flightModes[11]="" - flightModes[12]="Drift" - flightModes[13]="" - flightModes[14]="Sport" - flightModes[15]="Flip" - flightModes[16]="AutoTune" - flightModes[17]="PosHold" - flightModes[18]="Brake" - flightModes[19]="Throw" - flightModes[20]="AvoidADSB" - flightModes[21]="GuidedNOGPS" - flightModes[22]="SmartRTL" - flightModes[23]="FlowHold" - flightModes[24]="Follow" - -return {flightModes=flightModes} diff --git a/HORUS/SOURCES/PP/includes/hud_algo_inc.lua b/HORUS/SOURCES/PP/includes/hud_algo_inc.lua new file mode 100644 index 00000000..048fc1c6 --- /dev/null +++ b/HORUS/SOURCES/PP/includes/hud_algo_inc.lua @@ -0,0 +1,182 @@ + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x0d, 0x68, 0xb1)) -- bighud blue + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7b, 0x9d, 0xff)) -- default blue + lcd.drawFilledRectangle(minX,minY,maxX-minX,maxY - minY,CUSTOM_COLOR) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x90, 0x63, 0x20)) --906320 bighud brown + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x63, 0x30, 0x00)) --623000 old brown + + -- angle of the line passing on point(ox,oy) + local angle = math.tan(math.rad(-telemetry.roll)) + -- prevent divide by zero + if telemetry.roll == 0 then + drawLib.drawFilledRectangle(minX,math.max(minY,dy+minY+(maxY-minY)/2),maxX-minX,math.min(maxY-minY,(maxY-minY)/2-dy+(math.abs(dy) > 0 and 1 or 0)),CUSTOM_COLOR) + elseif math.abs(telemetry.roll) >= 180 then + drawLib.drawFilledRectangle(minX,minY,maxX-minX,math.min(maxY-minY,(maxY-minY)/2+dy),CUSTOM_COLOR) + else +#ifdef HUD_ALGO1 + -- HUD drawn using vertical bars of width 2 + local step = 2 + local steps = (maxX - minX)/step + local xx = 0 + local xxR = 0 + for s=0,steps -1 + do + xx = minX + s*step + xxR = xx + step + if telemetry.roll > 90 or telemetry.roll < -90 then + yy = (oy - ox*angle) + math.floor(xx*angle) + if yy > minY + 1 and yy < maxY then + lcd.drawFilledRectangle(xx,minY,step,yy-minY,CUSTOM_COLOR) + elseif yy >= maxY then + lcd.drawFilledRectangle(xx,minY,step,maxY-minY,CUSTOM_COLOR) + end + else + yy = (oy - ox*angle) + math.floor(xx*angle) + if yy <= minY then + lcd.drawFilledRectangle(xx,minY,step,maxY-minY,CUSTOM_COLOR) + elseif yy < maxY then + lcd.drawFilledRectangle(xx,yy,step,maxY-yy+1,CUSTOM_COLOR) + end + end + end +#endif --HUD_ALGO1 +#ifdef HUD_ALGO2 + -- HUD drawn using boxes + horizontal bars of height 2 + local minxY = (oy - ox * angle) + minX * angle; + local maxxY = (oy - ox * angle) + maxX * angle; + local maxyX = (maxY - (oy - ox * angle)) / angle; + local minyX = (minY - (oy - ox * angle)) / angle; + -- + if ( 0 <= -telemetry.roll and -telemetry.roll <= 90 ) then + if (minxY > minY and maxxY < maxY) then + -- 5 + lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR) + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle, CUSTOM_COLOR) + elseif (minxY < minY and maxxY < maxY and maxxY > minY) then + -- 6 + lcd.drawFilledRectangle(minX, minY, minyX - minX, maxxY - minY,CUSTOM_COLOR); + lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle, CUSTOM_COLOR) + elseif (minxY < minY and maxxY > maxY) then + -- 7 + lcd.drawFilledRectangle(minX, minY, minyX - minX, maxY - minY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle, CUSTOM_COLOR) + elseif (minxY < maxY and minxY > minY) then + -- 8 + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle, CUSTOM_COLOR) + elseif (minxY < minY and maxxY < minY) then + -- off screen + lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); + end + elseif (90 < -telemetry.roll and -telemetry.roll <= 180) then + if (minxY < maxY and maxxY > minY) then + -- 9 + lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY > maxY and maxxY > minY and maxxY < maxY) then + -- 10 + lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); + lcd.drawFilledRectangle(minX, maxxY, maxyX - minX, maxY - maxxY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY > maxY and maxyX < maxX) then + -- 11 + lcd.drawFilledRectangle(minX, minY, maxyX - minX, maxY - minY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY < maxY and minxY > minY) then + -- 12 + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY > maxY and maxxY > maxY) then + -- off screen + lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); + end + -- 9,10,11,12 + elseif (-90 < -telemetry.roll and -telemetry.roll < 0) then + if (minxY < maxY and maxxY > minY) then + -- 1 + lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY < maxY and maxxY < minY and minxY > minY) then + -- 2 + lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); + lcd.drawFilledRectangle(minyX, minY, maxX - minyX, minxY - minY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY > maxY and maxxY < minY) then + -- 3 + lcd.drawFilledRectangle(minyX, minY, maxX - minyX, maxY - minY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY > minY and maxxY < maxY) then + -- 4 + drawLib.fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY < minY and maxxY < minY) then + -- off screen + lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); + end + elseif (-180 <= -telemetry.roll and -telemetry.roll <= -90) then + if (minxY > minY and maxxY < maxY) then + -- 13 + lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (maxxY > maxY and minxY > minY and minxY < maxY) then + -- 14 + lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); + lcd.drawFilledRectangle(maxyX, minxY, maxX - maxyX, maxY - minxY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY < minY and maxyX < maxX) then + -- 15 + lcd.drawFilledRectangle(maxyX, minY, maxX - maxyX, maxY - minY,CUSTOM_COLOR); + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY < minY and maxxY > minY) then + -- 16 + drawLib.fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -telemetry.roll, angle,CUSTOM_COLOR); + elseif (minxY > maxY and maxxY > minY) then + -- off screen + lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); + end + end +#endif --HUD_ALGO2 +#ifdef HUD_ALGO3 + -- HUD drawn using horizontal bars of height 2 + -- true if flying inverted + local inverted = math.abs(telemetry.roll) > 90 + -- true if part of the hud can be filled in one pass with a rectangle + local fillNeeded = false + local yRect = inverted and 0 or LCD_H + + local step = 2 + local steps = (maxY - minY)/step - 1 + local yy = 0 + + if 0 < telemetry.roll and telemetry.roll < 180 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(xx, yy, maxX-xx+1, step,CUSTOM_COLOR) + elseif xx < minX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + elseif -180 < telemetry.roll and telemetry.roll < 0 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(minX, yy, xx-minX, step,CUSTOM_COLOR) + elseif xx > maxX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + end + + if fillNeeded then + local yMin = inverted and minY or yRect + local height = inverted and yRect - minY or maxY-yRect + --lcd.setColor(CUSTOM_COLOR,COLOR_RED) --623000 old brown + lcd.drawFilledRectangle(minX, yMin, maxX-minX, height ,CUSTOM_COLOR) + end +#endif --HUD_ALGO3 + end diff --git a/HORUS/SOURCES/PP/includes/layout_1_inc.lua b/HORUS/SOURCES/PP/includes/layout_1_inc.lua new file mode 100644 index 00000000..99c0791f --- /dev/null +++ b/HORUS/SOURCES/PP/includes/layout_1_inc.lua @@ -0,0 +1,52 @@ +--------------------------------- +-- LAYOUT +--------------------------------- +#define LEFTPANE_X 68 +#define RIGHTPANE_X 68 + +#define BOX1_X 0 +#define BOX1_Y 38 +#define BOX1_WIDTH 66 +#define BOX1_HEIGHT 8 + +#define BOX2_X 61 +#define BOX2_Y 46 +#define BOX2_WIDTH 17 +#define BOX2_HEIGHT 12 + +#define FLIGHTMODE_X 2 +#define FLIGHTMODE_Y 234 +#define FLIGHTMODE_FLAGS MIDSIZE+TIMEHOUR + +#define HOMEANGLE_X 60 +#define HOMEANGLE_Y 27 +#define HOMEANGLE_XLABEL 3 +#define HOMEANGLE_YLABEL 27 +#define HOMEANGLE_FLAGS SMLSIZE + +#define GPS_X 160 +#define GPS_Y 210 +#define GPS_BORDER 0 + +-- x:300 y:135 inside HUD +#define HOMEDIR_X 240 +#define HOMEDIR_Y 174 +#define HOMEDIR_R 20 + +#define FLIGHTTIME_X 330 +#define FLIGHTTIME_Y 206 +#define FLIGHTTIME_FLAGS DBLSIZE + +#define VSPEED_X 175 +#define VSPEED_Y LCD_H-60 +#define VSPEED_FLAGS MIDSIZE +#define VSPEED_XLABEL 165 +#define VSPEED_YLABEL LCD_H-37 +#define VSPEED_FLAGSLABEL SMLSIZE + +#define ALT_X 310 +#define ALT_Y LCD_H-60 +#define ALT_FLAGS MIDSIZE+RIGHT +#define ALT_XLABEL 275 +#define ALT_YLABEL LCD_H-37 +#define ALT_FLAGSLABEL SMLSIZE diff --git a/HORUS/SOURCES/PP/includes/layout_2_inc.lua b/HORUS/SOURCES/PP/includes/layout_2_inc.lua new file mode 100644 index 00000000..d725309d --- /dev/null +++ b/HORUS/SOURCES/PP/includes/layout_2_inc.lua @@ -0,0 +1,51 @@ +--------------------------------- +-- LAYOUT +--------------------------------- +#define LEFTPANE_X 68 +#define RIGHTPANE_X 68 + +#define BOX1_X 0 +#define BOX1_Y 38 +#define BOX1_WIDTH 66 +#define BOX1_HEIGHT 8 + +#define BOX2_X 61 +#define BOX2_Y 46 +#define BOX2_WIDTH 17 +#define BOX2_HEIGHT 12 + +#define FLIGHTMODE_X 2 +#define FLIGHTMODE_Y 222 +#define FLIGHTMODE_FLAGS MIDSIZE + +#define HOMEANGLE_X 60 +#define HOMEANGLE_Y 27 +#define HOMEANGLE_XLABEL 3 +#define HOMEANGLE_YLABEL 27 +#define HOMEANGLE_FLAGS SMLSIZE + +#define GPS_X 2 +#define GPS_Y 22 +#define GPS_BORDER 0 + +#define HOMEDIR_X (LCD_W/2) +#define HOMEDIR_Y 180 +#define HOMEDIR_R 22 + +#define FLIGHTTIME_X 330 +#define FLIGHTTIME_Y 206 +#define FLIGHTTIME_FLAGS DBLSIZE + +#define VSPEED_X 68 +#define VSPEED_Y 178 +#define VSPEED_FLAGS MIDSIZE+RIGHT +#define VSPEED_XLABEL 68 +#define VSPEED_YLABEL 165 +#define VSPEED_FLAGSLABEL SMLSIZE + +#define ALT_X 153 +#define ALT_Y 178 +#define ALT_FLAGS MIDSIZE+RIGHT +#define ALT_XLABEL 153 +#define ALT_YLABEL 165 +#define ALT_FLAGSLABEL SMLSIZE \ No newline at end of file diff --git a/HORUS/SOURCES/PP/includes/yaapu_inc.lua b/HORUS/SOURCES/PP/includes/yaapu_inc.lua new file mode 100644 index 00000000..ae29f383 --- /dev/null +++ b/HORUS/SOURCES/PP/includes/yaapu_inc.lua @@ -0,0 +1,421 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +#define VERSION "Yaapu Telemetry Widget 1.8.0" +#define VERSION_CONFIG 180 +-- load and compile of lua files +--#define LOADSCRIPT +#ifdef LOADSCRIPT +#define LOAD_LUA +#endif +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +#ifdef COMPILE +#define LOAD_LUA +#endif +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 +#define X10_OPENTX_221 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files +#define FNV_HASH + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +#ifdef TESTMODE + -- cell count + #define CELLCOUNT 6 + --#define DEMO + -- clone batt 1 data over fake batt 2 + #define BATT2TEST + -- clone FLVSS1 data over a fake FLVSS 2 + --#define FLVSS2TEST + --pushes some test messages + --#define TESTMESSAGES +#endif +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- +#define VFAS_ID 0x021F +#define VFAS_SUBID 0 +#define VFAS_INSTANCE 0 +#define VFAS_PRECISION 2 +#define VFAS_NAME "VFAS" + +#define CURR_ID 0x020F +#define CURR_SUBID 0 +#define CURR_INSTANCE 0 +#define CURR_PRECISION 1 +#define CURR_NAME "CURR" + +#define VSpd_ID 0x011F +#define VSpd_SUBID 0 +#define VSpd_INSTANCE 0 +#define VSpd_PRECISION 1 +#define VSpd_NAME "VSpd" + +#define GSpd_ID 0x083F +#define GSpd_SUBID 0 +#define GSpd_INSTANCE 0 +#define GSpd_PRECISION 0 +#define GSpd_NAME "GSpd" + +#define Alt_ID 0x010F +#define Alt_SUBID 0 +#define Alt_INSTANCE 0 +#define Alt_PRECISION 1 +#define Alt_NAME "Alt" + +#define GAlt_ID 0x082F +#define GAlt_SUBID 0 +#define GAlt_INSTANCE 0 +#define GAlt_PRECISION 0 +#define GAlt_NAME "GAlt" + +#define Hdg_ID 0x084F +#define Hdg_SUBID 0 +#define Hdg_INSTANCE 0 +#define Hdg_PRECISION 0 +#define Hdg_NAME "Hdg" + +#define Fuel_ID 0x060F +#define Fuel_SUBID 0 +#define Fuel_INSTANCE 0 +#define Fuel_PRECISION 0 +#define Fuel_NAME "Fuel" + +#define IMUTmp_ID 0x041F +#define IMUTmp_SUBID 0 +#define IMUTmp_INSTANCE 0 +#define IMUTmp_PRECISION 0 +#define IMUTmp_NAME "IMUt" + +#define ARM_ID 0x060F +#define ARM_SUBID 0 +#define ARM_INSTANCE 1 +#define ARM_PRECISION 0 +#define ARM_NAME "ARM" + +#define WPD_ID 0x082F +#define WPD_SUBID 0 +#define WPD_INSTANCE 10 +#define WPD_PRECISION 0 +#define WPD_NAME "WPD" + +#define WPN_ID 0x050F +#define WPN_SUBID 0 +#define WPN_INSTANCE 10 +#define WPN_PRECISION 0 +#define WPN_NAME "WPN" + +#define WPX_ID 0x082F +#define WPX_SUBID 0 +#define WPX_INSTANCE 11 +#define WPX_PRECISION 0 +#define WPX_NAME "WPX" + +#define WPB_ID 0x084F +#define WPB_SUBID 0 +#define WPB_INSTANCE 10 +#define WPB_PRECISION 0 +#define WPB_NAME "WPB" + +#define ASpd_ID 0x0AF +#define ASpd_SUBID 0 +#define ASpd_INSTANCE 0 +#define ASpd_PRECISION 0 +#define ASpd_NAME "ASpd" + +#define BAlt_ID 0x010F +#define BAlt_SUBID 0 +#define BAlt_INSTANCE 1 +#define BAlt_PRECISION 1 +#define BAlt_NAME "BAlt" + +-- Throttle and RC use RPM sensor IDs +#define Thr_ID 0x050F +#define Thr_SUBID 0 +#define Thr_INSTANCE 0 +#define Thr_PRECISION 0 +#define Thr_NAME "Thr" + +--------------------- +-- BATTERY DEFAULTS +--------------------- +#define CELLFULL 4.35 +#define CELLEMPTY 3.0 +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +#define BACKLIGHT_GV 8 +#define BACKLIGHT_DURATION 5 +--------------------------------- +-- CONF REFRESH GV +--------------------------------- +#define CONF_GV 8 +#define CONF_FM_GV 8 + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]] +#define ALARM_NOTIFIED 1 +#define ALARM_START 2 +#define ALARM_ARMED 3 +#define ALARM_TYPE 4 +#define ALARM_GRACE 5 +#define ALARM_READY 6 +#define ALARM_LAST_ALARM 7 +-- +#define ALARMS_MIN_ALT 1 +#define ALARMS_MAX_ALT 2 +#define ALARMS_MAX_DIST 3 +#define ALARMS_FS_EKF 4 +#define ALARMS_FS_BATT 5 +#define ALARMS_TIMER 6 +#define ALARMS_BATT_L1 7 +#define ALARMS_BATT_L2 8 +#define ALARMS_MAX_HDOP 9 +-- +#define ALARM_TYPE_MIN 0 +#define ALARM_TYPE_MAX 1 +#define ALARM_TYPE_TIMER 2 +#define ALARM_TYPE_BATT 3 +#define ALARM_TYPE_BATT_CRT 4 +-- +#define ALARM_TYPE_BATT_GRACE 4 + +#define MIN_BATT1_FC 1 +#define MIN_BATT2_FC 2 +#define MIN_CELL1_VS 3 +#define MIN_CELL2_VS 4 +#define MIN_BATT1_VS 5 +#define MIN_BATT2_VS 6 +-- +#define MAX_CURR 7 +#define MAX_CURR1 8 +#define MAX_CURR2 9 +#define MAX_POWER 10 +#define MINMAX_ALT 11 +#define MAX_GPSALT 12 +#define MAX_VSPEED 13 +#define MAX_HSPEED 14 +#define MAX_DIST 15 +#define MAX_RANGE 16 + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing +#define HUD_ALGO3 + +#define TOPBAR_Y 0 +#define TOPBAR_HEIGHT 20 +#define TOPBAR_WIDTH LCD_W + +#define BOTTOMBAR_Y LCD_H-20 +#define BOTTOMBAR_HEIGHT 20 +#define BOTTOMBAR_WIDTH LCD_W + +#define RSSI_X 285 +#define RSSI_Y 0 +#define RSSI_FLAGS 0 + +#define TXVOLTAGE_X 350 +#define TXVOLTAGE_Y 0 +#define TXVOLTAGE_FLAGS 0 + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- +#define TYPEVALUE 0 +#define TYPECOMBO 1 +#define MENU_Y 25 +#define MENU_PAGESIZE 11 +#define MENU_ITEM_X 300 + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + +#define UNIT_ALT_SCALE unitScale +#define UNIT_DIST_SCALE unitScale +#define UNIT_DIST_LONG_SCALE unitLongScale +#define UNIT_ALT_LABEL unitLabel +#define UNIT_DIST_LABEL unitLabel +#define UNIT_DIST_LONG_LABEL unitLongLabel +#define UNIT_HSPEED_SCALE conf.horSpeedMultiplier +#define UNIT_VSPEED_SCALE conf.vertSpeedMultiplier +#define UNIT_HSPEED_LABEL conf.horSpeedLabel +#define UNIT_VSPEED_LABEL conf.vertSpeedLabel + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +#define BATT_CELL 1 +#define BATT_VOLT 4 +#define BATT_CURR 7 +#define BATT_MAH 10 +#define BATT_CAP 13 +-- +#define BATT_IDALL 0 +#define BATT_ID1 1 +#define BATT_ID2 2 + +#define BATTCONF_PARALLEL 1 +#define BATTCONF_SERIAL 2 +#define BATTCONF_OTHER 3 +----------------------- +-- LIBRARY LOADING +----------------------- +#ifdef LOAD_LUA +#define loadMenuLib() dofile(basePath..menuLibFile..".lua") +#else +#define loadMenuLib() dofile(basePath..menuLibFile..".luac") +#endif + +---------------------- +--- COLORS +---------------------- +#define COLOR_BLACK 0x0000 +#define COLOR_WHITE 0xFFFF +#define COLOR_GREEN 0x1FEA +#define COLOR_DARKBLUE 0x0AB1 +#define COLOR_DARKBLUE_2 0x0169 +#define COLOR_DARKBLUE_3 0x01AB +#define COLOR_BLUE +#define COLOR_YELLOW 0xFE60 +#define COLOR_ORANGE 0xFE60 +#define COLOR_RED 0xF800 +#define COLOR_LIGHT_GREY 0x8C71 +#define COLOR_GREY 0x7BCF +#define COLOR_DARK_GREY 0x5AEB +#define COLOR_LIGHTRED 0xF9A0 +#define COLOR_BARS_2 0x10A3 + +#define COLOR_BATTERY COLOR_YELLOW +--#define COLOR_LABEL COLOR_GREY +#define COLOR_LABEL COLOR_BLACK +#define COLOR_TEXT COLOR_WHITE +#define COLOR_TEXTEX COLOR_WHITE +--#define COLOR_BG COLOR_DARKBLUE_2 +#define COLOR_BG COLOR_DARKBLUE +#define COLOR_BARS COLOR_BLACK +--#define COLOR_BARSEX COLOR_BARS_2 +#define COLOR_BARSEX COLOR_BLACK +#define COLOR_LINES COLOR_WHITE +#define COLOR_NOTELEM COLOR_RED + +#define COLOR_CRIT COLOR_RED +#define COLOR_WARN COLOR_YELLOW + +--#define COLOR_SENSORS COLOR_DARKBLUE_2 +#define COLOR_SENSORS COLOR_BLACK +#define COLOR_SENSORS_LABEL COLOR_LIGHT_GREY +#define COLOR_SENSORS_TEXT COLOR_WHITE + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- +#define TRANSITION_LASTVALUE 1 +#define TRANSITION_LASTCHANGED 2 +#define TRANSITION_DONE 3 +#define TRANSITION_DELAY 4 + +#define TRANSITIONS_FLIGHTMODE 1 + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- +#define CS_INSIDE 0 +#define CS_LEFT 1 +#define CS_RIGHT 2 +#define CS_BOTTOM 4 +#define CS_TOP 8 + + + + + + + diff --git a/HORUS/SOURCES/PP/init.lua b/HORUS/SOURCES/PP/init.lua deleted file mode 100644 index f8e0d568..00000000 --- a/HORUS/SOURCES/PP/init.lua +++ /dev/null @@ -1,132 +0,0 @@ - - --- --- --- - -local function resetTelemetry(status,alarms,function_pushMessage,function_clearTable) - -- sport queue max pops to prevent looping forever - local i = 0 - -- empty sport queue - local a,b,c,d = sportTelemetryPop() - while a ~= null and i < 50 do - a,b,c,d = sportTelemetryPop() - i = i + 1 - end - -- FLVSS 1 - status.cell1min = 0 - status.cell1sum = 0 - -- FLVSS 2 - status.cell2min = 0 - status.cell2sum = 0 - -- FC 1 - status.cell1sumFC = 0 - -- used to calculate cellcount - status.cell1maxFC = 0 - -- FC 2 - status.cell2sumFC = 0 - -- A2 - status.cellsumA2 = 0 - -- used to calculate cellcount - status.cellmaxA2 = 0 - -------------------------------- - -- AP STATUS - status.flightMode = 0 - status.simpleMode = 0 - status.landComplete = 0 - status.statusArmed = 0 - status.battFailsafe = 0 - status.ekfFailsafe = 0 - status.imuTemp = 0 - -- GPS - status.numSats = 0 - status.gpsStatus = 0 - status.gpsHdopC = 100 - status.gpsAlt = 0 - -- BATT - status.cellcount = 0 - status.battsource = "na" - -- BATT 1 - status.batt1volt = 0 - status.batt1current = 0 - status.batt1mah = 0 - status.batt1sources = { - a2 = false, - vs = false, - fc = false - } - -- BATT 2 - status.batt2volt = 0 - status.batt2current = 0 - status.batt2mah = 0 - status.batt2sources = { - a2 = false, - vs = false, - fc = false - } - -- TELEMETRY - status.noTelemetryData = 1 - -- HOME - status.homeDist = 0 - status.homeAlt = 0 - status.homeAngle = -1 - -- MESSAGES - status.msgBuffer = "" - status.lastMsgValue = 0 - status.lastMsgTime = 0 - -- VELANDYAW - status.vSpeed = 0 - status.hSpeed = 0 - status.yaw = 0 - -- SYNTH VSPEED SUPPORT - status.vspd = 0 - status.synthVSpeedTime = 0 - status.prevHomeAlt = 0 - -- ROLLPITCH - status.roll = 0 - status.pitch = 0 - status.range = 0 - -- PARAMS - status.frameType = -1 - status.batt1Capacity = 0 - status.batt2Capacity = 0 - -- FLIGHT TIME - status.lastTimerStart = 0 - status.timerRunning = 0 - status.flightTime = 0 - -- EVENTS - status.lastStatusArmed = 0 - status.lastGpsStatus = 0 - status.lastFlightMode = 0 - status.lastSimpleMode = 0 - -- battery levels - status.batLevel = 99 - status.battLevel1 = false - status.battLevel2 = false - status.lastBattLevel = 14 - -- messages - status.lastMessage = nil - status.lastMessageSeverity = 0 - status.lastMessageCount = 1 - status.messageCount = 0 - -- clear message queue - function_clearTable(status.messages) - --- - status.messages = {} - -- reset alarms - alarms[1] = { false, 0 , false, 0, 0, false, 0} --MIN_ALT - alarms[2] = { false, 0 , true, 1 , 0, false, 0 } --MAX_ALT - alarms[3] = { false, 0 , true, 1 , 0, false, 0 } --MAX_DIST - alarms[4] = { false, 0 , true, 1 , 0, false, 0 } --FS_EKF - alarms[5] = { false, 0 , true, 1 , 0, false, 0 } --FS_BAT - alarms[6] = { false, 0 , true, 2, 0, false, 0 } --FLIGTH_TIME - alarms[7] = { false, 0 , false, 3, 4, false, 0 } --BATT L1 - alarms[8] = { false, 0 , false, 3, 4, false, 0 } --BATT L2 - -- stop and reset timer - model.setTimer(2,{mode=0}) - model.setTimer(2,{value=0}) - -- - function_pushMessage(7,"telemetry reset") -end - -return {resetTelemetry=resetTelemetry} diff --git a/HORUS/SOURCES/PP/lib/copter.lua b/HORUS/SOURCES/PP/lib/copter.lua new file mode 100644 index 00000000..224854f8 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/copter.lua @@ -0,0 +1,59 @@ + --[[ + // Auto Pilot Modes enumeration + enum control_mode_t { + STABILIZE = 0, // manual airframe angle with manual throttle + ACRO = 1, // manual body-frame angular rate with manual throttle + ALT_HOLD = 2, // manual airframe angle with automatic throttle + AUTO = 3, // fully automatic waypoint control using mission commands + GUIDED = 4, // fully automatic fly to coordinate or fly at velocity/direction using GCS immediate commands + LOITER = 5, // automatic horizontal acceleration with automatic throttle + RTL = 6, // automatic return to launching point + CIRCLE = 7, // automatic circular flight with automatic throttle + LAND = 9, // automatic landing with horizontal position control + DRIFT = 11, // semi-automous position, yaw and throttle control + SPORT = 13, // manual earth-frame angular rate control with manual throttle + FLIP = 14, // automatically flip the vehicle on the roll axis + AUTOTUNE = 15, // automatically tune the vehicle's roll and pitch gains + POSHOLD = 16, // automatic position hold with manual override, with automatic throttle + BRAKE = 17, // full-brake using inertial/GPS system, no pilot input + THROW = 18, // throw to launch mode using inertial/GPS system, no pilot input + AVOID_ADSB = 19, // automatic avoidance of obstacles in the macro scale - e.g. full-sized aircraft + GUIDED_NOGPS = 20, // guided mode but only accepts attitude and altitude + SMART_RTL = 21, // SMART_RTL returns to home by retracing its steps + FLOWHOLD = 22, // FLOWHOLD holds position with optical flow without rangefinder + FOLLOW = 23, // follow attempts to follow another vehicle or ground station + ZIGZAG = 24, // ZIGZAG mode is able to fly in a zigzag manner with predefined point A and point B + }; + --]] + local flightModes = {} + + -- copter flight modes + flightModes[0]="" + flightModes[1]="Stabilize" + flightModes[2]="Acro" + flightModes[3]="AltHold" + flightModes[4]="Auto" + flightModes[5]="Guided" + flightModes[6]="Loiter" + flightModes[7]="RTL" + flightModes[8]="Circle" + flightModes[9]="" + flightModes[10]="Land" + flightModes[11]="" + flightModes[12]="Drift" + flightModes[13]="" + flightModes[14]="Sport" + flightModes[15]="Flip" + flightModes[16]="AutoTune" + flightModes[17]="PosHold" + flightModes[18]="Brake" + flightModes[19]="Throw" + flightModes[20]="AvoidADSB" + flightModes[21]="GuidedNOGPS" + flightModes[22]="SmartRTL" + flightModes[23]="FlowHold" + flightModes[24]="Follow" + flightModes[25]="ZigZag" + flightModes[26]="Initializing" + +return {flightModes=flightModes} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/copter_px4.lua b/HORUS/SOURCES/PP/lib/copter_px4.lua new file mode 100644 index 00000000..f1bb2c01 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/copter_px4.lua @@ -0,0 +1,28 @@ +local flightModes = {} +-- plane flight modes +flightModes[0]="" +flightModes[1]="Manual" +flightModes[2]="AltCtl" --px4 specific +flightModes[3]="PosCtl" --px4 specific +flightModes[4]="Ready" --px4 specific +flightModes[5]="Takeoff" --px4 specific +flightModes[6]="Loiter" +flightModes[7]="Mission" --px4 specific +flightModes[8]="RTL" +flightModes[9]="Land" +flightModes[10]="RTGS" --px4 specific +flightModes[11]="Follow" +flightModes[12]="PrecLand" --px4 specific +flightModes[13]="" +flightModes[14]="Acro" +flightModes[15]="OffBoard" --px4 specific +flightModes[16]="Stabilize" +flightModes[17]="RAttitude" --px4 specific +flightModes[18]="Simple" --px4 specific +flightModes[19]="" +flightModes[20]="" +flightModes[21]="" +flightModes[22]="" +flightModes[23]="" +-- +return {flightModes=flightModes} diff --git a/HORUS/SOURCES/PP/lib/draw.lua b/HORUS/SOURCES/PP/lib/draw.lua new file mode 100644 index 00000000..d6c115bf --- /dev/null +++ b/HORUS/SOURCES/PP/lib/draw.lua @@ -0,0 +1,491 @@ +#include "includes/yaapu_inc.lua" + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() + +#ifdef DEV +local function draw8(x0,y0,x,y) + lcd.drawPoint(x0 + x, y0 + y); + lcd.drawPoint(x0 + y, y0 + x); + lcd.drawPoint(x0 - y, y0 + x); + lcd.drawPoint(x0 - x, y0 + y); + lcd.drawPoint(x0 - x, y0 - y); + lcd.drawPoint(x0 - y, y0 - x); + lcd.drawPoint(x0 + y, y0 - x); + lcd.drawPoint(x0 + x, y0 - y); +end + +local function drawCircle10(x0,y0) + draw8(x0,y0,5,1) + draw8(x0,y0,5,2) + draw8(x0,y0,4,3) + draw8(x0,y0,4,4) + lcd.drawPoint(x0 + 5,y0) + lcd.drawPoint(x0 - 5,y0) + lcd.drawPoint(x0,y0 + 5) + lcd.drawPoint(x0,y0 - 5) +end + +local function drawCircle(x0,y0,radius,delta) + local x = radius-1 + local y = 0 + local dx = delta + local dy = delta + local err = dx - bit32.lshift(radius,1) + while (x >= y) do + lcd.drawPoint(x0 + x, y0 + y); + lcd.drawPoint(x0 + y, y0 + x); + lcd.drawPoint(x0 - y, y0 + x); + lcd.drawPoint(x0 - x, y0 + y); + lcd.drawPoint(x0 - x, y0 - y); + lcd.drawPoint(x0 - y, y0 - x); + lcd.drawPoint(x0 + y, y0 - x); + lcd.drawPoint(x0 + x, y0 - y); + if err <= 0 then + y=y+1 + err = err + dy + dy = dy + 2 + end + if err > 0 then + + x=x-1 + dx = dx + 2 + err = err + dx - bit32.lshift(radius,1) + end + end +end + +local function drawHomePad(x0,y0) + drawCircle(x0 + 5,y0,5,2) + lcd.drawText(x0 + 5 - 2,y0 - 3,"H") +end + +local function drawScreenTitle(title,page, pages) + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) +end +#endif --DEV + +local function drawHArrow(x,y,width,left,right,drawBlinkBitmap) + lcd.drawLine(x, y, x + width,y, SOLID, 0) + if left == true then + lcd.drawLine(x + 1,y - 1,x + 2,y - 2, SOLID, 0) + lcd.drawLine(x + 1,y + 1,x + 2,y + 2, SOLID, 0) + end + if right == true then + lcd.drawLine(x + width - 1,y - 1,x + width - 2,y - 2, SOLID, 0) + lcd.drawLine(x + width - 1,y + 1,x + width - 2,y + 2, SOLID, 0) + end +end +-- +local function drawVArrow(x,y,top,bottom,utils) + if top == true then + utils.drawBlinkBitmap("uparrow",x,y) + else + utils.drawBlinkBitmap("downarrow",x,y) + end +end + +local function drawHomeIcon(x,y,utils) + lcd.drawBitmap(utils.getBitmap("minihomeorange"),x,y) +end + +#ifdef X10_OPENTX_221 +local function drawLine(x1,y1,x2,y2,flags1,flags2) + -- if lines are hor or ver do not fix +--if string.find(radio, "x10") and rev < 2 and x1 ~= x2 and y1 ~= y2 then + if string.find(radio, "x10") and rev < 2 then + lcd.drawLine(LCD_W-x1,LCD_H-y1,LCD_W-x2,LCD_H-y2,flags1,flags2) + else + lcd.drawLine(x1,y1,x2,y2,flags1,flags2) + end +end +#endif --X10_OPENTX_221 + +local function computeOutCode(x,y,xmin,ymin,xmax,ymax) + local code = CS_INSIDE; --initialised as being inside of hud + -- + if x < xmin then --to the left of hud + code = bit32.bor(code,CS_LEFT); + elseif x > xmax then --to the right of hud + code = bit32.bor(code,CS_RIGHT); + end + if y < ymin then --below the hud + code = bit32.bor(code,CS_TOP); + elseif y > ymax then --above the hud + code = bit32.bor(code,CS_BOTTOM); + end + -- + return code; +end + +-- Cohen–Sutherland clipping algorithm +-- https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm +local function drawLineWithClippingXY(x0,y0,x1,y1,style,xmin,xmax,ymin,ymax,color,radio,rev) + -- compute outcodes for P0, P1, and whatever point lies outside the clip rectangle + local outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax); + local outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); + local accept = false; + + while (true) do + if ( bit32.bor(outcode0,outcode1) == CS_INSIDE) then + -- bitwise OR is 0: both points inside window; trivially accept and exit loop + accept = true; + break; + elseif (bit32.band(outcode0,outcode1) ~= CS_INSIDE) then + -- bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP, BOTTOM) + -- both must be outside window; exit loop (accept is false) + break; + else + -- failed both tests, so calculate the line segment to clip + -- from an outside point to an intersection with clip edge + local x = 0 + local y = 0 + -- At least one endpoint is outside the clip rectangle; pick it. + local outcodeOut = outcode0 ~= CS_INSIDE and outcode0 or outcode1 + -- No need to worry about divide-by-zero because, in each case, the + -- outcode bit being tested guarantees the denominator is non-zero + if bit32.band(outcodeOut,CS_BOTTOM) ~= CS_INSIDE then --point is above the clip window + x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0) + y = ymax + elseif bit32.band(outcodeOut,CS_TOP) ~= CS_INSIDE then --point is below the clip window + x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0) + y = ymin + elseif bit32.band(outcodeOut,CS_RIGHT) ~= CS_INSIDE then --point is to the right of clip window + y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0) + x = xmax + elseif bit32.band(outcodeOut,CS_LEFT) ~= CS_INSIDE then --point is to the left of clip window + y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0) + x = xmin + end + -- Now we move outside point to intersection point to clip + -- and get ready for next pass. + if outcodeOut == outcode0 then + x0 = x + y0 = y + outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax) + else + x1 = x + y1 = y + outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax) + end + end + end + if accept then +#ifdef X10_OPENTX_221 + drawLine(x0,y0,x1,y1, style,color) +#else + lcd.drawLine(x0,y0,x1,y1, style,color) +#endif + end +end + +local function drawLineWithClipping(ox,oy,angle,len,style,xmin,xmax,ymin,ymax,color,radio,rev) + local xx = math.cos(math.rad(angle)) * len * 0.5 + local yy = math.sin(math.rad(angle)) * len * 0.5 + + local x0 = ox - xx + local x1 = ox + xx + local y0 = oy - yy + local y1 = oy + yy + + drawLineWithClippingXY(x0,y0,x1,y1,style,xmin,xmax,ymin,ymax,color,radio,rev) +end + +local function drawNumberWithDim(x,y,xDim,yDim,number,dim,flags,dimFlags) + lcd.drawNumber(x, y, number,flags) + lcd.drawText(xDim, yDim, dim, dimFlags) +end + +local function drawRArrow(x,y,r,angle,color) + local ang = math.rad(angle - 90) + local x1 = x + r * math.cos(ang) + local y1 = y + r * math.sin(ang) + + ang = math.rad(angle - 90 + 150) + local x2 = x + r * math.cos(ang) + local y2 = y + r * math.sin(ang) + + ang = math.rad(angle - 90 - 150) + local x3 = x + r * math.cos(ang) + local y3 = y + r * math.sin(ang) + ang = math.rad(angle - 270) + local x4 = x + r * 0.5 * math.cos(ang) + local y4 = y + r * 0.5 *math.sin(ang) + -- +#ifdef X10_OPENTX_221 + drawLine(x1,y1,x2,y2,SOLID,color) + drawLine(x1,y1,x3,y3,SOLID,color) + drawLine(x2,y2,x4,y4,SOLID,color) + drawLine(x3,y3,x4,y4,SOLID,color) +#else + lcd.drawLine(x1,y1,x2,y2,SOLID,color) + lcd.drawLine(x1,y1,x3,y3,SOLID,color) + lcd.drawLine(x2,y2,x4,y4,SOLID,color) + lcd.drawLine(x3,y3,x4,y4,SOLID,color) +#endif +end + +local function drawFailsafe(telemetry,utils) + if telemetry.ekfFailsafe > 0 then + utils.drawBlinkBitmap("ekffailsafe",LCD_W/2 - 90,154) + end + if telemetry.battFailsafe > 0 then + utils.drawBlinkBitmap("battfailsafe",LCD_W/2 - 90,154) + end +end + +local function drawArmStatus(status,telemetry,utils) + -- armstatus + if telemetry.ekfFailsafe == 0 and telemetry.battFailsafe == 0 and status.timerRunning == 0 then + if (telemetry.statusArmed == 1) then + lcd.drawBitmap(utils.getBitmap("armed"),LCD_W/2 - 90,154) + else + utils.drawBlinkBitmap("disarmed",LCD_W/2 - 90,154) + end + end +end + +local function drawNoTelemetryData(status,telemetry,utils,telemetryEnabled) + -- no telemetry data + if (not telemetryEnabled()) then +#ifdef SPLASH + lcd.drawBitmap(utils.getBitmap("notelemetry"),(LCD_W-404)/2,(LCD_H-164)/2 + 10) --404x164 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255,255)) + lcd.drawText(130, 208, VERSION, SMLSIZE+CUSTOM_COLOR) +#else --SPLASH + lcd.setColor(CUSTOM_COLOR,COLOR_WHITE) + lcd.drawFilledRectangle(88,74, 304, 84, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_NOTELEM) + lcd.drawFilledRectangle(90,76, 300, 80, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(110, 85, "no telemetry data", DBLSIZE+CUSTOM_COLOR) + lcd.drawText(130, 120, VERSION, SMLSIZE+CUSTOM_COLOR) +#endif -- SPLAH + end +end + +local function drawFilledRectangle(x,y,w,h,flags) + if w > 0 and h > 0 then + lcd.drawFilledRectangle(x,y,w,h,flags) + end +end + +#ifdef HUD_ALGO2 +local function fillTriangle(ox, oy, x1, x2, roll, angle,color) + local step = 2 + -- + local y1 = (oy - ox*angle) + x1*angle + local y2 = (oy - ox*angle) + x2*angle + -- + local steps = math.abs(y2-y1) / step + if (0 < roll and roll <= 90) then + for s=0,steps + do + yy = y1 + s*step + xx = (yy - (oy - ox*angle))/angle + lcd.drawRectangle(x1,yy,xx - x1,step,color) + end + elseif (90 < roll and roll <= 180) then + for s=0,steps + do + yy = y2 + s*step + xx = (yy - (oy - ox*angle))/angle + lcd.drawRectangle(x1,yy,xx - x1,step,color) + end + elseif (-90 < roll and roll < 0) then + for s=0,steps + do + yy = y2 + s*step + xx = (yy - (oy - ox*angle))/angle + lcd.drawRectangle(xx,yy,x2-xx+1,step,color) + end + elseif (-180 < roll and roll <= -90) then + for s=0,steps + do + yy = y1 + s*step + xx = (yy - (oy - ox*angle))/angle + lcd.drawRectangle(xx,yy,x2-xx+1,step,color) + end + end +end +#endif --HUD_ALGO2 + +local yawRibbonPoints = {} +-- +yawRibbonPoints[0]="N" +yawRibbonPoints[1]=nil +yawRibbonPoints[2]="NE" +yawRibbonPoints[3]=nil +yawRibbonPoints[4]="E" +yawRibbonPoints[5]=nil +yawRibbonPoints[6]="SE" +yawRibbonPoints[7]=nil +yawRibbonPoints[8]="S" +yawRibbonPoints[9]=nil +yawRibbonPoints[10]="SW" +yawRibbonPoints[11]=nil +yawRibbonPoints[12]="W" +yawRibbonPoints[13]=nil +yawRibbonPoints[14]="NW" +yawRibbonPoints[15]=nil + +-- optimized yaw ribbon drawing +local function drawCompassRibbon(y,myWidget,conf,telemetry,status,battery,utils,width,xMin,xMax,stepWidth,bigFont) + -- ribbon centered +/- 90 on yaw + local centerYaw = (telemetry.yaw + 270 - (bigFont and 16 or 10))%360 -- (-10 needed to center ribbon) + -- this is the first point left to be drawn on the compass ribbon + local nextPoint = math.floor(centerYaw/22.5) * 22.5 + -- x coord of first ribbon letter + local nextPointX = xMin + (nextPoint - centerYaw)/22.5 * stepWidth + -- + local i = (nextPoint / 22.5) % 16 + for idx=1,12 + do + local letterOffset = 1 + local lineOffset = 4 + if nextPointX >= xMin -3 and nextPointX < xMax then + if yawRibbonPoints[i] == nil then + lcd.setColor(CUSTOM_COLOR,COLOR_LINES) + lcd.drawLine(nextPointX + lineOffset, y+1, nextPointX + lineOffset, y+7, SOLID, CUSTOM_COLOR) + else + if #yawRibbonPoints[i] > 1 then + letterOffset = -5 + lineOffset = 2 + end + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + --lcd.setColor(CUSTOM_COLOR,COLOR_GREY) + lcd.drawText(nextPointX+letterOffset,y+(bigFont and -2 or 0),yawRibbonPoints[i],SMLSIZE+CUSTOM_COLOR) + end + end + i = (i + 1) % 16 + nextPointX = nextPointX + stepWidth + end + -- home icon + local homeOffset = 0 + local angle = telemetry.homeAngle - telemetry.yaw + if angle < 0 then + angle = 360 + angle + end + if angle > 270 or angle < 90 then + homeOffset = ((angle + 90) % 180)/180 * width + elseif angle >= 90 and angle <= 180 then + homeOffset = width + end + drawHomeIcon(xMin + homeOffset -5,y + (bigFont and 28 or 20),utils) + -- yaw angle box + local xx = 0 + if ( telemetry.yaw < 10) then + xx = bigFont and 20 or 14 + elseif (telemetry.yaw < 100) then + xx = bigFont and 40 or 28 + else + xx = bigFont and 60 or 42 + end + --lcd.drawNumber(LCD_W/2 + xx - 6, YAW_Y, telemetry.yaw, MIDSIZE+INVERS) + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) + lcd.drawFilledRectangle(LCD_W/2 - (xx/2), y - 1, xx, bigFont and 28 or 20, CUSTOM_COLOR+SOLID) + lcd.drawRectangle(LCD_W/2 - (xx/2) - 1, y - 1, xx+2, bigFont and 28 or 20, CUSTOM_COLOR+SOLID) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(LCD_W/2 - (xx/2), y - 6, telemetry.yaw, (bigFont and DBLSIZE or MIDSIZE)+CUSTOM_COLOR) +end + +local function drawStatusBar(maxRows,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + local yDelta = (maxRows-1)*12 + + lcd.setColor(CUSTOM_COLOR,COLOR_BARSEX) + lcd.drawFilledRectangle(0,229-yDelta,480,LCD_H-(229-yDelta),CUSTOM_COLOR) + -- flight time + lcd.setColor(CUSTOM_COLOR,COLOR_TEXTEX) + lcd.drawTimer(LCD_W, 224-yDelta, model.getTimer(2).value, DBLSIZE+CUSTOM_COLOR+RIGHT) + -- flight mode + lcd.setColor(CUSTOM_COLOR,COLOR_TEXTEX) + if status.strFlightMode ~= nil then + lcd.drawText(1,230-yDelta,status.strFlightMode,MIDSIZE+CUSTOM_COLOR) + end + -- gps status, draw coordinatyes if good at least once + if telemetry.lon ~= nil and telemetry.lat ~= nil then + lcd.drawText(370,227-yDelta,utils.decToDMSFull(telemetry.lat),SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(370,241-yDelta,utils.decToDMSFull(telemetry.lon,telemetry.lat),SMLSIZE+CUSTOM_COLOR+RIGHT) + end + -- gps status + local hdop = telemetry.gpsHdopC + local strStatus = gpsStatuses[telemetry.gpsStatus] + local flags = BLINK + local mult = 1 + + if telemetry.gpsStatus > 2 then + if telemetry.homeAngle ~= -1 then + flags = PREC1 + end + if hdop > 999 then + hdop = 999 + flags = 0 + mult=0.1 + elseif hdop > 99 then + flags = 0 + mult=0.1 + end + -- HDOP +#ifdef MAX_HDOP + if telemetry.gpsHdopC > conf.maxHdopAlert then + lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + lcd.drawNumber(270,226-yDelta, hdop*mult,DBLSIZE+flags+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(270,226-yDelta, hdop*mult,DBLSIZE+flags+RIGHT+CUSTOM_COLOR) + end +#else + lcd.drawNumber(270,226-yDelta, hdop*mult,DBLSIZE+flags+RIGHT+CUSTOM_COLOR) +#endif + -- SATS + lcd.setColor(CUSTOM_COLOR,COLOR_TEXTEX) + lcd.drawText(170,226-yDelta, strStatus, SMLSIZE+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,COLOR_TEXTEX) + if telemetry.numSats == 15 then + lcd.drawNumber(170,235-yDelta, telemetry.numSats, MIDSIZE+CUSTOM_COLOR) + lcd.drawText(200,239-yDelta, "+", SMLSIZE+CUSTOM_COLOR) + else + lcd.drawNumber(170,235-yDelta,telemetry.numSats, MIDSIZE+CUSTOM_COLOR) + end + elseif telemetry.gpsStatus == 0 then + utils.drawBlinkBitmap("nogpsicon",150,227-yDelta) + else + utils.drawBlinkBitmap("nolockicon",150,227-yDelta) + end + + local offset = math.min(maxRows,#status.messages+1) + + for i=0,offset-1 do + if status.messages[(status.messageCount + i - offset) % (#status.messages+1)][2] < 4 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,70,0)) + elseif status.messages[(status.messageCount + i - offset) % (#status.messages+1)][2] == 4 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255,0)) + else + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + end + lcd.drawText(1,(256-yDelta)+(12*i), status.messages[(status.messageCount + i - offset) % (#status.messages+1)][1],SMLSIZE+CUSTOM_COLOR) + end +end + +return { + drawNumberWithDim=drawNumberWithDim, + drawHomeIcon=drawHomeIcon, + drawHArrow=drawHArrow, + drawVArrow=drawVArrow, + drawRArrow=drawRArrow, + computeOutCode=computeOutCode, + drawLineWithClippingXY=drawLineWithClippingXY, + drawLineWithClipping=drawLineWithClipping, + drawFailsafe=drawFailsafe, + drawArmStatus=drawArmStatus, + drawNoTelemetryData=drawNoTelemetryData, + drawStatusBar=drawStatusBar, + drawFilledRectangle=drawFilledRectangle, +#ifdef HUD_ALGO2 + fillTriangle=fillTriangle, +#endif --HUD_ALGO2 + drawCompassRibbon=drawCompassRibbon, + yawRibbonPoints=yawRibbonPoints +} diff --git a/HORUS/SOURCES/PP/lib/hud_1.lua b/HORUS/SOURCES/PP/lib/hud_1.lua new file mode 100644 index 00000000..13bbd27e --- /dev/null +++ b/HORUS/SOURCES/PP/lib/hud_1.lua @@ -0,0 +1,225 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_1_inc.lua" + +#define LEFTWIDTH 38 +#define RIGHTWIDTH 38 + +#define HUD_WIDTH 280 +#define HUD_HEIGHT 134 +#define HUD_X (LCD_W-HUD_WIDTH)/2 +#define HUD_Y 18 +#define HUD_Y_MID 85 + +#define VARIO_X 372 +#define VARIO_Y HUD_Y + 18 +#define VARIO_H HUD_HEIGHT/2 +#define VARIO_W 8 + +----------------------- +-- COMPASS RIBBON +----------------------- +#define YAW_X (LCD_W-260)/2 +#define YAW_Y 18 +#define YAW_WIDTH 240 + +#define YAWICON_Y 40 +#define YAWTEXT_Y 18 +#define YAW_STEPWIDTH 25 +#define YAW_SYMBOLS 16 +#define YAW_X_MIN (LCD_W-YAW_WIDTH)/2 +#define YAW_X_MAX (LCD_W+YAW_WIDTH)/2 + +#define PITCH_X 248 +#define PITCH_Y 90 + +#define ROLL_X 214 +#define ROLL_Y 76 + + +#define R2 21 + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() +#ifdef HUDTIMER +local hudDrawTime = 0 +local hudDrawCounter = 0 +#endif + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) +#ifdef HUDTIMER + local hudStart = getTime() +#endif + + local r = -telemetry.roll + local cx,cy,dx,dy,ccx,ccy,cccx,cccy + local yPos = TOPBAR_Y + TOPBAR_HEIGHT + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of R2 + if ( telemetry.roll == 0 or math.abs(telemetry.roll) == 180) then + dx=0 + dy=telemetry.pitch * 1.85 + cx=0 + cy=R2 + ccx=0 + ccy=2*R2 + cccx=0 + cccy=3*R2 + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch * 1.85 + -- 1st line offsets + cx = math.cos(math.rad(90 - r)) * R2 + cy = math.sin(math.rad(90 - r)) * R2 + end + local rollX = math.floor(HUD_X + HUD_WIDTH/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 140x90 + local minY = HUD_Y + local maxY = HUD_Y + HUD_HEIGHT + + local minX = HUD_X + local maxX = HUD_X + HUD_WIDTH + + local ox = HUD_X + HUD_WIDTH/2 + dx + local oy = HUD_Y_MID + dy + local yy = 0 + + -- HUD + #include "includes/hud_algo_inc.lua" + + -- parallel lines above and below horizon + local linesMaxY = maxY-2 + local linesMinY = minY+10 + lcd.setColor(CUSTOM_COLOR,COLOR_WHITE) + -- +/- 90 deg + for dist=1,8 + do + drawLib.drawLineWithClipping(rollX + dx - dist*cx,dy + HUD_Y_MID + dist*cy,r,(dist%2==0 and 80 or 40),DOTTED,HUD_X+2,HUD_X+HUD_WIDTH-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + dx + dist*cx,dy + HUD_Y_MID - dist*cy,r,(dist%2==0 and 80 or 40),DOTTED,HUD_X+2,HUD_X+HUD_WIDTH-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + end + + -- hashmarks + local startY = minY + 1 + local endY = maxY - 10 + local step = 18 + -- hSpeed + local roundHSpeed = math.floor((telemetry.hSpeed*UNIT_HSPEED_SCALE*0.1/5)+0.5)*5; + local offset = math.floor((telemetry.hSpeed*UNIT_HSPEED_SCALE*0.1-roundHSpeed)*0.2*step); + local ii = 0; + local yy = 0 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(120,120,120)) + for j=roundHSpeed+20,roundHSpeed-20,-5 + do + yy = startY + (ii*step) + offset - 14 + if yy >= startY and yy < endY then + lcd.drawLine(HUD_X, yy+9, HUD_X + 4, yy+9, SOLID, CUSTOM_COLOR) + lcd.drawNumber(HUD_X + 7, yy, j, SMLSIZE+CUSTOM_COLOR) + end + ii=ii+1; + end + -- altitude + local roundAlt = math.floor((telemetry.homeAlt*UNIT_ALT_SCALE/5)+0.5)*5; + offset = math.floor((telemetry.homeAlt*UNIT_ALT_SCALE-roundAlt)*0.2*step); + ii = 0; + yy = 0 + for j=roundAlt+20,roundAlt-20,-5 + do + yy = startY + (ii*step) + offset - 14 + if yy >= startY and yy < endY then + lcd.drawLine(HUD_X + HUD_WIDTH - 14, yy+8, HUD_X + HUD_WIDTH-10 , yy+8, SOLID, CUSTOM_COLOR) + lcd.drawNumber(HUD_X + HUD_WIDTH - 16, yy, j, SMLSIZE+RIGHT+CUSTOM_COLOR) + end + ii=ii+1; + end + lcd.setColor(CUSTOM_COLOR,COLOR_WHITE) + + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_280x134"),(LCD_W-HUD_WIDTH)/2,HUD_Y) --160x90 + + ------------------------------------- + -- vario + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = varioSpeed/varioMax*52 + --varioH = varioH + (varioH > 0 and 1 or 0) + if telemetry.vSpeed > 0 then + varioY = 19 + (52 - varioH) + else + varioY = 85 + 15 + end + --00ae10 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(50, 50, 50)) --dark grey + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) --white + lcd.drawFilledRectangle(VARIO_X, varioY, VARIO_W, varioH, CUSTOM_COLOR, 0) + + ------------------------------------- + -- left and right indicators on HUD + ------------------------------------- + -- DATA + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,MINMAX_ALT) * UNIT_ALT_SCALE + if math.abs(alt) > 999 or alt < -99 then + lcd.drawNumber(HUD_X+HUD_WIDTH+1,HUD_Y_MID-16,alt,MIDSIZE+CUSTOM_COLOR+RIGHT) + elseif math.abs(alt) >= 10 then + lcd.drawNumber(HUD_X+HUD_WIDTH+1,HUD_Y_MID-20,alt,DBLSIZE+CUSTOM_COLOR+RIGHT) + else + lcd.drawNumber(HUD_X+HUD_WIDTH+1,HUD_Y_MID-20,alt*10,DBLSIZE+PREC1+CUSTOM_COLOR+RIGHT) + end + -- telemetry.hSpeed is in dm/s + local hSpeed = utils.getMaxValue(telemetry.hSpeed,MAX_HSPEED) * 0.1 * UNIT_HSPEED_SCALE + if (math.abs(hSpeed) >= 10) then + lcd.drawNumber(HUD_X+2,HUD_Y_MID-20,hSpeed,DBLSIZE+CUSTOM_COLOR) + else + lcd.drawNumber(HUD_X+2,HUD_Y_MID-20,hSpeed*10,DBLSIZE+CUSTOM_COLOR+PREC1) + end + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow(HUD_X+68, HUD_Y_MID-12,true,false,utils) + drawLib.drawVArrow(HUD_X+HUD_WIDTH-79, HUD_Y_MID-12,true,false,utils) + end + + -- vspeed box + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + + local vSpeed = utils.getMaxValue(telemetry.vSpeed,MAX_VSPEED) * 0.1 -- m/s + + local xx = math.abs(vSpeed*UNIT_VSPEED_SCALE) > 999 and 4 or 3 + xx = xx + (vSpeed*UNIT_VSPEED_SCALE < 0 and 1 or 0) + + if math.abs(vSpeed*UNIT_VSPEED_SCALE*10) > 99 then -- + lcd.drawNumber((LCD_W)/2 + (xx/2)*12, 127, vSpeed*UNIT_VSPEED_SCALE, MIDSIZE+CUSTOM_COLOR+RIGHT) + else + lcd.drawNumber((LCD_W)/2 + (xx/2)*12, 127, vSpeed*UNIT_VSPEED_SCALE*10, MIDSIZE+CUSTOM_COLOR+RIGHT+PREC1) + end + + -- compass ribbon + drawLib.drawCompassRibbon(YAW_Y,myWidget,conf,telemetry,status,battery,utils,YAW_WIDTH,YAW_X_MIN,YAW_X_MAX,YAW_STEPWIDTH,true) + + -- pitch and roll + lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + local xoffset = math.abs(telemetry.pitch) > 99 and 6 or 0 + lcd.drawNumber(PITCH_X+xoffset,PITCH_Y,telemetry.pitch,CUSTOM_COLOR+SMLSIZE+RIGHT) + lcd.drawNumber(ROLL_X,ROLL_Y,telemetry.roll,CUSTOM_COLOR+SMLSIZE+RIGHT) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) +#ifdef HUDTIMER + hudDrawTime = hudDrawTime + (getTime() - hudStart) + hudDrawCounter = hudDrawCounter + 1 +#endif +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/hud_2.lua b/HORUS/SOURCES/PP/lib/hud_2.lua new file mode 100644 index 00000000..57d5e2ac --- /dev/null +++ b/HORUS/SOURCES/PP/lib/hud_2.lua @@ -0,0 +1,199 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_2_inc.lua" + +#define LEFTWIDTH 38 +#define RIGHTWIDTH 38 + +#define HUD_WIDTH 160 +#define HUD_HEIGHT 90 +#define HUD_X (LCD_W-HUD_WIDTH)/2 +#define HUD_Y 24 +#define HUD_Y_MID 69 + +#define VARIO_X 310 +#define VARIO_Y HUD_Y +#define VARIO_H HUD_HEIGHT/2 +#define VARIO_W 10 + +----------------------- +-- COMPASS RIBBON +----------------------- +#define YAW_X (LCD_W-140)/2 +#define YAW_Y 120 +#define YAW_WIDTH 140 + +#define YAWICON_Y 3 +#define YAWTEXT_Y 16 +#define YAW_STEPWIDTH 15 +#define YAW_SYMBOLS 16 +#define YAW_X_MIN (LCD_W-YAW_WIDTH)/2 +#define YAW_X_MAX (LCD_W+YAW_WIDTH)/2 +#define R2 12 + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() +#ifdef HUDTIMER +local hudDrawTime = 0 +local hudDrawCounter = 0 +#endif + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) +#ifdef HUDTIMER + local hudStart = getTime() +#endif + + local r = -telemetry.roll + local cx,cy,dx,dy,ccx,ccy,cccx,cccy + local yPos = TOPBAR_Y + TOPBAR_HEIGHT + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of R2 + if ( telemetry.roll == 0) then + dx=0 + dy=telemetry.pitch + cx=0 + cy=R2 + ccx=0 + ccy=2*R2 + cccx=0 + cccy=3*R2 + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch + -- 1st line offsets + cx = math.cos(math.rad(90 - r)) * R2 + cy = math.sin(math.rad(90 - r)) * R2 + -- 2nd line offsets + ccx = math.cos(math.rad(90 - r)) * 2 * R2 + ccy = math.sin(math.rad(90 - r)) * 2 * R2 + -- 3rd line offsets + cccx = math.cos(math.rad(90 - r)) * 3 * R2 + cccy = math.sin(math.rad(90 - r)) * 3 * R2 + end + local rollX = math.floor(HUD_X + HUD_WIDTH/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 140x90 + local minY = HUD_Y + local maxY = HUD_Y + HUD_HEIGHT + + local minX = HUD_X + local maxX = HUD_X + HUD_WIDTH + + local ox = HUD_X + HUD_WIDTH/2 + dx + local oy = HUD_Y_MID + dy + local yy = 0 + + -- HUD + #include "includes/hud_algo_inc.lua" + + -- parallel lines above and below horizon + local linesMaxY = maxY-1 + local linesMinY = minY+1 + lcd.setColor(CUSTOM_COLOR,COLOR_WHITE) + -- +/- 90 deg + for dist=1,8 + do + drawLib.drawLineWithClipping(rollX + dx - dist*cx,dy + HUD_Y_MID + dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,HUD_X+2,HUD_X+HUD_WIDTH-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + dx + dist*cx,dy + HUD_Y_MID - dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,HUD_X+2,HUD_X+HUD_WIDTH-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + end +-- hashmarks + local startY = minY + 1 + local endY = maxY - 10 + local step = 18 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(120,120,120)) + -- hSpeed + local roundHSpeed = math.floor((telemetry.hSpeed*UNIT_HSPEED_SCALE*0.1/5)+0.5)*5; + local offset = math.floor((telemetry.hSpeed*UNIT_HSPEED_SCALE*0.1-roundHSpeed)*0.2*step); + local ii = 0; + local yy = 0 + for j=roundHSpeed+10,roundHSpeed-10,-5 + do + yy = startY + (ii*step) + offset + if yy >= startY and yy < endY then + lcd.drawLine(HUD_X + 1, yy+9, HUD_X + 5, yy+9, SOLID, CUSTOM_COLOR) + lcd.drawNumber(HUD_X + 8, yy, j, SMLSIZE+CUSTOM_COLOR) + end + ii=ii+1; + end + -- altitude + local roundAlt = math.floor((telemetry.homeAlt*UNIT_ALT_SCALE/5)+0.5)*5; + offset = math.floor((telemetry.homeAlt*UNIT_ALT_SCALE-roundAlt)*0.2*step); + ii = 0; + yy = 0 + for j=roundAlt+10,roundAlt-10,-5 + do + yy = startY + (ii*step) + offset + if yy >= startY and yy < endY then + lcd.drawLine(HUD_X + HUD_WIDTH - 15, yy+8, HUD_X + HUD_WIDTH -10, yy+8, SOLID, CUSTOM_COLOR) + lcd.drawNumber(HUD_X + HUD_WIDTH - 16, yy, j, SMLSIZE+RIGHT+CUSTOM_COLOR) + end + ii=ii+1; + end + lcd.setColor(CUSTOM_COLOR,COLOR_WHITE) + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_160x90c"),(LCD_W-HUD_WIDTH)/2,HUD_Y) --160x90 + ------------------------------------- + -- vario bitmap + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = varioSpeed/varioMax*35 + if telemetry.vSpeed > 0 then + varioY = VARIO_Y + 35 - varioH + else + varioY = VARIO_Y + 55 + end + --00ae10 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(50, 50, 50)) --dark grey + lcd.drawFilledRectangle(VARIO_X, varioY, VARIO_W, varioH, CUSTOM_COLOR, 0) + + ------------------------------------- + -- left and right indicators on HUD + ------------------------------------- + -- DATA + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,MINMAX_ALT) * UNIT_ALT_SCALE + if math.abs(alt) > 999 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + lcd.drawNumber(HUD_X+HUD_WIDTH+1,HUD_Y_MID-10,alt,CUSTOM_COLOR+RIGHT) + elseif math.abs(alt) >= 10 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + lcd.drawNumber(HUD_X+HUD_WIDTH+1,HUD_Y_MID-14,alt,MIDSIZE+CUSTOM_COLOR+RIGHT) + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + lcd.drawNumber(HUD_X+HUD_WIDTH+1,HUD_Y_MID-14,alt*10,MIDSIZE+PREC1+CUSTOM_COLOR+RIGHT) + end + -- telemetry.hSpeed is in dm/s + local hSpeed = utils.getMaxValue(telemetry.hSpeed,MAX_HSPEED) * 0.1 * UNIT_HSPEED_SCALE + if (math.abs(hSpeed) >= 10) then + lcd.drawNumber(HUD_X+2,HUD_Y_MID-14,hSpeed,MIDSIZE+CUSTOM_COLOR) + else + lcd.drawNumber(HUD_X+2,HUD_Y_MID-14,hSpeed*10,MIDSIZE+CUSTOM_COLOR+PREC1) + end +#ifdef HUDTIMER + hudDrawTime = hudDrawTime + (getTime() - hudStart) + hudDrawCounter = hudDrawCounter + 1 +#endif + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow(HUD_X+50, HUD_Y_MID-9,true,false,utils) + drawLib.drawVArrow(HUD_X+HUD_WIDTH-57, HUD_Y_MID-9,true,false,utils) + end + -- compass ribbon + drawLib.drawCompassRibbon(YAW_Y,myWidget,conf,telemetry,status,battery,utils,YAW_WIDTH,YAW_X_MIN,YAW_X_MAX,YAW_STEPWIDTH,false) +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/hud_russian_2.lua b/HORUS/SOURCES/PP/lib/hud_russian_2.lua new file mode 100644 index 00000000..eaff8366 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/hud_russian_2.lua @@ -0,0 +1,194 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_2_inc.lua" + +#define HUD_RUSSIAN_R2 20 + +#define VARIO_X 310 +#define VARIO_Y HUD_Y +#define VARIO_H HUD_HEIGHT/2 +#define VARIO_W 10 + +#define LEFTWIDTH 38 +#define RIGHTWIDTH 38 + +#define HUD_WIDTH 158 +#define HUD_HEIGHT 90 +#define HUD_X (LCD_W-HUD_WIDTH)/2 +#define HUD_Y 24 +#define HUD_Y_MID 69 + +----------------------- +-- COMPASS RIBBON +----------------------- +#define YAW_X (LCD_W-140)/2 +#define YAW_Y 120 +#define YAW_WIDTH 140 + +#define YAWICON_Y 3 +#define YAWTEXT_Y 16 +#define YAW_STEPWIDTH 15 +#define YAW_SYMBOLS 16 +#define YAW_X_MIN (LCD_W-YAW_WIDTH)/2 +#define YAW_X_MAX (LCD_W+YAW_WIDTH)/2 + +#define R2 25 + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() +#ifdef HUDTIMER +local hudDrawTime = 0 +local hudDrawCounter = 0 +#endif + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) +#ifdef HUDTIMER + local hudStart = getTime() +#endif + + local r = -telemetry.roll + local cx,cy,dx,dy + local yPos = TOPBAR_Y + TOPBAR_HEIGHT + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of R2 + if ( telemetry.roll == 0) then + dx=0 + dy=telemetry.pitch + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch + end + local rollX = math.floor(HUD_X + HUD_WIDTH/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 140x110 + local minY = HUD_Y + local maxY = HUD_Y + HUD_HEIGHT + + local minX = HUD_X + 1 + local maxX = HUD_X + HUD_WIDTH + + local ox = HUD_X + HUD_WIDTH/2 + dx + 5 + local oy = HUD_Y_MID + dy + local yy = 0 + + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(179, 204, 255)) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7b, 0x9d, 0xff)) -- default blue + lcd.drawFilledRectangle(minX,minY,HUD_WIDTH,maxY-minY,CUSTOM_COLOR) + -- angle of the line passing on point(ox,oy) + local angle = math.tan(math.rad(-telemetry.roll)) + -- for each pixel of the hud base/top draw vertical black + -- lines from hud border to horizon line + -- horizon line moves with pitch/roll + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(102, 51, 0)) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x63, 0x30, 0x00)) --623000 old brown + if math.abs(telemetry.roll) < 90 then + if oy > minY and oy < maxY then + lcd.drawFilledRectangle(minX,oy,HUD_WIDTH,maxY-oy + 1,CUSTOM_COLOR) + elseif oy <= minY then + lcd.drawFilledRectangle(minX,minY,HUD_WIDTH,maxY-minY,CUSTOM_COLOR) + end + else + --inverted + if oy > minY and oy < maxY then + lcd.drawFilledRectangle(minX,minY,HUD_WIDTH,oy-minY + 1,CUSTOM_COLOR) + elseif oy >= maxY then + lcd.drawFilledRectangle(minX,minY,HUD_WIDTH,maxY-minY,CUSTOM_COLOR) + end + end + -- +-- parallel lines above and below horizon + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) + -- + local hx = math.cos(math.rad(90 - r)) * -(telemetry.pitch%45) + local hy = math.sin(math.rad(90 - r)) * (telemetry.pitch%45) + + --drawLineWithClipping(rollX - hx, HUD_Y_MID + hy,r,50,SOLID,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR) + + for line=0,4 + do + -- + local deltax = math.cos(math.rad(90 - r)) * HUD_RUSSIAN_R2 * line + local deltay = math.sin(math.rad(90 - r)) * HUD_RUSSIAN_R2 * line + -- + drawLib.drawLineWithClipping(rollX - deltax + hx, HUD_Y_MID + deltay + hy,r,50,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + deltax + hx, HUD_Y_MID - deltay + hy,r,50,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR,radio,rev) + end + + local xx = math.cos(math.rad(r)) * 70 * 0.5 + local yy = math.sin(math.rad(r)) * 70 * 0.5 + -- + local x0 = rollX - xx + local y0 = HUD_Y_MID - yy + -- + local x1 = rollX + xx + local y1 = HUD_Y_MID + yy + -- + drawLib.drawLineWithClipping(x0,y0,r + 90,70,SOLID,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(x1,y1,r + 90,70,SOLID,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR,radio,rev) + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_160x90_rus"),(LCD_W-HUD_WIDTH)/2,HUD_Y) --160x90 + ------------------------------------- + -- vario bitmap + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = varioSpeed/varioMax*35 + if telemetry.vSpeed > 0 then + varioY = VARIO_Y + 35 - varioH + else + varioY = VARIO_Y + 55 + end + --00ae10 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(50, 50, 50)) --dark grey + lcd.drawFilledRectangle(VARIO_X, varioY, VARIO_W, varioH, CUSTOM_COLOR, 0) + ------------------------------------- + -- left and right indicators on HUD + ------------------------------------- + -- DATA + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,MINMAX_ALT) * UNIT_ALT_SCALE + if math.abs(alt) > 999 then + lcd.setColor(CUSTOM_COLOR,COLOR_GREEN) + lcd.drawNumber(HUD_X+HUD_WIDTH - 42,HUD_Y_MID-10,alt,CUSTOM_COLOR) + elseif math.abs(alt) >= 10 then + lcd.setColor(CUSTOM_COLOR,COLOR_GREEN) + lcd.drawNumber(HUD_X+HUD_WIDTH - 42,HUD_Y_MID-14,alt,MIDSIZE+CUSTOM_COLOR) + else + lcd.setColor(CUSTOM_COLOR,COLOR_GREEN) + lcd.drawNumber(HUD_X+HUD_WIDTH - 42,HUD_Y_MID-14,alt*10,MIDSIZE+PREC1+CUSTOM_COLOR) + end + lcd.setColor(CUSTOM_COLOR,COLOR_GREEN) + -- telemetry.hSpeed is in dm/s + local hSpeed = utils.getMaxValue(telemetry.hSpeed,MAX_HSPEED) * 0.1 * UNIT_HSPEED_SCALE + if (math.abs(hSpeed) >= 10) then + lcd.drawNumber(HUD_X+44,HUD_Y_MID-14,hSpeed,MIDSIZE+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(HUD_X+44,HUD_Y_MID-14,hSpeed*10,MIDSIZE+RIGHT+CUSTOM_COLOR+PREC1) + end +#ifdef HUDTIMER + hudDrawTime = hudDrawTime + (getTime() - hudStart) + hudDrawCounter = hudDrawCounter + 1 +#endif + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow(HUD_X+50, HUD_Y_MID-9,true,false,utils) + drawLib.drawVArrow(HUD_X+HUD_WIDTH-57, HUD_Y_MID-9,true,false,utils) + end + -- compass ribbon + drawLib.drawCompassRibbon(YAW_Y,myWidget,conf,telemetry,status,battery,utils,YAW_WIDTH,YAW_X_MIN,YAW_X_MAX,YAW_STEPWIDTH) +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} diff --git a/HORUS/SOURCES/PP/lib/hud_small_2.lua b/HORUS/SOURCES/PP/lib/hud_small_2.lua new file mode 100644 index 00000000..482eecb3 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/hud_small_2.lua @@ -0,0 +1,140 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_2_inc.lua" + +#define VARIO_X 275 +#define VARIO_Y 20 + +#define LEFTWIDTH 38 +#define RIGHTWIDTH 38 + +#define HUD_Y 30 +#define HUD_HEIGHT 70 +#define HUD_WIDTH 92 +#define HUD_X (LCD_W-HUD_WIDTH)/2 +#define HUD_Y_MID HUD_Y+HUD_HEIGHT/2 + +----------------------- +-- COMPASS RIBBON +----------------------- +#define YAW_X (LCD_W-140)/2 +#define YAW_Y 115 +#define YAW_WIDTH 140 + +#define YAWICON_Y 3 +#define YAWTEXT_Y 16 +#define YAW_STEPWIDTH 15 +#define YAW_SYMBOLS 16 +#define YAW_X_MIN (LCD_W-YAW_WIDTH)/2 +#define YAW_X_MAX (LCD_W+YAW_WIDTH)/2 + +#define R2 11 + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() + +#ifdef HUDTIMER +local hudDrawTime = 0 +local hudDrawCounter = 0 +#endif + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils)--getMaxValue,getBitmap,drawBlinkBitmap) +#ifdef HUDTIMER + local hudStart = getTime() +#endif + + local r = -telemetry.roll + local cx,cy,dx,dy,ccx,ccy,cccx,cccy + local yPos = TOPBAR_Y + TOPBAR_HEIGHT + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of R2 + if ( telemetry.roll == 0) then + dx=0 + dy=telemetry.pitch + cx=0 + cy=R2 + ccx=0 + ccy=2*R2 + cccx=0 + cccy=3*R2 + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch + -- 1st line offsets + cx = math.cos(math.rad(90 - r)) * R2 + cy = math.sin(math.rad(90 - r)) * R2 + -- 2nd line offsets + ccx = math.cos(math.rad(90 - r)) * 2 * R2 + ccy = math.sin(math.rad(90 - r)) * 2 * R2 + -- 3rd line offsets + cccx = math.cos(math.rad(90 - r)) * 3 * R2 + cccy = math.sin(math.rad(90 - r)) * 3 * R2 + end + local rollX = math.floor(HUD_X + HUD_WIDTH/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 90x70 + local minY = HUD_Y + local maxY = HUD_Y+HUD_HEIGHT + -- + local minX = HUD_X + local maxX = HUD_X + HUD_WIDTH + -- + local ox = HUD_X + HUD_WIDTH/2 + dx + -- + local oy = HUD_Y_MID + dy + local yy = 0 + + -- HUD + #include "includes/hud_algo_inc.lua" + + -- parallel lines above and below horizon + local linesMaxY = maxY-1 + local linesMinY = minY+1 + lcd.setColor(CUSTOM_COLOR,COLOR_WHITE) + -- +/- 90 deg + for dist=1,8 + do + drawLib.drawLineWithClipping(rollX + dx - dist*cx,dy + HUD_Y_MID + dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,HUD_X+2,HUD_X+HUD_WIDTH-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + dx + dist*cx,dy + HUD_Y_MID - dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,HUD_X+2,HUD_X+HUD_WIDTH-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + end + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_90x70a"),(LCD_W-106)/2,HUD_Y-10) --106x90 + ------------------------------------- + -- vario bitmap + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = 0 + if telemetry.vSpeed > 0 then + varioY = VARIO_Y+46 - varioSpeed/varioMax*40 + else + varioY = VARIO_Y+45 + end + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) + lcd.drawFilledRectangle(VARIO_X+26, varioY, 7, varioSpeed/varioMax*39, CUSTOM_COLOR, 0) + lcd.drawBitmap(utils.getBitmap("variogauge_90"),VARIO_X,VARIO_Y) + + if telemetry.vSpeed > 0 then + lcd.drawBitmap(utils.getBitmap("varioline"),VARIO_X+21,varioY-1) + else + lcd.drawBitmap(utils.getBitmap("varioline"),VARIO_X+21,VARIO_Y+44 + varioSpeed/varioMax*39) + end +#ifdef HUDTIMER + hudDrawTime = hudDrawTime + (getTime() - hudStart) + hudDrawCounter = hudDrawCounter + 1 +#endif + -- compass ribbon + drawLib.drawCompassRibbon(YAW_Y,myWidget,conf,telemetry,status,battery,utils,YAW_WIDTH,YAW_X_MIN,YAW_X_MAX,YAW_STEPWIDTH) +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/layout_1.lua b/HORUS/SOURCES/PP/lib/layout_1.lua new file mode 100644 index 00000000..eed62698 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/layout_1.lua @@ -0,0 +1,147 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_1_inc.lua" + +#define SENSOR1_X 80 +#define SENSOR1_Y 203 +#define SENSOR1_XLABEL 80 +#define SENSOR1_YLABEL 193 + +#define SENSOR2_X 160 +#define SENSOR2_Y 203 +#define SENSOR2_XLABEL 160 +#define SENSOR2_YLABEL 193 + +#define SENSOR3_X 240 +#define SENSOR3_Y 203 +#define SENSOR3_XLABEL 240 +#define SENSOR3_YLABEL 193 + +#define SENSOR4_X 320 +#define SENSOR4_Y 203 +#define SENSOR4_XLABEL 320 +#define SENSOR4_YLABEL 193 + +#define SENSOR5_X 400 +#define SENSOR5_Y 203 +#define SENSOR5_XLABEL 400 +#define SENSOR5_YLABEL 193 + +#define SENSOR6_X 480 +#define SENSOR6_Y 203 +#define SENSOR6_XLABEL 480 +#define SENSOR6_YLABEL 193 + +-------------------------- +-- CUSTOM SENSORS SUPPORT +-------------------------- +#define SENSOR_LABEL 1 +#define SENSOR_NAME 2 +#define SENSOR_PREC 3 +#define SENSOR_UNIT 4 +#define SENSOR_MULT 5 +#define SENSOR_MAX 6 +#define SENSOR_FONT 7 +#define SENSOR_WARN 8 +#define SENSOR_CRIT 9 + +local customSensorXY = { + { SENSOR1_XLABEL, SENSOR1_YLABEL, SENSOR1_X, SENSOR1_Y}, + { SENSOR2_XLABEL, SENSOR2_YLABEL, SENSOR2_X, SENSOR2_Y}, + { SENSOR3_XLABEL, SENSOR3_YLABEL, SENSOR3_X, SENSOR3_Y}, + { SENSOR4_XLABEL, SENSOR4_YLABEL, SENSOR4_X, SENSOR4_Y}, + { SENSOR5_XLABEL, SENSOR5_YLABEL, SENSOR5_X, SENSOR5_Y}, + { SENSOR6_XLABEL, SENSOR6_YLABEL, SENSOR6_X, SENSOR6_Y}, +} + +local function drawCustomSensors(x,customSensors,utils,status) + lcd.setColor(CUSTOM_COLOR,COLOR_SENSORS) + lcd.drawFilledRectangle(0,194,LCD_W,35,CUSTOM_COLOR) + + local label,data,prec,mult,flags,sensorConfig + for i=1,6 + do + if customSensors.sensors[i] ~= nil then + sensorConfig = customSensors.sensors[i] + + if sensorConfig[SENSOR_UNIT] == "" then + label = string.format("%s",sensorConfig[SENSOR_LABEL]) + else + label = string.format("%s(%s)",sensorConfig[SENSOR_LABEL],sensorConfig[SENSOR_UNIT]) + end + -- draw sensor label + lcd.setColor(CUSTOM_COLOR,COLOR_SENSORS_LABEL) + lcd.drawText(x+customSensorXY[i][1], customSensorXY[i][2],label, SMLSIZE+RIGHT+CUSTOM_COLOR) + + mult = sensorConfig[SENSOR_PREC] == 0 and 1 or ( sensorConfig[SENSOR_PREC] == 1 and 10 or 100 ) + prec = mult == 1 and 0 or (mult == 10 and 32 or 48) + + local sensorName = sensorConfig[SENSOR_NAME]..(status.showMinMaxValues == true and sensorConfig[SENSOR_MAX] or "") + local sensorValue = getValue(sensorName) + local value = (sensorValue+(mult == 100 and 0.005 or 0))*mult*sensorConfig[SENSOR_MULT] + + -- default font size + flags = sensorConfig[SENSOR_FONT] == 1 and 0 or MIDSIZE + + -- for sensor 3,4,5,6 reduce font if necessary + if math.abs(value)*mult > 99999 then + flags = 0 + end + + local color = COLOR_SENSORS_TEXT + local sign = sensorConfig[SENSOR_MAX] == "+" and 1 or -1 + -- max tracking, high values are critical + if math.abs(value) ~= 0 and status.showMinMaxValues == false then + color = ( sensorValue*sign > sensorConfig[SENSOR_CRIT]*sign and lcd.RGB(255,70,0) or (sensorValue*sign > sensorConfig[SENSOR_WARN]*sign and COLOR_WARN or COLOR_SENSORS_TEXT)) + end + + lcd.setColor(CUSTOM_COLOR,color) + + local voffset = flags==0 and 6 or 0 + -- if a lookup table exists use it! + if customSensors.lookups[i] ~= nil and customSensors.lookups[i][value] ~= nil then + lcd.drawText(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, customSensors.lookups[i][value] or value, flags+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, value, flags+RIGHT+prec+CUSTOM_COLOR) + end + end + end +end + +local function draw(myWidget,drawLib,conf,telemetry,status,battery,alarms,frame,utils,customSensors,gpsStatuses,leftPanel,centerPanel,rightPanel) + lcd.setColor(CUSTOM_COLOR,COLOR_LINES) + centerPanel.drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) + --lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + drawLib.drawRArrow(HOMEDIR_X,HOMEDIR_Y,HOMEDIR_R,math.floor(telemetry.homeAngle - telemetry.yaw),CUSTOM_COLOR)--HomeDirection(telemetry) + -- with dual battery default is to show aggregate view + if status.batt2sources.fc or status.batt2sources.vs then + if status.showDualBattery == false then + -- dual battery: aggregate view + rightPanel.drawPane(380,drawLib,conf,telemetry,status,alarms,battery,BATT_IDALL,gpsStatuses,utils) + -- left pane info + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,BATT_IDALL,gpsStatuses,utils) + else + -- dual battery:battery 1 right pane + rightPanel.drawPane(380,drawLib,conf,telemetry,status,alarms,battery,BATT_ID1,gpsStatuses,utils) + -- dual battery:battery 2 left pane + rightPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,BATT_ID2,gpsStatuses,utils) + end + else + -- battery 1 right pane in single battery mode + rightPanel.drawPane(380,drawLib,conf,telemetry,status,alarms,battery,BATT_ID1,gpsStatuses,utils) + -- left pane info in single battery mode + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,BATT_IDALL,gpsStatuses,utils) + end + utils.drawTopBar() + local msgRows = 4 + if customSensors ~= nil then + --utils.drawBottomBar() + msgRows = 1 + -- draw custom sensors + drawCustomSensors(0,customSensors,utils,status) + end + drawLib.drawStatusBar(msgRows,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + drawLib.drawFailsafe(telemetry,utils) + drawLib.drawArmStatus(status,telemetry,utils) +end + +return {draw=draw} diff --git a/HORUS/SOURCES/PP/lib/layout_2.lua b/HORUS/SOURCES/PP/lib/layout_2.lua new file mode 100644 index 00000000..a7191767 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/layout_2.lua @@ -0,0 +1,68 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_2_inc.lua" + +local function drawExtendedStatusBar(drawLib,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + -- LEFT label + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALT_XLABEL,ALT_YLABEL,"Alt("..UNIT_ALT_LABEL..")",SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(VSPEED_XLABEL,VSPEED_YLABEL,"VSI("..UNIT_VSPEED_LABEL..")",SMLSIZE+CUSTOM_COLOR+RIGHT) + + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,MINMAX_ALT) * UNIT_ALT_SCALE + if math.abs(alt) > 999 then + lcd.drawNumber(ALT_X,ALT_Y,alt,ALT_FLAGS+CUSTOM_COLOR) + elseif math.abs(alt) >= 10 then + lcd.drawNumber(ALT_X,ALT_Y,alt,ALT_FLAGS+CUSTOM_COLOR) + else + lcd.drawNumber(ALT_X,ALT_Y,alt*10,ALT_FLAGS+PREC1+CUSTOM_COLOR) + end + -- vertical speed + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local vSpeed = utils.getMaxValue(telemetry.vSpeed,MAX_VSPEED) * 0.1 * UNIT_VSPEED_SCALE + if (math.abs(telemetry.vSpeed) >= 10) then + lcd.drawNumber(VSPEED_X,VSPEED_Y, vSpeed ,VSPEED_FLAGS+CUSTOM_COLOR) + else + lcd.drawNumber(VSPEED_X,VSPEED_Y,vSpeed*10,VSPEED_FLAGS+PREC1+CUSTOM_COLOR) + end + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow(3, ALT_Y + 3,true,false,utils) + drawLib.drawVArrow(VSPEED_X-70, VSPEED_Y + 3,true,false,utils) + end + +end + +local function draw(myWidget,drawLib,conf,telemetry,status,battery,alarms,frame,utils,customSensors,gpsStatuses,leftPanel,centerPanel,rightPanel) + if leftPanel ~= nil and centerPanel ~= nil and rightPanel ~= nil then + lcd.setColor(CUSTOM_COLOR,COLOR_LINES) + drawLib.drawRArrow(HOMEDIR_X,HOMEDIR_Y,HOMEDIR_R,math.floor(telemetry.homeAngle - telemetry.yaw),CUSTOM_COLOR)--HomeDirection(telemetry) + centerPanel.drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils,customSensors) + -- with dual battery default is to show aggregate view + if status.batt2sources.fc or status.batt2sources.vs then + if status.showDualBattery == false then + -- dual battery: aggregate view + rightPanel.drawPane(285,drawLib,conf,telemetry,status,alarms,battery,BATT_IDALL,gpsStatuses,utils,customSensors) + -- left panel + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,BATT_IDALL,gpsStatuses,utils,customSensors) + else + -- dual battery:battery 1 right pane + rightPanel.drawPane(285,drawLib,conf,telemetry,status,alarms,battery,BATT_ID1,gpsStatuses,utils,customSensors) + -- dual battery:battery 2 left pane + rightPanel.drawPane(-37,drawLib,conf,telemetry,status,alarms,battery,BATT_ID2,gpsStatuses,utils,customSensors) + end + else + -- battery 1 right pane in single battery mode + rightPanel.drawPane(285,drawLib,conf,telemetry,status,alarms,battery,BATT_ID1,gpsStatuses,utils,customSensors) + -- left panel + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,BATT_IDALL,gpsStatuses,utils,customSensors) + end + end + drawLib.drawStatusBar(3,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + drawExtendedStatusBar(drawLib,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + utils.drawTopBar() + drawLib.drawFailsafe(telemetry,utils) + drawLib.drawArmStatus(status,telemetry,utils) +end + +return {draw=draw} diff --git a/HORUS/SOURCES/PP/lib/left_1.lua b/HORUS/SOURCES/PP/lib/left_1.lua new file mode 100644 index 00000000..dfc1580f --- /dev/null +++ b/HORUS/SOURCES/PP/lib/left_1.lua @@ -0,0 +1,87 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_1_inc.lua" + +#define ALTASL_X 90 +#define ALTASL_Y 37 +#define ALTASL_XLABEL 90 +#define ALTASL_YLABEL 25 + +#define HOMEDIST_X 90 +#define HOMEDIST_Y 82 +#define HOMEDIST_XLABEL 90 +#define HOMEDIST_YLABEL 70 +#define HOMEDIST_ARROW_WIDTH 8 + +#define TOTDIST_X 90 +#define TOTDIST_Y 129 +#define TOTDIST_XLABEL 90 +#define TOTDIST_YLABEL 117 + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,MAX_RANGE) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "Range("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, string.format("%.1f",rng*0.01*UNIT_ALT_SCALE), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,MAX_GPSALT) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "AltAsl("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + local stralt = string.format("%d",alt*UNIT_ALT_SCALE) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + drawLib.drawHomeIcon(HOMEDIST_XLABEL - 70, HOMEDIST_YLABEL,utils) + lcd.drawText(HOMEDIST_XLABEL, HOMEDIST_YLABEL, "Dist("..UNIT_DIST_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(TOTDIST_XLABEL, TOTDIST_YLABEL, "Travel("..UNIT_DIST_LONG_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + -- VALUES + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- home distance + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,MAX_DIST) + if status.showMinMaxValues == true then + flags = 0 + end + local strdist = string.format("%d",dist*UNIT_DIST_SCALE) + --lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) --yellow + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(HOMEDIST_X, HOMEDIST_Y, strdist, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + -- total distance + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(TOTDIST_X, TOTDIST_Y, telemetry.totalDist*UNIT_DIST_LONG_SCALE*100, PREC2+MIDSIZE+RIGHT+CUSTOM_COLOR) + + if status.showMinMaxValues == true then + drawLib.drawVArrow(4, ALTASL_Y + 4,true,false,utils) + drawLib.drawVArrow(4, HOMEDIST_Y + 4 ,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/left_2.lua b/HORUS/SOURCES/PP/lib/left_2.lua new file mode 100644 index 00000000..592713ef --- /dev/null +++ b/HORUS/SOURCES/PP/lib/left_2.lua @@ -0,0 +1,110 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_2_inc.lua" + +#define ALTASL_X 73 +#define ALTASL_Y 33+8 +#define ALTASL_XLABEL 73 +#define ALTASL_YLABEL 21+8 + +#define HOMEDIST_X 155 +#define HOMEDIST_Y 41 +#define HOMEDIST_XLABEL 155 +#define HOMEDIST_YLABEL 29 +#define HOMEDIST_FLAGS MIDSIZE +#define HOMEDIST_ARROW_WIDTH 8 + +#define TOTDIST_X 155 +#define TOTDIST_Y 107 +#define TOTDIST_XLABEL 155 +#define TOTDIST_YLABEL 95 +#define TOTDIST_FLAGS MIDSIZE + +#define HSPEED_X 73 +#define HSPEED_Y 107 +#define HSPEED_XLABEL 73 +#define HSPEED_YLABEL 95 +#define HSPEED_XDIM 48 +#define HSPEED_YDIM 33 +#define HSPEED_FLAGS MIDSIZE +#define HSPEED_ARROW_WIDTH 10 + +#define EFF_X 155 +#define EFF_Y 150 +#define EFF_YW 165 +#define EFF_FLAGS SMLSIZE +#define EFF_FLAGSW MIDSIZE + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,MAX_RANGE) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "Rng("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, string.format("%.1f",rng*0.01*UNIT_ALT_SCALE), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,MAX_GPSALT) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "AltAsl("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + local stralt = string.format("%d",alt*UNIT_ALT_SCALE) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + drawLib.drawHomeIcon(HOMEDIST_XLABEL - 68, HOMEDIST_YLABEL,utils) + lcd.drawText(HOMEDIST_XLABEL, HOMEDIST_YLABEL, "Dist("..UNIT_DIST_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(HSPEED_XLABEL, HSPEED_YLABEL, "Spd("..UNIT_HSPEED_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(TOTDIST_XLABEL, TOTDIST_YLABEL, "Travel("..UNIT_DIST_LONG_LABEL..")", EFF_FLAGS+RIGHT+CUSTOM_COLOR) + -- VALUES + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- home distance + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,MAX_DIST) + if status.showMinMaxValues == true then + flags = 0 + end + local strdist = string.format("%d",dist*UNIT_DIST_SCALE) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + --lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) --yellow + lcd.drawText(HOMEDIST_X, HOMEDIST_Y, strdist, HOMEDIST_FLAGS+flags+RIGHT+CUSTOM_COLOR) + -- total distance + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(TOTDIST_X, TOTDIST_Y, telemetry.totalDist*UNIT_DIST_LONG_SCALE*100, PREC2+TOTDIST_FLAGS+RIGHT+CUSTOM_COLOR) + -- hspeed + local speed = utils.getMaxValue(telemetry.hSpeed,MAX_HSPEED) + + lcd.drawNumber(HSPEED_X,HSPEED_Y,speed * UNIT_HSPEED_SCALE,HSPEED_FLAGS+RIGHT+PREC1+CUSTOM_COLOR) + + if status.showMinMaxValues == true then + drawLib.drawVArrow(4, ALTASL_Y + 4,true,false,utils) + drawLib.drawVArrow(HOMEDIST_X-70, HOMEDIST_Y + 4 ,true,false,utils) + drawLib.drawVArrow(4,HSPEED_Y+4,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/left_m2f_1.lua b/HORUS/SOURCES/PP/lib/left_m2f_1.lua new file mode 100644 index 00000000..e9811437 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/left_m2f_1.lua @@ -0,0 +1,158 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_1_inc.lua" + +#define ALTASL_X 88 +#define ALTASL_Y 33 +#define ALTASL_XLABEL 25 +#define ALTASL_YLABEL 21 + +#define HSPEED_X 88 +#define HSPEED_Y 74 +#define HSPEED_XLABEL 88 +#define HSPEED_YLABEL 63 +#define HSPEED_FLAGS MIDSIZE+RIGHT + +#define HOMEDIST_X 88 +#define HOMEDIST_Y 113 +#define HOMEDIST_XLABEL 88 +#define HOMEDIST_YLABEL 102 +#define HOMEDIST_FLAGS MIDSIZE +#define HOMEDIST_ARROW_WIDTH 8 + +#define TOTDIST_X 69 +#define TOTDIST_Y 134 +#define TOTDIST_XLABEL 88 +#define TOTDIST_YLABEL 138 +#define TOTDIST_FLAGS 0 + +#define WPN_X 68 +#define WPN_Y 164 +#define WPN_XLABEL 88 +#define WPN_YLABEL 154 +#define WPN_FLAGS MIDSIZE + +#define WPB_X 80 +#define WPB_Y 180 +#define WPB_R 9 + +#define WPD_X 165 +#define WPD_Y 164 +#define WPD_XLABEL 165 +#define WPD_YLABEL 154 +#define WPD_FLAGS MIDSIZE+RIGHT + +#define THROTTLE_X 315 +#define THROTTLE_Y 164 +#define THROTTLE_XLABEL 315 +#define THROTTLE_YLABEL 154 + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils)--,getMaxValue,getBitmap,drawBlinkBitmap,lcdBacklightOn) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0,33,56)) + --lcd.drawFilledRectangle(x + 3,21,93,203,CUSTOM_COLOR) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,MAX_RANGE) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "Range("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, string.format("%.1f",rng*0.01*UNIT_ALT_SCALE), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,MAX_GPSALT) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "AltAsl("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR) + local stralt = string.format("%d",alt*UNIT_ALT_SCALE) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(HOMEDIST_X, HOMEDIST_YLABEL, "Dist("..UNIT_DIST_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + --lcd.drawText(TOTDIST_XLABEL, TOTDIST_YLABEL, "Dist("..UNIT_DIST_LONG_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(WPN_XLABEL, WPN_YLABEL, "WPN", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(WPD_XLABEL, WPD_YLABEL, "WPD("..UNIT_DIST_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + -- drawn on HUD bottom left + lcd.drawText(HSPEED_XLABEL, HSPEED_YLABEL, "ASpd("..UNIT_HSPEED_LABEL..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(THROTTLE_XLABEL, THROTTLE_YLABEL, "Thr(%)", SMLSIZE+CUSTOM_COLOR+RIGHT) + -- VALUES + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- home distance + drawLib.drawHomeIcon(2, HOMEDIST_YLABEL + 18,utils) + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,MAX_DIST) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + local strdist = string.format("%d",dist*UNIT_DIST_SCALE) + lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + lcd.drawText(HOMEDIST_X, HOMEDIST_Y, strdist, HOMEDIST_FLAGS+flags+RIGHT+CUSTOM_COLOR) + -- total distance + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(TOTDIST_XLABEL, TOTDIST_YLABEL, UNIT_DIST_LONG_LABEL, SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawNumber(TOTDIST_X, TOTDIST_Y, telemetry.totalDist*UNIT_DIST_LONG_SCALE*100, TOTDIST_FLAGS+RIGHT+CUSTOM_COLOR+PREC2) + -- wp number + lcd.drawNumber(WPN_X, WPN_Y, telemetry.wpNumber,WPN_FLAGS+RIGHT+CUSTOM_COLOR) + -- wp distance + lcd.drawNumber(WPD_X, WPD_Y, telemetry.wpDistance * UNIT_DIST_SCALE,WPD_FLAGS+CUSTOM_COLOR) + -- airspeed + lcd.drawNumber(HSPEED_X,HSPEED_Y,telemetry.airspeed * UNIT_HSPEED_SCALE,HSPEED_FLAGS+PREC1+CUSTOM_COLOR) + -- throttle % + lcd.drawNumber(THROTTLE_X,THROTTLE_Y,telemetry.throttle,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- LINES + lcd.setColor(CUSTOM_COLOR,COLOR_LINES) --yellow + -- wp bearing + drawLib.drawRArrow(WPB_X,WPB_Y,WPB_R,telemetry.wpBearing*45,CUSTOM_COLOR) + -- + if status.showMinMaxValues == true then + drawLib.drawVArrow(3, ALTASL_Y+4,true,false,utils) + drawLib.drawVArrow(3, HOMEDIST_Y+4 ,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) + -- RC CHANNELS + --[[ + if conf.enableRCChannels == true then + for i=1,#telemetry.rcchannels do + setTelemetryValue(Thr_ID, Thr_SUBID, Thr_INSTANCE + i, telemetry.rcchannels[i], 13 , Thr_PRECISION , "RC"..i) + end + end + --]] + + -- VFR + setTelemetryValue(ASpd_ID, ASpd_SUBID, ASpd_INSTANCE, telemetry.airspeed*0.1, 4 , ASpd_PRECISION , ASpd_NAME) + setTelemetryValue(BAlt_ID, BAlt_SUBID, BAlt_INSTANCE, telemetry.baroAlt*10, 9 , BAlt_PRECISION , BAlt_NAME) + setTelemetryValue(Thr_ID, Thr_SUBID, Thr_INSTANCE, telemetry.throttle, 13 , Thr_PRECISION , Thr_NAME) + + -- WP + setTelemetryValue(WPN_ID, WPN_SUBID, WPN_INSTANCE, telemetry.wpNumber, 0 , WPN_PRECISION , WPN_NAME) + setTelemetryValue(WPD_ID, WPD_SUBID, WPD_INSTANCE, telemetry.wpDistance, 9 , WPD_PRECISION , WPD_NAME) + + -- crosstrack error and wp bearing not exposed as OpenTX variables by default + --[[ + setTelemetryValue(WPX_ID, WPX_SUBID, WPX_INSTANCE, telemetry.wpXTError, 9 , WPX_PRECISION , WPX_NAME) + setTelemetryValue(WPB_ID, WPB_SUBID, WPB_INSTANCE, telemetry.wpBearing, 20 , WPB_PRECISION , WPB_NAME) + --]] +end + +return {drawPane=drawPane,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/left_m2f_2.lua b/HORUS/SOURCES/PP/lib/left_m2f_2.lua new file mode 100644 index 00000000..20f1ab4d --- /dev/null +++ b/HORUS/SOURCES/PP/lib/left_m2f_2.lua @@ -0,0 +1,157 @@ +#include "includes/yaapu_inc.lua" +#include "includes/layout_2_inc.lua" + +#define ALTASL_X 68 +#define ALTASL_Y 31 +#define ALTASL_XLABEL 8 +#define ALTASL_YLABEL 20 + +#define HOMEDIST_X 153 +#define HOMEDIST_Y 31 +#define HOMEDIST_XLABEL 69 +#define HOMEDIST_YLABEL 20 +#define HOMEDIST_FLAGS MIDSIZE +#define HOMEDIST_ARROW_WIDTH 8 + +#define TOTDIST_X 152 +#define TOTDIST_Y 54 +#define TOTDIST_XLABEL 69 +#define TOTDIST_YLABEL 54 +#define TOTDIST_FLAGS SMLSIZE + +#define THROTTLE_X 153 +#define THROTTLE_Y 122 +#define THROTTLE_YW 134 +#define THROTTLE_FLAGS SMLSIZE +#define THROTTLE_FLAGSW MIDSIZE + +#define WPN_X 57 +#define WPN_Y 87 +#define WPN_XLABEL 69 +#define WPN_YLABEL 76 +#define WPN_FLAGS MIDSIZE + +#define WPB_X 67 +#define WPB_Y 100 +#define WPB_R 10 + +#define WPD_X 153 +#define WPD_Y 87 +#define WPD_XLABEL 153 +#define WPD_YLABEL 76 +#define WPD_FLAGS MIDSIZE + +#define HSPEED_X 68 +#define HSPEED_Y 134 +#define HSPEED_XLABEL 69 +#define HSPEED_YLABEL 122 +#define HSPEED_XDIM 48 +#define HSPEED_YDIM 33 +#define HSPEED_FLAGS MIDSIZE +#define HSPEED_ARROW_WIDTH 10 + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils)--,getMaxValue,getBitmap,drawBlinkBitmap,lcdBacklightOn) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,MAX_RANGE) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "Range("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, string.format("%.1f",rng*0.01*UNIT_ALT_SCALE), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,MAX_GPSALT) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "AltAsl("..UNIT_ALT_LABEL..")", SMLSIZE+CUSTOM_COLOR) + local stralt = string.format("%d",alt*UNIT_ALT_SCALE) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(ALTASL_X, ALTASL_Y, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(HOMEDIST_X, HOMEDIST_YLABEL, "Dist("..UNIT_DIST_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(HSPEED_XLABEL, HSPEED_YLABEL, "AS("..UNIT_HSPEED_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(WPN_XLABEL, WPN_YLABEL, "WPN", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(WPD_XLABEL, WPD_YLABEL, "WPD("..UNIT_DIST_LABEL..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(THROTTLE_X, THROTTLE_Y, "THR(%)", THROTTLE_FLAGS+RIGHT+CUSTOM_COLOR) + -- VALUES + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- home distance + drawLib.drawHomeIcon(HOMEDIST_XLABEL + 15, HOMEDIST_YLABEL + 2,utils) + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,MAX_DIST) + if status.showMinMaxValues == true then + flags = 0 + end + local strdist = string.format("%d",dist*UNIT_DIST_SCALE) + --lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + lcd.drawText(HOMEDIST_X, HOMEDIST_Y, strdist, HOMEDIST_FLAGS+flags+RIGHT+CUSTOM_COLOR) + -- total distance + strdist = string.format("%.02f%s", telemetry.totalDist*UNIT_DIST_LONG_SCALE,UNIT_DIST_LONG_LABEL) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(TOTDIST_X, TOTDIST_Y, strdist, TOTDIST_FLAGS+RIGHT+CUSTOM_COLOR) + -- airspeed + lcd.drawNumber(HSPEED_X,HSPEED_Y,telemetry.airspeed * UNIT_HSPEED_SCALE,HSPEED_FLAGS+RIGHT+PREC1+CUSTOM_COLOR) + -- wp number + lcd.drawNumber(WPN_X, WPN_Y, telemetry.wpNumber,WPN_FLAGS+RIGHT+CUSTOM_COLOR) + -- wp distance + lcd.drawNumber(WPD_X, WPD_Y, telemetry.wpDistance * UNIT_DIST_SCALE,WPD_FLAGS+RIGHT+CUSTOM_COLOR) + -- throttle % + lcd.drawNumber(THROTTLE_X,THROTTLE_YW,telemetry.throttle,THROTTLE_FLAGSW+RIGHT+CUSTOM_COLOR) + -- LINES + lcd.setColor(CUSTOM_COLOR,COLOR_LINES) --yellow + -- wp bearing + drawLib.drawRArrow(WPB_X,WPB_Y,WPB_R,telemetry.wpBearing*45,CUSTOM_COLOR) + -- + if status.showMinMaxValues == true then + drawLib.drawVArrow(ALTASL_X-70, ALTASL_Y+4,true,false,utils) + drawLib.drawVArrow(HOMEDIST_X-78, HOMEDIST_Y+4 ,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) + -- RC CHANNELS + --[[ + if conf.enableRCChannels == true then + for i=1,#telemetry.rcchannels do + setTelemetryValue(Thr_ID, Thr_SUBID, Thr_INSTANCE + i, telemetry.rcchannels[i], 13 , Thr_PRECISION , "RC"..i) + end + end + --]] + + -- VFR + setTelemetryValue(ASpd_ID, ASpd_SUBID, ASpd_INSTANCE, telemetry.airspeed*0.1, 4 , ASpd_PRECISION , ASpd_NAME) + setTelemetryValue(BAlt_ID, BAlt_SUBID, BAlt_INSTANCE, telemetry.baroAlt*10, 9 , BAlt_PRECISION , BAlt_NAME) + setTelemetryValue(Thr_ID, Thr_SUBID, Thr_INSTANCE, telemetry.throttle, 13 , Thr_PRECISION , Thr_NAME) + + -- WP + setTelemetryValue(WPN_ID, WPN_SUBID, WPN_INSTANCE, telemetry.wpNumber, 0 , WPN_PRECISION , WPN_NAME) + setTelemetryValue(WPD_ID, WPD_SUBID, WPD_INSTANCE, telemetry.wpDistance, 9 , WPD_PRECISION , WPD_NAME) + + -- crosstrack error and wp bearing not exposed as OpenTX variables by default + --[[ + setTelemetryValue(WPX_ID, WPX_SUBID, WPX_INSTANCE, telemetry.wpXTError, 9 , WPX_PRECISION , WPX_NAME) + setTelemetryValue(WPB_ID, WPB_SUBID, WPB_INSTANCE, telemetry.wpBearing, 20 , WPB_PRECISION , WPB_NAME) + --]] +end + +return {drawPane=drawPane,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/plane.lua b/HORUS/SOURCES/PP/lib/plane.lua similarity index 54% rename from HORUS/SOURCES/PP/plane.lua rename to HORUS/SOURCES/PP/lib/plane.lua index a81f81b5..62580e22 100644 --- a/HORUS/SOURCES/PP/plane.lua +++ b/HORUS/SOURCES/PP/lib/plane.lua @@ -1,3 +1,29 @@ +--[[ +enum FlightMode { + MANUAL = 0, + CIRCLE = 1, + STABILIZE = 2, + TRAINING = 3, + ACRO = 4, + FLY_BY_WIRE_A = 5, + FLY_BY_WIRE_B = 6, + CRUISE = 7, + AUTOTUNE = 8, + AUTO = 10, + RTL = 11, + LOITER = 12, + AVOID_ADSB = 14, + GUIDED = 15, + INITIALISING = 16, + QSTABILIZE = 17, + QHOVER = 18, + QLOITER = 19, + QLAND = 20, + QRTL = 21, + QAUTOTUNE = 22 +}; +--]] + local flightModes = {} -- plane flight modes flightModes[0]="" @@ -23,6 +49,6 @@ flightModes[19]="QHover" flightModes[20]="QLoiter" flightModes[21]="Qland" flightModes[22]="QRTL" +flightModes[23]="QAutotune" -- return {flightModes=flightModes} - diff --git a/HORUS/SOURCES/PP/lib/plane_px4.lua b/HORUS/SOURCES/PP/lib/plane_px4.lua new file mode 100644 index 00000000..f1bb2c01 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/plane_px4.lua @@ -0,0 +1,28 @@ +local flightModes = {} +-- plane flight modes +flightModes[0]="" +flightModes[1]="Manual" +flightModes[2]="AltCtl" --px4 specific +flightModes[3]="PosCtl" --px4 specific +flightModes[4]="Ready" --px4 specific +flightModes[5]="Takeoff" --px4 specific +flightModes[6]="Loiter" +flightModes[7]="Mission" --px4 specific +flightModes[8]="RTL" +flightModes[9]="Land" +flightModes[10]="RTGS" --px4 specific +flightModes[11]="Follow" +flightModes[12]="PrecLand" --px4 specific +flightModes[13]="" +flightModes[14]="Acro" +flightModes[15]="OffBoard" --px4 specific +flightModes[16]="Stabilize" +flightModes[17]="RAttitude" --px4 specific +flightModes[18]="Simple" --px4 specific +flightModes[19]="" +flightModes[20]="" +flightModes[21]="" +flightModes[22]="" +flightModes[23]="" +-- +return {flightModes=flightModes} diff --git a/HORUS/SOURCES/init0.lua b/HORUS/SOURCES/PP/lib/reset.lua similarity index 51% rename from HORUS/SOURCES/init0.lua rename to HORUS/SOURCES/PP/lib/reset.lua index 8ee45063..29b2d8d4 100644 --- a/HORUS/SOURCES/init0.lua +++ b/HORUS/SOURCES/PP/lib/reset.lua @@ -1,31 +1,6 @@ +#include "includes/yaapu_inc.lua" -#define VERSION "Yaapu Telemetry Script 1.7.4" - -#define ALARM_NOTIFIED 1 -#define ALARM_START 2 -#define ALARM_ARMED 3 -#define ALARM_TYPE 4 -#define ALARM_GRACE 5 -#define ALARM_READY 6 -#define ALARM_LAST_ALARM 7 --- -#define ALARMS_MIN_ALT 1 -#define ALARMS_MAX_ALT 2 -#define ALARMS_MAX_DIST 3 -#define ALARMS_FS_EKF 4 -#define ALARMS_FS_BATT 5 -#define ALARMS_TIMER 6 -#define ALARMS_BATT_L1 7 -#define ALARMS_BATT_L2 8 --- -#define ALARM_TYPE_MIN 0 -#define ALARM_TYPE_MAX 1 -#define ALARM_TYPE_TIMER 2 -#define ALARM_TYPE_BATT 3 --- -#define ALARM_TYPE_BATT_GRACE 4 - -local function resetTelemetry(status,alarms,function_pushMessage,function_clearTable) +local function resetTelemetry(status,telemetry,battery,alarms,utils) -- sport queue max pops to prevent looping forever local i = 0 -- empty sport queue @@ -34,6 +9,68 @@ local function resetTelemetry(status,alarms,function_pushMessage,function_clearT a,b,c,d = sportTelemetryPop() i = i + 1 end + ----------------------------- + -- TELEMETRY + ----------------------------- + -- AP STATUS + telemetry.flightMode = 0 + telemetry.simpleMode = 0 + telemetry.landComplete = 0 + telemetry.statusArmed = 0 + telemetry.battFailsafe = 0 + telemetry.ekfFailsafe = 0 + telemetry.imuTemp = 0 + -- GPS + telemetry.numSats = 0 + telemetry.gpsStatus = 0 + telemetry.gpsHdopC = 100 + telemetry.gpsAlt = 0 + -- BATT 1 + telemetry.batt1volt = 0 + telemetry.batt1current = 0 + telemetry.batt1mah = 0 + -- BATT 2 + telemetry.batt2volt = 0 + telemetry.batt2current = 0 + telemetry.batt2mah = 0 + -- HOME + telemetry.homeDist = 0 + telemetry.homeAlt = 0 + telemetry.homeAngle = -1 + -- VELANDYAW + telemetry.vSpeed = 0 + telemetry.hSpeed = 0 + telemetry.yaw = 0 + -- ROLLPITCH + telemetry.roll = 0 + telemetry.pitch = 0 + telemetry.range = 0 + -- PARAMS + telemetry.frameType = -1 + telemetry.batt1Capacity = 0 + telemetry.batt2Capacity = 0 + -- GPS + telemetry.lat = nil + telemetry.lon = nil + telemetry.homeLat = nil + telemetry.homeLon = nil + -- WP + telemetry.wpNumber = 0 + telemetry.wpDistance = 0 + telemetry.wpXTError = 0 + telemetry.wpBearing = 0 + telemetry.wpCommands = 0 + -- RC channels + telemetry.rcchannels = {} + -- VFR + telemetry.airspeed = 0 + telemetry.throttle = 0 + telemetry.baroAlt = 0 + -- + telemetry.totalDist = 0 + ----------------------------- + -- SCRIPT STATUS + ----------------------------- -- FLVSS 1 status.cell1min = 0 status.cell1sum = 0 @@ -42,75 +79,31 @@ local function resetTelemetry(status,alarms,function_pushMessage,function_clearT status.cell2sum = 0 -- FC 1 status.cell1sumFC = 0 - -- used to calculate cellcount status.cell1maxFC = 0 -- FC 2 status.cell2sumFC = 0 - -- A2 - status.cellsumA2 = 0 - -- used to calculate cellcount - status.cellmaxA2 = 0 - -------------------------------- - -- AP STATUS - status.flightMode = 0 - status.simpleMode = 0 - status.landComplete = 0 - status.statusArmed = 0 - status.battFailsafe = 0 - status.ekfFailsafe = 0 - status.imuTemp = 0 - -- GPS - status.numSats = 0 - status.gpsStatus = 0 - status.gpsHdopC = 100 - status.gpsAlt = 0 + status.cell2maxFC = 0 -- BATT - status.cellcount = 0 + status.cell1count = 0 + status.cell2count = 0 + status.battsource = "na" -- BATT 1 - status.batt1volt = 0 - status.batt1current = 0 - status.batt1mah = 0 status.batt1sources = { - a2 = false, vs = false, fc = false } -- BATT 2 - status.batt2volt = 0 - status.batt2current = 0 - status.batt2mah = 0 status.batt2sources = { - a2 = false, vs = false, fc = false } -- TELEMETRY status.noTelemetryData = 1 - -- HOME - status.homeDist = 0 - status.homeAlt = 0 - status.homeAngle = -1 -- MESSAGES status.msgBuffer = "" status.lastMsgValue = 0 status.lastMsgTime = 0 - -- VELANDYAW - status.vSpeed = 0 - status.hSpeed = 0 - status.yaw = 0 - -- SYNTH VSPEED SUPPORT - status.vspd = 0 - status.synthVSpeedTime = 0 - status.prevHomeAlt = 0 - -- ROLLPITCH - status.roll = 0 - status.pitch = 0 - status.range = 0 - -- PARAMS - status.frameType = -1 - status.batt1Capacity = 0 - status.batt2Capacity = 0 -- FLIGHT TIME status.lastTimerStart = 0 status.timerRunning = 0 @@ -130,8 +123,12 @@ local function resetTelemetry(status,alarms,function_pushMessage,function_clearT status.lastMessageSeverity = 0 status.lastMessageCount = 1 status.messageCount = 0 + ------------------------- + -- BATTERY ARRAY + ------------------------- + battery = {0,0,0,0,0,0,0,0,0,0,0,0} -- clear message queue - function_clearTable(status.messages) + utils.clearTable(status.messages) --- status.messages = {} -- reset alarms @@ -142,12 +139,11 @@ local function resetTelemetry(status,alarms,function_pushMessage,function_clearT alarms[5] = { false, 0 , true, ALARM_TYPE_MAX, 0, false, 0 } --FS_BAT alarms[6] = { false, 0 , true, ALARM_TYPE_TIMER, 0, false, 0 } --FLIGTH_TIME alarms[7] = { false, 0 , false, ALARM_TYPE_BATT, ALARM_TYPE_BATT_GRACE, false, 0 } --BATT L1 - alarms[8] = { false, 0 , false, ALARM_TYPE_BATT, ALARM_TYPE_BATT_GRACE, false, 0 } --BATT L2 - -- stop and reset timer + alarms[8] = { false, 0 , false, ALARM_TYPE_BATT_CRT, ALARM_TYPE_BATT_GRACE, false, 0 } --BATT L2 + alarms[9] = { false, 0 , false, ALARM_TYPE_MAX, 0, false, 0 } --MAX_HDOP + -- stop and reset timer model.setTimer(2,{mode=0}) model.setTimer(2,{value=0}) - -- - function_pushMessage(7,"telemetry reset") end return {resetTelemetry=resetTelemetry} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/right_1.lua b/HORUS/SOURCES/PP/lib/right_1.lua new file mode 100644 index 00000000..165d1e77 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/right_1.lua @@ -0,0 +1,231 @@ +#include "includes/yaapu_inc.lua" + +#define BATTCELL_X 75 +#define BATTCELL_Y 16 +#define BATTCELL_XV 76 +#define BATTCELL_YS 18 +#define BATTCELL_YV 32 +#define BATTCELL_FLAGS DBLSIZE+RIGHT +#define BATTCELL_XI 7 +#define BATTCELL_YI 20 + +#define BATTVOLT_X 75 +#define BATTVOLT_Y 48 +#define BATTVOLT_XV 75 +#define BATTVOLT_YV 58 +#define BATTVOLT_FLAGS RIGHT+MIDSIZE+PREC1 +#define BATTVOLT_FLAGSV SMLSIZE + +#define BATTCURR_X 75 +#define BATTCURR_Y 68 +#define BATTCURR_XA 76 +#define BATTCURR_YA 83 +#define BATTCURR_FLAGS DBLSIZE+RIGHT +#define BATTCURR_FLAGSA 0 + +#define BATTPERC_X 35 +#define BATTPERC_Y 101 +#define BATTPERC_YPERC 99 +#define BATTPERC_FLAGS MIDSIZE +#define BATTPERC_FLAGSPERC SMLSIZE + +#define BATTGAUGE_X 10 +#define BATTGAUGE_Y 105 +#define BATTGAUGE_WIDTH 80 +#define BATTGAUGE_HEIGHT 21 +#define BATTGAUGE_STEPS 10 + +#define BATTLABEL_X 90 +#define BATTLABEL_Y 126 +#define BATTLABEL_FLAGS SMLSIZE+RIGHT + +#define BATTMAH_X 90 +#define BATTMAH_Y 138 +#define BATTMAH_FLAGS 0 + +#define POWER_X 95 +#define POWER_Y 164 +#define POWER_XLABEL 95 +#define POWER_YLABEL 154 + +#define BATTEFF_X 12 +#define BATTEFF_Y 164 +#define BATTEFF_XLABEL 12 +#define BATTEFF_YLABEL 154 + +#ifdef BATTPERC_BY_VOLTAGE +#define VOLTAGE_DROP 0.15 +--[[ + Example data based on a 18 minutes flight for quad, battery:5200mAh LiPO 10C, hover @15A + Notes: + - when motors are armed VOLTAGE_DROP offset is applied! + - number of samples is fixed at 11 but percentage values can be anything and are not restricted to multiples of 10 + - voltage between samples is assumed to be linear +--]] +local battPercByVoltage = { + {3.40, 0}, + {3.46, 10}, + {3.51, 20}, + {3.53, 30}, + {3.56, 40}, + {3.60, 50}, + {3.63, 60}, + {3.70, 70}, + {3.73, 80}, + {3.86, 90}, + {4.00, 99} + } + +function getBattPercByCell(cellVoltage) + if cellVoltage == 0 then + return 99 + end + if cellVoltage >= battPercByVoltage[11][1] then + return 99 + end + if cellVoltage <= battPercByVoltage[1][1] then + return 0 + end + for i=2,11 do + if cellVoltage <= battPercByVoltage[i][1] then + -- + local v0 = battPercByVoltage[i-1][1] + local fv0 = battPercByVoltage[i-1][2] + -- + local v1 = battPercByVoltage[i][1] + local fv1 = battPercByVoltage[i][2] + -- interpolation polinomial + return fv0 + ((fv1 - fv0)/(v1-v0))*(cellVoltage - v0) + end + end --for +end +#endif --BATTPERC_BY_VOLTAGE + +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +--[[ +BATT_CELL 1 +BATT_VOLT 4 +BATT_CURR 7 +BATT_MAH 10 +BATT_CAP 13 + +BATT_IDALL 0 +BATT_ID1 1 +BATT_ID2 2 +--]] +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local perc = 0 + #ifdef BATTPERC_BY_VOLTAGE + if conf.enableBattPercByVoltage == true then + --[[ + discharge curve is based on battery under load, when motors are disarmed + cellvoltage needs to be corrected by subtracting the "under load" voltage drop + --]] + if telemetry.statusArmed then + perc = getBattPercByCell(0.01*battery[BATT_CELL+battId]) + else + perc = getBattPercByCell((0.01*battery[BATT_CELL+battId])-VOLTAGE_DROP) + end + else + #endif --BATTPERC_BY_VOLTAGE + if (battery[BATT_CAP+battId] > 0) then + perc = (1 - (battery[BATT_MAH+battId]/battery[BATT_CAP+battId]))*100 + if perc > 99 then + perc = 99 + elseif perc < 0 then + perc = 0 + end + end + #ifdef BATTPERC_BY_VOLTAGE + end --conf.enableBattPercByVoltage + #endif --BATTPERC_BY_VOLTAGE + -- battery min cell + local flags = 0 + -- + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) -- white + if status.showMinMaxValues == false then + if status.battLevel2 == false and alarms[ALARMS_BATT_L2][ALARM_START] > 0 then + utils.drawBlinkBitmap("cell_red_blink_86x30",x+BATTCELL_XI,BATTCELL_YI) + utils.lcdBacklightOn() + elseif status.battLevel2 == true then + lcd.drawBitmap(utils.getBitmap("cell_red_86x30"),x+BATTCELL_XI,BATTCELL_YI) + elseif status.battLevel1 == false and alarms[ALARMS_BATT_L1][ALARM_START] > 0 then + --lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + utils.drawBlinkBitmap("cell_orange_blink_86x30",x+BATTCELL_XI,BATTCELL_YI) + utils.lcdBacklightOn() + elseif status.battLevel1 == true then + lcd.drawBitmap(utils.getBitmap("cell_orange_86x30"),x+BATTCELL_XI,BATTCELL_YI) + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + end + end + flags = CUSTOM_COLOR + --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) + if battery[BATT_CELL+battId] * 0.01 < 10 then + lcd.drawNumber(x+BATTCELL_X+2, BATTCELL_Y, battery[BATT_CELL+battId] + 0.5, PREC2+BATTCELL_FLAGS+flags) + else + lcd.drawNumber(x+BATTCELL_X+2, BATTCELL_Y, (battery[BATT_CELL+battId] + 0.5)*0.1, PREC1+BATTCELL_FLAGS+flags) + end + + local lx = x+BATTCELL_XV + lcd.drawText(lx, BATTCELL_YV, "V", flags) + lcd.drawText(lx, BATTCELL_YS, status.battsource, flags) + + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) -- white + -- battery voltage + drawLib.drawNumberWithDim(x+BATTVOLT_X,BATTVOLT_Y,x+BATTVOLT_XV, BATTVOLT_YV, battery[BATT_VOLT+battId],"V",BATTVOLT_FLAGS+CUSTOM_COLOR,BATTVOLT_FLAGSV+CUSTOM_COLOR) + -- battery current + local lowAmp = battery[BATT_CURR+battId]*0.1 < 10 + drawLib.drawNumberWithDim(x+BATTCURR_X,BATTCURR_Y,x+BATTCURR_XA,BATTCURR_YA,battery[BATT_CURR+battId]*(lowAmp and 1 or 0.1),"A",BATTCURR_FLAGS+CUSTOM_COLOR+(lowAmp and PREC1 or 0),BATTCURR_FLAGSA+CUSTOM_COLOR) + -- display capacity bar % + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255, 255)) + lcd.drawFilledRectangle(x+BATTGAUGE_X, BATTGAUGE_Y,BATTGAUGE_WIDTH,BATTGAUGE_HEIGHT,CUSTOM_COLOR) + if perc > 50 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) + elseif perc <= 50 and perc > 25 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) + end + lcd.drawGauge(x+BATTGAUGE_X, BATTGAUGE_Y,BATTGAUGE_WIDTH,BATTGAUGE_HEIGHT,perc,100,CUSTOM_COLOR) + -- battery percentage + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + + local strperc = string.format("%02d%%",perc) + lcd.drawText(x+BATTPERC_X, BATTPERC_Y, strperc, BATTPERC_FLAGS+CUSTOM_COLOR) + + -- battery mah + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local strmah = string.format("%.02f/%.01f",battery[BATT_MAH+battId]/1000,battery[BATT_CAP+battId]/1000) + --lcd.drawText(x+BATTMAH_X, BATTMAH_Y+2, "Ah", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(x+BATTMAH_X, BATTMAH_Y, strmah, BATTMAH_FLAGS+RIGHT+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(x+BATTLABEL_X,BATTLABEL_Y,battId == 0 and "B1+B2(Ah)" or (battId == 1 and "B1(Ah)" or "B2(Ah)"),BATTLABEL_FLAGS+CUSTOM_COLOR) + if battId < 2 then + -- labels + lcd.drawText(x+BATTEFF_XLABEL, BATTEFF_YLABEL, "Eff(mAh)", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(x+POWER_XLABEL, POWER_YLABEL, "Power(W)", SMLSIZE+CUSTOM_COLOR+RIGHT) + -- data + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local speed = utils.getMaxValue(telemetry.hSpeed,MAX_HSPEED) + -- efficiency for indipendent batteries makes sense only for battery 1 + local eff = speed > 2 and (conf.battConf == BATTCONF_OTHER and battery[BATT_CURR+1] or battery[BATT_CURR])*1000/(speed*UNIT_HSPEED_SCALE) or 0 + eff = ( conf.battConf == BATTCONF_OTHER and battId == 2) and 0 or eff + lcd.drawNumber(x+BATTEFF_X,BATTEFF_Y,eff,(eff > 99999 and 0 or MIDSIZE)+RIGHT+CUSTOM_COLOR) + -- power + local power = battery[BATT_VOLT+battId]*battery[BATT_CURR+battId]*0.01 + lcd.drawNumber(x+POWER_X,POWER_Y,power,MIDSIZE+RIGHT+CUSTOM_COLOR) + --lcd.drawText(x+POWER_X,POWER_Y,string.format("%dW",power),MIDSIZE+CUSTOM_COLOR) + end + if status.showMinMaxValues == true then + drawLib.drawVArrow(x+BATTCELL_X+11, BATTCELL_Y + 8,false,true,utils) + drawLib.drawVArrow(x+BATTVOLT_X+11,BATTVOLT_Y + 3, false,true,utils) + drawLib.drawVArrow(x+BATTCURR_X+11,BATTCURR_Y + 10,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/right_2.lua b/HORUS/SOURCES/PP/lib/right_2.lua new file mode 100644 index 00000000..7103d0fb --- /dev/null +++ b/HORUS/SOURCES/PP/lib/right_2.lua @@ -0,0 +1,228 @@ +#include "includes/yaapu_inc.lua" + +#define BATTCELL_X 41 +#define BATTCELL_Y 13 +#define BATTCELL_XV 175 +#define BATTCELL_YV 23 +#define BATTCELL_YS 58 +#define BATTCELL_FLAGS XXLSIZE + +#define BATTVOLT_X 105 +#define BATTVOLT_Y 79 +#define BATTVOLT_XV 103 +#define BATTVOLT_YV 79 +#define BATTVOLT_FLAGS DBLSIZE+PREC1+RIGHT +#define BATTVOLT_FLAGSV SMLSIZE + +#define BATTCURR_X 178 +#define BATTCURR_Y 79 +#define BATTCURR_XA 176 +#define BATTCURR_YA 79 +#define BATTCURR_FLAGS DBLSIZE+RIGHT +#define BATTCURR_FLAGSA SMLSIZE + +#define BATTPERC_X 98 +#define BATTPERC_Y 114 +#define BATTPERC_YPERC 117 +#define BATTPERC_FLAGS MIDSIZE +#define BATTPERC_FLAGSPERC SMLSIZE + +#define BATTGAUGE_X 43 +#define BATTGAUGE_Y 117 +#define BATTGAUGE_WIDTH 147 +#define BATTGAUGE_HEIGHT 23 +#define BATTGAUGE_STEPS 10 + +#define BATTMAH_X 183 +#define BATTMAH_Y 140 +#define BATTMAH_FLAGS MIDSIZE + +#define BATTEFF_X 478 +#define BATTEFF_Y 178 +#define BATTEFF_XLABEL 478 +#define BATTEFF_YLABEL 165 +#define BATTEFF_FLAGS SMLSIZE +#define BATTEFF_FLAGSW MIDSIZE + +#define POWER_X 395 +#define POWER_Y 178 +#define POWER_XLABEL 395 +#define POWER_YLABEL 165 + +#ifdef BATTPERC_BY_VOLTAGE +#define VOLTAGE_DROP 0.15 +--[[ + Example data based on a 18 minutes flight for quad, battery:5200mAh LiPO 10C, hover @15A + Notes: + - when motors are armed VOLTAGE_DROP offset is applied! + - number of samples is fixed at 11 but percentage values can be anything and are not restricted to multiples of 10 + - voltage between samples is assumed to be linear +--]] +local battPercByVoltage = { + {3.40, 0}, + {3.46, 10}, + {3.51, 20}, + {3.53, 30}, + {3.56, 40}, + {3.60, 50}, + {3.63, 60}, + {3.70, 70}, + {3.73, 80}, + {3.86, 90}, + {4.00, 99} + } + +function getBattPercByCell(cellVoltage) + if cellVoltage == 0 then + return 99 + end + if cellVoltage >= battPercByVoltage[11][1] then + return 99 + end + if cellVoltage <= battPercByVoltage[1][1] then + return 0 + end + for i=2,11 do + if cellVoltage <= battPercByVoltage[i][1] then + -- + local v0 = battPercByVoltage[i-1][1] + local fv0 = battPercByVoltage[i-1][2] + -- + local v1 = battPercByVoltage[i][1] + local fv1 = battPercByVoltage[i][2] + -- interpolation polinomial + return fv0 + ((fv1 - fv0)/(v1-v0))*(cellVoltage - v0) + end + end --for +end +#endif --BATTPERC_BY_VOLTAGE + +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +--[[ +BATT_CELL 1 +BATT_VOLT 4 +BATT_CURR 7 +BATT_MAH 10 +BATT_CAP 13 + +BATT_IDALL 0 +BATT_ID1 1 +BATT_ID2 2 +--]] +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local perc = 0 + #ifdef BATTPERC_BY_VOLTAGE + if conf.enableBattPercByVoltage == true then + --[[ + discharge curve is based on battery under load, when motors are disarmed + cellvoltage needs to be corrected by subtracting the "under load" voltage drop + --]] + if telemetry.statusArmed then + perc = getBattPercByCell(0.01*battery[BATT_CELL+battId]) + else + perc = getBattPercByCell((0.01*battery[BATT_CELL+battId])-VOLTAGE_DROP) + end + else + #endif --BATTPERC_BY_VOLTAGE + if (battery[BATT_CAP+battId] > 0) then + perc = (1 - (battery[BATT_MAH+battId]/battery[BATT_CAP+battId]))*100 + if perc > 99 then + perc = 99 + elseif perc < 0 then + perc = 0 + end + end + #ifdef BATTPERC_BY_VOLTAGE + end --conf.enableBattPercByVoltage + #endif --BATTPERC_BY_VOLTAGE + -- battery min cell + local flags = 0 + -- + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) -- white + if status.showMinMaxValues == false then + if status.battLevel2 == false and alarms[ALARMS_BATT_L2][ALARM_START] > 0 then + utils.drawBlinkBitmap("cell_red",x+BATTCELL_X - 2,BATTCELL_Y + 7) + utils.lcdBacklightOn() + elseif status.battLevel2 == true then + lcd.drawBitmap(utils.getBitmap("cell_red"),x+BATTCELL_X - 2,BATTCELL_Y + 7) + elseif status.battLevel1 == false and alarms[ALARMS_BATT_L1][ALARM_START] > 0 then + --lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + utils.drawBlinkBitmap("cell_orange_blink",x+BATTCELL_X - 2,BATTCELL_Y + 7) + utils.lcdBacklightOn() + elseif status.battLevel1 == true then + lcd.drawBitmap(utils.getBitmap("cell_orange"),x+BATTCELL_X - 2,BATTCELL_Y + 7) + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + end + end + flags = CUSTOM_COLOR + --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) + if battery[BATT_CELL+battId] * 0.01 < 10 then + lcd.drawNumber(x+BATTCELL_X+2, BATTCELL_Y, battery[BATT_CELL+battId] + 0.5, PREC2+BATTCELL_FLAGS+flags) + else + lcd.drawNumber(x+BATTCELL_X+2, BATTCELL_Y, (battery[BATT_CELL+battId] + 0.5)*0.1, PREC1+BATTCELL_FLAGS+flags) + end + + --lcd.drawNumber(x+BATTCELL_X+2, BATTCELL_Y, battery[BATT_CELL+battId] + 0.5, BATTCELL_FLAGS+flags) + local lx = x+BATTCELL_XV + lcd.drawText(lx, BATTCELL_YV, "V", flags) + lcd.drawText(lx, BATTCELL_YS, status.battsource, flags) + + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) -- white + -- battery voltage + drawLib.drawNumberWithDim(x+BATTVOLT_X,BATTVOLT_Y,x+BATTVOLT_XV, BATTVOLT_YV, battery[BATT_VOLT+battId],"V",BATTVOLT_FLAGS+CUSTOM_COLOR,BATTVOLT_FLAGSV+CUSTOM_COLOR) + -- battery current + drawLib.drawNumberWithDim(x+BATTCURR_X,BATTCURR_Y,x+BATTCURR_XA,BATTCURR_YA,battery[BATT_CURR+battId]*(battery[BATT_CURR+battId] >= 100 and 0.1 or 1),"A",BATTCURR_FLAGS+CUSTOM_COLOR+(battery[BATT_CURR+battId] >= 100 and 0 or PREC1),BATTCURR_FLAGSA+CUSTOM_COLOR) + -- display capacity bar % + if perc > 50 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) + elseif perc <= 50 and perc > 25 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) + end + lcd.drawBitmap(utils.getBitmap("gauge_bg"),x+BATTGAUGE_X-2,BATTGAUGE_Y-2) + lcd.drawGauge(x+BATTGAUGE_X, BATTGAUGE_Y,BATTGAUGE_WIDTH,BATTGAUGE_HEIGHT,perc,100,CUSTOM_COLOR) + -- battery percentage + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + + local strperc = string.format("%02d%%",perc) + lcd.drawText(x+BATTPERC_X, BATTPERC_Y, strperc, BATTPERC_FLAGS+CUSTOM_COLOR) + + -- battery mah + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local strmah = string.format("%.02f/%.01f",battery[BATT_MAH+battId]/1000,battery[BATT_CAP+battId]/1000) + lcd.drawText(x+BATTMAH_X, BATTMAH_Y+6, "Ah", RIGHT+CUSTOM_COLOR) + lcd.drawText(x+BATTMAH_X - 22, BATTMAH_Y, strmah, BATTMAH_FLAGS+RIGHT+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,COLOR_DARK_GREY) + lcd.drawText(x+190,124,battId == 0 and "B1+B2" or (battId == 1 and "B1" or "B2"),SMLSIZE+CUSTOM_COLOR+RIGHT) + + if battId < 2 then + -- RIGHT labels + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(BATTEFF_XLABEL, BATTEFF_YLABEL, "Eff(mAh)", BATTEFF_FLAGS+RIGHT+CUSTOM_COLOR) + lcd.drawText(POWER_XLABEL, POWER_YLABEL, "Power(W)", SMLSIZE+CUSTOM_COLOR+RIGHT) + --data + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- efficiency for indipendent batteries makes sense only for battery 1 + local speed = utils.getMaxValue(telemetry.hSpeed,MAX_HSPEED) + local eff = speed > 2 and (conf.battConf == BATTCONF_OTHER and battery[BATT_CURR+1] or battery[BATT_CURR])*1000/(speed*UNIT_HSPEED_SCALE) or 0 + eff = ( conf.battConf == BATTCONF_OTHER and battId == 2) and 0 or eff + lcd.drawNumber(BATTEFF_X,BATTEFF_Y,eff,BATTEFF_FLAGSW+RIGHT+CUSTOM_COLOR) + -- power + local power = battery[BATT_VOLT]*(conf.battConf == BATTCONF_OTHER and battery[BATT_CURR+1] or battery[BATT_CURR])*0.01 + lcd.drawNumber(POWER_X,POWER_Y,power,MIDSIZE+RIGHT+CUSTOM_COLOR) + end + + if status.showMinMaxValues == true then + drawLib.drawVArrow(x+BATTCELL_X+140, BATTCELL_Y + 27,false,true,utils) + drawLib.drawVArrow(x+BATTVOLT_X+4,BATTVOLT_Y + 10, false,true,utils) + drawLib.drawVArrow(x+BATTCURR_X+3,BATTCURR_Y + 10,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/right_custom_2.lua b/HORUS/SOURCES/PP/lib/right_custom_2.lua new file mode 100644 index 00000000..c8f24aec --- /dev/null +++ b/HORUS/SOURCES/PP/lib/right_custom_2.lua @@ -0,0 +1,318 @@ +#include "includes/yaapu_inc.lua" + +#define BATTCELL_X 110 +#define BATTCELL_Y 16 +#define BATTCELL_XV 180 +#define BATTCELL_YV 19 +#define BATTCELL_YS 35 +#define BATTCELL_FLAGS DBLSIZE + +#define BATTVOLT_X 110 +#define BATTVOLT_Y 48 +#define BATTVOLT_XV 110 +#define BATTVOLT_YV 46 +#define BATTVOLT_FLAGS MIDSIZE+PREC1+RIGHT +#define BATTVOLT_FLAGSV SMLSIZE + +#define BATTCURR_X 178 +#define BATTCURR_Y 48 +#define BATTCURR_XA 178 +#define BATTCURR_YA 48 +#define BATTCURR_FLAGS MIDSIZE+RIGHT+PREC1 +#define BATTCURR_FLAGSA SMLSIZE + +#define BATTPERC_X 63 +#define BATTPERC_Y 27 +#define BATTPERC_FLAGS 0 +#define BATTPERC_FLAGSPERC SMLSIZE + +#define BATTGAUGE_X 47 +#define BATTGAUGE_Y 29 +#define BATTGAUGE_WIDTH 58 +#define BATTGAUGE_HEIGHT 16 +#define BATTGAUGE_STEPS 10 + +#define BATTMAH_X 180 +#define BATTMAH_Y 71 +#define BATTMAH_FLAGS 0 + +#define BATTEFF_X 191 +#define BATTEFF_Y 93 +#define BATTEFF_YW 105 +#define BATTEFF_FLAGS SMLSIZE +#define BATTEFF_FLAGSW 0 + +#define SENSOR1_X 110 +#define SENSOR1_Y 101 +#define SENSOR1_XLABEL 110 +#define SENSOR1_YLABEL 90 + +#define SENSOR2_X 196 +#define SENSOR2_Y 101 +#define SENSOR2_XLABEL 196 +#define SENSOR2_YLABEL 90 + +#define SENSOR3_X 110 +#define SENSOR3_Y 132 +#define SENSOR3_XLABEL 110 +#define SENSOR3_YLABEL 123 + +#define SENSOR4_X 196 +#define SENSOR4_Y 132 +#define SENSOR4_XLABEL 196 +#define SENSOR4_YLABEL 123 + +#define SENSOR5_X 110 +#define SENSOR5_Y 173 +#define SENSOR5_XLABEL 110 +#define SENSOR5_YLABEL 163 + +#define SENSOR6_X 196 +#define SENSOR6_Y 173 +#define SENSOR6_XLABEL 196 +#define SENSOR6_YLABEL 163 + + +-------------------------- +-- CUSTOM SENSORS SUPPORT +-------------------------- +#define SENSOR_LABEL 1 +#define SENSOR_NAME 2 +#define SENSOR_PREC 3 +#define SENSOR_UNIT 4 +#define SENSOR_MULT 5 +#define SENSOR_MAX 6 +#define SENSOR_FONT 7 +#define SENSOR_WARN 8 +#define SENSOR_CRIT 9 + +#ifdef BATTPERC_BY_VOLTAGE +#define VOLTAGE_DROP 0.15 +--[[ + Example data based on a 18 minutes flight for quad, battery:5200mAh LiPO 10C, hover @15A + Notes: + - when motors are armed VOLTAGE_DROP offset is applied! + - number of samples is fixed at 11 but percentage values can be anything and are not restricted to multiples of 10 + - voltage between samples is assumed to be linear +--]] + +local battPercByVoltage = { + {3.40, 0}, + {3.46, 10}, + {3.51, 20}, + {3.53, 30}, + {3.56, 40}, + {3.60, 50}, + {3.63, 60}, + {3.70, 70}, + {3.73, 80}, + {3.86, 90}, + {4.00, 99} +} + +function getBattPercByCell(cellVoltage) + if cellVoltage == 0 then + return 99 + end + if cellVoltage >= battPercByVoltage[11][1] then + return 99 + end + if cellVoltage <= battPercByVoltage[1][1] then + return 0 + end + for i=2,11 do + if cellVoltage <= battPercByVoltage[i][1] then + -- + local v0 = battPercByVoltage[i-1][1] + local fv0 = battPercByVoltage[i-1][2] + -- + local v1 = battPercByVoltage[i][1] + local fv1 = battPercByVoltage[i][2] + -- interpolation polinomial + return fv0 + ((fv1 - fv0)/(v1-v0))*(cellVoltage - v0) + end + end --for +end +#endif --BATTPERC_BY_VOLTAGE + +local customSensorXY = { + { SENSOR1_XLABEL, SENSOR1_YLABEL, SENSOR1_X, SENSOR1_Y}, + { SENSOR2_XLABEL, SENSOR2_YLABEL, SENSOR2_X, SENSOR2_Y}, + { SENSOR3_XLABEL, SENSOR3_YLABEL, SENSOR3_X, SENSOR3_Y}, + { SENSOR4_XLABEL, SENSOR4_YLABEL, SENSOR4_X, SENSOR4_Y}, + { SENSOR5_XLABEL, SENSOR5_YLABEL, SENSOR5_X, SENSOR5_Y}, + { SENSOR6_XLABEL, SENSOR6_YLABEL, SENSOR6_X, SENSOR6_Y}, +} + +local function drawCustomSensors(x,customSensors,utils,status) + if customSensors == nil then + return + end + + local label,data,prec,mult,flags,sensorConfig + for i=1,6 + do + if customSensors.sensors[i] ~= nil then + sensorConfig = customSensors.sensors[i] + + if sensorConfig[SENSOR_UNIT] == "" then + label = string.format("%s",sensorConfig[SENSOR_LABEL]) + else + label = string.format("%s(%s)",sensorConfig[SENSOR_LABEL],sensorConfig[SENSOR_UNIT]) + end + -- draw sensor label + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) + lcd.drawText(x+customSensorXY[i][1], customSensorXY[i][2],label, SMLSIZE+RIGHT+CUSTOM_COLOR) + + mult = sensorConfig[SENSOR_PREC] == 0 and 1 or ( sensorConfig[SENSOR_PREC] == 1 and 10 or 100 ) + prec = mult == 1 and 0 or (mult == 10 and 32 or 48) + + local sensorName = sensorConfig[SENSOR_NAME]..(status.showMinMaxValues == true and sensorConfig[SENSOR_MAX] or "") + local sensorValue = getValue(sensorName) + local value = (sensorValue+(mult == 100 and 0.005 or 0))*mult*sensorConfig[SENSOR_MULT] + + -- default font size + flags = (i<=2 and MIDSIZE or (sensorConfig[SENSOR_FONT] == 1 and MIDSIZE or DBLSIZE)) + + -- for sensor 3,4,5,6 reduce font if necessary + if i>2 and math.abs(value)*mult > 99999 then + flags = MIDSIZE + end + + local color = COLOR_TEXT + local sign = sensorConfig[SENSOR_MAX] == "+" and 1 or -1 + + -- max tracking, high values are critical + if math.abs(value) ~= 0 and status.showMinMaxValues == false then + color = ( sensorValue*sign > sensorConfig[SENSOR_CRIT]*sign and COLOR_CRIT or (sensorValue*sign > sensorConfig[SENSOR_WARN]*sign and COLOR_WARN or COLOR_TEXT)) + end + + lcd.setColor(CUSTOM_COLOR,color) + + local voffset = (i>2 and flags==MIDSIZE) and 5 or 0 + -- if a lookup table exists use it! + if customSensors.lookups[i] ~= nil and customSensors.lookups[i][value] ~= nil then + lcd.drawText(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, customSensors.lookups[i][value] or value, flags+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, value, flags+RIGHT+prec+CUSTOM_COLOR) + end + end + end +end + +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +--[[ +BATT_CELL 1 +BATT_VOLT 4 +BATT_CURR 7 +BATT_MAH 10 +BATT_CAP 13 + +BATT_IDALL 0 +BATT_ID1 1 +BATT_ID2 2 +--]] +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils,customSensors) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local perc = 0 + #ifdef BATTPERC_BY_VOLTAGE + if conf.enableBattPercByVoltage == true then + --[[ + discharge curve is based on battery under load, when motors are disarmed + cellvoltage needs to be corrected by subtracting the "under load" voltage drop + --]] + if telemetry.statusArmed then + perc = getBattPercByCell(0.01*battery[BATT_CELL+battId]) + else + perc = getBattPercByCell((0.01*battery[BATT_CELL+battId])-VOLTAGE_DROP) + end + else + #endif --BATTPERC_BY_VOLTAGE + if (battery[BATT_CAP+battId] > 0) then + perc = (1 - (battery[BATT_MAH+battId]/battery[BATT_CAP+battId]))*100 + if perc > 99 then + perc = 99 + elseif perc < 0 then + perc = 0 + end + end + #ifdef BATTPERC_BY_VOLTAGE + end --conf.enableBattPercByVoltage + #endif --BATTPERC_BY_VOLTAGE + -- battery min cell + local flags = 0 + -- + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) -- white + if status.showMinMaxValues == false then + if status.battLevel2 == false and alarms[ALARMS_BATT_L2][ALARM_START] > 0 then + utils.drawBlinkBitmap("cell_red_small",x+BATTCELL_X+1,BATTCELL_Y + 7) + utils.lcdBacklightOn() + elseif status.battLevel2 == true then + lcd.drawBitmap(utils.getBitmap("cell_red_small"),x+BATTCELL_X+1,BATTCELL_Y + 7) + elseif status.battLevel1 == false and alarms[ALARMS_BATT_L1][ALARM_START] > 0 then + --lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + utils.drawBlinkBitmap("cell_orange_small_blink",x+BATTCELL_X+1,BATTCELL_Y + 7) + utils.lcdBacklightOn() + elseif status.battLevel1 == true then + lcd.drawBitmap(utils.getBitmap("cell_orange_small"),x+BATTCELL_X+1,BATTCELL_Y + 7) + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + end + end + flags = CUSTOM_COLOR + --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) + if battery[BATT_CELL+battId] * 0.01 < 10 then + lcd.drawNumber(x+BATTCELL_X+2, BATTCELL_Y, battery[BATT_CELL+battId] + 0.5, PREC2+BATTCELL_FLAGS+flags) + else + lcd.drawNumber(x+BATTCELL_X+2, BATTCELL_Y, (battery[BATT_CELL+battId] + 0.5)*0.1, PREC1+BATTCELL_FLAGS+flags) + end + local lx = x+BATTCELL_XV + lcd.drawText(lx, BATTCELL_YV, "V", SMLSIZE+flags) + lcd.drawText(lx-2, BATTCELL_YS, status.battsource, SMLSIZE+flags) + + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) -- white + -- battery voltage + drawLib.drawNumberWithDim(x+BATTVOLT_X,BATTVOLT_Y,x+BATTVOLT_XV, BATTVOLT_YV, battery[BATT_VOLT+battId],"V",BATTVOLT_FLAGS+CUSTOM_COLOR,BATTVOLT_FLAGSV+CUSTOM_COLOR) + -- battery current + drawLib.drawNumberWithDim(x+BATTCURR_X,BATTCURR_Y,x+BATTCURR_XA,BATTCURR_YA,battery[BATT_CURR+battId],"A",BATTCURR_FLAGS+CUSTOM_COLOR,BATTCURR_FLAGSA+CUSTOM_COLOR) + -- display capacity bar % + if perc > 50 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) + elseif perc <= 50 and perc > 25 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) + end + lcd.drawBitmap(utils.getBitmap("gauge_bg_small"),x+BATTGAUGE_X,BATTGAUGE_Y) + lcd.drawGauge(x+BATTGAUGE_X, BATTGAUGE_Y,BATTGAUGE_WIDTH,BATTGAUGE_HEIGHT,perc,100,CUSTOM_COLOR) + -- battery percentage + lcd.setColor(CUSTOM_COLOR,COLOR_BLACK) -- black + + local strperc = string.format("%02d%%",perc) + lcd.drawText(x+BATTPERC_X, BATTPERC_Y, strperc, BATTPERC_FLAGS+CUSTOM_COLOR) + + -- battery mah + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + local strmah = string.format("%.02f/%.01f",battery[BATT_MAH+battId]/1000,battery[BATT_CAP+battId]/1000) + lcd.drawText(x+BATTMAH_X, BATTMAH_Y+4, "Ah", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(x+BATTMAH_X - 22, BATTMAH_Y, strmah, BATTMAH_FLAGS+RIGHT+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,COLOR_DARK_GREY) + --lcd.drawText(475,124,battId == 0 and "B1+B2" or (battId == 1 and "B1" or "B2"),SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawBitmap(utils.getBitmap("battbox_small"),x+42,21) + + -- do no show custom sensors when displaying 2nd battery info + if battId < 2 then + drawCustomSensors(x,customSensors,utils,status) + end + + if status.showMinMaxValues == true then + drawLib.drawVArrow(LCD_W-12, BATTCELL_Y + 8,false,true,utils) + drawLib.drawVArrow(x+BATTVOLT_X+5,BATTVOLT_Y + 6, false,true,utils) + drawLib.drawVArrow(x+BATTCURR_X+4,BATTCURR_Y + 6,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/lib/rover.lua b/HORUS/SOURCES/PP/lib/rover.lua new file mode 100644 index 00000000..1abb7481 --- /dev/null +++ b/HORUS/SOURCES/PP/lib/rover.lua @@ -0,0 +1,47 @@ +--[[ + // Auto Pilot modes + // ---------------- + enum Number { + MANUAL = 0, + ACRO = 1, + STEERING = 3, + HOLD = 4, + LOITER = 5, + FOLLOW = 6, + SIMPLE = 7, + AUTO = 10, + RTL = 11, + SMART_RTL = 12, + GUIDED = 15, + INITIALISING = 16 + }; +--]] + +local flightModes = {} + +-- rover modes +flightModes[0]="" +flightModes[1]="Manual" +flightModes[2]="Acro" +flightModes[3]="" +flightModes[4]="Steering" +flightModes[5]="Hold" +flightModes[6]="Loiter" +flightModes[7]="Follow" +flightModes[8]="Simple" +flightModes[9]="" +flightModes[10]="" +flightModes[11]="Auto" +flightModes[12]="RTL" +flightModes[13]="SmartRTL" +flightModes[14]="" +flightModes[15]="" +flightModes[16]="Guided" +flightModes[17]="Initializing" +flightModes[18]="" +flightModes[19]="" +flightModes[20]="" +flightModes[21]="" +flightModes[22]="" +-- +return {flightModes=flightModes} diff --git a/HORUS/SOURCES/PP/main.lua b/HORUS/SOURCES/PP/main.lua deleted file mode 100644 index 08fd5721..00000000 --- a/HORUS/SOURCES/PP/main.lua +++ /dev/null @@ -1,2364 +0,0 @@ --- --- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios --- --- Copyright (C) 2018. Alessandro Apostoli --- https://github.com/yaapu --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- 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. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, see . --- --- Passthrough protocol reference: --- https://cdn.rawgit.com/ArduPilot/ardupilot_wiki/33cd0c2c/images/FrSky_Passthrough_protocol.xlsx --- --- Borrowed some code from the LI-xx BATTCHECK v3.30 script --- http://frskytaranis.forumactif.org/t2800-lua-download-un-testeur-de-batterie-sur-la-radio - ---------------------- --- script version ---------------------- - --- 480x272 LCD_WxLCD_H ---#define WIDGETDEBUG ---#define COMPILE ---#define SPLASH ---#define MEMDEBUG --- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 ---#define LOAD_LUA ---------------------- --- features ---------------------- ---#define HUD_ALGO1 ---#define BATTPERC_BY_VOLTAGE ---#define COMPASS_ROSE ---------------------- --- dev features ---------------------- ---#define LOGTELEMETRY ---#define DEBUG ---#define DEBUGEVT ---#define TESTMODE ---#define DEV ---#define DEBUGHUD - --- calc and show background function rate ---#define BGRATE --- calc and show run function rate ---#define FGRATE - --- calc and show hud refresh rate --- default for beta ---#define HUDRATE - ---#define HUDTIMER - --- calc and show telemetry process rate --- default for beta ---#define BGTELERATE - --- calc and show actual incoming telemetry rate ---#define TELERATE - --- - - - - - - - - - - - ---[[ - MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */ - MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */ - MAV_TYPE_QUADROTOR=2, /* Quadrotor | */ - MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */ - MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */ - MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */ - MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */ - MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */ - MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */ - MAV_TYPE_ROCKET=9, /* Rocket | */ - MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */ - MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */ - MAV_TYPE_SUBMARINE=12, /* Submarine | */ - MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */ - MAV_TYPE_OCTOROTOR=14, /* Octorotor | */ - MAV_TYPE_TRICOPTER=15, /* Tricopter | */ - MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */ - MAV_TYPE_KITE=17, /* Kite | */ - MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */ - MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */ - MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */ - MAV_TYPE_VTOL_TILTROTOR=21, /* Tiltrotor VTOL | */ - MAV_TYPE_VTOL_RESERVED2=22, /* VTOL reserved 2 | */ - MAV_TYPE_VTOL_RESERVED3=23, /* VTOL reserved 3 | */ - MAV_TYPE_VTOL_RESERVED4=24, /* VTOL reserved 4 | */ - MAV_TYPE_VTOL_RESERVED5=25, /* VTOL reserved 5 | */ - MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */ - MAV_TYPE_ADSB=27, /* Onboard ADSB peripheral | */ - MAV_TYPE_PARAFOIL=28, /* Steerable, nonrigid airfoil | */ - MAV_TYPE_DODECAROTOR=29, /* Dodecarotor | */ -]] -------------------------------------- --- UNITS Scales from Ardupilot OSD code /ardupilot/libraries/AP_OSD/AP_OSD_Screen.cpp -------------------------------------- ---[[ - static const float scale_metric[UNIT_TYPE_LAST] = { - 1.0, //ALTITUDE m - 3.6, //SPEED km/hr - 1.0, //VSPEED m/s - 1.0, //DISTANCE m - 1.0/1000, //DISTANCE_LONG km - 1.0, //TEMPERATURE C - }; - static const float scale_imperial[UNIT_TYPE_LAST] = { - 3.28084, //ALTITUDE ft - 2.23694, //SPEED mph - 3.28084, //VSPEED ft/s - 3.28084, //DISTANCE ft - 1.0/1609.34, //DISTANCE_LONG miles - 1.8, //TEMPERATURE F - }; - static const float scale_SI[UNIT_TYPE_LAST] = { - 1.0, //ALTITUDE m - 1.0, //SPEED m/s - 1.0, //VSPEED m/s - 1.0, //DISTANCE m - 1.0/1000, //DISTANCE_LONG km - 1.0, //TEMPERATURE C - }; - static const float scale_aviation[UNIT_TYPE_LAST] = { - 3.28084, //ALTITUDE Ft - 1.94384, //SPEED Knots - 196.85, //VSPEED ft/min - 3.28084, //DISTANCE ft - 0.000539957, //DISTANCE_LONG Nm - 1.0, //TEMPERATURE C - }; ---]]local frameNames = {} --- copter -frameNames[0] = "GEN" -frameNames[2] = "QUAD" -frameNames[3] = "COAX" -frameNames[4] = "HELI" -frameNames[13] = "HEX" -frameNames[14] = "OCTO" -frameNames[15] = "TRI" -frameNames[29] = "DODE" - --- plane -frameNames[1] = "WING" -frameNames[16] = "FLAP" -frameNames[19] = "VTOL2" -frameNames[20] = "VTOL4" -frameNames[21] = "VTOLT" -frameNames[22] = "VTOL" -frameNames[23] = "VTOL" -frameNames[24] = "VTOL" -frameNames[25] = "VTOL" -frameNames[28] = "FOIL" - --- rover -frameNames[10] = "ROV" --- boat -frameNames[11] = "BOAT" - -local currentModel = nil -local frameTypes = {} --- copter -frameTypes[0] = "c" -frameTypes[2] = "c" -frameTypes[3] = "c" -frameTypes[4] = "c" -frameTypes[13] = "c" -frameTypes[14] = "c" -frameTypes[15] = "c" -frameTypes[29] = "c" - --- plane -frameTypes[1] = "p" -frameTypes[16] = "p" -frameTypes[19] = "p" -frameTypes[20] = "p" -frameTypes[21] = "p" -frameTypes[22] = "p" -frameTypes[23] = "p" -frameTypes[24] = "p" -frameTypes[25] = "p" -frameTypes[28] = "p" - --- rover -frameTypes[10] = "r" --- boat -frameTypes[11] = "b" - --- flightmodes are loaded at run time -local soundFileBasePath = "/SOUNDS/yaapu0" -local gpsStatuses = {} - -gpsStatuses[0]="NoGPS" -gpsStatuses[1]="NoLock" -gpsStatuses[2]="2D" -gpsStatuses[3]="3D" -gpsStatuses[4]="DGPS" -gpsStatuses[5]="RTK" -gpsStatuses[6]="RTK" - ---[[ -0 MAV_SEVERITY_EMERGENCY System is unusable. This is a "panic" condition. -1 MAV_SEVERITY_ALERT Action should be taken immediately. Indicates error in non-critical systems. -2 MAV_SEVERITY_CRITICAL Action must be taken immediately. Indicates failure in a primary system. -3 MAV_SEVERITY_ERROR Indicates an error in secondary/redundant systems. -4 MAV_SEVERITY_WARNING Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. -5 MAV_SEVERITY_NOTICE An unusual event has occured, though not an error condition. This should be investigated for the root cause. -6 MAV_SEVERITY_INFO Normal operational messages. Useful for logging. No action is required for these messages. -7 MAV_SEVERITY_DEBUG Useful non-operational messages that can assist in debugging. These should not occur during normal operation. ---]] -local mavSeverity = {} -mavSeverity[0]="EMR" -mavSeverity[1]="ALR" -mavSeverity[2]="CRT" -mavSeverity[3]="ERR" -mavSeverity[4]="WRN" -mavSeverity[5]="NOT" -mavSeverity[6]="INF" -mavSeverity[7]="DBG" - --------------------------------- -local status = { - -- FLVSS 1 - cell1min = 0, - cell1sum = 0, - -- FLVSS 2 - cell2min = 0, - cell2sum = 0, - -- FC 1 - cell1sumFC = 0, - -- used to calculate cellcount - cell1maxFC = 0, - -- FC 2 - cell2sumFC = 0, - -- A2 - cellsumA2 = 0, - -- used to calculate cellcount - cellmaxA2 = 0, - -------------------------------- - -- AP STATUS - flightMode = 0, - simpleMode = 0, - landComplete = 0, - statusArmed = 0, - battFailsafe = 0, - ekfFailsafe = 0, - imuTemp = 0, - -- GPS - numSats = 0, - gpsStatus = 0, - gpsHdopC = 100, - gpsAlt = 0, - -- BATT - cellcount = 0, - battsource = "na", - -- BATT 1 - batt1volt = 0, - batt1current = 0, - batt1mah = 0, - batt1sources = { - a2 = false, - vs = false, - fc = false - }, - -- BATT 2 - batt2volt = 0, - batt2current = 0, - batt2mah = 0, - batt2sources = { - a2 = false, - vs = false, - fc = false - }, - -- TELEMETRY - noTelemetryData = 1, - -- HOME - homeDist = 0, - homeAlt = 0, - homeAngle = -1, - -- MESSAGES - msgBuffer = "", - lastMsgValue = 0, - lastMsgTime = 0, - -- VELANDYAW - vSpeed = 0, - hSpeed = 0, - yaw = 0, - -- SYNTH VSPEED SUPPORT - vspd = 0, - synthVSpeedTime = 0, - prevHomeAlt = 0, - -- ROLLPITCH - roll = 0, - pitch = 0, - range = 0, - -- PARAMS - frameType = -1, - batt1Capacity = 0, - batt2Capacity = 0, - -- FLIGHT TIME - lastTimerStart = 0, - timerRunning = 0, - flightTime = 0, - -- EVENTS - lastStatusArmed = 0, - lastGpsStatus = 0, - lastFlightMode = 0, - lastSimpleMode = 0, - -- battery levels - batLevel = 99, - battLevel1 = false, - battLevel2 = false, - lastBattLevel = 14, - -- messages - lastMessage = nil, - lastMessageSeverity = 0, - lastMessageCount = 1, - messageCount = 0, - messages = {} -} -local frame = {} --- -local backlightLastTime = 0 --- ---[[ - ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing - ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing - ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing - ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing -{ - 1 = notified, - 2 = alarm start, - 3 = armed, - 4 = type(0=min,1=max,2=timer,3=batt), - 5 = grace duration - 6 = ready - 7 = last alarm -} ---]]-- --- --- --- -local alarms = { - --{ notified, alarm_start, armed, type(0=min,1=max,2=timer,3=batt), grace, ready, last_alarm} - { false, 0 , false, 0, 0, false, 0}, --MIN_ALT - { false, 0 , true, 1 , 0, false, 0 }, --MAX_ALT - { false, 0 , true, 1 , 0, false, 0 }, --MAX_DIST - { false, 0 , true, 1 , 0, false, 0 }, --FS_EKF - { false, 0 , true, 1 , 0, false, 0 }, --FS_BAT - { false, 0 , true, 2, 0, false, 0 }, --FLIGTH_TIME - { false, 0 , false, 3, 4, false, 0 }, --BATT L1 - { false, 0 , false, 4, 4, false, 0 } --BATT L2 -} - --- -local paramId,paramValue --- -local batLevels = {0,5,10,15,20,25,30,40,50,60,70,80,90} --- dual battery -local showDualBattery = false --- -local bitmaps = {} -local blinktime = getTime() -local blinkon = false --- GPS -local function getTelemetryId(name) - local field = getFieldInfo(name) - return field and field.id or -1 -end --- -local gpsDataId = getTelemetryId("GPS") --- --- --- -local minmaxValues = {} --- min -minmaxValues[1] = 0 -minmaxValues[2] = 0 -minmaxValues[3] = 0 -minmaxValues[4] = 0 -minmaxValues[5] = 0 -minmaxValues[6] = 0 -minmaxValues[7] = 0 --- max -minmaxValues[8] = 0 -minmaxValues[9] = 0 -minmaxValues[10] = 0 -minmaxValues[11] = 0 -minmaxValues[12] = 0 -minmaxValues[13] = 0 -minmaxValues[14] = 0 -minmaxValues[15] = 0 -minmaxValues[16] = 0 -minmaxValues[17] = 0 - -local showMinMaxValues = false --- - --- - - - - - - - - - - - - - - - - - - - - - - - - - - - --- model and opentx version -local ver, radio, maj, minor, rev = getVersion() ------------------------------ --- clears the loaded table --- and recovers memory ------------------------------ -local function clearTable(t) - if type(t)=="table" then - for i,v in pairs(t) do - if type(v) == "table" then - clearTable(v) - end - t[i] = nil - end - end - collectgarbage() - maxmem = 0 -end --------------------------------------------------------------------------------- --- CONFIGURATION MENU --------------------------------------------------------------------------------- -local conf = { - language = "en", - defaultBattSource = nil, -- auto - battAlertLevel1 = 0, - battAlertLevel2 = 0, - battCapOverride1 = 0, - battCapOverride2 = 0, - disableAllSounds = false, - disableMsgBeep = false, - disableMsgBlink = false, - timerAlert = 0, - minAltitudeAlert = 0, - maxAltitudeAlert = 0, - maxDistanceAlert = 0, - cellCount = 0, - enableBattPercByVoltage = false, - rangeMax=0, - enableSynthVSpeed=false, - horSpeedMultiplier=1, - vertSpeedMultiplier=1 -} --------------------------------------------------------------------------------- --- MENU VALUE,COMBO --------------------------------------------------------------------------------- - - -local menu = { - selectedItem = 1, - editSelected = false, - offset = 0 -} - - - --- max 4 extra sensors -local customSensors = { - -- {label,name,prec:0,1,2,unit,stype:I,E,1} -} - -local menuItems = {} - -- label, type, alias, currval, min, max, label, flags, increment -menuItems[1] = {"voice language:", 1, "L1", 1, { "english", "italian", "french", "german" } , {"en","it","fr","de"} } -menuItems[2] = {"batt alert level 1:", 0, "V1", 375, 0,5000,"V", PREC2 ,5 } -menuItems[3] = {"batt alert level 2:", 0, "V2", 350, 0,5000,"V", PREC2 ,5 } -menuItems[4] = {"batt[1] capacity override:", 0, "B1", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[5] = {"batt[2] capacity override:", 0, "B2", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[6] = {"disable all sounds:", 1, "S1", 1, { "no", "yes" }, { false, true } } -menuItems[7] = {"disable msg beep:", 1, "S2", 1, { "no", "yes" }, { false, true } } -menuItems[8] = {"disable msg blink:", 1, "S3", 1, { "no", "yes" }, { false, true } } -menuItems[9] = {"default voltage source:", 1, "VS", 1, { "auto", "FLVSS", "A2", "fc" }, { nil, "vs", "a2", "fc" } } -menuItems[10] = {"timer alert every:", 0, "T1", 0, 0,600,"min",PREC1,5 } -menuItems[11] = {"min altitude alert:", 0, "A1", 0, 0,500,"m",PREC1,5 } -menuItems[12] = {"max altitude alert:", 0, "A2", 0, 0,10000,"m",0,1 } -menuItems[13] = {"max distance alert:", 0, "D1", 0, 0,100000,"m",0,10 } -menuItems[14] = {"repeat alerts every:", 0, "T2", 10, 5,600,"sec",0,5 } -menuItems[15] = {"cell count override:", 0, "CC", 0, 0,12,"cells",0,1 } -menuItems[16] = {"rangefinder max:", 0, "RM", 0, 0,10000," cm",0,10 } -menuItems[17] = {"enable synthetic vspeed:", 1, "SVS", 1, { "no", "yes" }, { false, true } } -menuItems[18] = {"air/groundspeed unit:", 1, "HSPD", 1, { "m/s", "km/h", "mph", "kn" }, { 1, 3.6, 2.23694, 1.94384} } -menuItems[19] = {"vertical speed unit:", 1, "VSPD", 1, { "m/s", "ft/s", "ft/min" }, { 1, 3.28084, 196.85} } --- - - -local unitScale, unitlabel - - - -local currentPage = 0 - -local function getConfigFilename() - local info = model.getInfo() - return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".cfg") -end - -local function getBitmap(name) - if bitmaps[name] == nil then - bitmaps[name] = Bitmap.open("/SCRIPTS/YAAPU/IMAGES/"..name..".png") - end - return bitmaps[name] -end - -local function applyConfigValues() - conf.language = menuItems[1][6][menuItems[1][4]] - conf.battAlertLevel1 = menuItems[2][4] - conf.battAlertLevel2 = menuItems[3][4] - conf.battCapOverride1 = menuItems[4][4]*0.1 - conf.battCapOverride2 = menuItems[5][4]*0.1 - conf.disableAllSounds = menuItems[6][6][menuItems[6][4]] - conf.disableMsgBeep = menuItems[7][6][menuItems[7][4]] - conf.disableMsgBlink = menuItems[8][6][menuItems[8][4]] - conf.defaultBattSource = menuItems[9][6][menuItems[9][4]] - conf.timerAlert = math.floor(menuItems[10][4]*0.1*60) - conf.minAltitudeAlert = menuItems[11][4]*0.1 - conf.maxAltitudeAlert = menuItems[12][4] - conf.maxDistanceAlert = menuItems[13][4] - conf.cellCount = menuItems[15][4] - conf.rangeMax = menuItems[16][4] - conf.enableSynthVSpeed = menuItems[17][6][menuItems[17][4]] - conf.horSpeedMultiplier = menuItems[18][6][menuItems[18][4]] - conf.vertSpeedMultiplier = menuItems[19][6][menuItems[19][4]] - -- - if conf.defaultBattSource ~= nil then - status.battsource = conf.defaultBattSource - end -end - -local function loadConfig() - local cfg = io.open(getConfigFilename(),"r") - if cfg == nil then - return - end - local str = io.read(cfg,200) - if string.len(str) > 0 then - for i=1,#menuItems - do - local value = string.match(str, menuItems[i][3]..":(%d+)") - if value ~= nil then - menuItems[i][4] = tonumber(value) - end - end - end - if cfg ~= nil then - io.close(cfg) - end - applyConfigValues() -end - -local function saveConfig() - local cfg = assert(io.open(getConfigFilename(),"w")) - if cfg == nil then - return - end - for i=1,#menuItems - do - io.write(cfg,menuItems[i][3],":",menuItems[i][4]) - if i < #menuItems then - io.write(cfg,",") - end - end - if cfg ~= nil then - io.close(cfg) - end - applyConfigValues() -end - --- -local function lcdBacklightOn() - model.setGlobalVariable(8,0,1) - backlightLastTime = getTime()/100 -- seconds -end --- -local function playSound(soundFile) - if conf.disableAllSounds then - return - end - lcdBacklightOn() - playFile(soundFileBasePath .."/"..conf.language.."/".. soundFile..".wav") -end - ----------------------------------------------- --- sound file has same name as flightmode all lowercase with .wav extension ----------------------------------------------- -local function playSoundByFrameTypeAndFlightMode(flightMode) - if conf.disableAllSounds then - return - end - if frame.flightModes then - if frame.flightModes[flightMode] ~= nil then - lcdBacklightOn() - playFile(soundFileBasePath.."/"..conf.language.."/".. string.lower(frame.flightModes[flightMode])..".wav") - end - end -end - -local function drawHArrow(x,y,width,left,right) - lcd.drawLine(x, y, x + width,y, SOLID, 0) - if left == true then - lcd.drawLine(x + 1,y - 1,x + 2,y - 2, SOLID, 0) - lcd.drawLine(x + 1,y + 1,x + 2,y + 2, SOLID, 0) - end - if right == true then - lcd.drawLine(x + width - 1,y - 1,x + width - 2,y - 2, SOLID, 0) - lcd.drawLine(x + width - 1,y + 1,x + width - 2,y + 2, SOLID, 0) - end -end --- -local function drawBlinkBitmap(bitmap,x,y) - if blinkon == true then - lcd.drawBitmap(getBitmap(bitmap),x,y) - end -end --- -local function drawVArrow(x,y,h,top,bottom) - if top == true then - drawBlinkBitmap("uparrow",x,y) - else - drawBlinkBitmap("downarrow",x,y) - end -end - -local function drawHomeIcon(x,y) - lcd.drawBitmap(getBitmap("minihomeorange"),x,y) -end - -local function drawLine(x1,y1,x2,y2,flags1,flags2) - -- if lines are hor or ver do not fix ---if string.find(radio, "x10") and rev < 2 and x1 ~= x2 and y1 ~= y2 then - if string.find(radio, "x10") and rev < 2 then - lcd.drawLine(LCD_W-x1,LCD_H-y1,LCD_W-x2,LCD_H-y2,flags1,flags2) - else - lcd.drawLine(x1,y1,x2,y2,flags1,flags2) - end -end - - -local function computeOutCode(x,y,xmin,ymin,xmax,ymax) - local code = 0; --initialised as being inside of hud - -- - if x < xmin then --to the left of hud - code = bit32.bor(code,1); - elseif x > xmax then --to the right of hud - code = bit32.bor(code,2); - end - if y < ymin then --below the hud - code = bit32.bor(code,4); - elseif y > ymax then --above the hud - code = bit32.bor(code,8); - end - -- - return code; -end - --- Cohen–Sutherland clipping algorithm --- https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm -local function drawLineWithClipping(ox,oy,angle,len,style,xmin,xmax,ymin,ymax,color) - -- - local xx = math.cos(math.rad(angle)) * len * 0.5 - local yy = math.sin(math.rad(angle)) * len * 0.5 - -- - local x0 = ox - xx - local x1 = ox + xx - local y0 = oy - yy - local y1 = oy + yy - -- compute outcodes for P0, P1, and whatever point lies outside the clip rectangle - local outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax); - local outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); - local accept = false; - - while (true) do - if ( bit32.bor(outcode0,outcode1) == 0) then - -- bitwise OR is 0: both points inside window; trivially accept and exit loop - accept = true; - break; - elseif (bit32.band(outcode0,outcode1) ~= 0) then - -- bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP, BOTTOM) - -- both must be outside window; exit loop (accept is false) - break; - else - -- failed both tests, so calculate the line segment to clip - -- from an outside point to an intersection with clip edge - local x = 0 - local y = 0 - -- At least one endpoint is outside the clip rectangle; pick it. - local outcodeOut = outcode0 ~= 0 and outcode0 or outcode1 - -- No need to worry about divide-by-zero because, in each case, the - -- outcode bit being tested guarantees the denominator is non-zero - if bit32.band(outcodeOut,8) ~= 0 then --point is above the clip window - x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0) - y = ymax - elseif bit32.band(outcodeOut,4) ~= 0 then --point is below the clip window - x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0) - y = ymin - elseif bit32.band(outcodeOut,2) ~= 0 then --point is to the right of clip window - y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0) - x = xmax - elseif bit32.band(outcodeOut,1) ~= 0 then --point is to the left of clip window - y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0) - x = xmin - end - -- Now we move outside point to intersection point to clip - -- and get ready for next pass. - if outcodeOut == outcode0 then - x0 = x - y0 = y - outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax) - else - x1 = x - y1 = y - outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax) - end - end - end - if accept then - drawLine(x0,y0,x1,y1, style,color) - end -end - - -local function drawNumberWithTwoDims(x,y,xDim,yTop,yBottom,number,topDim,bottomDim,flags,topFlags,bottomFlags) - --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) - lcd.drawNumber(x, y, number + 0.5, flags) - local lx = xDim - lcd.drawText(lx, yTop, topDim, topFlags) - lcd.drawText(lx, yBottom, bottomDim, bottomFlags) -end - -local function drawNumberWithDim(x,y,xDim,yDim,number,dim,flags,dimFlags) - lcd.drawNumber(x, y, number,flags) - lcd.drawText(xDim, yDim, dim, dimFlags) -end - --- --- -local function formatMessage(severity,msg) - if status.lastMessageCount > 1 then - return string.format("%02d:%s (x%d) %s", status.messageCount, mavSeverity[severity], status.lastMessageCount, msg) - else - return string.format("%02d:%s %s", status.messageCount, mavSeverity[severity], msg) - end -end - -local function pushMessage(severity, msg) - if conf.disableMsgBeep == false and conf.disableAllSounds == false then - if ( severity < 5) then - playSound("../err") - else - playSound("../inf") - end - end - -- check if wrapping is needed - if #status.messages == 17 and msg ~= status.lastMessage then - for i=1,17-1 do - status.messages[i]=status.messages[i+1] - end - -- trunc at 9 - status.messages[17] = nil - end - -- is it a duplicate? - if msg == status.lastMessage then - status.lastMessageCount = status.lastMessageCount + 1 - status.messages[#status.messages] = formatMessage(severity,msg) - else - status.lastMessageCount = 1 - status.messageCount = status.messageCount + 1 - status.messages[#status.messages+1] = formatMessage(severity,msg) - end - status.lastMessage = msg - status.lastMessageSeverity = severity -end - --- -local function startTimer() - status.lastTimerStart = getTime()/100 - model.setTimer(2,{mode=1}) -end - -local function stopTimer() - model.setTimer(2,{mode=0}) - status.lastTimerStart = 0 -end - - ------------------------------------------------------------------ --- TELEMETRY ------------------------------------------------------------------ --- -local function processTelemetry() - local SENSOR_ID,FRAME_ID,DATA_ID,VALUE = sportTelemetryPop() - if ( FRAME_ID == 0x10) then - status.noTelemetryData = 0 - if ( DATA_ID == 0x5006) then -- ROLLPITCH - -- roll [0,1800] ==> [-180,180] - status.roll = (math.min(bit32.extract(VALUE,0,11),1800) - 900) * 0.2 - -- pitch [0,900] ==> [-90,90] - status.pitch = (math.min(bit32.extract(VALUE,11,10),900) - 450) * 0.2 - -- #define ATTIANDRNG_RNGFND_OFFSET 21 - -- number encoded on 11 bits: 10 bits for digits + 1 for 10^power - status.range = bit32.extract(VALUE,22,10) * (10^bit32.extract(VALUE,21,1)) -- cm - elseif ( DATA_ID == 0x5005) then -- VELANDYAW - status.vSpeed = bit32.extract(VALUE,1,7) * (10^bit32.extract(VALUE,0,1)) * (bit32.extract(VALUE,8,1) == 1 and -1 or 1)-- dm/s - status.hSpeed = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) -- dm/s - status.yaw = bit32.extract(VALUE,17,11) * 0.2 - elseif ( DATA_ID == 0x5001) then -- AP STATUS - status.flightMode = bit32.extract(VALUE,0,5) - status.simpleMode = bit32.extract(VALUE,5,2) - status.landComplete = bit32.extract(VALUE,7,1) - status.statusArmed = bit32.extract(VALUE,8,1) - status.battFailsafe = bit32.extract(VALUE,9,1) - status.ekfFailsafe = bit32.extract(VALUE,10,2) - -- IMU temperature: 0 means temp =< 19°, 63 means temp => 82° - status.imuTemp = bit32.extract(VALUE,26,6) + 19 -- C° - elseif ( DATA_ID == 0x5002) then -- GPS STATUS - status.numSats = bit32.extract(VALUE,0,4) - -- offset 4: NO_GPS = 0, NO_FIX = 1, GPS_OK_FIX_2D = 2, GPS_OK_FIX_3D or GPS_OK_FIX_3D_DGPS or GPS_OK_FIX_3D_RTK_FLOAT or GPS_OK_FIX_3D_RTK_FIXED = 3 - -- offset 14: 0: no advanced fix, 1: GPS_OK_FIX_3D_DGPS, 2: GPS_OK_FIX_3D_RTK_FLOAT, 3: GPS_OK_FIX_3D_RTK_FIXED - status.gpsStatus = bit32.extract(VALUE,4,2) + bit32.extract(VALUE,14,2) - status.gpsHdopC = bit32.extract(VALUE,7,7) * (10^bit32.extract(VALUE,6,1)) -- dm - status.gpsAlt = bit32.extract(VALUE,24,7) * (10^bit32.extract(VALUE,22,2)) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1)-- dm - elseif ( DATA_ID == 0x5003) then -- BATT - status.batt1volt = bit32.extract(VALUE,0,9) - status.batt1current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) - status.batt1mah = bit32.extract(VALUE,17,15) - elseif ( DATA_ID == 0x5008) then -- BATT2 - status.batt2volt = bit32.extract(VALUE,0,9) - status.batt2current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) - status.batt2mah = bit32.extract(VALUE,17,15) - elseif ( DATA_ID == 0x5004) then -- HOME - status.homeDist = bit32.extract(VALUE,2,10) * (10^bit32.extract(VALUE,0,2)) - status.homeAlt = bit32.extract(VALUE,14,10) * (10^bit32.extract(VALUE,12,2)) * 0.1 * (bit32.extract(VALUE,24,1) == 1 and -1 or 1) - status.homeAngle = bit32.extract(VALUE, 25, 7) * 3 - elseif ( DATA_ID == 0x5000) then -- MESSAGES - if (VALUE ~= status.lastMsgValue) then - status.lastMsgValue = VALUE - local c1 = bit32.extract(VALUE,0,7) - local c2 = bit32.extract(VALUE,8,7) - local c3 = bit32.extract(VALUE,16,7) - local c4 = bit32.extract(VALUE,24,7) - -- - local msgEnd = false - -- - if (c4 ~= 0) then - status.msgBuffer = status.msgBuffer .. string.char(c4) - else - msgEnd = true; - end - if (c3 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c3) - else - msgEnd = true; - end - if (c2 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c2) - else - msgEnd = true; - end - if (c1 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c1) - else - msgEnd = true; - end - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x4)<<21; - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x2)<<14; - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x1)<<7; - if (msgEnd) then - local severity = (bit32.extract(VALUE,7,1) * 1) + (bit32.extract(VALUE,15,1) * 2) + (bit32.extract(VALUE,23,1) * 4) - pushMessage( severity, status.msgBuffer) - status.msgBuffer = "" - end - end - elseif ( DATA_ID == 0x5007) then -- PARAMS - paramId = bit32.extract(VALUE,24,4) - paramValue = bit32.extract(VALUE,0,24) - if paramId == 1 then - status.frameType = paramValue - elseif paramId == 4 then - status.batt1Capacity = paramValue - elseif paramId == 5 then - status.batt2Capacity = paramValue - end - end - end -end - -local function telemetryEnabled() - if getRSSI() == 0 then - status.noTelemetryData = 1 - end - return status.noTelemetryData == 0 -end - -local function getMaxValue(value,idx) - minmaxValues[idx] = math.max(value,minmaxValues[idx]) - return showMinMaxValues == true and minmaxValues[idx] or value -end - -local function calcMinValue(value,min) - return min == 0 and value or math.min(value,min) -end - --- returns the actual minimun only if both are > 0 -local function getNonZeroMin(v1,v2) - return v1 == 0 and v2 or ( v2 == 0 and v1 or math.min(v1,v2)) -end - - - -local function calcCellCount() - -- cellcount override from menu - if conf.cellCount ~= nil and conf.cellCount > 0 then - return conf.cellCount - end - -- cellcount is cached only for FLVSS - if status.batt1sources.vs == true and status.cellcount > 1 then - return status.cellcount - end - -- round in excess and return - -- Note: cellcount is not cached because max voltage can rise during initialization) - return math.floor( (( math.max(status.cell1maxFC,status.cellmaxA2)*0.1 ) / 4.35) + 1) -end - -local function calcBattery() - ------------ - -- FLVSS 1 - ------------ - local cellResult = getValue("Cels") - if type(cellResult) == "table" then - status.cell1min = 4.35 - status.cell1sum = 0 - -- cellcount is global and shared - status.cellcount = #cellResult - for i, v in pairs(cellResult) do - status.cell1sum = status.cell1sum + v - if status.cell1min > v then - status.cell1min = v - end - end - -- if connected after scritp started - if status.batt1sources.vs == false then - status.battsource = "na" - end - if status.battsource == "na" then - status.battsource = "vs" - end - status.batt1sources.vs = true - else - status.batt1sources.vs = false - status.cell1min = 0 - status.cell1sum = 0 - end - ------------ - -- FLVSS 2 - ------------ - cellResult = getValue("Cel2") - if type(cellResult) == "table" then - status.cell2min = 4.35 - status.cell2sum = 0 - -- cellcount is global and shared - status.cellcount = #cellResult - for i, v in pairs(cellResult) do - status.cell2sum = status.cell2sum + v - if status.cell2min > v then - status.cell2min = v - end - end - -- if connected after scritp started - if status.batt2sources.vs == false then - status.battsource = "na" - end - if status.battsource == "na" then - status.battsource = "vs" - end - status.batt2sources.vs = true - else - status.batt2sources.vs = false - status.cell2min = 0 - status.cell2sum = 0 - end - -------------------------------- - -- flight controller battery 1 - -------------------------------- - if status.batt1volt > 0 then - status.cell1sumFC = status.batt1volt*0.1 - status.cell1maxFC = math.max(status.batt1volt,status.cell1maxFC) - if status.battsource == "na" then - status.battsource = "fc" - end - status.batt1sources.fc = true - else - status.batt1sources.fc = false - status.cell1sumFC = 0 - end - -------------------------------- - -- flight controller battery 2 - -------------------------------- - if status.batt2volt > 0 then - status.cell2sumFC = status.batt2volt*0.1 - if status.battsource == "na" then - status.battsource = "fc" - end - status.batt2sources.fc = true - else - status.batt2sources.fc = false - status.cell2sumFC = 0 - end - ---------------------------------- - -- 12 analog voltage only 1 supported - ---------------------------------- - local battA2 = getValue("A2") - -- - if battA2 > 0 then - status.cellsumA2 = battA2 - status.cellmaxA2 = math.max(battA2*10,status.cellmaxA2) - status.batt1sources.a2 = true - else - status.batt1sources.a2 = false - status.cellsumA2 = 0 - end - -- batt fc - minmaxValues[1] = calcMinValue(status.cell1sumFC,minmaxValues[1]) - minmaxValues[2] = calcMinValue(status.cell2sumFC,minmaxValues[2]) - -- cell flvss - minmaxValues[3] = calcMinValue(status.cell1min,minmaxValues[3]) - minmaxValues[4] = calcMinValue(status.cell2min,minmaxValues[4]) - -- batt flvss - minmaxValues[5] = calcMinValue(status.cell1sum,minmaxValues[5]) - minmaxValues[6] = calcMinValue(status.cell2sum,minmaxValues[6]) - -- batt 12 - minmaxValues[7] = calcMinValue(status.cellsumA2,minmaxValues[7]) -end - -local function checkLandingStatus() - if ( status.timerRunning == 0 and status.landComplete == 1 and status.lastTimerStart == 0) then - startTimer() - end - if (status.timerRunning == 1 and status.landComplete == 0 and status.lastTimerStart ~= 0) then - stopTimer() - if status.statusArmed == 1 then - playSound("landing") - end - end - status.timerRunning = status.landComplete -end - -local initLib = {} -local initFile = "/SCRIPTS/YAAPU/LIB/init.luac" - -local function reset() - -- initialize status - if initLib.resetWidget == nil then - initLib = dofile(initFile) - end - -- reset frame - clearTable(frame.frameTypes) - -- reset widget pages - currentPage = 0 - showMinMaxValues = false - showDualBattery = false - -- - frame = {} - -- reset all - initLib.resetTelemetry(status,alarms,pushMessage,clearTable) - -- release resources - clearTable(initLib) - -- load model config - loadConfig() - -- done - playSound("yaapu") -end - -local function calcFlightTime() - -- update local variable with timer 3 value - if ( model.getTimer(2).value < status.flightTime and status.statusArmed == 0) then - reset() - end - if (model.getTimer(2).value < status.flightTime and status.statusArmed == 1) then - model.setTimer(2,{value=status.flightTime}) - pushMessage(3,"timer reset ignored while armed") - end - status.flightTime = model.getTimer(2).value -end - -local function getBatt1Capacity() - return conf.battCapOverride1 > 0 and conf.battCapOverride1*100 or status.batt1Capacity -end - -local function getBatt2Capacity() - return conf.battCapOverride2 > 0 and conf.battCapOverride2*100 or status.batt2Capacity -end - --- gets the voltage based on source and min value, battId = [1|2] -local function getMinVoltageBySource(source,cell,cellFC,cellA2,battId,count) - -- offset 0 for cell voltage, 2 for pack voltage - local offset = 0 - -- - if cell > 4.35*2 or cellFC > 4.35*2 or cellA2 > 4.35*2 then - offset = 2 - end - -- - if source == "vs" then - return showMinMaxValues == true and minmaxValues[2+offset+battId] or cell - elseif source == "fc" then - -- FC only tracks batt1 and batt2 no cell voltage tracking - local minmax = (offset == 2 and minmaxValues[battId] or minmaxValues[battId]/count) - return showMinMaxValues == true and minmax or cellFC - elseif source == "a2" then - -- 12 does not depend on battery id - local minmax = (offset == 2 and minmaxValues[7] or minmaxValues[7]/count) - return showMinMaxValues == true and minmax or cellA2 - end - -- - return 0 -end - -local sensors = { - {0x060F, 0, 0,0, 13 , 0 , "Fuel" }, - {0x021F, 0, 0,0, 1 , 2 , "VFAS"}, - {0x020F, 0, 0,0, 2 , 1 , "CURR"}, - {0x011F, 0, 0,0, 5 , 1 , "VSpd"}, - {0x083F, 0, 0,0, 5 , 0 , "GSpd"}, - {0x010F, 0, 0,0, 9 , 1 , "Alt"}, - {0x082F, 0, 0,0, 9 , 0 , "GAlt"}, - {0x084F, 0, 0,0, 20 , 0 , "Hdg"}, - {0x041F, 0, 0,0, 11 , 0 , "IMUt"}, - {0x060F, 0, 1,0, 0 , 0 , "ARM"} -} - -local function setSensorValues() - if (not telemetryEnabled()) then - return - end - local battmah = status.batt1mah - local battcapacity = getBatt1Capacity() - if status.batt2mah > 0 then - battcapacity = getBatt1Capacity() + getBatt2Capacity() - battmah = status.batt1mah + status.batt2mah - end - local perc = 0 - if (battcapacity > 0) then - perc = (1 - (battmah/battcapacity))*100 - if perc > 99 then - perc = 99 - elseif perc < 0 then - perc = 0 - end - end - -- - sensors[1][4] = perc; - sensors[2][4] = getNonZeroMin(status.batt1volt,status.batt2volt)*10; - sensors[3][4] = status.batt1current+status.batt2current; - sensors[4][4] = status.vSpeed; - sensors[5][4] = status.hSpeed*0.1; - sensors[6][4] = status.homeAlt*10; - sensors[7][4] = math.floor(status.gpsAlt*0.1); - sensors[8][4] = math.floor(status.yaw); - sensors[9][4] = status.imuTemp; - sensors[10][4] = status.statusArmed*100; - -- - for s=1,#sensors - do - setTelemetryValue(sensors[s][1], sensors[s][2], sensors[s][3], sensors[s][4], sensors[s][5] , sensors[s][6] , sensors[s][7]) - end -end - --------------------- --- Single long function much more memory efficient than many little functions ---------------------- -local function drawBatteryPane(x,battVolt,cellVolt,current,battmah,battcapacity) - local perc = 0 - if (battcapacity > 0) then - perc = (1 - (battmah/battcapacity))*100 - if perc > 99 then - perc = 99 - elseif perc < 0 then - perc = 0 - end - end - -- battery min cell - local flags = 0 - -- - if showMinMaxValues == false then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) -- white - if status.battLevel2 == false and alarms[8][2] > 0 then - drawBlinkBitmap("cell_red",x+33 - 4,13 + 8) - lcdBacklightOn() - elseif status.battLevel2 == true then - lcd.drawBitmap(getBitmap("cell_red"),x+33 - 4,13 + 8) - elseif status.battLevel1 == false and alarms[7][2] > 0 then - drawBlinkBitmap("cell_orange",x+33 - 4,13 + 8) - lcdBacklightOn() - elseif status.battLevel1 == true then - lcd.drawBitmap(getBitmap("cell_orange"),x+33 - 4,13 + 8) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 0, 0)) -- black - end - flags = CUSTOM_COLOR - end - drawNumberWithTwoDims(x+33, 13,x+171, 23, 60,cellVolt,"V",status.battsource,XXLSIZE+PREC2+flags,flags,flags) - -- battery voltage - drawNumberWithDim(x+100,164,x+95, 159, battVolt,"V",DBLSIZE+PREC1+RIGHT,SMLSIZE) - -- battery current - drawNumberWithDim(x+192,164,x+186,159,current,"A",DBLSIZE+PREC1+RIGHT,SMLSIZE) - -- display capacity bar % - if perc > 50 then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) - elseif perc <= 50 and perc > 25 then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow - else - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) - end - lcd.drawBitmap(getBitmap("gauge_bg"),x+29-2,109-2) - lcd.drawGauge(x+29, 109,160,23,perc,100,CUSTOM_COLOR) - -- battery percentage - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 0, 0)) -- black - local strperc = string.format("%02d%%",perc) - lcd.drawText(x+90, 108, strperc, MIDSIZE+CUSTOM_COLOR) - -- battery mah - local strmah = string.format("%.02f/%.01f",battmah/1000,battcapacity/1000) - lcd.drawText(x+185, 136+6, "Ah", RIGHT) - lcd.drawText(x+185 - 22, 136, strmah, MIDSIZE+RIGHT) - if showMinMaxValues == true then - drawVArrow(x+33+140, 13 + 27,6,false,true) - drawVArrow(x+100-2,164 + 10, 5,false,true) - drawVArrow(x+192-5,164 + 10,5,true,false) - end -end - -local function drawNoTelemetryData() - -- no telemetry data - if (not telemetryEnabled()) then - lcd.drawFilledRectangle(75,90, 330, 100, TITLE_BGCOLOR) - lcd.drawText(140, 120, "no telemetry data", MIDSIZE+INVERS) - lcd.drawText(130, 160, "Yaapu Telemetry Script 1.7.4", SMLSIZE+INVERS) - end -end - -local function drawFlightMode() - -- flight mode - if frame.flightModes then - local strMode = frame.flightModes[status.flightMode] - if strMode ~= nil then - if ( status.simpleMode > 0 ) then - local strSimpleMode = status.simpleMode == 1 and "(S)" or "(SS)" - strMode = string.format("%s%s",strMode,strSimpleMode) - end - lcd.drawText(2 + 2, 218, strMode, MIDSIZE) - end - end - lcd.drawLine(2 + 2,218, 2 + 150,218, SOLID,0) - lcd.drawText(2 + 2,218 - 16,"Flight Mode",SMLSIZE) -end - -local function drawTopBar() - -- black bar - lcd.drawFilledRectangle(0,0, LCD_W, 20, TITLE_BGCOLOR) - -- frametype and model name - local info = model.getInfo() - -- model change event - if currentModel ~= info.name then - currentModel = info.name - reset() - end - local fn = frameNames[status.frameType] - local strmodel = info.name - if fn ~= nil then - strmodel = fn..": "..info.name - end - lcd.drawText(2, 0, strmodel, MENU_TITLE_COLOR) - -- flight time - local time = getDateTime() - local strtime = string.format("%02d:%02d:%02d",time.hour,time.min,time.sec) - lcd.drawText(LCD_W, 0+4, strtime, SMLSIZE+RIGHT+MENU_TITLE_COLOR) - -- RSSI - lcd.drawText(265, 0, "RS:", 0 +MENU_TITLE_COLOR) - lcd.drawText(265 + 30,0, getRSSI(), 0 +MENU_TITLE_COLOR) - -- tx voltage - local vtx = string.format("Tx:%.1fv",getValue(getFieldInfo("tx-voltage").id)) - lcd.drawText(330,0, vtx, 0+MENU_TITLE_COLOR) -end - -local function drawFlightTime() - -- flight time - lcd.drawText(330, 202, "Flight Time", SMLSIZE) - lcd.drawLine(330,202 + 16, 330 + 140,202 + 16, SOLID,0) - lcd.drawTimer(330, 202 + 14, model.getTimer(2).value, DBLSIZE) -end - -local function drawScreenTitle(title,page, pages) - lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, title, MENU_TITLE_COLOR) - lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) -end - -local function drawBottomBar() - -- black bar - lcd.drawFilledRectangle(0,LCD_H - 20, LCD_W, 20, TITLE_BGCOLOR) - -- message text - local now = getTime() - local msg = status.messages[#status.messages] - if (now - status.lastMsgTime ) > 150 or conf.disableMsgBlink then - lcd.drawText(2, LCD_H - 20 + 1, msg,MENU_TITLE_COLOR) - else - lcd.drawText(2, LCD_H - 20 + 1, msg,INVERS+BLINK+MENU_TITLE_COLOR) - end -end - -local function drawAllMessages() - for i=1,#status.messages do - lcd.drawText(1,16*(i-1), status.messages[i],SMLSIZE) - end -end - -local function drawGPSStatus() - -- gps status - local strStatus = gpsStatuses[status.gpsStatus] - local flags = BLINK - local mult = 1 - local gpsData = nil - local hdop = status.gpsHdopC - if status.gpsStatus > 2 then - if status.homeAngle ~= -1 then - flags = PREC1 - end - if hdop > 999 then - hdop = 999 - flags = 0 - mult=0.1 - elseif hdop > 99 then - flags = 0 - mult=0.1 - end - lcd.drawText(2 -1,22 - 3, strStatus, SMLSIZE) - lcd.drawText(2 -1,22 + 16 - 3, "fix", 0) - if status.numSats == 15 then - lcd.drawNumber(2 + 80, 22 + 4 , status.numSats, DBLSIZE+RIGHT) - lcd.drawText(2 + 89, 22 + 19, "+", RIGHT) - else - lcd.drawNumber(2 + 87, 22 + 4 , status.numSats, DBLSIZE+RIGHT) - end - -- - lcd.drawText(2 + 94, 22-3, "hd", SMLSIZE) - lcd.drawNumber(2 + 166, 22 + 4, hdop*mult , DBLSIZE+flags+RIGHT) - -- - lcd.drawLine(2 + 91,22 ,2+91,22 + 36,SOLID,0) - -- - gpsData = getValue("GPS") - -- - if type(gpsData) == "table" and gpsData.lat ~= nil and gpsData.lon ~= nil then - lcd.drawText(2 ,22 + 38,math.floor(gpsData.lat * 100000) / 100000,SMLSIZE) - lcd.drawText(165 ,22 + 38,math.floor(gpsData.lon * 100000) / 100000,SMLSIZE+RIGHT) - end - lcd.drawLine(2 ,22 + 37,2+160,22 + 37,SOLID,0) - lcd.drawLine(2 ,22 + 54,2+160,22 + 54,SOLID,0) - elseif status.gpsStatus == 0 then - drawBlinkBitmap("nogpsicon",4,24) - else - drawBlinkBitmap("nolockicon",4,24) - end -end - -local function drawLeftPane(battcurrent,cellsumFC) - if conf.rangeMax > 0 then - flags = 0 - local rng = status.range - if rng > conf.rangeMax then - flags = BLINK+INVERS - end - rng = getMaxValue(rng,17) - if showMinMaxValues == true then - flags = 0 - end - lcd.drawText(10, 95, "Range("..unitLabel..")", SMLSIZE) - lcd.drawText(75, 112, string.format("%.1f",rng*0.01*unitScale), MIDSIZE+flags+RIGHT) - else - flags = BLINK - -- always display gps altitude even without 3d lock - local alt = status.gpsAlt/10 - if status.gpsStatus > 2 then - flags = 0 - -- update max only with 3d or better lock - alt = getMaxValue(alt,13) - end - if showMinMaxValues == true then - flags = 0 - end - lcd.drawText(10, 95, "AltAsl("..unitLabel..")", SMLSIZE) - local stralt = string.format("%d",alt*unitScale) - lcd.drawText(75, 112, stralt, MIDSIZE+flags+RIGHT) - end - -- home distance - drawHomeIcon(91,95,7) - lcd.drawText(165, 95, "Dist("..unitLabel..")", SMLSIZE+RIGHT) - flags = 0 - if status.homeAngle == -1 then - flags = BLINK - end - local dist = getMaxValue(status.homeDist,16) - if showMinMaxValues == true then - flags = 0 - end - local strdist = string.format("%d",dist*unitScale) - lcd.drawText(165, 112, strdist, MIDSIZE+flags+RIGHT) - -- hspeed - local speed = getMaxValue(status.hSpeed,15) - lcd.drawText(81, 152, "Spd("..menuItems[18][5][menuItems[18][4]]..")", SMLSIZE+RIGHT) - lcd.drawNumber(80,170,speed * menuItems[18][6][menuItems[18][4]],MIDSIZE+RIGHT+PREC1) - -- power - --[[ - local power = cellsumFC*battcurrent*0.1 - power = getMaxValue(power,MAX_POWER) - lcd.drawText(BATTPOWER_X, BATTPOWER_Y, "Power(W)", BATTPOWER_FLAGS+RIGHT) - lcd.drawNumber(BATTPOWER_X,BATTPOWER_YW,power,BATTPOWER_FLAGSW+RIGHT) - --]] -- - local eff = speed > 2 and battcurrent*1000/(speed*menuItems[18][6][menuItems[18][4]]) or 0 - lcd.drawText(165, 152, "Eff(mAh)", SMLSIZE+RIGHT) - lcd.drawNumber(165,170,eff,MIDSIZE+RIGHT) - -- - if showMinMaxValues == true then - drawVArrow(75-81, 112,6,true,false) - drawVArrow(165-78, 112 ,6,true,false) - drawVArrow(55-60,170,6,true,false) - drawVArrow(165-78, 170, 5,true,false) - end -end - -local function drawFailsafe() - if status.ekfFailsafe > 0 then - drawBlinkBitmap("ekffailsafe",LCD_W/2 - 90,180) - end - if status.battFailsafe > 0 then - drawBlinkBitmap("battfailsafe",LCD_W/2 - 90,180) - end -end - -local function drawArmStatus() - -- armstatus - if status.ekfFailsafe == 0 and status.battFailsafe == 0 and status.timerRunning == 0 then - if (status.statusArmed == 1) then - lcd.drawBitmap(getBitmap("armed"),LCD_W/2 - 90,180) - else - drawBlinkBitmap("disarmed",LCD_W/2 - 90,180) - end - end -end - --- vertical distance between roll horiz segments - - -local yawRibbonPoints = {} --- -yawRibbonPoints[0]={"N",2} -yawRibbonPoints[1]={"NE",-5} -yawRibbonPoints[2]={"E",2} -yawRibbonPoints[3]={"SE",-5} -yawRibbonPoints[4]={"S",2} -yawRibbonPoints[5]={"SW",-5} -yawRibbonPoints[6]={"W",2} -yawRibbonPoints[7]={"NW",-5} - --- optimized yaw ribbon drawing -local function drawCompassRibbon() - -- ribbon centered +/- 90 on yaw - local centerYaw = (status.yaw+270)%360 - -- this is the first point left to be drawn on the compass ribbon - local nextPoint = math.floor(centerYaw/45) * 45 - -- distance in degrees between leftmost ribbon point and first 45° multiple normalized to 120/8 - local yawMinX = (LCD_W - 120)/2 - local yawMaxX = (LCD_W + 120)/2 - -- x coord of first ribbon letter - local nextPointX = yawMinX + (nextPoint - centerYaw)/45 * 28 - local yawY = 140 - -- - local i = (nextPoint / 45) % 8 - for idx=1,6 - do - if nextPointX >= yawMinX - 3 and nextPointX < yawMaxX then - lcd.drawText(nextPointX+yawRibbonPoints[i][2],yawY,yawRibbonPoints[i][1],SMLSIZE) - end - i = (i + 1) % 8 - nextPointX = nextPointX + 28 - end - -- home icon - local leftYaw = (status.yaw + 180)%360 - local rightYaw = status.yaw%360 - local centerHome = (status.homeAngle+270)%360 - -- - local homeIconX = yawMinX - local homeIconY = yawY + 25 - if rightYaw >= leftYaw then - if centerHome > leftYaw and centerHome < rightYaw then - drawHomeIcon(yawMinX + ((centerHome - leftYaw)/180)*120 - 5,homeIconY) - end - else - if centerHome < rightYaw then - drawHomeIcon(yawMinX + (((360-leftYaw) + centerHome)/180)*120 - 5,homeIconY) - elseif centerHome >= leftYaw then - drawHomeIcon(yawMinX + ((centerHome-leftYaw)/180)*120 - 5,homeIconY) - end - end - -- when abs(home angle) > 90 draw home icon close to left/right border - local angle = status.homeAngle - status.yaw - local cos = math.cos(math.rad(angle - 90)) - local sin = math.sin(math.rad(angle - 90)) - if cos > 0 and sin > 0 then - drawHomeIcon(yawMaxX - 5, homeIconY) - elseif cos < 0 and sin > 0 then - drawHomeIcon(yawMinX - 5, homeIconY) - end - -- - lcd.drawLine(yawMinX, yawY + 16, yawMaxX, yawY + 16, SOLID, 0) - local xx = 0 - if ( status.yaw < 10) then - xx = 0 - elseif (status.yaw < 100) then - xx = -8 - else - xx = -14 - end - lcd.drawNumber(LCD_W/2 + xx - 6, yawY, status.yaw, MIDSIZE+INVERS) -end - - - - - -local function fillTriangle(ox, oy, x1, x2, roll, angle,color) - local step = 2 - -- - local y1 = (oy - ox*angle) + x1*angle - local y2 = (oy - ox*angle) + x2*angle - -- - local steps = math.abs(y2-y1) / step - -- - if (0 < roll and roll <= 90) then - for s=0,steps - do - yy = y1 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(x1,yy,xx - x1,step,color) - end - elseif (90 < roll and roll <= 180) then - for s=0,steps - do - yy = y2 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(x1,yy,xx - x1,step,color) - end - elseif (-90 < roll and roll < 0) then - for s=0,steps - do - yy = y2 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(xx,yy,x2-xx+1,step,color) - end - elseif (-180 < roll and roll <= -90) then - for s=0,steps - do - yy = y1 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(xx,yy,x2-xx+1,step,color) - end - end -end - -------------------------------------------- - -local function drawHud(myWidget) - - local r = -status.roll - local cx,cy,dx,dy,ccx,ccy,cccx,cccy - local yPos = 0 + 20 + 8 - ----------------------- - -- artificial horizon - ----------------------- - -- no roll ==> segments are vertical, offsets are multiples of 10 - if ( status.roll == 0) then - dx=0 - dy=status.pitch - cx=0 - cy=10 - ccx=0 - ccy=2*10 - cccx=0 - cccy=3*10 - else - -- center line offsets - dx = math.cos(math.rad(90 - r)) * -status.pitch - dy = math.sin(math.rad(90 - r)) * status.pitch - -- 1st line offsets - cx = math.cos(math.rad(90 - r)) * 10 - cy = math.sin(math.rad(90 - r)) * 10 - -- 2nd line offsets - ccx = math.cos(math.rad(90 - r)) * 2 * 10 - ccy = math.sin(math.rad(90 - r)) * 2 * 10 - -- 3rd line offsets - cccx = math.cos(math.rad(90 - r)) * 3 * 10 - cccy = math.sin(math.rad(90 - r)) * 3 * 10 - end - local rollX = math.floor((LCD_W-92)/2 + 92/2) - ----------------------- - -- dark color for "ground" - ----------------------- - -- 90x70 - local minY = 44 - local maxY = 114 - local minX = (LCD_W-92)/2 + 1 - local maxX = (LCD_W-92)/2 + 92 - -- - local ox = (LCD_W-92)/2 + 92/2 + dx - -- - local oy = 79 + dy - local yy = 0 - - --lcd.setColor(CUSTOM_COLOR,lcd.RGB(179, 204, 255)) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7a, 0x9c, 0xff)) - - lcd.drawFilledRectangle(minX,minY,92,maxY - minY,CUSTOM_COLOR) - -- angle of the line passing on point(ox,oy) - local angle = math.tan(math.rad(-status.roll)) - -- for each pixel of the hud base/top draw vertical black - -- lines from hud border to horizon line - -- horizon line moves with pitch/roll - --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(102, 51, 0)) - -- - -- - local minxY = (oy - ox * angle) + minX * angle; - local maxxY = (oy - ox * angle) + maxX * angle; - local maxyX = (maxY - (oy - ox * angle)) / angle; - local minyX = (minY - (oy - ox * angle)) / angle; - -- - if ( 0 <= -status.roll and -status.roll <= 90 ) then - if (minxY > minY and maxxY < maxY) then - -- 5 - lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR) - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY < maxY and maxxY > minY) then - -- 6 - lcd.drawFilledRectangle(minX, minY, minyX - minX, maxxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY > maxY) then - -- 7 - lcd.drawFilledRectangle(minX, minY, minyX - minX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < maxY and minxY > minY) then - -- 8 - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY < minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - elseif (90 < -status.roll and -status.roll <= 180) then - if (minxY < maxY and maxxY > minY) then - -- 9 - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > minY and maxxY < maxY) then - -- 10 - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minX, maxxY, maxyX - minX, maxY - maxxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxyX < maxX) then - -- 11 - lcd.drawFilledRectangle(minX, minY, maxyX - minX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < maxY and minxY > minY) then - -- 12 - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > maxY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - -- 9,10,11,12 - elseif (-90 < -status.roll and -status.roll < 0) then - if (minxY < maxY and maxxY > minY) then - -- 1 - lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < maxY and maxxY < minY and minxY > minY) then - -- 2 - lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minyX, minY, maxX - minyX, minxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY < minY) then - -- 3 - lcd.drawFilledRectangle(minyX, minY, maxX - minyX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > minY and maxxY < maxY) then - -- 4 - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxxY < minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - elseif (-180 <= -status.roll and -status.roll <= -90) then - if (minxY > minY and maxxY < maxY) then - -- 13 - lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (maxxY > maxY and minxY > minY and minxY < maxY) then - -- 14 - lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(maxyX, minxY, maxX - maxyX, maxY - minxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxyX < maxX) then - -- 15 - lcd.drawFilledRectangle(maxyX, minY, maxX - maxyX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxxY > minY) then - -- 16 - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - end - -- parallel lines above and below horizon - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) - -- - drawLineWithClipping(rollX + dx - cccx,dy + 79 + cccy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx - ccx,dy + 79 + ccy,r,20,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx - cx,dy + 79 + cy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + cx,dy + 79 - cy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + ccx,dy + 79 - ccy,r,20,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + cccx,dy + 79 - cccy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - ------------------------------------- - -- hud bitmap - ------------------------------------- - lcd.drawBitmap(getBitmap("hud_90x70a"),(LCD_W-106)/2,34) --106x90 - ------------------------------------ - -- synthetic vSpeed based on - -- home altitude when EKF is disabled - -- updated at 1Hz (i.e every 1000ms) - ------------------------------------- - if conf.enableSynthVSpeed == true then - if (status.synthVSpeedTime == 0) then - -- first time do nothing - status.synthVSpeedTime = getTime() - status.prevHomeAlt = status.homeAlt -- dm - elseif (getTime() - status.synthVSpeedTime > 100) then - -- calc vspeed - status.vspd = 1000*(status.homeAlt-status.prevHomeAlt)/(getTime()-status.synthVSpeedTime) -- m/s - -- update counters - status.synthVSpeedTime = getTime() - status.prevHomeAlt = status.homeAlt -- m - end - else - status.vspd = status.vSpeed - end - - ------------------------------------- - -- vario bitmap - ------------------------------------- - local varioMax = math.log(5) - local varioSpeed = math.log(1 + math.min(math.abs(0.05*status.vspd),4)) - local varioH = 0 - if status.vspd > 0 then - varioY = math.min(79 - varioSpeed/varioMax*55,125) - else - varioY = 78 - end - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) - lcd.drawFilledRectangle(172+2, varioY, 7, varioSpeed/varioMax*55, CUSTOM_COLOR, 0) - lcd.drawBitmap(getBitmap("variogauge_big"),172,19) - if status.vSpeed > 0 then - lcd.drawBitmap(getBitmap("varioline"),172-3,varioY) - else - lcd.drawBitmap(getBitmap("varioline"),172-3,77 + varioSpeed/varioMax*55) - end - ------------------------------------- - -- left and right indicators on HUD - ------------------------------------- - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) - -- altitude - local alt = getMaxValue(status.homeAlt,12) * unitScale - lcd.drawText(275,LCD_H-37,"alt("..unitLabel..")",SMLSIZE) - if math.abs(alt) >= 10 then - lcd.drawNumber(310,LCD_H-60,alt,MIDSIZE+RIGHT) - else - lcd.drawNumber(310,LCD_H-60,alt*10,MIDSIZE+RIGHT+PREC1) - end - -- vertical speed - local vspd = status.vspd * 0.1 * menuItems[19][6][menuItems[19][4]] - lcd.drawText(170,LCD_H-37,"vspd("..menuItems[19][5][menuItems[19][4]]..")",SMLSIZE) - if (math.abs(vspd) >= 10) then - lcd.drawNumber(180,LCD_H-60, vspd ,MIDSIZE) - else - lcd.drawNumber(180,LCD_H-60,vspd*10,MIDSIZE+PREC1) - end - -- min/max arrows - if showMinMaxValues == true then - drawVArrow(310+3, LCD_H-60 + 2,6,true,false) - end -end - -local function drawHomeDirection() - local angle = math.floor(status.homeAngle - status.yaw) - local x1 = (LCD_W/2) + 17 * math.cos(math.rad(angle - 90)) - local y1 = 202 + 17 * math.sin(math.rad(angle - 90)) - local x2 = (LCD_W/2) + 17 * math.cos(math.rad(angle - 90 + 150)) - local y2 = 202 + 17 * math.sin(math.rad(angle - 90 + 150)) - local x3 = (LCD_W/2) + 17 * math.cos(math.rad(angle - 90 - 150)) - local y3 = 202 + 17 * math.sin(math.rad(angle - 90 - 150)) - local x4 = (LCD_W/2) + 17 * 0.5 * math.cos(math.rad(angle - 270)) - local y4 = 202 + 17 * 0.5 *math.sin(math.rad(angle - 270)) - -- - drawLine(x1,y1,x2,y2,SOLID,1) - drawLine(x1,y1,x3,y3,SOLID,1) - drawLine(x2,y2,x4,y4,SOLID,1) - drawLine(x3,y3,x4,y4,SOLID,1) -end - ---------------------------------- --- This function checks alarm condition and as long as the condition persists it plays --- a warning sound. ---------------------------------- -local function checkAlarm(level,value,idx,sign,sound,delay) - -- once landed reset all alarms except battery alerts - if status.timerRunning == 0 then - if alarms[idx][4] == 0 then - alarms[idx] = { false, 0, false, 0, 0, false, 0} - elseif alarms[idx][4] == 1 then - alarms[idx] = { false, 0, true, 1 , 0, false, 0} - elseif alarms[idx][4] == 2 then - alarms[idx] = { false, 0, true, 2, 0, false, 0} - elseif alarms[idx][4] == 3 then - alarms[idx] = { false, 0 , false, 3, 4, false, 0} - elseif alarms[idx][4] == 4 then - alarms[idx] = { false, 0 , false, 4, 4, false, 0} - end - -- reset done - return - end - -- if needed arm the alarm only after value has reached level - if alarms[idx][3] == false and level > 0 and -1 * sign*value > -1 * sign*level then - alarms[idx][3] = true - end - -- - if alarms[idx][4] == 2 then - if status.flightTime > 0 and math.floor(status.flightTime) % delay == 0 then - if alarms[idx][1] == false then - alarms[idx][1] = true - playSound(sound) - -- flightime is a multiple of 1 minute - if (status.flightTime % 60 == 0 ) then - -- minutes - playNumber(status.flightTime / 60,25) --25=minutes,26=seconds - else - -- minutes - if (status.flightTime > 60) then playNumber(status.flightTime / 60,25) end - -- seconds - playNumber(status.flightTime % 60,26) - end - end - else - alarms[idx][1] = false - end - else - if alarms[idx][3] == true then - if level > 0 and sign*value > sign*level then - -- value is outside level - if alarms[idx][2] == 0 then - -- first time outside level after last reset - alarms[idx][2] = status.flightTime - -- status: START - end - else - -- value back to normal ==> reset - alarms[idx][2] = 0 - alarms[idx][1] = false - alarms[idx][6] = false - -- status: RESET - end - if alarms[idx][2] > 0 and (status.flightTime ~= alarms[idx][2]) and (status.flightTime - alarms[idx][2]) >= alarms[idx][5] then - -- enough time has passed after START - alarms[idx][6] = true - -- status: READY - end - -- - if alarms[idx][6] == true and alarms[idx][1] == false then - playSound(sound) - alarms[idx][1] = true - alarms[idx][7] = status.flightTime - -- status: BEEP - end - -- all but battery alarms - if alarms[idx][4] ~= 3 then - if alarms[idx][6] == true and status.flightTime ~= alarms[idx][7] and (status.flightTime - alarms[idx][7]) % delay == 0 then - alarms[idx][1] = false - -- status: REPEAT - end - end - end - end -end - -local function loadFlightModes() - if frame.flightModes then - return - end - -- - if status.frameType ~= -1 then - if frameTypes[status.frameType] == "c" then - frame = dofile("/SCRIPTS/YAAPU/LIB/copter.luac") - elseif frameTypes[status.frameType] == "p" then - frame = dofile("/SCRIPTS/YAAPU/LIB/plane.luac") - elseif frameTypes[status.frameType] == "r" then - frame = dofile("/SCRIPTS/YAAPU/LIB/rover.luac") - end - end -end - -local function checkEvents(celm) - loadFlightModes() - -- silence alarms when showing min/max values - if showMinMaxValues == false then - checkAlarm(conf.minAltitudeAlert,status.homeAlt,1,-1,"minalt",menuItems[14][4]) - checkAlarm(conf.maxAltitudeAlert,status.homeAlt,2,1,"maxalt",menuItems[14][4]) - checkAlarm(conf.maxDistanceAlert,status.homeDist,3,1,"maxdist",menuItems[14][4]) - checkAlarm(1,2*status.ekfFailsafe,4,1,"ekf",menuItems[14][4]) - checkAlarm(1,2*status.battFailsafe,5,1,"lowbat",menuItems[14][4]) - checkAlarm(conf.timerAlert,status.flightTime,6,1,"timealert",conf.timerAlert) -end - -- default is use battery 1 - local capacity = getBatt1Capacity() - local mah = status.batt1mah - -- only if dual battery has been detected use battery 2 - if status.batt2sources.fc or status.batt2sources.vs then - capacity = capacity + getBatt2Capacity() - mah = mah + status.batt2mah - end - -- - if (capacity > 0) then - status.batLevel = (1 - (mah/capacity))*100 - else - status.batLevel = 99 - end - for l=1,13 do - -- trigger alarm as as soon as it falls below level + 1 (i.e 91%,81%,71%,...) - if status.batLevel <= batLevels[l] + 1 and l < status.lastBattLevel then - status.lastBattLevel = l - playSound("bat"..batLevels[l]) - break - end - end - - if status.statusArmed == 1 and status.lastStatusArmed == 0 then - status.lastStatusArmed = status.statusArmed - playSound("armed") - elseif status.statusArmed == 0 and status.lastStatusArmed == 1 then - status.lastStatusArmed = status.statusArmed - playSound("disarmed") - end - - if status.gpsStatus > 2 and status.lastGpsStatus <= 2 then - status.lastGpsStatus = status.gpsStatus - playSound("gpsfix") - elseif status.gpsStatus <= 2 and status.lastGpsStatus > 2 then - status.lastGpsStatus = status.gpsStatus - playSound("gpsnofix") - end - - if status.frameType ~= -1 and status.flightMode ~= status.lastFlightMode then - status.lastFlightMode = status.flightMode - playSoundByFrameTypeAndFlightMode(status.flightMode) - end - - if status.simpleMode ~= status.lastSimpleMode then - if status.simpleMode == 0 then - playSound( status.lastSimpleMode == 1 and "simpleoff" or "ssimpleoff" ) - else - playSound( status.simpleMode == 1 and "simpleon" or "ssimpleon" ) - end - status.lastSimpleMode = status.simpleMode - end -end - -local function checkCellVoltage(celm) - -- check alarms - checkAlarm(conf.battAlertLevel1,celm,7,-1,"batalert1",menuItems[14][4]) - checkAlarm(conf.battAlertLevel2,celm,8,-1,"batalert2",menuItems[14][4]) - -- cell bgcolor is sticky but gets triggered with alarms - if status.battLevel1 == false then status.battLevel1 = alarms[7][1] end - if status.battLevel2 == false then status.battLevel2 = alarms[8][1] end -end - -local function cycleBatteryInfo() - if showDualBattery == false and (status.batt2sources.fc or status.batt2sources.vs) then - showDualBattery = true - return - end - if status.battsource == "vs" then - status.battsource = "fc" - elseif status.battsource == "fc" then - status.battsource = "a2" - elseif status.battsource == "a2" then - status.battsource = "vs" - end -end --------------------------------------------------------------------------------- --- MAIN LOOP --------------------------------------------------------------------------------- --- -local bgclock = 0 - -------------------------------- --- running at 20Hz (every 50ms) -------------------------------- -local bgprocessing = false -local bglockcounter = 0 --- -local function backgroundTasks(telemetryLoops) -if bgprocessing == true then - bglockcounter = bglockcounter + 1 - return 0 -end -bgprocessing = true - -- FAST: this runs at 60Hz (every 16ms) - for i=1,telemetryLoops - do - processTelemetry() - end - -- NORMAL: this runs at 20Hz (every 50ms) - calcFlightTime() - -- SLOW: this runs at 4Hz (every 250ms) - if (bgclock % 4 == 0) then - setSensorValues() - collectgarbage() - end - -- SLOWER: this runs at 2Hz (every 500ms) - if (bgclock % 8 == 0) then - -- update battery - calcBattery() - -- prepare celm based on battsource - local count = calcCellCount() - local cellVoltage = 0 - -- - if status.battsource == "vs" then - cellVoltage = getNonZeroMin(status.cell1min, status.cell2min)*100 --FLVSS - elseif status.battsource == "fc" then - cellVoltage = getNonZeroMin(status.cell1sumFC/count,status.cell2sumFC/count)*100 --FC - elseif status.battsource == "a2" then - cellVoltage = (status.cellsumA2/count)*100 --12 - end - -- - checkEvents(cellVoltage) - checkLandingStatus() - -- no need for alarms if reported voltage is 0 - if cellVoltage > 0 then - checkCellVoltage(cellVoltage) - end - -- aggregate value - minmaxValues[8] = math.max(status.batt1current+status.batt2current,minmaxValues[8]) - -- indipendent values - minmaxValues[9] = math.max(status.batt1current,minmaxValues[9]) - minmaxValues[10] = math.max(status.batt2current,minmaxValues[10]) - -- reset backlight panel - if (model.getGlobalVariable(8,0) > 0 and getTime()/100 - backlightLastTime > 5) then - model.setGlobalVariable(8,0,0) - end - bgclock = 0 - end - bgclock = bgclock+1 - -- blinking support - if (getTime() - blinktime) > 65 then - blinkon = not blinkon - blinktime = getTime() - end - bgprocessing = false - return 0 -end - -local showSensorPage = false -local showMessages = false - -local function init() - -- initialize flight timer - model.setTimer(2,{mode=0}) - model.setTimer(2,{value=0}) - currentModel = model.getInfo().name - loadConfig() - playSound("yaapu") - pushMessage(7,"Yaapu Telemetry Script 1.7.4") - -- load unit definitions - unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 - unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" -end - --------------------------------------------------------------------------------- --- SCRIPT END --------------------------------------------------------------------------------- --- 4 pages --- page 1 single battery view --- page 2 message history --- page 3 min max --- page 4 dual battery view -local options = { - { "page", VALUE, 1, 1, 4}, -} - -local widgetPages = { - {active=false, bgtasks=false, fgtasks=false}, - {active=false, bgtasks=false, fgtasks=false}, - {active=false, bgtasks=false, fgtasks=false}, - {active=false, bgtasks=false, fgtasks=false} -} ---------------------- --- script version ---------------------- --- shared init flag -local initDone = 0 --- This function is runned once at the creation of the widget -local function create(zone, options) - -- this vars are widget scoped, each instance has its own set - local vars = { - } - -- all local vars are shared between widget instances - -- init() needs to be called only once! - if initDone == 0 then - init() - initDone = 1 - end - -- register current page as active - widgetPages[options.page].active = true - -- - return { zone=zone, options=options, vars=vars } -end - --- This function allow updates when you change widgets settings -local function update(myWidget, options) - myWidget.options = options - -- register current page as active - widgetPages[options.page].active = true - -- reload menu settings - loadConfig() -end -local function fullScreenRequired(myWidget) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0, 0)) - lcd.drawText(myWidget.zone.x,myWidget.zone.y,"Yaapu requires",SMLSIZE+CUSTOM_COLOR) - lcd.drawText(myWidget.zone.x,myWidget.zone.y+16,"full screen",SMLSIZE+CUSTOM_COLOR) - --[[ - if myWidget.zone.h > 100 then - local strsize = string.format("%d x %d",myWidget.zone.w,myWidget.zone.h) - lcd.drawText(myWidget.zone.x,myWidget.zone.y+32,strsize,SMLSIZE+CUSTOM_COLOR) - end - --]]end --- This size is for top bar widgets -local function zoneTiny(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 160x30 1/8th -local function zoneSmall(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 180x70 1/4th -local function zoneMedium(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 190x150 -local function zoneLarge(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 390x170 -local function zoneXLarge(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 480x272 -local function zoneFullScreen(myWidget) - -------------------------- - -- Widget Page 2 is message history - -------------------------- - if myWidget.options.page == 2 then - drawAllMessages() - else - drawHomeDirection() - drawHud(myWidget) - drawCompassRibbon() - -- - -- Note: these can be calculated. not necessary to track them as min/max - -- status.cell1minFC = status.cell1sumFC/calcCellCount() - -- status.cell2minFC = status.cell2sumFC/calcCellCount() - -- status.cell1minA2 = status.cell1sumA2/calcCellCount() - -- - local count = calcCellCount() - local cel1m = getMinVoltageBySource(status.battsource,status.cell1min,status.cell1sumFC/count,status.cellsumA2/count,1,count)*100 - local cel2m = getMinVoltageBySource(status.battsource,status.cell2min,status.cell2sumFC/count,status.cellsumA2/count,2,count)*100 - local batt1 = getMinVoltageBySource(status.battsource,status.cell1sum,status.cell1sumFC,status.cellsumA2,1,count)*10 - local batt2 = getMinVoltageBySource(status.battsource,status.cell2sum,status.cell2sumFC,status.cellsumA2,2,count)*10 - local curr = getMaxValue(status.batt1current+status.batt2current,8) - local curr1 = getMaxValue(status.batt1current,9) - local curr2 = getMaxValue(status.batt2current,10) - local mah1 = status.batt1mah - local mah2 = status.batt2mah - local cap1 = getBatt1Capacity() - local cap2 = getBatt2Capacity() - -- - -- with dual battery default is to show aggregate view - if status.batt2sources.fc or status.batt2sources.vs then - if showDualBattery == false then - -- dual battery: aggregate view - lcd.drawText(285+67,85,"BATTERY: 1+2",SMLSIZE+INVERS) - drawBatteryPane(285,getNonZeroMin(batt1,batt2),getNonZeroMin(cel1m,cel2m),curr,mah1+mah2,cap1+cap2) - else - -- dual battery: do I have also dual current monitor? - if curr1 > 0 and curr2 == 0 then - -- special case: assume 1 power brick is monitoring batt1+batt2 in parallel - curr1 = curr1/2 - curr2 = curr1 - -- - mah1 = mah1/2 - mah2 = mah1 - -- - cap1 = cap1/2 - cap2 = cap1 - end - -- dual battery:battery 1 right pane - lcd.drawText(285+75,85,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - -- dual battery:battery 2 left pane - lcd.drawText(50,85,"BATTERY: 2",SMLSIZE+INVERS) - drawBatteryPane(-24,batt2,cel2m,curr2,mah2,cap2) - end - else - -- battery 1 right pane in single battery mode - lcd.drawText(285+75,85,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - end - -- left pane info when not in dual battery mode - if showDualBattery == false then - -- power is always based on flight controller values - drawGPSStatus() - if showSensorPage then - drawCustomSensors() - else - drawLeftPane(curr1+curr2,getNonZeroMin(status.cell1sumFC,status.cell2sumFC)) - end - end - drawFlightMode() - drawTopBar() - drawBottomBar() - drawFlightTime() - drawFailsafe() - drawArmStatus() - if showDualBattery == false and showSensorPage == false then - end - end - drawNoTelemetryData() -end - --- called when widget instance page changes -local function onChangePage(myWidget) - -- reset HUD counters - myWidget.vars.hudcounter = 0 - -- refresh config on page change so it's possible to use menu in one time mode - loadConfig() - collectgarbage() -end - --- Called when script is hidden @20Hz -local function background(myWidget) - -- when page 3 goes to background hide minmax values - if myWidget.options.page == 3 then - showMinMaxValues = false - return - end - -- when page 4 goes to background hide dual battery view - if myWidget.options.page == 4 then - showDualBattery = false - return - end - -- when page 1 goes to background run bg tasks only if page 2 is not registered - if myWidget.options.page == 1 and widgetPages[2].active == false then - -- run bg tasks - backgroundTasks(6) - return - end - -- when page 2 goes to background always run bg tasks - if myWidget.options.page == 2 then - -- run bg tasks - backgroundTasks(6) - end -end - --- Called when script is visible -function refresh(myWidget) - -- check if current widget page changed - if currentPage ~= myWidget.options.page then - currentPage = myWidget.options.page - onChangePage(myWidget) - end - -- when page 1 goes to foreground run bg tasks only if page 2 is not registered - if myWidget.options.page == 1 and widgetPages[2].active == false then - -- run bg tasks - backgroundTasks(6) - end - -- if widget page 2 is declared then always run bg tasks when in foreground - if myWidget.options.page == 2 then - -- run bg tasks - backgroundTasks(4) - end - -- when page 3 goes to foreground show minmax values - if myWidget.options.page == 3 then - showMinMaxValues = true - end - -- when page 4 goes to foreground show dual battery view - if myWidget.options.page == 4 then - showDualBattery = true - end - -- - if myWidget.zone.w > 450 and myWidget.zone.h > 250 then zoneFullScreen(myWidget) - elseif myWidget.zone.w > 380 and myWidget.zone.h > 165 then zoneXLarge(myWidget) - elseif myWidget.zone.w > 180 and myWidget.zone.h > 145 then zoneLarge(myWidget) - elseif myWidget.zone.w > 170 and myWidget.zone.h > 65 then zoneMedium(myWidget) - elseif myWidget.zone.w > 150 and myWidget.zone.h > 28 then zoneSmall(myWidget) - elseif myWidget.zone.w > 65 and myWidget.zone.h > 35 then zoneTiny(myWidget) - end -end - -return { name="Yaapu", options=options, create=create, update=update, background=background, refresh=refresh } diff --git a/HORUS/SOURCES/PP/menu.lua b/HORUS/SOURCES/PP/menu.lua index c73e80b8..cc1c24bc 100644 --- a/HORUS/SOURCES/PP/menu.lua +++ b/HORUS/SOURCES/PP/menu.lua @@ -1,124 +1,342 @@ --- --- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios --- --- Copyright (C) 2018. Alessandro Apostoli --- https://github.com/yaapu --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- 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. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, see . --- --- Passthrough protocol reference: --- https://cdn.rawgit.com/ArduPilot/ardupilot_wiki/33cd0c2c/images/FrSky_Passthrough_protocol.xlsx --- --- Borrowed some code from the LI-xx BATTCHECK v3.30 script --- http://frskytaranis.forumactif.org/t2800-lua-download-un-testeur-de-batterie-sur-la-radio +#include "includes/yaapu_inc.lua" ---------------------- --- Script Version ---------------------- +------------------------------------- +-- UNITS Scales from Ardupilot OSD code /ardupilot/libraries/AP_OSD/AP_OSD_Screen.cpp +------------------------------------- +--[[ + static const float scale_metric[UNIT_TYPE_LAST] = { + 1.0, //ALTITUDE m + 3.6, //SPEED km/hr + 1.0, //VSPEED m/s + 1.0, //DISTANCE m + 1.0/1000, //DISTANCE_LONG km + 1.0, //TEMPERATURE C + }; + static const float scale_imperial[UNIT_TYPE_LAST] = { + 3.28084, //ALTITUDE ft + 2.23694, //SPEED mph + 3.28084, //VSPEED ft/s + 3.28084, //DISTANCE ft + 1.0/1609.34, //DISTANCE_LONG miles + 1.8, //TEMPERATURE F + }; + static const float scale_SI[UNIT_TYPE_LAST] = { + 1.0, //ALTITUDE m + 1.0, //SPEED m/s + 1.0, //VSPEED m/s + 1.0, //DISTANCE m + 1.0/1000, //DISTANCE_LONG km + 1.0, //TEMPERATURE C + }; + static const float scale_aviation[UNIT_TYPE_LAST] = { + 3.28084, //ALTITUDE Ft + 1.94384, //SPEED Knots + 196.85, //VSPEED ft/min + 3.28084, //DISTANCE ft + 0.000539957, //DISTANCE_LONG Nm + 1.0, //TEMPERATURE C + }; +--]] +--[[ ---#define BATTPERC_BY_VOLTAGE +TYPEVALUE - menu option to select a numeric value +{description, type,name,default value,min,max,uit of measure,precision,increment step, , } +example {"batt alert level 1:", TYPEVALUE, "V1", 375, 0,5000,"V",PREC2,5,"L2",350 }, +TYPECOMBO - menu option to select a value from a list +{description, type, name, default, label list, value list, , } +example {"center pane layout:", TYPECOMBO, "CPANE", 1, { "hud","radar" }, { 1, 2 },"CPANE",1 }, --------------------------------------------------------------------------------- --- CONFIGURATION MENU --------------------------------------------------------------------------------- +--]] +-- +local menuItems = { + {"voice language:", TYPECOMBO, "L1", 1, { "english", "italian", "french", "german" } , {"en","it","fr","de"} }, + {"batt alert level 1:", TYPEVALUE, "V1", 375, 0,5000,"V",PREC2,5 }, + {"batt alert level 2:", TYPEVALUE, "V2", 350, 0,5000,"V",PREC2,5 }, + {"batt[1] capacity override:", TYPEVALUE, "B1", 0, 0,5000,"Ah",PREC2,10 }, + {"batt[2] capacity override:", TYPEVALUE, "B2", 0, 0,5000,"Ah",PREC2,10 }, + {"disable all sounds:", TYPECOMBO, "S1", 1, { "no", "yes" }, { false, true } }, + {"disable msg beep:", TYPECOMBO, "S2", 1, { "no", "info", "all" }, { 1, 2, 3 } }, + {"enable haptic:", TYPECOMBO, "VIBR", 1, { "no", "yes" }, { false, true } }, + {"default voltage source:", TYPECOMBO, "VS", 1, { "auto", "FLVSS", "fc" }, { nil, "vs", "fc" } }, + {"timer alert every:", TYPEVALUE, "T1", 0, 0,600,"min",PREC1,5 }, + {"min altitude alert:", TYPEVALUE, "A1", 0, 0,500,"m",PREC1,5 }, + {"max altitude alert:", TYPEVALUE, "A2", 0, 0,10000,"m",0,1 }, + {"max distance alert:", TYPEVALUE, "D1", 0, 0,100000,"m",0,10 }, + {"repeat alerts every:", TYPEVALUE, "T2", 10, 5,600,"sec",0,5 }, + {"dual battery config:", TYPECOMBO, "BC", 1, { "par", "ser", "other" }, { 1, 2, 3 } }, + {"batt[1] cell count override:", TYPEVALUE, "CC", 0, 0,12," cells",0,1 }, + {"batt[2] cell count override:", TYPEVALUE, "CC2", 0, 0,12," cells",0,1 }, + {"rangefinder max:", TYPEVALUE, "RM", 0, 0,10000," cm",0,10 }, + {"air/groundspeed unit:", TYPECOMBO, "HSPD", 1, { "m/s", "km/h", "mph", "kn" }, { 1, 3.6, 2.23694, 1.94384} }, + {"vertical speed unit:", TYPECOMBO, "VSPD", 1, { "m/s", "ft/s", "ft/min" }, { 1, 3.28084, 196.85} }, +#ifdef HDOP_ALERT + {"max hdop alert:", TYPEVALUE, "HDOP", 20, 0,50,"hdop",PREC1,2 }, +#endif + {"widget layout:", TYPECOMBO, "WL", 1, { "default","legacy"}, { 1, 2 } }, + {"center panel:", TYPECOMBO, "CPANE", 1, { "option 1","option 2","option 3","option 4" }, { 1, 2, 3, 4 } }, + {"right panel:", TYPECOMBO, "RPANE", 1, { "option 1","option 2","option 3","option 4" }, { 1, 2, 3, 4 } }, + {"left panel:", TYPECOMBO, "LPANE", 1, { "option 1","option 2","option 3","option 4" }, { 1 , 2, 3, 4 } }, +#ifdef DEV + {"[gas] rpm label:", TYPECOMBO, "GAS_RPM", 1, { "eng","head" }, { 1, 2 },"RPANE",2 }, + {"[gas] pinion gear:", TYPEVALUE, "GAS_PG", 14, 0,100,"",0,1,"RPANE",2 }, + {"[gas] main gear:", TYPEVALUE, "GAS_MG", 105, 0,200,"",0,1,"RPANE",2 }, +#endif +#ifdef BATTPERC_BY_VOLTAGE + {"enable battery % by voltage:", TYPECOMBO, "BPBV", 1, { "no", "yes" }, { false, true } }, +#endif --BATTPERC_BY_VOLTAGE + {"enable px4 flightmodes:", TYPECOMBO, "PX4", 1, { "no", "yes" }, { false, true } }, + {"screen toggle channel:", TYPEVALUE, "STC", 0, 0, 32,nil,0,1 }, +} - local menu = { selectedItem = 1, editSelected = false, - offset = 0 + offset = 0, + updated = true, -- if true menu needs a call to updateMenuItems() + wrapOffset = 0, -- changes according to enabled/disabled features and panels } -local menuItems = {} - -- label, type, alias, currval, min, max, label, flags, increment -menuItems[1] = {"voice language:", 1, "L1", 1, { "english", "italian", "french", "german" } , {"en","it","fr","de"} } -menuItems[2] = {"batt alert level 1:", 0, "V1", 375, 0,5000,"V", PREC2 ,5 } -menuItems[3] = {"batt alert level 2:", 0, "V2", 350, 0,5000,"V", PREC2 ,5 } -menuItems[4] = {"batt[1] capacity override:", 0, "B1", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[5] = {"batt[2] capacity override:", 0, "B2", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[6] = {"disable all sounds:", 1, "S1", 1, { "no", "yes" }, { false, true } } -menuItems[7] = {"disable msg beep:", 1, "S2", 1, { "no", "yes" }, { false, true } } -menuItems[8] = {"disable msg blink:", 1, "S3", 1, { "no", "yes" }, { false, true } } -menuItems[9] = {"default voltage source:", 1, "VS", 1, { "auto", "FLVSS", "A2", "fc" }, { nil, "vs", "a2", "fc" } } -menuItems[10] = {"timer alert every:", 0, "T1", 0, 0,600,"min",PREC1,5 } -menuItems[11] = {"min altitude alert:", 0, "A1", 0, 0,500,"m",PREC1,5 } -menuItems[12] = {"max altitude alert:", 0, "A2", 0, 0,10000,"m",0,1 } -menuItems[13] = {"max distance alert:", 0, "D1", 0, 0,100000,"m",0,10 } -menuItems[14] = {"repeat alerts every:", 0, "T2", 10, 5,600,"sec",0,5 } -menuItems[15] = {"cell count override:", 0, "CC", 0, 0,12,"cells",0,1 } -menuItems[16] = {"rangefinder max:", 0, "RM", 0, 0,10000," cm",0,10 } -menuItems[17] = {"enable synthetic vspeed:", 1, "SVS", 1, { "no", "yes" }, { false, true } } -menuItems[18] = {"air/groundspeed unit:", 1, "HSPD", 1, { "m/s", "km/h", "mph", "kn" }, { 1, 3.6, 2.23694, 1.94384} } -menuItems[19] = {"vertical speed unit:", 1, "VSPD", 1, { "m/s", "ft/s", "ft/min" }, { 1, 3.28084, 196.85} } --- +local basePath = "/SCRIPTS/YAAPU/" +local libBasePath = basePath.."LIB/" + +local widgetLayoutFiles = {"layout_1","layout_2"} -local function getConfigFilename() +local centerPanelFiles = {} +local rightPanelFiles = {} +local leftPanelFiles = {} + +------------------------------------------ +-- returns item's VALUE,LABEL,IDX +------------------------------------------ +local function getMenuItemByName(items,name) + for idx=1,#items + do + -- items[idx][3] is the menu item's name as it appears in the config file + if items[idx][3] == name then + if items[idx][2] == TYPECOMBO then + -- return item's value, label, index + return items[idx][6][items[idx][4]], items[idx][5][items[idx][4]], idx + else + -- return item's value, label, index + return items[idx][4], name, idx + end + end + end + return nil +end + +local function updateMenuItems() + if menu.updated == true then + local value, name, idx = getMenuItemByName(menuItems,"WL") + if value == 1 then + --------------------- + -- large hud layout + --------------------- + + --{"center panel layout:", TYPECOMBO, "CPANE", 1, { "def","small","russian","dev" }, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"CPANE") + menuItems[idx][5] = { "default"}; + menuItems[idx][6] = { 1 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"right panel layout:", TYPECOMBO, "RPANE", 1, { "def", "custom", "empty","dev"}, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"RPANE") + menuItems[idx][5] = { "default"}; + menuItems[idx][6] = { 1 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"left panel layout:", TYPECOMBO, "LPANE", 1, { "def","mav2frsky", "empty", "dev" }, { 1 , 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"LPANE") + menuItems[idx][5] = { "default","mav2passthru"}; + menuItems[idx][6] = { 1, 2 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + centerPanelFiles = {"hud_1"} + rightPanelFiles = {"right_1"} + leftPanelFiles = {"left_1", "left_m2f_1"} + + elseif value == 2 then + --------------------- + -- legacy layout + --------------------- + + --{"center panel layout:", TYPECOMBO, "CPANE", 1, { "def","small","russian","dev" }, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"CPANE") + menuItems[idx][5] = { "default", "russian hud", "compact hud "}; + menuItems[idx][6] = { 1, 2, 3 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"right panel layout:", TYPECOMBO, "RPANE", 1, { "def", "custom", "empty","dev"}, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"RPANE") + menuItems[idx][5] = { "default", "custom sensors"}; + menuItems[idx][6] = { 1, 2 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"left panel layout:", TYPECOMBO, "LPANE", 1, { "def","mav2frsky", "empty", "dev" }, { 1 , 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"LPANE") + menuItems[idx][5] = { "default","mav2passthru" }; + menuItems[idx][6] = { 1, 2 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + centerPanelFiles = {"hud_2", "hud_russian_2", "hud_small_2" } + rightPanelFiles = {"right_2", "right_custom_2" } + leftPanelFiles = {"left_2", "left_m2f_2" } + end + + menu.updated = false + collectgarbage() + collectgarbage() + end +end + +local +function getConfigFilename() local info = model.getInfo() return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".cfg") end -local function loadConfig() +local function applyConfigValues(conf) + if menu.updated == true then + updateMenuItems() + menu.updated = false + end + conf.language = getMenuItemByName(menuItems,"L1") + conf.battAlertLevel1 = getMenuItemByName(menuItems,"V1") + conf.battAlertLevel2 = getMenuItemByName(menuItems,"V2") + conf.battCapOverride1 = getMenuItemByName(menuItems,"B1") + conf.battCapOverride2 = getMenuItemByName(menuItems,"B2") + conf.disableAllSounds = getMenuItemByName(menuItems,"S1") + conf.disableMsgBeep = getMenuItemByName(menuItems,"S2") + conf.enableHaptic = getMenuItemByName(menuItems,"VIBR") + conf.timerAlert = math.floor(getMenuItemByName(menuItems,"T1")*0.1*60) + conf.minAltitudeAlert = getMenuItemByName(menuItems,"A1")*0.1 + conf.maxAltitudeAlert = getMenuItemByName(menuItems,"A2") + conf.maxDistanceAlert = getMenuItemByName(menuItems,"D1") + conf.repeatAlertsPeriod = getMenuItemByName(menuItems,"T2") + conf.battConf = getMenuItemByName(menuItems,"BC") + conf.cell1Count = getMenuItemByName(menuItems,"CC") + conf.cell2Count = getMenuItemByName(menuItems,"CC2") + conf.rangeFinderMax = getMenuItemByName(menuItems,"RM") + conf.horSpeedMultiplier, conf.horSpeedLabel = getMenuItemByName(menuItems,"HSPD") + conf.vertSpeedMultiplier, conf.vertSpeedLabel = getMenuItemByName(menuItems,"VSPD") + -- Layout configuration + conf.widgetLayout = getMenuItemByName(menuItems,"WL") + conf.widgetLayoutFilename = widgetLayoutFiles[conf.widgetLayout] + + conf.centerPanel = getMenuItemByName(menuItems,"CPANE") + conf.centerPanelFilename = centerPanelFiles[conf.centerPanel] + + conf.rightPanel = getMenuItemByName(menuItems,"RPANE") + conf.rightPanelFilename = rightPanelFiles[conf.rightPanel] + + conf.leftPanel = getMenuItemByName(menuItems,"LPANE") + conf.leftPanelFilename = leftPanelFiles[conf.leftPanel] + +#ifdef HDOP_ALERT + conf.maxHdopAlert = getMenuItemByName(menuItems,"HDOP") +#endif + conf.enablePX4Modes = getMenuItemByName(menuItems,"PX4") + + local chInfo = getFieldInfo("ch"..getMenuItemByName(menuItems,"STC")) + conf.screenToggleChannelId = (chInfo == nil and -1 or chInfo['id']) + + -- set default voltage source + if getMenuItemByName(menuItems,"VS") ~= nil then + conf.defaultBattSource = getMenuItemByName(menuItems,"VS") + end + + menu.editSelected = false + collectgarbage() + collectgarbage() +end + +local function loadConfig(conf) local cfg = io.open(getConfigFilename(),"r") - if cfg == nil then - return - end - local str = io.read(cfg,200) - if string.len(str) > 0 then - for i=1,#menuItems - do - local value = string.match(str, menuItems[i][3]..":(%d+)") - if value ~= nil then - menuItems[i][4] = tonumber(value) - end + if cfg ~= nil then + local str = io.read(cfg,500) + io.close(cfg) + if string.len(str) > 0 then + for i=1,#menuItems + do + local value = string.match(str, menuItems[i][3]..":([-%d]+)") + collectgarbage() + if value ~= nil then + menuItems[i][4] = tonumber(value) + -- check if the value read from file is compatible with available options + if menuItems[i][2] == TYPECOMBO and tonumber(value) > #menuItems[i][5] then + --if not force default + menuItems[i][4] = 1 + end + end + end end end - if cfg ~= nil then - io.close(cfg) + -- menu was loaded apply required changes + menu.updated = true + -- when run standalone there's nothing to update :-) + if conf ~= nil then + applyConfigValues(conf) end end -local function saveConfig() - local cfg = assert(io.open(getConfigFilename(),"w")) - if cfg == nil then - return - end +local function saveConfig(conf) + local myConfig = "" for i=1,#menuItems do - io.write(cfg,menuItems[i][3],":",menuItems[i][4]) + myConfig = myConfig..menuItems[i][3]..":"..menuItems[i][4] if i < #menuItems then - io.write(cfg,",") + myConfig = myConfig.."," end end - if cfg ~= nil then + local cfg = assert(io.open(getConfigFilename(),"w")) + if cfg ~= nil then + io.write(cfg,myConfig) io.close(cfg) end + myConfig = nil + collectgarbage() + collectgarbage() + -- when run standalone there's nothing to update :-) + if conf ~= nil then + applyConfigValues(conf) + end + model.setGlobalVariable(CONF_GV,CONF_FM_GV,1) end local function drawConfigMenuBars() + lcd.setColor(CUSTOM_COLOR,COLOR_BARS) local itemIdx = string.format("%d/%d",menu.selectedItem,#menuItems) - lcd.drawFilledRectangle(0,0, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,0,"Yaapu Telemetry Script 1.7.4",MENU_TITLE_COLOR) - lcd.drawFilledRectangle(0,LCD_H - 20, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, LCD_H - 20, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,LCD_H - 20+1,getConfigFilename(),MENU_TITLE_COLOR) - lcd.drawText(LCD_W,LCD_H - 20+1,itemIdx,MENU_TITLE_COLOR+RIGHT) + lcd.drawFilledRectangle(0,TOPBAR_Y, LCD_W, 20, CUSTOM_COLOR) + lcd.drawRectangle(0, TOPBAR_Y, LCD_W, 20, CUSTOM_COLOR) + lcd.drawFilledRectangle(0,BOTTOMBAR_Y, LCD_W, 20, CUSTOM_COLOR) + lcd.drawRectangle(0, BOTTOMBAR_Y, LCD_W, 20, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(2,0,VERSION,CUSTOM_COLOR) + lcd.drawText(2,BOTTOMBAR_Y+1,getConfigFilename(),CUSTOM_COLOR) + lcd.drawText(BOTTOMBAR_WIDTH,BOTTOMBAR_Y+1,itemIdx,CUSTOM_COLOR+RIGHT) end local function incMenuItem(idx) - if menuItems[idx][2] == 0 then + if menuItems[idx][2] == TYPEVALUE then menuItems[idx][4] = menuItems[idx][4] + menuItems[idx][9] if menuItems[idx][4] > menuItems[idx][6] then menuItems[idx][4] = menuItems[idx][6] @@ -132,7 +350,7 @@ local function incMenuItem(idx) end local function decMenuItem(idx) - if menuItems[idx][2] == 0 then + if menuItems[idx][2] == TYPEVALUE then menuItems[idx][4] = menuItems[idx][4] - menuItems[idx][9] if menuItems[idx][4] < menuItems[idx][5] then menuItems[idx][4] = menuItems[idx][5] @@ -146,26 +364,31 @@ local function decMenuItem(idx) end local function drawItem(idx,flags) - if menuItems[idx][2] == 0 then - if menuItems[idx][4] == 0 then - lcd.drawText(300,25 + (idx-menu.offset-1)*20, "---",flags) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + if menuItems[idx][2] == TYPEVALUE then + if menuItems[idx][4] == 0 and menuItems[idx][5] >= 0 then + lcd.drawText(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, "---",flags+CUSTOM_COLOR) else - lcd.drawNumber(300,25 + (idx-menu.offset-1)*20, menuItems[idx][4],flags+menuItems[idx][8]) - lcd.drawText(300 + 50,25 + (idx-menu.offset-1)*20, menuItems[idx][7],flags) + lcd.drawNumber(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][4],flags+menuItems[idx][8]+CUSTOM_COLOR) + if menuItems[idx][7] ~= nil then + lcd.drawText(MENU_ITEM_X + 50,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][7],flags+CUSTOM_COLOR) + end end else - lcd.drawText(300,25 + (idx-menu.offset-1)*20, menuItems[idx][5][menuItems[idx][4]],flags) + lcd.drawText(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][5][menuItems[idx][4]],flags+CUSTOM_COLOR) end end local function drawConfigMenu(event) drawConfigMenuBars() + updateMenuItems() if event == EVT_ENTER_BREAK then if menu.editSelected == true then -- confirm modified value saveConfig() end menu.editSelected = not menu.editSelected + menu.updated = true elseif menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT or event == EVT_PLUS_REPT) then incMenuItem(menu.selectedItem) elseif menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT or event == EVT_MINUS_REPT) then @@ -177,7 +400,7 @@ local function drawConfigMenu(event) end elseif not menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT) then menu.selectedItem = (menu.selectedItem + 1) - if menu.selectedItem - 11 > menu.offset then + if menu.selectedItem - MENU_PAGESIZE > menu.offset then menu.offset = menu.offset + 1 end end @@ -187,11 +410,12 @@ local function drawConfigMenu(event) menu.offset = 0 elseif menu.selectedItem < 1 then menu.selectedItem = #menuItems - menu.offset = 8 + menu.offset = #menuItems - MENU_PAGESIZE end -- - for m=1+menu.offset,math.min(#menuItems,11+menu.offset) do - lcd.drawText(2,25 + (m-menu.offset-1)*20, menuItems[m][1],0+0) + for m=1+menu.offset,math.min(#menuItems,MENU_PAGESIZE+menu.offset) do + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(2,MENU_Y + (m-menu.offset-1)*20, menuItems[m][1],CUSTOM_COLOR) if m == menu.selectedItem then if menu.editSelected then drawItem(m,INVERS+BLINK) @@ -204,14 +428,36 @@ local function drawConfigMenu(event) end end +#ifdef COMPILE +local function compileLayouts() + local files = { + "layout_1", "layout_2", + + "hud_1", "hud_nav_1", + "right_1", + "left_1", "left_m2f_1", + + "hud_2", "hud_russian_2", "hud_small_2", + "right_2", "right_custom_2", + "left_2", "left_m2f_2", + } + + -- compile all layouts for all panes + for i=1,#files do + loadScript(libBasePath..files[i]..".lua","c") + end +end +#endif + -------------------------- -- RUN -------------------------- local function run(event) - lcd.clear() + lcd.setColor(CUSTOM_COLOR, COLOR_BG) -- hex 0x084c7b -- 073f66 + lcd.clear(CUSTOM_COLOR) --------------------- -- CONFIG MENU - --------------------- + --------------------- drawConfigMenu(event) return 0 end @@ -223,4 +469,4 @@ end -------------------------------------------------------------------------------- -- SCRIPT END -------------------------------------------------------------------------------- -return {run=run, init=init} +return {run=run, init=init, loadConfig=loadConfig, compileLayouts=compileLayouts, menuItems=menuItems} \ No newline at end of file diff --git a/HORUS/SOURCES/PP/rover.lua b/HORUS/SOURCES/PP/rover.lua deleted file mode 100644 index 4e235ad4..00000000 --- a/HORUS/SOURCES/PP/rover.lua +++ /dev/null @@ -1,27 +0,0 @@ -local flightModes = {} --- rover flight modes -flightModes[1]="Manual" -flightModes[2]="Acro" -flightModes[4]="Steering" -flightModes[5]="Hold" -flightModes[11]="Auto" -flightModes[12]="RTL" -flightModes[13]="SmartRTL" -flightModes[16]="Guided" -flightModes[17]="Initializing" -flightModes[0]="" -flightModes[6]="" -flightModes[7]="" -flightModes[8]="" -flightModes[9]="" -flightModes[10]="" -flightModes[14]="" -flightModes[15]="" -flightModes[18]="" -flightModes[19]="" -flightModes[20]="" -flightModes[21]="" -flightModes[22]="" --- -return {flightModes=flightModes} - diff --git a/HORUS/SOURCES/PP/yaapu.lua b/HORUS/SOURCES/PP/yaapu.lua new file mode 100644 index 00000000..25f1e1b8 --- /dev/null +++ b/HORUS/SOURCES/PP/yaapu.lua @@ -0,0 +1,2297 @@ +#include "includes/yaapu_inc.lua" + +local frameNames = {} +-- copter +frameNames[0] = "GEN" +frameNames[2] = "QUAD" +frameNames[3] = "COAX" +frameNames[4] = "HELI" +frameNames[13] = "HEX" +frameNames[14] = "OCTO" +frameNames[15] = "TRI" +frameNames[29] = "DODE" +-- plane +frameNames[1] = "WING" +frameNames[16] = "FLAP" +frameNames[19] = "VTOL2" +frameNames[20] = "VTOL4" +frameNames[20] = "VTOL4" +frameNames[21] = "VTOLT" +frameNames[22] = "VTOL" +frameNames[23] = "VTOL" +frameNames[24] = "VTOL" +frameNames[25] = "VTOL" +frameNames[28] = "FOIL" +-- rover +frameNames[10] = "ROV" +-- boat +frameNames[11] = "BOAT" + +local currentModel = nil +local frameTypes = {} +local frameType = nil + +--[[ + MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */ + MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */ + MAV_TYPE_QUADROTOR=2, /* Quadrotor | */ + MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */ + MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */ + MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */ + MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */ + MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */ + MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */ + MAV_TYPE_ROCKET=9, /* Rocket | */ + MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */ + MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */ + MAV_TYPE_SUBMARINE=12, /* Submarine | */ + MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */ + MAV_TYPE_OCTOROTOR=14, /* Octorotor | */ + MAV_TYPE_TRICOPTER=15, /* Tricopter | */ + MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */ + MAV_TYPE_KITE=17, /* Kite | */ + MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */ + MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */ + MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */ + MAV_TYPE_VTOL_TILTROTOR=21, /* Tiltrotor VTOL | */ + MAV_TYPE_VTOL_RESERVED2=22, /* VTOL reserved 2 | */ + MAV_TYPE_VTOL_RESERVED3=23, /* VTOL reserved 3 | */ + MAV_TYPE_VTOL_RESERVED4=24, /* VTOL reserved 4 | */ + MAV_TYPE_VTOL_RESERVED5=25, /* VTOL reserved 5 | */ + MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */ + MAV_TYPE_ADSB=27, /* Onboard ADSB peripheral | */ + MAV_TYPE_PARAFOIL=28, /* Steerable, nonrigid airfoil | */ + MAV_TYPE_DODECAROTOR=29, /* Dodecarotor | */ +]]-- + +-- copter +frameTypes[0] = "c" +frameTypes[2] = "c" +frameTypes[3] = "c" +frameTypes[4] = "c" +frameTypes[13] = "c" +frameTypes[14] = "c" +frameTypes[15] = "c" +frameTypes[29] = "c" +-- plane +frameTypes[1] = "p" +frameTypes[16] = "p" +frameTypes[19] = "p" +frameTypes[20] = "p" +frameTypes[21] = "p" +frameTypes[22] = "p" +frameTypes[23] = "p" +frameTypes[24] = "p" +frameTypes[25] = "p" +frameTypes[28] = "p" +-- rover +frameTypes[10] = "r" +-- boat +frameTypes[11] = "b" + +#ifdef TESTMODE +-- undefined +frameTypes[5] = "" +frameTypes[6] = "" +frameTypes[7] = "" +frameTypes[8] = "" +frameTypes[9] = "" +frameTypes[12] = "" +frameTypes[17] = "" +frameTypes[18] = "" +frameTypes[26] = "" +frameTypes[27] = "" +frameTypes[30] = "" +#endif --TESTMODE + +local soundFileBasePath = "/SOUNDS/yaapu0" +local gpsStatuses = {} + +gpsStatuses[0]="NoGPS" +gpsStatuses[1]="NoLock" +gpsStatuses[2]="2D" +gpsStatuses[3]="3D" +gpsStatuses[4]="DGPS" +gpsStatuses[5]="RTK" +gpsStatuses[6]="RTK" + +--[[ +0 MAV_SEVERITY_EMERGENCY System is unusable. This is a "panic" condition. +1 MAV_SEVERITY_ALERT Action should be taken immediately. Indicates error in non-critical systems. +2 MAV_SEVERITY_CRITICAL Action must be taken immediately. Indicates failure in a primary system. +3 MAV_SEVERITY_ERROR Indicates an error in secondary/redundant systems. +4 MAV_SEVERITY_WARNING Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. +5 MAV_SEVERITY_NOTICE An unusual event has occured, though not an error condition. This should be investigated for the root cause. +6 MAV_SEVERITY_INFO Normal operational messages. Useful for logging. No action is required for these messages. +7 MAV_SEVERITY_DEBUG Useful non-operational messages that can assist in debugging. These should not occur during normal operation. +--]] + +local mavSeverity = {} +mavSeverity[0]="EMR" +mavSeverity[1]="ALR" +mavSeverity[2]="CRT" +mavSeverity[3]="ERR" +mavSeverity[4]="WRN" +mavSeverity[5]="NOT" +mavSeverity[6]="INF" +mavSeverity[7]="DBG" + +------------------------------ +-- TELEMETRY DATA +------------------------------ +local telemetry = {} +-- STATUS +telemetry.flightMode = 0 +telemetry.simpleMode = 0 +telemetry.landComplete = 0 +telemetry.statusArmed = 0 +telemetry.battFailsafe = 0 +telemetry.ekfFailsafe = 0 +telemetry.imuTemp = 0 +-- GPS +telemetry.numSats = 0 +telemetry.gpsStatus = 0 +telemetry.gpsHdopC = 100 +telemetry.gpsAlt = 0 +-- BATT 1 +telemetry.batt1volt = 0 +telemetry.batt1current = 0 +telemetry.batt1mah = 0 +-- BATT 2 +telemetry.batt2volt = 0 +telemetry.batt2current = 0 +telemetry.batt2mah = 0 +-- HOME +telemetry.homeDist = 0 +telemetry.homeAlt = 0 +telemetry.homeAngle = -1 +-- VELANDYAW +telemetry.vSpeed = 0 +telemetry.hSpeed = 0 +telemetry.yaw = 0 +-- ROLLPITCH +telemetry.roll = 0 +telemetry.pitch = 0 +telemetry.range = 0 +-- PARAMS +telemetry.frameType = -1 +telemetry.batt1Capacity = 0 +telemetry.batt2Capacity = 0 +-- GPS +telemetry.lat = nil +telemetry.lon = nil +telemetry.homeLat = nil +telemetry.homeLon = nil +-- WP +telemetry.wpNumber = 0 +telemetry.wpDistance = 0 +telemetry.wpXTError = 0 +telemetry.wpBearing = 0 +telemetry.wpCommands = 0 +-- RC channels +telemetry.rcchannels = {} +-- VFR +telemetry.airspeed = 0 +telemetry.throttle = 0 +telemetry.baroAlt = 0 +-- Total distance +telemetry.totalDist = 0 +-------------------------------- +-- STATUS DATA +-------------------------------- +local status = {} +-- FLVSS 1 +status.cell1min = 0 +status.cell1sum = 0 +-- FLVSS 2 +status.cell2min = 0 +status.cell2sum = 0 +-- FC 1 +status.cell1sumFC = 0 +status.cell1maxFC = 0 +-- FC 2 +status.cell2sumFC = 0 +status.cell2maxFC = 0 +-------------------------------- +status.cell1count = 0 +status.cell2count = 0 + +status.battsource = "na" + +status.batt1sources = { + vs = false, + fc = false +} +status.batt2sources = { + vs = false, + fc = false +} +-- SYNTH VSPEED SUPPORT +status.vspd = 0 +status.synthVSpeedTime = 0 +status.prevHomeAlt = 0 +-- FLIGHT TIME +status.lastTimerStart = 0 +status.timerRunning = 0 +status.flightTime = 0 +-- EVENTS +status.lastStatusArmed = 0 +status.lastGpsStatus = 0 +status.lastFlightMode = 0 +status.lastSimpleMode = 0 +-- battery levels +status.batLevel = 99 +status.battLevel1 = false +status.battLevel2 = false +status.lastBattLevel = 14 +-- MESSAGES +status.messages = {} +status.msgBuffer = "" +status.lastMsgValue = 0 +status.lastMsgTime = 0 +status.lastMessage = nil +status.lastMessageSeverity = 0 +status.lastMessageCount = 1 +status.messageCount = 0 +-- LINK STATUS +status.noTelemetryData = 1 +status.hideNoTelemetry = false +status.showDualBattery = false +status.showMinMaxValues = false +-- FLIGHTMODE +status.strFlightMode = nil +status.modelString = nil +--------------------------- +-- BATTERY TABLE +--------------------------- +local battery = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +--------------------------- +-- LIBRARY LOADING +--------------------------- +local basePath = "/SCRIPTS/YAAPU/" +local libBasePath = basePath.."LIB/" + +-- loadable modules +local drawLibFile = "draw" +local menuLibFile = "menu" + +local frame = {} +local drawLib = {} +local utils = {} + +------------------------------- +-- MAIN SCREEN LAYOUT +------------------------------- +local layout = nil +local centerPanel = nil +local rightPanel = nil +local leftPanel = nil + +local customSensors = nil + +local backlightLastTime = 0 +local resetPending = false + +local alarms = { + --{ notified, alarm_start, armed, type(0=min,1=max,2=timer,3=batt), grace, ready, last_alarm} + { false, 0 , false, ALARM_TYPE_MIN, 0, false, 0}, --MIN_ALT + { false, 0 , false, ALARM_TYPE_MAX, 0, false, 0 }, --MAX_ALT + { false, 0 , false, ALARM_TYPE_MAX, 0, false, 0 }, --MAX_DIST + { false, 0 , true, ALARM_TYPE_MAX, 0, false, 0 }, --FS_EKF + { false, 0 , true, ALARM_TYPE_MAX, 0, false, 0 }, --FS_BAT + { false, 0 , true, ALARM_TYPE_TIMER, 0, false, 0 }, --FLIGTH_TIME + { false, 0 , false, ALARM_TYPE_BATT, ALARM_TYPE_BATT_GRACE, false, 0 }, --BATT L1 + { false, 0 , false, ALARM_TYPE_BATT_CRT, ALARM_TYPE_BATT_GRACE, false, 0 }, --BATT L2 + { false, 0 , false, ALARM_TYPE_MAX, 0, false, 0 } --MAX_HDOP +} + +local transitions = { + --{ last_value, last_changed, transition_done, delay } + { 0, 0, false, 30 }, +} + +-- SYNTH GPS DIST SUPPORT +local prevDist = 0 +local lastSpeed = 0 +local lastYaw = 0 +local lastUpdateTotDist = 0 + +local paramId,paramValue + +local batLevels = {0,5,10,15,20,25,30,40,50,60,70,80,90} +-- Blinking bitmap support +local bitmaps = {} +local blinktime = getTime() +local blinkon = false + +local minmaxValues = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} + +#ifdef LOGTELEMETRY +local logfile +local logfilename +#endif --LOGTELEMETRY + +#ifdef TESTMODE +-- TEST MODE +local thrOut = 0 +#endif --TESTMODE +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() +-- widget selected page +local currentPage = 0 +-------------------------------------------------------------------------------- +-- CONFIGURATION MENU +-------------------------------------------------------------------------------- +local conf = { + language = "en", + defaultBattSource = "na", -- auto + battAlertLevel1 = 0, + battAlertLevel2 = 0, + battCapOverride1 = 0, + battCapOverride2 = 0, + disableAllSounds = false, + disableMsgBeep = 1, + enableHaptic = false, + timerAlert = 0, + repeatAlertsPeriod = 10, + minAltitudeAlert = 0, + maxAltitudeAlert = 0, + maxDistanceAlert = 0, + battConf = BATTCONF_PARALLEL, -- 1=parallel,2=other + cell1Count = 0, + cell2Count = 0, + enableBattPercByVoltage = false, + rangeMax=0, + enableSynthVSpeed=false, + horSpeedMultiplier=1, + vertSpeedMultiplier=1, + horSpeedLabel = "m/s", + vertSpeedLabel = "m/s", + maxHdopAlert = 2, + enablePX4Modes = false, + centerPanel = 1, + rightPanel = 1, + leftPanel = 1, + widgetLayout = 1, + widgetLayoutFilename = nil, + centerPanelFilename = nil, + rightPanelFilename = nil, + leftPanelFilename = nil, + screenToggleChannelId = nil, +} + +#ifdef FNV_HASH +------------------------- +-- message hash support +------------------------- +local shortHashes = { + -- 16 bytes hashes + {554623408}, -- "554623408.wav", "Takeoff complete" + {3025044912}, -- "3025044912.wav", "SmartRTL deactiv" + {3956583920}, -- "3956583920.wav", "EKF2 IMU0 is usi" + {1309405592}, -- "1309405592.wav", "EKF3 IMU0 is usi" + {4091124880,true}, -- "4091124880.wav", "Reached command " + {3311875476,true}, -- "3311875476.wav", "Reached waypoint" + {1997782032,true}, -- "1997782032.wav", "Passed waypoint " +} + +local shortHash = nil +local parseShortHash = false +local hashByteIndex = 0 +local hash = 2166136261 +#endif --FNV_HASH + +local loadCycle = 0 + +utils.doLibrary = function(filename) +#ifdef LOADSCRIPT + local f = assert(loadScript(libBasePath..filename..".lua")) +#else +#ifdef LOAD_LUA + local f = assert(loadfile(libBasePath..filename..".lua")) +#else + local f = assert(loadfile(libBasePath..filename..".luac")) +#endif +#endif + collectgarbage() + collectgarbage() + return f() +end +----------------------------- +-- clears the loaded table +-- and recovers memory +----------------------------- +utils.clearTable = function(t) + if type(t)=="table" then + for i,v in pairs(t) do + if type(v) == "table" then + utils.clearTable(v) + end + t[i] = nil + end + end + t = nil + collectgarbage() + collectgarbage() + maxmem = 0 +end + +local function loadConfig() + -- load menu library + menuLib = loadMenuLib() + menuLib.loadConfig(conf) +#ifdef COMPILE + menuLib.compileLayouts() +#endif + -- ok configuration loaded + status.battsource = conf.defaultBattSource + -- unload libraries + utils.clearTable(menuLib) + utils.clearTable(layout) + layout = nil + utils.clearTable(centerPanel) + centerPanel = nil + utils.clearTable(rightPanel) + rightPanel = nil + utils.clearTable(leftPanel) + leftPanel = nil + collectgarbage() + collectgarbage() +end + +utils.getBitmap = function(name) + if bitmaps[name] == nil then + bitmaps[name] = Bitmap.open("/SCRIPTS/YAAPU/IMAGES/"..name..".png") + end + return bitmaps[name],Bitmap.getSize(bitmaps[name]) +end + +utils.unloadBitmap = function(name) + if bitmaps[name] ~= nil then + bitmaps[name] = nil + -- force call to luaDestroyBitmap() + collectgarbage() + collectgarbage() + end +end + +utils.lcdBacklightOn = function() + model.setGlobalVariable(BACKLIGHT_GV,0,1) + backlightLastTime = getTime()/100 -- seconds +end + +utils.playSound = function(soundFile,skipHaptic) + if conf.enableHaptic and skipHaptic == nil then + playHaptic(15,0) + end + if conf.disableAllSounds then + return + end + utils.lcdBacklightOn() + playFile(soundFileBasePath .."/"..conf.language.."/".. soundFile..".wav") +end + +---------------------------------------------- +-- sound file has same name as flightmode all lowercase with .wav extension +---------------------------------------------- +utils.playSoundByFlightMode = function(flightMode) + if conf.enableHaptic then + playHaptic(15,0) + end + if conf.disableAllSounds then + return + end + if frame.flightModes then + if frame.flightModes[flightMode] ~= nil then + utils.lcdBacklightOn() + -- rover sound files differ because they lack "flight" word + playFile(soundFileBasePath.."/"..conf.language.."/".. string.lower(frame.flightModes[flightMode]) .. ((frameTypes[telemetry.frameType]=="r" or frameTypes[telemetry.frameType]=="b") and "_r.wav" or ".wav")) + end + end +end + +#ifdef LOGTELEMETRY +local function getLogFilename(date) + local info = model.getInfo() + local modelName = string.lower(string.gsub(info.name, "[%c%p%s%z]", "")) + return string.format("/LOGS/%s-%04d%02d%02d_%02d%02d%02d.plog",modelName,date.year,date.mon,date.day,date.hour,date.min,date.sec) +end +#endif --LOGTELEMETRY + +#define MAX_MESSAGES 20 + +local function formatMessage(severity,msg) + local clippedMsg = msg + + if #msg > 50 then + clippedMsg = string.sub(msg,1,50) + msg = nil + collectgarbage() + collectgarbage() + end + + if status.lastMessageCount > 1 then + return string.format("%02d:%s (x%d) %s", status.messageCount, mavSeverity[severity], status.lastMessageCount, clippedMsg) + else + return string.format("%02d:%s %s", status.messageCount, mavSeverity[severity], clippedMsg) + end +end + +utils.pushMessage = function(severity, msg) + if conf.enableHaptic then + playHaptic(15,0) + end + if conf.disableAllSounds == false then + if ( severity < 5 and conf.disableMsgBeep < 3) then + utils.playSound("../err",true) + else + if conf.disableMsgBeep < 2 then + utils.playSound("../inf",true) + end + end + end + + if msg == status.lastMessage then + status.lastMessageCount = status.lastMessageCount + 1 + else + status.lastMessageCount = 1 + status.messageCount = status.messageCount + 1 + end + if status.messages[(status.messageCount-1) % MAX_MESSAGES] == nil then + status.messages[(status.messageCount-1) % MAX_MESSAGES] = {} + end + status.messages[(status.messageCount-1) % MAX_MESSAGES][1] = formatMessage(severity,msg) + status.messages[(status.messageCount-1) % MAX_MESSAGES][2] = severity + + status.lastMessage = msg + status.lastMessageSeverity = severity + -- Collect Garbage + collectgarbage() + collectgarbage() +end + +#ifdef HAVERSINE +utils.haversine = function(lat1, lon1, lat2, lon2) + lat1 = lat1 * math.pi / 180 + lon1 = lon1 * math.pi / 180 + lat2 = lat2 * math.pi / 180 + lon2 = lon2 * math.pi / 180 + + lat_dist = lat2-lat1 + lon_dist = lon2-lon1 + lat_hsin = math.pow(math.sin(lat_dist/2),2) + lon_hsin = math.pow(math.sin(lon_dist/2),2) + + a = lat_hsin + math.cos(lat1) * math.cos(lat2) * lon_hsin + return 2 * 6372.8 * math.asin(math.sqrt(a)) * 1000 +end +#endif --HAVERSINE + +utils.getHomeFromAngleAndDistance = function(telemetry) +--[[ + la1,lo1 coordinates of first point + d be distance (m), + R as radius of Earth (m), + Ad be the angular distance i.e d/R and + θ be the bearing in deg + + la2 = asin(sin la1 * cos Ad + cos la1 * sin Ad * cos θ), and + lo2 = lo1 + atan2(sin θ * sin Ad * cos la1 , cos Ad – sin la1 * sin la2) +--]] + if telemetry.lat == nil or telemetry.lon == nil then + return nil,nil + end + + local lat1 = math.rad(telemetry.lat) + local lon1 = math.rad(telemetry.lon) + local Ad = telemetry.homeDist/(6371000) --meters + local lat2 = math.asin( math.sin(lat1) * math.cos(Ad) + math.cos(lat1) * math.sin(Ad) * math.cos( math.rad(telemetry.homeAngle)) ) + local lon2 = lon1 + math.atan2( math.sin( math.rad(telemetry.homeAngle) ) * math.sin(Ad) * math.cos(lat1) , math.cos(Ad) - math.sin(lat1) * math.sin(lat2)) + return math.deg(lat2), math.deg(lon2) +end + + +utils.decToDMS = function(dec,lat) + local D = math.floor(math.abs(dec)) + local M = (math.abs(dec) - D)*60 + local S = (math.abs((math.abs(dec) - D)*60) - M)*60 + return D .. string.format("\64%04.2f", M) .. (lat and (dec >= 0 and "E" or "W") or (dec >= 0 and "N" or "S")) +end + +utils.decToDMSFull = function(dec,lat) + local D = math.floor(math.abs(dec)) + local M = math.floor((math.abs(dec) - D)*60) + local S = (math.abs((math.abs(dec) - D)*60) - M)*60 + return D .. string.format("\64%d'%04.1f", M, S) .. (lat and (dec >= 0 and "E" or "W") or (dec >= 0 and "N" or "S")) +end + +utils.updateTotalDist = function() + if telemetry.armingStatus == 0 then + lastUpdateTotDist = getTime() + return + end + local delta = getTime() - lastUpdateTotDist + local avgSpeed = (telemetry.hSpeed + lastSpeed)/2 + lastUpdateTotDist = getTime() + lastSpeed = telemetry.hSpeed + if avgSpeed * 0.1 > 1 then + telemetry.totalDist = telemetry.totalDist + (avgSpeed * 0.1 * delta * 0.01) --hSpeed dm/s, getTime()/100 secs + end +end + +utils.drawBlinkBitmap = function(bitmap,x,y) + if blinkon == true then + lcd.drawBitmap(utils.getBitmap(bitmap),x,y) + end +end + +local function getSensorsConfigFilename() + local info = model.getInfo() + return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "").."_sensors.lua") +end + +-------------------------- +-- CUSTOM SENSORS SUPPORT +-------------------------- +#define SENSOR_LABEL 1 +#define SENSOR_NAME 2 +#define SENSOR_PREC 3 +#define SENSOR_UNIT 4 +#define SENSOR_MULT 5 +#define SENSOR_MAX 6 +#define SENSOR_FONT 7 +#define SENSOR_WARN 8 +#define SENSOR_CRIT 9 + +utils.loadCustomSensors = function() + local success, sensorScript = pcall(loadScript,getSensorsConfigFilename()) + if success then + if sensorScript == nil then + customSensors = nil + return + end + collectgarbage() + customSensors = sensorScript() + -- handle nil values for warning and critical levels + for i=1,6 + do + if customSensors.sensors[i] ~= nil then + local sign = customSensors.sensors[i][SENSOR_MAX] == "+" and 1 or -1 + if customSensors.sensors[i][SENSOR_CRIT] == nil then + customSensors.sensors[i][SENSOR_CRIT] = math.huge*sign + end + if customSensors.sensors[i][SENSOR_WARN] == nil then + customSensors.sensors[i][SENSOR_WARN] = math.huge*sign + end + end + end + collectgarbage() + collectgarbage() + else + customSensors = nil + end +end + +local function startTimer() + status.lastTimerStart = getTime()/100 + model.setTimer(2,{mode=1}) +end + +local function stopTimer() + model.setTimer(2,{mode=0}) + status.lastTimerStart = 0 +end + +#ifdef TESTMODE +----------------------------------------------------- +-- TEST MODE +----------------------------------------------------- +local function symTimer() + thrOut = getValue("thr") + if (thrOut > 200 ) then + telemetry.landComplete = 1 + else + telemetry.landComplete = 0 + end +end + +local function symGPS() + thrOut = getValue("thr") + if thrOut > 500 then + telemetry.numSats = 15 + telemetry.gpsStatus = 4 + telemetry.gpsHdopC = 6 + telemetry.ekfFailsafe = 0 + telemetry.battFailsafe = 0 + status.noTelemetryData = 0 + telemetry.statusArmed = 1 + elseif thrOut > 200 then + telemetry.numSats = 12 + telemetry.gpsStatus = 3 + telemetry.gpsHdopC = 25 + telemetry.ekfFailsafe = 0 + telemetry.battFailsafe = 0 + status.noTelemetryData = 0 + telemetry.statusArmed = 1 + elseif thrOut < 200 and thrOut > 0 then + status.vnumSats = 13 + telemetry.gpsStatus = 5 + telemetry.gpsHdopC = 1000 + telemetry.ekfFailsafe = 1 + telemetry.battFailsafe = 0 + status.noTelemetryData = 0 + telemetry.statusArmed = 1 + elseif thrOut > -500 then + telemetry.numSats = 6 + telemetry.gpsStatus = 1 + telemetry.gpsHdopC = 120 + telemetry.ekfFailsafe = 0 + telemetry.battFailsafe = 1 + status.noTelemetryData = 0 + telemetry.statusArmed = 0 + else + telemetry.numSats = 0 + telemetry.gpsStatus = 0 + telemetry.gpsHdopC = 100 + telemetry.ekfFailsafe = 0 + telemetry.battFailsafe = 0 + status.noTelemetryData = 1 + telemetry.statusArmed = 0 + end +end + +local function symFrameType() + local ch11 = getValue("ch11") + if ch11 < -300 then + telemetry.frameType = 2 + elseif ch11 < 300 then + telemetry.frameType = 1 + else + telemetry.frameType = 10 + end +end + +local function symBatt() + thrOut = getValue("thr") + if (thrOut > -500 ) then +#ifdef DEMO + if telemetry.battFailsafe == 1 then + minmaxValues[MIN_BATT1_FC] = CELLCOUNT * 3.40 * 10 + minmaxValues[MIN_BATT2_FC] = CELLCOUNT * 3.43 * 10 + minmaxValues[MAX_CURR] = 341 + 335 + minmaxValues[MAX_CURR1] = 341 + minmaxValues[MAX_CURR2] = 335 + minmaxValues[MAX_POWER] = (CELLCOUNT * 3.43)*(34.1 + 33.5) + -- battery voltage + telemetry.batt1current = 235 + telemetry.batt1volt = CELLCOUNT * 3.43 * 10 + telemetry.batt1Capacity = 5200 + telemetry.batt1mah = 4400 +#ifdef BATT2TEST + telemetry.batt2current = 238 + telemetry.batt2volt = CELLCOUNT * 3.44 * 10 + telemetry.batt2Capacity = 5200 + telemetry.batt2mah = 4500 +#endif --BATT2TEST + else + minmaxValues[MIN_BATT1_FC] = CELLCOUNT * 3.75 * 10 + minmaxValues[MIN_BATT2_FC] = CELLCOUNT * 3.77 * 10 + minmaxValues[MAX_CURR] = 341+335 + minmaxValues[MAX_CURR1] = 341 + minmaxValues[MAX_CURR2] = 335 + minmaxValues[MAX_POWER] = (CELLCOUNT * 3.89)*(34.1+33.5) + -- battery voltage + telemetry.batt1current = 235 + telemetry.batt1volt = CELLCOUNT * 3.87 * 10 + telemetry.batt1Capacity = 5200 + telemetry.batt1mah = 2800 +#ifdef BATT2TEST + telemetry.batt2current = 238 + telemetry.batt2volt = CELLCOUNT * 3.89 * 10 + telemetry.batt2Capacity = 5200 + telemetry.batt2mah = 2700 +#endif --BATT2TEST + end +#else --DEMO + -- battery voltage + telemetry.batt1current = 100 + ((thrOut)*0.01 * 30) + telemetry.batt1volt = CELLCOUNT * (32 + 10*math.abs(thrOut)*0.001) + telemetry.batt1Capacity = 5200 + telemetry.batt1mah = math.abs(1000*(thrOut/200)) +#ifdef BATT2TEST + telemetry.batt2current = 100 + ((thrOut)*0.01 * 30) + telemetry.batt2volt = CELLCOUNT * (32 + 10*math.abs(thrOut)*0.001) + telemetry.batt2Capacity = 5200 + telemetry.batt2mah = math.abs(1000*(thrOut/200)) +#endif --BATT2TEST +#endif --DEMO + -- flightmode +#ifdef DEMO + telemetry.flightMode = 1 + minmaxValues[MAX_GPSALT] = 270*0.1 + minmaxValues[MAX_DIST] = 130 + telemetry.gpsAlt = 200 + telemetry.homeDist = 95 +#else --DEMO + telemetry.flightMode = math.floor(20 * math.abs(thrOut)*0.001) + telemetry.gpsAlt = math.floor(10 * math.abs(thrOut)*0.1) + telemetry.homeDist = math.floor(10 * math.abs(thrOut)*0.1) +#endif --DEMO + else + telemetry.batt1mah = 0 + end +end + +-- simulates attitude by using channel 1 for roll, channel 2 for pitch and channel 4 for yaw +local function symAttitude() +#ifdef DEMO + telemetry.roll = 14 + telemetry.pitch = -0.8 + telemetry.yaw = 33 +#else --DEMO + local rollCh = 0 + local pitchCh = 0 + local yawCh = 0 + -- roll [-1024,1024] ==> [-180,180] + rollCh = getValue("ch1") * 0.088 * 2 + -- clipping + rollCH = rollCh > 0 and math.min(rollCh,180) or math.max(rollCh,-180) + -- pitch [1024,-1024] ==> [-90,90] + pitchCh = getValue("ch2") * 0.088 -- -90<-->90) + -- clipping + pitchCh = pitchCh > 0 and math.min(pitchCh,90) or math.max(pitchCh,-90) + -- yaw [-1024,1024] ==> [0,360] + yawCh = getValue("ch10") + if ( yawCh >= 0) then + yawCh = yawCh * 0.175 + else + yawCh = 360 + (yawCh * 0.175) + end + telemetry.roll = rollCh + telemetry.pitch = pitchCh + telemetry.yaw = yawCh +#endif --DEMO +end + +local function symHome() + local yawCh = 0 + local S2Ch = 0 + -- home angle in deg [0-360] + S2Ch = getValue("ch12") + yawCh = getValue("ch4") +#ifdef DEMO + minmaxValues[MINMAX_ALT] = 45 + minmaxValues[MAX_VSPEED] = 4 + minmaxValues[MAX_HSPEED] = 77 + telemetry.homeAlt = 24 + telemetry.vSpeed = 24 + telemetry.hSpeed = 34 +#else --DEMO + telemetry.homeAlt = yawCh * 0.1 + telemetry.range = 10 * yawCh * 0.1 + telemetry.vSpeed = yawCh * 0.1 + telemetry.hSpeed = telemetry.vSpeed + telemetry.throttle = math.abs(yawCh/10) +#endif --DEMO + if ( yawCh >= 0) then + yawCh = yawCh * 0.175 + else + yawCh = 360 + (yawCh * 0.175) + end + telemetry.yaw = yawCh + if ( S2Ch >= 0) then + S2Ch = S2Ch * 0.175 + else + S2Ch = 360 + (S2Ch * 0.175) + end + if (thrOut > 0 ) then + telemetry.homeAngle = S2Ch + else + telemetry.homeAngle = -1 + end + telemetry.wpNumber = math.min(telemetry.homeDist,1023) + telemetry.wpDistance = telemetry.homeDist + telemetry.totalDist = telemetry.homeDist * 100 + telemetry.wpBearing = (telemetry.yaw / 45) % 8 +end + +local function symMode() + symGPS() + symAttitude() + symTimer() + symHome() + symBatt() + symFrameType() +end +#endif --TESTMODE + +----------------------------------------------------------------- +-- TELEMETRY +----------------------------------------------------------------- +#ifdef LOGTELEMETRY +local lastAttiLogTime = 0 +#endif --LOGTELEMETRY + +local function processTelemetry(DATA_ID,VALUE) + if DATA_ID == 0x5006 then -- ROLLPITCH + -- roll [0,1800] ==> [-180,180] + telemetry.roll = (math.min(bit32.extract(VALUE,0,11),1800) - 900) * 0.2 + -- pitch [0,900] ==> [-90,90] + telemetry.pitch = (math.min(bit32.extract(VALUE,11,10),900) - 450) * 0.2 + -- number encoded on 11 bits: 10 bits for digits + 1 for 10^power + telemetry.range = bit32.extract(VALUE,22,10) * (10^bit32.extract(VALUE,21,1)) -- cm + elseif DATA_ID == 0x5005 then -- VELANDYAW + telemetry.vSpeed = bit32.extract(VALUE,1,7) * (10^bit32.extract(VALUE,0,1)) * (bit32.extract(VALUE,8,1) == 1 and -1 or 1)-- dm/s + telemetry.hSpeed = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) -- dm/s + telemetry.yaw = bit32.extract(VALUE,17,11) * 0.2 + elseif DATA_ID == 0x5001 then -- AP STATUS + telemetry.flightMode = bit32.extract(VALUE,0,5) + telemetry.simpleMode = bit32.extract(VALUE,5,2) + telemetry.landComplete = bit32.extract(VALUE,7,1) + telemetry.statusArmed = bit32.extract(VALUE,8,1) + telemetry.battFailsafe = bit32.extract(VALUE,9,1) + telemetry.ekfFailsafe = bit32.extract(VALUE,10,2) + -- IMU temperature: 0 means temp =< 19°, 63 means temp => 82° + telemetry.imuTemp = bit32.extract(VALUE,26,6) + 19 -- C° + elseif DATA_ID == 0x5002 then -- GPS STATUS + telemetry.numSats = bit32.extract(VALUE,0,4) + -- offset 4: NO_GPS = 0, NO_FIX = 1, GPS_OK_FIX_2D = 2, GPS_OK_FIX_3D or GPS_OK_FIX_3D_DGPS or GPS_OK_FIX_3D_RTK_FLOAT or GPS_OK_FIX_3D_RTK_FIXED = 3 + -- offset 14: 0: no advanced fix, 1: GPS_OK_FIX_3D_DGPS, 2: GPS_OK_FIX_3D_RTK_FLOAT, 3: GPS_OK_FIX_3D_RTK_FIXED + telemetry.gpsStatus = bit32.extract(VALUE,4,2) + bit32.extract(VALUE,14,2) + telemetry.gpsHdopC = bit32.extract(VALUE,7,7) * (10^bit32.extract(VALUE,6,1)) -- dm + telemetry.gpsAlt = bit32.extract(VALUE,24,7) * (10^bit32.extract(VALUE,22,2)) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1)-- dm + elseif DATA_ID == 0x5003 then -- BATT + telemetry.batt1volt = bit32.extract(VALUE,0,9) + -- telemetry max is 51.1V, 51.2 is reported as 0.0, 52.3 is 0.1...60 is 88 + -- if 12S and V > 51.1 ==> Vreal = 51.2 + telemetry.batt1volt + if conf.cell1Count == 12 and telemetry.batt1volt < 240 then + -- assume a 2Vx12 as minimum acceptable "real" voltage + telemetry.batt1volt = 512 + telemetry.batt1volt + end + telemetry.batt1current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) + telemetry.batt1mah = bit32.extract(VALUE,17,15) +#ifdef BATT2TEST + telemetry.batt2volt = bit32.extract(VALUE,0,9) + -- telemetry max is 51.1V, 51.2 is reported as 0.0, 52.3 is 0.1...60 is 88 + -- if 12S and V > 51.1 ==> Vreal = 51.2 + telemetry.batt1volt + if conf.cell2Count == 12 and telemetry.batt2volt < 240 then + -- assume a 2Vx12 as minimum acceptable "real" voltage + telemetry.batt2volt = 512 + telemetry.batt2volt + end + telemetry.batt2current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) + telemetry.batt2mah = bit32.extract(VALUE,17,15) +#endif --BATT2TEST + elseif DATA_ID == 0x5008 then -- BATT2 + telemetry.batt2volt = bit32.extract(VALUE,0,9) + -- telemetry max is 51.1V, 51.2 is reported as 0.0, 52.3 is 0.1...60 is 88 + -- if 12S and V > 51.1 ==> Vreal = 51.2 + telemetry.batt1volt + if conf.cell2Count == 12 and telemetry.batt2volt < 240 then + -- assume a 2Vx12 as minimum acceptable "real" voltage + telemetry.batt2volt = 512 + telemetry.batt2volt + end + telemetry.batt2current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) + telemetry.batt2mah = bit32.extract(VALUE,17,15) + elseif DATA_ID == 0x5004 then -- HOME + telemetry.homeDist = bit32.extract(VALUE,2,10) * (10^bit32.extract(VALUE,0,2)) + telemetry.homeAlt = bit32.extract(VALUE,14,10) * (10^bit32.extract(VALUE,12,2)) * 0.1 * (bit32.extract(VALUE,24,1) == 1 and -1 or 1) + telemetry.homeAngle = bit32.extract(VALUE, 25, 7) * 3 + elseif DATA_ID == 0x5000 then -- MESSAGES + if VALUE ~= status.lastMsgValue then + status.lastMsgValue = VALUE + local c + local msgEnd = false + for i=3,0,-1 + do + c = bit32.extract(VALUE,i*8,7) + if c ~= 0 then + status.msgBuffer = status.msgBuffer .. string.char(c) + collectgarbage() + collectgarbage() +#ifdef FNV_HASH + hash = bit32.bxor(hash, c) + hash = (hash * 16777619) % 2^32 + hashByteIndex = hashByteIndex+1 + -- check if this hash matches any 16bytes prefix hash + if hashByteIndex == 16 then + for i=1,#shortHashes + do + if hash == shortHashes[i][1] then + shortHash = hash + -- check if needs parsing + parseShortHash = shortHashes[i][2] == nil and false or true + break; + end + end + end +#endif --FNV_HASH + else + msgEnd = true; + break; + end + end + if msgEnd then + local severity = (bit32.extract(VALUE,7,1) * 1) + (bit32.extract(VALUE,15,1) * 2) + (bit32.extract(VALUE,23,1) * 4) +#ifdef HASHDEBUG + utils.pushMessage( severity, (shortHash == nil and "H:" or "SH:") .. tostring(shortHash == nil and hash or shortHash) .. " "..status.msgBuffer) +#else + utils.pushMessage( severity, status.msgBuffer) +#endif +#ifdef FNV_HASH + -- try to play the hash sound file without checking + -- for existence, OpenTX will gracefully ignore it :-) + utils.playSound(tostring(shortHash == nil and hash or shortHash),true) + -- if required parse parameter and play it! + if parseShortHash then + local param = string.match(status.msgBuffer, ".*#(%d+).*") + collectgarbage() + if param ~= nil then + playNumber(tonumber(param),0) + collectgarbage() + end + end + -- reset hash for next string + parseShortHash = false + shortHash = nil + hash = 2166136261 + hashByteIndex = 0 +#endif --FNV_HASH + status.msgBuffer = nil + -- recover memory + collectgarbage() + collectgarbage() + status.msgBuffer = "" + end + end + elseif DATA_ID == 0x5007 then -- PARAMS + paramId = bit32.extract(VALUE,24,4) + paramValue = bit32.extract(VALUE,0,24) + if paramId == 1 then + telemetry.frameType = paramValue + elseif paramId == 4 then + telemetry.batt1Capacity = paramValue +#ifdef BATT2TEST + telemetry.batt2Capacity = paramValue +#endif --BATT2TEST + elseif paramId == 5 then + telemetry.batt2Capacity = paramValue + elseif paramId == 6 then + telemetry.wpCommands = paramValue + end + elseif DATA_ID == 0x5009 then -- WAYPOINTS @1Hz + telemetry.wpNumber = bit32.extract(VALUE,0,10) -- wp index + telemetry.wpDistance = bit32.extract(VALUE,12,10) * (10^bit32.extract(VALUE,10,2)) -- meters + telemetry.wpXTError = bit32.extract(VALUE,23,4) * (10^bit32.extract(VALUE,22,1)) * (bit32.extract(VALUE,27,1) == 1 and -1 or 1)-- meters + telemetry.wpBearing = bit32.extract(VALUE,29,3) -- offset from cog with 45° resolution + --[[ + elseif DATA_ID == 0x50F1 then -- RC CHANNELS + -- channels 1 - 32 + local offset = bit32.extract(VALUE,0,4) * 4 + rcchannels[1 + offset] = 100 * (bit32.extract(VALUE,4,6)/63) * (bit32.extract(VALUE,10,1) == 1 and -1 or 1) + rcchannels[2 + offset] = 100 * (bit32.extract(VALUE,11,6)/63) * (bit32.extract(VALUE,17,1) == 1 and -1 or 1) + rcchannels[3 + offset] = 100 * (bit32.extract(VALUE,18,6)/63) * (bit32.extract(VALUE,24,1) == 1 and -1 or 1) + rcchannels[4 + offset] = 100 * (bit32.extract(VALUE,25,6)/63) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1) + --]] + elseif DATA_ID == 0x50F2 then -- VFR + telemetry.airspeed = bit32.extract(VALUE,1,7) * (10^bit32.extract(VALUE,0,1)) -- dm/s + telemetry.throttle = bit32.extract(VALUE,8,7) + telemetry.baroAlt = bit32.extract(VALUE,17,10) * (10^bit32.extract(VALUE,15,2)) * 0.1 * (bit32.extract(VALUE,27,1) == 1 and -1 or 1) + end +end + +#ifdef TESTMODE +local function telemetryEnabled(status) + return true +end +#else --TESTMODE +local function telemetryEnabled() + if getRSSI() == 0 then + status.noTelemetryData = 1 + end + return status.noTelemetryData == 0 +end +#endif --TESTMODE + +utils.getMaxValue = function(value,idx) + minmaxValues[idx] = math.max(value,minmaxValues[idx]) + return status.showMinMaxValues == true and minmaxValues[idx] or value +end + +local function calcMinValue(value,min) + return min == 0 and value or math.min(value,min) +end + +-- returns the actual minimun only if both are > 0 +local function getNonZeroMin(v1,v2) + return v1 == 0 and v2 or ( v2 == 0 and v1 or math.min(v1,v2)) +end + +local function calcCellCount() + -- cellcount override from menu + local c1 = 0 + local c2 = 0 + + if conf.cell1Count ~= nil and conf.cell1Count > 0 then + c1 = conf.cell1Count + elseif status.batt1sources.vs == true and status.cell1count > 1 then + c1 = status.cell1count + else + c1 = math.floor( ((status.cell1maxFC*0.1) / CELLFULL) + 1) + end + + if conf.cell2Count ~= nil and conf.cell2Count > 0 then + c2 = conf.cell2Count + elseif status.batt2sources.vs == true and status.cell2count > 1 then + c2 = status.cell2count + else + c2 = math.floor(((status.cell2maxFC*0.1)/CELLFULL) + 1) + end + + return c1,c2 +end + +local function getBatt1Capacity() + return conf.battCapOverride1 > 0 and conf.battCapOverride1*10 or telemetry.batt1Capacity +end + +local function getBatt2Capacity() + -- this is a fix for passthrough telemetry reporting batt2 capacity > 0 even if BATT2_MONITOR = 0 + return conf.battCapOverride2 > 0 and conf.battCapOverride2*10 or ( status.batt2sources.fc and telemetry.batt2Capacity or 0 ) +end + +-- gets the voltage based on source and min value, battId = [1|2] +local function getMinVoltageBySource(source, cell, cellFC, battId) + -- offset 0 for cell voltage, 2 for pack voltage + local offset = 0 + -- + if cell > CELLFULL*2 or cellFC > CELLFULL*2 then + offset = 2 + end + -- + if source == "vs" then + return status.showMinMaxValues == true and minmaxValues[2+offset+battId] or cell + elseif source == "fc" then + -- FC only tracks batt1 and batt2 no cell voltage tracking + local minmax = (offset == 2 and minmaxValues[battId] or minmaxValues[battId]/calcCellCount()) + return status.showMinMaxValues == true and minmax or cellFC + end + -- + return 0 +end + +local function calcFLVSSBatt(battIdx) + local cellMin,cellSum,cellCount + local battSources = battIdx == 1 and status.batt1sources or status.batt2sources + +#ifdef FLVSS2TEST + local cellResult = battIdx == 1 and getValue("Cels") or getValue("Cels") +#else + local cellResult = battIdx == 1 and getValue("Cels") or getValue("Cel2") +#endif + + if type(cellResult) == "table" then + cellMin = CELLFULL + cellSum = 0 + -- cellcount is global and shared + cellCount = #cellResult + for i, v in pairs(cellResult) do + cellSum = cellSum + v + if cellMin > v then + cellMin = v + end + end + -- if connected after scritp started + if battSources.vs == false then + status.battsource = "na" + end + if status.battsource == "na" then + status.battsource = "vs" + end + battSources.vs = true + else + battSources.vs = false + cellMin = 0 + cellSum = 0 + end + return cellMin,cellSum,cellCount +end + +local function calcBattery() + ------------ + -- FLVSS 1 + ------------ + status.cell1min, status.cell1sum, status.cell1count = calcFLVSSBatt(1) --1 = Cels + + ------------ + -- FLVSS 2 + ------------ + status.cell2min, status.cell2sum, status.cell2count = calcFLVSSBatt(2) --2 = Cel2 + + -------------------------------- + -- flight controller battery 1 + -------------------------------- + if telemetry.batt1volt > 0 then + status.cell1sumFC = telemetry.batt1volt*0.1 + status.cell1maxFC = math.max(telemetry.batt1volt,status.cell1maxFC) + if status.battsource == "na" then + status.battsource = "fc" + end + status.batt1sources.fc = true + else + status.batt1sources.fc = false + status.cell1sumFC = 0 + end + -------------------------------- + -- flight controller battery 2 + -------------------------------- + if telemetry.batt2volt > 0 then + status.cell2sumFC = telemetry.batt2volt*0.1 + status.cell2maxFC = math.max(telemetry.batt2volt,status.cell2maxFC) + if status.battsource == "na" then + status.battsource = "fc" + end + status.batt2sources.fc = true + else + status.batt2sources.fc = false + status.cell2sumFC = 0 + end + -- batt fc + minmaxValues[MIN_BATT1_FC] = calcMinValue(status.cell1sumFC,minmaxValues[MIN_BATT1_FC]) + minmaxValues[MIN_BATT2_FC] = calcMinValue(status.cell2sumFC,minmaxValues[MIN_BATT2_FC]) + -- cell flvss + minmaxValues[MIN_CELL1_VS] = calcMinValue(status.cell1min,minmaxValues[MIN_CELL1_VS]) + minmaxValues[MIN_CELL2_VS] = calcMinValue(status.cell2min,minmaxValues[MIN_CELL2_VS]) + -- batt flvss + minmaxValues[MIN_BATT1_VS] = calcMinValue(status.cell1sum,minmaxValues[MIN_BATT1_VS]) + minmaxValues[MIN_BATT2_VS] = calcMinValue(status.cell2sum,minmaxValues[MIN_BATT2_VS]) + -- + ------------------------------------------ + -- table to pass battery info to panes + -- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 + -- value = offset + [0 aggregate|1 for batt 1| 2 for batt2] + -- batt2 = 4 + 2 = 6 + ------------------------------------------ + -- Note: these can be calculated. not necessary to track them as min/max + -- cell1minFC = cell1sumFC/calcCellCount() + -- cell2minFC = cell2sumFC/calcCellCount() + -- cell1minA2 = cell1sumA2/calcCellCount() + -- + local count1,count2 = calcCellCount() + + battery[BATT_CELL+1] = getMinVoltageBySource(status.battsource, status.cell1min, status.cell1sumFC/count1, 1)*100 --cel1m + battery[BATT_CELL+2] = getMinVoltageBySource(status.battsource, status.cell2min, status.cell2sumFC/count2, 2)*100 --cel2m + battery[BATT_CELL] = (conf.battConf == BATTCONF_OTHER and battery[2] or getNonZeroMin(battery[2], battery[3]) ) + + battery[BATT_VOLT+1] = getMinVoltageBySource(status.battsource, status.cell1sum, status.cell1sumFC, 1)*10 --batt1 + battery[BATT_VOLT+2] = getMinVoltageBySource(status.battsource, status.cell2sum, status.cell2sumFC, 2)*10 --batt2 + battery[BATT_VOLT] = (conf.battConf == BATTCONF_OTHER and battery[5] or (conf.battConf == BATTCONF_SERIAL and battery[5]+battery[6] or getNonZeroMin(battery[5],battery[6]))) + + battery[BATT_CURR] = utils.getMaxValue((conf.battConf == BATTCONF_OTHER and telemetry.batt1current or telemetry.batt1current + telemetry.batt2current),MAX_CURR) + battery[BATT_CURR+1] = utils.getMaxValue(telemetry.batt1current,MAX_CURR1) --curr1 + battery[BATT_CURR+2] = utils.getMaxValue(telemetry.batt2current,MAX_CURR2) --curr2 + + battery[BATT_MAH] = (conf.battConf == BATTCONF_OTHER and telemetry.batt1mah or telemetry.batt1mah + telemetry.batt2mah) + battery[BATT_MAH+1] = telemetry.batt1mah --mah1 + battery[BATT_MAH+2] = telemetry.batt2mah --mah2 + + battery[BATT_CAP] = (conf.battConf == BATTCONF_PARALLEL and getBatt1Capacity() + getBatt2Capacity() or getBatt1Capacity()) + battery[BATT_CAP+1] = getBatt1Capacity() --cap1 + battery[BATT_CAP+2] = getBatt2Capacity() --cap2 + + if status.showDualBattery == true and conf.battConf == BATTCONF_PARALLEL then + -- dual parallel battery: do I have also dual current monitor? + if battery[BATT_CURR+1] > 0 and battery[BATT_CURR+2] == 0 then + -- special case: assume 1 power brick is monitoring batt1+batt2 in parallel + battery[BATT_CURR+1] = battery[BATT_CURR+1]/2 --curr1 + battery[BATT_CURR+2] = battery[BATT_CURR+1] --curr2 + -- + battery[BATT_MAH+1] = battery[BATT_MAH+1]/2 --mah1 + battery[BATT_MAH+2] = battery[BATT_MAH+1] --mah2 + -- + battery[BATT_CAP+1] = battery[BATT_CAP+1]/2 --cap1 + battery[BATT_CAP+2] = battery[BATT_CAP+1] --cap2 + end + end +end + +local function checkLandingStatus() + if ( status.timerRunning == 0 and telemetry.landComplete == 1 and status.lastTimerStart == 0) then + startTimer() + end + if (status.timerRunning == 1 and telemetry.landComplete == 0 and status.lastTimerStart ~= 0) then + stopTimer() + -- play landing complete anly if motorts are armed + if telemetry.statusArmed == 1 then + utils.playSound("landing") + end + end + status.timerRunning = telemetry.landComplete +end + +local resetLib = {} +#ifdef LOAD_LUA +local resetFile = libBasePath.."reset.lua" +#else --LOAD_LUA +local resetFile = libBasePath.."reset.luac" +#endif --LOAD_LUA + +local function reset() + -- ERRORE reset da kill CPU limit!!!!!!!! + -- 2 stage reset + if resetPending == false then + -- initialize status + if resetLib.resetWidget == nil then + resetLib = dofile(resetFile) + collectgarbage() + collectgarbage() + end + -- reset frame + utils.clearTable(frame.frameTypes) + -- reset widget pages + currentPage = 0 + + minmaxValues = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} + + status.showMinMaxValues = false + status.showDualBattery = false + status.strFlightMode = nil + status.modelString = nil + + frame = {} + -- reset all + resetLib.resetTelemetry(status,telemetry,battery,alarms,utils) + -- release resources + utils.clearTable(resetLib) + -- force load model config + model.setGlobalVariable(CONF_GV,CONF_FM_GV,1) + collectgarbage() + collectgarbage() + utils.pushMessage(6,"telemetry reset done!") + resetPending = true + else + -- custom sensors + utils.clearTable(customSensors) + customSensors = nil + utils.loadCustomSensors() + -- done + utils.playSound("yaapu") + collectgarbage() + collectgarbage() + resetPending = false + end +end + +local function calcFlightTime() + -- update local variable with timer 3 value + if ( model.getTimer(2).value < status.flightTime and telemetry.statusArmed == 0) then + reset() + end + if (model.getTimer(2).value < status.flightTime and telemetry.statusArmed == 1) then + model.setTimer(2,{value=status.flightTime}) + utils.pushMessage(4,"Reset ignored while armed") + end + status.flightTime = model.getTimer(2).value +end + +local function setSensorValues() + if (not telemetryEnabled()) then + return + end + local battmah = telemetry.batt1mah + local battcapacity = getBatt1Capacity() + if telemetry.batt2mah > 0 then + battcapacity = getBatt1Capacity() + getBatt2Capacity() + battmah = telemetry.batt1mah + telemetry.batt2mah + end + + local perc = 0 + + if (battcapacity > 0) then + perc = math.min(math.max((1 - (battmah/battcapacity))*100,0),99) + end + + setTelemetryValue(Fuel_ID, Fuel_SUBID, Fuel_INSTANCE, perc, 13 , Fuel_PRECISION , Fuel_NAME) + setTelemetryValue(VFAS_ID, VFAS_SUBID, VFAS_INSTANCE, getNonZeroMin(telemetry.batt1volt,telemetry.batt2volt)*10, 1 , VFAS_PRECISION , VFAS_NAME) + setTelemetryValue(CURR_ID, CURR_SUBID, CURR_INSTANCE, telemetry.batt1current+telemetry.batt2current, 2 , CURR_PRECISION , CURR_NAME) + setTelemetryValue(VSpd_ID, VSpd_SUBID, VSpd_INSTANCE, telemetry.vSpeed, 5 , VSpd_PRECISION , VSpd_NAME) + setTelemetryValue(GSpd_ID, GSpd_SUBID, GSpd_INSTANCE, telemetry.hSpeed*0.1, 5 , GSpd_PRECISION , GSpd_NAME) + setTelemetryValue(Alt_ID, Alt_SUBID, Alt_INSTANCE, telemetry.homeAlt*10, 9 , Alt_PRECISION , Alt_NAME) + setTelemetryValue(GAlt_ID, GAlt_SUBID, GAlt_INSTANCE, math.floor(telemetry.gpsAlt*0.1), 9 , GAlt_PRECISION , GAlt_NAME) + setTelemetryValue(Hdg_ID, Hdg_SUBID, Hdg_INSTANCE, math.floor(telemetry.yaw), 20 , Hdg_PRECISION , Hdg_NAME) + setTelemetryValue(IMUTmp_ID, IMUTmp_SUBID, IMUTmp_INSTANCE, telemetry.imuTemp, 11 , IMUTmp_PRECISION , IMUTmp_NAME) + setTelemetryValue(ARM_ID, ARM_SUBID, ARM_INSTANCE, telemetry.statusArmed*100, 0 , ARM_PRECISION , ARM_NAME) +end + +utils.drawTopBar = function() + lcd.setColor(CUSTOM_COLOR,COLOR_BARS) + -- black bar + lcd.drawFilledRectangle(0,0, LCD_W, 18, CUSTOM_COLOR) + -- frametype and model name + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + if status.modelString ~= nil then + lcd.drawText(2, RSSI_Y, status.modelString, CUSTOM_COLOR) + end + -- flight time + local time = getDateTime() + local strtime = string.format("%02d:%02d:%02d",time.hour,time.min,time.sec) + lcd.drawText(LCD_W, RSSI_Y+4, strtime, SMLSIZE+RIGHT+CUSTOM_COLOR) + -- RSSI + if telemetryEnabled() == false then + lcd.setColor(CUSTOM_COLOR,COLOR_RED) + lcd.drawText(RSSI_X-23, RSSI_Y, "NO TELEM", RSSI_FLAGS+CUSTOM_COLOR) + else + lcd.drawText(RSSI_X, RSSI_Y, "RS:", RSSI_FLAGS+CUSTOM_COLOR) +#ifdef DEMO + lcd.drawText(RSSI_X + 30,RSSI_Y, 87, RSSI_FLAGS+CUSTOM_COLOR) +#else --DEMO + lcd.drawText(RSSI_X + 30,RSSI_Y, getRSSI(), RSSI_FLAGS+CUSTOM_COLOR) +#endif --DEMO + end + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- tx voltage + local vtx = string.format("Tx:%.1fv",getValue(getFieldInfo("tx-voltage").id)) + lcd.drawText(TXVOLTAGE_X,TXVOLTAGE_Y, vtx, TXVOLTAGE_FLAGS+CUSTOM_COLOR) +end + +local function drawMessageScreen() + for i=0,#status.messages do + if status.messages[(status.messageCount + i) % (#status.messages+1)][2] == 4 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255,0)) + elseif status.messages[(status.messageCount + i) % (#status.messages+1)][2] < 4 then + --lcd.setColor(CUSTOM_COLOR,COLOR_RED) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,70,0)) + else + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + end + lcd.drawText(0,2+13*i, status.messages[(status.messageCount + i) % (#status.messages+1)][1],SMLSIZE+CUSTOM_COLOR) + end + + lcd.setColor(CUSTOM_COLOR,COLOR_BG) + lcd.drawFilledRectangle(405,0,75,272,CUSTOM_COLOR) + + #define TXT_X 410 + #define TXT_ALIGN 0 + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + -- print info on the right + -- CELL + if battery[BATT_CELL] * 0.01 < 10 then + lcd.drawNumber(TXT_X, 0, battery[BATT_CELL] + 0.5, PREC2+TXT_ALIGN+MIDSIZE+CUSTOM_COLOR) + else + lcd.drawNumber(TXT_X, 0, (battery[BATT_CELL] + 0.5)*0.1, PREC1+TXT_ALIGN+MIDSIZE+CUSTOM_COLOR) + end + lcd.drawText(TXT_X+50, 1, status.battsource, SMLSIZE+CUSTOM_COLOR) + lcd.drawText(TXT_X+50, 11, "V", SMLSIZE+CUSTOM_COLOR) + -- ALT + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(TXT_X, 25, "Alt("..UNIT_ALT_LABEL..")", SMLSIZE+TXT_ALIGN+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(TXT_X,37,telemetry.homeAlt*UNIT_ALT_SCALE,MIDSIZE+CUSTOM_COLOR+TXT_ALIGN) + -- SPEED + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(TXT_X, 60, "Spd("..UNIT_HSPEED_LABEL..")", SMLSIZE+TXT_ALIGN+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(TXT_X,72,telemetry.hSpeed*0.1* UNIT_HSPEED_SCALE,MIDSIZE+CUSTOM_COLOR+TXT_ALIGN) + -- VSPEED + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(TXT_X, 95, "VSI("..UNIT_VSPEED_LABEL..")", SMLSIZE+TXT_ALIGN+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(TXT_X,107, telemetry.vSpeed*0.1*UNIT_VSPEED_SCALE, MIDSIZE+CUSTOM_COLOR+TXT_ALIGN) + -- DIST + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(TXT_X, 130, "Dist("..UNIT_DIST_LABEL..")", SMLSIZE+TXT_ALIGN+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(TXT_X, 142, telemetry.homeDist*UNIT_DIST_SCALE, MIDSIZE+TXT_ALIGN+CUSTOM_COLOR) + -- HDG + lcd.setColor(CUSTOM_COLOR,COLOR_LABEL) + lcd.drawText(TXT_X, 165, "Heading", SMLSIZE+TXT_ALIGN+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawNumber(TXT_X, 177, telemetry.yaw, MIDSIZE+TXT_ALIGN+CUSTOM_COLOR) + -- HOMEDIR + lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + drawLib.drawRArrow(442,235,22,math.floor(telemetry.homeAngle - telemetry.yaw),CUSTOM_COLOR)--HomeDirection(telemetry) +end + +#ifdef COMPASS_ROSE +#define COMPASS_CHARSIZE 10 +#define COMPASS_RADIUS 30 +#define COMPASS_LINE 5 + +local compassPoints = {} + +compassPoints[0] = "N" +compassPoints[1] = nil +compassPoints[2] = "E" +compassPoints[3] = nil +compassPoints[4] = "S" +compassPoints[5] = nil +compassPoints[6] = "W" +compassPoints[7] = nil + +local function drawCompassRose() + local hw = math.floor(YAW_WIDTH/2) + local yawRounded = roundTo(telemetry.yaw,1) + local homeRounded = roundTo(telemetry.homeAngle,1) + local minY = TOPBAR_Y + TOPBAR_HEIGHT - 1 + local Hdy = math.sin(math.rad(270+homeRounded-yawRounded))*COMPASS_RADIUS + local Hdx = math.cos(math.rad(270+homeRounded-yawRounded))*COMPASS_RADIUS + for ang=0,7 + do + local Rdy = math.sin(math.rad(45*ang+270-yawRounded))*COMPASS_RADIUS + local Rdx = math.cos(math.rad(45*ang+270-yawRounded))*COMPASS_RADIUS + local Ldy = math.sin(math.rad(45*ang+270-yawRounded))*(COMPASS_RADIUS-COMPASS_LINE) + local Ldx = math.cos(math.rad(45*ang+270-yawRounded))*(COMPASS_RADIUS-COMPASS_LINE) + if compassPoints[ang] == nil then + lcd.drawLine(HOMEDIR_X+Ldx,HOMEDIR_Y+Ldy,HOMEDIR_X+Rdx,HOMEDIR_Y+Rdy,SOLID,2) + else + lcd.drawText(HOMEDIR_X+Rdx-(COMPASS_CHARSIZE/2),HOMEDIR_Y+Rdy-(COMPASS_CHARSIZE/2),compassPoints[ang],0) + end + end + drawLib.drawHomeIcon(HOMEDIR_X+Hdx-(COMPASS_CHARSIZE/2),HOMEDIR_Y+Hdy-(COMPASS_CHARSIZE/2),utils) + -- + local xx = 0 + if ( telemetry.yaw < 10) then + xx = 1 + elseif (telemetry.yaw < 100) then + xx = -8 + else + xx = -12 + end + lcd.drawNumber(HOMEDIR_X + xx - 5, HOMEDIR_Y - COMPASS_RADIUS - 24, telemetry.yaw, INVERS) +end +#endif +--------------------------------- +-- This function checks alarm condition and as long as the condition persists it plays +-- a warning sound. +--------------------------------- +utils.checkAlarm = function(level,value,idx,sign,sound,delay) + -- once landed reset all alarms except battery alerts + if status.timerRunning == 0 then + if alarms[idx][ALARM_TYPE] == ALARM_TYPE_MIN then + alarms[idx] = { false, 0, false, ALARM_TYPE_MIN, 0, false, 0} + elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_MAX then + alarms[idx] = { false, 0, true, ALARM_TYPE_MAX, 0, false, 0} + elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_TIMER then + alarms[idx] = { false, 0, true, ALARM_TYPE_TIMER, 0, false, 0} + elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_BATT then + alarms[idx] = { false, 0 , false, ALARM_TYPE_BATT, ALARM_TYPE_BATT_GRACE, false, 0} + elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_BATT_CRT then + alarms[idx] = { false, 0 , false, ALARM_TYPE_BATT_CRT, ALARM_TYPE_BATT_GRACE, false, 0} + end + -- reset done + return + end + -- if needed arm the alarm only after value has reached level + if alarms[idx][ALARM_ARMED] == false and level > 0 and -1 * sign*value > -1 * sign*level then + alarms[idx][ALARM_ARMED] = true + end + + if alarms[idx][ALARM_TYPE] == ALARM_TYPE_TIMER then + if status.flightTime > 0 and math.floor(status.flightTime) % delay == 0 then + if alarms[idx][ALARM_NOTIFIED] == false then + alarms[idx][ALARM_NOTIFIED] = true + utils.playSound(sound) + playDuration(status.flightTime,(status.flightTime > 3600 and 1 or 0)) -- minutes,seconds + end + else + alarms[idx][ALARM_NOTIFIED] = false + end + else + if alarms[idx][ALARM_ARMED] == true then + if level > 0 and sign*value > sign*level then + -- value is outside level + if alarms[idx][ALARM_START] == 0 then + -- first time outside level after last reset + alarms[idx][ALARM_START] = status.flightTime + -- status: START + end + else + -- value back to normal ==> reset + alarms[idx][ALARM_START] = 0 + alarms[idx][ALARM_NOTIFIED] = false + alarms[idx][ALARM_READY] = false + -- status: RESET + end + if alarms[idx][ALARM_START] > 0 and (status.flightTime ~= alarms[idx][ALARM_START]) and (status.flightTime - alarms[idx][ALARM_START]) >= alarms[idx][ALARM_GRACE] then + -- enough time has passed after START + alarms[idx][ALARM_READY] = true + -- status: READY + end + + if alarms[idx][ALARM_READY] == true and alarms[idx][ALARM_NOTIFIED] == false then + utils.playSound(sound) + alarms[idx][ALARM_NOTIFIED] = true + alarms[idx][ALARM_LAST_ALARM] = status.flightTime + -- status: BEEP + end + -- all but battery alarms + if alarms[idx][ALARM_TYPE] ~= ALARM_TYPE_BATT then + if alarms[idx][ALARM_READY] == true and status.flightTime ~= alarms[idx][ALARM_LAST_ALARM] and (status.flightTime - alarms[idx][ALARM_LAST_ALARM]) % delay == 0 then + alarms[idx][ALARM_NOTIFIED] = false + -- status: REPEAT + end + end + end + end +end + +local function loadFlightModes() + if frame.flightModes then + return + end + if telemetry.frameType ~= -1 then + if frameTypes[telemetry.frameType] == "c" then + frame = utils.doLibrary(conf.enablePX4Modes and "copter_px4" or "copter") + elseif frameTypes[telemetry.frameType] == "p" then + frame = utils.doLibrary(conf.enablePX4Modes and "plane_px4" or "plane") + elseif frameTypes[telemetry.frameType] == "r" or frameTypes[telemetry.frameType] == "b" then + frame = utils.doLibrary("rover") + end + collectgarbage() + collectgarbage() + maxmem = 0 + end +end +--[[ +local function loadFlightModes() + if frame.flightModes then + return + end + + if telemetry.frameType ~= -1 then +#ifdef LOAD_LUA + if frameTypes[telemetry.frameType] == "c" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "copter_px4.lua" or "copter.lua")) + elseif frameTypes[telemetry.frameType] == "p" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "plane_px4.lua" or "plane.lua")) + elseif frameTypes[telemetry.frameType] == "r" then + frame = dofile(libBasePath.."rover.lua") + end +#else + if frameTypes[telemetry.frameType] == "c" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "copter_px4.luac" or "copter.luac")) + elseif frameTypes[telemetry.frameType] == "p" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "plane_px4.luac" or "plane.luac")) + elseif frameTypes[telemetry.frameType] == "r" then + frame = dofile(libBasePath.."rover.luac") + end +#endif + collectgarbage() + maxmem = 0 + end +end +--]] + +--------------------------------- +-- This function checks state transitions and only returns true if a specific delay has passed +-- new transitions reset the delay timer +--------------------------------- +local function checkTransition(idx,value) + if value ~= transitions[idx][TRANSITION_LASTVALUE] then + -- value has changed + transitions[idx][TRANSITION_LASTVALUE] = value + transitions[idx][TRANSITION_LASTCHANGED] = getTime() + transitions[idx][TRANSITION_DONE] = false + -- status: RESET + return false + end + if transitions[idx][TRANSITION_DONE] == false and (getTime() - transitions[idx][TRANSITION_LASTCHANGED]) > transitions[idx][TRANSITION_DELAY] then + -- enough time has passed after RESET + transitions[idx][TRANSITION_DONE] = true + -- status: FIRE + return true; + end +end + +local function checkEvents(celm) + loadFlightModes() + + -- silence alarms when showing min/max values + if status.showMinMaxValues == false then + utils.checkAlarm(conf.minAltitudeAlert,telemetry.homeAlt,ALARMS_MIN_ALT,-1,"minalt",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.maxAltitudeAlert,telemetry.homeAlt,ALARMS_MAX_ALT,1,"maxalt",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.maxDistanceAlert,telemetry.homeDist,ALARMS_MAX_DIST,1,"maxdist",conf.repeatAlertsPeriod) + utils.checkAlarm(1,2*telemetry.ekfFailsafe,ALARMS_FS_EKF,1,"ekf",conf.repeatAlertsPeriod) + utils.checkAlarm(1,2*telemetry.battFailsafe,ALARMS_FS_BATT,1,"lowbat",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.timerAlert,status.flightTime,ALARMS_TIMER,1,"timealert",conf.timerAlert) +#ifdef HDOP_ALERT + if telemetry.gpsStatus > 2 then + utils.checkAlarm(conf.maxHdopAlert,telemetry.gpsHdopC,ALARMS_MAX_HDOP,1,"badgps",conf.repeatAlertsPeriod) + end +#endif + end + + -- default is use battery 1 + local capacity = getBatt1Capacity() + local mah = telemetry.batt1mah + -- only if dual battery has been detected use battery 2 + if (status.batt2sources.fc or status.batt2sources.vs) and conf.battConf == BATTCONF_PARALLEL then + capacity = capacity + getBatt2Capacity() + mah = mah + telemetry.batt2mah + end + -- +#ifdef BATTPERC_BY_VOLTAGE + if conf.enableBattPercByVoltage == true then + -- discharge curve is based on battery under load, when motors are disarmed + -- cellvoltage needs to be corrected by subtracting the "under load" voltage drop + if telemetry.statusArmed then + status.batLevel = getBattPercByCell(celm*0.01) + else + status.batLevel = getBattPercByCell((celm*0.01)-VOLTAGE_DROP) + end + else +#endif + if (capacity > 0) then + status.batLevel = (1 - (mah/capacity))*100 + else + status.batLevel = 99 + end +#ifdef BATTPERC_BY_VOLTAGE + end +#endif + for l=1,13 do + -- trigger alarm as as soon as it falls below level + 1 (i.e 91%,81%,71%,...) + if status.batLevel <= batLevels[l] + 1 and l < status.lastBattLevel then + status.lastBattLevel = l + utils.playSound("bat"..batLevels[l]) + break + end + end + + if telemetry.statusArmed == 1 and status.lastStatusArmed == 0 then + status.lastStatusArmed = telemetry.statusArmed + utils.playSound("armed") + -- reset home on arming + telemetry.homeLat = nil + telemetry.homeLon = nil + elseif telemetry.statusArmed == 0 and status.lastStatusArmed == 1 then + status.lastStatusArmed = telemetry.statusArmed + utils.playSound("disarmed") + end + + if telemetry.gpsStatus > 2 and status.lastGpsStatus <= 2 then + status.lastGpsStatus = telemetry.gpsStatus + utils.playSound("gpsfix") + elseif telemetry.gpsStatus <= 2 and status.lastGpsStatus > 2 then + status.lastGpsStatus = telemetry.gpsStatus + utils.playSound("gpsnofix") + end + + -- home detecting code + if telemetry.homeLat == nil then + if telemetry.gpsStatus > 2 and telemetry.homeAngle ~= -1 then + telemetry.homeLat, telemetry.homeLon = utils.getHomeFromAngleAndDistance(telemetry) + end + end + + -- flightmode transitions have a grace period to prevent unwanted flightmode call out + -- on quick radio mode switches + if telemetry.frameType ~= -1 and checkTransition(TRANSITIONS_FLIGHTMODE,telemetry.flightMode) then + utils.playSoundByFlightMode(telemetry.flightMode) + end + + if telemetry.simpleMode ~= status.lastSimpleMode then + if telemetry.simpleMode == 0 then + utils.playSound( status.lastSimpleMode == 1 and "simpleoff" or "ssimpleoff" ) + else + utils.playSound( telemetry.simpleMode == 1 and "simpleon" or "ssimpleon" ) + end + status.lastSimpleMode = telemetry.simpleMode + end +end + +local function checkCellVoltage(celm) + -- check alarms + utils.checkAlarm(conf.battAlertLevel1,celm,ALARMS_BATT_L1,-1,"batalert1",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.battAlertLevel2,celm,ALARMS_BATT_L2,-1,"batalert2",conf.repeatAlertsPeriod) + -- cell bgcolor is sticky but gets triggered with alarms + if status.battLevel1 == false then status.battLevel1 = alarms[ALARMS_BATT_L1][ALARM_NOTIFIED] end + if status.battLevel2 == false then status.battLevel2 = alarms[ALARMS_BATT_L2][ALARM_NOTIFIED] end +end + +local function cycleBatteryInfo() + if status.showDualBattery == false and (status.batt2sources.fc or status.batt2sources.vs) and conf.battConf ~= BATTCONF_SERIAL then + status.showDualBattery = true + return + end + status.battsource = status.battsource == "vs" and "fc" or "vs" +end +-------------------------------------------------------------------------------- +-- MAIN LOOP +-------------------------------------------------------------------------------- +-- +local bgclock = 0 +#ifdef BGTELERATE +local bgtelecounter = 0 +local bgtelerate = 0 +local bgtelestart = 0 +#endif --BGTELERATE + +------------------------------- +-- running at 20Hz (every 50ms) +------------------------------- +local timer2Hz = getTime() +local function backgroundTasks(myWidget,telemetryLoops) + -- FAST: this runs at 60Hz (every 16ms) + for i=1,telemetryLoops + do + local sensor_id,frame_id,data_id,value = sportTelemetryPop() + + if frame_id == 0x10 then + status.noTelemetryData = 0 + -- no telemetry dialog only shown once + status.hideNoTelemetry = true + processTelemetry(data_id,value) +#ifdef LOGTELEMETRY + -- log pitch and roll at max 3Hz + if lastAttiLogTime == 0 then + io.write(logfile, getTime(),";" , flightTime, ";", data_id, ";", value, "\r\n") + lastAttiLogTime = getTime() + elseif DATA_ID == 0x5006 and getTime() - lastAttiLogTime > 33 then -- 330ms + io.write(logfile, getTime(),";" , flightTime, ";", data_id, ";", value, "\r\n") + lastAttiLogTime = getTime() + else + io.write(logfile, getTime(),";" , flightTime, ";", data_id, ";", value, "\r\n") + end +#endif --LOGTELEMETRY + end +#ifdef BGTELERATE + ------------------------ + -- CALC BG TELE PROCESSING RATE + ------------------------ + -- skip first iteration + local now = getTime() + + if bgtelecounter == 0 then + bgtelestart = now + else + bgtelerate = bgtelerate*0.8 + 100*0.2*bgtelecounter/(now - bgtelestart + 1) + end + -- + bgtelecounter=bgtelecounter+1 + + if now - bgtelestart > 1000 then + bgtelecounter = 0 + end +#endif --BGTELERATE + end + -- SLOW: this runs around 2.5Hz + if bgclock % 2 == 1 then + calcFlightTime() + -- update gps telemetry data + local gpsData = getValue("GPS") + + if type(gpsData) == "table" and gpsData.lat ~= nil and gpsData.lon ~= nil then + telemetry.lat = gpsData.lat + telemetry.lon = gpsData.lon + end + --export OpenTX sensor values + setSensorValues() + -- update total distance as often as po + utils.updateTotalDist() + + if getTime() - timer2Hz > 50 then + status.screenTogglePage = utils.getScreenTogglePage(myWidget,conf,status) + timer2Hz = getTime() + end + + -- flight mode + if frame.flightModes then + status.strFlightMode = frame.flightModes[telemetry.flightMode] + if status.strFlightMode ~= nil and telemetry.simpleMode > 0 then + local strSimpleMode = telemetry.simpleMode == 1 and "(S)" or "(SS)" + status.strFlightMode = string.format("%s%s",status.strFlightMode,strSimpleMode) + end + end + + -- top bar model frame and name + if status.modelString == nil then + -- frametype and model name + local info = model.getInfo() + local fn = frameNames[telemetry.frameType] + local strmodel = info.name + if fn ~= nil then + status.modelString = fn..": "..info.name + end + end + end + + -- SLOWER: this runs around 1.25Hz but not when the previous block runs + -- because bgclock%4 == 0 is always different than bgclock%2==1 + if bgclock % 4 == 0 then + -- update battery + calcBattery() + -- prepare celm based on status.battsource + local count1,count2 = calcCellCount() + local cellVoltage = 0 + + if conf.battConf == BATTCONF_OTHER then + -- alarms are based on battery 1 + cellVoltage = 100*(status.battsource == "vs" and status.cell1min or status.cell1sumFC/count1) + else + -- alarms are based on battery 1 and battery 2 + cellVoltage = 100*(status.battsource == "vs" and getNonZeroMin(status.cell1min,status.cell2min) or getNonZeroMin(status.cell1sumFC/count1,status.cell2sumFC/count2)) + end + + checkEvents(cellVoltage) + checkLandingStatus() + -- no need for alarms if reported voltage is 0 + if cellVoltage > 0 then + checkCellVoltage(cellVoltage) + end + -- aggregate value + minmaxValues[MAX_CURR] = math.max((conf.battConf == BATTCONF_OTHER and telemetry.batt1current or telemetry.batt1current+telemetry.batt2current), minmaxValues[MAX_CURR]) + + -- indipendent values + minmaxValues[MAX_CURR1] = math.max(telemetry.batt1current,minmaxValues[MAX_CURR1]) + minmaxValues[MAX_CURR2] = math.max(telemetry.batt2current,minmaxValues[MAX_CURR2]) + + -- reset backlight panel + if (model.getGlobalVariable(BACKLIGHT_GV,0) > 0 and getTime()/100 - backlightLastTime > BACKLIGHT_DURATION) then + model.setGlobalVariable(BACKLIGHT_GV,0,0) + end + -- reload config + if (model.getGlobalVariable(CONF_GV,CONF_FM_GV) > 0) then + loadConfig() + model.setGlobalVariable(CONF_GV,CONF_FM_GV,0) + end + -- call custom panel background functions + if leftPanel ~= nil then + leftPanel.background(myWidget,conf,telemetry,status,utils) + end + if centerPanel ~= nil then + centerPanel.background(myWidget,conf,telemetry,status,utils) + end + if rightPanel ~= nil then + rightPanel.background(myWidget,conf,telemetry,status,utils) + end + + bgclock = 0 + end + bgclock = bgclock+1 + -- blinking support + if (getTime() - blinktime) > 65 then + blinkon = not blinkon + blinktime = getTime() +#ifdef LOGTELEMETRY + -- flush + pcall(io.close,logfile) + logfile = io.open(logfilename,"a") +#endif --LOGTELEMETRY + end + collectgarbage() + collectgarbage() + return 0 +end + +local showSensorPage = false +local showMessages = false + +local function init() +#ifdef COMPILE + loadScript("/SCRIPTS/YAAPU/menu.lua","c") + loadScript(libBasePath.."reset.lua","c") + loadScript(libBasePath.."copter.lua","c") + loadScript(libBasePath.."plane.lua","c") + loadScript(libBasePath.."copter_px4.lua","c") + loadScript(libBasePath.."plane_px4.lua","c") + loadScript(libBasePath.."rover.lua","c") + loadScript(libBasePath..drawLibFile..".lua","c") +#endif + -- initialize flight timer + model.setTimer(2,{mode=0}) +#ifdef TESTMODE + telemetry.lat = -35.362864 + telemetry.lon = 149.165491 +#else + model.setTimer(2,{value=0}) +#endif +-- load configuration at boot and only refresh if GV(8,8) = 1 + loadConfig() + -- load draw library + drawLib = utils.doLibrary(drawLibFile) + + currentModel = model.getInfo().name + -- load custom sensors + utils.loadCustomSensors() + -- ok done + utils.pushMessage(7,VERSION) +#ifdef TESTMODE +#ifdef DEMO + utils.pushMessage(6,"APM:Copter V3.5.4 (284349c3) QUAD") + utils.pushMessage(6,"Calibrating barometer") + utils.pushMessage(6,"Initialising APM") + utils.pushMessage(6,"Barometer calibration complete") + utils.pushMessage(6,"EKF2 IMU0 initial yaw alignment complete") + utils.pushMessage(6,"EKF2 IMU1 initial yaw alignment complete") + utils.pushMessage(6,"GPS 1: detected as u-blox at 115200 baud") + utils.pushMessage(6,"EKF2 IMU0 tilt alignment complete") + utils.pushMessage(6,"EKF2 IMU1 tilt alignment complete") + utils.pushMessage(6,"u-blox 1 HW: 00080000 SW: 2.01 (75331)") + utils.pushMessage(4,"Bad AHRS") +#else -- add some more messages to force memory allocation :-) +#ifdef TESTMESSAGES + utils.pushMessage(6,"APM:Copter V3.5.4 (284349c3) QUAD") + utils.pushMessage(6,"Calibrating barometer") + utils.pushMessage(6,"Initialising APM") + utils.pushMessage(6,"Barometer calibration complete") + utils.pushMessage(6,"EKF2 IMU0 initial yaw alignment complete") + utils.pushMessage(6,"EKF2 IMU1 initial yaw alignment complete") +#endif --TESTMESSAGES +#endif --DEMO +#endif --TESTMODE +#ifdef LOGTELEMETRY + logfilename = getLogFilename(getDateTime()) + logfile = io.open(logfilename,"a") + io.write(logfile, "counter;f_time;data_id;value\r\n") + utils.pushMessage(7,logfilename) +#endif --LOGTELEMETRY + utils.playSound("yaapu") + -- fix for generalsettings lazy loading... + unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 + unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" + unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 + unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" +end + +-------------------------------------------------------------------------------- +-- 4 pages +-- page 1 single battery view +-- page 2 message history +-- page 3 min max +-- page 4 dual battery view +local options = { + { "page", VALUE, 1, 1, 5}, +} +-- shared init flag +local initDone = 0 +-- This function is runned once at the creation of the widget +local function create(zone, options) + -- this vars are widget scoped, each instance has its own set + local vars = { + #ifdef HUDRATE + hudcounter = 0, + hudrate = 0, + hudstart = 0, + #endif --HUDRATE + } + -- all local vars are shared between widget instances + -- init() needs to be called only once! + if initDone == 0 then + init() + initDone = 1 + end + -- + return { zone=zone, options=options, vars=vars } +end +-- This function allow updates when you change widgets settings +local function update(myWidget, options) + myWidget.options = options + -- reload menu settings + loadConfig() +end + +local function fullScreenRequired(myWidget) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0, 0)) + lcd.drawText(myWidget.zone.x,myWidget.zone.y,"Yaapu requires",SMLSIZE+CUSTOM_COLOR) + lcd.drawText(myWidget.zone.x,myWidget.zone.y+16,"full screen",SMLSIZE+CUSTOM_COLOR) +end + + +utils.getScreenTogglePage = function(myWidget,conf,status) +#ifdef TESTMODE + local screenChValue = getValue(conf.screenToggleChannelId) +#else + local screenChValue = status.hideNoTelemetry == false and -1000 or getValue(conf.screenToggleChannelId) +#endif --TESTMODE + + if conf.screenToggleChannelId > -1 then + if screenChValue > -600 then + -- message history + return 2 + end + end + return myWidget.options.page +end + +-- called when widget instance page changes +local function onChangePage(myWidget) +#ifdef BGTELERATE + bgtelecounter = 0 +#endif --BGTELERATE + -- reset HUD counters + myWidget.vars.hudcounter = 0 + collectgarbage() + collectgarbage() +end + +-- Called when script is hidden @20Hz +local function background(myWidget) + -- when page 1 goes to background run bg tasks + if myWidget.options.page == 1 then + -- run bg tasks + backgroundTasks(myWidget,12) + return + end + -- when page 3 goes to background hide minmax values + if myWidget.options.page == 3 then + status.showMinMaxValues = false + return + end + -- when page 4 goes to background hide dual battery view + if myWidget.options.page == 4 then + status.showDualBattery = false + return + end +end + +local slowTimer = getTime() + +-- Called when script is visible +local function drawFullScreen(myWidget) +#ifdef HUDRATE + ------------------------ + -- CALC HUD REFRESH RATE + ------------------------ + -- skip first iteration + local hudnow = getTime() + + if myWidget.vars.hudcounter == 0 then + myWidget.vars.hudstart = hudnow + else + myWidget.vars.hudrate = myWidget.vars.hudrate*0.8 + 100*(myWidget.vars.hudcounter/(hudnow - myWidget.vars.hudstart + 1))*0.2 + end + -- + myWidget.vars.hudcounter=myWidget.vars.hudcounter+1 + + if hudnow - myWidget.vars.hudstart + 1 > 1000 then + myWidget.vars.hudcounter = 0 + end +#endif --HUDRATE + if getTime() - slowTimer > 50 then + -- reset phase 2 if reset pending + if resetPending == true then + reset() + else + -- frametype and model name + local info = model.getInfo() + -- model change event + if currentModel ~= info.name then + currentModel = info.name + -- trigger reset phase 1 + reset() + end + end + + if myWidget.options.page == 3 then + -- when page 3 goes to foreground show minmax values + status.showMinMaxValues = true + elseif myWidget.options.page == 4 then + -- when page 4 goes to foreground show dual battery view + status.showDualBattery = true + end + + -- check if current widget page changed + if currentPage ~= myWidget.options.page then + currentPage = myWidget.options.page + onChangePage(myWidget) + end + + slowTimer = getTime() + end + + -- when page 1 goes to foreground run bg tasks + if myWidget.options.page == 1 then + -- run bg tasks only if we are not resetting, this prevent cpu limit kill + if resetPending == false then + backgroundTasks(myWidget,12) + end + end + -- +#ifdef TESTMODE + symMode() +#endif --TESTMODE + + lcd.setColor(CUSTOM_COLOR, COLOR_BG) + if myWidget.options.page == 2 or status.screenTogglePage == 2 then + ------------------------------------ + -- Widget Page 2 is message history + ------------------------------------ + -- message history has black background + lcd.setColor(CUSTOM_COLOR, COLOR_BLACK) + lcd.clear(CUSTOM_COLOR) + + drawMessageScreen() + else + lcd.clear(CUSTOM_COLOR) + + if layout ~= nil then + layout.draw(myWidget,drawLib,conf,telemetry,status,battery,alarms,frame,utils,customSensors,gpsStatuses,leftPanel,centerPanel,rightPanel) + else + -- Layout start + if leftPanel == nil and loadCycle == 1 then + leftPanel = utils.doLibrary(conf.leftPanelFilename) + end + + if centerPanel == nil and loadCycle == 2 then + centerPanel = utils.doLibrary(conf.centerPanelFilename) + end + + if rightPanel == nil and loadCycle == 4 then + rightPanel = utils.doLibrary(conf.rightPanelFilename) + end + + if layout == nil and loadCycle == 6 and leftPanel ~= nil and centerPanel ~= nil and rightPanel ~= nil then + layout = utils.doLibrary(conf.widgetLayoutFilename) + end + + lcd.setColor(CUSTOM_COLOR,COLOR_WHITE) + lcd.drawFilledRectangle(88,74, 304, 84, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_BARS_2) + lcd.drawFilledRectangle(90,76, 300, 80, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,COLOR_TEXT) + lcd.drawText(155, 95, "loading...", DBLSIZE+CUSTOM_COLOR) + end + -- Layout END + end + -- no telemetry/minmax outer box + if telemetryEnabled() == false then + -- no telemetry inner box + if not status.hideNoTelemetry then + drawLib.drawNoTelemetryData(status,telemetry,utils,telemetryEnabled) + end + utils.drawBlinkBitmap("warn",0,0) + else + if status.showMinMaxValues == true then + utils.drawBlinkBitmap("minmax",0,0) + end + end + + loadCycle=(loadCycle+1)%8 +#ifdef HUDRATE + lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + local hudrateTxt = string.format("%.1ffps",myWidget.vars.hudrate) + lcd.drawText(212,3,hudrateTxt,SMLSIZE+CUSTOM_COLOR+RIGHT) +#endif --HUDRATE +#ifdef BGTELERATE + lcd.setColor(CUSTOM_COLOR,COLOR_YELLOW) + local bgtelerateTxt = string.format("%.0fHz",math.floor(bgtelerate+0.5)) + lcd.drawText(260,3,bgtelerateTxt,SMLSIZE+RIGHT+CUSTOM_COLOR) +#endif --BGTELERATE +#ifdef MEMDEBUG + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0,0)) + maxmem = math.max(maxmem,collectgarbage("count")*1024) + -- test with absolute coordinates + lcd.drawNumber(480,LCD_H-14,maxmem,SMLSIZE+MENU_TITLE_COLOR+RIGHT) +#endif + collectgarbage() + collectgarbage() +end + +function refresh(myWidget) + if myWidget.zone.h < 250 then + fullScreenRequired(myWidget) + return + end + drawFullScreen(myWidget) +end + +return { name="Yaapu", options=options, create=create, update=update, background=background, refresh=refresh } \ No newline at end of file diff --git a/HORUS/SOURCES/PP/yaapux.lua b/HORUS/SOURCES/PP/yaapux.lua deleted file mode 100644 index f53154e3..00000000 --- a/HORUS/SOURCES/PP/yaapux.lua +++ /dev/null @@ -1,2422 +0,0 @@ --- --- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios --- --- Copyright (C) 2018. Alessandro Apostoli --- https://github.com/yaapu --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- 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. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, see . --- --- Passthrough protocol reference: --- https://cdn.rawgit.com/ArduPilot/ardupilot_wiki/33cd0c2c/images/FrSky_Passthrough_protocol.xlsx --- --- Borrowed some code from the LI-xx BATTCHECK v3.30 script --- http://frskytaranis.forumactif.org/t2800-lua-download-un-testeur-de-batterie-sur-la-radio - ---------------------- --- script version ---------------------- - --- 480x272 LCD_WxLCD_H ---#define WIDGET ---#define WIDGETDEBUG ---#define COMPILE ---#define SPLASH ---#define MEMDEBUG --- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 ---------------------- --- features ---------------------- ---#define HUD_ALGO1 ---#define BATTPERC_BY_VOLTAGE ---#define COMPASS_ROSE ---------------------- --- dev features ---------------------- ---#define LOGTELEMETRY ---#define DEBUG ---#define DEBUGEVT ---#define TESTMODE ---#define DEV ---#define DEBUGHUD - --- calc and show background function rate ---#define BGRATE --- calc and show run function rate ---#define FGRATE - --- calc and show hud refresh rate --- default for beta ---#define HUDRATE - ---#define HUDTIMER - --- calc and show telemetry process rate --- default for beta ---#define BGTELERATE - --- calc and show actual incoming telemetry rate ---#define TELERATE - --- - - - - - - - - - - - ---[[ - MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */ - MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */ - MAV_TYPE_QUADROTOR=2, /* Quadrotor | */ - MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */ - MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */ - MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */ - MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */ - MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */ - MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */ - MAV_TYPE_ROCKET=9, /* Rocket | */ - MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */ - MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */ - MAV_TYPE_SUBMARINE=12, /* Submarine | */ - MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */ - MAV_TYPE_OCTOROTOR=14, /* Octorotor | */ - MAV_TYPE_TRICOPTER=15, /* Tricopter | */ - MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */ - MAV_TYPE_KITE=17, /* Kite | */ - MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */ - MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */ - MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */ - MAV_TYPE_VTOL_TILTROTOR=21, /* Tiltrotor VTOL | */ - MAV_TYPE_VTOL_RESERVED2=22, /* VTOL reserved 2 | */ - MAV_TYPE_VTOL_RESERVED3=23, /* VTOL reserved 3 | */ - MAV_TYPE_VTOL_RESERVED4=24, /* VTOL reserved 4 | */ - MAV_TYPE_VTOL_RESERVED5=25, /* VTOL reserved 5 | */ - MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */ - MAV_TYPE_ADSB=27, /* Onboard ADSB peripheral | */ - MAV_TYPE_PARAFOIL=28, /* Steerable, nonrigid airfoil | */ - MAV_TYPE_DODECAROTOR=29, /* Dodecarotor | */ -]] -------------------------------------- --- UNITS Scales from Ardupilot OSD code /ardupilot/libraries/AP_OSD/AP_OSD_Screen.cpp -------------------------------------- ---[[ - static const float scale_metric[UNIT_TYPE_LAST] = { - 1.0, //ALTITUDE m - 3.6, //SPEED km/hr - 1.0, //VSPEED m/s - 1.0, //DISTANCE m - 1.0/1000, //DISTANCE_LONG km - 1.0, //TEMPERATURE C - }; - static const float scale_imperial[UNIT_TYPE_LAST] = { - 3.28084, //ALTITUDE ft - 2.23694, //SPEED mph - 3.28084, //VSPEED ft/s - 3.28084, //DISTANCE ft - 1.0/1609.34, //DISTANCE_LONG miles - 1.8, //TEMPERATURE F - }; - static const float scale_SI[UNIT_TYPE_LAST] = { - 1.0, //ALTITUDE m - 1.0, //SPEED m/s - 1.0, //VSPEED m/s - 1.0, //DISTANCE m - 1.0/1000, //DISTANCE_LONG km - 1.0, //TEMPERATURE C - }; - static const float scale_aviation[UNIT_TYPE_LAST] = { - 3.28084, //ALTITUDE Ft - 1.94384, //SPEED Knots - 196.85, //VSPEED ft/min - 3.28084, //DISTANCE ft - 0.000539957, //DISTANCE_LONG Nm - 1.0, //TEMPERATURE C - }; ---]]local frameNames = {} --- copter -frameNames[0] = "GEN" -frameNames[2] = "QUAD" -frameNames[3] = "COAX" -frameNames[4] = "HELI" -frameNames[13] = "HEX" -frameNames[14] = "OCTO" -frameNames[15] = "TRI" -frameNames[29] = "DODE" - --- plane -frameNames[1] = "WING" -frameNames[16] = "FLAP" -frameNames[19] = "VTOL2" -frameNames[20] = "VTOL4" -frameNames[21] = "VTOLT" -frameNames[22] = "VTOL" -frameNames[23] = "VTOL" -frameNames[24] = "VTOL" -frameNames[25] = "VTOL" -frameNames[28] = "FOIL" - --- rover -frameNames[10] = "ROV" --- boat -frameNames[11] = "BOAT" - -local currentModel = nil -local frameTypes = {} --- copter -frameTypes[0] = "c" -frameTypes[2] = "c" -frameTypes[3] = "c" -frameTypes[4] = "c" -frameTypes[13] = "c" -frameTypes[14] = "c" -frameTypes[15] = "c" -frameTypes[29] = "c" - --- plane -frameTypes[1] = "p" -frameTypes[16] = "p" -frameTypes[19] = "p" -frameTypes[20] = "p" -frameTypes[21] = "p" -frameTypes[22] = "p" -frameTypes[23] = "p" -frameTypes[24] = "p" -frameTypes[25] = "p" -frameTypes[28] = "p" - --- rover -frameTypes[10] = "r" --- boat -frameTypes[11] = "b" - --- flightmodes are loaded at run time -local soundFileBasePath = "/SOUNDS/yaapu0" -local gpsStatuses = {} - -gpsStatuses[0]="NoGPS" -gpsStatuses[1]="NoLock" -gpsStatuses[2]="2D" -gpsStatuses[3]="3D" -gpsStatuses[4]="DGPS" -gpsStatuses[5]="RTK" -gpsStatuses[6]="RTK" - ---[[ -0 MAV_SEVERITY_EMERGENCY System is unusable. This is a "panic" condition. -1 MAV_SEVERITY_ALERT Action should be taken immediately. Indicates error in non-critical systems. -2 MAV_SEVERITY_CRITICAL Action must be taken immediately. Indicates failure in a primary system. -3 MAV_SEVERITY_ERROR Indicates an error in secondary/redundant systems. -4 MAV_SEVERITY_WARNING Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. -5 MAV_SEVERITY_NOTICE An unusual event has occured, though not an error condition. This should be investigated for the root cause. -6 MAV_SEVERITY_INFO Normal operational messages. Useful for logging. No action is required for these messages. -7 MAV_SEVERITY_DEBUG Useful non-operational messages that can assist in debugging. These should not occur during normal operation. ---]] -local mavSeverity = {} -mavSeverity[0]="EMR" -mavSeverity[1]="ALR" -mavSeverity[2]="CRT" -mavSeverity[3]="ERR" -mavSeverity[4]="WRN" -mavSeverity[5]="NOT" -mavSeverity[6]="INF" -mavSeverity[7]="DBG" - --------------------------------- -local status = { - -- FLVSS 1 - cell1min = 0, - cell1sum = 0, - -- FLVSS 2 - cell2min = 0, - cell2sum = 0, - -- FC 1 - cell1sumFC = 0, - -- used to calculate cellcount - cell1maxFC = 0, - -- FC 2 - cell2sumFC = 0, - -- A2 - cellsumA2 = 0, - -- used to calculate cellcount - cellmaxA2 = 0, - -------------------------------- - -- AP STATUS - flightMode = 0, - simpleMode = 0, - landComplete = 0, - statusArmed = 0, - battFailsafe = 0, - ekfFailsafe = 0, - imuTemp = 0, - -- GPS - numSats = 0, - gpsStatus = 0, - gpsHdopC = 100, - gpsAlt = 0, - -- BATT - cellcount = 0, - battsource = "na", - -- BATT 1 - batt1volt = 0, - batt1current = 0, - batt1mah = 0, - batt1sources = { - a2 = false, - vs = false, - fc = false - }, - -- BATT 2 - batt2volt = 0, - batt2current = 0, - batt2mah = 0, - batt2sources = { - a2 = false, - vs = false, - fc = false - }, - -- TELEMETRY - noTelemetryData = 1, - -- HOME - homeDist = 0, - homeAlt = 0, - homeAngle = -1, - -- MESSAGES - msgBuffer = "", - lastMsgValue = 0, - lastMsgTime = 0, - -- VELANDYAW - vSpeed = 0, - hSpeed = 0, - yaw = 0, - -- SYNTH VSPEED SUPPORT - vspd = 0, - synthVSpeedTime = 0, - prevHomeAlt = 0, - -- ROLLPITCH - roll = 0, - pitch = 0, - range = 0, - -- PARAMS - frameType = -1, - batt1Capacity = 0, - batt2Capacity = 0, - -- FLIGHT TIME - lastTimerStart = 0, - timerRunning = 0, - flightTime = 0, - -- EVENTS - lastStatusArmed = 0, - lastGpsStatus = 0, - lastFlightMode = 0, - lastSimpleMode = 0, - -- battery levels - batLevel = 99, - battLevel1 = false, - battLevel2 = false, - lastBattLevel = 14, - -- messages - lastMessage = nil, - lastMessageSeverity = 0, - lastMessageCount = 1, - messageCount = 0, - messages = {} -} -local frame = {} --- -local backlightLastTime = 0 --- ---[[ - ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing - ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing - ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing - ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing -{ - 1 = notified, - 2 = alarm start, - 3 = armed, - 4 = type(0=min,1=max,2=timer,3=batt), - 5 = grace duration - 6 = ready - 7 = last alarm -} ---]]-- --- --- --- -local alarms = { - --{ notified, alarm_start, armed, type(0=min,1=max,2=timer,3=batt), grace, ready, last_alarm} - { false, 0 , false, 0, 0, false, 0}, --MIN_ALT - { false, 0 , true, 1 , 0, false, 0 }, --MAX_ALT - { false, 0 , true, 1 , 0, false, 0 }, --MAX_DIST - { false, 0 , true, 1 , 0, false, 0 }, --FS_EKF - { false, 0 , true, 1 , 0, false, 0 }, --FS_BAT - { false, 0 , true, 2, 0, false, 0 }, --FLIGTH_TIME - { false, 0 , false, 3, 4, false, 0 }, --BATT L1 - { false, 0 , false, 4, 4, false, 0 } --BATT L2 -} - --- -local paramId,paramValue --- -local batLevels = {0,5,10,15,20,25,30,40,50,60,70,80,90} --- dual battery -local showDualBattery = false --- -local bitmaps = {} -local blinktime = getTime() -local blinkon = false --- GPS -local function getTelemetryId(name) - local field = getFieldInfo(name) - return field and field.id or -1 -end --- -local gpsDataId = getTelemetryId("GPS") --- --- --- -local minmaxValues = {} --- min -minmaxValues[1] = 0 -minmaxValues[2] = 0 -minmaxValues[3] = 0 -minmaxValues[4] = 0 -minmaxValues[5] = 0 -minmaxValues[6] = 0 -minmaxValues[7] = 0 --- max -minmaxValues[8] = 0 -minmaxValues[9] = 0 -minmaxValues[10] = 0 -minmaxValues[11] = 0 -minmaxValues[12] = 0 -minmaxValues[13] = 0 -minmaxValues[14] = 0 -minmaxValues[15] = 0 -minmaxValues[16] = 0 -minmaxValues[17] = 0 - -local showMinMaxValues = false --- - --- - - - - - - - - - - - - - - - - - - - - - - - - - - - --- model and opentx version -local ver, radio, maj, minor, rev = getVersion() ------------------------------ --- clears the loaded table --- and recovers memory ------------------------------ -local function clearTable(t) - if type(t)=="table" then - for i,v in pairs(t) do - if type(v) == "table" then - clearTable(v) - end - t[i] = nil - end - end - collectgarbage() - maxmem = 0 -end --------------------------------------------------------------------------------- --- CONFIGURATION MENU --------------------------------------------------------------------------------- -local conf = { - language = "en", - defaultBattSource = nil, -- auto - battAlertLevel1 = 0, - battAlertLevel2 = 0, - battCapOverride1 = 0, - battCapOverride2 = 0, - disableAllSounds = false, - disableMsgBeep = false, - disableMsgBlink = false, - timerAlert = 0, - minAltitudeAlert = 0, - maxAltitudeAlert = 0, - maxDistanceAlert = 0, - cellCount = 0, - enableBattPercByVoltage = false, - rangeMax=0, - enableSynthVSpeed=false, - horSpeedMultiplier=1, - vertSpeedMultiplier=1 -} --------------------------------------------------------------------------------- --- MENU VALUE,COMBO --------------------------------------------------------------------------------- - - -local menu = { - selectedItem = 1, - editSelected = false, - offset = 0 -} - - - --- max 4 extra sensors -local customSensors = { - -- {label,name,prec:0,1,2,unit,stype:I,E,1} -} - -local menuItems = {} - -- label, type, alias, currval, min, max, label, flags, increment -menuItems[1] = {"voice language:", 1, "L1", 1, { "english", "italian", "french", "german" } , {"en","it","fr","de"} } -menuItems[2] = {"batt alert level 1:", 0, "V1", 375, 0,5000,"V", PREC2 ,5 } -menuItems[3] = {"batt alert level 2:", 0, "V2", 350, 0,5000,"V", PREC2 ,5 } -menuItems[4] = {"batt[1] capacity override:", 0, "B1", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[5] = {"batt[2] capacity override:", 0, "B2", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[6] = {"disable all sounds:", 1, "S1", 1, { "no", "yes" }, { false, true } } -menuItems[7] = {"disable msg beep:", 1, "S2", 1, { "no", "yes" }, { false, true } } -menuItems[8] = {"disable msg blink:", 1, "S3", 1, { "no", "yes" }, { false, true } } -menuItems[9] = {"default voltage source:", 1, "VS", 1, { "auto", "FLVSS", "A2", "fc" }, { nil, "vs", "a2", "fc" } } -menuItems[10] = {"timer alert every:", 0, "T1", 0, 0,600,"min",PREC1,5 } -menuItems[11] = {"min altitude alert:", 0, "A1", 0, 0,500,"m",PREC1,5 } -menuItems[12] = {"max altitude alert:", 0, "A2", 0, 0,10000,"m",0,1 } -menuItems[13] = {"max distance alert:", 0, "D1", 0, 0,100000,"m",0,10 } -menuItems[14] = {"repeat alerts every:", 0, "T2", 10, 5,600,"sec",0,5 } -menuItems[15] = {"cell count override:", 0, "CC", 0, 0,12,"cells",0,1 } -menuItems[16] = {"rangefinder max:", 0, "RM", 0, 0,10000," cm",0,10 } -menuItems[17] = {"enable synthetic vspeed:", 1, "SVS", 1, { "no", "yes" }, { false, true } } -menuItems[18] = {"air/groundspeed unit:", 1, "HSPD", 1, { "m/s", "km/h", "mph", "kn" }, { 1, 3.6, 2.23694, 1.94384} } -menuItems[19] = {"vertical speed unit:", 1, "VSPD", 1, { "m/s", "ft/s", "ft/min" }, { 1, 3.28084, 196.85} } --- - - -local unitScale, unitlabel - - - - -local function getConfigFilename() - local info = model.getInfo() - return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".cfg") -end - -local function getBitmap(name) - if bitmaps[name] == nil then - bitmaps[name] = Bitmap.open("/SCRIPTS/YAAPU/IMAGES/"..name..".png") - end - return bitmaps[name] -end - -local function applyConfigValues() - conf.language = menuItems[1][6][menuItems[1][4]] - conf.battAlertLevel1 = menuItems[2][4] - conf.battAlertLevel2 = menuItems[3][4] - conf.battCapOverride1 = menuItems[4][4]*0.1 - conf.battCapOverride2 = menuItems[5][4]*0.1 - conf.disableAllSounds = menuItems[6][6][menuItems[6][4]] - conf.disableMsgBeep = menuItems[7][6][menuItems[7][4]] - conf.disableMsgBlink = menuItems[8][6][menuItems[8][4]] - conf.defaultBattSource = menuItems[9][6][menuItems[9][4]] - conf.timerAlert = math.floor(menuItems[10][4]*0.1*60) - conf.minAltitudeAlert = menuItems[11][4]*0.1 - conf.maxAltitudeAlert = menuItems[12][4] - conf.maxDistanceAlert = menuItems[13][4] - conf.cellCount = menuItems[15][4] - conf.rangeMax = menuItems[16][4] - conf.enableSynthVSpeed = menuItems[17][6][menuItems[17][4]] - conf.horSpeedMultiplier = menuItems[18][6][menuItems[18][4]] - conf.vertSpeedMultiplier = menuItems[19][6][menuItems[19][4]] - -- - if conf.defaultBattSource ~= nil then - status.battsource = conf.defaultBattSource - end -end - -local function loadConfig() - local cfg = io.open(getConfigFilename(),"r") - if cfg == nil then - return - end - local str = io.read(cfg,200) - if string.len(str) > 0 then - for i=1,#menuItems - do - local value = string.match(str, menuItems[i][3]..":(%d+)") - if value ~= nil then - menuItems[i][4] = tonumber(value) - end - end - end - if cfg ~= nil then - io.close(cfg) - end - applyConfigValues() -end - -local function saveConfig() - local cfg = assert(io.open(getConfigFilename(),"w")) - if cfg == nil then - return - end - for i=1,#menuItems - do - io.write(cfg,menuItems[i][3],":",menuItems[i][4]) - if i < #menuItems then - io.write(cfg,",") - end - end - if cfg ~= nil then - io.close(cfg) - end - applyConfigValues() -end - -local function drawConfigMenuBars() - local itemIdx = string.format("%d/%d",menu.selectedItem,#menuItems) - lcd.drawFilledRectangle(0,0, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, 0, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,0,"Yaapu Telemetry Script 1.7.4",MENU_TITLE_COLOR) - lcd.drawFilledRectangle(0,LCD_H - 20, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, LCD_H - 20, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,LCD_H - 20+1,getConfigFilename(),MENU_TITLE_COLOR) - lcd.drawText(LCD_W,LCD_H - 20+1,itemIdx,MENU_TITLE_COLOR+RIGHT) -end - -local function incMenuItem(idx) - if menuItems[idx][2] == 0 then - menuItems[idx][4] = menuItems[idx][4] + menuItems[idx][9] - if menuItems[idx][4] > menuItems[idx][6] then - menuItems[idx][4] = menuItems[idx][6] - end - else - menuItems[idx][4] = menuItems[idx][4] + 1 - if menuItems[idx][4] > #menuItems[idx][5] then - menuItems[idx][4] = 1 - end - end -end - -local function decMenuItem(idx) - if menuItems[idx][2] == 0 then - menuItems[idx][4] = menuItems[idx][4] - menuItems[idx][9] - if menuItems[idx][4] < menuItems[idx][5] then - menuItems[idx][4] = menuItems[idx][5] - end - else - menuItems[idx][4] = menuItems[idx][4] - 1 - if menuItems[idx][4] < 1 then - menuItems[idx][4] = #menuItems[idx][5] - end - end -end - -local function drawItem(idx,flags) - if menuItems[idx][2] == 0 then - if menuItems[idx][4] == 0 then - lcd.drawText(300,25 + (idx-menu.offset-1)*20, "---",flags) - else - lcd.drawNumber(300,25 + (idx-menu.offset-1)*20, menuItems[idx][4],flags+menuItems[idx][8]) - lcd.drawText(300 + 50,25 + (idx-menu.offset-1)*20, menuItems[idx][7],flags) - end - else - lcd.drawText(300,25 + (idx-menu.offset-1)*20, menuItems[idx][5][menuItems[idx][4]],flags) - end -end - -local function drawConfigMenu(event) - drawConfigMenuBars() - if event == EVT_ENTER_BREAK then - menu.editSelected = not menu.editSelected - elseif menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT or event == EVT_PLUS_REPT) then - incMenuItem(menu.selectedItem) - elseif menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT or event == EVT_MINUS_REPT) then - decMenuItem(menu.selectedItem) - elseif not menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT) then - menu.selectedItem = (menu.selectedItem - 1) - if menu.offset >= menu.selectedItem then - menu.offset = menu.offset - 1 - end - elseif not menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT) then - menu.selectedItem = (menu.selectedItem + 1) - if menu.selectedItem - 11 > menu.offset then - menu.offset = menu.offset + 1 - end - end - --wrap - if menu.selectedItem > #menuItems then - menu.selectedItem = 1 - menu.offset = 0 - elseif menu.selectedItem < 1 then - menu.selectedItem = #menuItems - menu.offset = 8 - end - -- - for m=1+menu.offset,math.min(#menuItems,11+menu.offset) do - lcd.drawText(2,25 + (m-menu.offset-1)*20, menuItems[m][1],0+0) - if m == menu.selectedItem then - if menu.editSelected then - drawItem(m,INVERS+BLINK) - else - drawItem(m,INVERS) - end - else - drawItem(m,0) - end - end -end --- -local function lcdBacklightOn() - model.setGlobalVariable(8,0,1) - backlightLastTime = getTime()/100 -- seconds -end --- -local function playSound(soundFile) - if conf.disableAllSounds then - return - end - lcdBacklightOn() - playFile(soundFileBasePath .."/"..conf.language.."/".. soundFile..".wav") -end - ----------------------------------------------- --- sound file has same name as flightmode all lowercase with .wav extension ----------------------------------------------- -local function playSoundByFrameTypeAndFlightMode(flightMode) - if conf.disableAllSounds then - return - end - if frame.flightModes then - if frame.flightModes[flightMode] ~= nil then - lcdBacklightOn() - playFile(soundFileBasePath.."/"..conf.language.."/".. string.lower(frame.flightModes[flightMode])..".wav") - end - end -end - -local function drawHArrow(x,y,width,left,right) - lcd.drawLine(x, y, x + width,y, SOLID, 0) - if left == true then - lcd.drawLine(x + 1,y - 1,x + 2,y - 2, SOLID, 0) - lcd.drawLine(x + 1,y + 1,x + 2,y + 2, SOLID, 0) - end - if right == true then - lcd.drawLine(x + width - 1,y - 1,x + width - 2,y - 2, SOLID, 0) - lcd.drawLine(x + width - 1,y + 1,x + width - 2,y + 2, SOLID, 0) - end -end --- -local function drawBlinkBitmap(bitmap,x,y) - if blinkon == true then - lcd.drawBitmap(getBitmap(bitmap),x,y) - end -end --- -local function drawVArrow(x,y,h,top,bottom) - if top == true then - drawBlinkBitmap("uparrow",x,y) - else - drawBlinkBitmap("downarrow",x,y) - end -end - -local function drawHomeIcon(x,y) - lcd.drawBitmap(getBitmap("minihomeorange"),x,y) -end - -local function drawLine(x1,y1,x2,y2,flags1,flags2) - -- if lines are hor or ver do not fix ---if string.find(radio, "x10") and rev < 2 and x1 ~= x2 and y1 ~= y2 then - if string.find(radio, "x10") and rev < 2 then - lcd.drawLine(LCD_W-x1,LCD_H-y1,LCD_W-x2,LCD_H-y2,flags1,flags2) - else - lcd.drawLine(x1,y1,x2,y2,flags1,flags2) - end -end - - -local function computeOutCode(x,y,xmin,ymin,xmax,ymax) - local code = 0; --initialised as being inside of hud - -- - if x < xmin then --to the left of hud - code = bit32.bor(code,1); - elseif x > xmax then --to the right of hud - code = bit32.bor(code,2); - end - if y < ymin then --below the hud - code = bit32.bor(code,4); - elseif y > ymax then --above the hud - code = bit32.bor(code,8); - end - -- - return code; -end - --- Cohen–Sutherland clipping algorithm --- https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm -local function drawLineWithClipping(ox,oy,angle,len,style,xmin,xmax,ymin,ymax,color) - -- - local xx = math.cos(math.rad(angle)) * len * 0.5 - local yy = math.sin(math.rad(angle)) * len * 0.5 - -- - local x0 = ox - xx - local x1 = ox + xx - local y0 = oy - yy - local y1 = oy + yy - -- compute outcodes for P0, P1, and whatever point lies outside the clip rectangle - local outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax); - local outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); - local accept = false; - - while (true) do - if ( bit32.bor(outcode0,outcode1) == 0) then - -- bitwise OR is 0: both points inside window; trivially accept and exit loop - accept = true; - break; - elseif (bit32.band(outcode0,outcode1) ~= 0) then - -- bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP, BOTTOM) - -- both must be outside window; exit loop (accept is false) - break; - else - -- failed both tests, so calculate the line segment to clip - -- from an outside point to an intersection with clip edge - local x = 0 - local y = 0 - -- At least one endpoint is outside the clip rectangle; pick it. - local outcodeOut = outcode0 ~= 0 and outcode0 or outcode1 - -- No need to worry about divide-by-zero because, in each case, the - -- outcode bit being tested guarantees the denominator is non-zero - if bit32.band(outcodeOut,8) ~= 0 then --point is above the clip window - x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0) - y = ymax - elseif bit32.band(outcodeOut,4) ~= 0 then --point is below the clip window - x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0) - y = ymin - elseif bit32.band(outcodeOut,2) ~= 0 then --point is to the right of clip window - y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0) - x = xmax - elseif bit32.band(outcodeOut,1) ~= 0 then --point is to the left of clip window - y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0) - x = xmin - end - -- Now we move outside point to intersection point to clip - -- and get ready for next pass. - if outcodeOut == outcode0 then - x0 = x - y0 = y - outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax) - else - x1 = x - y1 = y - outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax) - end - end - end - if accept then - drawLine(x0,y0,x1,y1, style,color) - end -end - - -local function drawNumberWithTwoDims(x,y,xDim,yTop,yBottom,number,topDim,bottomDim,flags,topFlags,bottomFlags) - --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) - lcd.drawNumber(x, y, number + 0.5, flags) - local lx = xDim - lcd.drawText(lx, yTop, topDim, topFlags) - lcd.drawText(lx, yBottom, bottomDim, bottomFlags) -end - -local function drawNumberWithDim(x,y,xDim,yDim,number,dim,flags,dimFlags) - lcd.drawNumber(x, y, number,flags) - lcd.drawText(xDim, yDim, dim, dimFlags) -end - --- --- -local function formatMessage(severity,msg) - if status.lastMessageCount > 1 then - return string.format("%02d:%s (x%d) %s", status.messageCount, mavSeverity[severity], status.lastMessageCount, msg) - else - return string.format("%02d:%s %s", status.messageCount, mavSeverity[severity], msg) - end -end - -local function pushMessage(severity, msg) - if conf.disableMsgBeep == false and conf.disableAllSounds == false then - if ( severity < 5) then - playSound("../err") - else - playSound("../inf") - end - end - -- check if wrapping is needed - if #status.messages == 17 and msg ~= status.lastMessage then - for i=1,17-1 do - status.messages[i]=status.messages[i+1] - end - -- trunc at 9 - status.messages[17] = nil - end - -- is it a duplicate? - if msg == status.lastMessage then - status.lastMessageCount = status.lastMessageCount + 1 - status.messages[#status.messages] = formatMessage(severity,msg) - else - status.lastMessageCount = 1 - status.messageCount = status.messageCount + 1 - status.messages[#status.messages+1] = formatMessage(severity,msg) - end - status.lastMessage = msg - status.lastMessageSeverity = severity -end - -local function getSensorsConfigFilename() - local info = model.getInfo() - return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".sensors") -end - -local function loadSensors() - local cfg = io.open(getSensorsConfigFilename(),"r") - if cfg == nil then - return - end - local str = io.read(cfg,200) - if string.len(str) > 0 then - for i=1,4 - do - local label, name, prec, unit, stype, mult = string.match(str, "S"..i..":(%w+),([A-Za-z0-9]+),(%d+),([A-Za-z0-9//%%]+),(%a+),(%d+)") - if label ~= nil and name ~= nil and prec ~= nil and unit ~= nil and stype ~= nil then - customSensors[i] = { label, name, prec, unit, stype, mult } - pushMessage(7,"Custom sensor enabled: "..label) - end - end - end - -- - if cfg ~= nil then - io.close(cfg) - end -end - -local customSensorXY = { - { 81, 95, 75, 112}, - { 165, 95, 165, 112}, - { 81, 152, 80, 170}, - { 165, 152, 165, 170 } -} - -local function drawCustomSensors() - local label,data,prec,mult - for i=1,4 - do - if customSensors[i] ~= nil then - label = string.format("%s(%s)",customSensors[i][1],customSensors[i][4]) - lcd.drawText(customSensorXY[i][1], customSensorXY[i][2],label, SMLSIZE+RIGHT) - mult = tonumber(customSensors[i][3]) - mult = mult == 0 and 1 or ( mult == 1 and 10 or 100 ) - prec = mult == 1 and 0 or (mult == 10 and 32 or 48) - lcd.drawNumber(customSensorXY[i][3], customSensorXY[i][4], getValue(customSensors[i][2])*mult*customSensors[i][6], MIDSIZE+RIGHT+prec) - end - end -end --- -local function startTimer() - status.lastTimerStart = getTime()/100 - model.setTimer(2,{mode=1}) -end - -local function stopTimer() - model.setTimer(2,{mode=0}) - status.lastTimerStart = 0 -end - - ------------------------------------------------------------------ --- TELEMETRY ------------------------------------------------------------------ --- -local function processTelemetry() - local SENSOR_ID,FRAME_ID,DATA_ID,VALUE = sportTelemetryPop() - if ( FRAME_ID == 0x10) then - status.noTelemetryData = 0 - if ( DATA_ID == 0x5006) then -- ROLLPITCH - -- roll [0,1800] ==> [-180,180] - status.roll = (math.min(bit32.extract(VALUE,0,11),1800) - 900) * 0.2 - -- pitch [0,900] ==> [-90,90] - status.pitch = (math.min(bit32.extract(VALUE,11,10),900) - 450) * 0.2 - -- #define ATTIANDRNG_RNGFND_OFFSET 21 - -- number encoded on 11 bits: 10 bits for digits + 1 for 10^power - status.range = bit32.extract(VALUE,22,10) * (10^bit32.extract(VALUE,21,1)) -- cm - elseif ( DATA_ID == 0x5005) then -- VELANDYAW - status.vSpeed = bit32.extract(VALUE,1,7) * (10^bit32.extract(VALUE,0,1)) * (bit32.extract(VALUE,8,1) == 1 and -1 or 1)-- dm/s - status.hSpeed = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) -- dm/s - status.yaw = bit32.extract(VALUE,17,11) * 0.2 - elseif ( DATA_ID == 0x5001) then -- AP STATUS - status.flightMode = bit32.extract(VALUE,0,5) - status.simpleMode = bit32.extract(VALUE,5,2) - status.landComplete = bit32.extract(VALUE,7,1) - status.statusArmed = bit32.extract(VALUE,8,1) - status.battFailsafe = bit32.extract(VALUE,9,1) - status.ekfFailsafe = bit32.extract(VALUE,10,2) - -- IMU temperature: 0 means temp =< 19°, 63 means temp => 82° - status.imuTemp = bit32.extract(VALUE,26,6) + 19 -- C° - elseif ( DATA_ID == 0x5002) then -- GPS STATUS - status.numSats = bit32.extract(VALUE,0,4) - -- offset 4: NO_GPS = 0, NO_FIX = 1, GPS_OK_FIX_2D = 2, GPS_OK_FIX_3D or GPS_OK_FIX_3D_DGPS or GPS_OK_FIX_3D_RTK_FLOAT or GPS_OK_FIX_3D_RTK_FIXED = 3 - -- offset 14: 0: no advanced fix, 1: GPS_OK_FIX_3D_DGPS, 2: GPS_OK_FIX_3D_RTK_FLOAT, 3: GPS_OK_FIX_3D_RTK_FIXED - status.gpsStatus = bit32.extract(VALUE,4,2) + bit32.extract(VALUE,14,2) - status.gpsHdopC = bit32.extract(VALUE,7,7) * (10^bit32.extract(VALUE,6,1)) -- dm - status.gpsAlt = bit32.extract(VALUE,24,7) * (10^bit32.extract(VALUE,22,2)) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1)-- dm - elseif ( DATA_ID == 0x5003) then -- BATT - status.batt1volt = bit32.extract(VALUE,0,9) - status.batt1current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) - status.batt1mah = bit32.extract(VALUE,17,15) - elseif ( DATA_ID == 0x5008) then -- BATT2 - status.batt2volt = bit32.extract(VALUE,0,9) - status.batt2current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) - status.batt2mah = bit32.extract(VALUE,17,15) - elseif ( DATA_ID == 0x5004) then -- HOME - status.homeDist = bit32.extract(VALUE,2,10) * (10^bit32.extract(VALUE,0,2)) - status.homeAlt = bit32.extract(VALUE,14,10) * (10^bit32.extract(VALUE,12,2)) * 0.1 * (bit32.extract(VALUE,24,1) == 1 and -1 or 1) - status.homeAngle = bit32.extract(VALUE, 25, 7) * 3 - elseif ( DATA_ID == 0x5000) then -- MESSAGES - if (VALUE ~= status.lastMsgValue) then - status.lastMsgValue = VALUE - local c1 = bit32.extract(VALUE,0,7) - local c2 = bit32.extract(VALUE,8,7) - local c3 = bit32.extract(VALUE,16,7) - local c4 = bit32.extract(VALUE,24,7) - -- - local msgEnd = false - -- - if (c4 ~= 0) then - status.msgBuffer = status.msgBuffer .. string.char(c4) - else - msgEnd = true; - end - if (c3 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c3) - else - msgEnd = true; - end - if (c2 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c2) - else - msgEnd = true; - end - if (c1 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c1) - else - msgEnd = true; - end - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x4)<<21; - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x2)<<14; - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x1)<<7; - if (msgEnd) then - local severity = (bit32.extract(VALUE,7,1) * 1) + (bit32.extract(VALUE,15,1) * 2) + (bit32.extract(VALUE,23,1) * 4) - pushMessage( severity, status.msgBuffer) - status.msgBuffer = "" - end - end - elseif ( DATA_ID == 0x5007) then -- PARAMS - paramId = bit32.extract(VALUE,24,4) - paramValue = bit32.extract(VALUE,0,24) - if paramId == 1 then - status.frameType = paramValue - elseif paramId == 4 then - status.batt1Capacity = paramValue - elseif paramId == 5 then - status.batt2Capacity = paramValue - end - end - end -end - -local function telemetryEnabled() - if getRSSI() == 0 then - status.noTelemetryData = 1 - end - return status.noTelemetryData == 0 -end - -local function getMaxValue(value,idx) - minmaxValues[idx] = math.max(value,minmaxValues[idx]) - return showMinMaxValues == true and minmaxValues[idx] or value -end - -local function calcMinValue(value,min) - return min == 0 and value or math.min(value,min) -end - --- returns the actual minimun only if both are > 0 -local function getNonZeroMin(v1,v2) - return v1 == 0 and v2 or ( v2 == 0 and v1 or math.min(v1,v2)) -end - - - -local function calcCellCount() - -- cellcount override from menu - if conf.cellCount ~= nil and conf.cellCount > 0 then - return conf.cellCount - end - -- cellcount is cached only for FLVSS - if status.batt1sources.vs == true and status.cellcount > 1 then - return status.cellcount - end - -- round in excess and return - -- Note: cellcount is not cached because max voltage can rise during initialization) - return math.floor( (( math.max(status.cell1maxFC,status.cellmaxA2)*0.1 ) / 4.35) + 1) -end - -local function calcBattery() - ------------ - -- FLVSS 1 - ------------ - local cellResult = getValue("Cels") - if type(cellResult) == "table" then - status.cell1min = 4.35 - status.cell1sum = 0 - -- cellcount is global and shared - status.cellcount = #cellResult - for i, v in pairs(cellResult) do - status.cell1sum = status.cell1sum + v - if status.cell1min > v then - status.cell1min = v - end - end - -- if connected after scritp started - if status.batt1sources.vs == false then - status.battsource = "na" - end - if status.battsource == "na" then - status.battsource = "vs" - end - status.batt1sources.vs = true - else - status.batt1sources.vs = false - status.cell1min = 0 - status.cell1sum = 0 - end - ------------ - -- FLVSS 2 - ------------ - cellResult = getValue("Cel2") - if type(cellResult) == "table" then - status.cell2min = 4.35 - status.cell2sum = 0 - -- cellcount is global and shared - status.cellcount = #cellResult - for i, v in pairs(cellResult) do - status.cell2sum = status.cell2sum + v - if status.cell2min > v then - status.cell2min = v - end - end - -- if connected after scritp started - if status.batt2sources.vs == false then - status.battsource = "na" - end - if status.battsource == "na" then - status.battsource = "vs" - end - status.batt2sources.vs = true - else - status.batt2sources.vs = false - status.cell2min = 0 - status.cell2sum = 0 - end - -------------------------------- - -- flight controller battery 1 - -------------------------------- - if status.batt1volt > 0 then - status.cell1sumFC = status.batt1volt*0.1 - status.cell1maxFC = math.max(status.batt1volt,status.cell1maxFC) - if status.battsource == "na" then - status.battsource = "fc" - end - status.batt1sources.fc = true - else - status.batt1sources.fc = false - status.cell1sumFC = 0 - end - -------------------------------- - -- flight controller battery 2 - -------------------------------- - if status.batt2volt > 0 then - status.cell2sumFC = status.batt2volt*0.1 - if status.battsource == "na" then - status.battsource = "fc" - end - status.batt2sources.fc = true - else - status.batt2sources.fc = false - status.cell2sumFC = 0 - end - ---------------------------------- - -- 12 analog voltage only 1 supported - ---------------------------------- - local battA2 = getValue("A2") - -- - if battA2 > 0 then - status.cellsumA2 = battA2 - status.cellmaxA2 = math.max(battA2*10,status.cellmaxA2) - status.batt1sources.a2 = true - else - status.batt1sources.a2 = false - status.cellsumA2 = 0 - end - -- batt fc - minmaxValues[1] = calcMinValue(status.cell1sumFC,minmaxValues[1]) - minmaxValues[2] = calcMinValue(status.cell2sumFC,minmaxValues[2]) - -- cell flvss - minmaxValues[3] = calcMinValue(status.cell1min,minmaxValues[3]) - minmaxValues[4] = calcMinValue(status.cell2min,minmaxValues[4]) - -- batt flvss - minmaxValues[5] = calcMinValue(status.cell1sum,minmaxValues[5]) - minmaxValues[6] = calcMinValue(status.cell2sum,minmaxValues[6]) - -- batt 12 - minmaxValues[7] = calcMinValue(status.cellsumA2,minmaxValues[7]) -end - -local function checkLandingStatus() - if ( status.timerRunning == 0 and status.landComplete == 1 and status.lastTimerStart == 0) then - startTimer() - end - if (status.timerRunning == 1 and status.landComplete == 0 and status.lastTimerStart ~= 0) then - stopTimer() - if status.statusArmed == 1 then - playSound("landing") - end - end - status.timerRunning = status.landComplete -end - - -local function calcFlightTime() - -- update local variable with timer 3 value - if ( model.getTimer(2).value < status.flightTime and status.statusArmed == 0) then - reset() - end - if (model.getTimer(2).value < status.flightTime and status.statusArmed == 1) then - model.setTimer(2,{value=status.flightTime}) - pushMessage(3,"timer reset ignored while armed") - end - status.flightTime = model.getTimer(2).value -end - -local function getBatt1Capacity() - return conf.battCapOverride1 > 0 and conf.battCapOverride1*100 or status.batt1Capacity -end - -local function getBatt2Capacity() - return conf.battCapOverride2 > 0 and conf.battCapOverride2*100 or status.batt2Capacity -end - --- gets the voltage based on source and min value, battId = [1|2] -local function getMinVoltageBySource(source,cell,cellFC,cellA2,battId,count) - -- offset 0 for cell voltage, 2 for pack voltage - local offset = 0 - -- - if cell > 4.35*2 or cellFC > 4.35*2 or cellA2 > 4.35*2 then - offset = 2 - end - -- - if source == "vs" then - return showMinMaxValues == true and minmaxValues[2+offset+battId] or cell - elseif source == "fc" then - -- FC only tracks batt1 and batt2 no cell voltage tracking - local minmax = (offset == 2 and minmaxValues[battId] or minmaxValues[battId]/count) - return showMinMaxValues == true and minmax or cellFC - elseif source == "a2" then - -- 12 does not depend on battery id - local minmax = (offset == 2 and minmaxValues[7] or minmaxValues[7]/count) - return showMinMaxValues == true and minmax or cellA2 - end - -- - return 0 -end - -local sensors = { - {0x060F, 0, 0,0, 13 , 0 , "Fuel" }, - {0x021F, 0, 0,0, 1 , 2 , "VFAS"}, - {0x020F, 0, 0,0, 2 , 1 , "CURR"}, - {0x011F, 0, 0,0, 5 , 1 , "VSpd"}, - {0x083F, 0, 0,0, 5 , 0 , "GSpd"}, - {0x010F, 0, 0,0, 9 , 1 , "Alt"}, - {0x082F, 0, 0,0, 9 , 0 , "GAlt"}, - {0x084F, 0, 0,0, 20 , 0 , "Hdg"}, - {0x041F, 0, 0,0, 11 , 0 , "IMUt"}, - {0x060F, 0, 1,0, 0 , 0 , "ARM"} -} - -local function setSensorValues() - if (not telemetryEnabled()) then - return - end - local battmah = status.batt1mah - local battcapacity = getBatt1Capacity() - if status.batt2mah > 0 then - battcapacity = getBatt1Capacity() + getBatt2Capacity() - battmah = status.batt1mah + status.batt2mah - end - local perc = 0 - if (battcapacity > 0) then - perc = (1 - (battmah/battcapacity))*100 - if perc > 99 then - perc = 99 - elseif perc < 0 then - perc = 0 - end - end - -- - sensors[1][4] = perc; - sensors[2][4] = getNonZeroMin(status.batt1volt,status.batt2volt)*10; - sensors[3][4] = status.batt1current+status.batt2current; - sensors[4][4] = status.vSpeed; - sensors[5][4] = status.hSpeed*0.1; - sensors[6][4] = status.homeAlt*10; - sensors[7][4] = math.floor(status.gpsAlt*0.1); - sensors[8][4] = math.floor(status.yaw); - sensors[9][4] = status.imuTemp; - sensors[10][4] = status.statusArmed*100; - -- - for s=1,#sensors - do - local skip = false - -- check if sensor - for i=1,4 - do - -- if a sensor created by the script has a user defined override then do not expose it to OpenTX - if customSensors[i] ~= nil and customSensors[i][2] == sensors[s][7] and customSensors[i][5] == "E" then - -- sensor is external ==> disable the internal one - skip = true - end - end - if skip == false then - setTelemetryValue(sensors[s][1], sensors[s][2], sensors[s][3], sensors[s][4], sensors[s][5] , sensors[s][6] , sensors[s][7]) - end - end -end - --------------------- --- Single long function much more memory efficient than many little functions ---------------------- -local function drawBatteryPane(x,battVolt,cellVolt,current,battmah,battcapacity) - local perc = 0 - if (battcapacity > 0) then - perc = (1 - (battmah/battcapacity))*100 - if perc > 99 then - perc = 99 - elseif perc < 0 then - perc = 0 - end - end - -- battery min cell - local flags = 0 - -- - if showMinMaxValues == false then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) -- white - if status.battLevel2 == false and alarms[8][2] > 0 then - drawBlinkBitmap("cell_red",x+33 - 4,13 + 8) - lcdBacklightOn() - elseif status.battLevel2 == true then - lcd.drawBitmap(getBitmap("cell_red"),x+33 - 4,13 + 8) - elseif status.battLevel1 == false and alarms[7][2] > 0 then - drawBlinkBitmap("cell_orange",x+33 - 4,13 + 8) - lcdBacklightOn() - elseif status.battLevel1 == true then - lcd.drawBitmap(getBitmap("cell_orange"),x+33 - 4,13 + 8) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 0, 0)) -- black - end - flags = CUSTOM_COLOR - end - drawNumberWithTwoDims(x+33, 13,x+171, 23, 60,cellVolt,"V",status.battsource,XXLSIZE+PREC2+flags,flags,flags) - -- battery voltage - drawNumberWithDim(x+100,164,x+95, 159, battVolt,"V",DBLSIZE+PREC1+RIGHT,SMLSIZE) - -- battery current - drawNumberWithDim(x+192,164,x+186,159,current,"A",DBLSIZE+PREC1+RIGHT,SMLSIZE) - -- display capacity bar % - if perc > 50 then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) - elseif perc <= 50 and perc > 25 then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow - else - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) - end - lcd.drawBitmap(getBitmap("gauge_bg"),x+29-2,109-2) - lcd.drawGauge(x+29, 109,160,23,perc,100,CUSTOM_COLOR) - -- battery percentage - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 0, 0)) -- black - local strperc = string.format("%02d%%",perc) - lcd.drawText(x+90, 108, strperc, MIDSIZE+CUSTOM_COLOR) - -- battery mah - local strmah = string.format("%.02f/%.01f",battmah/1000,battcapacity/1000) - lcd.drawText(x+185, 136+6, "Ah", RIGHT) - lcd.drawText(x+185 - 22, 136, strmah, MIDSIZE+RIGHT) - if showMinMaxValues == true then - drawVArrow(x+33+140, 13 + 27,6,false,true) - drawVArrow(x+100-2,164 + 10, 5,false,true) - drawVArrow(x+192-5,164 + 10,5,true,false) - end -end - -local function drawNoTelemetryData() - -- no telemetry data - if (not telemetryEnabled()) then - lcd.drawFilledRectangle(75,90, 330, 100, TITLE_BGCOLOR) - lcd.drawText(140, 120, "no telemetry data", MIDSIZE+INVERS) - lcd.drawText(130, 160, "Yaapu Telemetry Script 1.7.4", SMLSIZE+INVERS) - end -end - -local function drawFlightMode() - -- flight mode - if frame.flightModes then - local strMode = frame.flightModes[status.flightMode] - if strMode ~= nil then - if ( status.simpleMode > 0 ) then - local strSimpleMode = status.simpleMode == 1 and "(S)" or "(SS)" - strMode = string.format("%s%s",strMode,strSimpleMode) - end - lcd.drawText(2 + 2, 218, strMode, MIDSIZE) - end - end - lcd.drawLine(2 + 2,218, 2 + 150,218, SOLID,0) - lcd.drawText(2 + 2,218 - 16,"Flight Mode",SMLSIZE) -end - -local function drawTopBar() - -- black bar - lcd.drawFilledRectangle(0,0, LCD_W, 20, TITLE_BGCOLOR) - -- frametype and model name - local info = model.getInfo() - local fn = frameNames[status.frameType] - local strmodel = info.name - if fn ~= nil then - strmodel = fn..": "..info.name - end - lcd.drawText(2, 0, strmodel, MENU_TITLE_COLOR) - -- flight time - local time = getDateTime() - local strtime = string.format("%02d:%02d:%02d",time.hour,time.min,time.sec) - lcd.drawText(LCD_W, 0+4, strtime, SMLSIZE+RIGHT+MENU_TITLE_COLOR) - -- RSSI - lcd.drawText(265, 0, "RS:", 0 +MENU_TITLE_COLOR) - lcd.drawText(265 + 30,0, getRSSI(), 0 +MENU_TITLE_COLOR) - -- tx voltage - local vtx = string.format("Tx:%.1fv",getValue(getFieldInfo("tx-voltage").id)) - lcd.drawText(330,0, vtx, 0+MENU_TITLE_COLOR) -end - -local function drawFlightTime() - -- flight time - lcd.drawText(330, 202, "Flight Time", SMLSIZE) - lcd.drawLine(330,202 + 16, 330 + 140,202 + 16, SOLID,0) - lcd.drawTimer(330, 202 + 14, model.getTimer(2).value, DBLSIZE) -end - -local function drawScreenTitle(title,page, pages) - lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, title, MENU_TITLE_COLOR) - lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) -end - -local function drawBottomBar() - -- black bar - lcd.drawFilledRectangle(0,LCD_H - 20, LCD_W, 20, TITLE_BGCOLOR) - -- message text - local now = getTime() - local msg = status.messages[#status.messages] - if (now - status.lastMsgTime ) > 150 or conf.disableMsgBlink then - lcd.drawText(2, LCD_H - 20 + 1, msg,MENU_TITLE_COLOR) - else - lcd.drawText(2, LCD_H - 20 + 1, msg,INVERS+BLINK+MENU_TITLE_COLOR) - end -end - -local function drawAllMessages() - for i=1,#status.messages do - lcd.drawText(1,16*(i-1), status.messages[i],SMLSIZE) - end -end - -local function drawGPSStatus() - -- gps status - local strStatus = gpsStatuses[status.gpsStatus] - local flags = BLINK - local mult = 1 - local gpsData = nil - local hdop = status.gpsHdopC - if status.gpsStatus > 2 then - if status.homeAngle ~= -1 then - flags = PREC1 - end - if hdop > 999 then - hdop = 999 - flags = 0 - mult=0.1 - elseif hdop > 99 then - flags = 0 - mult=0.1 - end - lcd.drawText(2 -1,22 - 3, strStatus, SMLSIZE) - lcd.drawText(2 -1,22 + 16 - 3, "fix", 0) - if status.numSats == 15 then - lcd.drawNumber(2 + 80, 22 + 4 , status.numSats, DBLSIZE+RIGHT) - lcd.drawText(2 + 89, 22 + 19, "+", RIGHT) - else - lcd.drawNumber(2 + 87, 22 + 4 , status.numSats, DBLSIZE+RIGHT) - end - -- - lcd.drawText(2 + 94, 22-3, "hd", SMLSIZE) - lcd.drawNumber(2 + 166, 22 + 4, hdop*mult , DBLSIZE+flags+RIGHT) - -- - lcd.drawLine(2 + 91,22 ,2+91,22 + 36,SOLID,0) - -- - gpsData = getValue("GPS") - -- - if type(gpsData) == "table" and gpsData.lat ~= nil and gpsData.lon ~= nil then - lcd.drawText(2 ,22 + 38,math.floor(gpsData.lat * 100000) / 100000,SMLSIZE) - lcd.drawText(165 ,22 + 38,math.floor(gpsData.lon * 100000) / 100000,SMLSIZE+RIGHT) - end - lcd.drawLine(2 ,22 + 37,2+160,22 + 37,SOLID,0) - lcd.drawLine(2 ,22 + 54,2+160,22 + 54,SOLID,0) - elseif status.gpsStatus == 0 then - drawBlinkBitmap("nogpsicon",4,24) - else - drawBlinkBitmap("nolockicon",4,24) - end -end - -local function drawLeftPane(battcurrent,cellsumFC) - if conf.rangeMax > 0 then - flags = 0 - local rng = status.range - if rng > conf.rangeMax then - flags = BLINK+INVERS - end - rng = getMaxValue(rng,17) - if showMinMaxValues == true then - flags = 0 - end - lcd.drawText(10, 95, "Range("..unitLabel..")", SMLSIZE) - lcd.drawText(75, 112, string.format("%.1f",rng*0.01*unitScale), MIDSIZE+flags+RIGHT) - else - flags = BLINK - -- always display gps altitude even without 3d lock - local alt = status.gpsAlt/10 - if status.gpsStatus > 2 then - flags = 0 - -- update max only with 3d or better lock - alt = getMaxValue(alt,13) - end - if showMinMaxValues == true then - flags = 0 - end - lcd.drawText(10, 95, "AltAsl("..unitLabel..")", SMLSIZE) - local stralt = string.format("%d",alt*unitScale) - lcd.drawText(75, 112, stralt, MIDSIZE+flags+RIGHT) - end - -- home distance - drawHomeIcon(91,95,7) - lcd.drawText(165, 95, "Dist("..unitLabel..")", SMLSIZE+RIGHT) - flags = 0 - if status.homeAngle == -1 then - flags = BLINK - end - local dist = getMaxValue(status.homeDist,16) - if showMinMaxValues == true then - flags = 0 - end - local strdist = string.format("%d",dist*unitScale) - lcd.drawText(165, 112, strdist, MIDSIZE+flags+RIGHT) - -- hspeed - local speed = getMaxValue(status.hSpeed,15) - lcd.drawText(81, 152, "Spd("..menuItems[18][5][menuItems[18][4]]..")", SMLSIZE+RIGHT) - lcd.drawNumber(80,170,speed * menuItems[18][6][menuItems[18][4]],MIDSIZE+RIGHT+PREC1) - -- power - --[[ - local power = cellsumFC*battcurrent*0.1 - power = getMaxValue(power,MAX_POWER) - lcd.drawText(BATTPOWER_X, BATTPOWER_Y, "Power(W)", BATTPOWER_FLAGS+RIGHT) - lcd.drawNumber(BATTPOWER_X,BATTPOWER_YW,power,BATTPOWER_FLAGSW+RIGHT) - --]] -- - local eff = speed > 2 and battcurrent*1000/(speed*menuItems[18][6][menuItems[18][4]]) or 0 - lcd.drawText(165, 152, "Eff(mAh)", SMLSIZE+RIGHT) - lcd.drawNumber(165,170,eff,MIDSIZE+RIGHT) - -- - if showMinMaxValues == true then - drawVArrow(75-81, 112,6,true,false) - drawVArrow(165-78, 112 ,6,true,false) - drawVArrow(55-60,170,6,true,false) - drawVArrow(165-78, 170, 5,true,false) - end -end - -local function drawFailsafe() - if status.ekfFailsafe > 0 then - drawBlinkBitmap("ekffailsafe",LCD_W/2 - 90,180) - end - if status.battFailsafe > 0 then - drawBlinkBitmap("battfailsafe",LCD_W/2 - 90,180) - end -end - -local function drawArmStatus() - -- armstatus - if status.ekfFailsafe == 0 and status.battFailsafe == 0 and status.timerRunning == 0 then - if (status.statusArmed == 1) then - lcd.drawBitmap(getBitmap("armed"),LCD_W/2 - 90,180) - else - drawBlinkBitmap("disarmed",LCD_W/2 - 90,180) - end - end -end - --- vertical distance between roll horiz segments - - -local yawRibbonPoints = {} --- -yawRibbonPoints[0]={"N",2} -yawRibbonPoints[1]={"NE",-5} -yawRibbonPoints[2]={"E",2} -yawRibbonPoints[3]={"SE",-5} -yawRibbonPoints[4]={"S",2} -yawRibbonPoints[5]={"SW",-5} -yawRibbonPoints[6]={"W",2} -yawRibbonPoints[7]={"NW",-5} - --- optimized yaw ribbon drawing -local function drawCompassRibbon() - -- ribbon centered +/- 90 on yaw - local centerYaw = (status.yaw+270)%360 - -- this is the first point left to be drawn on the compass ribbon - local nextPoint = math.floor(centerYaw/45) * 45 - -- distance in degrees between leftmost ribbon point and first 45° multiple normalized to 120/8 - local yawMinX = (LCD_W - 120)/2 - local yawMaxX = (LCD_W + 120)/2 - -- x coord of first ribbon letter - local nextPointX = yawMinX + (nextPoint - centerYaw)/45 * 28 - local yawY = 140 - -- - local i = (nextPoint / 45) % 8 - for idx=1,6 - do - if nextPointX >= yawMinX - 3 and nextPointX < yawMaxX then - lcd.drawText(nextPointX+yawRibbonPoints[i][2],yawY,yawRibbonPoints[i][1],SMLSIZE) - end - i = (i + 1) % 8 - nextPointX = nextPointX + 28 - end - -- home icon - local leftYaw = (status.yaw + 180)%360 - local rightYaw = status.yaw%360 - local centerHome = (status.homeAngle+270)%360 - -- - local homeIconX = yawMinX - local homeIconY = yawY + 25 - if rightYaw >= leftYaw then - if centerHome > leftYaw and centerHome < rightYaw then - drawHomeIcon(yawMinX + ((centerHome - leftYaw)/180)*120 - 5,homeIconY) - end - else - if centerHome < rightYaw then - drawHomeIcon(yawMinX + (((360-leftYaw) + centerHome)/180)*120 - 5,homeIconY) - elseif centerHome >= leftYaw then - drawHomeIcon(yawMinX + ((centerHome-leftYaw)/180)*120 - 5,homeIconY) - end - end - -- when abs(home angle) > 90 draw home icon close to left/right border - local angle = status.homeAngle - status.yaw - local cos = math.cos(math.rad(angle - 90)) - local sin = math.sin(math.rad(angle - 90)) - if cos > 0 and sin > 0 then - drawHomeIcon(yawMaxX - 5, homeIconY) - elseif cos < 0 and sin > 0 then - drawHomeIcon(yawMinX - 5, homeIconY) - end - -- - lcd.drawLine(yawMinX, yawY + 16, yawMaxX, yawY + 16, SOLID, 0) - local xx = 0 - if ( status.yaw < 10) then - xx = 0 - elseif (status.yaw < 100) then - xx = -8 - else - xx = -14 - end - lcd.drawNumber(LCD_W/2 + xx - 6, yawY, status.yaw, MIDSIZE+INVERS) -end - - - - - -local function fillTriangle(ox, oy, x1, x2, roll, angle,color) - local step = 2 - -- - local y1 = (oy - ox*angle) + x1*angle - local y2 = (oy - ox*angle) + x2*angle - -- - local steps = math.abs(y2-y1) / step - -- - if (0 < roll and roll <= 90) then - for s=0,steps - do - yy = y1 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(x1,yy,xx - x1,step,color) - end - elseif (90 < roll and roll <= 180) then - for s=0,steps - do - yy = y2 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(x1,yy,xx - x1,step,color) - end - elseif (-90 < roll and roll < 0) then - for s=0,steps - do - yy = y2 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(xx,yy,x2-xx+1,step,color) - end - elseif (-180 < roll and roll <= -90) then - for s=0,steps - do - yy = y1 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(xx,yy,x2-xx+1,step,color) - end - end -end - -------------------------------------------- - -local function drawHud(myWidget) - - local r = -status.roll - local cx,cy,dx,dy,ccx,ccy,cccx,cccy - local yPos = 0 + 20 + 8 - ----------------------- - -- artificial horizon - ----------------------- - -- no roll ==> segments are vertical, offsets are multiples of 10 - if ( status.roll == 0) then - dx=0 - dy=status.pitch - cx=0 - cy=10 - ccx=0 - ccy=2*10 - cccx=0 - cccy=3*10 - else - -- center line offsets - dx = math.cos(math.rad(90 - r)) * -status.pitch - dy = math.sin(math.rad(90 - r)) * status.pitch - -- 1st line offsets - cx = math.cos(math.rad(90 - r)) * 10 - cy = math.sin(math.rad(90 - r)) * 10 - -- 2nd line offsets - ccx = math.cos(math.rad(90 - r)) * 2 * 10 - ccy = math.sin(math.rad(90 - r)) * 2 * 10 - -- 3rd line offsets - cccx = math.cos(math.rad(90 - r)) * 3 * 10 - cccy = math.sin(math.rad(90 - r)) * 3 * 10 - end - local rollX = math.floor((LCD_W-92)/2 + 92/2) - ----------------------- - -- dark color for "ground" - ----------------------- - -- 90x70 - local minY = 44 - local maxY = 114 - local minX = (LCD_W-92)/2 + 1 - local maxX = (LCD_W-92)/2 + 92 - -- - local ox = (LCD_W-92)/2 + 92/2 + dx - -- - local oy = 79 + dy - local yy = 0 - - --lcd.setColor(CUSTOM_COLOR,lcd.RGB(179, 204, 255)) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7a, 0x9c, 0xff)) - - lcd.drawFilledRectangle(minX,minY,92,maxY - minY,CUSTOM_COLOR) - -- angle of the line passing on point(ox,oy) - local angle = math.tan(math.rad(-status.roll)) - -- for each pixel of the hud base/top draw vertical black - -- lines from hud border to horizon line - -- horizon line moves with pitch/roll - --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(102, 51, 0)) - -- - -- - local minxY = (oy - ox * angle) + minX * angle; - local maxxY = (oy - ox * angle) + maxX * angle; - local maxyX = (maxY - (oy - ox * angle)) / angle; - local minyX = (minY - (oy - ox * angle)) / angle; - -- - if ( 0 <= -status.roll and -status.roll <= 90 ) then - if (minxY > minY and maxxY < maxY) then - -- 5 - lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR) - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY < maxY and maxxY > minY) then - -- 6 - lcd.drawFilledRectangle(minX, minY, minyX - minX, maxxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY > maxY) then - -- 7 - lcd.drawFilledRectangle(minX, minY, minyX - minX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < maxY and minxY > minY) then - -- 8 - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY < minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - elseif (90 < -status.roll and -status.roll <= 180) then - if (minxY < maxY and maxxY > minY) then - -- 9 - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > minY and maxxY < maxY) then - -- 10 - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minX, maxxY, maxyX - minX, maxY - maxxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxyX < maxX) then - -- 11 - lcd.drawFilledRectangle(minX, minY, maxyX - minX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < maxY and minxY > minY) then - -- 12 - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > maxY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - -- 9,10,11,12 - elseif (-90 < -status.roll and -status.roll < 0) then - if (minxY < maxY and maxxY > minY) then - -- 1 - lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < maxY and maxxY < minY and minxY > minY) then - -- 2 - lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minyX, minY, maxX - minyX, minxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY < minY) then - -- 3 - lcd.drawFilledRectangle(minyX, minY, maxX - minyX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > minY and maxxY < maxY) then - -- 4 - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxxY < minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - elseif (-180 <= -status.roll and -status.roll <= -90) then - if (minxY > minY and maxxY < maxY) then - -- 13 - lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (maxxY > maxY and minxY > minY and minxY < maxY) then - -- 14 - lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(maxyX, minxY, maxX - maxyX, maxY - minxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxyX < maxX) then - -- 15 - lcd.drawFilledRectangle(maxyX, minY, maxX - maxyX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxxY > minY) then - -- 16 - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - end - -- parallel lines above and below horizon - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) - -- - drawLineWithClipping(rollX + dx - cccx,dy + 79 + cccy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx - ccx,dy + 79 + ccy,r,20,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx - cx,dy + 79 + cy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + cx,dy + 79 - cy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + ccx,dy + 79 - ccy,r,20,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + cccx,dy + 79 - cccy,r,40,DOTTED,(LCD_W-92)/2,(LCD_W-92)/2 + 92,minY,maxY,CUSTOM_COLOR) - ------------------------------------- - -- hud bitmap - ------------------------------------- - lcd.drawBitmap(getBitmap("hud_90x70a"),(LCD_W-106)/2,34) --106x90 - ------------------------------------ - -- synthetic vSpeed based on - -- home altitude when EKF is disabled - -- updated at 1Hz (i.e every 1000ms) - ------------------------------------- - if conf.enableSynthVSpeed == true then - if (status.synthVSpeedTime == 0) then - -- first time do nothing - status.synthVSpeedTime = getTime() - status.prevHomeAlt = status.homeAlt -- dm - elseif (getTime() - status.synthVSpeedTime > 100) then - -- calc vspeed - status.vspd = 1000*(status.homeAlt-status.prevHomeAlt)/(getTime()-status.synthVSpeedTime) -- m/s - -- update counters - status.synthVSpeedTime = getTime() - status.prevHomeAlt = status.homeAlt -- m - end - else - status.vspd = status.vSpeed - end - - ------------------------------------- - -- vario bitmap - ------------------------------------- - local varioMax = math.log(5) - local varioSpeed = math.log(1 + math.min(math.abs(0.05*status.vspd),4)) - local varioH = 0 - if status.vspd > 0 then - varioY = math.min(79 - varioSpeed/varioMax*55,125) - else - varioY = 78 - end - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) - lcd.drawFilledRectangle(172+2, varioY, 7, varioSpeed/varioMax*55, CUSTOM_COLOR, 0) - lcd.drawBitmap(getBitmap("variogauge_big"),172,19) - if status.vSpeed > 0 then - lcd.drawBitmap(getBitmap("varioline"),172-3,varioY) - else - lcd.drawBitmap(getBitmap("varioline"),172-3,77 + varioSpeed/varioMax*55) - end - ------------------------------------- - -- left and right indicators on HUD - ------------------------------------- - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) - -- altitude - local alt = getMaxValue(status.homeAlt,12) * unitScale - lcd.drawText(275,LCD_H-37,"alt("..unitLabel..")",SMLSIZE) - if math.abs(alt) >= 10 then - lcd.drawNumber(310,LCD_H-60,alt,MIDSIZE+RIGHT) - else - lcd.drawNumber(310,LCD_H-60,alt*10,MIDSIZE+RIGHT+PREC1) - end - -- vertical speed - local vspd = status.vspd * 0.1 * menuItems[19][6][menuItems[19][4]] - lcd.drawText(170,LCD_H-37,"vspd("..menuItems[19][5][menuItems[19][4]]..")",SMLSIZE) - if (math.abs(vspd) >= 10) then - lcd.drawNumber(180,LCD_H-60, vspd ,MIDSIZE) - else - lcd.drawNumber(180,LCD_H-60,vspd*10,MIDSIZE+PREC1) - end - -- min/max arrows - if showMinMaxValues == true then - drawVArrow(310+3, LCD_H-60 + 2,6,true,false) - end -end - -local function drawHomeDirection() - local angle = math.floor(status.homeAngle - status.yaw) - local x1 = (LCD_W/2) + 17 * math.cos(math.rad(angle - 90)) - local y1 = 202 + 17 * math.sin(math.rad(angle - 90)) - local x2 = (LCD_W/2) + 17 * math.cos(math.rad(angle - 90 + 150)) - local y2 = 202 + 17 * math.sin(math.rad(angle - 90 + 150)) - local x3 = (LCD_W/2) + 17 * math.cos(math.rad(angle - 90 - 150)) - local y3 = 202 + 17 * math.sin(math.rad(angle - 90 - 150)) - local x4 = (LCD_W/2) + 17 * 0.5 * math.cos(math.rad(angle - 270)) - local y4 = 202 + 17 * 0.5 *math.sin(math.rad(angle - 270)) - -- - drawLine(x1,y1,x2,y2,SOLID,1) - drawLine(x1,y1,x3,y3,SOLID,1) - drawLine(x2,y2,x4,y4,SOLID,1) - drawLine(x3,y3,x4,y4,SOLID,1) -end - ---------------------------------- --- This function checks alarm condition and as long as the condition persists it plays --- a warning sound. ---------------------------------- -local function checkAlarm(level,value,idx,sign,sound,delay) - -- once landed reset all alarms except battery alerts - if status.timerRunning == 0 then - if alarms[idx][4] == 0 then - alarms[idx] = { false, 0, false, 0, 0, false, 0} - elseif alarms[idx][4] == 1 then - alarms[idx] = { false, 0, true, 1 , 0, false, 0} - elseif alarms[idx][4] == 2 then - alarms[idx] = { false, 0, true, 2, 0, false, 0} - elseif alarms[idx][4] == 3 then - alarms[idx] = { false, 0 , false, 3, 4, false, 0} - elseif alarms[idx][4] == 4 then - alarms[idx] = { false, 0 , false, 4, 4, false, 0} - end - -- reset done - return - end - -- if needed arm the alarm only after value has reached level - if alarms[idx][3] == false and level > 0 and -1 * sign*value > -1 * sign*level then - alarms[idx][3] = true - end - -- - if alarms[idx][4] == 2 then - if status.flightTime > 0 and math.floor(status.flightTime) % delay == 0 then - if alarms[idx][1] == false then - alarms[idx][1] = true - playSound(sound) - -- flightime is a multiple of 1 minute - if (status.flightTime % 60 == 0 ) then - -- minutes - playNumber(status.flightTime / 60,25) --25=minutes,26=seconds - else - -- minutes - if (status.flightTime > 60) then playNumber(status.flightTime / 60,25) end - -- seconds - playNumber(status.flightTime % 60,26) - end - end - else - alarms[idx][1] = false - end - else - if alarms[idx][3] == true then - if level > 0 and sign*value > sign*level then - -- value is outside level - if alarms[idx][2] == 0 then - -- first time outside level after last reset - alarms[idx][2] = status.flightTime - -- status: START - end - else - -- value back to normal ==> reset - alarms[idx][2] = 0 - alarms[idx][1] = false - alarms[idx][6] = false - -- status: RESET - end - if alarms[idx][2] > 0 and (status.flightTime ~= alarms[idx][2]) and (status.flightTime - alarms[idx][2]) >= alarms[idx][5] then - -- enough time has passed after START - alarms[idx][6] = true - -- status: READY - end - -- - if alarms[idx][6] == true and alarms[idx][1] == false then - playSound(sound) - alarms[idx][1] = true - alarms[idx][7] = status.flightTime - -- status: BEEP - end - -- all but battery alarms - if alarms[idx][4] ~= 3 then - if alarms[idx][6] == true and status.flightTime ~= alarms[idx][7] and (status.flightTime - alarms[idx][7]) % delay == 0 then - alarms[idx][1] = false - -- status: REPEAT - end - end - end - end -end - -local function loadFlightModes() - if frame.flightModes then - return - end - -- - if status.frameType ~= -1 then - if frameTypes[status.frameType] == "c" then - frame = dofile("/SCRIPTS/YAAPU/LIB/copter.lua") - elseif frameTypes[status.frameType] == "p" then - frame = dofile("/SCRIPTS/YAAPU/LIB/plane.lua") - elseif frameTypes[status.frameType] == "r" then - frame = dofile("/SCRIPTS/YAAPU/LIB/rover.lua") - end - end -end - -local function checkEvents(celm) - loadFlightModes() - -- silence alarms when showing min/max values - if showMinMaxValues == false then - checkAlarm(conf.minAltitudeAlert,status.homeAlt,1,-1,"minalt",menuItems[14][4]) - checkAlarm(conf.maxAltitudeAlert,status.homeAlt,2,1,"maxalt",menuItems[14][4]) - checkAlarm(conf.maxDistanceAlert,status.homeDist,3,1,"maxdist",menuItems[14][4]) - checkAlarm(1,2*status.ekfFailsafe,4,1,"ekf",menuItems[14][4]) - checkAlarm(1,2*status.battFailsafe,5,1,"lowbat",menuItems[14][4]) - checkAlarm(conf.timerAlert,status.flightTime,6,1,"timealert",conf.timerAlert) -end - -- default is use battery 1 - local capacity = getBatt1Capacity() - local mah = status.batt1mah - -- only if dual battery has been detected use battery 2 - if status.batt2sources.fc or status.batt2sources.vs then - capacity = capacity + getBatt2Capacity() - mah = mah + status.batt2mah - end - -- - if (capacity > 0) then - status.batLevel = (1 - (mah/capacity))*100 - else - status.batLevel = 99 - end - for l=1,13 do - -- trigger alarm as as soon as it falls below level + 1 (i.e 91%,81%,71%,...) - if status.batLevel <= batLevels[l] + 1 and l < status.lastBattLevel then - status.lastBattLevel = l - playSound("bat"..batLevels[l]) - break - end - end - - if status.statusArmed == 1 and status.lastStatusArmed == 0 then - status.lastStatusArmed = status.statusArmed - playSound("armed") - elseif status.statusArmed == 0 and status.lastStatusArmed == 1 then - status.lastStatusArmed = status.statusArmed - playSound("disarmed") - end - - if status.gpsStatus > 2 and status.lastGpsStatus <= 2 then - status.lastGpsStatus = status.gpsStatus - playSound("gpsfix") - elseif status.gpsStatus <= 2 and status.lastGpsStatus > 2 then - status.lastGpsStatus = status.gpsStatus - playSound("gpsnofix") - end - - if status.frameType ~= -1 and status.flightMode ~= status.lastFlightMode then - status.lastFlightMode = status.flightMode - playSoundByFrameTypeAndFlightMode(status.flightMode) - end - - if status.simpleMode ~= status.lastSimpleMode then - if status.simpleMode == 0 then - playSound( status.lastSimpleMode == 1 and "simpleoff" or "ssimpleoff" ) - else - playSound( status.simpleMode == 1 and "simpleon" or "ssimpleon" ) - end - status.lastSimpleMode = status.simpleMode - end -end - -local function checkCellVoltage(celm) - -- check alarms - checkAlarm(conf.battAlertLevel1,celm,7,-1,"batalert1",menuItems[14][4]) - checkAlarm(conf.battAlertLevel2,celm,8,-1,"batalert2",menuItems[14][4]) - -- cell bgcolor is sticky but gets triggered with alarms - if status.battLevel1 == false then status.battLevel1 = alarms[7][1] end - if status.battLevel2 == false then status.battLevel2 = alarms[8][1] end -end - -local function cycleBatteryInfo() - if showDualBattery == false and (status.batt2sources.fc or status.batt2sources.vs) then - showDualBattery = true - return - end - if status.battsource == "vs" then - status.battsource = "fc" - elseif status.battsource == "fc" then - status.battsource = "a2" - elseif status.battsource == "a2" then - status.battsource = "vs" - end -end --------------------------------------------------------------------------------- --- MAIN LOOP --------------------------------------------------------------------------------- --- -local bgclock = 0 - -------------------------------- --- running at 20Hz (every 50ms) -------------------------------- -local bgprocessing = false -local bglockcounter = 0 --- -local function backgroundTasks(telemetryLoops) -if bgprocessing == true then - bglockcounter = bglockcounter + 1 - return 0 -end -bgprocessing = true - -- FAST: this runs at 60Hz (every 16ms) - for i=1,telemetryLoops - do - processTelemetry() - end - -- NORMAL: this runs at 20Hz (every 50ms) - calcFlightTime() - -- SLOW: this runs at 4Hz (every 250ms) - if (bgclock % 4 == 0) then - setSensorValues() - collectgarbage() - end - -- SLOWER: this runs at 2Hz (every 500ms) - if (bgclock % 8 == 0) then - -- update battery - calcBattery() - -- prepare celm based on battsource - local count = calcCellCount() - local cellVoltage = 0 - -- - if status.battsource == "vs" then - cellVoltage = getNonZeroMin(status.cell1min, status.cell2min)*100 --FLVSS - elseif status.battsource == "fc" then - cellVoltage = getNonZeroMin(status.cell1sumFC/count,status.cell2sumFC/count)*100 --FC - elseif status.battsource == "a2" then - cellVoltage = (status.cellsumA2/count)*100 --12 - end - -- - checkEvents(cellVoltage) - checkLandingStatus() - -- no need for alarms if reported voltage is 0 - if cellVoltage > 0 then - checkCellVoltage(cellVoltage) - end - -- aggregate value - minmaxValues[8] = math.max(status.batt1current+status.batt2current,minmaxValues[8]) - -- indipendent values - minmaxValues[9] = math.max(status.batt1current,minmaxValues[9]) - minmaxValues[10] = math.max(status.batt2current,minmaxValues[10]) - -- reset backlight panel - if (model.getGlobalVariable(8,0) > 0 and getTime()/100 - backlightLastTime > 5) then - model.setGlobalVariable(8,0,0) - end - bgclock = 0 - end - bgclock = bgclock+1 - -- blinking support - if (getTime() - blinktime) > 65 then - blinkon = not blinkon - blinktime = getTime() - end - bgprocessing = false - return 0 -end - -local showSensorPage = false -local showMessages = false -local showConfigMenu = false - -local function background() - backgroundTasks(5) -end --------------------------- --- RUN --------------------------- --- EVT_EXIT_BREAK = RTN - - - - - - - -local function run(event) - background() - lcd.clear() - --------------------- - -- SHOW MESSAGES - --------------------- - if showConfigMenu == false and (event == EVT_PLUS_BREAK or event == EVT_ROT_RIGHT) then - showMessages = true - -- stop event processing chain - event = 0 - end - --------------------- - -- SHOW CONFIG MENU - --------------------- - if showMessages == false and (event == 2053 or event == 2051 ) then - showConfigMenu = true - -- stop event processing chain - event = 0 - end - --------------------- - -- SHOW SENSORS PAGE - --------------------- - -- - if showSensorPage == false and showConfigMenu == false and showMessages == false and (event == 1537 or event == 1536) then - showSensorPage = true - -- stop event processing chain - event = 0 - end - - if showMessages then - --------------------- - -- MESSAGES - --------------------- - if event == EVT_EXIT_BREAK or event == EVT_MINUS_BREAK or event == EVT_ROT_LEFT then - showMessages = false - end - drawAllMessages() - elseif showConfigMenu then - --------------------- - -- CONFIG MENU - --------------------- - drawConfigMenu(event) - -- - if event == EVT_EXIT_BREAK then - menu.editSelected = false - showConfigMenu = false - saveConfig() - end - else - --------------------- - -- MAIN VIEW - --------------------- - if event == 518 then - showMinMaxValues = not showMinMaxValues - -- stop event processing chain - event = 0 - end - if showDualBattery == true and event == EVT_EXIT_BREAK then - showDualBattery = false - -- stop event processing chain - event = 0 - end - if showSensorPage == true and event == EVT_EXIT_BREAK or event == 1537 or event == 1536 then - showSensorPage = false - -- stop event processing chain - event = 0 - end - if event == EVT_ROT_BREAK then - cycleBatteryInfo() - -- stop event processing chain - event = 0 - end - drawHomeDirection() - drawHud() - drawCompassRibbon() - -- - -- Note: these can be calculated. not necessary to track them as min/max - -- status.cell1minFC = status.cell1sumFC/calcCellCount() - -- status.cell2minFC = status.cell2sumFC/calcCellCount() - -- status.cell1minA2 = status.cell1sumA2/calcCellCount() - -- - local count = calcCellCount() - local cel1m = getMinVoltageBySource(status.battsource,status.cell1min,status.cell1sumFC/count,status.cellsumA2/count,1,count)*100 - local cel2m = getMinVoltageBySource(status.battsource,status.cell2min,status.cell2sumFC/count,status.cellsumA2/count,2,count)*100 - local batt1 = getMinVoltageBySource(status.battsource,status.cell1sum,status.cell1sumFC,status.cellsumA2,1,count)*10 - local batt2 = getMinVoltageBySource(status.battsource,status.cell2sum,status.cell2sumFC,status.cellsumA2,2,count)*10 - local curr = getMaxValue(status.batt1current+status.batt2current,8) - local curr1 = getMaxValue(status.batt1current,9) - local curr2 = getMaxValue(status.batt2current,10) - local mah1 = status.batt1mah - local mah2 = status.batt2mah - local cap1 = getBatt1Capacity() - local cap2 = getBatt2Capacity() - -- - -- with dual battery default is to show aggregate view - if status.batt2sources.fc or status.batt2sources.vs then - if showDualBattery == false then - -- dual battery: aggregate view - lcd.drawText(285+67,85,"BATTERY: 1+2",SMLSIZE+INVERS) - drawBatteryPane(285,getNonZeroMin(batt1,batt2),getNonZeroMin(cel1m,cel2m),curr,mah1+mah2,cap1+cap2) - else - -- dual battery: do I have also dual current monitor? - if curr1 > 0 and curr2 == 0 then - -- special case: assume 1 power brick is monitoring batt1+batt2 in parallel - curr1 = curr1/2 - curr2 = curr1 - -- - mah1 = mah1/2 - mah2 = mah1 - -- - cap1 = cap1/2 - cap2 = cap1 - end - -- dual battery:battery 1 right pane - lcd.drawText(285+75,85,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - -- dual battery:battery 2 left pane - lcd.drawText(50,85,"BATTERY: 2",SMLSIZE+INVERS) - drawBatteryPane(-24,batt2,cel2m,curr2,mah2,cap2) - end - else - -- battery 1 right pane in single battery mode - lcd.drawText(285+75,85,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - end - -- left pane info when not in dual battery mode - if showDualBattery == false then - -- power is always based on flight controller values - drawGPSStatus() - if showSensorPage then - drawCustomSensors() - else - drawLeftPane(curr1+curr2,getNonZeroMin(status.cell1sumFC,status.cell2sumFC)) - end - end - drawFlightMode() - drawTopBar() - drawBottomBar() - drawFlightTime() - drawFailsafe() - drawArmStatus() - if showDualBattery == false and showSensorPage == false then - end - drawNoTelemetryData() - end - return 0 -end - -local function init() - -- initialize flight timer - model.setTimer(2,{mode=0}) - model.setTimer(2,{value=0}) - loadConfig() - playSound("yaapu") - loadSensors() - pushMessage(7,"Yaapu Telemetry Script 1.7.4") - -- load unit definitions - unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 - unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" -end - --------------------------------------------------------------------------------- --- SCRIPT END --------------------------------------------------------------------------------- -return {run=run, init=init} diff --git a/HORUS/SOURCES/README.md b/HORUS/SOURCES/README.md new file mode 100644 index 00000000..8f4ee6c1 --- /dev/null +++ b/HORUS/SOURCES/README.md @@ -0,0 +1,5 @@ +Note +- files in the PP folder have to be preprocessed first with /TOOLS/pp.lua prior to compiling in OpenTX companion +- files in the SRC folder are ready to be copied to the root of your virtual SD Card in OpenTX companion for compilation + + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/copter.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/copter.lua new file mode 100644 index 00000000..cf18a422 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/copter.lua @@ -0,0 +1,58 @@ + --[[ + // Auto Pilot Modes enumeration + enum control_mode_t { + STABILIZE = 0, // manual airframe angle with manual throttle + ACRO = 1, // manual body-frame angular rate with manual throttle + ALT_HOLD = 2, // manual airframe angle with automatic throttle + AUTO = 3, // fully automatic waypoint control using mission commands + GUIDED = 4, // fully automatic fly to coordinate or fly at velocity/direction using GCS immediate commands + LOITER = 5, // automatic horizontal acceleration with automatic throttle + RTL = 6, // automatic return to launching point + CIRCLE = 7, // automatic circular flight with automatic throttle + LAND = 9, // automatic landing with horizontal position control + DRIFT = 11, // semi-automous position, yaw and throttle control + SPORT = 13, // manual earth-frame angular rate control with manual throttle + FLIP = 14, // automatically flip the vehicle on the roll axis + AUTOTUNE = 15, // automatically tune the vehicle's roll and pitch gains + POSHOLD = 16, // automatic position hold with manual override, with automatic throttle + BRAKE = 17, // full-brake using inertial/GPS system, no pilot input + THROW = 18, // throw to launch mode using inertial/GPS system, no pilot input + AVOID_ADSB = 19, // automatic avoidance of obstacles in the macro scale - e.g. full-sized aircraft + GUIDED_NOGPS = 20, // guided mode but only accepts attitude and altitude + SMART_RTL = 21, // SMART_RTL returns to home by retracing its steps + FLOWHOLD = 22, // FLOWHOLD holds position with optical flow without rangefinder + FOLLOW = 23, // follow attempts to follow another vehicle or ground station + ZIGZAG = 24, // ZIGZAG mode is able to fly in a zigzag manner with predefined point A and point B + }; + --]] local flightModes = {} + + -- copter flight modes + flightModes[0]="" + flightModes[1]="Stabilize" + flightModes[2]="Acro" + flightModes[3]="AltHold" + flightModes[4]="Auto" + flightModes[5]="Guided" + flightModes[6]="Loiter" + flightModes[7]="RTL" + flightModes[8]="Circle" + flightModes[9]="" + flightModes[10]="Land" + flightModes[11]="" + flightModes[12]="Drift" + flightModes[13]="" + flightModes[14]="Sport" + flightModes[15]="Flip" + flightModes[16]="AutoTune" + flightModes[17]="PosHold" + flightModes[18]="Brake" + flightModes[19]="Throw" + flightModes[20]="AvoidADSB" + flightModes[21]="GuidedNOGPS" + flightModes[22]="SmartRTL" + flightModes[23]="FlowHold" + flightModes[24]="Follow" + flightModes[25]="ZigZag" + flightModes[26]="Initializing" + +return {flightModes=flightModes} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/copter_px4.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/copter_px4.lua new file mode 100644 index 00000000..d143e236 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/copter_px4.lua @@ -0,0 +1,29 @@ +local flightModes = {} +-- plane flight modes +flightModes[0]="" +flightModes[1]="Manual" +flightModes[2]="AltCtl" --px4 specific +flightModes[3]="PosCtl" --px4 specific +flightModes[4]="Ready" --px4 specific +flightModes[5]="Takeoff" --px4 specific +flightModes[6]="Loiter" +flightModes[7]="Mission" --px4 specific +flightModes[8]="RTL" +flightModes[9]="Land" +flightModes[10]="RTGS" --px4 specific +flightModes[11]="Follow" +flightModes[12]="PrecLand" --px4 specific +flightModes[13]="" +flightModes[14]="Acro" +flightModes[15]="OffBoard" --px4 specific +flightModes[16]="Stabilize" +flightModes[17]="RAttitude" --px4 specific +flightModes[18]="Simple" --px4 specific +flightModes[19]="" +flightModes[20]="" +flightModes[21]="" +flightModes[22]="" +flightModes[23]="" +-- +return {flightModes=flightModes} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/draw.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/draw.lua new file mode 100644 index 00000000..8df7089a --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/draw.lua @@ -0,0 +1,546 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() + + +local function drawHArrow(x,y,width,left,right,drawBlinkBitmap) + lcd.drawLine(x, y, x + width,y, SOLID, 0) + if left == true then + lcd.drawLine(x + 1,y - 1,x + 2,y - 2, SOLID, 0) + lcd.drawLine(x + 1,y + 1,x + 2,y + 2, SOLID, 0) + end + if right == true then + lcd.drawLine(x + width - 1,y - 1,x + width - 2,y - 2, SOLID, 0) + lcd.drawLine(x + width - 1,y + 1,x + width - 2,y + 2, SOLID, 0) + end +end +-- +local function drawVArrow(x,y,top,bottom,utils) + if top == true then + utils.drawBlinkBitmap("uparrow",x,y) + else + utils.drawBlinkBitmap("downarrow",x,y) + end +end + +local function drawHomeIcon(x,y,utils) + lcd.drawBitmap(utils.getBitmap("minihomeorange"),x,y) +end + +local function drawLine(x1,y1,x2,y2,flags1,flags2) + -- if lines are hor or ver do not fix +--if string.find(radio, "x10") and rev < 2 and x1 ~= x2 and y1 ~= y2 then + if string.find(radio, "x10") and rev < 2 then + lcd.drawLine(LCD_W-x1,LCD_H-y1,LCD_W-x2,LCD_H-y2,flags1,flags2) + else + lcd.drawLine(x1,y1,x2,y2,flags1,flags2) + end +end + +local function computeOutCode(x,y,xmin,ymin,xmax,ymax) + local code = 0; --initialised as being inside of hud + -- + if x < xmin then --to the left of hud + code = bit32.bor(code,1); + elseif x > xmax then --to the right of hud + code = bit32.bor(code,2); + end + if y < ymin then --below the hud + code = bit32.bor(code,8); + elseif y > ymax then --above the hud + code = bit32.bor(code,4); + end + -- + return code; +end + +-- Cohen–Sutherland clipping algorithm +-- https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm +local function drawLineWithClippingXY(x0,y0,x1,y1,style,xmin,xmax,ymin,ymax,color,radio,rev) + -- compute outcodes for P0, P1, and whatever point lies outside the clip rectangle + local outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax); + local outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); + local accept = false; + + while (true) do + if ( bit32.bor(outcode0,outcode1) == 0) then + -- bitwise OR is 0: both points inside window; trivially accept and exit loop + accept = true; + break; + elseif (bit32.band(outcode0,outcode1) ~= 0) then + -- bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP, BOTTOM) + -- both must be outside window; exit loop (accept is false) + break; + else + -- failed both tests, so calculate the line segment to clip + -- from an outside point to an intersection with clip edge + local x = 0 + local y = 0 + -- At least one endpoint is outside the clip rectangle; pick it. + local outcodeOut = outcode0 ~= 0 and outcode0 or outcode1 + -- No need to worry about divide-by-zero because, in each case, the + -- outcode bit being tested guarantees the denominator is non-zero + if bit32.band(outcodeOut,4) ~= 0 then --point is above the clip window + x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0) + y = ymax + elseif bit32.band(outcodeOut,8) ~= 0 then --point is below the clip window + x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0) + y = ymin + elseif bit32.band(outcodeOut,2) ~= 0 then --point is to the right of clip window + y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0) + x = xmax + elseif bit32.band(outcodeOut,1) ~= 0 then --point is to the left of clip window + y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0) + x = xmin + end + -- Now we move outside point to intersection point to clip + -- and get ready for next pass. + if outcodeOut == outcode0 then + x0 = x + y0 = y + outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax) + else + x1 = x + y1 = y + outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax) + end + end + end + if accept then + drawLine(x0,y0,x1,y1, style,color) + end +end + +local function drawLineWithClipping(ox,oy,angle,len,style,xmin,xmax,ymin,ymax,color,radio,rev) + local xx = math.cos(math.rad(angle)) * len * 0.5 + local yy = math.sin(math.rad(angle)) * len * 0.5 + + local x0 = ox - xx + local x1 = ox + xx + local y0 = oy - yy + local y1 = oy + yy + + drawLineWithClippingXY(x0,y0,x1,y1,style,xmin,xmax,ymin,ymax,color,radio,rev) +end + +local function drawNumberWithDim(x,y,xDim,yDim,number,dim,flags,dimFlags) + lcd.drawNumber(x, y, number,flags) + lcd.drawText(xDim, yDim, dim, dimFlags) +end + +local function drawRArrow(x,y,r,angle,color) + local ang = math.rad(angle - 90) + local x1 = x + r * math.cos(ang) + local y1 = y + r * math.sin(ang) + + ang = math.rad(angle - 90 + 150) + local x2 = x + r * math.cos(ang) + local y2 = y + r * math.sin(ang) + + ang = math.rad(angle - 90 - 150) + local x3 = x + r * math.cos(ang) + local y3 = y + r * math.sin(ang) + ang = math.rad(angle - 270) + local x4 = x + r * 0.5 * math.cos(ang) + local y4 = y + r * 0.5 *math.sin(ang) + -- + drawLine(x1,y1,x2,y2,SOLID,color) + drawLine(x1,y1,x3,y3,SOLID,color) + drawLine(x2,y2,x4,y4,SOLID,color) + drawLine(x3,y3,x4,y4,SOLID,color) +end + +local function drawFailsafe(telemetry,utils) + if telemetry.ekfFailsafe > 0 then + utils.drawBlinkBitmap("ekffailsafe",LCD_W/2 - 90,154) + end + if telemetry.battFailsafe > 0 then + utils.drawBlinkBitmap("battfailsafe",LCD_W/2 - 90,154) + end +end + +local function drawArmStatus(status,telemetry,utils) + -- armstatus + if telemetry.ekfFailsafe == 0 and telemetry.battFailsafe == 0 and status.timerRunning == 0 then + if (telemetry.statusArmed == 1) then + lcd.drawBitmap(utils.getBitmap("armed"),LCD_W/2 - 90,154) + else + utils.drawBlinkBitmap("disarmed",LCD_W/2 - 90,154) + end + end +end + +local function drawNoTelemetryData(status,telemetry,utils,telemetryEnabled) + -- no telemetry data + if (not telemetryEnabled()) then + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawFilledRectangle(88,74, 304, 84, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xF800) + lcd.drawFilledRectangle(90,76, 300, 80, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(110, 85, "no telemetry data", DBLSIZE+CUSTOM_COLOR) + lcd.drawText(130, 120, "Yaapu Telemetry Widget 1.8.0", SMLSIZE+CUSTOM_COLOR) + end +end + +local function drawFilledRectangle(x,y,w,h,flags) + if w > 0 and h > 0 then + lcd.drawFilledRectangle(x,y,w,h,flags) + end +end + + +local yawRibbonPoints = {} +-- +yawRibbonPoints[0]="N" +yawRibbonPoints[1]=nil +yawRibbonPoints[2]="NE" +yawRibbonPoints[3]=nil +yawRibbonPoints[4]="E" +yawRibbonPoints[5]=nil +yawRibbonPoints[6]="SE" +yawRibbonPoints[7]=nil +yawRibbonPoints[8]="S" +yawRibbonPoints[9]=nil +yawRibbonPoints[10]="SW" +yawRibbonPoints[11]=nil +yawRibbonPoints[12]="W" +yawRibbonPoints[13]=nil +yawRibbonPoints[14]="NW" +yawRibbonPoints[15]=nil + +-- optimized yaw ribbon drawing +local function drawCompassRibbon(y,myWidget,conf,telemetry,status,battery,utils,width,xMin,xMax,stepWidth,bigFont) + -- ribbon centered +/- 90 on yaw + local centerYaw = (telemetry.yaw + 270 - (bigFont and 16 or 10))%360 -- (-10 needed to center ribbon) + -- this is the first point left to be drawn on the compass ribbon + local nextPoint = math.floor(centerYaw/22.5) * 22.5 + -- x coord of first ribbon letter + local nextPointX = xMin + (nextPoint - centerYaw)/22.5 * stepWidth + -- + local i = (nextPoint / 22.5) % 16 + for idx=1,12 + do + local letterOffset = 1 + local lineOffset = 4 + if nextPointX >= xMin -3 and nextPointX < xMax then + if yawRibbonPoints[i] == nil then + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawLine(nextPointX + lineOffset, y+1, nextPointX + lineOffset, y+7, SOLID, CUSTOM_COLOR) + else + if #yawRibbonPoints[i] > 1 then + letterOffset = -5 + lineOffset = 2 + end + lcd.setColor(CUSTOM_COLOR,0xFFFF) + --lcd.setColor(CUSTOM_COLOR,0x7BCF) + lcd.drawText(nextPointX+letterOffset,y+(bigFont and -2 or 0),yawRibbonPoints[i],SMLSIZE+CUSTOM_COLOR) + end + end + i = (i + 1) % 16 + nextPointX = nextPointX + stepWidth + end + -- home icon + local homeOffset = 0 + local angle = telemetry.homeAngle - telemetry.yaw + if angle < 0 then + angle = 360 + angle + end + if angle > 270 or angle < 90 then + homeOffset = ((angle + 90) % 180)/180 * width + elseif angle >= 90 and angle <= 180 then + homeOffset = width + end + drawHomeIcon(xMin + homeOffset -5,y + (bigFont and 28 or 20),utils) + -- yaw angle box + local xx = 0 + if ( telemetry.yaw < 10) then + xx = bigFont and 20 or 14 + elseif (telemetry.yaw < 100) then + xx = bigFont and 40 or 28 + else + xx = bigFont and 60 or 42 + end + --lcd.drawNumber(LCD_W/2 + xx - 6, YAW_Y, telemetry.yaw, MIDSIZE+INVERS) + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawFilledRectangle(LCD_W/2 - (xx/2), y - 1, xx, bigFont and 28 or 20, CUSTOM_COLOR+SOLID) + lcd.drawRectangle(LCD_W/2 - (xx/2) - 1, y - 1, xx+2, bigFont and 28 or 20, CUSTOM_COLOR+SOLID) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(LCD_W/2 - (xx/2), y - 6, telemetry.yaw, (bigFont and DBLSIZE or MIDSIZE)+CUSTOM_COLOR) +end + +local function drawStatusBar(maxRows,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + local yDelta = (maxRows-1)*12 + + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawFilledRectangle(0,229-yDelta,480,LCD_H-(229-yDelta),CUSTOM_COLOR) + -- flight time + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawTimer(LCD_W, 224-yDelta, model.getTimer(2).value, DBLSIZE+CUSTOM_COLOR+RIGHT) + -- flight mode + lcd.setColor(CUSTOM_COLOR,0xFFFF) + if status.strFlightMode ~= nil then + lcd.drawText(1,230-yDelta,status.strFlightMode,MIDSIZE+CUSTOM_COLOR) + end + -- gps status, draw coordinatyes if good at least once + if telemetry.lon ~= nil and telemetry.lat ~= nil then + lcd.drawText(370,227-yDelta,utils.decToDMSFull(telemetry.lat),SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(370,241-yDelta,utils.decToDMSFull(telemetry.lon,telemetry.lat),SMLSIZE+CUSTOM_COLOR+RIGHT) + end + -- gps status + local hdop = telemetry.gpsHdopC + local strStatus = gpsStatuses[telemetry.gpsStatus] + local flags = BLINK + local mult = 1 + + if telemetry.gpsStatus > 2 then + if telemetry.homeAngle ~= -1 then + flags = PREC1 + end + if hdop > 999 then + hdop = 999 + flags = 0 + mult=0.1 + elseif hdop > 99 then + flags = 0 + mult=0.1 + end + -- HDOP + lcd.drawNumber(270,226-yDelta, hdop*mult,DBLSIZE+flags+RIGHT+CUSTOM_COLOR) + -- SATS + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(170,226-yDelta, strStatus, SMLSIZE+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,0xFFFF) + if telemetry.numSats == 15 then + lcd.drawNumber(170,235-yDelta, telemetry.numSats, MIDSIZE+CUSTOM_COLOR) + lcd.drawText(200,239-yDelta, "+", SMLSIZE+CUSTOM_COLOR) + else + lcd.drawNumber(170,235-yDelta,telemetry.numSats, MIDSIZE+CUSTOM_COLOR) + end + elseif telemetry.gpsStatus == 0 then + utils.drawBlinkBitmap("nogpsicon",150,227-yDelta) + else + utils.drawBlinkBitmap("nolockicon",150,227-yDelta) + end + + local offset = math.min(maxRows,#status.messages+1) + + for i=0,offset-1 do + if status.messages[(status.messageCount + i - offset) % (#status.messages+1)][2] < 4 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,70,0)) + elseif status.messages[(status.messageCount + i - offset) % (#status.messages+1)][2] == 4 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255,0)) + else + lcd.setColor(CUSTOM_COLOR,0xFFFF) + end + lcd.drawText(1,(256-yDelta)+(12*i), status.messages[(status.messageCount + i - offset) % (#status.messages+1)][1],SMLSIZE+CUSTOM_COLOR) + end +end + +return { + drawNumberWithDim=drawNumberWithDim, + drawHomeIcon=drawHomeIcon, + drawHArrow=drawHArrow, + drawVArrow=drawVArrow, + drawRArrow=drawRArrow, + computeOutCode=computeOutCode, + drawLineWithClippingXY=drawLineWithClippingXY, + drawLineWithClipping=drawLineWithClipping, + drawFailsafe=drawFailsafe, + drawArmStatus=drawArmStatus, + drawNoTelemetryData=drawNoTelemetryData, + drawStatusBar=drawStatusBar, + drawFilledRectangle=drawFilledRectangle, + drawCompassRibbon=drawCompassRibbon, + yawRibbonPoints=yawRibbonPoints +} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_1.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_1.lua new file mode 100644 index 00000000..d77a9736 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_1.lua @@ -0,0 +1,448 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + +-- x:300 y:135 inside HUD + + + + + + + + +----------------------- +-- COMPASS RIBBON +----------------------- + + + + + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) + + local r = -telemetry.roll + local cx,cy,dx,dy,ccx,ccy,cccx,cccy + local yPos = 0 + 20 + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of 21 + if ( telemetry.roll == 0 or math.abs(telemetry.roll) == 180) then + dx=0 + dy=telemetry.pitch * 1.85 + cx=0 + cy=21 + ccx=0 + ccy=2*21 + cccx=0 + cccy=3*21 + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch * 1.85 + -- 1st line offsets + cx = math.cos(math.rad(90 - r)) * 21 + cy = math.sin(math.rad(90 - r)) * 21 + end + local rollX = math.floor((LCD_W-280)/2 + 280/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 140x90 + local minY = 18 + local maxY = 18 + 134 + + local minX = (LCD_W-280)/2 + local maxX = (LCD_W-280)/2 + 280 + + local ox = (LCD_W-280)/2 + 280/2 + dx + local oy = 85 + dy + local yy = 0 + + -- HUD + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x0d, 0x68, 0xb1)) -- bighud blue + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7b, 0x9d, 0xff)) -- default blue + lcd.drawFilledRectangle(minX,minY,maxX-minX,maxY - minY,CUSTOM_COLOR) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x90, 0x63, 0x20)) --906320 bighud brown + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x63, 0x30, 0x00)) --623000 old brown + + -- angle of the line passing on point(ox,oy) + local angle = math.tan(math.rad(-telemetry.roll)) + -- prevent divide by zero + if telemetry.roll == 0 then + drawLib.drawFilledRectangle(minX,math.max(minY,dy+minY+(maxY-minY)/2),maxX-minX,math.min(maxY-minY,(maxY-minY)/2-dy+(math.abs(dy) > 0 and 1 or 0)),CUSTOM_COLOR) + elseif math.abs(telemetry.roll) >= 180 then + drawLib.drawFilledRectangle(minX,minY,maxX-minX,math.min(maxY-minY,(maxY-minY)/2+dy),CUSTOM_COLOR) + else + -- HUD drawn using horizontal bars of height 2 + -- true if flying inverted + local inverted = math.abs(telemetry.roll) > 90 + -- true if part of the hud can be filled in one pass with a rectangle + local fillNeeded = false + local yRect = inverted and 0 or LCD_H + + local step = 2 + local steps = (maxY - minY)/step - 1 + local yy = 0 + + if 0 < telemetry.roll and telemetry.roll < 180 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(xx, yy, maxX-xx+1, step,CUSTOM_COLOR) + elseif xx < minX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + elseif -180 < telemetry.roll and telemetry.roll < 0 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(minX, yy, xx-minX, step,CUSTOM_COLOR) + elseif xx > maxX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + end + + if fillNeeded then + local yMin = inverted and minY or yRect + local height = inverted and yRect - minY or maxY-yRect + --lcd.setColor(CUSTOM_COLOR,0xF800) --623000 old brown + lcd.drawFilledRectangle(minX, yMin, maxX-minX, height ,CUSTOM_COLOR) + end + end + + + -- parallel lines above and below horizon + local linesMaxY = maxY-2 + local linesMinY = minY+10 + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- +/- 90 deg + for dist=1,8 + do + drawLib.drawLineWithClipping(rollX + dx - dist*cx,dy + 85 + dist*cy,r,(dist%2==0 and 80 or 40),DOTTED,(LCD_W-280)/2+2,(LCD_W-280)/2+280-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + dx + dist*cx,dy + 85 - dist*cy,r,(dist%2==0 and 80 or 40),DOTTED,(LCD_W-280)/2+2,(LCD_W-280)/2+280-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + end + + -- hashmarks + local startY = minY + 1 + local endY = maxY - 10 + local step = 18 + -- hSpeed + local roundHSpeed = math.floor((telemetry.hSpeed*conf.horSpeedMultiplier*0.1/5)+0.5)*5; + local offset = math.floor((telemetry.hSpeed*conf.horSpeedMultiplier*0.1-roundHSpeed)*0.2*step); + local ii = 0; + local yy = 0 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(120,120,120)) + for j=roundHSpeed+20,roundHSpeed-20,-5 + do + yy = startY + (ii*step) + offset - 14 + if yy >= startY and yy < endY then + lcd.drawLine((LCD_W-280)/2, yy+9, (LCD_W-280)/2 + 4, yy+9, SOLID, CUSTOM_COLOR) + lcd.drawNumber((LCD_W-280)/2 + 7, yy, j, SMLSIZE+CUSTOM_COLOR) + end + ii=ii+1; + end + -- altitude + local roundAlt = math.floor((telemetry.homeAlt*unitScale/5)+0.5)*5; + offset = math.floor((telemetry.homeAlt*unitScale-roundAlt)*0.2*step); + ii = 0; + yy = 0 + for j=roundAlt+20,roundAlt-20,-5 + do + yy = startY + (ii*step) + offset - 14 + if yy >= startY and yy < endY then + lcd.drawLine((LCD_W-280)/2 + 280 - 14, yy+8, (LCD_W-280)/2 + 280-10 , yy+8, SOLID, CUSTOM_COLOR) + lcd.drawNumber((LCD_W-280)/2 + 280 - 16, yy, j, SMLSIZE+RIGHT+CUSTOM_COLOR) + end + ii=ii+1; + end + lcd.setColor(CUSTOM_COLOR,0xFFFF) + + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_280x134"),(LCD_W-280)/2,18) --160x90 + + ------------------------------------- + -- vario + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = varioSpeed/varioMax*52 + --varioH = varioH + (varioH > 0 and 1 or 0) + if telemetry.vSpeed > 0 then + varioY = 19 + (52 - varioH) + else + varioY = 85 + 15 + end + --00ae10 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(50, 50, 50)) --dark grey + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) --white + lcd.drawFilledRectangle(372, varioY, 8, varioH, CUSTOM_COLOR, 0) + + ------------------------------------- + -- left and right indicators on HUD + ------------------------------------- + -- DATA + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,11) * unitScale + if math.abs(alt) > 999 or alt < -99 then + lcd.drawNumber((LCD_W-280)/2+280+1,85-16,alt,MIDSIZE+CUSTOM_COLOR+RIGHT) + elseif math.abs(alt) >= 10 then + lcd.drawNumber((LCD_W-280)/2+280+1,85-20,alt,DBLSIZE+CUSTOM_COLOR+RIGHT) + else + lcd.drawNumber((LCD_W-280)/2+280+1,85-20,alt*10,DBLSIZE+PREC1+CUSTOM_COLOR+RIGHT) + end + -- telemetry.hSpeed is in dm/s + local hSpeed = utils.getMaxValue(telemetry.hSpeed,14) * 0.1 * conf.horSpeedMultiplier + if (math.abs(hSpeed) >= 10) then + lcd.drawNumber((LCD_W-280)/2+2,85-20,hSpeed,DBLSIZE+CUSTOM_COLOR) + else + lcd.drawNumber((LCD_W-280)/2+2,85-20,hSpeed*10,DBLSIZE+CUSTOM_COLOR+PREC1) + end + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow((LCD_W-280)/2+68, 85-12,true,false,utils) + drawLib.drawVArrow((LCD_W-280)/2+280-79, 85-12,true,false,utils) + end + + -- vspeed box + lcd.setColor(CUSTOM_COLOR,0xFFFF) + + local vSpeed = utils.getMaxValue(telemetry.vSpeed,13) * 0.1 -- m/s + + local xx = math.abs(vSpeed*conf.vertSpeedMultiplier) > 999 and 4 or 3 + xx = xx + (vSpeed*conf.vertSpeedMultiplier < 0 and 1 or 0) + + if math.abs(vSpeed*conf.vertSpeedMultiplier*10) > 99 then -- + lcd.drawNumber((LCD_W)/2 + (xx/2)*12, 127, vSpeed*conf.vertSpeedMultiplier, MIDSIZE+CUSTOM_COLOR+RIGHT) + else + lcd.drawNumber((LCD_W)/2 + (xx/2)*12, 127, vSpeed*conf.vertSpeedMultiplier*10, MIDSIZE+CUSTOM_COLOR+RIGHT+PREC1) + end + + -- compass ribbon + drawLib.drawCompassRibbon(18,myWidget,conf,telemetry,status,battery,utils,240,(LCD_W-240)/2,(LCD_W+240)/2,25,true) + + -- pitch and roll + lcd.setColor(CUSTOM_COLOR,0xFE60) + local xoffset = math.abs(telemetry.pitch) > 99 and 6 or 0 + lcd.drawNumber(248+xoffset,90,telemetry.pitch,CUSTOM_COLOR+SMLSIZE+RIGHT) + lcd.drawNumber(214,76,telemetry.roll,CUSTOM_COLOR+SMLSIZE+RIGHT) + lcd.setColor(CUSTOM_COLOR,0xFFFF) +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_2.lua new file mode 100644 index 00000000..6bde2b5f --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_2.lua @@ -0,0 +1,424 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + + + + + + + + +----------------------- +-- COMPASS RIBBON +----------------------- + + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) + + local r = -telemetry.roll + local cx,cy,dx,dy,ccx,ccy,cccx,cccy + local yPos = 0 + 20 + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of 12 + if ( telemetry.roll == 0) then + dx=0 + dy=telemetry.pitch + cx=0 + cy=12 + ccx=0 + ccy=2*12 + cccx=0 + cccy=3*12 + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch + -- 1st line offsets + cx = math.cos(math.rad(90 - r)) * 12 + cy = math.sin(math.rad(90 - r)) * 12 + -- 2nd line offsets + ccx = math.cos(math.rad(90 - r)) * 2 * 12 + ccy = math.sin(math.rad(90 - r)) * 2 * 12 + -- 3rd line offsets + cccx = math.cos(math.rad(90 - r)) * 3 * 12 + cccy = math.sin(math.rad(90 - r)) * 3 * 12 + end + local rollX = math.floor((LCD_W-160)/2 + 160/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 140x90 + local minY = 24 + local maxY = 24 + 90 + + local minX = (LCD_W-160)/2 + local maxX = (LCD_W-160)/2 + 160 + + local ox = (LCD_W-160)/2 + 160/2 + dx + local oy = 69 + dy + local yy = 0 + + -- HUD + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x0d, 0x68, 0xb1)) -- bighud blue + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7b, 0x9d, 0xff)) -- default blue + lcd.drawFilledRectangle(minX,minY,maxX-minX,maxY - minY,CUSTOM_COLOR) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x90, 0x63, 0x20)) --906320 bighud brown + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x63, 0x30, 0x00)) --623000 old brown + + -- angle of the line passing on point(ox,oy) + local angle = math.tan(math.rad(-telemetry.roll)) + -- prevent divide by zero + if telemetry.roll == 0 then + drawLib.drawFilledRectangle(minX,math.max(minY,dy+minY+(maxY-minY)/2),maxX-minX,math.min(maxY-minY,(maxY-minY)/2-dy+(math.abs(dy) > 0 and 1 or 0)),CUSTOM_COLOR) + elseif math.abs(telemetry.roll) >= 180 then + drawLib.drawFilledRectangle(minX,minY,maxX-minX,math.min(maxY-minY,(maxY-minY)/2+dy),CUSTOM_COLOR) + else + -- HUD drawn using horizontal bars of height 2 + -- true if flying inverted + local inverted = math.abs(telemetry.roll) > 90 + -- true if part of the hud can be filled in one pass with a rectangle + local fillNeeded = false + local yRect = inverted and 0 or LCD_H + + local step = 2 + local steps = (maxY - minY)/step - 1 + local yy = 0 + + if 0 < telemetry.roll and telemetry.roll < 180 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(xx, yy, maxX-xx+1, step,CUSTOM_COLOR) + elseif xx < minX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + elseif -180 < telemetry.roll and telemetry.roll < 0 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(minX, yy, xx-minX, step,CUSTOM_COLOR) + elseif xx > maxX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + end + + if fillNeeded then + local yMin = inverted and minY or yRect + local height = inverted and yRect - minY or maxY-yRect + --lcd.setColor(CUSTOM_COLOR,0xF800) --623000 old brown + lcd.drawFilledRectangle(minX, yMin, maxX-minX, height ,CUSTOM_COLOR) + end + end + + + -- parallel lines above and below horizon + local linesMaxY = maxY-1 + local linesMinY = minY+1 + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- +/- 90 deg + for dist=1,8 + do + drawLib.drawLineWithClipping(rollX + dx - dist*cx,dy + 69 + dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,(LCD_W-160)/2+2,(LCD_W-160)/2+160-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + dx + dist*cx,dy + 69 - dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,(LCD_W-160)/2+2,(LCD_W-160)/2+160-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + end +-- hashmarks + local startY = minY + 1 + local endY = maxY - 10 + local step = 18 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(120,120,120)) + -- hSpeed + local roundHSpeed = math.floor((telemetry.hSpeed*conf.horSpeedMultiplier*0.1/5)+0.5)*5; + local offset = math.floor((telemetry.hSpeed*conf.horSpeedMultiplier*0.1-roundHSpeed)*0.2*step); + local ii = 0; + local yy = 0 + for j=roundHSpeed+10,roundHSpeed-10,-5 + do + yy = startY + (ii*step) + offset + if yy >= startY and yy < endY then + lcd.drawLine((LCD_W-160)/2 + 1, yy+9, (LCD_W-160)/2 + 5, yy+9, SOLID, CUSTOM_COLOR) + lcd.drawNumber((LCD_W-160)/2 + 8, yy, j, SMLSIZE+CUSTOM_COLOR) + end + ii=ii+1; + end + -- altitude + local roundAlt = math.floor((telemetry.homeAlt*unitScale/5)+0.5)*5; + offset = math.floor((telemetry.homeAlt*unitScale-roundAlt)*0.2*step); + ii = 0; + yy = 0 + for j=roundAlt+10,roundAlt-10,-5 + do + yy = startY + (ii*step) + offset + if yy >= startY and yy < endY then + lcd.drawLine((LCD_W-160)/2 + 160 - 15, yy+8, (LCD_W-160)/2 + 160 -10, yy+8, SOLID, CUSTOM_COLOR) + lcd.drawNumber((LCD_W-160)/2 + 160 - 16, yy, j, SMLSIZE+RIGHT+CUSTOM_COLOR) + end + ii=ii+1; + end + lcd.setColor(CUSTOM_COLOR,0xFFFF) + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_160x90c"),(LCD_W-160)/2,24) --160x90 + ------------------------------------- + -- vario bitmap + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = varioSpeed/varioMax*35 + if telemetry.vSpeed > 0 then + varioY = 24 + 35 - varioH + else + varioY = 24 + 55 + end + --00ae10 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(50, 50, 50)) --dark grey + lcd.drawFilledRectangle(310, varioY, 10, varioH, CUSTOM_COLOR, 0) + + ------------------------------------- + -- left and right indicators on HUD + ------------------------------------- + -- DATA + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,11) * unitScale + if math.abs(alt) > 999 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + lcd.drawNumber((LCD_W-160)/2+160+1,69-10,alt,CUSTOM_COLOR+RIGHT) + elseif math.abs(alt) >= 10 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + lcd.drawNumber((LCD_W-160)/2+160+1,69-14,alt,MIDSIZE+CUSTOM_COLOR+RIGHT) + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + lcd.drawNumber((LCD_W-160)/2+160+1,69-14,alt*10,MIDSIZE+PREC1+CUSTOM_COLOR+RIGHT) + end + -- telemetry.hSpeed is in dm/s + local hSpeed = utils.getMaxValue(telemetry.hSpeed,14) * 0.1 * conf.horSpeedMultiplier + if (math.abs(hSpeed) >= 10) then + lcd.drawNumber((LCD_W-160)/2+2,69-14,hSpeed,MIDSIZE+CUSTOM_COLOR) + else + lcd.drawNumber((LCD_W-160)/2+2,69-14,hSpeed*10,MIDSIZE+CUSTOM_COLOR+PREC1) + end + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow((LCD_W-160)/2+50, 69-9,true,false,utils) + drawLib.drawVArrow((LCD_W-160)/2+160-57, 69-9,true,false,utils) + end + -- compass ribbon + drawLib.drawCompassRibbon(120,myWidget,conf,telemetry,status,battery,utils,140,(LCD_W-140)/2,(LCD_W+140)/2,15,false) +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_russian_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_russian_2.lua new file mode 100644 index 00000000..016dafb9 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_russian_2.lua @@ -0,0 +1,360 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + + + + + + + + + +----------------------- +-- COMPASS RIBBON +----------------------- + + + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) + + local r = -telemetry.roll + local cx,cy,dx,dy + local yPos = 0 + 20 + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of 25 + if ( telemetry.roll == 0) then + dx=0 + dy=telemetry.pitch + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch + end + local rollX = math.floor((LCD_W-158)/2 + 158/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 140x110 + local minY = 24 + local maxY = 24 + 90 + + local minX = (LCD_W-158)/2 + 1 + local maxX = (LCD_W-158)/2 + 158 + + local ox = (LCD_W-158)/2 + 158/2 + dx + 5 + local oy = 69 + dy + local yy = 0 + + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(179, 204, 255)) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7b, 0x9d, 0xff)) -- default blue + lcd.drawFilledRectangle(minX,minY,158,maxY-minY,CUSTOM_COLOR) + -- angle of the line passing on point(ox,oy) + local angle = math.tan(math.rad(-telemetry.roll)) + -- for each pixel of the hud base/top draw vertical black + -- lines from hud border to horizon line + -- horizon line moves with pitch/roll + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(102, 51, 0)) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x63, 0x30, 0x00)) --623000 old brown + if math.abs(telemetry.roll) < 90 then + if oy > minY and oy < maxY then + lcd.drawFilledRectangle(minX,oy,158,maxY-oy + 1,CUSTOM_COLOR) + elseif oy <= minY then + lcd.drawFilledRectangle(minX,minY,158,maxY-minY,CUSTOM_COLOR) + end + else + --inverted + if oy > minY and oy < maxY then + lcd.drawFilledRectangle(minX,minY,158,oy-minY + 1,CUSTOM_COLOR) + elseif oy >= maxY then + lcd.drawFilledRectangle(minX,minY,158,maxY-minY,CUSTOM_COLOR) + end + end + -- +-- parallel lines above and below horizon + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) + -- + local hx = math.cos(math.rad(90 - r)) * -(telemetry.pitch%45) + local hy = math.sin(math.rad(90 - r)) * (telemetry.pitch%45) + + --drawLineWithClipping(rollX - hx, 69 + hy,r,50,SOLID,(LCD_W-158)/2,(LCD_W-158)/2 + 158,minY,maxY,CUSTOM_COLOR) + + for line=0,4 + do + -- + local deltax = math.cos(math.rad(90 - r)) * 20 * line + local deltay = math.sin(math.rad(90 - r)) * 20 * line + -- + drawLib.drawLineWithClipping(rollX - deltax + hx, 69 + deltay + hy,r,50,DOTTED,(LCD_W-158)/2,(LCD_W-158)/2 + 158,minY,maxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + deltax + hx, 69 - deltay + hy,r,50,DOTTED,(LCD_W-158)/2,(LCD_W-158)/2 + 158,minY,maxY,CUSTOM_COLOR,radio,rev) + end + + local xx = math.cos(math.rad(r)) * 70 * 0.5 + local yy = math.sin(math.rad(r)) * 70 * 0.5 + -- + local x0 = rollX - xx + local y0 = 69 - yy + -- + local x1 = rollX + xx + local y1 = 69 + yy + -- + drawLib.drawLineWithClipping(x0,y0,r + 90,70,SOLID,(LCD_W-158)/2,(LCD_W-158)/2 + 158,minY,maxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(x1,y1,r + 90,70,SOLID,(LCD_W-158)/2,(LCD_W-158)/2 + 158,minY,maxY,CUSTOM_COLOR,radio,rev) + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_160x90_rus"),(LCD_W-158)/2,24) --160x90 + ------------------------------------- + -- vario bitmap + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = varioSpeed/varioMax*35 + if telemetry.vSpeed > 0 then + varioY = 24 + 35 - varioH + else + varioY = 24 + 55 + end + --00ae10 + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(00, 0xED, 0x32)) --green + -- lcd.setColor(CUSTOM_COLOR,lcd.RGB(50, 50, 50)) --dark grey + lcd.drawFilledRectangle(310, varioY, 10, varioH, CUSTOM_COLOR, 0) + ------------------------------------- + -- left and right indicators on HUD + ------------------------------------- + -- DATA + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,11) * unitScale + if math.abs(alt) > 999 then + lcd.setColor(CUSTOM_COLOR,0x1FEA) + lcd.drawNumber((LCD_W-158)/2+158 - 42,69-10,alt,CUSTOM_COLOR) + elseif math.abs(alt) >= 10 then + lcd.setColor(CUSTOM_COLOR,0x1FEA) + lcd.drawNumber((LCD_W-158)/2+158 - 42,69-14,alt,MIDSIZE+CUSTOM_COLOR) + else + lcd.setColor(CUSTOM_COLOR,0x1FEA) + lcd.drawNumber((LCD_W-158)/2+158 - 42,69-14,alt*10,MIDSIZE+PREC1+CUSTOM_COLOR) + end + lcd.setColor(CUSTOM_COLOR,0x1FEA) + -- telemetry.hSpeed is in dm/s + local hSpeed = utils.getMaxValue(telemetry.hSpeed,14) * 0.1 * conf.horSpeedMultiplier + if (math.abs(hSpeed) >= 10) then + lcd.drawNumber((LCD_W-158)/2+44,69-14,hSpeed,MIDSIZE+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber((LCD_W-158)/2+44,69-14,hSpeed*10,MIDSIZE+RIGHT+CUSTOM_COLOR+PREC1) + end + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow((LCD_W-158)/2+50, 69-9,true,false,utils) + drawLib.drawVArrow((LCD_W-158)/2+158-57, 69-9,true,false,utils) + end + -- compass ribbon + drawLib.drawCompassRibbon(120,myWidget,conf,telemetry,status,battery,utils,140,(LCD_W-140)/2,(LCD_W+140)/2,15) +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_small_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_small_2.lua new file mode 100644 index 00000000..fc26505d --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/hud_small_2.lua @@ -0,0 +1,367 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + + + + + + + + +----------------------- +-- COMPASS RIBBON +----------------------- + + + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() + + +local function drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils)--getMaxValue,getBitmap,drawBlinkBitmap) + + local r = -telemetry.roll + local cx,cy,dx,dy,ccx,ccy,cccx,cccy + local yPos = 0 + 20 + 8 + ----------------------- + -- artificial horizon + ----------------------- + -- no roll ==> segments are vertical, offsets are multiples of 11 + if ( telemetry.roll == 0) then + dx=0 + dy=telemetry.pitch + cx=0 + cy=11 + ccx=0 + ccy=2*11 + cccx=0 + cccy=3*11 + else + -- center line offsets + dx = math.cos(math.rad(90 - r)) * -telemetry.pitch + dy = math.sin(math.rad(90 - r)) * telemetry.pitch + -- 1st line offsets + cx = math.cos(math.rad(90 - r)) * 11 + cy = math.sin(math.rad(90 - r)) * 11 + -- 2nd line offsets + ccx = math.cos(math.rad(90 - r)) * 2 * 11 + ccy = math.sin(math.rad(90 - r)) * 2 * 11 + -- 3rd line offsets + cccx = math.cos(math.rad(90 - r)) * 3 * 11 + cccy = math.sin(math.rad(90 - r)) * 3 * 11 + end + local rollX = math.floor((LCD_W-92)/2 + 92/2) + ----------------------- + -- dark color for "ground" + ----------------------- + -- 90x70 + local minY = 30 + local maxY = 30+70 + -- + local minX = (LCD_W-92)/2 + local maxX = (LCD_W-92)/2 + 92 + -- + local ox = (LCD_W-92)/2 + 92/2 + dx + -- + local oy = 30+70/2 + dy + local yy = 0 + + -- HUD + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x0d, 0x68, 0xb1)) -- bighud blue + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7b, 0x9d, 0xff)) -- default blue + lcd.drawFilledRectangle(minX,minY,maxX-minX,maxY - minY,CUSTOM_COLOR) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x90, 0x63, 0x20)) --906320 bighud brown + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x63, 0x30, 0x00)) --623000 old brown + + -- angle of the line passing on point(ox,oy) + local angle = math.tan(math.rad(-telemetry.roll)) + -- prevent divide by zero + if telemetry.roll == 0 then + drawLib.drawFilledRectangle(minX,math.max(minY,dy+minY+(maxY-minY)/2),maxX-minX,math.min(maxY-minY,(maxY-minY)/2-dy+(math.abs(dy) > 0 and 1 or 0)),CUSTOM_COLOR) + elseif math.abs(telemetry.roll) >= 180 then + drawLib.drawFilledRectangle(minX,minY,maxX-minX,math.min(maxY-minY,(maxY-minY)/2+dy),CUSTOM_COLOR) + else + -- HUD drawn using horizontal bars of height 2 + -- true if flying inverted + local inverted = math.abs(telemetry.roll) > 90 + -- true if part of the hud can be filled in one pass with a rectangle + local fillNeeded = false + local yRect = inverted and 0 or LCD_H + + local step = 2 + local steps = (maxY - minY)/step - 1 + local yy = 0 + + if 0 < telemetry.roll and telemetry.roll < 180 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(xx, yy, maxX-xx+1, step,CUSTOM_COLOR) + elseif xx < minX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + elseif -180 < telemetry.roll and telemetry.roll < 0 then + for s=0,steps + do + yy = minY + s*step + xx = ox + (yy-oy)/angle + if xx >= minX and xx <= maxX then + lcd.drawFilledRectangle(minX, yy, xx-minX, step,CUSTOM_COLOR) + elseif xx > maxX then + yRect = inverted and math.max(yy,yRect)+step or math.min(yy,yRect) + fillNeeded = true + end + end + end + + if fillNeeded then + local yMin = inverted and minY or yRect + local height = inverted and yRect - minY or maxY-yRect + --lcd.setColor(CUSTOM_COLOR,0xF800) --623000 old brown + lcd.drawFilledRectangle(minX, yMin, maxX-minX, height ,CUSTOM_COLOR) + end + end + + + -- parallel lines above and below horizon + local linesMaxY = maxY-1 + local linesMinY = minY+1 + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- +/- 90 deg + for dist=1,8 + do + drawLib.drawLineWithClipping(rollX + dx - dist*cx,dy + 30+70/2 + dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,(LCD_W-92)/2+2,(LCD_W-92)/2+92-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + drawLib.drawLineWithClipping(rollX + dx + dist*cx,dy + 30+70/2 - dist*cy,r,(dist%2==0 and 40 or 20),DOTTED,(LCD_W-92)/2+2,(LCD_W-92)/2+92-2,linesMinY,linesMaxY,CUSTOM_COLOR,radio,rev) + end + ------------------------------------- + -- hud bitmap + ------------------------------------- + lcd.drawBitmap(utils.getBitmap("hud_90x70a"),(LCD_W-106)/2,30-10) --106x90 + ------------------------------------- + -- vario bitmap + ------------------------------------- + local varioMax = 5 + local varioSpeed = math.min(math.abs(0.1*telemetry.vSpeed),5) + local varioH = 0 + if telemetry.vSpeed > 0 then + varioY = 20+46 - varioSpeed/varioMax*40 + else + varioY = 20+45 + end + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) + lcd.drawFilledRectangle(275+26, varioY, 7, varioSpeed/varioMax*39, CUSTOM_COLOR, 0) + lcd.drawBitmap(utils.getBitmap("variogauge_90"),275,20) + + if telemetry.vSpeed > 0 then + lcd.drawBitmap(utils.getBitmap("varioline"),275+21,varioY-1) + else + lcd.drawBitmap(utils.getBitmap("varioline"),275+21,20+44 + varioSpeed/varioMax*39) + end + -- compass ribbon + drawLib.drawCompassRibbon(115,myWidget,conf,telemetry,status,battery,utils,140,(LCD_W-140)/2,(LCD_W+140)/2,15) +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawHud=drawHud,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/layout_1.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/layout_1.lua new file mode 100644 index 00000000..0045f64f --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/layout_1.lua @@ -0,0 +1,315 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + +-- x:300 y:135 inside HUD + + + + + + + + + + + +-------------------------- +-- CUSTOM SENSORS SUPPORT +-------------------------- + +local customSensorXY = { + { 80, 193, 80, 203}, + { 160, 193, 160, 203}, + { 240, 193, 240, 203}, + { 320, 193, 320, 203}, + { 400, 193, 400, 203}, + { 480, 193, 480, 203}, +} + +local function drawCustomSensors(x,customSensors,utils,status) + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawFilledRectangle(0,194,LCD_W,35,CUSTOM_COLOR) + + local label,data,prec,mult,flags,sensorConfig + for i=1,6 + do + if customSensors.sensors[i] ~= nil then + sensorConfig = customSensors.sensors[i] + + if sensorConfig[4] == "" then + label = string.format("%s",sensorConfig[1]) + else + label = string.format("%s(%s)",sensorConfig[1],sensorConfig[4]) + end + -- draw sensor label + lcd.setColor(CUSTOM_COLOR,0x8C71) + lcd.drawText(x+customSensorXY[i][1], customSensorXY[i][2],label, SMLSIZE+RIGHT+CUSTOM_COLOR) + + mult = sensorConfig[3] == 0 and 1 or ( sensorConfig[3] == 1 and 10 or 100 ) + prec = mult == 1 and 0 or (mult == 10 and 32 or 48) + + local sensorName = sensorConfig[2]..(status.showMinMaxValues == true and sensorConfig[6] or "") + local sensorValue = getValue(sensorName) + local value = (sensorValue+(mult == 100 and 0.005 or 0))*mult*sensorConfig[5] + + -- default font size + flags = sensorConfig[7] == 1 and 0 or MIDSIZE + + -- for sensor 3,4,5,6 reduce font if necessary + if math.abs(value)*mult > 99999 then + flags = 0 + end + + local color = 0xFFFF + local sign = sensorConfig[6] == "+" and 1 or -1 + -- max tracking, high values are critical + if math.abs(value) ~= 0 and status.showMinMaxValues == false then + color = ( sensorValue*sign > sensorConfig[9]*sign and lcd.RGB(255,70,0) or (sensorValue*sign > sensorConfig[8]*sign and 0xFE60 or 0xFFFF)) + end + + lcd.setColor(CUSTOM_COLOR,color) + + local voffset = flags==0 and 6 or 0 + -- if a lookup table exists use it! + if customSensors.lookups[i] ~= nil and customSensors.lookups[i][value] ~= nil then + lcd.drawText(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, customSensors.lookups[i][value] or value, flags+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, value, flags+RIGHT+prec+CUSTOM_COLOR) + end + end + end +end + +local function draw(myWidget,drawLib,conf,telemetry,status,battery,alarms,frame,utils,customSensors,gpsStatuses,leftPanel,centerPanel,rightPanel) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + centerPanel.drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils) + --lcd.setColor(CUSTOM_COLOR,0xFE60) + drawLib.drawRArrow(240,174,20,math.floor(telemetry.homeAngle - telemetry.yaw),CUSTOM_COLOR)--HomeDirection(telemetry) + -- with dual battery default is to show aggregate view + if status.batt2sources.fc or status.batt2sources.vs then + if status.showDualBattery == false then + -- dual battery: aggregate view + rightPanel.drawPane(380,drawLib,conf,telemetry,status,alarms,battery,0,gpsStatuses,utils) + -- left pane info + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,0,gpsStatuses,utils) + else + -- dual battery:battery 1 right pane + rightPanel.drawPane(380,drawLib,conf,telemetry,status,alarms,battery,1,gpsStatuses,utils) + -- dual battery:battery 2 left pane + rightPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,2,gpsStatuses,utils) + end + else + -- battery 1 right pane in single battery mode + rightPanel.drawPane(380,drawLib,conf,telemetry,status,alarms,battery,1,gpsStatuses,utils) + -- left pane info in single battery mode + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,0,gpsStatuses,utils) + end + utils.drawTopBar() + local msgRows = 4 + if customSensors ~= nil then + --utils.drawBottomBar() + msgRows = 1 + -- draw custom sensors + drawCustomSensors(0,customSensors,utils,status) + end + drawLib.drawStatusBar(msgRows,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + drawLib.drawFailsafe(telemetry,utils) + drawLib.drawArmStatus(status,telemetry,utils) +end + +return {draw=draw} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/layout_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/layout_2.lua new file mode 100644 index 00000000..afff1a09 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/layout_2.lua @@ -0,0 +1,267 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + + + + + +local function drawExtendedStatusBar(drawLib,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + -- LEFT label + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(153,165,"Alt("..unitLabel..")",SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(68,165,"VSI("..conf.vertSpeedLabel..")",SMLSIZE+CUSTOM_COLOR+RIGHT) + + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- altitude + local alt = utils.getMaxValue(telemetry.homeAlt,11) * unitScale + if math.abs(alt) > 999 then + lcd.drawNumber(153,178,alt,MIDSIZE+RIGHT+CUSTOM_COLOR) + elseif math.abs(alt) >= 10 then + lcd.drawNumber(153,178,alt,MIDSIZE+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(153,178,alt*10,MIDSIZE+RIGHT+PREC1+CUSTOM_COLOR) + end + -- vertical speed + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local vSpeed = utils.getMaxValue(telemetry.vSpeed,13) * 0.1 * conf.vertSpeedMultiplier + if (math.abs(telemetry.vSpeed) >= 10) then + lcd.drawNumber(68,178, vSpeed ,MIDSIZE+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(68,178,vSpeed*10,MIDSIZE+RIGHT+PREC1+CUSTOM_COLOR) + end + -- min/max arrows + if status.showMinMaxValues == true then + drawLib.drawVArrow(3, 178 + 3,true,false,utils) + drawLib.drawVArrow(68-70, 178 + 3,true,false,utils) + end + +end + +local function draw(myWidget,drawLib,conf,telemetry,status,battery,alarms,frame,utils,customSensors,gpsStatuses,leftPanel,centerPanel,rightPanel) + if leftPanel ~= nil and centerPanel ~= nil and rightPanel ~= nil then + lcd.setColor(CUSTOM_COLOR,0xFFFF) + drawLib.drawRArrow((LCD_W/2),180,22,math.floor(telemetry.homeAngle - telemetry.yaw),CUSTOM_COLOR)--HomeDirection(telemetry) + centerPanel.drawHud(myWidget,drawLib,conf,telemetry,status,battery,utils,customSensors) + -- with dual battery default is to show aggregate view + if status.batt2sources.fc or status.batt2sources.vs then + if status.showDualBattery == false then + -- dual battery: aggregate view + rightPanel.drawPane(285,drawLib,conf,telemetry,status,alarms,battery,0,gpsStatuses,utils,customSensors) + -- left panel + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,0,gpsStatuses,utils,customSensors) + else + -- dual battery:battery 1 right pane + rightPanel.drawPane(285,drawLib,conf,telemetry,status,alarms,battery,1,gpsStatuses,utils,customSensors) + -- dual battery:battery 2 left pane + rightPanel.drawPane(-37,drawLib,conf,telemetry,status,alarms,battery,2,gpsStatuses,utils,customSensors) + end + else + -- battery 1 right pane in single battery mode + rightPanel.drawPane(285,drawLib,conf,telemetry,status,alarms,battery,1,gpsStatuses,utils,customSensors) + -- left panel + leftPanel.drawPane(0,drawLib,conf,telemetry,status,alarms,battery,0,gpsStatuses,utils,customSensors) + end + end + drawLib.drawStatusBar(3,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + drawExtendedStatusBar(drawLib,conf,telemetry,status,battery,alarms,frame,utils,gpsStatuses) + utils.drawTopBar() + drawLib.drawFailsafe(telemetry,utils) + drawLib.drawArmStatus(status,telemetry,utils) +end + +return {draw=draw} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_1.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_1.lua new file mode 100644 index 00000000..28436eeb --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_1.lua @@ -0,0 +1,274 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + +-- x:300 y:135 inside HUD + + + + + + + + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,16) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(90, 25, "Range("..unitLabel..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(90, 37, string.format("%.1f",rng*0.01*unitScale), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,12) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(90, 25, "AltAsl("..unitLabel..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + local stralt = string.format("%d",alt*unitScale) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(90, 37, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,0x0000) + drawLib.drawHomeIcon(90 - 70, 70,utils) + lcd.drawText(90, 70, "Dist("..unitLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(90, 117, "Travel("..unitLongLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + -- VALUES + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- home distance + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,15) + if status.showMinMaxValues == true then + flags = 0 + end + local strdist = string.format("%d",dist*unitScale) + --lcd.setColor(CUSTOM_COLOR,0xFE60) --yellow + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(90, 82, strdist, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + -- total distance + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(90, 129, telemetry.totalDist*unitLongScale*100, PREC2+MIDSIZE+RIGHT+CUSTOM_COLOR) + + if status.showMinMaxValues == true then + drawLib.drawVArrow(4, 37 + 4,true,false,utils) + drawLib.drawVArrow(4, 82 + 4 ,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_2.lua new file mode 100644 index 00000000..621d2cd6 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_2.lua @@ -0,0 +1,280 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + + + + + + + + + + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,16) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(73, 21+8, "Rng("..unitLabel..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(73, 33+8, string.format("%.1f",rng*0.01*unitScale), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,12) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(73, 21+8, "AltAsl("..unitLabel..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + local stralt = string.format("%d",alt*unitScale) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(73, 33+8, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,0x0000) + drawLib.drawHomeIcon(155 - 68, 29,utils) + lcd.drawText(155, 29, "Dist("..unitLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(73, 95, "Spd("..conf.horSpeedLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(155, 95, "Travel("..unitLongLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + -- VALUES + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- home distance + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,15) + if status.showMinMaxValues == true then + flags = 0 + end + local strdist = string.format("%d",dist*unitScale) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + --lcd.setColor(CUSTOM_COLOR,0xFE60) --yellow + lcd.drawText(155, 41, strdist, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + -- total distance + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(155, 107, telemetry.totalDist*unitLongScale*100, PREC2+MIDSIZE+RIGHT+CUSTOM_COLOR) + -- hspeed + local speed = utils.getMaxValue(telemetry.hSpeed,14) + + lcd.drawNumber(73,107,speed * conf.horSpeedMultiplier,MIDSIZE+RIGHT+PREC1+CUSTOM_COLOR) + + if status.showMinMaxValues == true then + drawLib.drawVArrow(4, 33+8 + 4,true,false,utils) + drawLib.drawVArrow(155-70, 41 + 4 ,true,false,utils) + drawLib.drawVArrow(4,107+4,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_m2f_1.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_m2f_1.lua new file mode 100644 index 00000000..7c980d54 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_m2f_1.lua @@ -0,0 +1,319 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + +-- x:300 y:135 inside HUD + + + + + + + + + + + + + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils)--,getMaxValue,getBitmap,drawBlinkBitmap,lcdBacklightOn) + --lcd.setColor(CUSTOM_COLOR,lcd.RGB(0,33,56)) + --lcd.drawFilledRectangle(x + 3,21,93,203,CUSTOM_COLOR) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,16) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(25, 21, "Range("..unitLabel..")", SMLSIZE+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(88, 33, string.format("%.1f",rng*0.01*unitScale), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,12) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(25, 21, "AltAsl("..unitLabel..")", SMLSIZE+CUSTOM_COLOR) + local stralt = string.format("%d",alt*unitScale) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(88, 33, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(88, 102, "Dist("..unitLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + --lcd.drawText(88, 138, "Dist("..unitLongLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(88, 154, "WPN", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(165, 154, "WPD("..unitLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + -- drawn on HUD bottom left + lcd.drawText(88, 63, "ASpd("..conf.horSpeedLabel..")", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(315, 154, "Thr(%)", SMLSIZE+CUSTOM_COLOR+RIGHT) + -- VALUES + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- home distance + drawLib.drawHomeIcon(2, 102 + 18,utils) + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,15) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) --yellow + local strdist = string.format("%d",dist*unitScale) + lcd.setColor(CUSTOM_COLOR,0xFE60) + lcd.drawText(88, 113, strdist, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + -- total distance + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(88, 138, unitLongLabel, SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawNumber(69, 134, telemetry.totalDist*unitLongScale*100, 0+RIGHT+CUSTOM_COLOR+PREC2) + -- wp number + lcd.drawNumber(68, 164, telemetry.wpNumber,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- wp distance + lcd.drawNumber(165, 164, telemetry.wpDistance * unitScale,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- airspeed + lcd.drawNumber(88,74,telemetry.airspeed * conf.horSpeedMultiplier,MIDSIZE+RIGHT+PREC1+CUSTOM_COLOR) + -- throttle % + lcd.drawNumber(315,164,telemetry.throttle,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- LINES + lcd.setColor(CUSTOM_COLOR,0xFFFF) --yellow + -- wp bearing + drawLib.drawRArrow(80,180,9,telemetry.wpBearing*45,CUSTOM_COLOR) + -- + if status.showMinMaxValues == true then + drawLib.drawVArrow(3, 33+4,true,false,utils) + drawLib.drawVArrow(3, 113+4 ,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) + -- RC CHANNELS + --[[ + if conf.enableRCChannels == true then + for i=1,#telemetry.rcchannels do + setTelemetryValue(Thr_ID, Thr_SUBID, Thr_INSTANCE + i, telemetry.rcchannels[i], 13 , Thr_PRECISION , "RC"..i) + end + end + --]] + -- VFR + setTelemetryValue(0x0AF, 0, 0, telemetry.airspeed*0.1, 4 , 0 , "ASpd") + setTelemetryValue(0x010F, 0, 1, telemetry.baroAlt*10, 9 , 1 , "BAlt") + setTelemetryValue(0x050F, 0, 0, telemetry.throttle, 13 , 0 , "Thr") + + -- WP + setTelemetryValue(0x050F, 0, 10, telemetry.wpNumber, 0 , 0 , "WPN") + setTelemetryValue(0x082F, 0, 10, telemetry.wpDistance, 9 , 0 , "WPD") + + -- crosstrack error and wp bearing not exposed as OpenTX variables by default + --[[ + setTelemetryValue(WPX_ID, WPX_SUBID, WPX_INSTANCE, telemetry.wpXTError, 9 , WPX_PRECISION , WPX_NAME) + setTelemetryValue(WPB_ID, WPB_SUBID, WPB_INSTANCE, telemetry.wpBearing, 20 , WPB_PRECISION , WPB_NAME) + --]]end + +return {drawPane=drawPane,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_m2f_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_m2f_2.lua new file mode 100644 index 00000000..36c6b874 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/left_m2f_2.lua @@ -0,0 +1,312 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + +--------------------------------- +-- LAYOUT +--------------------------------- + + + + + + + + + + + + + + + + + + +local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils)--,getMaxValue,getBitmap,drawBlinkBitmap,lcdBacklightOn) + if conf.rangeMax > 0 then + flags = 0 + local rng = telemetry.range + if rng > conf.rangeMax then + flags = BLINK+INVERS + end + rng = utils.getMaxValue(rng,16) + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(8, 20, "Range("..unitLabel..")", SMLSIZE+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(68, 31, string.format("%.1f",rng*0.01*unitScale), MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + else + flags = BLINK + -- always display gps altitude even without 3d lock + local alt = telemetry.gpsAlt/10 + if telemetry.gpsStatus > 2 then + flags = 0 + -- update max only with 3d or better lock + alt = utils.getMaxValue(alt,12) + end + if status.showMinMaxValues == true then + flags = 0 + end + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(8, 20, "AltAsl("..unitLabel..")", SMLSIZE+CUSTOM_COLOR) + local stralt = string.format("%d",alt*unitScale) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(68, 31, stralt, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + end + -- LABELS + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(153, 20, "Dist("..unitLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(69, 122, "AS("..conf.horSpeedLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(69, 76, "WPN", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(153, 76, "WPD("..unitLabel..")", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(153, 122, "THR(%)", SMLSIZE+RIGHT+CUSTOM_COLOR) + -- VALUES + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- home distance + drawLib.drawHomeIcon(69 + 15, 20 + 2,utils) + flags = 0 + if telemetry.homeAngle == -1 then + flags = BLINK + end + local dist = utils.getMaxValue(telemetry.homeDist,15) + if status.showMinMaxValues == true then + flags = 0 + end + local strdist = string.format("%d",dist*unitScale) + --lcd.setColor(CUSTOM_COLOR,0xFE60) + lcd.drawText(153, 31, strdist, MIDSIZE+flags+RIGHT+CUSTOM_COLOR) + -- total distance + strdist = string.format("%.02f%s", telemetry.totalDist*unitLongScale,unitLongLabel) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(152, 54, strdist, SMLSIZE+RIGHT+CUSTOM_COLOR) + -- airspeed + lcd.drawNumber(68,134,telemetry.airspeed * conf.horSpeedMultiplier,MIDSIZE+RIGHT+PREC1+CUSTOM_COLOR) + -- wp number + lcd.drawNumber(57, 87, telemetry.wpNumber,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- wp distance + lcd.drawNumber(153, 87, telemetry.wpDistance * unitScale,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- throttle % + lcd.drawNumber(153,134,telemetry.throttle,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- LINES + lcd.setColor(CUSTOM_COLOR,0xFFFF) --yellow + -- wp bearing + drawLib.drawRArrow(67,100,10,telemetry.wpBearing*45,CUSTOM_COLOR) + -- + if status.showMinMaxValues == true then + drawLib.drawVArrow(68-70, 31+4,true,false,utils) + drawLib.drawVArrow(153-78, 31+4 ,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) + -- RC CHANNELS + --[[ + if conf.enableRCChannels == true then + for i=1,#telemetry.rcchannels do + setTelemetryValue(Thr_ID, Thr_SUBID, Thr_INSTANCE + i, telemetry.rcchannels[i], 13 , Thr_PRECISION , "RC"..i) + end + end + --]] + -- VFR + setTelemetryValue(0x0AF, 0, 0, telemetry.airspeed*0.1, 4 , 0 , "ASpd") + setTelemetryValue(0x010F, 0, 1, telemetry.baroAlt*10, 9 , 1 , "BAlt") + setTelemetryValue(0x050F, 0, 0, telemetry.throttle, 13 , 0 , "Thr") + + -- WP + setTelemetryValue(0x050F, 0, 10, telemetry.wpNumber, 0 , 0 , "WPN") + setTelemetryValue(0x082F, 0, 10, telemetry.wpDistance, 9 , 0 , "WPD") + + -- crosstrack error and wp bearing not exposed as OpenTX variables by default + --[[ + setTelemetryValue(WPX_ID, WPX_SUBID, WPX_INSTANCE, telemetry.wpXTError, 9 , WPX_PRECISION , WPX_NAME) + setTelemetryValue(WPB_ID, WPB_SUBID, WPB_INSTANCE, telemetry.wpBearing, 20 , WPB_PRECISION , WPB_NAME) + --]]end + +return {drawPane=drawPane,background=background} diff --git a/HORUS/SOURCES/plane.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/plane.lua similarity index 53% rename from HORUS/SOURCES/plane.lua rename to HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/plane.lua index b00cea99..0cb037b2 100644 --- a/HORUS/SOURCES/plane.lua +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/plane.lua @@ -1,3 +1,28 @@ +--[[ +enum FlightMode { + MANUAL = 0, + CIRCLE = 1, + STABILIZE = 2, + TRAINING = 3, + ACRO = 4, + FLY_BY_WIRE_A = 5, + FLY_BY_WIRE_B = 6, + CRUISE = 7, + AUTOTUNE = 8, + AUTO = 10, + RTL = 11, + LOITER = 12, + AVOID_ADSB = 14, + GUIDED = 15, + INITIALISING = 16, + QSTABILIZE = 17, + QHOVER = 18, + QLOITER = 19, + QLAND = 20, + QRTL = 21, + QAUTOTUNE = 22 +}; +--]] local flightModes = {} -- plane flight modes flightModes[0]="" @@ -23,5 +48,7 @@ flightModes[19]="QHover" flightModes[20]="QLoiter" flightModes[21]="Qland" flightModes[22]="QRTL" +flightModes[23]="QAutotune" -- return {flightModes=flightModes} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/plane_px4.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/plane_px4.lua new file mode 100644 index 00000000..d143e236 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/plane_px4.lua @@ -0,0 +1,29 @@ +local flightModes = {} +-- plane flight modes +flightModes[0]="" +flightModes[1]="Manual" +flightModes[2]="AltCtl" --px4 specific +flightModes[3]="PosCtl" --px4 specific +flightModes[4]="Ready" --px4 specific +flightModes[5]="Takeoff" --px4 specific +flightModes[6]="Loiter" +flightModes[7]="Mission" --px4 specific +flightModes[8]="RTL" +flightModes[9]="Land" +flightModes[10]="RTGS" --px4 specific +flightModes[11]="Follow" +flightModes[12]="PrecLand" --px4 specific +flightModes[13]="" +flightModes[14]="Acro" +flightModes[15]="OffBoard" --px4 specific +flightModes[16]="Stabilize" +flightModes[17]="RAttitude" --px4 specific +flightModes[18]="Simple" --px4 specific +flightModes[19]="" +flightModes[20]="" +flightModes[21]="" +flightModes[22]="" +flightModes[23]="" +-- +return {flightModes=flightModes} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/reset.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/reset.lua new file mode 100644 index 00000000..f8d2ad8b --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/reset.lua @@ -0,0 +1,336 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + + +local function resetTelemetry(status,telemetry,battery,alarms,utils) + -- sport queue max pops to prevent looping forever + local i = 0 + -- empty sport queue + local a,b,c,d = sportTelemetryPop() + while a ~= null and i < 50 do + a,b,c,d = sportTelemetryPop() + i = i + 1 + end + ----------------------------- + -- TELEMETRY + ----------------------------- + -- AP STATUS + telemetry.flightMode = 0 + telemetry.simpleMode = 0 + telemetry.landComplete = 0 + telemetry.statusArmed = 0 + telemetry.battFailsafe = 0 + telemetry.ekfFailsafe = 0 + telemetry.imuTemp = 0 + -- GPS + telemetry.numSats = 0 + telemetry.gpsStatus = 0 + telemetry.gpsHdopC = 100 + telemetry.gpsAlt = 0 + -- BATT 1 + telemetry.batt1volt = 0 + telemetry.batt1current = 0 + telemetry.batt1mah = 0 + -- BATT 2 + telemetry.batt2volt = 0 + telemetry.batt2current = 0 + telemetry.batt2mah = 0 + -- HOME + telemetry.homeDist = 0 + telemetry.homeAlt = 0 + telemetry.homeAngle = -1 + -- VELANDYAW + telemetry.vSpeed = 0 + telemetry.hSpeed = 0 + telemetry.yaw = 0 + -- ROLLPITCH + telemetry.roll = 0 + telemetry.pitch = 0 + telemetry.range = 0 + -- PARAMS + telemetry.frameType = -1 + telemetry.batt1Capacity = 0 + telemetry.batt2Capacity = 0 + -- GPS + telemetry.lat = nil + telemetry.lon = nil + telemetry.homeLat = nil + telemetry.homeLon = nil + -- WP + telemetry.wpNumber = 0 + telemetry.wpDistance = 0 + telemetry.wpXTError = 0 + telemetry.wpBearing = 0 + telemetry.wpCommands = 0 + -- RC channels + telemetry.rcchannels = {} + -- VFR + telemetry.airspeed = 0 + telemetry.throttle = 0 + telemetry.baroAlt = 0 + -- + telemetry.totalDist = 0 + ----------------------------- + -- SCRIPT STATUS + ----------------------------- + -- FLVSS 1 + status.cell1min = 0 + status.cell1sum = 0 + -- FLVSS 2 + status.cell2min = 0 + status.cell2sum = 0 + -- FC 1 + status.cell1sumFC = 0 + status.cell1maxFC = 0 + -- FC 2 + status.cell2sumFC = 0 + status.cell2maxFC = 0 + -- BATT + status.cell1count = 0 + status.cell2count = 0 + + status.battsource = "na" + -- BATT 1 + status.batt1sources = { + vs = false, + fc = false + } + -- BATT 2 + status.batt2sources = { + vs = false, + fc = false + } + -- TELEMETRY + status.noTelemetryData = 1 + -- MESSAGES + status.msgBuffer = "" + status.lastMsgValue = 0 + status.lastMsgTime = 0 + -- FLIGHT TIME + status.lastTimerStart = 0 + status.timerRunning = 0 + status.flightTime = 0 + -- EVENTS + status.lastStatusArmed = 0 + status.lastGpsStatus = 0 + status.lastFlightMode = 0 + status.lastSimpleMode = 0 + -- battery levels + status.batLevel = 99 + status.battLevel1 = false + status.battLevel2 = false + status.lastBattLevel = 14 + -- messages + status.lastMessage = nil + status.lastMessageSeverity = 0 + status.lastMessageCount = 1 + status.messageCount = 0 + ------------------------- + -- BATTERY ARRAY + ------------------------- + battery = {0,0,0,0,0,0,0,0,0,0,0,0} + -- clear message queue + utils.clearTable(status.messages) + --- + status.messages = {} + -- reset alarms + alarms[1] = { false, 0 , false, 0, 0, false, 0} --MIN_ALT + alarms[2] = { false, 0 , true, 1 , 0, false, 0 } --MAX_ALT + alarms[3] = { false, 0 , true, 1 , 0, false, 0 } --15 + alarms[4] = { false, 0 , true, 1 , 0, false, 0 } --FS_EKF + alarms[5] = { false, 0 , true, 1 , 0, false, 0 } --FS_BAT + alarms[6] = { false, 0 , true, 2, 0, false, 0 } --FLIGTH_TIME + alarms[7] = { false, 0 , false, 3, 4, false, 0 } --BATT L1 + alarms[8] = { false, 0 , false, 4, 4, false, 0 } --BATT L2 + alarms[9] = { false, 0 , false, 1 , 0, false, 0 } --MAX_HDOP + -- stop and reset timer + model.setTimer(2,{mode=0}) + model.setTimer(2,{value=0}) +end + +return {resetTelemetry=resetTelemetry} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_1.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_1.lua new file mode 100644 index 00000000..c1ea4b74 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_1.lua @@ -0,0 +1,310 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + + + + + + + + + + + + +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +--[[ +BATT_CELL 1 +BATT_VOLT 4 +BATT_CURR 7 +BATT_MAH 10 +BATT_CAP 13 + +BATT_IDALL 0 +BATT_ID1 1 +BATT_ID2 2 +--]]local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local perc = 0 + if (battery[13+battId] > 0) then + perc = (1 - (battery[10+battId]/battery[13+battId]))*100 + if perc > 99 then + perc = 99 + elseif perc < 0 then + perc = 0 + end + end + -- battery min cell + local flags = 0 + -- + lcd.setColor(CUSTOM_COLOR,0xFFFF) -- white + if status.showMinMaxValues == false then + if status.battLevel2 == false and alarms[8][2] > 0 then + utils.drawBlinkBitmap("cell_red_blink_86x30",x+7,20) + utils.lcdBacklightOn() + elseif status.battLevel2 == true then + lcd.drawBitmap(utils.getBitmap("cell_red_86x30"),x+7,20) + elseif status.battLevel1 == false and alarms[7][2] > 0 then + --lcd.setColor(CUSTOM_COLOR,0x0000) -- black + utils.drawBlinkBitmap("cell_orange_blink_86x30",x+7,20) + utils.lcdBacklightOn() + elseif status.battLevel1 == true then + lcd.drawBitmap(utils.getBitmap("cell_orange_86x30"),x+7,20) + lcd.setColor(CUSTOM_COLOR,0x0000) -- black + end + end + flags = CUSTOM_COLOR + --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) + if battery[1+battId] * 0.01 < 10 then + lcd.drawNumber(x+75+2, 16, battery[1+battId] + 0.5, PREC2+DBLSIZE+RIGHT+flags) + else + lcd.drawNumber(x+75+2, 16, (battery[1+battId] + 0.5)*0.1, PREC1+DBLSIZE+RIGHT+flags) + end + + local lx = x+76 + lcd.drawText(lx, 32, "V", flags) + lcd.drawText(lx, 18, status.battsource, flags) + + lcd.setColor(CUSTOM_COLOR,0xFFFF) -- white + -- battery voltage + drawLib.drawNumberWithDim(x+75,48,x+75, 58, battery[4+battId],"V",RIGHT+MIDSIZE+PREC1+CUSTOM_COLOR,SMLSIZE+CUSTOM_COLOR) + -- battery current + local lowAmp = battery[7+battId]*0.1 < 10 + drawLib.drawNumberWithDim(x+75,68,x+76,83,battery[7+battId]*(lowAmp and 1 or 0.1),"A",DBLSIZE+RIGHT+CUSTOM_COLOR+(lowAmp and PREC1 or 0),0+CUSTOM_COLOR) + -- display capacity bar % + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255, 255)) + lcd.drawFilledRectangle(x+10, 105,80,21,CUSTOM_COLOR) + if perc > 50 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) + elseif perc <= 50 and perc > 25 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) + end + lcd.drawGauge(x+10, 105,80,21,perc,100,CUSTOM_COLOR) + -- battery percentage + lcd.setColor(CUSTOM_COLOR,0x0000) -- black + + local strperc = string.format("%02d%%",perc) + lcd.drawText(x+35, 101, strperc, MIDSIZE+CUSTOM_COLOR) + + -- battery mah + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local strmah = string.format("%.02f/%.01f",battery[10+battId]/1000,battery[13+battId]/1000) + --lcd.drawText(x+90, 138+2, "Ah", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(x+90, 138, strmah, 0+RIGHT+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(x+90,126,battId == 0 and "B1+B2(Ah)" or (battId == 1 and "B1(Ah)" or "B2(Ah)"),SMLSIZE+RIGHT+CUSTOM_COLOR) + if battId < 2 then + -- labels + lcd.drawText(x+12, 154, "Eff(mAh)", SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawText(x+95, 154, "Power(W)", SMLSIZE+CUSTOM_COLOR+RIGHT) + -- data + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local speed = utils.getMaxValue(telemetry.hSpeed,14) + -- efficiency for indipendent batteries makes sense only for battery 1 + local eff = speed > 2 and (conf.battConf == 3 and battery[7+1] or battery[7])*1000/(speed*conf.horSpeedMultiplier) or 0 + eff = ( conf.battConf == 3 and battId == 2) and 0 or eff + lcd.drawNumber(x+12,164,eff,(eff > 99999 and 0 or MIDSIZE)+RIGHT+CUSTOM_COLOR) + -- power + local power = battery[4+battId]*battery[7+battId]*0.01 + lcd.drawNumber(x+95,164,power,MIDSIZE+RIGHT+CUSTOM_COLOR) + --lcd.drawText(x+95,164,string.format("%dW",power),MIDSIZE+CUSTOM_COLOR) + end + if status.showMinMaxValues == true then + drawLib.drawVArrow(x+75+11, 16 + 8,false,true,utils) + drawLib.drawVArrow(x+75+11,48 + 3, false,true,utils) + drawLib.drawVArrow(x+75+11,68 + 10,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_2.lua new file mode 100644 index 00000000..de909f93 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_2.lua @@ -0,0 +1,310 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + + + + + + + + + + + +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +--[[ +BATT_CELL 1 +BATT_VOLT 4 +BATT_CURR 7 +BATT_MAH 10 +BATT_CAP 13 + +BATT_IDALL 0 +BATT_ID1 1 +BATT_ID2 2 +--]]local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local perc = 0 + if (battery[13+battId] > 0) then + perc = (1 - (battery[10+battId]/battery[13+battId]))*100 + if perc > 99 then + perc = 99 + elseif perc < 0 then + perc = 0 + end + end + -- battery min cell + local flags = 0 + -- + lcd.setColor(CUSTOM_COLOR,0xFFFF) -- white + if status.showMinMaxValues == false then + if status.battLevel2 == false and alarms[8][2] > 0 then + utils.drawBlinkBitmap("cell_red",x+41 - 2,13 + 7) + utils.lcdBacklightOn() + elseif status.battLevel2 == true then + lcd.drawBitmap(utils.getBitmap("cell_red"),x+41 - 2,13 + 7) + elseif status.battLevel1 == false and alarms[7][2] > 0 then + --lcd.setColor(CUSTOM_COLOR,0x0000) -- black + utils.drawBlinkBitmap("cell_orange_blink",x+41 - 2,13 + 7) + utils.lcdBacklightOn() + elseif status.battLevel1 == true then + lcd.drawBitmap(utils.getBitmap("cell_orange"),x+41 - 2,13 + 7) + lcd.setColor(CUSTOM_COLOR,0x0000) -- black + end + end + flags = CUSTOM_COLOR + --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) + if battery[1+battId] * 0.01 < 10 then + lcd.drawNumber(x+41+2, 13, battery[1+battId] + 0.5, PREC2+XXLSIZE+flags) + else + lcd.drawNumber(x+41+2, 13, (battery[1+battId] + 0.5)*0.1, PREC1+XXLSIZE+flags) + end + + --lcd.drawNumber(x+41+2, 13, battery[1+battId] + 0.5, XXLSIZE+flags) + local lx = x+175 + lcd.drawText(lx, 23, "V", flags) + lcd.drawText(lx, 58, status.battsource, flags) + + lcd.setColor(CUSTOM_COLOR,0xFFFF) -- white + -- battery voltage + drawLib.drawNumberWithDim(x+105,79,x+103, 79, battery[4+battId],"V",DBLSIZE+PREC1+RIGHT+CUSTOM_COLOR,SMLSIZE+CUSTOM_COLOR) + -- battery current + drawLib.drawNumberWithDim(x+178,79,x+176,79,battery[7+battId]*(battery[7+battId] >= 100 and 0.1 or 1),"A",DBLSIZE+RIGHT+CUSTOM_COLOR+(battery[7+battId] >= 100 and 0 or PREC1),SMLSIZE+CUSTOM_COLOR) + -- display capacity bar % + if perc > 50 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) + elseif perc <= 50 and perc > 25 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) + end + lcd.drawBitmap(utils.getBitmap("gauge_bg"),x+43-2,117-2) + lcd.drawGauge(x+43, 117,147,23,perc,100,CUSTOM_COLOR) + -- battery percentage + lcd.setColor(CUSTOM_COLOR,0x0000) -- black + + local strperc = string.format("%02d%%",perc) + lcd.drawText(x+98, 114, strperc, MIDSIZE+CUSTOM_COLOR) + + -- battery mah + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local strmah = string.format("%.02f/%.01f",battery[10+battId]/1000,battery[13+battId]/1000) + lcd.drawText(x+183, 140+6, "Ah", RIGHT+CUSTOM_COLOR) + lcd.drawText(x+183 - 22, 140, strmah, MIDSIZE+RIGHT+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,0x5AEB) + lcd.drawText(x+190,124,battId == 0 and "B1+B2" or (battId == 1 and "B1" or "B2"),SMLSIZE+CUSTOM_COLOR+RIGHT) + + if battId < 2 then + -- RIGHT labels + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(478, 165, "Eff(mAh)", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(395, 165, "Power(W)", SMLSIZE+CUSTOM_COLOR+RIGHT) + --data + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- efficiency for indipendent batteries makes sense only for battery 1 + local speed = utils.getMaxValue(telemetry.hSpeed,14) + local eff = speed > 2 and (conf.battConf == 3 and battery[7+1] or battery[7])*1000/(speed*conf.horSpeedMultiplier) or 0 + eff = ( conf.battConf == 3 and battId == 2) and 0 or eff + lcd.drawNumber(478,178,eff,MIDSIZE+RIGHT+CUSTOM_COLOR) + -- power + local power = battery[4]*(conf.battConf == 3 and battery[7+1] or battery[7])*0.01 + lcd.drawNumber(395,178,power,MIDSIZE+RIGHT+CUSTOM_COLOR) + end + + if status.showMinMaxValues == true then + drawLib.drawVArrow(x+41+140, 13 + 27,false,true,utils) + drawLib.drawVArrow(x+105+4,79 + 10, false,true,utils) + drawLib.drawVArrow(x+178+3,79 + 10,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_custom_2.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_custom_2.lua new file mode 100644 index 00000000..c8d8a3ca --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/right_custom_2.lua @@ -0,0 +1,372 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + + + + + + + + + + + + + + + + +-------------------------- +-- CUSTOM SENSORS SUPPORT +-------------------------- + + +local customSensorXY = { + { 110, 90, 110, 101}, + { 196, 90, 196, 101}, + { 110, 123, 110, 132}, + { 196, 123, 196, 132}, + { 110, 163, 110, 173}, + { 196, 163, 196, 173}, +} + +local function drawCustomSensors(x,customSensors,utils,status) + if customSensors == nil then + return + end + + local label,data,prec,mult,flags,sensorConfig + for i=1,6 + do + if customSensors.sensors[i] ~= nil then + sensorConfig = customSensors.sensors[i] + + if sensorConfig[4] == "" then + label = string.format("%s",sensorConfig[1]) + else + label = string.format("%s(%s)",sensorConfig[1],sensorConfig[4]) + end + -- draw sensor label + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(x+customSensorXY[i][1], customSensorXY[i][2],label, SMLSIZE+RIGHT+CUSTOM_COLOR) + + mult = sensorConfig[3] == 0 and 1 or ( sensorConfig[3] == 1 and 10 or 100 ) + prec = mult == 1 and 0 or (mult == 10 and 32 or 48) + + local sensorName = sensorConfig[2]..(status.showMinMaxValues == true and sensorConfig[6] or "") + local sensorValue = getValue(sensorName) + local value = (sensorValue+(mult == 100 and 0.005 or 0))*mult*sensorConfig[5] + + -- default font size + flags = (i<=2 and MIDSIZE or (sensorConfig[7] == 1 and MIDSIZE or DBLSIZE)) + + -- for sensor 3,4,5,6 reduce font if necessary + if i>2 and math.abs(value)*mult > 99999 then + flags = MIDSIZE + end + + local color = 0xFFFF + local sign = sensorConfig[6] == "+" and 1 or -1 + + -- max tracking, high values are critical + if math.abs(value) ~= 0 and status.showMinMaxValues == false then + color = ( sensorValue*sign > sensorConfig[9]*sign and 0xF800 or (sensorValue*sign > sensorConfig[8]*sign and 0xFE60 or 0xFFFF)) + end + + lcd.setColor(CUSTOM_COLOR,color) + + local voffset = (i>2 and flags==MIDSIZE) and 5 or 0 + -- if a lookup table exists use it! + if customSensors.lookups[i] ~= nil and customSensors.lookups[i][value] ~= nil then + lcd.drawText(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, customSensors.lookups[i][value] or value, flags+RIGHT+CUSTOM_COLOR) + else + lcd.drawNumber(x+customSensorXY[i][3], customSensorXY[i][4]+voffset, value, flags+RIGHT+prec+CUSTOM_COLOR) + end + end + end +end + +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +--[[ +BATT_CELL 1 +BATT_VOLT 4 +BATT_CURR 7 +BATT_MAH 10 +BATT_CAP 13 + +BATT_IDALL 0 +BATT_ID1 1 +BATT_ID2 2 +--]]local function drawPane(x,drawLib,conf,telemetry,status,alarms,battery,battId,gpsStatuses,utils,customSensors) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local perc = 0 + if (battery[13+battId] > 0) then + perc = (1 - (battery[10+battId]/battery[13+battId]))*100 + if perc > 99 then + perc = 99 + elseif perc < 0 then + perc = 0 + end + end + -- battery min cell + local flags = 0 + -- + lcd.setColor(CUSTOM_COLOR,0xFFFF) -- white + if status.showMinMaxValues == false then + if status.battLevel2 == false and alarms[8][2] > 0 then + utils.drawBlinkBitmap("cell_red_small",x+110+1,16 + 7) + utils.lcdBacklightOn() + elseif status.battLevel2 == true then + lcd.drawBitmap(utils.getBitmap("cell_red_small"),x+110+1,16 + 7) + elseif status.battLevel1 == false and alarms[7][2] > 0 then + --lcd.setColor(CUSTOM_COLOR,0x0000) -- black + utils.drawBlinkBitmap("cell_orange_small_blink",x+110+1,16 + 7) + utils.lcdBacklightOn() + elseif status.battLevel1 == true then + lcd.drawBitmap(utils.getBitmap("cell_orange_small"),x+110+1,16 + 7) + lcd.setColor(CUSTOM_COLOR,0x0000) -- black + end + end + flags = CUSTOM_COLOR + --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) + if battery[1+battId] * 0.01 < 10 then + lcd.drawNumber(x+110+2, 16, battery[1+battId] + 0.5, PREC2+DBLSIZE+flags) + else + lcd.drawNumber(x+110+2, 16, (battery[1+battId] + 0.5)*0.1, PREC1+DBLSIZE+flags) + end + local lx = x+180 + lcd.drawText(lx, 19, "V", SMLSIZE+flags) + lcd.drawText(lx-2, 35, status.battsource, SMLSIZE+flags) + + lcd.setColor(CUSTOM_COLOR,0xFFFF) -- white + -- battery voltage + drawLib.drawNumberWithDim(x+110,48,x+110, 46, battery[4+battId],"V",MIDSIZE+PREC1+RIGHT+CUSTOM_COLOR,SMLSIZE+CUSTOM_COLOR) + -- battery current + drawLib.drawNumberWithDim(x+178,48,x+178,48,battery[7+battId],"A",MIDSIZE+RIGHT+PREC1+CUSTOM_COLOR,SMLSIZE+CUSTOM_COLOR) + -- display capacity bar % + if perc > 50 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) + elseif perc <= 50 and perc > 25 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow + else + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) + end + lcd.drawBitmap(utils.getBitmap("gauge_bg_small"),x+47,29) + lcd.drawGauge(x+47, 29,58,16,perc,100,CUSTOM_COLOR) + -- battery percentage + lcd.setColor(CUSTOM_COLOR,0x0000) -- black + + local strperc = string.format("%02d%%",perc) + lcd.drawText(x+63, 27, strperc, 0+CUSTOM_COLOR) + + -- battery mah + lcd.setColor(CUSTOM_COLOR,0xFFFF) + local strmah = string.format("%.02f/%.01f",battery[10+battId]/1000,battery[13+battId]/1000) + lcd.drawText(x+180, 71+4, "Ah", SMLSIZE+RIGHT+CUSTOM_COLOR) + lcd.drawText(x+180 - 22, 71, strmah, 0+RIGHT+CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,0x5AEB) + --lcd.drawText(475,124,battId == 0 and "B1+B2" or (battId == 1 and "B1" or "B2"),SMLSIZE+CUSTOM_COLOR+RIGHT) + lcd.drawBitmap(utils.getBitmap("battbox_small"),x+42,21) + + -- do no show custom sensors when displaying 2nd battery info + if battId < 2 then + drawCustomSensors(x,customSensors,utils,status) + end + + if status.showMinMaxValues == true then + drawLib.drawVArrow(LCD_W-12, 16 + 8,false,true,utils) + drawLib.drawVArrow(x+110+5,48 + 6, false,true,utils) + drawLib.drawVArrow(x+178+4,48 + 6,true,false,utils) + end +end + +local function background(myWidget,conf,telemetry,status,utils) +end + +return {drawPane=drawPane,background=background} diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/rover.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/rover.lua new file mode 100644 index 00000000..29e08ab0 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/LIB/rover.lua @@ -0,0 +1,47 @@ +--[[ + // Auto Pilot modes + // ---------------- + enum Number { + MANUAL = 0, + ACRO = 1, + STEERING = 3, + HOLD = 4, + LOITER = 5, + FOLLOW = 6, + SIMPLE = 7, + AUTO = 10, + RTL = 11, + SMART_RTL = 12, + GUIDED = 15, + INITIALISING = 16 + }; +--]] +local flightModes = {} + +-- rover modes +flightModes[0]="" +flightModes[1]="Manual" +flightModes[2]="Acro" +flightModes[3]="" +flightModes[4]="Steering" +flightModes[5]="Hold" +flightModes[6]="Loiter" +flightModes[7]="Follow" +flightModes[8]="Simple" +flightModes[9]="" +flightModes[10]="" +flightModes[11]="Auto" +flightModes[12]="RTL" +flightModes[13]="SmartRTL" +flightModes[14]="" +flightModes[15]="" +flightModes[16]="Guided" +flightModes[17]="Initializing" +flightModes[18]="" +flightModes[19]="" +flightModes[20]="" +flightModes[21]="" +flightModes[22]="" +-- +return {flightModes=flightModes} + diff --git a/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/menu.lua b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/menu.lua new file mode 100644 index 00000000..c5956934 --- /dev/null +++ b/HORUS/SOURCES/SRC/SCRIPTS/YAAPU/menu.lua @@ -0,0 +1,623 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + + +------------------------------------- +-- UNITS Scales from Ardupilot OSD code /ardupilot/libraries/AP_OSD/AP_OSD_Screen.cpp +------------------------------------- +--[[ + static const float scale_metric[UNIT_TYPE_LAST] = { + 1.0, //ALTITUDE m + 3.6, //SPEED km/hr + 1.0, //VSPEED m/s + 1.0, //DISTANCE m + 1.0/1000, //DISTANCE_LONG km + 1.0, //TEMPERATURE C + }; + static const float scale_imperial[UNIT_TYPE_LAST] = { + 3.28084, //ALTITUDE ft + 2.23694, //SPEED mph + 3.28084, //VSPEED ft/s + 3.28084, //DISTANCE ft + 1.0/1609.34, //DISTANCE_LONG miles + 1.8, //TEMPERATURE F + }; + static const float scale_SI[UNIT_TYPE_LAST] = { + 1.0, //ALTITUDE m + 1.0, //SPEED m/s + 1.0, //VSPEED m/s + 1.0, //DISTANCE m + 1.0/1000, //DISTANCE_LONG km + 1.0, //TEMPERATURE C + }; + static const float scale_aviation[UNIT_TYPE_LAST] = { + 3.28084, //ALTITUDE Ft + 1.94384, //SPEED Knots + 196.85, //VSPEED ft/min + 3.28084, //DISTANCE ft + 0.000539957, //DISTANCE_LONG Nm + 1.0, //TEMPERATURE C + }; +--]]--[[ + +TYPEVALUE - menu option to select a numeric value +{description, type,name,default value,min,max,uit of measure,precision,increment step, , } +example {"batt alert level 1:", TYPEVALUE, "V1", 375, 0,5000,"V",PREC2,5,"L2",350 }, + +TYPECOMBO - menu option to select a value from a list +{description, type, name, default, label list, value list, , } +example {"center pane layout:", TYPECOMBO, "CPANE", 1, { "hud","radar" }, { 1, 2 },"CPANE",1 }, + +--]]-- +local menuItems = { + {"voice language:", 1, "L1", 1, { "english", "italian", "french", "german" } , {"en","it","fr","de"} }, + {"batt alert level 1:", 0, "V1", 375, 0,5000,"V",PREC2,5 }, + {"batt alert level 2:", 0, "V2", 350, 0,5000,"V",PREC2,5 }, + {"batt[1] capacity override:", 0, "B1", 0, 0,5000,"Ah",PREC2,10 }, + {"batt[2] capacity override:", 0, "B2", 0, 0,5000,"Ah",PREC2,10 }, + {"disable all sounds:", 1, "S1", 1, { "no", "yes" }, { false, true } }, + {"disable msg beep:", 1, "S2", 1, { "no", "info", "all" }, { 1, 2, 3 } }, + {"enable haptic:", 1, "VIBR", 1, { "no", "yes" }, { false, true } }, + {"default voltage source:", 1, "VS", 1, { "auto", "FLVSS", "fc" }, { nil, "vs", "fc" } }, + {"timer alert every:", 0, "T1", 0, 0,600,"min",PREC1,5 }, + {"min altitude alert:", 0, "A1", 0, 0,500,"m",PREC1,5 }, + {"max altitude alert:", 0, "A2", 0, 0,10000,"m",0,1 }, + {"max distance alert:", 0, "D1", 0, 0,100000,"m",0,10 }, + {"repeat alerts every:", 0, "T2", 10, 5,600,"sec",0,5 }, + {"dual battery config:", 1, "BC", 1, { "par", "ser", "other" }, { 1, 2, 3 } }, + {"batt[1] cell count override:", 0, "CC", 0, 0,12," cells",0,1 }, + {"batt[2] cell count override:", 0, "CC2", 0, 0,12," cells",0,1 }, + {"rangefinder max:", 0, "RM", 0, 0,10000," cm",0,10 }, + {"air/groundspeed unit:", 1, "HSPD", 1, { "m/s", "km/h", "mph", "kn" }, { 1, 3.6, 2.23694, 1.94384} }, + {"vertical speed unit:", 1, "VSPD", 1, { "m/s", "ft/s", "ft/min" }, { 1, 3.28084, 196.85} }, + {"widget layout:", 1, "WL", 1, { "default","legacy"}, { 1, 2 } }, + {"center panel:", 1, "CPANE", 1, { "option 1","option 2","option 3","option 4" }, { 1, 2, 3, 4 } }, + {"right panel:", 1, "RPANE", 1, { "option 1","option 2","option 3","option 4" }, { 1, 2, 3, 4 } }, + {"left panel:", 1, "LPANE", 1, { "option 1","option 2","option 3","option 4" }, { 1 , 2, 3, 4 } }, + {"enable px4 flightmodes:", 1, "PX4", 1, { "no", "yes" }, { false, true } }, + {"screen toggle channel:", 0, "STC", 0, 0, 32,nil,0,1 }, +} + +local menu = { + selectedItem = 1, + editSelected = false, + offset = 0, + updated = true, -- if true menu needs a call to updateMenuItems() + wrapOffset = 0, -- changes according to enabled/disabled features and panels +} + +local basePath = "/SCRIPTS/YAAPU/" +local libBasePath = basePath.."LIB/" + +local widgetLayoutFiles = {"layout_1","layout_2"} + +local centerPanelFiles = {} +local rightPanelFiles = {} +local leftPanelFiles = {} + +------------------------------------------ +-- returns item's VALUE,LABEL,IDX +------------------------------------------ +local function getMenuItemByName(items,name) + for idx=1,#items + do + -- items[idx][3] is the menu item's name as it appears in the config file + if items[idx][3] == name then + if items[idx][2] == 1 then + -- return item's value, label, index + return items[idx][6][items[idx][4]], items[idx][5][items[idx][4]], idx + else + -- return item's value, label, index + return items[idx][4], name, idx + end + end + end + return nil +end + +local function updateMenuItems() + if menu.updated == true then + local value, name, idx = getMenuItemByName(menuItems,"WL") + if value == 1 then + --------------------- + -- large hud layout + --------------------- + + --{"center panel layout:", 1, "CPANE", 1, { "def","small","russian","dev" }, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"CPANE") + menuItems[idx][5] = { "default"}; + menuItems[idx][6] = { 1 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"right panel layout:", 1, "RPANE", 1, { "def", "custom", "empty","dev"}, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"RPANE") + menuItems[idx][5] = { "default"}; + menuItems[idx][6] = { 1 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"left panel layout:", 1, "LPANE", 1, { "def","mav2frsky", "empty", "dev" }, { 1 , 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"LPANE") + menuItems[idx][5] = { "default","mav2passthru"}; + menuItems[idx][6] = { 1, 2 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + centerPanelFiles = {"hud_1"} + rightPanelFiles = {"right_1"} + leftPanelFiles = {"left_1", "left_m2f_1"} + + elseif value == 2 then + --------------------- + -- legacy layout + --------------------- + + --{"center panel layout:", 1, "CPANE", 1, { "def","small","russian","dev" }, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"CPANE") + menuItems[idx][5] = { "default", "russian hud", "compact hud "}; + menuItems[idx][6] = { 1, 2, 3 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"right panel layout:", 1, "RPANE", 1, { "def", "custom", "empty","dev"}, { 1, 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"RPANE") + menuItems[idx][5] = { "default", "custom sensors"}; + menuItems[idx][6] = { 1, 2 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + --{"left panel layout:", 1, "LPANE", 1, { "def","mav2frsky", "empty", "dev" }, { 1 , 2, 3, 4 } }, + value, name, idx = getMenuItemByName(menuItems,"LPANE") + menuItems[idx][5] = { "default","mav2passthru" }; + menuItems[idx][6] = { 1, 2 }; + + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + + centerPanelFiles = {"hud_2", "hud_russian_2", "hud_small_2" } + rightPanelFiles = {"right_2", "right_custom_2" } + leftPanelFiles = {"left_2", "left_m2f_2" } + end + + menu.updated = false + collectgarbage() + collectgarbage() + end +end + +local +function getConfigFilename() + local info = model.getInfo() + return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".cfg") +end + +local function applyConfigValues(conf) + if menu.updated == true then + updateMenuItems() + menu.updated = false + end + conf.language = getMenuItemByName(menuItems,"L1") + conf.battAlertLevel1 = getMenuItemByName(menuItems,"V1") + conf.battAlertLevel2 = getMenuItemByName(menuItems,"V2") + conf.battCapOverride1 = getMenuItemByName(menuItems,"B1") + conf.battCapOverride2 = getMenuItemByName(menuItems,"B2") + conf.disableAllSounds = getMenuItemByName(menuItems,"S1") + conf.disableMsgBeep = getMenuItemByName(menuItems,"S2") + conf.enableHaptic = getMenuItemByName(menuItems,"VIBR") + conf.timerAlert = math.floor(getMenuItemByName(menuItems,"T1")*0.1*60) + conf.minAltitudeAlert = getMenuItemByName(menuItems,"A1")*0.1 + conf.maxAltitudeAlert = getMenuItemByName(menuItems,"A2") + conf.maxDistanceAlert = getMenuItemByName(menuItems,"D1") + conf.repeatAlertsPeriod = getMenuItemByName(menuItems,"T2") + conf.battConf = getMenuItemByName(menuItems,"BC") + conf.cell1Count = getMenuItemByName(menuItems,"CC") + conf.cell2Count = getMenuItemByName(menuItems,"CC2") + conf.rangeFinderMax = getMenuItemByName(menuItems,"RM") + conf.horSpeedMultiplier, conf.horSpeedLabel = getMenuItemByName(menuItems,"HSPD") + conf.vertSpeedMultiplier, conf.vertSpeedLabel = getMenuItemByName(menuItems,"VSPD") + -- Layout configuration + conf.widgetLayout = getMenuItemByName(menuItems,"WL") + conf.widgetLayoutFilename = widgetLayoutFiles[conf.widgetLayout] + + conf.centerPanel = getMenuItemByName(menuItems,"CPANE") + conf.centerPanelFilename = centerPanelFiles[conf.centerPanel] + + conf.rightPanel = getMenuItemByName(menuItems,"RPANE") + conf.rightPanelFilename = rightPanelFiles[conf.rightPanel] + + conf.leftPanel = getMenuItemByName(menuItems,"LPANE") + conf.leftPanelFilename = leftPanelFiles[conf.leftPanel] + + conf.enablePX4Modes = getMenuItemByName(menuItems,"PX4") + + local chInfo = getFieldInfo("ch"..getMenuItemByName(menuItems,"STC")) + conf.screenToggleChannelId = (chInfo == nil and -1 or chInfo['id']) + + -- set default voltage source + if getMenuItemByName(menuItems,"VS") ~= nil then + conf.defaultBattSource = getMenuItemByName(menuItems,"VS") + end + + menu.editSelected = false + collectgarbage() + collectgarbage() +end + +local function loadConfig(conf) + local cfg = io.open(getConfigFilename(),"r") + if cfg ~= nil then + local str = io.read(cfg,500) + io.close(cfg) + if string.len(str) > 0 then + for i=1,#menuItems + do + local value = string.match(str, menuItems[i][3]..":([-%d]+)") + collectgarbage() + if value ~= nil then + menuItems[i][4] = tonumber(value) + -- check if the value read from file is compatible with available options + if menuItems[i][2] == 1 and tonumber(value) > #menuItems[i][5] then + --if not force default + menuItems[i][4] = 1 + end + end + end + end + end + -- menu was loaded apply required changes + menu.updated = true + -- when run standalone there's nothing to update :-) + if conf ~= nil then + applyConfigValues(conf) + end +end + +local function saveConfig(conf) + local myConfig = "" + for i=1,#menuItems + do + myConfig = myConfig..menuItems[i][3]..":"..menuItems[i][4] + if i < #menuItems then + myConfig = myConfig.."," + end + end + local cfg = assert(io.open(getConfigFilename(),"w")) + if cfg ~= nil then + io.write(cfg,myConfig) + io.close(cfg) + end + myConfig = nil + collectgarbage() + collectgarbage() + -- when run standalone there's nothing to update :-) + if conf ~= nil then + applyConfigValues(conf) + end + model.setGlobalVariable(8,8,1) +end + +local function drawConfigMenuBars() + lcd.setColor(CUSTOM_COLOR,0x0000) + local itemIdx = string.format("%d/%d",menu.selectedItem,#menuItems) + lcd.drawFilledRectangle(0,0, LCD_W, 20, CUSTOM_COLOR) + lcd.drawRectangle(0, 0, LCD_W, 20, CUSTOM_COLOR) + lcd.drawFilledRectangle(0,LCD_H-20, LCD_W, 20, CUSTOM_COLOR) + lcd.drawRectangle(0, LCD_H-20, LCD_W, 20, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(2,0,"Yaapu Telemetry Widget 1.8.0",CUSTOM_COLOR) + lcd.drawText(2,LCD_H-20+1,getConfigFilename(),CUSTOM_COLOR) + lcd.drawText(LCD_W,LCD_H-20+1,itemIdx,CUSTOM_COLOR+RIGHT) +end + +local function incMenuItem(idx) + if menuItems[idx][2] == 0 then + menuItems[idx][4] = menuItems[idx][4] + menuItems[idx][9] + if menuItems[idx][4] > menuItems[idx][6] then + menuItems[idx][4] = menuItems[idx][6] + end + else + menuItems[idx][4] = menuItems[idx][4] + 1 + if menuItems[idx][4] > #menuItems[idx][5] then + menuItems[idx][4] = 1 + end + end +end + +local function decMenuItem(idx) + if menuItems[idx][2] == 0 then + menuItems[idx][4] = menuItems[idx][4] - menuItems[idx][9] + if menuItems[idx][4] < menuItems[idx][5] then + menuItems[idx][4] = menuItems[idx][5] + end + else + menuItems[idx][4] = menuItems[idx][4] - 1 + if menuItems[idx][4] < 1 then + menuItems[idx][4] = #menuItems[idx][5] + end + end +end + +local function drawItem(idx,flags) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + if menuItems[idx][2] == 0 then + if menuItems[idx][4] == 0 and menuItems[idx][5] >= 0 then + lcd.drawText(300,25 + (idx-menu.offset-1)*20, "---",flags+CUSTOM_COLOR) + else + lcd.drawNumber(300,25 + (idx-menu.offset-1)*20, menuItems[idx][4],flags+menuItems[idx][8]+CUSTOM_COLOR) + if menuItems[idx][7] ~= nil then + lcd.drawText(300 + 50,25 + (idx-menu.offset-1)*20, menuItems[idx][7],flags+CUSTOM_COLOR) + end + end + else + lcd.drawText(300,25 + (idx-menu.offset-1)*20, menuItems[idx][5][menuItems[idx][4]],flags+CUSTOM_COLOR) + end +end + +local function drawConfigMenu(event) + drawConfigMenuBars() + updateMenuItems() + if event == EVT_ENTER_BREAK then + if menu.editSelected == true then + -- confirm modified value + saveConfig() + end + menu.editSelected = not menu.editSelected + menu.updated = true + elseif menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT or event == EVT_PLUS_REPT) then + incMenuItem(menu.selectedItem) + elseif menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT or event == EVT_MINUS_REPT) then + decMenuItem(menu.selectedItem) + elseif not menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT) then + menu.selectedItem = (menu.selectedItem - 1) + if menu.offset >= menu.selectedItem then + menu.offset = menu.offset - 1 + end + elseif not menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT) then + menu.selectedItem = (menu.selectedItem + 1) + if menu.selectedItem - 11 > menu.offset then + menu.offset = menu.offset + 1 + end + end + --wrap + if menu.selectedItem > #menuItems then + menu.selectedItem = 1 + menu.offset = 0 + elseif menu.selectedItem < 1 then + menu.selectedItem = #menuItems + menu.offset = #menuItems - 11 + end + -- + for m=1+menu.offset,math.min(#menuItems,11+menu.offset) do + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(2,25 + (m-menu.offset-1)*20, menuItems[m][1],CUSTOM_COLOR) + if m == menu.selectedItem then + if menu.editSelected then + drawItem(m,INVERS+BLINK) + else + drawItem(m,INVERS) + end + else + drawItem(m,0) + end + end +end + + +-------------------------- +-- RUN +-------------------------- +local function run(event) + lcd.setColor(CUSTOM_COLOR, 0x0AB1) -- hex 0x084c7b -- 073f66 + lcd.clear(CUSTOM_COLOR) + --------------------- + -- CONFIG MENU + --------------------- + drawConfigMenu(event) + return 0 +end + +local function init() + loadConfig() +end + +-------------------------------------------------------------------------------- +-- SCRIPT END +-------------------------------------------------------------------------------- +return {run=run, init=init, loadConfig=loadConfig, compileLayouts=compileLayouts, menuItems=menuItems} diff --git a/HORUS/SOURCES/SRC/WIDGETS/main.lua b/HORUS/SOURCES/SRC/WIDGETS/main.lua new file mode 100644 index 00000000..bad59db7 --- /dev/null +++ b/HORUS/SOURCES/SRC/WIDGETS/main.lua @@ -0,0 +1,1941 @@ +-- +-- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios +-- +-- Copyright (C) 2018-2019. Alessandro Apostoli +-- https://github.com/yaapu +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, see . +-- + +--------------------- +-- MAIN CONFIG +-- 480x272 LCD_W x LCD_H +--------------------- + +--------------------- +-- VERSION +--------------------- +-- load and compile of lua files +--#define LOADSCRIPT +-- uncomment to force compile of all chunks, comment for release +--#define COMPILE +-- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 + +--------------------- +-- FEATURE CONFIG +--------------------- +-- enable splash screen for no telemetry data +--#define SPLASH +-- enable battery percentage based on voltage +--#define BATTPERC_BY_VOLTAGE +-- enable code to draw a compass rose vs a compass ribbon +--#define COMPASS_ROSE +-- enable support for FNV hash based sound files + +--------------------- +-- DEV FEATURE CONFIG +--------------------- +-- enable memory debuging +--#define MEMDEBUG +-- enable dev code +--#define DEV +-- uncomment haversine calculation routine +--#define HAVERSINE +-- enable telemetry logging to file (experimental) +--#define LOGTELEMETRY +-- use radio channels imputs to generate fake telemetry data +--#define TESTMODE +-- enable debug of generated hash or short hash string +--#define HASHDEBUG + +--------------------- +-- DEBUG REFRESH RATES +--------------------- +-- calc and show hud refresh rate +--#define HUDRATE +-- calc and show telemetry process rate +--#define BGTELERATE + +--------------------- +-- SENSOR IDS +--------------------- + + + + + + + + + + + + + + + + +-- Throttle and RC use RPM sensor IDs + +--------------------- +-- BATTERY DEFAULTS +--------------------- +--------------------------------- +-- BACKLIGHT SUPPORT +-- GV is zero based, GV 8 = GV 9 in OpenTX +--------------------------------- +--------------------------------- +-- CONF REFRESH GV +--------------------------------- + +--------------------------------- +-- ALARMS +--------------------------------- +--[[ + ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing + ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing + ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing + ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing +{ + 1 = notified, + 2 = alarm start, + 3 = armed, + 4 = type(0=min,1=max,2=timer,3=batt), + 5 = grace duration + 6 = ready + 7 = last alarm +} +--]]-- +-- +-- + +-- + +---------------------- +-- COMMON LAYOUT +---------------------- +-- enable vertical bars HUD drawing (same as taranis) +--#define HUD_ALGO1 +-- enable optimized hor bars HUD drawing +--#define HUD_ALGO2 +-- enable hor bars HUD drawing + + + + + + +-------------------------------------------------------------------------------- +-- MENU VALUE,COMBO +-------------------------------------------------------------------------------- + +-------------------------- +-- UNIT OF MEASURE +-------------------------- +local unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 +local unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" +local unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 +local unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" + + +----------------------- +-- BATTERY +----------------------- +-- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 +-- + +----------------------- +-- LIBRARY LOADING +----------------------- + +---------------------- +--- COLORS +---------------------- + +--#define COLOR_LABEL 0x7BCF +--#define COLOR_BG 0x0169 +--#define COLOR_BARSEX 0x10A3 + + +--#define COLOR_SENSORS 0x0169 + +----------------------------------- +-- STATE TRANSITION ENGINE SUPPORT +----------------------------------- + + +-------------------------- +-- CLIPPING ALGO DEFINES +-------------------------- + + + + + + + + + +local frameNames = {} +-- copter +frameNames[0] = "GEN" +frameNames[2] = "QUAD" +frameNames[3] = "COAX" +frameNames[4] = "HELI" +frameNames[13] = "HEX" +frameNames[14] = "OCTO" +frameNames[15] = "TRI" +frameNames[29] = "DODE" +-- plane +frameNames[1] = "WING" +frameNames[16] = "FLAP" +frameNames[19] = "VTOL2" +frameNames[20] = "VTOL4" +frameNames[20] = "VTOL4" +frameNames[21] = "VTOLT" +frameNames[22] = "VTOL" +frameNames[23] = "VTOL" +frameNames[24] = "VTOL" +frameNames[25] = "VTOL" +frameNames[28] = "FOIL" +-- rover +frameNames[10] = "ROV" +-- boat +frameNames[11] = "BOAT" + +local currentModel = nil +local frameTypes = {} +local frameType = nil + +--[[ + MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */ + MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */ + MAV_TYPE_QUADROTOR=2, /* Quadrotor | */ + MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */ + MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */ + MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */ + MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */ + MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */ + MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */ + MAV_TYPE_ROCKET=9, /* Rocket | */ + MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */ + MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */ + MAV_TYPE_SUBMARINE=12, /* Submarine | */ + MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */ + MAV_TYPE_OCTOROTOR=14, /* Octorotor | */ + MAV_TYPE_TRICOPTER=15, /* Tricopter | */ + MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */ + MAV_TYPE_KITE=17, /* Kite | */ + MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */ + MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */ + MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */ + MAV_TYPE_VTOL_TILTROTOR=21, /* Tiltrotor VTOL | */ + MAV_TYPE_VTOL_RESERVED2=22, /* VTOL reserved 2 | */ + MAV_TYPE_VTOL_RESERVED3=23, /* VTOL reserved 3 | */ + MAV_TYPE_VTOL_RESERVED4=24, /* VTOL reserved 4 | */ + MAV_TYPE_VTOL_RESERVED5=25, /* VTOL reserved 5 | */ + MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */ + MAV_TYPE_ADSB=27, /* Onboard ADSB peripheral | */ + MAV_TYPE_PARAFOIL=28, /* Steerable, nonrigid airfoil | */ + MAV_TYPE_DODECAROTOR=29, /* Dodecarotor | */ +]] +-- copter +frameTypes[0] = "c" +frameTypes[2] = "c" +frameTypes[3] = "c" +frameTypes[4] = "c" +frameTypes[13] = "c" +frameTypes[14] = "c" +frameTypes[15] = "c" +frameTypes[29] = "c" +-- plane +frameTypes[1] = "p" +frameTypes[16] = "p" +frameTypes[19] = "p" +frameTypes[20] = "p" +frameTypes[21] = "p" +frameTypes[22] = "p" +frameTypes[23] = "p" +frameTypes[24] = "p" +frameTypes[25] = "p" +frameTypes[28] = "p" +-- rover +frameTypes[10] = "r" +-- boat +frameTypes[11] = "b" + + +local soundFileBasePath = "/SOUNDS/yaapu0" +local gpsStatuses = {} + +gpsStatuses[0]="NoGPS" +gpsStatuses[1]="NoLock" +gpsStatuses[2]="2D" +gpsStatuses[3]="3D" +gpsStatuses[4]="DGPS" +gpsStatuses[5]="RTK" +gpsStatuses[6]="RTK" + +--[[ +0 MAV_SEVERITY_EMERGENCY System is unusable. This is a "panic" condition. +1 MAV_SEVERITY_ALERT Action should be taken immediately. Indicates error in non-critical systems. +2 MAV_SEVERITY_CRITICAL Action must be taken immediately. Indicates failure in a primary system. +3 MAV_SEVERITY_ERROR Indicates an error in secondary/redundant systems. +4 MAV_SEVERITY_WARNING Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. +5 MAV_SEVERITY_NOTICE An unusual event has occured, though not an error condition. This should be investigated for the root cause. +6 MAV_SEVERITY_INFO Normal operational messages. Useful for logging. No action is required for these messages. +7 MAV_SEVERITY_DEBUG Useful non-operational messages that can assist in debugging. These should not occur during normal operation. +--]] +local mavSeverity = {} +mavSeverity[0]="EMR" +mavSeverity[1]="ALR" +mavSeverity[2]="CRT" +mavSeverity[3]="ERR" +mavSeverity[4]="WRN" +mavSeverity[5]="NOT" +mavSeverity[6]="INF" +mavSeverity[7]="DBG" + +------------------------------ +-- TELEMETRY DATA +------------------------------ +local telemetry = {} +-- STATUS +telemetry.flightMode = 0 +telemetry.simpleMode = 0 +telemetry.landComplete = 0 +telemetry.statusArmed = 0 +telemetry.battFailsafe = 0 +telemetry.ekfFailsafe = 0 +telemetry.imuTemp = 0 +-- GPS +telemetry.numSats = 0 +telemetry.gpsStatus = 0 +telemetry.gpsHdopC = 100 +telemetry.gpsAlt = 0 +-- BATT 1 +telemetry.batt1volt = 0 +telemetry.batt1current = 0 +telemetry.batt1mah = 0 +-- BATT 2 +telemetry.batt2volt = 0 +telemetry.batt2current = 0 +telemetry.batt2mah = 0 +-- HOME +telemetry.homeDist = 0 +telemetry.homeAlt = 0 +telemetry.homeAngle = -1 +-- VELANDYAW +telemetry.vSpeed = 0 +telemetry.hSpeed = 0 +telemetry.yaw = 0 +-- ROLLPITCH +telemetry.roll = 0 +telemetry.pitch = 0 +telemetry.range = 0 +-- PARAMS +telemetry.frameType = -1 +telemetry.batt1Capacity = 0 +telemetry.batt2Capacity = 0 +-- GPS +telemetry.lat = nil +telemetry.lon = nil +telemetry.homeLat = nil +telemetry.homeLon = nil +-- WP +telemetry.wpNumber = 0 +telemetry.wpDistance = 0 +telemetry.wpXTError = 0 +telemetry.wpBearing = 0 +telemetry.wpCommands = 0 +-- RC channels +telemetry.rcchannels = {} +-- VFR +telemetry.airspeed = 0 +telemetry.throttle = 0 +telemetry.baroAlt = 0 +-- Total distance +telemetry.totalDist = 0 +-------------------------------- +-- STATUS DATA +-------------------------------- +local status = {} +-- FLVSS 1 +status.cell1min = 0 +status.cell1sum = 0 +-- FLVSS 2 +status.cell2min = 0 +status.cell2sum = 0 +-- FC 1 +status.cell1sumFC = 0 +status.cell1maxFC = 0 +-- FC 2 +status.cell2sumFC = 0 +status.cell2maxFC = 0 +-------------------------------- +status.cell1count = 0 +status.cell2count = 0 + +status.battsource = "na" + +status.batt1sources = { + vs = false, + fc = false +} +status.batt2sources = { + vs = false, + fc = false +} +-- SYNTH VSPEED SUPPORT +status.vspd = 0 +status.synthVSpeedTime = 0 +status.prevHomeAlt = 0 +-- FLIGHT TIME +status.lastTimerStart = 0 +status.timerRunning = 0 +status.flightTime = 0 +-- EVENTS +status.lastStatusArmed = 0 +status.lastGpsStatus = 0 +status.lastFlightMode = 0 +status.lastSimpleMode = 0 +-- battery levels +status.batLevel = 99 +status.battLevel1 = false +status.battLevel2 = false +status.lastBattLevel = 14 +-- MESSAGES +status.messages = {} +status.msgBuffer = "" +status.lastMsgValue = 0 +status.lastMsgTime = 0 +status.lastMessage = nil +status.lastMessageSeverity = 0 +status.lastMessageCount = 1 +status.messageCount = 0 +-- LINK STATUS +status.noTelemetryData = 1 +status.hideNoTelemetry = false +status.showDualBattery = false +status.showMinMaxValues = false +-- FLIGHTMODE +status.strFlightMode = nil +status.modelString = nil +--------------------------- +-- BATTERY TABLE +--------------------------- +local battery = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +--------------------------- +-- LIBRARY LOADING +--------------------------- +local basePath = "/SCRIPTS/YAAPU/" +local libBasePath = basePath.."LIB/" + +-- loadable modules +local drawLibFile = "draw" +local menuLibFile = "menu" + +local frame = {} +local drawLib = {} +local utils = {} + +------------------------------- +-- MAIN SCREEN LAYOUT +------------------------------- +local layout = nil +local centerPanel = nil +local rightPanel = nil +local leftPanel = nil + +local customSensors = nil + +local backlightLastTime = 0 +local resetPending = false + +local alarms = { + --{ notified, alarm_start, armed, type(0=min,1=max,2=timer,3=batt), grace, ready, last_alarm} + { false, 0 , false, 0, 0, false, 0}, --MIN_ALT + { false, 0 , false, 1 , 0, false, 0 }, --MAX_ALT + { false, 0 , false, 1 , 0, false, 0 }, --15 + { false, 0 , true, 1 , 0, false, 0 }, --FS_EKF + { false, 0 , true, 1 , 0, false, 0 }, --FS_BAT + { false, 0 , true, 2, 0, false, 0 }, --FLIGTH_TIME + { false, 0 , false, 3, 4, false, 0 }, --BATT L1 + { false, 0 , false, 4, 4, false, 0 }, --BATT L2 + { false, 0 , false, 1 , 0, false, 0 } --MAX_HDOP +} + +local transitions = { + --{ last_value, last_changed, transition_done, delay } + { 0, 0, false, 30 }, +} + +-- SYNTH GPS DIST SUPPORT +local prevDist = 0 +local lastSpeed = 0 +local lastYaw = 0 +local lastUpdateTotDist = 0 + +local paramId,paramValue + +local batLevels = {0,5,10,15,20,25,30,40,50,60,70,80,90} +-- Blinking bitmap support +local bitmaps = {} +local blinktime = getTime() +local blinkon = false + +local minmaxValues = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} + + +-- model and opentx version +local ver, radio, maj, minor, rev = getVersion() +-- widget selected page +local currentPage = 0 +-------------------------------------------------------------------------------- +-- CONFIGURATION MENU +-------------------------------------------------------------------------------- +local conf = { + language = "en", + defaultBattSource = "na", -- auto + battAlertLevel1 = 0, + battAlertLevel2 = 0, + battCapOverride1 = 0, + battCapOverride2 = 0, + disableAllSounds = false, + disableMsgBeep = 1, + enableHaptic = false, + timerAlert = 0, + repeatAlertsPeriod = 10, + minAltitudeAlert = 0, + maxAltitudeAlert = 0, + maxDistanceAlert = 0, + battConf = 1, -- 1=parallel,2=other + cell1Count = 0, + cell2Count = 0, + enableBattPercByVoltage = false, + rangeMax=0, + enableSynthVSpeed=false, + horSpeedMultiplier=1, + vertSpeedMultiplier=1, + horSpeedLabel = "m/s", + vertSpeedLabel = "m/s", + maxHdopAlert = 2, + enablePX4Modes = false, + centerPanel = 1, + rightPanel = 1, + leftPanel = 1, + widgetLayout = 1, + widgetLayoutFilename = nil, + centerPanelFilename = nil, + rightPanelFilename = nil, + leftPanelFilename = nil, + screenToggleChannelId = nil, +} + +------------------------- +-- message hash support +------------------------- +local shortHashes = { + -- 16 bytes hashes + {554623408}, -- "554623408.wav", "Takeoff complete" + {3025044912}, -- "3025044912.wav", "SmartRTL deactiv" + {3956583920}, -- "3956583920.wav", "EKF2 IMU0 is usi" + {1309405592}, -- "1309405592.wav", "EKF3 IMU0 is usi" + {4091124880,true}, -- "4091124880.wav", "Reached command " + {3311875476,true}, -- "3311875476.wav", "Reached waypoint" + {1997782032,true}, -- "1997782032.wav", "Passed waypoint " +} + +local shortHash = nil +local parseShortHash = false +local hashByteIndex = 0 +local hash = 2166136261 + +local loadCycle = 0 + +utils.doLibrary = function(filename) + local f = assert(loadfile(libBasePath..filename..".luac")) + collectgarbage() + collectgarbage() + return f() +end +----------------------------- +-- clears the loaded table +-- and recovers memory +----------------------------- +utils.clearTable = function(t) + if type(t)=="table" then + for i,v in pairs(t) do + if type(v) == "table" then + utils.clearTable(v) + end + t[i] = nil + end + end + t = nil + collectgarbage() + collectgarbage() + maxmem = 0 +end + +local function loadConfig() + -- load menu library + menuLib = dofile(basePath..menuLibFile..".luac") + menuLib.loadConfig(conf) + -- ok configuration loaded + status.battsource = conf.defaultBattSource + -- unload libraries + utils.clearTable(menuLib) + utils.clearTable(layout) + layout = nil + utils.clearTable(centerPanel) + centerPanel = nil + utils.clearTable(rightPanel) + rightPanel = nil + utils.clearTable(leftPanel) + leftPanel = nil + collectgarbage() + collectgarbage() +end + +utils.getBitmap = function(name) + if bitmaps[name] == nil then + bitmaps[name] = Bitmap.open("/SCRIPTS/YAAPU/IMAGES/"..name..".png") + end + return bitmaps[name],Bitmap.getSize(bitmaps[name]) +end + +utils.unloadBitmap = function(name) + if bitmaps[name] ~= nil then + bitmaps[name] = nil + -- force call to luaDestroyBitmap() + collectgarbage() + collectgarbage() + end +end + +utils.lcdBacklightOn = function() + model.setGlobalVariable(8,0,1) + backlightLastTime = getTime()/100 -- seconds +end + +utils.playSound = function(soundFile,skipHaptic) + if conf.enableHaptic and skipHaptic == nil then + playHaptic(15,0) + end + if conf.disableAllSounds then + return + end + utils.lcdBacklightOn() + playFile(soundFileBasePath .."/"..conf.language.."/".. soundFile..".wav") +end + +---------------------------------------------- +-- sound file has same name as flightmode all lowercase with .wav extension +---------------------------------------------- +utils.playSoundByFlightMode = function(flightMode) + if conf.enableHaptic then + playHaptic(15,0) + end + if conf.disableAllSounds then + return + end + if frame.flightModes then + if frame.flightModes[flightMode] ~= nil then + utils.lcdBacklightOn() + -- rover sound files differ because they lack "flight" word + playFile(soundFileBasePath.."/"..conf.language.."/".. string.lower(frame.flightModes[flightMode]) .. ((frameTypes[telemetry.frameType]=="r" or frameTypes[telemetry.frameType]=="b") and "_r.wav" or ".wav")) + end + end +end + + + +local function formatMessage(severity,msg) + local clippedMsg = msg + + if #msg > 50 then + clippedMsg = string.sub(msg,1,50) + msg = nil + collectgarbage() + collectgarbage() + end + + if status.lastMessageCount > 1 then + return string.format("%02d:%s (x%d) %s", status.messageCount, mavSeverity[severity], status.lastMessageCount, clippedMsg) + else + return string.format("%02d:%s %s", status.messageCount, mavSeverity[severity], clippedMsg) + end +end + +utils.pushMessage = function(severity, msg) + if conf.enableHaptic then + playHaptic(15,0) + end + if conf.disableAllSounds == false then + if ( severity < 5 and conf.disableMsgBeep < 3) then + utils.playSound("../err",true) + else + if conf.disableMsgBeep < 2 then + utils.playSound("../inf",true) + end + end + end + + if msg == status.lastMessage then + status.lastMessageCount = status.lastMessageCount + 1 + else + status.lastMessageCount = 1 + status.messageCount = status.messageCount + 1 + end + if status.messages[(status.messageCount-1) % 20] == nil then + status.messages[(status.messageCount-1) % 20] = {} + end + status.messages[(status.messageCount-1) % 20][1] = formatMessage(severity,msg) + status.messages[(status.messageCount-1) % 20][2] = severity + + status.lastMessage = msg + status.lastMessageSeverity = severity + -- Collect Garbage + collectgarbage() + collectgarbage() +end + + +utils.getHomeFromAngleAndDistance = function(telemetry) +--[[ + la1,lo1 coordinates of first point + d be distance (m), + R as radius of Earth (m), + Ad be the angular distance i.e d/R and + θ be the bearing in deg + + la2 = asin(sin la1 * cos Ad + cos la1 * sin Ad * cos θ), and + lo2 = lo1 + atan2(sin θ * sin Ad * cos la1 , cos Ad – sin la1 * sin la2) +--]] if telemetry.lat == nil or telemetry.lon == nil then + return nil,nil + end + + local lat1 = math.rad(telemetry.lat) + local lon1 = math.rad(telemetry.lon) + local Ad = telemetry.homeDist/(6371000) --meters + local lat2 = math.asin( math.sin(lat1) * math.cos(Ad) + math.cos(lat1) * math.sin(Ad) * math.cos( math.rad(telemetry.homeAngle)) ) + local lon2 = lon1 + math.atan2( math.sin( math.rad(telemetry.homeAngle) ) * math.sin(Ad) * math.cos(lat1) , math.cos(Ad) - math.sin(lat1) * math.sin(lat2)) + return math.deg(lat2), math.deg(lon2) +end + + +utils.decToDMS = function(dec,lat) + local D = math.floor(math.abs(dec)) + local M = (math.abs(dec) - D)*60 + local S = (math.abs((math.abs(dec) - D)*60) - M)*60 + return D .. string.format("\64%04.2f", M) .. (lat and (dec >= 0 and "E" or "W") or (dec >= 0 and "N" or "S")) +end + +utils.decToDMSFull = function(dec,lat) + local D = math.floor(math.abs(dec)) + local M = math.floor((math.abs(dec) - D)*60) + local S = (math.abs((math.abs(dec) - D)*60) - M)*60 + return D .. string.format("\64%d'%04.1f", M, S) .. (lat and (dec >= 0 and "E" or "W") or (dec >= 0 and "N" or "S")) +end + +utils.updateTotalDist = function() + if telemetry.armingStatus == 0 then + lastUpdateTotDist = getTime() + return + end + local delta = getTime() - lastUpdateTotDist + local avgSpeed = (telemetry.hSpeed + lastSpeed)/2 + lastUpdateTotDist = getTime() + lastSpeed = telemetry.hSpeed + if avgSpeed * 0.1 > 1 then + telemetry.totalDist = telemetry.totalDist + (avgSpeed * 0.1 * delta * 0.01) --hSpeed dm/s, getTime()/100 secs + end +end + +utils.drawBlinkBitmap = function(bitmap,x,y) + if blinkon == true then + lcd.drawBitmap(utils.getBitmap(bitmap),x,y) + end +end + +local function getSensorsConfigFilename() + local info = model.getInfo() + return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "").."_sensors.lua") +end + +-------------------------- +-- CUSTOM SENSORS SUPPORT +-------------------------- + +utils.loadCustomSensors = function() + local success, sensorScript = pcall(loadScript,getSensorsConfigFilename()) + if success then + if sensorScript == nil then + customSensors = nil + return + end + collectgarbage() + customSensors = sensorScript() + -- handle nil values for warning and critical levels + for i=1,6 + do + if customSensors.sensors[i] ~= nil then + local sign = customSensors.sensors[i][6] == "+" and 1 or -1 + if customSensors.sensors[i][9] == nil then + customSensors.sensors[i][9] = math.huge*sign + end + if customSensors.sensors[i][8] == nil then + customSensors.sensors[i][8] = math.huge*sign + end + end + end + collectgarbage() + collectgarbage() + else + customSensors = nil + end +end + +local function startTimer() + status.lastTimerStart = getTime()/100 + model.setTimer(2,{mode=1}) +end + +local function stopTimer() + model.setTimer(2,{mode=0}) + status.lastTimerStart = 0 +end + + +----------------------------------------------------------------- +-- TELEMETRY +----------------------------------------------------------------- + +local function processTelemetry(DATA_ID,VALUE) + if DATA_ID == 0x5006 then -- ROLLPITCH + -- roll [0,1800] ==> [-180,180] + telemetry.roll = (math.min(bit32.extract(VALUE,0,11),1800) - 900) * 0.2 + -- pitch [0,900] ==> [-90,90] + telemetry.pitch = (math.min(bit32.extract(VALUE,11,10),900) - 450) * 0.2 + -- number encoded on 11 bits: 10 bits for digits + 1 for 10^power + telemetry.range = bit32.extract(VALUE,22,10) * (10^bit32.extract(VALUE,21,1)) -- cm + elseif DATA_ID == 0x5005 then -- VELANDYAW + telemetry.vSpeed = bit32.extract(VALUE,1,7) * (10^bit32.extract(VALUE,0,1)) * (bit32.extract(VALUE,8,1) == 1 and -1 or 1)-- dm/s + telemetry.hSpeed = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) -- dm/s + telemetry.yaw = bit32.extract(VALUE,17,11) * 0.2 + elseif DATA_ID == 0x5001 then -- AP STATUS + telemetry.flightMode = bit32.extract(VALUE,0,5) + telemetry.simpleMode = bit32.extract(VALUE,5,2) + telemetry.landComplete = bit32.extract(VALUE,7,1) + telemetry.statusArmed = bit32.extract(VALUE,8,1) + telemetry.battFailsafe = bit32.extract(VALUE,9,1) + telemetry.ekfFailsafe = bit32.extract(VALUE,10,2) + -- IMU temperature: 0 means temp =< 19°, 63 means temp => 82° + telemetry.imuTemp = bit32.extract(VALUE,26,6) + 19 -- C° + elseif DATA_ID == 0x5002 then -- GPS STATUS + telemetry.numSats = bit32.extract(VALUE,0,4) + -- offset 4: NO_GPS = 0, NO_FIX = 1, GPS_OK_FIX_2D = 2, GPS_OK_FIX_3D or GPS_OK_FIX_3D_DGPS or GPS_OK_FIX_3D_RTK_FLOAT or GPS_OK_FIX_3D_RTK_FIXED = 3 + -- offset 14: 0: no advanced fix, 1: GPS_OK_FIX_3D_DGPS, 2: GPS_OK_FIX_3D_RTK_FLOAT, 3: GPS_OK_FIX_3D_RTK_FIXED + telemetry.gpsStatus = bit32.extract(VALUE,4,2) + bit32.extract(VALUE,14,2) + telemetry.gpsHdopC = bit32.extract(VALUE,7,7) * (10^bit32.extract(VALUE,6,1)) -- dm + telemetry.gpsAlt = bit32.extract(VALUE,24,7) * (10^bit32.extract(VALUE,22,2)) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1)-- dm + elseif DATA_ID == 0x5003 then -- BATT + telemetry.batt1volt = bit32.extract(VALUE,0,9) + -- telemetry max is 51.1V, 51.2 is reported as 0.0, 52.3 is 0.1...60 is 88 + -- if 12S and V > 51.1 ==> Vreal = 51.2 + telemetry.batt1volt + if conf.cell1Count == 12 and telemetry.batt1volt < 240 then + -- assume a 2Vx12 as minimum acceptable "real" voltage + telemetry.batt1volt = 512 + telemetry.batt1volt + end + telemetry.batt1current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) + telemetry.batt1mah = bit32.extract(VALUE,17,15) + elseif DATA_ID == 0x5008 then -- BATT2 + telemetry.batt2volt = bit32.extract(VALUE,0,9) + -- telemetry max is 51.1V, 51.2 is reported as 0.0, 52.3 is 0.1...60 is 88 + -- if 12S and V > 51.1 ==> Vreal = 51.2 + telemetry.batt1volt + if conf.cell2Count == 12 and telemetry.batt2volt < 240 then + -- assume a 2Vx12 as minimum acceptable "real" voltage + telemetry.batt2volt = 512 + telemetry.batt2volt + end + telemetry.batt2current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) + telemetry.batt2mah = bit32.extract(VALUE,17,15) + elseif DATA_ID == 0x5004 then -- HOME + telemetry.homeDist = bit32.extract(VALUE,2,10) * (10^bit32.extract(VALUE,0,2)) + telemetry.homeAlt = bit32.extract(VALUE,14,10) * (10^bit32.extract(VALUE,12,2)) * 0.1 * (bit32.extract(VALUE,24,1) == 1 and -1 or 1) + telemetry.homeAngle = bit32.extract(VALUE, 25, 7) * 3 + elseif DATA_ID == 0x5000 then -- MESSAGES + if VALUE ~= status.lastMsgValue then + status.lastMsgValue = VALUE + local c + local msgEnd = false + for i=3,0,-1 + do + c = bit32.extract(VALUE,i*8,7) + if c ~= 0 then + status.msgBuffer = status.msgBuffer .. string.char(c) + collectgarbage() + collectgarbage() + hash = bit32.bxor(hash, c) + hash = (hash * 16777619) % 2^32 + hashByteIndex = hashByteIndex+1 + -- check if this hash matches any 16bytes prefix hash + if hashByteIndex == 16 then + for i=1,#shortHashes + do + if hash == shortHashes[i][1] then + shortHash = hash + -- check if needs parsing + parseShortHash = shortHashes[i][2] == nil and false or true + break; + end + end + end + else + msgEnd = true; + break; + end + end + if msgEnd then + local severity = (bit32.extract(VALUE,7,1) * 1) + (bit32.extract(VALUE,15,1) * 2) + (bit32.extract(VALUE,23,1) * 4) + utils.pushMessage( severity, status.msgBuffer) + -- try to play the hash sound file without checking + -- for existence, OpenTX will gracefully ignore it :-) + utils.playSound(tostring(shortHash == nil and hash or shortHash),true) + -- if required parse parameter and play it! + if parseShortHash then + local param = string.match(status.msgBuffer, ".*#(%d+).*") + collectgarbage() + if param ~= nil then + playNumber(tonumber(param),0) + collectgarbage() + end + end + -- reset hash for next string + parseShortHash = false + shortHash = nil + hash = 2166136261 + hashByteIndex = 0 + status.msgBuffer = nil + -- recover memory + collectgarbage() + collectgarbage() + status.msgBuffer = "" + end + end + elseif DATA_ID == 0x5007 then -- PARAMS + paramId = bit32.extract(VALUE,24,4) + paramValue = bit32.extract(VALUE,0,24) + if paramId == 1 then + telemetry.frameType = paramValue + elseif paramId == 4 then + telemetry.batt1Capacity = paramValue + elseif paramId == 5 then + telemetry.batt2Capacity = paramValue + elseif paramId == 6 then + telemetry.wpCommands = paramValue + end + elseif DATA_ID == 0x5009 then -- WAYPOINTS @1Hz + telemetry.wpNumber = bit32.extract(VALUE,0,10) -- wp index + telemetry.wpDistance = bit32.extract(VALUE,12,10) * (10^bit32.extract(VALUE,10,2)) -- meters + telemetry.wpXTError = bit32.extract(VALUE,23,4) * (10^bit32.extract(VALUE,22,1)) * (bit32.extract(VALUE,27,1) == 1 and -1 or 1)-- meters + telemetry.wpBearing = bit32.extract(VALUE,29,3) -- offset from cog with 45° resolution + --[[ + elseif DATA_ID == 0x50F1 then -- RC CHANNELS + -- channels 1 - 32 + local offset = bit32.extract(VALUE,0,4) * 4 + rcchannels[1 + offset] = 100 * (bit32.extract(VALUE,4,6)/63) * (bit32.extract(VALUE,10,1) == 1 and -1 or 1) + rcchannels[2 + offset] = 100 * (bit32.extract(VALUE,11,6)/63) * (bit32.extract(VALUE,17,1) == 1 and -1 or 1) + rcchannels[3 + offset] = 100 * (bit32.extract(VALUE,18,6)/63) * (bit32.extract(VALUE,24,1) == 1 and -1 or 1) + rcchannels[4 + offset] = 100 * (bit32.extract(VALUE,25,6)/63) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1) + --]] elseif DATA_ID == 0x50F2 then -- VFR + telemetry.airspeed = bit32.extract(VALUE,1,7) * (10^bit32.extract(VALUE,0,1)) -- dm/s + telemetry.throttle = bit32.extract(VALUE,8,7) + telemetry.baroAlt = bit32.extract(VALUE,17,10) * (10^bit32.extract(VALUE,15,2)) * 0.1 * (bit32.extract(VALUE,27,1) == 1 and -1 or 1) + end +end + +local function telemetryEnabled() + if getRSSI() == 0 then + status.noTelemetryData = 1 + end + return status.noTelemetryData == 0 +end + +utils.getMaxValue = function(value,idx) + minmaxValues[idx] = math.max(value,minmaxValues[idx]) + return status.showMinMaxValues == true and minmaxValues[idx] or value +end + +local function calcMinValue(value,min) + return min == 0 and value or math.min(value,min) +end + +-- returns the actual minimun only if both are > 0 +local function getNonZeroMin(v1,v2) + return v1 == 0 and v2 or ( v2 == 0 and v1 or math.min(v1,v2)) +end + +local function calcCellCount() + -- cellcount override from menu + local c1 = 0 + local c2 = 0 + + if conf.cell1Count ~= nil and conf.cell1Count > 0 then + c1 = conf.cell1Count + elseif status.batt1sources.vs == true and status.cell1count > 1 then + c1 = status.cell1count + else + c1 = math.floor( ((status.cell1maxFC*0.1) / 4.35) + 1) + end + + if conf.cell2Count ~= nil and conf.cell2Count > 0 then + c2 = conf.cell2Count + elseif status.batt2sources.vs == true and status.cell2count > 1 then + c2 = status.cell2count + else + c2 = math.floor(((status.cell2maxFC*0.1)/4.35) + 1) + end + + return c1,c2 +end + +local function getBatt1Capacity() + return conf.battCapOverride1 > 0 and conf.battCapOverride1*10 or telemetry.batt1Capacity +end + +local function getBatt2Capacity() + -- this is a fix for passthrough telemetry reporting batt2 capacity > 0 even if BATT2_MONITOR = 0 + return conf.battCapOverride2 > 0 and conf.battCapOverride2*10 or ( status.batt2sources.fc and telemetry.batt2Capacity or 0 ) +end + +-- gets the voltage based on source and min value, battId = [1|2] +local function getMinVoltageBySource(source, cell, cellFC, battId) + -- offset 0 for cell voltage, 2 for pack voltage + local offset = 0 + -- + if cell > 4.35*2 or cellFC > 4.35*2 then + offset = 2 + end + -- + if source == "vs" then + return status.showMinMaxValues == true and minmaxValues[2+offset+battId] or cell + elseif source == "fc" then + -- FC only tracks batt1 and batt2 no cell voltage tracking + local minmax = (offset == 2 and minmaxValues[battId] or minmaxValues[battId]/calcCellCount()) + return status.showMinMaxValues == true and minmax or cellFC + end + -- + return 0 +end + +local function calcFLVSSBatt(battIdx) + local cellMin,cellSum,cellCount + local battSources = battIdx == 1 and status.batt1sources or status.batt2sources + + local cellResult = battIdx == 1 and getValue("Cels") or getValue("Cel2") + + if type(cellResult) == "table" then + cellMin = 4.35 + cellSum = 0 + -- cellcount is global and shared + cellCount = #cellResult + for i, v in pairs(cellResult) do + cellSum = cellSum + v + if cellMin > v then + cellMin = v + end + end + -- if connected after scritp started + if battSources.vs == false then + status.battsource = "na" + end + if status.battsource == "na" then + status.battsource = "vs" + end + battSources.vs = true + else + battSources.vs = false + cellMin = 0 + cellSum = 0 + end + return cellMin,cellSum,cellCount +end + +local function calcBattery() + ------------ + -- FLVSS 1 + ------------ + status.cell1min, status.cell1sum, status.cell1count = calcFLVSSBatt(1) --1 = Cels + + ------------ + -- FLVSS 2 + ------------ + status.cell2min, status.cell2sum, status.cell2count = calcFLVSSBatt(2) --2 = Cel2 + + -------------------------------- + -- flight controller battery 1 + -------------------------------- + if telemetry.batt1volt > 0 then + status.cell1sumFC = telemetry.batt1volt*0.1 + status.cell1maxFC = math.max(telemetry.batt1volt,status.cell1maxFC) + if status.battsource == "na" then + status.battsource = "fc" + end + status.batt1sources.fc = true + else + status.batt1sources.fc = false + status.cell1sumFC = 0 + end + -------------------------------- + -- flight controller battery 2 + -------------------------------- + if telemetry.batt2volt > 0 then + status.cell2sumFC = telemetry.batt2volt*0.1 + status.cell2maxFC = math.max(telemetry.batt2volt,status.cell2maxFC) + if status.battsource == "na" then + status.battsource = "fc" + end + status.batt2sources.fc = true + else + status.batt2sources.fc = false + status.cell2sumFC = 0 + end + -- batt fc + minmaxValues[1] = calcMinValue(status.cell1sumFC,minmaxValues[1]) + minmaxValues[2] = calcMinValue(status.cell2sumFC,minmaxValues[2]) + -- cell flvss + minmaxValues[3] = calcMinValue(status.cell1min,minmaxValues[3]) + minmaxValues[4] = calcMinValue(status.cell2min,minmaxValues[4]) + -- batt flvss + minmaxValues[5] = calcMinValue(status.cell1sum,minmaxValues[5]) + minmaxValues[6] = calcMinValue(status.cell2sum,minmaxValues[6]) + -- + ------------------------------------------ + -- table to pass battery info to panes + -- offsets are: 1 celm, 4 batt, 7 curr, 10 mah, 13 cap, indexing starts at 1 + -- value = offset + [0 aggregate|1 for batt 1| 2 for batt2] + -- batt2 = 4 + 2 = 6 + ------------------------------------------ + -- Note: these can be calculated. not necessary to track them as min/max + -- cell1minFC = cell1sumFC/calcCellCount() + -- cell2minFC = cell2sumFC/calcCellCount() + -- cell1minA2 = cell1sumA2/calcCellCount() + -- + local count1,count2 = calcCellCount() + + battery[1+1] = getMinVoltageBySource(status.battsource, status.cell1min, status.cell1sumFC/count1, 1)*100 --cel1m + battery[1+2] = getMinVoltageBySource(status.battsource, status.cell2min, status.cell2sumFC/count2, 2)*100 --cel2m + battery[1] = (conf.battConf == 3 and battery[2] or getNonZeroMin(battery[2], battery[3]) ) + + battery[4+1] = getMinVoltageBySource(status.battsource, status.cell1sum, status.cell1sumFC, 1)*10 --batt1 + battery[4+2] = getMinVoltageBySource(status.battsource, status.cell2sum, status.cell2sumFC, 2)*10 --batt2 + battery[4] = (conf.battConf == 3 and battery[5] or (conf.battConf == 2 and battery[5]+battery[6] or getNonZeroMin(battery[5],battery[6]))) + + battery[7] = utils.getMaxValue((conf.battConf == 3 and telemetry.batt1current or telemetry.batt1current + telemetry.batt2current),7) + battery[7+1] = utils.getMaxValue(telemetry.batt1current,8) --curr1 + battery[7+2] = utils.getMaxValue(telemetry.batt2current,9) --curr2 + + battery[10] = (conf.battConf == 3 and telemetry.batt1mah or telemetry.batt1mah + telemetry.batt2mah) + battery[10+1] = telemetry.batt1mah --mah1 + battery[10+2] = telemetry.batt2mah --mah2 + + battery[13] = (conf.battConf == 1 and getBatt1Capacity() + getBatt2Capacity() or getBatt1Capacity()) + battery[13+1] = getBatt1Capacity() --cap1 + battery[13+2] = getBatt2Capacity() --cap2 + + if status.showDualBattery == true and conf.battConf == 1 then + -- dual parallel battery: do I have also dual current monitor? + if battery[7+1] > 0 and battery[7+2] == 0 then + -- special case: assume 1 power brick is monitoring batt1+batt2 in parallel + battery[7+1] = battery[7+1]/2 --curr1 + battery[7+2] = battery[7+1] --curr2 + -- + battery[10+1] = battery[10+1]/2 --mah1 + battery[10+2] = battery[10+1] --mah2 + -- + battery[13+1] = battery[13+1]/2 --cap1 + battery[13+2] = battery[13+1] --cap2 + end + end +end + +local function checkLandingStatus() + if ( status.timerRunning == 0 and telemetry.landComplete == 1 and status.lastTimerStart == 0) then + startTimer() + end + if (status.timerRunning == 1 and telemetry.landComplete == 0 and status.lastTimerStart ~= 0) then + stopTimer() + -- play landing complete anly if motorts are armed + if telemetry.statusArmed == 1 then + utils.playSound("landing") + end + end + status.timerRunning = telemetry.landComplete +end + +local resetLib = {} +local resetFile = libBasePath.."reset.luac" + +local function reset() + -- ERRORE reset da kill CPU limit!!!!!!!! + -- 2 stage reset + if resetPending == false then + -- initialize status + if resetLib.resetWidget == nil then + resetLib = dofile(resetFile) + collectgarbage() + collectgarbage() + end + -- reset frame + utils.clearTable(frame.frameTypes) + -- reset widget pages + currentPage = 0 + + minmaxValues = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} + + status.showMinMaxValues = false + status.showDualBattery = false + status.strFlightMode = nil + status.modelString = nil + + frame = {} + -- reset all + resetLib.resetTelemetry(status,telemetry,battery,alarms,utils) + -- release resources + utils.clearTable(resetLib) + -- force load model config + model.setGlobalVariable(8,8,1) + collectgarbage() + collectgarbage() + utils.pushMessage(6,"telemetry reset done!") + resetPending = true + else + -- custom sensors + utils.clearTable(customSensors) + customSensors = nil + utils.loadCustomSensors() + -- done + utils.playSound("yaapu") + collectgarbage() + collectgarbage() + resetPending = false + end +end + +local function calcFlightTime() + -- update local variable with timer 3 value + if ( model.getTimer(2).value < status.flightTime and telemetry.statusArmed == 0) then + reset() + end + if (model.getTimer(2).value < status.flightTime and telemetry.statusArmed == 1) then + model.setTimer(2,{value=status.flightTime}) + utils.pushMessage(4,"Reset ignored while armed") + end + status.flightTime = model.getTimer(2).value +end + +local function setSensorValues() + if (not telemetryEnabled()) then + return + end + local battmah = telemetry.batt1mah + local battcapacity = getBatt1Capacity() + if telemetry.batt2mah > 0 then + battcapacity = getBatt1Capacity() + getBatt2Capacity() + battmah = telemetry.batt1mah + telemetry.batt2mah + end + + local perc = 0 + + if (battcapacity > 0) then + perc = math.min(math.max((1 - (battmah/battcapacity))*100,0),99) + end + + setTelemetryValue(0x060F, 0, 0, perc, 13 , 0 , "Fuel") + setTelemetryValue(0x021F, 0, 0, getNonZeroMin(telemetry.batt1volt,telemetry.batt2volt)*10, 1 , 2 , "VFAS") + setTelemetryValue(0x020F, 0, 0, telemetry.batt1current+telemetry.batt2current, 2 , 1 , "CURR") + setTelemetryValue(0x011F, 0, 0, telemetry.vSpeed, 5 , 1 , "VSpd") + setTelemetryValue(0x083F, 0, 0, telemetry.hSpeed*0.1, 5 , 0 , "GSpd") + setTelemetryValue(0x010F, 0, 0, telemetry.homeAlt*10, 9 , 1 , "Alt") + setTelemetryValue(0x082F, 0, 0, math.floor(telemetry.gpsAlt*0.1), 9 , 0 , "GAlt") + setTelemetryValue(0x084F, 0, 0, math.floor(telemetry.yaw), 20 , 0 , "Hdg") + setTelemetryValue(0x041F, 0, 0, telemetry.imuTemp, 11 , 0 , "IMUt") + setTelemetryValue(0x060F, 0, 1, telemetry.statusArmed*100, 0 , 0 , "ARM") +end + +utils.drawTopBar = function() + lcd.setColor(CUSTOM_COLOR,0x0000) + -- black bar + lcd.drawFilledRectangle(0,0, LCD_W, 18, CUSTOM_COLOR) + -- frametype and model name + lcd.setColor(CUSTOM_COLOR,0xFFFF) + if status.modelString ~= nil then + lcd.drawText(2, 0, status.modelString, CUSTOM_COLOR) + end + -- flight time + local time = getDateTime() + local strtime = string.format("%02d:%02d:%02d",time.hour,time.min,time.sec) + lcd.drawText(LCD_W, 0+4, strtime, SMLSIZE+RIGHT+CUSTOM_COLOR) + -- RSSI + if telemetryEnabled() == false then + lcd.setColor(CUSTOM_COLOR,0xF800) + lcd.drawText(285-23, 0, "NO TELEM", 0 +CUSTOM_COLOR) + else + lcd.drawText(285, 0, "RS:", 0 +CUSTOM_COLOR) + lcd.drawText(285 + 30,0, getRSSI(), 0 +CUSTOM_COLOR) + end + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- tx voltage + local vtx = string.format("Tx:%.1fv",getValue(getFieldInfo("tx-voltage").id)) + lcd.drawText(350,0, vtx, 0+CUSTOM_COLOR) +end + +local function drawMessageScreen() + for i=0,#status.messages do + if status.messages[(status.messageCount + i) % (#status.messages+1)][2] == 4 then + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255,0)) + elseif status.messages[(status.messageCount + i) % (#status.messages+1)][2] < 4 then + --lcd.setColor(CUSTOM_COLOR,0xF800) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,70,0)) + else + lcd.setColor(CUSTOM_COLOR,0xFFFF) + end + lcd.drawText(0,2+13*i, status.messages[(status.messageCount + i) % (#status.messages+1)][1],SMLSIZE+CUSTOM_COLOR) + end + + lcd.setColor(CUSTOM_COLOR,0x0AB1) + lcd.drawFilledRectangle(405,0,75,272,CUSTOM_COLOR) + + lcd.setColor(CUSTOM_COLOR,0xFFFF) + -- print info on the right + -- CELL + if battery[1] * 0.01 < 10 then + lcd.drawNumber(410, 0, battery[1] + 0.5, PREC2+0+MIDSIZE+CUSTOM_COLOR) + else + lcd.drawNumber(410, 0, (battery[1] + 0.5)*0.1, PREC1+0+MIDSIZE+CUSTOM_COLOR) + end + lcd.drawText(410+50, 1, status.battsource, SMLSIZE+CUSTOM_COLOR) + lcd.drawText(410+50, 11, "V", SMLSIZE+CUSTOM_COLOR) + -- ALT + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(410, 25, "Alt("..unitLabel..")", SMLSIZE+0+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(410,37,telemetry.homeAlt*unitScale,MIDSIZE+CUSTOM_COLOR+0) + -- SPEED + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(410, 60, "Spd("..conf.horSpeedLabel..")", SMLSIZE+0+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(410,72,telemetry.hSpeed*0.1* conf.horSpeedMultiplier,MIDSIZE+CUSTOM_COLOR+0) + -- VSPEED + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(410, 95, "VSI("..conf.vertSpeedLabel..")", SMLSIZE+0+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(410,107, telemetry.vSpeed*0.1*conf.vertSpeedMultiplier, MIDSIZE+CUSTOM_COLOR+0) + -- DIST + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(410, 130, "Dist("..unitLabel..")", SMLSIZE+0+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(410, 142, telemetry.homeDist*unitScale, MIDSIZE+0+CUSTOM_COLOR) + -- HDG + lcd.setColor(CUSTOM_COLOR,0x0000) + lcd.drawText(410, 165, "Heading", SMLSIZE+0+CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawNumber(410, 177, telemetry.yaw, MIDSIZE+0+CUSTOM_COLOR) + -- HOMEDIR + lcd.setColor(CUSTOM_COLOR,0xFE60) + drawLib.drawRArrow(442,235,22,math.floor(telemetry.homeAngle - telemetry.yaw),CUSTOM_COLOR)--HomeDirection(telemetry) +end + +--------------------------------- +-- This function checks alarm condition and as long as the condition persists it plays +-- a warning sound. +--------------------------------- +utils.checkAlarm = function(level,value,idx,sign,sound,delay) + -- once landed reset all alarms except battery alerts + if status.timerRunning == 0 then + if alarms[idx][4] == 0 then + alarms[idx] = { false, 0, false, 0, 0, false, 0} + elseif alarms[idx][4] == 1 then + alarms[idx] = { false, 0, true, 1 , 0, false, 0} + elseif alarms[idx][4] == 2 then + alarms[idx] = { false, 0, true, 2, 0, false, 0} + elseif alarms[idx][4] == 3 then + alarms[idx] = { false, 0 , false, 3, 4, false, 0} + elseif alarms[idx][4] == 4 then + alarms[idx] = { false, 0 , false, 4, 4, false, 0} + end + -- reset done + return + end + -- if needed arm the alarm only after value has reached level + if alarms[idx][3] == false and level > 0 and -1 * sign*value > -1 * sign*level then + alarms[idx][3] = true + end + + if alarms[idx][4] == 2 then + if status.flightTime > 0 and math.floor(status.flightTime) % delay == 0 then + if alarms[idx][1] == false then + alarms[idx][1] = true + utils.playSound(sound) + playDuration(status.flightTime,(status.flightTime > 3600 and 1 or 0)) -- minutes,seconds + end + else + alarms[idx][1] = false + end + else + if alarms[idx][3] == true then + if level > 0 and sign*value > sign*level then + -- value is outside level + if alarms[idx][2] == 0 then + -- first time outside level after last reset + alarms[idx][2] = status.flightTime + -- status: START + end + else + -- value back to normal ==> reset + alarms[idx][2] = 0 + alarms[idx][1] = false + alarms[idx][6] = false + -- status: RESET + end + if alarms[idx][2] > 0 and (status.flightTime ~= alarms[idx][2]) and (status.flightTime - alarms[idx][2]) >= alarms[idx][5] then + -- enough time has passed after START + alarms[idx][6] = true + -- status: READY + end + + if alarms[idx][6] == true and alarms[idx][1] == false then + utils.playSound(sound) + alarms[idx][1] = true + alarms[idx][7] = status.flightTime + -- status: BEEP + end + -- all but battery alarms + if alarms[idx][4] ~= 3 then + if alarms[idx][6] == true and status.flightTime ~= alarms[idx][7] and (status.flightTime - alarms[idx][7]) % delay == 0 then + alarms[idx][1] = false + -- status: REPEAT + end + end + end + end +end + +local function loadFlightModes() + if frame.flightModes then + return + end + if telemetry.frameType ~= -1 then + if frameTypes[telemetry.frameType] == "c" then + frame = utils.doLibrary(conf.enablePX4Modes and "copter_px4" or "copter") + elseif frameTypes[telemetry.frameType] == "p" then + frame = utils.doLibrary(conf.enablePX4Modes and "plane_px4" or "plane") + elseif frameTypes[telemetry.frameType] == "r" or frameTypes[telemetry.frameType] == "b" then + frame = utils.doLibrary("rover") + end + collectgarbage() + collectgarbage() + maxmem = 0 + end +end +--[[ +local function loadFlightModes() + if frame.flightModes then + return + end + + if telemetry.frameType ~= -1 then +#ifdef LOAD_LUA + if frameTypes[telemetry.frameType] == "c" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "copter_px4.lua" or "copter.lua")) + elseif frameTypes[telemetry.frameType] == "p" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "plane_px4.lua" or "plane.lua")) + elseif frameTypes[telemetry.frameType] == "r" then + frame = dofile(libBasePath.."rover.lua") + end +#else + if frameTypes[telemetry.frameType] == "c" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "copter_px4.luac" or "copter.luac")) + elseif frameTypes[telemetry.frameType] == "p" then + frame = dofile(libBasePath..(conf.enablePX4Modes and "plane_px4.luac" or "plane.luac")) + elseif frameTypes[telemetry.frameType] == "r" then + frame = dofile(libBasePath.."rover.luac") + end +#endif + collectgarbage() + maxmem = 0 + end +end +--]] +--------------------------------- +-- This function checks state transitions and only returns true if a specific delay has passed +-- new transitions reset the delay timer +--------------------------------- +local function checkTransition(idx,value) + if value ~= transitions[idx][1] then + -- value has changed + transitions[idx][1] = value + transitions[idx][2] = getTime() + transitions[idx][3] = false + -- status: RESET + return false + end + if transitions[idx][3] == false and (getTime() - transitions[idx][2]) > transitions[idx][4] then + -- enough time has passed after RESET + transitions[idx][3] = true + -- status: FIRE + return true; + end +end + +local function checkEvents(celm) + loadFlightModes() + + -- silence alarms when showing min/max values + if status.showMinMaxValues == false then + utils.checkAlarm(conf.minAltitudeAlert,telemetry.homeAlt,1,-1,"minalt",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.maxAltitudeAlert,telemetry.homeAlt,2,1,"maxalt",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.maxDistanceAlert,telemetry.homeDist,3,1,"maxdist",conf.repeatAlertsPeriod) + utils.checkAlarm(1,2*telemetry.ekfFailsafe,4,1,"ekf",conf.repeatAlertsPeriod) + utils.checkAlarm(1,2*telemetry.battFailsafe,5,1,"lowbat",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.timerAlert,status.flightTime,6,1,"timealert",conf.timerAlert) + end + + -- default is use battery 1 + local capacity = getBatt1Capacity() + local mah = telemetry.batt1mah + -- only if dual battery has been detected use battery 2 + if (status.batt2sources.fc or status.batt2sources.vs) and conf.battConf == 1 then + capacity = capacity + getBatt2Capacity() + mah = mah + telemetry.batt2mah + end + -- + if (capacity > 0) then + status.batLevel = (1 - (mah/capacity))*100 + else + status.batLevel = 99 + end + for l=1,13 do + -- trigger alarm as as soon as it falls below level + 1 (i.e 91%,81%,71%,...) + if status.batLevel <= batLevels[l] + 1 and l < status.lastBattLevel then + status.lastBattLevel = l + utils.playSound("bat"..batLevels[l]) + break + end + end + + if telemetry.statusArmed == 1 and status.lastStatusArmed == 0 then + status.lastStatusArmed = telemetry.statusArmed + utils.playSound("armed") + -- reset home on arming + telemetry.homeLat = nil + telemetry.homeLon = nil + elseif telemetry.statusArmed == 0 and status.lastStatusArmed == 1 then + status.lastStatusArmed = telemetry.statusArmed + utils.playSound("disarmed") + end + + if telemetry.gpsStatus > 2 and status.lastGpsStatus <= 2 then + status.lastGpsStatus = telemetry.gpsStatus + utils.playSound("gpsfix") + elseif telemetry.gpsStatus <= 2 and status.lastGpsStatus > 2 then + status.lastGpsStatus = telemetry.gpsStatus + utils.playSound("gpsnofix") + end + + -- home detecting code + if telemetry.homeLat == nil then + if telemetry.gpsStatus > 2 and telemetry.homeAngle ~= -1 then + telemetry.homeLat, telemetry.homeLon = utils.getHomeFromAngleAndDistance(telemetry) + end + end + + -- flightmode transitions have a grace period to prevent unwanted flightmode call out + -- on quick radio mode switches + if telemetry.frameType ~= -1 and checkTransition(1,telemetry.flightMode) then + utils.playSoundByFlightMode(telemetry.flightMode) + end + + if telemetry.simpleMode ~= status.lastSimpleMode then + if telemetry.simpleMode == 0 then + utils.playSound( status.lastSimpleMode == 1 and "simpleoff" or "ssimpleoff" ) + else + utils.playSound( telemetry.simpleMode == 1 and "simpleon" or "ssimpleon" ) + end + status.lastSimpleMode = telemetry.simpleMode + end +end + +local function checkCellVoltage(celm) + -- check alarms + utils.checkAlarm(conf.battAlertLevel1,celm,7,-1,"batalert1",conf.repeatAlertsPeriod) + utils.checkAlarm(conf.battAlertLevel2,celm,8,-1,"batalert2",conf.repeatAlertsPeriod) + -- cell bgcolor is sticky but gets triggered with alarms + if status.battLevel1 == false then status.battLevel1 = alarms[7][1] end + if status.battLevel2 == false then status.battLevel2 = alarms[8][1] end +end + +local function cycleBatteryInfo() + if status.showDualBattery == false and (status.batt2sources.fc or status.batt2sources.vs) and conf.battConf ~= 2 then + status.showDualBattery = true + return + end + status.battsource = status.battsource == "vs" and "fc" or "vs" +end +-------------------------------------------------------------------------------- +-- MAIN LOOP +-------------------------------------------------------------------------------- +-- +local bgclock = 0 + +------------------------------- +-- running at 20Hz (every 50ms) +------------------------------- +local timer2Hz = getTime() +local function backgroundTasks(myWidget,telemetryLoops) + -- FAST: this runs at 60Hz (every 16ms) + for i=1,telemetryLoops + do + local sensor_id,frame_id,data_id,value = sportTelemetryPop() + + if frame_id == 0x10 then + status.noTelemetryData = 0 + -- no telemetry dialog only shown once + status.hideNoTelemetry = true + processTelemetry(data_id,value) + end + end + -- SLOW: this runs around 2.5Hz + if bgclock % 2 == 1 then + calcFlightTime() + -- update gps telemetry data + local gpsData = getValue("GPS") + + if type(gpsData) == "table" and gpsData.lat ~= nil and gpsData.lon ~= nil then + telemetry.lat = gpsData.lat + telemetry.lon = gpsData.lon + end + --export OpenTX sensor values + setSensorValues() + -- update total distance as often as po + utils.updateTotalDist() + + if getTime() - timer2Hz > 50 then + status.screenTogglePage = utils.getScreenTogglePage(myWidget,conf,status) + timer2Hz = getTime() + end + + -- flight mode + if frame.flightModes then + status.strFlightMode = frame.flightModes[telemetry.flightMode] + if status.strFlightMode ~= nil and telemetry.simpleMode > 0 then + local strSimpleMode = telemetry.simpleMode == 1 and "(S)" or "(SS)" + status.strFlightMode = string.format("%s%s",status.strFlightMode,strSimpleMode) + end + end + + -- top bar model frame and name + if status.modelString == nil then + -- frametype and model name + local info = model.getInfo() + local fn = frameNames[telemetry.frameType] + local strmodel = info.name + if fn ~= nil then + status.modelString = fn..": "..info.name + end + end + end + + -- SLOWER: this runs around 1.25Hz but not when the previous block runs + -- because bgclock%4 == 0 is always different than bgclock%2==1 + if bgclock % 4 == 0 then + -- update battery + calcBattery() + -- prepare celm based on status.battsource + local count1,count2 = calcCellCount() + local cellVoltage = 0 + + if conf.battConf == 3 then + -- alarms are based on battery 1 + cellVoltage = 100*(status.battsource == "vs" and status.cell1min or status.cell1sumFC/count1) + else + -- alarms are based on battery 1 and battery 2 + cellVoltage = 100*(status.battsource == "vs" and getNonZeroMin(status.cell1min,status.cell2min) or getNonZeroMin(status.cell1sumFC/count1,status.cell2sumFC/count2)) + end + + checkEvents(cellVoltage) + checkLandingStatus() + -- no need for alarms if reported voltage is 0 + if cellVoltage > 0 then + checkCellVoltage(cellVoltage) + end + -- aggregate value + minmaxValues[7] = math.max((conf.battConf == 3 and telemetry.batt1current or telemetry.batt1current+telemetry.batt2current), minmaxValues[7]) + + -- indipendent values + minmaxValues[8] = math.max(telemetry.batt1current,minmaxValues[8]) + minmaxValues[9] = math.max(telemetry.batt2current,minmaxValues[9]) + + -- reset backlight panel + if (model.getGlobalVariable(8,0) > 0 and getTime()/100 - backlightLastTime > 5) then + model.setGlobalVariable(8,0,0) + end + -- reload config + if (model.getGlobalVariable(8,8) > 0) then + loadConfig() + model.setGlobalVariable(8,8,0) + end + -- call custom panel background functions + if leftPanel ~= nil then + leftPanel.background(myWidget,conf,telemetry,status,utils) + end + if centerPanel ~= nil then + centerPanel.background(myWidget,conf,telemetry,status,utils) + end + if rightPanel ~= nil then + rightPanel.background(myWidget,conf,telemetry,status,utils) + end + + bgclock = 0 + end + bgclock = bgclock+1 + -- blinking support + if (getTime() - blinktime) > 65 then + blinkon = not blinkon + blinktime = getTime() + end + collectgarbage() + collectgarbage() + return 0 +end + +local showSensorPage = false +local showMessages = false + +local function init() + -- initialize flight timer + model.setTimer(2,{mode=0}) + model.setTimer(2,{value=0}) +-- load configuration at boot and only refresh if GV(8,8) = 1 + loadConfig() + -- load draw library + drawLib = utils.doLibrary(drawLibFile) + + currentModel = model.getInfo().name + -- load custom sensors + utils.loadCustomSensors() + -- ok done + utils.pushMessage(7,"Yaapu Telemetry Widget 1.8.0") + utils.playSound("yaapu") + -- fix for generalsettings lazy loading... + unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 + unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" + unitLongScale = getGeneralSettings().imperial == 0 and 1/1000 or 1/1609.34 + unitLongLabel = getGeneralSettings().imperial == 0 and "km" or "mi" +end + +-------------------------------------------------------------------------------- +-- 4 pages +-- page 1 single battery view +-- page 2 message history +-- page 3 min max +-- page 4 dual battery view +local options = { + { "page", VALUE, 1, 1, 5}, +} +-- shared init flag +local initDone = 0 +-- This function is runned once at the creation of the widget +local function create(zone, options) + -- this vars are widget scoped, each instance has its own set + local vars = { + } + -- all local vars are shared between widget instances + -- init() needs to be called only once! + if initDone == 0 then + init() + initDone = 1 + end + -- + return { zone=zone, options=options, vars=vars } +end +-- This function allow updates when you change widgets settings +local function update(myWidget, options) + myWidget.options = options + -- reload menu settings + loadConfig() +end + +local function fullScreenRequired(myWidget) + lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0, 0)) + lcd.drawText(myWidget.zone.x,myWidget.zone.y,"Yaapu requires",SMLSIZE+CUSTOM_COLOR) + lcd.drawText(myWidget.zone.x,myWidget.zone.y+16,"full screen",SMLSIZE+CUSTOM_COLOR) +end + + +utils.getScreenTogglePage = function(myWidget,conf,status) + local screenChValue = status.hideNoTelemetry == false and -1000 or getValue(conf.screenToggleChannelId) + + if conf.screenToggleChannelId > -1 then + if screenChValue > -600 then + -- message history + return 2 + end + end + return myWidget.options.page +end + +-- called when widget instance page changes +local function onChangePage(myWidget) + -- reset HUD counters + myWidget.vars.hudcounter = 0 + collectgarbage() + collectgarbage() +end + +-- Called when script is hidden @20Hz +local function background(myWidget) + -- when page 1 goes to background run bg tasks + if myWidget.options.page == 1 then + -- run bg tasks + backgroundTasks(myWidget,12) + return + end + -- when page 3 goes to background hide minmax values + if myWidget.options.page == 3 then + status.showMinMaxValues = false + return + end + -- when page 4 goes to background hide dual battery view + if myWidget.options.page == 4 then + status.showDualBattery = false + return + end +end + +local slowTimer = getTime() + +-- Called when script is visible +local function drawFullScreen(myWidget) + if getTime() - slowTimer > 50 then + -- reset phase 2 if reset pending + if resetPending == true then + reset() + else + -- frametype and model name + local info = model.getInfo() + -- model change event + if currentModel ~= info.name then + currentModel = info.name + -- trigger reset phase 1 + reset() + end + end + + if myWidget.options.page == 3 then + -- when page 3 goes to foreground show minmax values + status.showMinMaxValues = true + elseif myWidget.options.page == 4 then + -- when page 4 goes to foreground show dual battery view + status.showDualBattery = true + end + + -- check if current widget page changed + if currentPage ~= myWidget.options.page then + currentPage = myWidget.options.page + onChangePage(myWidget) + end + + slowTimer = getTime() + end + + -- when page 1 goes to foreground run bg tasks + if myWidget.options.page == 1 then + -- run bg tasks only if we are not resetting, this prevent cpu limit kill + if resetPending == false then + backgroundTasks(myWidget,12) + end + end + -- + + lcd.setColor(CUSTOM_COLOR, 0x0AB1) + if myWidget.options.page == 2 or status.screenTogglePage == 2 then + ------------------------------------ + -- Widget Page 2 is message history + ------------------------------------ + -- message history has black background + lcd.setColor(CUSTOM_COLOR, 0x0000) + lcd.clear(CUSTOM_COLOR) + + drawMessageScreen() + else + lcd.clear(CUSTOM_COLOR) + + if layout ~= nil then + layout.draw(myWidget,drawLib,conf,telemetry,status,battery,alarms,frame,utils,customSensors,gpsStatuses,leftPanel,centerPanel,rightPanel) + else + -- Layout start + if leftPanel == nil and loadCycle == 1 then + leftPanel = utils.doLibrary(conf.leftPanelFilename) + end + + if centerPanel == nil and loadCycle == 2 then + centerPanel = utils.doLibrary(conf.centerPanelFilename) + end + + if rightPanel == nil and loadCycle == 4 then + rightPanel = utils.doLibrary(conf.rightPanelFilename) + end + + if layout == nil and loadCycle == 6 and leftPanel ~= nil and centerPanel ~= nil and rightPanel ~= nil then + layout = utils.doLibrary(conf.widgetLayoutFilename) + end + + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawFilledRectangle(88,74, 304, 84, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0x10A3) + lcd.drawFilledRectangle(90,76, 300, 80, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR,0xFFFF) + lcd.drawText(155, 95, "loading...", DBLSIZE+CUSTOM_COLOR) + end + -- Layout END + end + -- no telemetry/minmax outer box + if telemetryEnabled() == false then + -- no telemetry inner box + if not status.hideNoTelemetry then + drawLib.drawNoTelemetryData(status,telemetry,utils,telemetryEnabled) + end + utils.drawBlinkBitmap("warn",0,0) + else + if status.showMinMaxValues == true then + utils.drawBlinkBitmap("minmax",0,0) + end + end + + loadCycle=(loadCycle+1)%8 + collectgarbage() + collectgarbage() +end + +function refresh(myWidget) + if myWidget.zone.h < 250 then + fullScreenRequired(myWidget) + return + end + drawFullScreen(myWidget) +end + +return { name="Yaapu", options=options, create=create, update=update, background=background, refresh=refresh } diff --git a/HORUS/SOURCES/copter.lua b/HORUS/SOURCES/copter.lua deleted file mode 100644 index 7f82933d..00000000 --- a/HORUS/SOURCES/copter.lua +++ /dev/null @@ -1,29 +0,0 @@ - local flightModes = {} - -- copter flight modes - flightModes[0]="" - flightModes[1]="Stabilize" - flightModes[2]="Acro" - flightModes[3]="AltHold" - flightModes[4]="Auto" - flightModes[5]="Guided" - flightModes[6]="Loiter" - flightModes[7]="RTL" - flightModes[8]="Circle" - flightModes[9]="" - flightModes[10]="Land" - flightModes[11]="" - flightModes[12]="Drift" - flightModes[13]="" - flightModes[14]="Sport" - flightModes[15]="Flip" - flightModes[16]="AutoTune" - flightModes[17]="PosHold" - flightModes[18]="Brake" - flightModes[19]="Throw" - flightModes[20]="AvoidADSB" - flightModes[21]="GuidedNOGPS" - flightModes[22]="SmartRTL" - flightModes[23]="FlowHold" - flightModes[24]="Follow" - -return {flightModes=flightModes} \ No newline at end of file diff --git a/HORUS/SOURCES/menu0.lua b/HORUS/SOURCES/menu0.lua deleted file mode 100644 index f630475c..00000000 --- a/HORUS/SOURCES/menu0.lua +++ /dev/null @@ -1,267 +0,0 @@ --- --- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios --- --- Copyright (C) 2018. Alessandro Apostoli --- https://github.com/yaapu --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- 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. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, see . --- --- Passthrough protocol reference: --- https://cdn.rawgit.com/ArduPilot/ardupilot_wiki/33cd0c2c/images/FrSky_Passthrough_protocol.xlsx --- --- Borrowed some code from the LI-xx BATTCHECK v3.30 script --- http://frskytaranis.forumactif.org/t2800-lua-download-un-testeur-de-batterie-sur-la-radio - ---------------------- --- Script Version ---------------------- -#define VERSION "Yaapu Telemetry Script 1.7.4" - ---#define BATTPERC_BY_VOLTAGE - -#define TOPBAR_Y 0 -#define TOPBAR_HEIGHT 20 -#define TOPBAR_WIDTH LCD_W - -#define BOTTOMBAR_Y LCD_H - 20 -#define BOTTOMBAR_HEIGHT 20 -#define BOTTOMBAR_WIDTH LCD_W --------------------------------------------------------------------------------- --- CONFIGURATION MENU --------------------------------------------------------------------------------- -#define TYPEVALUE 0 -#define TYPECOMBO 1 -#define MENU_Y 25 -#define MENU_PAGESIZE 11 -#ifdef BATTPERC_BY_VOLTAGE -#define MENU_WRAPOFFSET 9 -#else -#define MENU_WRAPOFFSET 8 -#endif -#define MENU_ITEM_X 300 - -#define L1 1 -#define V1 2 -#define V2 3 -#define B1 4 -#define B2 5 -#define S1 6 -#define S2 7 -#define S3 8 -#define VS 9 -#define T1 10 -#define A1 11 -#define A2 12 -#define D1 13 -#define T2 14 -#define CC 15 -#define RM 16 -#define SVS 17 -#define HSPD 18 -#define VSPD 19 -#define BPBV 20 - -local menu = { - selectedItem = 1, - editSelected = false, - offset = 0 -} - -local menuItems = {} - -- label, type, alias, currval, min, max, label, flags, increment -menuItems[L1] = {"voice language:", TYPECOMBO, "L1", 1, { "english", "italian", "french", "german" } , {"en","it","fr","de"} } -menuItems[V1] = {"batt alert level 1:", TYPEVALUE, "V1", 375, 0,5000,"V", PREC2 ,5 } -menuItems[V2] = {"batt alert level 2:", TYPEVALUE, "V2", 350, 0,5000,"V", PREC2 ,5 } -menuItems[B1] = {"batt[1] capacity override:", TYPEVALUE, "B1", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[B2] = {"batt[2] capacity override:", TYPEVALUE, "B2", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[S1] = {"disable all sounds:", TYPECOMBO, "S1", 1, { "no", "yes" }, { false, true } } -menuItems[S2] = {"disable msg beep:", TYPECOMBO, "S2", 1, { "no", "yes" }, { false, true } } -menuItems[S3] = {"disable msg blink:", TYPECOMBO, "S3", 1, { "no", "yes" }, { false, true } } -menuItems[VS] = {"default voltage source:", TYPECOMBO, "VS", 1, { "auto", "FLVSS", "A2", "fc" }, { nil, "vs", "a2", "fc" } } -menuItems[T1] = {"timer alert every:", TYPEVALUE, "T1", 0, 0,600,"min",PREC1,5 } -menuItems[A1] = {"min altitude alert:", TYPEVALUE, "A1", 0, 0,500,"m",PREC1,5 } -menuItems[A2] = {"max altitude alert:", TYPEVALUE, "A2", 0, 0,10000,"m",0,1 } -menuItems[D1] = {"max distance alert:", TYPEVALUE, "D1", 0, 0,100000,"m",0,10 } -menuItems[T2] = {"repeat alerts every:", TYPEVALUE, "T2", 10, 5,600,"sec",0,5 } -menuItems[CC] = {"cell count override:", TYPEVALUE, "CC", 0, 0,12,"cells",0,1 } -menuItems[RM] = {"rangefinder max:", TYPEVALUE, "RM", 0, 0,10000," cm",0,10 } -menuItems[SVS] = {"enable synthetic vspeed:", TYPECOMBO, "SVS", 1, { "no", "yes" }, { false, true } } -menuItems[HSPD] = {"air/groundspeed unit:", TYPECOMBO, "HSPD", 1, { "m/s", "km/h", "mph", "kn" }, { 1, 3.6, 2.23694, 1.94384} } -menuItems[VSPD] = {"vertical speed unit:", TYPECOMBO, "VSPD", 1, { "m/s", "ft/s", "ft/min" }, { 1, 3.28084, 196.85} } -#ifdef BATTPERC_BY_VOLTAGE -menuItems[BPBV] = {"enable battery % by voltage:", TYPECOMBO, "BPBV", 1, { "no", "yes" }, { false, true } } -#endif --BATTPERC_BY_VOLTAGE --- - -local function getConfigFilename() - local info = model.getInfo() - return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".cfg") -end - -local function loadConfig() - local cfg = io.open(getConfigFilename(),"r") - if cfg == nil then - return - end - local str = io.read(cfg,200) - if string.len(str) > 0 then - for i=1,#menuItems - do - local value = string.match(str, menuItems[i][3]..":(%d+)") - if value ~= nil then - menuItems[i][4] = tonumber(value) - end - end - end - if cfg ~= nil then - io.close(cfg) - end -end - -local function saveConfig() - local cfg = assert(io.open(getConfigFilename(),"w")) - if cfg == nil then - return - end - for i=1,#menuItems - do - io.write(cfg,menuItems[i][3],":",menuItems[i][4]) - if i < #menuItems then - io.write(cfg,",") - end - end - if cfg ~= nil then - io.close(cfg) - end -end - -local function drawConfigMenuBars() - local itemIdx = string.format("%d/%d",menu.selectedItem,#menuItems) - lcd.drawFilledRectangle(0,TOPBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, TOPBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,0,VERSION,MENU_TITLE_COLOR) - lcd.drawFilledRectangle(0,BOTTOMBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, BOTTOMBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,BOTTOMBAR_Y+1,getConfigFilename(),MENU_TITLE_COLOR) - lcd.drawText(BOTTOMBAR_WIDTH,BOTTOMBAR_Y+1,itemIdx,MENU_TITLE_COLOR+RIGHT) -end - -local function incMenuItem(idx) - if menuItems[idx][2] == TYPEVALUE then - menuItems[idx][4] = menuItems[idx][4] + menuItems[idx][9] - if menuItems[idx][4] > menuItems[idx][6] then - menuItems[idx][4] = menuItems[idx][6] - end - else - menuItems[idx][4] = menuItems[idx][4] + 1 - if menuItems[idx][4] > #menuItems[idx][5] then - menuItems[idx][4] = 1 - end - end -end - -local function decMenuItem(idx) - if menuItems[idx][2] == TYPEVALUE then - menuItems[idx][4] = menuItems[idx][4] - menuItems[idx][9] - if menuItems[idx][4] < menuItems[idx][5] then - menuItems[idx][4] = menuItems[idx][5] - end - else - menuItems[idx][4] = menuItems[idx][4] - 1 - if menuItems[idx][4] < 1 then - menuItems[idx][4] = #menuItems[idx][5] - end - end -end - -local function drawItem(idx,flags) - if menuItems[idx][2] == TYPEVALUE then - if menuItems[idx][4] == 0 then - lcd.drawText(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, "---",flags) - else - lcd.drawNumber(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][4],flags+menuItems[idx][8]) - lcd.drawText(MENU_ITEM_X + 50,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][7],flags) - end - else - lcd.drawText(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][5][menuItems[idx][4]],flags) - end -end - -local function drawConfigMenu(event) - drawConfigMenuBars() - if event == EVT_ENTER_BREAK then - if menu.editSelected == true then - -- confirm modified value - saveConfig() - end - menu.editSelected = not menu.editSelected - elseif menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT or event == EVT_PLUS_REPT) then - incMenuItem(menu.selectedItem) - elseif menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT or event == EVT_MINUS_REPT) then - decMenuItem(menu.selectedItem) - elseif not menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT) then - menu.selectedItem = (menu.selectedItem - 1) - if menu.offset >= menu.selectedItem then - menu.offset = menu.offset - 1 - end - elseif not menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT) then - menu.selectedItem = (menu.selectedItem + 1) - if menu.selectedItem - MENU_PAGESIZE > menu.offset then - menu.offset = menu.offset + 1 - end - end - --wrap - if menu.selectedItem > #menuItems then - menu.selectedItem = 1 - menu.offset = 0 - elseif menu.selectedItem < 1 then - menu.selectedItem = #menuItems - menu.offset = MENU_WRAPOFFSET - end - -- - for m=1+menu.offset,math.min(#menuItems,MENU_PAGESIZE+menu.offset) do - lcd.drawText(2,MENU_Y + (m-menu.offset-1)*20, menuItems[m][1],0+0) - if m == menu.selectedItem then - if menu.editSelected then - drawItem(m,INVERS+BLINK) - else - drawItem(m,INVERS) - end - else - drawItem(m,0) - end - end -end - --------------------------- --- RUN --------------------------- -local function run(event) - lcd.clear() - --------------------- - -- CONFIG MENU - --------------------- - drawConfigMenu(event) - return 0 -end -#endif --WIDGET - -local function init() - loadConfig() -end - --------------------------------------------------------------------------------- --- SCRIPT END --------------------------------------------------------------------------------- -return {run=run, init=init} \ No newline at end of file diff --git a/HORUS/SOURCES/rover.lua b/HORUS/SOURCES/rover.lua deleted file mode 100644 index d4063e7f..00000000 --- a/HORUS/SOURCES/rover.lua +++ /dev/null @@ -1,26 +0,0 @@ -local flightModes = {} --- rover flight modes -flightModes[1]="Manual" -flightModes[2]="Acro" -flightModes[4]="Steering" -flightModes[5]="Hold" -flightModes[11]="Auto" -flightModes[12]="RTL" -flightModes[13]="SmartRTL" -flightModes[16]="Guided" -flightModes[17]="Initializing" -flightModes[0]="" -flightModes[6]="" -flightModes[7]="" -flightModes[8]="" -flightModes[9]="" -flightModes[10]="" -flightModes[14]="" -flightModes[15]="" -flightModes[18]="" -flightModes[19]="" -flightModes[20]="" -flightModes[21]="" -flightModes[22]="" --- -return {flightModes=flightModes} diff --git a/HORUS/SOURCES/yaapu0.lua b/HORUS/SOURCES/yaapu0.lua deleted file mode 100644 index a39ea647..00000000 --- a/HORUS/SOURCES/yaapu0.lua +++ /dev/null @@ -1,3937 +0,0 @@ --- --- An FRSKY S.Port based Telemetry script for the Horus X10 and X12 radios --- --- Copyright (C) 2018. Alessandro Apostoli --- https://github.com/yaapu --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- 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. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, see . --- --- Passthrough protocol reference: --- https://cdn.rawgit.com/ArduPilot/ardupilot_wiki/33cd0c2c/images/FrSky_Passthrough_protocol.xlsx --- --- Borrowed some code from the LI-xx BATTCHECK v3.30 script --- http://frskytaranis.forumactif.org/t2800-lua-download-un-testeur-de-batterie-sur-la-radio - ---------------------- --- script version ---------------------- -#define VERSION "Yaapu Telemetry Script 1.7.4" - --- 480x272 LCD_WxLCD_H -#define WIDGET ---#define WIDGETDEBUG ---#define COMPILE ---#define SPLASH ---#define MEMDEBUG --- fix for issue OpenTX 2.2.1 on X10/X10S - https://github.com/opentx/opentx/issues/5764 -#define X10_OPENTX_221 ---#define LOAD_LUA -#ifdef COMPILE -#define LOAD_LUA -#endif ---------------------- --- features ---------------------- ---#define HUD_ALGO1 -#define HUD_ALGO2 -#define HUD_BIG ---#define BATTPERC_BY_VOLTAGE ---#define COMPASS_ROSE -#define UNIT_SCALE ---------------------- --- dev features ---------------------- ---#define LOGTELEMETRY ---#define DEBUG ---#define DEBUGEVT ---#define TESTMODE -#ifdef TESTMODE -#define CELLCOUNT 4 ---#define BATT2TEST ---#define FLVSS2TEST ---#define DEMO -#endif ---#define DEV ---#define DEBUGHUD - --- calc and show background function rate ---#define BGRATE --- calc and show run function rate ---#define FGRATE - --- calc and show hud refresh rate --- default for beta ---#define HUDRATE - ---#define HUDTIMER - --- calc and show telemetry process rate --- default for beta ---#define BGTELERATE - --- calc and show actual incoming telemetry rate ---#define TELERATE - --- - -#define VFAS_ID 0x021F -#define VFAS_SUBID 0 -#define VFAS_INSTANCE 0 -#define VFAS_PRECISION 2 -#define VFAS_NAME "VFAS" - -#define CURR_ID 0x020F -#define CURR_SUBID 0 -#define CURR_INSTANCE 0 -#define CURR_PRECISION 1 -#define CURR_NAME "CURR" - -#define VSpd_ID 0x011F -#define VSpd_SUBID 0 -#define VSpd_INSTANCE 0 -#define VSpd_PRECISION 1 -#define VSpd_NAME "VSpd" - -#define GSpd_ID 0x083F -#define GSpd_SUBID 0 -#define GSpd_INSTANCE 0 -#define GSpd_PRECISION 0 -#define GSpd_NAME "GSpd" - -#define Alt_ID 0x010F -#define Alt_SUBID 0 -#define Alt_INSTANCE 0 -#define Alt_PRECISION 1 -#define Alt_NAME "Alt" - -#define GAlt_ID 0x082F -#define GAlt_SUBID 0 -#define GAlt_INSTANCE 0 -#define GAlt_PRECISION 0 -#define GAlt_NAME "GAlt" - -#define Hdg_ID 0x084F -#define Hdg_SUBID 0 -#define Hdg_INSTANCE 0 -#define Hdg_PRECISION 0 -#define Hdg_NAME "Hdg" - -#define Fuel_ID 0x060F -#define Fuel_SUBID 0 -#define Fuel_INSTANCE 0 -#define Fuel_PRECISION 0 -#define Fuel_NAME "Fuel" - -#define IMUTmp_ID 0x041F -#define IMUTmp_SUBID 0 -#define IMUTmp_INSTANCE 0 -#define IMUTmp_PRECISION 0 -#define IMUTmp_NAME "IMUt" - -#define ARM_ID 0x060F -#define ARM_SUBID 0 -#define ARM_INSTANCE 1 -#define ARM_PRECISION 0 -#define ARM_NAME "ARM" - ---[[ - MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */ - MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */ - MAV_TYPE_QUADROTOR=2, /* Quadrotor | */ - MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */ - MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */ - MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */ - MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */ - MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */ - MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */ - MAV_TYPE_ROCKET=9, /* Rocket | */ - MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */ - MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */ - MAV_TYPE_SUBMARINE=12, /* Submarine | */ - MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */ - MAV_TYPE_OCTOROTOR=14, /* Octorotor | */ - MAV_TYPE_TRICOPTER=15, /* Tricopter | */ - MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */ - MAV_TYPE_KITE=17, /* Kite | */ - MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */ - MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */ - MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */ - MAV_TYPE_VTOL_TILTROTOR=21, /* Tiltrotor VTOL | */ - MAV_TYPE_VTOL_RESERVED2=22, /* VTOL reserved 2 | */ - MAV_TYPE_VTOL_RESERVED3=23, /* VTOL reserved 3 | */ - MAV_TYPE_VTOL_RESERVED4=24, /* VTOL reserved 4 | */ - MAV_TYPE_VTOL_RESERVED5=25, /* VTOL reserved 5 | */ - MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */ - MAV_TYPE_ADSB=27, /* Onboard ADSB peripheral | */ - MAV_TYPE_PARAFOIL=28, /* Steerable, nonrigid airfoil | */ - MAV_TYPE_DODECAROTOR=29, /* Dodecarotor | */ -]]-- - -------------------------------------- --- UNITS Scales from Ardupilot OSD code /ardupilot/libraries/AP_OSD/AP_OSD_Screen.cpp -------------------------------------- ---[[ - static const float scale_metric[UNIT_TYPE_LAST] = { - 1.0, //ALTITUDE m - 3.6, //SPEED km/hr - 1.0, //VSPEED m/s - 1.0, //DISTANCE m - 1.0/1000, //DISTANCE_LONG km - 1.0, //TEMPERATURE C - }; - static const float scale_imperial[UNIT_TYPE_LAST] = { - 3.28084, //ALTITUDE ft - 2.23694, //SPEED mph - 3.28084, //VSPEED ft/s - 3.28084, //DISTANCE ft - 1.0/1609.34, //DISTANCE_LONG miles - 1.8, //TEMPERATURE F - }; - static const float scale_SI[UNIT_TYPE_LAST] = { - 1.0, //ALTITUDE m - 1.0, //SPEED m/s - 1.0, //VSPEED m/s - 1.0, //DISTANCE m - 1.0/1000, //DISTANCE_LONG km - 1.0, //TEMPERATURE C - }; - static const float scale_aviation[UNIT_TYPE_LAST] = { - 3.28084, //ALTITUDE Ft - 1.94384, //SPEED Knots - 196.85, //VSPEED ft/min - 3.28084, //DISTANCE ft - 0.000539957, //DISTANCE_LONG Nm - 1.0, //TEMPERATURE C - }; ---]] -local frameNames = {} --- copter -frameNames[0] = "GEN" -frameNames[2] = "QUAD" -frameNames[3] = "COAX" -frameNames[4] = "HELI" -frameNames[13] = "HEX" -frameNames[14] = "OCTO" -frameNames[15] = "TRI" -frameNames[29] = "DODE" - --- plane -frameNames[1] = "WING" -frameNames[16] = "FLAP" -frameNames[19] = "VTOL2" -frameNames[20] = "VTOL4" -frameNames[21] = "VTOLT" -frameNames[22] = "VTOL" -frameNames[23] = "VTOL" -frameNames[24] = "VTOL" -frameNames[25] = "VTOL" -frameNames[28] = "FOIL" - --- rover -frameNames[10] = "ROV" --- boat -frameNames[11] = "BOAT" - -local currentModel = nil -local frameTypes = {} --- copter -frameTypes[0] = "c" -frameTypes[2] = "c" -frameTypes[3] = "c" -frameTypes[4] = "c" -frameTypes[13] = "c" -frameTypes[14] = "c" -frameTypes[15] = "c" -frameTypes[29] = "c" - --- plane -frameTypes[1] = "p" -frameTypes[16] = "p" -frameTypes[19] = "p" -frameTypes[20] = "p" -frameTypes[21] = "p" -frameTypes[22] = "p" -frameTypes[23] = "p" -frameTypes[24] = "p" -frameTypes[25] = "p" -frameTypes[28] = "p" - --- rover -frameTypes[10] = "r" --- boat -frameTypes[11] = "b" - -#ifdef TESTMODE --- undefined -frameTypes[5] = "" -frameTypes[6] = "" -frameTypes[7] = "" -frameTypes[8] = "" -frameTypes[9] = "" -frameTypes[12] = "" -frameTypes[17] = "" -frameTypes[18] = "" -frameTypes[26] = "" -frameTypes[27] = "" -frameTypes[30] = "" -#endif --TESTMODE --- flightmodes are loaded at run time -local soundFileBasePath = "/SOUNDS/yaapu0" -local gpsStatuses = {} - -gpsStatuses[0]="NoGPS" -gpsStatuses[1]="NoLock" -gpsStatuses[2]="2D" -gpsStatuses[3]="3D" -gpsStatuses[4]="DGPS" -gpsStatuses[5]="RTK" -gpsStatuses[6]="RTK" - ---[[ -0 MAV_SEVERITY_EMERGENCY System is unusable. This is a "panic" condition. -1 MAV_SEVERITY_ALERT Action should be taken immediately. Indicates error in non-critical systems. -2 MAV_SEVERITY_CRITICAL Action must be taken immediately. Indicates failure in a primary system. -3 MAV_SEVERITY_ERROR Indicates an error in secondary/redundant systems. -4 MAV_SEVERITY_WARNING Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. -5 MAV_SEVERITY_NOTICE An unusual event has occured, though not an error condition. This should be investigated for the root cause. -6 MAV_SEVERITY_INFO Normal operational messages. Useful for logging. No action is required for these messages. -7 MAV_SEVERITY_DEBUG Useful non-operational messages that can assist in debugging. These should not occur during normal operation. ---]] - -local mavSeverity = {} -mavSeverity[0]="EMR" -mavSeverity[1]="ALR" -mavSeverity[2]="CRT" -mavSeverity[3]="ERR" -mavSeverity[4]="WRN" -mavSeverity[5]="NOT" -mavSeverity[6]="INF" -mavSeverity[7]="DBG" - -#define CELLFULL 4.35 -#define CELLEMPTY 3.0 --------------------------------- -local status = { - -- FLVSS 1 - cell1min = 0, - cell1sum = 0, - -- FLVSS 2 - cell2min = 0, - cell2sum = 0, - -- FC 1 - cell1sumFC = 0, - -- used to calculate cellcount - cell1maxFC = 0, - -- FC 2 - cell2sumFC = 0, - -- A2 - cellsumA2 = 0, - -- used to calculate cellcount - cellmaxA2 = 0, - -------------------------------- - -- AP STATUS - flightMode = 0, - simpleMode = 0, - landComplete = 0, - statusArmed = 0, - battFailsafe = 0, - ekfFailsafe = 0, - imuTemp = 0, - -- GPS - numSats = 0, - gpsStatus = 0, - gpsHdopC = 100, - gpsAlt = 0, - -- BATT - cellcount = 0, - battsource = "na", - -- BATT 1 - batt1volt = 0, - batt1current = 0, - batt1mah = 0, - batt1sources = { - a2 = false, - vs = false, - fc = false - }, - -- BATT 2 - batt2volt = 0, - batt2current = 0, - batt2mah = 0, - batt2sources = { - a2 = false, - vs = false, - fc = false - }, - -- TELEMETRY - noTelemetryData = 1, - -- HOME - homeDist = 0, - homeAlt = 0, - homeAngle = -1, - -- MESSAGES - msgBuffer = "", - lastMsgValue = 0, - lastMsgTime = 0, - -- VELANDYAW - vSpeed = 0, - hSpeed = 0, - yaw = 0, - -- SYNTH VSPEED SUPPORT - vspd = 0, - synthVSpeedTime = 0, - prevHomeAlt = 0, - -- ROLLPITCH - roll = 0, - pitch = 0, - range = 0, - -- PARAMS - frameType = -1, - batt1Capacity = 0, - batt2Capacity = 0, - -- FLIGHT TIME - lastTimerStart = 0, - timerRunning = 0, - flightTime = 0, - -- EVENTS - lastStatusArmed = 0, - lastGpsStatus = 0, - lastFlightMode = 0, - lastSimpleMode = 0, - -- battery levels - batLevel = 99, - battLevel1 = false, - battLevel2 = false, - lastBattLevel = 14, - -- messages - lastMessage = nil, - lastMessageSeverity = 0, - lastMessageCount = 1, - messageCount = 0, - messages = {} -} -local frame = {} --- -#define BACKLIGHT_GV 8 -#define BACKLIGHT_DURATION 5 -local backlightLastTime = 0 --- ---[[ - ALARM_TYPE_MIN needs arming (min has to be reached first), value below level for grace, once armed is periodic, reset on landing - ALARM_TYPE_MAX no arming, value above level for grace, once armed is periodic, reset on landing - ALARM_TYPE_TIMER no arming, fired periodically, spoken time, reset on landing - ALARM_TYPE_BATT needs arming (min has to be reached first), value below level for grace, no reset on landing -{ - 1 = notified, - 2 = alarm start, - 3 = armed, - 4 = type(0=min,1=max,2=timer,3=batt), - 5 = grace duration - 6 = ready - 7 = last alarm -} ---]] -#define ALARM_NOTIFIED 1 -#define ALARM_START 2 -#define ALARM_ARMED 3 -#define ALARM_TYPE 4 -#define ALARM_GRACE 5 -#define ALARM_READY 6 -#define ALARM_LAST_ALARM 7 --- -#define ALARMS_MIN_ALT 1 -#define ALARMS_MAX_ALT 2 -#define ALARMS_MAX_DIST 3 -#define ALARMS_FS_EKF 4 -#define ALARMS_FS_BATT 5 -#define ALARMS_TIMER 6 -#define ALARMS_BATT_L1 7 -#define ALARMS_BATT_L2 8 --- -#define ALARM_TYPE_MIN 0 -#define ALARM_TYPE_MAX 1 -#define ALARM_TYPE_TIMER 2 -#define ALARM_TYPE_BATT 3 -#define ALARM_TYPE_BATT_CRT 4 --- -#define ALARM_TYPE_BATT_GRACE 4 --- -local alarms = { - --{ notified, alarm_start, armed, type(0=min,1=max,2=timer,3=batt), grace, ready, last_alarm} - { false, 0 , false, ALARM_TYPE_MIN, 0, false, 0}, --MIN_ALT - { false, 0 , true, ALARM_TYPE_MAX, 0, false, 0 }, --MAX_ALT - { false, 0 , true, ALARM_TYPE_MAX, 0, false, 0 }, --MAX_DIST - { false, 0 , true, ALARM_TYPE_MAX, 0, false, 0 }, --FS_EKF - { false, 0 , true, ALARM_TYPE_MAX, 0, false, 0 }, --FS_BAT - { false, 0 , true, ALARM_TYPE_TIMER, 0, false, 0 }, --FLIGTH_TIME - { false, 0 , false, ALARM_TYPE_BATT, ALARM_TYPE_BATT_GRACE, false, 0 }, --BATT L1 - { false, 0 , false, ALARM_TYPE_BATT_CRT, ALARM_TYPE_BATT_GRACE, false, 0 } --BATT L2 -} - --- -local paramId,paramValue --- -local batLevels = {0,5,10,15,20,25,30,40,50,60,70,80,90} --- dual battery -local showDualBattery = false --- -local bitmaps = {} -local blinktime = getTime() -local blinkon = false --- GPS -local function getTelemetryId(name) - local field = getFieldInfo(name) - return field and field.id or -1 -end --- -local gpsDataId = getTelemetryId("GPS") --- -#define MIN_BATT1_FC 1 -#define MIN_BATT2_FC 2 -#define MIN_CELL1_VS 3 -#define MIN_CELL2_VS 4 -#define MIN_BATT1_VS 5 -#define MIN_BATT2_VS 6 -#define MIN_BATT_A2 7 --- -#define MAX_CURR 8 -#define MAX_CURR1 9 -#define MAX_CURR2 10 -#define MAX_POWER 11 -#define MINMAX_ALT 12 -#define MAX_GPSALT 13 -#define MAX_VSPEED 14 -#define MAX_HSPEED 15 -#define MAX_DIST 16 -#define MAX_RANGE 17 --- -local minmaxValues = {} --- min -minmaxValues[1] = 0 -minmaxValues[2] = 0 -minmaxValues[3] = 0 -minmaxValues[4] = 0 -minmaxValues[5] = 0 -minmaxValues[6] = 0 -minmaxValues[7] = 0 --- max -minmaxValues[8] = 0 -minmaxValues[9] = 0 -minmaxValues[10] = 0 -minmaxValues[11] = 0 -minmaxValues[12] = 0 -minmaxValues[13] = 0 -minmaxValues[14] = 0 -minmaxValues[15] = 0 -minmaxValues[16] = 0 -minmaxValues[17] = 0 - -local showMinMaxValues = false --- -#ifdef BATTPERC_BY_VOLTAGE -#define VOLTAGE_DROP 0.15 ---[[ - Example data based on a 18 minutes flight for quad, battery:5200mAh LiPO 10C, hover @15A - Notes: - - when motors are armed VOLTAGE_DROP offset is applied! - - number of samples is fixed at 11 but percentage values can be anything and are not restricted to multiples of 10 - - voltage between samples is assumed to be linear ---]] -local battPercByVoltage = { - {3.40, 0}, - {3.46, 10}, - {3.51, 20}, - {3.53, 30}, - {3.56, 40}, - {3.60, 50}, - {3.63, 60}, - {3.70, 70}, - {3.73, 80}, - {3.86, 90}, - {4.00, 99} - } -#endif --BATTPERC_BY_VOLTAGE - -#ifdef LOGTELEMETRY -local logfile -local logfilename -#endif --LOGTELEMETRY --- -#ifdef TESTMODE --- TEST MODE -local thrOut = 0 -#endif --TESTMODE - -#ifdef HUD_BIG -#define HUD_WIDTH 92 -#define HUD_X (LCD_W-92)/2 -#define HUD_Y_MID 79 -#else -#define HUD_WIDTH 70 -#define HUD_X (LCD_W-70)/2 -#define HUD_Y_MID 80 -#endif - -#define YAW_WIDTH 120 -#define YAW_X (LCD_W-120)/2 -#define YAW_Y 140 - -#define LEFTPANE_X 68 -#define RIGHTPANE_X 68 - -#define TOPBAR_Y 0 -#define TOPBAR_HEIGHT 20 -#define TOPBAR_WIDTH LCD_W - -#define BOTTOMBAR_Y LCD_H - 20 -#define BOTTOMBAR_HEIGHT 20 -#define BOTTOMBAR_WIDTH LCD_W - -#define BOX1_X 0 -#define BOX1_Y 38 -#define BOX1_WIDTH 66 -#define BOX1_HEIGHT 8 - -#define BOX2_X 61 -#define BOX2_Y 46 -#define BOX2_WIDTH 17 -#define BOX2_HEIGHT 12 - -#define BATTCELL_X 33 -#define BATTCELL_Y 13 -#define BATTCELL_XV 171 -#define BATTCELL_YV 23 -#define BATTCELL_YS 60 -#define BATTCELL_FLAGS XXLSIZE+PREC2 - -#define BATTVOLT_X 100 -#define BATTVOLT_Y 164 -#define BATTVOLT_XV 95 -#define BATTVOLT_YV 159 -#define BATTVOLT_FLAGS DBLSIZE+PREC1+RIGHT -#define BATTVOLT_FLAGSV SMLSIZE - -#define BATTCURR_X 192 -#define BATTCURR_Y 164 -#define BATTCURR_XA 186 -#define BATTCURR_YA 159 -#define BATTCURR_FLAGS DBLSIZE+PREC1+RIGHT -#define BATTCURR_FLAGSA SMLSIZE - -#define BATTPERC_X 90 -#define BATTPERC_Y 108 -#define BATTPERC_YPERC 120 -#define BATTPERC_FLAGS MIDSIZE -#define BATTPERC_FLAGSPERC SMLSIZE - -#define BATTGAUGE_X 29 -#define BATTGAUGE_Y 109 -#define BATTGAUGE_WIDTH 160 -#define BATTGAUGE_HEIGHT 23 -#define BATTGAUGE_STEPS 10 - -#define BATTMAH_X 185 -#define BATTMAH_Y 136 -#define BATTMAH_FLAGS MIDSIZE - -#define BATTINFO_B1B2_X 67 -#define BATTINFO_B1_X 75 -#define BATTINFO_B2_X 50 -#define BATTINFO_Y 85 - -#define FLIGHTMODE_X 2 -#define FLIGHTMODE_Y 218 -#define FLIGHTMODE_FLAGS MIDSIZE - -#define HOMEANGLE_X 60 -#define HOMEANGLE_Y 27 -#define HOMEANGLE_XLABEL 3 -#define HOMEANGLE_YLABEL 27 -#define HOMEANGLE_FLAGS SMLSIZE - -#define GPS_X 2 -#define GPS_Y 22 -#define GPS_BORDER 0 - -#define ALTASL_X 75 -#define ALTASL_Y 112 -#define ALTASL_XLABEL 10 -#define ALTASL_YLABEL 95 - -#define HSPEED_X 80 -#define HSPEED_Y 170 -#define HSPEED_XLABEL 81 -#define HSPEED_YLABEL 152 -#define HSPEED_XDIM 55 -#define HSPEED_YDIM 49 -#define HSPEED_FLAGS MIDSIZE -#define HSPEED_ARROW_WIDTH 10 - -#define BATTPOWER_X 165 -#define BATTPOWER_Y 152 -#define BATTPOWER_YW 170 -#define BATTPOWER_FLAGS SMLSIZE -#define BATTPOWER_FLAGSW MIDSIZE - -#define HOMEDIST_X 165 -#define HOMEDIST_Y 112 -#define HOMEDIST_XLABEL 91 -#define HOMEDIST_YLABEL 95 -#define HOMEDIST_FLAGS MIDSIZE -#define HOMEDIST_ARROW_WIDTH 8 - -#define HOMEDIR_X (LCD_W/2) -#define HOMEDIR_Y 202 -#define HOMEDIR_R 17 - -#define FLIGHTTIME_X 330 -#define FLIGHTTIME_Y 202 -#define FLIGHTTIME_FLAGS DBLSIZE - -#define RSSI_X 265 -#define RSSI_Y 0 -#define RSSI_FLAGS 0 - -#define TXVOLTAGE_X 330 -#define TXVOLTAGE_Y 0 -#define TXVOLTAGE_FLAGS 0 - -#define VSPEED_X 180 -#define VSPEED_Y LCD_H-60 -#define VSPEED_FLAGS MIDSIZE -#define VSPEED_XLABEL 170 -#define VSPEED_YLABEL LCD_H-37 -#define VSPEED_FLAGSLABEL SMLSIZE - -#define ALT_X 310 -#define ALT_Y LCD_H-60 -#define ALT_FLAGS MIDSIZE+RIGHT -#define ALT_XLABEL 275 -#define ALT_YLABEL LCD_H-37 -#define ALT_FLAGSLABEL SMLSIZE --- model and opentx version -local ver, radio, maj, minor, rev = getVersion() ------------------------------ --- clears the loaded table --- and recovers memory ------------------------------ -local function clearTable(t) - if type(t)=="table" then - for i,v in pairs(t) do - if type(v) == "table" then - clearTable(v) - end - t[i] = nil - end - end - collectgarbage() - maxmem = 0 -end --------------------------------------------------------------------------------- --- CONFIGURATION MENU --------------------------------------------------------------------------------- -local conf = { - language = "en", - defaultBattSource = nil, -- auto - battAlertLevel1 = 0, - battAlertLevel2 = 0, - battCapOverride1 = 0, - battCapOverride2 = 0, - disableAllSounds = false, - disableMsgBeep = false, - disableMsgBlink = false, - timerAlert = 0, - minAltitudeAlert = 0, - maxAltitudeAlert = 0, - maxDistanceAlert = 0, - cellCount = 0, - enableBattPercByVoltage = false, - rangeMax=0, - enableSynthVSpeed=false, - horSpeedMultiplier=1, - vertSpeedMultiplier=1 -} --------------------------------------------------------------------------------- --- MENU VALUE,COMBO --------------------------------------------------------------------------------- -#define TYPEVALUE 0 -#define TYPECOMBO 1 -#define MENU_Y 25 -#define MENU_PAGESIZE 11 -#define MENU_WRAPOFFSET 8 -#define MENU_ITEM_X 300 - -#define L1 1 -#define V1 2 -#define V2 3 -#define B1 4 -#define B2 5 -#define S1 6 -#define S2 7 -#define S3 8 -#define VS 9 -#define T1 10 -#define A1 11 -#define A2 12 -#define D1 13 -#define T2 14 -#define CC 15 -#define RM 16 -#define SVS 17 -#define HSPD 18 -#define VSPD 19 -#define BPBV 20 - -local menu = { - selectedItem = 1, - editSelected = false, - offset = 0 -} - - -#define SENSOR_LABEL 1 -#define SENSOR_NAME 2 -#define SENSOR_PREC 3 -#define SENSOR_UNIT 4 -#define SENSOR_TYPE 5 -#define SENSOR_MULT 6 - --- max 4 extra sensors -local customSensors = { - -- {label,name,prec:0,1,2,unit,stype:I,E,1} -} - -local menuItems = {} - -- label, type, alias, currval, min, max, label, flags, increment -menuItems[L1] = {"voice language:", TYPECOMBO, "L1", 1, { "english", "italian", "french", "german" } , {"en","it","fr","de"} } -menuItems[V1] = {"batt alert level 1:", TYPEVALUE, "V1", 375, 0,5000,"V", PREC2 ,5 } -menuItems[V2] = {"batt alert level 2:", TYPEVALUE, "V2", 350, 0,5000,"V", PREC2 ,5 } -menuItems[B1] = {"batt[1] capacity override:", TYPEVALUE, "B1", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[B2] = {"batt[2] capacity override:", TYPEVALUE, "B2", 0, 0,5000,"Ah",PREC2 ,10 } -menuItems[S1] = {"disable all sounds:", TYPECOMBO, "S1", 1, { "no", "yes" }, { false, true } } -menuItems[S2] = {"disable msg beep:", TYPECOMBO, "S2", 1, { "no", "yes" }, { false, true } } -menuItems[S3] = {"disable msg blink:", TYPECOMBO, "S3", 1, { "no", "yes" }, { false, true } } -menuItems[VS] = {"default voltage source:", TYPECOMBO, "VS", 1, { "auto", "FLVSS", "A2", "fc" }, { nil, "vs", "a2", "fc" } } -menuItems[T1] = {"timer alert every:", TYPEVALUE, "T1", 0, 0,600,"min",PREC1,5 } -menuItems[A1] = {"min altitude alert:", TYPEVALUE, "A1", 0, 0,500,"m",PREC1,5 } -menuItems[A2] = {"max altitude alert:", TYPEVALUE, "A2", 0, 0,10000,"m",0,1 } -menuItems[D1] = {"max distance alert:", TYPEVALUE, "D1", 0, 0,100000,"m",0,10 } -menuItems[T2] = {"repeat alerts every:", TYPEVALUE, "T2", 10, 5,600,"sec",0,5 } -menuItems[CC] = {"cell count override:", TYPEVALUE, "CC", 0, 0,12,"cells",0,1 } -menuItems[RM] = {"rangefinder max:", TYPEVALUE, "RM", 0, 0,10000," cm",0,10 } -menuItems[SVS] = {"enable synthetic vspeed:", TYPECOMBO, "SVS", 1, { "no", "yes" }, { false, true } } -menuItems[HSPD] = {"air/groundspeed unit:", TYPECOMBO, "HSPD", 1, { "m/s", "km/h", "mph", "kn" }, { 1, 3.6, 2.23694, 1.94384} } -menuItems[VSPD] = {"vertical speed unit:", TYPECOMBO, "VSPD", 1, { "m/s", "ft/s", "ft/min" }, { 1, 3.28084, 196.85} } -#ifdef BATTPERC_BY_VOLTAGE -menuItems[BPBV] = {"enable battery % by voltage:", TYPECOMBO, "BPBV", 1, { "no", "yes" }, { false, true } } -#endif --BATTPERC_BY_VOLTAGE --- - -#ifdef UNIT_SCALE - -local unitScale, unitlabel - -#define UNIT_ALT_SCALE unitScale -#define UNIT_DIST_SCALE unitScale -#define UNIT_DIST_LONG_SCALE (getGeneralSettings().imperial==0 and 1/1000 or 1/1609.34) -#define UNIT_HSPEED_SCALE menuItems[HSPD][6][menuItems[HSPD][4]] -#define UNIT_VSPEED_SCALE menuItems[VSPD][6][menuItems[VSPD][4]] -#define UNIT_ALT_LABEL unitLabel -#define UNIT_DIST_LABEL unitLabel -#define UNIT_HSPEED_LABEL menuItems[HSPD][5][menuItems[HSPD][4]] -#define UNIT_VSPEED_LABEL menuItems[VSPD][5][menuItems[VSPD][4]] - -#endif --UNIT_SCALE - -#ifdef WIDGET -local currentPage = 0 -#endif - -local function getConfigFilename() - local info = model.getInfo() - return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".cfg") -end - -local function getBitmap(name) - if bitmaps[name] == nil then - bitmaps[name] = Bitmap.open("/SCRIPTS/YAAPU/IMAGES/"..name..".png") - end - return bitmaps[name] -end - -local function applyConfigValues() - conf.language = menuItems[L1][6][menuItems[L1][4]] - conf.battAlertLevel1 = menuItems[V1][4] - conf.battAlertLevel2 = menuItems[V2][4] - conf.battCapOverride1 = menuItems[B1][4]*0.1 - conf.battCapOverride2 = menuItems[B2][4]*0.1 - conf.disableAllSounds = menuItems[S1][6][menuItems[S1][4]] - conf.disableMsgBeep = menuItems[S2][6][menuItems[S2][4]] - conf.disableMsgBlink = menuItems[S3][6][menuItems[S3][4]] - conf.defaultBattSource = menuItems[VS][6][menuItems[VS][4]] - conf.timerAlert = math.floor(menuItems[T1][4]*0.1*60) - conf.minAltitudeAlert = menuItems[A1][4]*0.1 - conf.maxAltitudeAlert = menuItems[A2][4] - conf.maxDistanceAlert = menuItems[D1][4] - conf.cellCount = menuItems[CC][4] - conf.rangeMax = menuItems[RM][4] - conf.enableSynthVSpeed = menuItems[SVS][6][menuItems[SVS][4]] - conf.horSpeedMultiplier = menuItems[HSPD][6][menuItems[HSPD][4]] - conf.vertSpeedMultiplier = menuItems[VSPD][6][menuItems[VSPD][4]] -#ifdef BATTPERC_BY_VOLTAGE - conf.enableBattPercByVoltage = menuItems[BPBV][6][menuItems[BPBV][4]] -#endif --BATTPERC_BY_VOLTAGE - -- - if conf.defaultBattSource ~= nil then - status.battsource = conf.defaultBattSource - end -end - -local function loadConfig() - local cfg = io.open(getConfigFilename(),"r") - if cfg == nil then - return - end - local str = io.read(cfg,200) - if string.len(str) > 0 then - for i=1,#menuItems - do - local value = string.match(str, menuItems[i][3]..":(%d+)") - if value ~= nil then - menuItems[i][4] = tonumber(value) - end - end - end - if cfg ~= nil then - io.close(cfg) - end - applyConfigValues() -end - -local function saveConfig() - local cfg = assert(io.open(getConfigFilename(),"w")) - if cfg == nil then - return - end - for i=1,#menuItems - do - io.write(cfg,menuItems[i][3],":",menuItems[i][4]) - if i < #menuItems then - io.write(cfg,",") - end - end - if cfg ~= nil then - io.close(cfg) - end - applyConfigValues() -end - -#ifndef WIDGET -local function drawConfigMenuBars() - local itemIdx = string.format("%d/%d",menu.selectedItem,#menuItems) - lcd.drawFilledRectangle(0,TOPBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, TOPBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,0,VERSION,MENU_TITLE_COLOR) - lcd.drawFilledRectangle(0,BOTTOMBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawRectangle(0, BOTTOMBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - lcd.drawText(2,BOTTOMBAR_Y+1,getConfigFilename(),MENU_TITLE_COLOR) - lcd.drawText(BOTTOMBAR_WIDTH,BOTTOMBAR_Y+1,itemIdx,MENU_TITLE_COLOR+RIGHT) -end - -local function incMenuItem(idx) - if menuItems[idx][2] == TYPEVALUE then - menuItems[idx][4] = menuItems[idx][4] + menuItems[idx][9] - if menuItems[idx][4] > menuItems[idx][6] then - menuItems[idx][4] = menuItems[idx][6] - end - else - menuItems[idx][4] = menuItems[idx][4] + 1 - if menuItems[idx][4] > #menuItems[idx][5] then - menuItems[idx][4] = 1 - end - end -end - -local function decMenuItem(idx) - if menuItems[idx][2] == TYPEVALUE then - menuItems[idx][4] = menuItems[idx][4] - menuItems[idx][9] - if menuItems[idx][4] < menuItems[idx][5] then - menuItems[idx][4] = menuItems[idx][5] - end - else - menuItems[idx][4] = menuItems[idx][4] - 1 - if menuItems[idx][4] < 1 then - menuItems[idx][4] = #menuItems[idx][5] - end - end -end - -local function drawItem(idx,flags) - if menuItems[idx][2] == TYPEVALUE then - if menuItems[idx][4] == 0 then - lcd.drawText(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, "---",flags) - else - lcd.drawNumber(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][4],flags+menuItems[idx][8]) - lcd.drawText(MENU_ITEM_X + 50,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][7],flags) - end - else - lcd.drawText(MENU_ITEM_X,MENU_Y + (idx-menu.offset-1)*20, menuItems[idx][5][menuItems[idx][4]],flags) - end -end - -local function drawConfigMenu(event) - drawConfigMenuBars() - if event == EVT_ENTER_BREAK then - menu.editSelected = not menu.editSelected - elseif menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT or event == EVT_PLUS_REPT) then - incMenuItem(menu.selectedItem) - elseif menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT or event == EVT_MINUS_REPT) then - decMenuItem(menu.selectedItem) - elseif not menu.editSelected and (event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT) then - menu.selectedItem = (menu.selectedItem - 1) - if menu.offset >= menu.selectedItem then - menu.offset = menu.offset - 1 - end - elseif not menu.editSelected and (event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT) then - menu.selectedItem = (menu.selectedItem + 1) - if menu.selectedItem - MENU_PAGESIZE > menu.offset then - menu.offset = menu.offset + 1 - end - end - --wrap - if menu.selectedItem > #menuItems then - menu.selectedItem = 1 - menu.offset = 0 - elseif menu.selectedItem < 1 then - menu.selectedItem = #menuItems - menu.offset = MENU_WRAPOFFSET - end - -- - for m=1+menu.offset,math.min(#menuItems,MENU_PAGESIZE+menu.offset) do - lcd.drawText(2,MENU_Y + (m-menu.offset-1)*20, menuItems[m][1],0+0) - if m == menu.selectedItem then - if menu.editSelected then - drawItem(m,INVERS+BLINK) - else - drawItem(m,INVERS) - end - else - drawItem(m,0) - end - end -end -#endif --WIDGET --- -local function lcdBacklightOn() - model.setGlobalVariable(BACKLIGHT_GV,0,1) - backlightLastTime = getTime()/100 -- seconds -end --- -local function playSound(soundFile) - if conf.disableAllSounds then - return - end - lcdBacklightOn() - playFile(soundFileBasePath .."/"..conf.language.."/".. soundFile..".wav") -end - ----------------------------------------------- --- sound file has same name as flightmode all lowercase with .wav extension ----------------------------------------------- -local function playSoundByFrameTypeAndFlightMode(flightMode) - if conf.disableAllSounds then - return - end - if frame.flightModes then - if frame.flightModes[flightMode] ~= nil then - lcdBacklightOn() - playFile(soundFileBasePath.."/"..conf.language.."/".. string.lower(frame.flightModes[flightMode])..".wav") - end - end -end - -local function drawHArrow(x,y,width,left,right) - lcd.drawLine(x, y, x + width,y, SOLID, 0) - if left == true then - lcd.drawLine(x + 1,y - 1,x + 2,y - 2, SOLID, 0) - lcd.drawLine(x + 1,y + 1,x + 2,y + 2, SOLID, 0) - end - if right == true then - lcd.drawLine(x + width - 1,y - 1,x + width - 2,y - 2, SOLID, 0) - lcd.drawLine(x + width - 1,y + 1,x + width - 2,y + 2, SOLID, 0) - end -end --- -local function drawBlinkBitmap(bitmap,x,y) - if blinkon == true then - lcd.drawBitmap(getBitmap(bitmap),x,y) - end -end --- -local function drawVArrow(x,y,h,top,bottom) - if top == true then - drawBlinkBitmap("uparrow",x,y) - else - drawBlinkBitmap("downarrow",x,y) - end -end - -local function drawHomeIcon(x,y) - lcd.drawBitmap(getBitmap("minihomeorange"),x,y) -end - -#ifdef X10_OPENTX_221 -local function drawLine(x1,y1,x2,y2,flags1,flags2) - -- if lines are hor or ver do not fix ---if string.find(radio, "x10") and rev < 2 and x1 ~= x2 and y1 ~= y2 then - if string.find(radio, "x10") and rev < 2 then - lcd.drawLine(LCD_W-x1,LCD_H-y1,LCD_W-x2,LCD_H-y2,flags1,flags2) - else - lcd.drawLine(x1,y1,x2,y2,flags1,flags2) - end -end -#endif --X10_OPENTX_221 - -#define CS_INSIDE 0 -#define CS_LEFT 1 -#define CS_RIGHT 2 -#define CS_BOTTOM 4 -#define CS_TOP 8 - -local function computeOutCode(x,y,xmin,ymin,xmax,ymax) - local code = CS_INSIDE; --initialised as being inside of hud - -- - if x < xmin then --to the left of hud - code = bit32.bor(code,CS_LEFT); - elseif x > xmax then --to the right of hud - code = bit32.bor(code,CS_RIGHT); - end - if y < ymin then --below the hud - code = bit32.bor(code,CS_BOTTOM); - elseif y > ymax then --above the hud - code = bit32.bor(code,CS_TOP); - end - -- - return code; -end - --- Cohen–Sutherland clipping algorithm --- https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm -local function drawLineWithClipping(ox,oy,angle,len,style,xmin,xmax,ymin,ymax,color) - -- - local xx = math.cos(math.rad(angle)) * len * 0.5 - local yy = math.sin(math.rad(angle)) * len * 0.5 - -- - local x0 = ox - xx - local x1 = ox + xx - local y0 = oy - yy - local y1 = oy + yy - -- compute outcodes for P0, P1, and whatever point lies outside the clip rectangle - local outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax); - local outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); - local accept = false; - - while (true) do - if ( bit32.bor(outcode0,outcode1) == CS_INSIDE) then - -- bitwise OR is 0: both points inside window; trivially accept and exit loop - accept = true; - break; - elseif (bit32.band(outcode0,outcode1) ~= CS_INSIDE) then - -- bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP, BOTTOM) - -- both must be outside window; exit loop (accept is false) - break; - else - -- failed both tests, so calculate the line segment to clip - -- from an outside point to an intersection with clip edge - local x = 0 - local y = 0 - -- At least one endpoint is outside the clip rectangle; pick it. - local outcodeOut = outcode0 ~= CS_INSIDE and outcode0 or outcode1 - -- No need to worry about divide-by-zero because, in each case, the - -- outcode bit being tested guarantees the denominator is non-zero - if bit32.band(outcodeOut,CS_TOP) ~= CS_INSIDE then --point is above the clip window - x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0) - y = ymax - elseif bit32.band(outcodeOut,CS_BOTTOM) ~= CS_INSIDE then --point is below the clip window - x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0) - y = ymin - elseif bit32.band(outcodeOut,CS_RIGHT) ~= CS_INSIDE then --point is to the right of clip window - y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0) - x = xmax - elseif bit32.band(outcodeOut,CS_LEFT) ~= CS_INSIDE then --point is to the left of clip window - y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0) - x = xmin - end - -- Now we move outside point to intersection point to clip - -- and get ready for next pass. - if outcodeOut == outcode0 then - x0 = x - y0 = y - outcode0 = computeOutCode(x0, y0, xmin, ymin, xmax, ymax) - else - x1 = x - y1 = y - outcode1 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax) - end - end - end - if accept then -#ifdef X10_OPENTX_221 - drawLine(x0,y0,x1,y1, style,color) -#else - lcd.drawLine(x0,y0,x1,y1, style,color) -#endif - end -end - -#ifdef DEV -local function draw8(x0,y0,x,y) - lcd.drawPoint(x0 + x, y0 + y); - lcd.drawPoint(x0 + y, y0 + x); - lcd.drawPoint(x0 - y, y0 + x); - lcd.drawPoint(x0 - x, y0 + y); - lcd.drawPoint(x0 - x, y0 - y); - lcd.drawPoint(x0 - y, y0 - x); - lcd.drawPoint(x0 + y, y0 - x); - lcd.drawPoint(x0 + x, y0 - y); -end - -local function drawCircle10(x0,y0) - draw8(x0,y0,5,1) - draw8(x0,y0,5,2) - draw8(x0,y0,4,3) - draw8(x0,y0,4,4) - lcd.drawPoint(x0 + 5,y0) - lcd.drawPoint(x0 - 5,y0) - lcd.drawPoint(x0,y0 + 5) - lcd.drawPoint(x0,y0 - 5) -end - -local function drawCircle(x0,y0,radius,delta) - local x = radius-1 - local y = 0 - local dx = delta - local dy = delta - local err = dx - bit32.lshift(radius,1) - while (x >= y) do - lcd.drawPoint(x0 + x, y0 + y); - lcd.drawPoint(x0 + y, y0 + x); - lcd.drawPoint(x0 - y, y0 + x); - lcd.drawPoint(x0 - x, y0 + y); - lcd.drawPoint(x0 - x, y0 - y); - lcd.drawPoint(x0 - y, y0 - x); - lcd.drawPoint(x0 + y, y0 - x); - lcd.drawPoint(x0 + x, y0 - y); - if err <= 0 then - y=y+1 - err = err + dy - dy = dy + 2 - end - if err > 0 then - - x=x-1 - dx = dx + 2 - err = err + dx - bit32.lshift(radius,1) - end - end -end - -local function drawHomePad(x0,y0) - drawCircle(x0 + 5,y0,5,2) - lcd.drawText(x0 + 5 - 2,y0 - 3,"H") -end -#endif --DEV - -local function drawNumberWithTwoDims(x,y,xDim,yTop,yBottom,number,topDim,bottomDim,flags,topFlags,bottomFlags) - --PREC2 forces a math.floor() whereas a math.round() is required, math.round(f) = math.floor(f+0.5) - lcd.drawNumber(x, y, number + 0.5, flags) - local lx = xDim - lcd.drawText(lx, yTop, topDim, topFlags) - lcd.drawText(lx, yBottom, bottomDim, bottomFlags) -end - -local function drawNumberWithDim(x,y,xDim,yDim,number,dim,flags,dimFlags) - lcd.drawNumber(x, y, number,flags) - lcd.drawText(xDim, yDim, dim, dimFlags) -end - -#ifdef LOGTELEMETRY -local function getLogFilename(date) - local info = model.getInfo() - local modelName = string.lower(string.gsub(info.name, "[%c%p%s%z]", "")) - return string.format("%s-%04d%02d%02d_%02d%02d%02d.plog",modelName,date.year,date.mon,date.day,date.hour,date.min,date.sec) -end -local function logTelemetryToFile(lc1,lc2,lc3,lc4) - -- flight time - local fmins = math.floor(flightTime / 60) - local fsecs = flightTime % 60 - -- local date tiime from radio - io.write(logfile,string.format("%d;%02d:%02d;%#01x;%#01x;%#02x;%#04x",getTime(),fmins,fsecs, lc1, lc2, lc3, lc4),"\r\n") -end -#endif --LOGTELEMETRY --- -#define MAX_MESSAGES 17 --- -local function formatMessage(severity,msg) - if status.lastMessageCount > 1 then - return string.format("%02d:%s (x%d) %s", status.messageCount, mavSeverity[severity], status.lastMessageCount, msg) - else - return string.format("%02d:%s %s", status.messageCount, mavSeverity[severity], msg) - end -end - -local function pushMessage(severity, msg) - if conf.disableMsgBeep == false and conf.disableAllSounds == false then - if ( severity < 5) then - playSound("../err") - else - playSound("../inf") - end - end - -- check if wrapping is needed - if #status.messages == MAX_MESSAGES and msg ~= status.lastMessage then - for i=1,MAX_MESSAGES-1 do - status.messages[i]=status.messages[i+1] - end - -- trunc at 9 - status.messages[MAX_MESSAGES] = nil - end - -- is it a duplicate? - if msg == status.lastMessage then - status.lastMessageCount = status.lastMessageCount + 1 - status.messages[#status.messages] = formatMessage(severity,msg) - else - status.lastMessageCount = 1 - status.messageCount = status.messageCount + 1 - status.messages[#status.messages+1] = formatMessage(severity,msg) - end - status.lastMessage = msg - status.lastMessageSeverity = severity -#ifdef COLLECTGARBAGE - collectgarbage() -#endif -end - -#ifndef WIDGET -local function getSensorsConfigFilename() - local info = model.getInfo() - return "/SCRIPTS/YAAPU/CFG/" .. string.lower(string.gsub(info.name, "[%c%p%s%z]", "")..".sensors") -end - -local function loadSensors() - local cfg = io.open(getSensorsConfigFilename(),"r") - if cfg == nil then - return - end - local str = io.read(cfg,200) - if string.len(str) > 0 then - for i=1,4 - do - local label, name, prec, unit, stype, mult = string.match(str, "S"..i..":(%w+),([A-Za-z0-9]+),(%d+),([A-Za-z0-9//%%]+),(%a+),(%d+)") - if label ~= nil and name ~= nil and prec ~= nil and unit ~= nil and stype ~= nil then - customSensors[i] = { label, name, prec, unit, stype, mult } - pushMessage(7,"Custom sensor enabled: "..label) - end - end - end - -- - if cfg ~= nil then - io.close(cfg) - end -end - -local customSensorXY = { - { HSPEED_XLABEL, ALTASL_YLABEL, ALTASL_X, ALTASL_Y}, - { HOMEDIST_X, HOMEDIST_YLABEL, HOMEDIST_X, HOMEDIST_Y}, - { HSPEED_XLABEL, HSPEED_YLABEL, HSPEED_X, HSPEED_Y}, - { BATTPOWER_X, BATTPOWER_Y, BATTPOWER_X, BATTPOWER_YW } -} - -local function drawCustomSensors() - local label,data,prec,mult - for i=1,4 - do - if customSensors[i] ~= nil then - label = string.format("%s(%s)",customSensors[i][SENSOR_LABEL],customSensors[i][SENSOR_UNIT]) - lcd.drawText(customSensorXY[i][1], customSensorXY[i][2],label, SMLSIZE+RIGHT) - mult = tonumber(customSensors[i][SENSOR_PREC]) - mult = mult == 0 and 1 or ( mult == 1 and 10 or 100 ) - prec = mult == 1 and 0 or (mult == 10 and 32 or 48) - lcd.drawNumber(customSensorXY[i][3], customSensorXY[i][4], getValue(customSensors[i][SENSOR_NAME])*mult*customSensors[i][SENSOR_MULT], MIDSIZE+RIGHT+prec) - end - end -end -#endif --WIDGET --- -local function startTimer() - status.lastTimerStart = getTime()/100 - model.setTimer(2,{mode=1}) -end - -local function stopTimer() - model.setTimer(2,{mode=0}) - status.lastTimerStart = 0 -end - -#ifdef TESTMODE ------------------------------------------------------ --- TEST MODE ------------------------------------------------------ -local function symTimer() - thrOut = getValue("thr") - if (thrOut > 200 ) then - status.landComplete = 1 - else - status.landComplete = 0 - end -end - -local function symGPS() - thrOut = getValue("thr") - if thrOut > 200 then - status.numSats = 15 - status.gpsStatus = 4 - status.gpsHdopC = 6 - status.ekfFailsafe = 0 - status.battFailsafe = 0 - status.noTelemetryData = 0 - status.statusArmed = 1 - elseif thrOut < 200 and thrOut > 0 then - status.vnumSats = 13 - status.gpsStatus = 5 - status.gpsHdopC = 1000 - status.ekfFailsafe = 1 - status.battFailsafe = 0 - status.noTelemetryData = 0 - status.statusArmed = 1 - elseif thrOut > -500 then - status.numSats = 6 - status.gpsStatus = 1 - status.gpsHdopC = 120 - status.ekfFailsafe = 0 - status.battFailsafe = 1 - status.noTelemetryData = 0 - status.statusArmed = 0 - else - status.numSats = 0 - status.gpsStatus = 0 - status.gpsHdopC = 100 - status.ekfFailsafe = 0 - status.battFailsafe = 0 - status.noTelemetryData = 1 - status.statusArmed = 0 - end -end - -local function symFrameType() - local ch11 = getValue("ch11") - if ch11 < -300 then - status.frameType = 2 - elseif ch11 < 300 then - status.frameType = 1 - else - status.frameType = 10 - end -end - -local function symBatt() - thrOut = getValue("thr") - if (thrOut > -500 ) then -#ifdef DEMO - if status.battFailsafe == 1 then - minmaxValues[MIN_BATT1_FC] = CELLCOUNT * 3.40 - minmaxValues[MIN_BATT2_FC] = CELLCOUNT * 3.43 - minmaxValues[MAX_CURR] = 341 + 335 - minmaxValues[MAX_CURR1] = 341 - minmaxValues[MAX_CURR2] = 335 - minmaxValues[MAX_POWER] = (CELLCOUNT * 3.43)*(34.1 + 33.5) - -- battery voltage - status.batt1current = 235 - status.batt1volt = CELLCOUNT * 3.43 * 10 - status.batt1Capacity = 5200 - status.batt1mah = 4400 -#ifdef BATT2TEST - status.batt2current = 238 - status.batt2volt = CELLCOUNT * 3.44 * 10 - status.batt2Capacity = 5200 - status.batt2mah = 4500 -#endif --BATT2TEST - else - minmaxValues[MIN_BATT1_FC] = CELLCOUNT * 3.75 - minmaxValues[MIN_BATT2_FC] = CELLCOUNT * 3.77 - minmaxValues[MAX_CURR] = 341+335 - minmaxValues[MAX_CURR1] = 341 - minmaxValues[MAX_CURR2] = 335 - minmaxValues[MAX_POWER] = (CELLCOUNT * 3.89)*(34.1+33.5) - -- battery voltage - status.batt1current = 235 - status.batt1volt = CELLCOUNT * 3.87 * 10 - status.batt1Capacity = 5200 - status.batt1mah = 2800 -#ifdef BATT2TEST - status.batt2current = 238 - status.batt2volt = CELLCOUNT * 3.89 * 10 - status.batt2Capacity = 5200 - status.batt2mah = 2700 -#endif --BATT2TEST - end -#else --DEMO - -- battery voltage - status.batt1current = 100 + ((thrOut)*0.01 * 30) - status.batt1volt = CELLCOUNT * (32 + 10*math.abs(thrOut)*0.001) - status.batt1Capacity = 5200 - status.batt1mah = math.abs(1000*(thrOut/200)) -#ifdef BATT2TEST - status.batt2current = 100 + ((thrOut)*0.01 * 30) - status.batt2volt = CELLCOUNT * (32 + 10*math.abs(thrOut)*0.001) - status.batt2Capacity = 5200 - status.batt2mah = math.abs(1000*(thrOut/200)) -#endif --BATT2TEST -#endif --DEMO - -- flightmode -#ifdef DEMO - status.flightMode = 1 - minmaxValues[MAX_GPSALT] = 270*0.1 - minmaxValues[MAX_DIST] = 130 - status.gpsAlt = 200 - status.homeDist = 95 -#else --DEMO - status.flightMode = math.floor(20 * math.abs(thrOut)*0.001) - status.gpsAlt = math.floor(10 * math.abs(thrOut)*0.1) - status.homeDist = math.floor(10 * math.abs(thrOut)*0.1) -#endif --DEMO - else - status.batt1mah = 0 - end -end - --- simulates attitude by using channel 1 for roll, channel 2 for pitch and channel 4 for yaw -local function symAttitude() -#ifdef DEMO - status.roll = 14 - status.pitch = -0.8 - status.yaw = 33 -#else --DEMO - local rollCh = 0 - local pitchCh = 0 - local yawCh = 0 - -- roll [-1024,1024] ==> [-180,180] - rollCh = getValue("ch1") * 0.5 -- 0.175 - -- pitch [1024,-1024] ==> [-90,90] - pitchCh = getValue("ch2") * 0.0878 * 5 - -- yaw [-1024,1024] ==> [0,360] - yawCh = getValue("ch10") - if ( yawCh >= 0) then - yawCh = yawCh * 0.175 - else - yawCh = 360 + (yawCh * 0.175) - end - status.roll = rollCh/3 - status.pitch = pitchCh/2 - status.yaw = yawCh -#endif --DEMO -end - -local function symHome() - local yawCh = 0 - local S2Ch = 0 - -- home angle in deg [0-360] - S2Ch = getValue("ch12") - yawCh = getValue("ch4") -#ifdef DEMO - minmaxValues[MINMAX_ALT] = 45 - minmaxValues[MAX_VSPEED] = 4 - minmaxValues[MAX_HSPEED] = 77 - status.homeAlt = 24 - status.vSpeed = 24 - status.hSpeed = 34 -#else --DEMO - status.homeAlt = yawCh * 0.1 - status.range = 10 * yawCh * 0.1 - status.vSpeed = yawCh * 0.1 * -1 - status.hSpeed = status.vSpeed -#endif --DEMO - if ( yawCh >= 0) then - yawCh = yawCh * 0.175 - else - yawCh = 360 + (yawCh * 0.175) - end - status.yaw = yawCh - if ( S2Ch >= 0) then - S2Ch = S2Ch * 0.175 - else - S2Ch = 360 + (S2Ch * 0.175) - end - if (thrOut > 0 ) then - status.homeAngle = S2Ch - else - status.homeAngle = -1 - end -end - -local function symMode() - symGPS() - symAttitude() - symTimer() - symHome() - symBatt() - symFrameType() -end -#endif --TESTMODE - ------------------------------------------------------------------ --- TELEMETRY ------------------------------------------------------------------ -#ifdef TELERATE -local telecounter = 0 -local telerate = 0 -local telestart = 0 -#endif --TELERATE -#ifdef LOGTELEMETRY -local lastAttiLogTime = 0 -#endif --LOGTELEMETRY --- -local function processTelemetry() - local SENSOR_ID,FRAME_ID,DATA_ID,VALUE = sportTelemetryPop() - if ( FRAME_ID == 0x10) then -#ifdef LOGTELEMETRY - -- log all pitch and roll at ma - if lastAttiLogTime == 0 then - logTelemetryToFile(SENSOR_ID,FRAME_ID,DATA_ID,VALUE) - lastAttiLogTime = getTime() - elseif DATA_ID == 0x5006 and getTime() - lastAttiLogTime > 100 then -- 1000ms - logTelemetryToFile(SENSOR_ID,FRAME_ID,DATA_ID,VALUE) - lastAttiLogTime = getTime() - else - logTelemetryToFile(SENSOR_ID,FRAME_ID,DATA_ID,VALUE) - end -#endif --LOGTELEMETRY -#ifdef TELERATE - ------------------------ - -- CALC ACTUAL TELE RATE - ------------------------ - local now = getTime()/100 - if telecounter == 0 then - telestart = now - else - telerate = telecounter / (now - telestart) - end - -- - telecounter=telecounter+1 -#endif --TELERATE - status.noTelemetryData = 0 - if ( DATA_ID == 0x5006) then -- ROLLPITCH - -- roll [0,1800] ==> [-180,180] - status.roll = (math.min(bit32.extract(VALUE,0,11),1800) - 900) * 0.2 - -- pitch [0,900] ==> [-90,90] - status.pitch = (math.min(bit32.extract(VALUE,11,10),900) - 450) * 0.2 - -- #define ATTIANDRNG_RNGFND_OFFSET 21 - -- number encoded on 11 bits: 10 bits for digits + 1 for 10^power - status.range = bit32.extract(VALUE,22,10) * (10^bit32.extract(VALUE,21,1)) -- cm - elseif ( DATA_ID == 0x5005) then -- VELANDYAW - status.vSpeed = bit32.extract(VALUE,1,7) * (10^bit32.extract(VALUE,0,1)) * (bit32.extract(VALUE,8,1) == 1 and -1 or 1)-- dm/s - status.hSpeed = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) -- dm/s - status.yaw = bit32.extract(VALUE,17,11) * 0.2 - elseif ( DATA_ID == 0x5001) then -- AP STATUS - status.flightMode = bit32.extract(VALUE,0,5) - status.simpleMode = bit32.extract(VALUE,5,2) - status.landComplete = bit32.extract(VALUE,7,1) - status.statusArmed = bit32.extract(VALUE,8,1) - status.battFailsafe = bit32.extract(VALUE,9,1) - status.ekfFailsafe = bit32.extract(VALUE,10,2) - -- IMU temperature: 0 means temp =< 19°, 63 means temp => 82° - status.imuTemp = bit32.extract(VALUE,26,6) + 19 -- C° - elseif ( DATA_ID == 0x5002) then -- GPS STATUS - status.numSats = bit32.extract(VALUE,0,4) - -- offset 4: NO_GPS = 0, NO_FIX = 1, GPS_OK_FIX_2D = 2, GPS_OK_FIX_3D or GPS_OK_FIX_3D_DGPS or GPS_OK_FIX_3D_RTK_FLOAT or GPS_OK_FIX_3D_RTK_FIXED = 3 - -- offset 14: 0: no advanced fix, 1: GPS_OK_FIX_3D_DGPS, 2: GPS_OK_FIX_3D_RTK_FLOAT, 3: GPS_OK_FIX_3D_RTK_FIXED - status.gpsStatus = bit32.extract(VALUE,4,2) + bit32.extract(VALUE,14,2) - status.gpsHdopC = bit32.extract(VALUE,7,7) * (10^bit32.extract(VALUE,6,1)) -- dm - status.gpsAlt = bit32.extract(VALUE,24,7) * (10^bit32.extract(VALUE,22,2)) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1)-- dm - elseif ( DATA_ID == 0x5003) then -- BATT - status.batt1volt = bit32.extract(VALUE,0,9) - status.batt1current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) - status.batt1mah = bit32.extract(VALUE,17,15) -#ifdef BATT2TEST - status.batt2volt = bit32.extract(VALUE,0,9) - status.batt2current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) - status.batt2mah = bit32.extract(VALUE,17,15) -#endif --BATT2TEST - elseif ( DATA_ID == 0x5008) then -- BATT2 - status.batt2volt = bit32.extract(VALUE,0,9) - status.batt2current = bit32.extract(VALUE,10,7) * (10^bit32.extract(VALUE,9,1)) - status.batt2mah = bit32.extract(VALUE,17,15) - elseif ( DATA_ID == 0x5004) then -- HOME - status.homeDist = bit32.extract(VALUE,2,10) * (10^bit32.extract(VALUE,0,2)) - status.homeAlt = bit32.extract(VALUE,14,10) * (10^bit32.extract(VALUE,12,2)) * 0.1 * (bit32.extract(VALUE,24,1) == 1 and -1 or 1) - status.homeAngle = bit32.extract(VALUE, 25, 7) * 3 - elseif ( DATA_ID == 0x5000) then -- MESSAGES - if (VALUE ~= status.lastMsgValue) then - status.lastMsgValue = VALUE - local c1 = bit32.extract(VALUE,0,7) - local c2 = bit32.extract(VALUE,8,7) - local c3 = bit32.extract(VALUE,16,7) - local c4 = bit32.extract(VALUE,24,7) - -- - local msgEnd = false - -- - if (c4 ~= 0) then - status.msgBuffer = status.msgBuffer .. string.char(c4) - else - msgEnd = true; - end - if (c3 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c3) - else - msgEnd = true; - end - if (c2 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c2) - else - msgEnd = true; - end - if (c1 ~= 0 and not msgEnd) then - status.msgBuffer = status.msgBuffer .. string.char(c1) - else - msgEnd = true; - end - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x4)<<21; - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x2)<<14; - --_msg_chunk.chunk |= (_statustext_queue[0]->severity & 0x1)<<7; - if (msgEnd) then - local severity = (bit32.extract(VALUE,7,1) * 1) + (bit32.extract(VALUE,15,1) * 2) + (bit32.extract(VALUE,23,1) * 4) - pushMessage( severity, status.msgBuffer) - status.msgBuffer = "" - end - end - elseif ( DATA_ID == 0x5007) then -- PARAMS - paramId = bit32.extract(VALUE,24,4) - paramValue = bit32.extract(VALUE,0,24) - if paramId == 1 then - status.frameType = paramValue - elseif paramId == 4 then - status.batt1Capacity = paramValue -#ifdef BATT2TEST - status.batt2Capacity = paramValue -#endif --BATT2TEST - elseif paramId == 5 then - status.batt2Capacity = paramValue - end - end - end -end - -#ifdef TESTMODE -local function telemetryEnabled() - return true -end -#else --TESTMODE -local function telemetryEnabled() - if getRSSI() == 0 then - status.noTelemetryData = 1 - end - return status.noTelemetryData == 0 -end -#endif --TESTMODE - -local function getMaxValue(value,idx) - minmaxValues[idx] = math.max(value,minmaxValues[idx]) - return showMinMaxValues == true and minmaxValues[idx] or value -end - -local function calcMinValue(value,min) - return min == 0 and value or math.min(value,min) -end - --- returns the actual minimun only if both are > 0 -local function getNonZeroMin(v1,v2) - return v1 == 0 and v2 or ( v2 == 0 and v1 or math.min(v1,v2)) -end - -#ifdef BATTPERC_BY_VOLTAGE -function getBattPercByCell(cellVoltage) - if cellVoltage == 0 then - return 99 - end - if cellVoltage >= battPercByVoltage[11][1] then - return 99 - end - if cellVoltage <= battPercByVoltage[1][1] then - return 0 - end - for i=2,11 do - if cellVoltage <= battPercByVoltage[i][1] then - -- - local v0 = battPercByVoltage[i-1][1] - local fv0 = battPercByVoltage[i-1][2] - -- - local v1 = battPercByVoltage[i][1] - local fv1 = battPercByVoltage[i][2] - -- interpolation polinomial - return fv0 + ((fv1 - fv0)/(v1-v0))*(cellVoltage - v0) - end - end --for -end -#endif --BATTPERC_BY_VOLTAGE - - -local function calcCellCount() - -- cellcount override from menu - if conf.cellCount ~= nil and conf.cellCount > 0 then - return conf.cellCount - end - -- cellcount is cached only for FLVSS - if status.batt1sources.vs == true and status.cellcount > 1 then - return status.cellcount - end - -- round in excess and return - -- Note: cellcount is not cached because max voltage can rise during initialization) - return math.floor( (( math.max(status.cell1maxFC,status.cellmaxA2)*0.1 ) / CELLFULL) + 1) -end - -local function calcBattery() - ------------ - -- FLVSS 1 - ------------ - local cellResult = getValue("Cels") - if type(cellResult) == "table" then - status.cell1min = CELLFULL - status.cell1sum = 0 - -- cellcount is global and shared - status.cellcount = #cellResult - for i, v in pairs(cellResult) do - status.cell1sum = status.cell1sum + v - if status.cell1min > v then - status.cell1min = v - end - end - -- if connected after scritp started - if status.batt1sources.vs == false then - status.battsource = "na" - end - if status.battsource == "na" then - status.battsource = "vs" - end - status.batt1sources.vs = true - else - status.batt1sources.vs = false - status.cell1min = 0 - status.cell1sum = 0 - end - ------------ - -- FLVSS 2 - ------------ -#ifdef FLVSS2TEST - cellResult = getValue("Cels") -#else --FLVSS2TEST - cellResult = getValue("Cel2") -#endif --FLVSS2TEST - if type(cellResult) == "table" then - status.cell2min = CELLFULL - status.cell2sum = 0 - -- cellcount is global and shared - status.cellcount = #cellResult - for i, v in pairs(cellResult) do - status.cell2sum = status.cell2sum + v - if status.cell2min > v then - status.cell2min = v - end - end - -- if connected after scritp started - if status.batt2sources.vs == false then - status.battsource = "na" - end - if status.battsource == "na" then - status.battsource = "vs" - end - status.batt2sources.vs = true - else - status.batt2sources.vs = false - status.cell2min = 0 - status.cell2sum = 0 - end - -------------------------------- - -- flight controller battery 1 - -------------------------------- - if status.batt1volt > 0 then - status.cell1sumFC = status.batt1volt*0.1 - status.cell1maxFC = math.max(status.batt1volt,status.cell1maxFC) - if status.battsource == "na" then - status.battsource = "fc" - end - status.batt1sources.fc = true - else - status.batt1sources.fc = false - status.cell1sumFC = 0 - end - -------------------------------- - -- flight controller battery 2 - -------------------------------- - if status.batt2volt > 0 then - status.cell2sumFC = status.batt2volt*0.1 - if status.battsource == "na" then - status.battsource = "fc" - end - status.batt2sources.fc = true - else - status.batt2sources.fc = false - status.cell2sumFC = 0 - end - ---------------------------------- - -- A2 analog voltage only 1 supported - ---------------------------------- - local battA2 = getValue("A2") - -- - if battA2 > 0 then - status.cellsumA2 = battA2 - status.cellmaxA2 = math.max(battA2*10,status.cellmaxA2) - status.batt1sources.a2 = true - else - status.batt1sources.a2 = false - status.cellsumA2 = 0 - end - -- batt fc - minmaxValues[MIN_BATT1_FC] = calcMinValue(status.cell1sumFC,minmaxValues[MIN_BATT1_FC]) - minmaxValues[MIN_BATT2_FC] = calcMinValue(status.cell2sumFC,minmaxValues[MIN_BATT2_FC]) - -- cell flvss - minmaxValues[MIN_CELL1_VS] = calcMinValue(status.cell1min,minmaxValues[MIN_CELL1_VS]) - minmaxValues[MIN_CELL2_VS] = calcMinValue(status.cell2min,minmaxValues[MIN_CELL2_VS]) - -- batt flvss - minmaxValues[MIN_BATT1_VS] = calcMinValue(status.cell1sum,minmaxValues[MIN_BATT1_VS]) - minmaxValues[MIN_BATT2_VS] = calcMinValue(status.cell2sum,minmaxValues[MIN_BATT2_VS]) - -- batt A2 - minmaxValues[MIN_BATT_A2] = calcMinValue(status.cellsumA2,minmaxValues[MIN_BATT_A2]) -end - -local function checkLandingStatus() - if ( status.timerRunning == 0 and status.landComplete == 1 and status.lastTimerStart == 0) then - startTimer() - end - if (status.timerRunning == 1 and status.landComplete == 0 and status.lastTimerStart ~= 0) then - stopTimer() - if status.statusArmed == 1 then - playSound("landing") - end - end - status.timerRunning = status.landComplete -end - -#ifdef WIDGET -local initLib = {} -#ifdef LOAD_LUA -local initFile = "/SCRIPTS/YAAPU/LIB/init.lua" -#else --LOAD_LUA -local initFile = "/SCRIPTS/YAAPU/LIB/init.luac" -#endif --LOAD_LUA - -local function reset() - -- initialize status - if initLib.resetWidget == nil then - initLib = dofile(initFile) - end - -- reset frame - clearTable(frame.frameTypes) - -- reset widget pages - currentPage = 0 - showMinMaxValues = false - showDualBattery = false - -- - frame = {} - -- reset all - initLib.resetTelemetry(status,alarms,pushMessage,clearTable) - -- release resources - clearTable(initLib) - -- load model config - loadConfig() - -- done - playSound("yaapu") -end -#endif --WIDGET - -local function calcFlightTime() - -- update local variable with timer 3 value - if ( model.getTimer(2).value < status.flightTime and status.statusArmed == 0) then - reset() - end - if (model.getTimer(2).value < status.flightTime and status.statusArmed == 1) then - model.setTimer(2,{value=status.flightTime}) - pushMessage(3,"timer reset ignored while armed") - end - status.flightTime = model.getTimer(2).value -end - -local function getBatt1Capacity() - return conf.battCapOverride1 > 0 and conf.battCapOverride1*100 or status.batt1Capacity -end - -local function getBatt2Capacity() - return conf.battCapOverride2 > 0 and conf.battCapOverride2*100 or status.batt2Capacity -end - --- gets the voltage based on source and min value, battId = [1|2] -local function getMinVoltageBySource(source,cell,cellFC,cellA2,battId,count) - -- offset 0 for cell voltage, 2 for pack voltage - local offset = 0 - -- - if cell > CELLFULL*2 or cellFC > CELLFULL*2 or cellA2 > CELLFULL*2 then - offset = 2 - end - -- - if source == "vs" then - return showMinMaxValues == true and minmaxValues[2+offset+battId] or cell - elseif source == "fc" then - -- FC only tracks batt1 and batt2 no cell voltage tracking - local minmax = (offset == 2 and minmaxValues[battId] or minmaxValues[battId]/count) - return showMinMaxValues == true and minmax or cellFC - elseif source == "a2" then - -- A2 does not depend on battery id - local minmax = (offset == 2 and minmaxValues[MIN_BATT_A2] or minmaxValues[MIN_BATT_A2]/count) - return showMinMaxValues == true and minmax or cellA2 - end - -- - return 0 -end - -local sensors = { - {Fuel_ID, Fuel_SUBID, Fuel_INSTANCE,0, 13 , Fuel_PRECISION , Fuel_NAME }, - {VFAS_ID, VFAS_SUBID, VFAS_INSTANCE,0, 1 , VFAS_PRECISION , VFAS_NAME}, - {CURR_ID, CURR_SUBID, CURR_INSTANCE,0, 2 , CURR_PRECISION , CURR_NAME}, - {VSpd_ID, VSpd_SUBID, VSpd_INSTANCE,0, 5 , VSpd_PRECISION , VSpd_NAME}, - {GSpd_ID, GSpd_SUBID, GSpd_INSTANCE,0, 5 , GSpd_PRECISION , GSpd_NAME}, - {Alt_ID, Alt_SUBID, Alt_INSTANCE,0, 9 , Alt_PRECISION , Alt_NAME}, - {GAlt_ID, GAlt_SUBID, GAlt_INSTANCE,0, 9 , GAlt_PRECISION , GAlt_NAME}, - {Hdg_ID, Hdg_SUBID, Hdg_INSTANCE,0, 20 , Hdg_PRECISION , Hdg_NAME}, - {IMUTmp_ID, IMUTmp_SUBID, IMUTmp_INSTANCE,0, 11 , IMUTmp_PRECISION , IMUTmp_NAME}, - {ARM_ID, ARM_SUBID, ARM_INSTANCE,0, 0 , ARM_PRECISION , ARM_NAME} -} - -local function setSensorValues() - if (not telemetryEnabled()) then - return - end - local battmah = status.batt1mah - local battcapacity = getBatt1Capacity() - if status.batt2mah > 0 then - battcapacity = getBatt1Capacity() + getBatt2Capacity() - battmah = status.batt1mah + status.batt2mah - end - local perc = 0 - if (battcapacity > 0) then - perc = (1 - (battmah/battcapacity))*100 - if perc > 99 then - perc = 99 - elseif perc < 0 then - perc = 0 - end - end - -- - sensors[1][4] = perc; - sensors[2][4] = getNonZeroMin(status.batt1volt,status.batt2volt)*10; - sensors[3][4] = status.batt1current+status.batt2current; - sensors[4][4] = status.vSpeed; - sensors[5][4] = status.hSpeed*0.1; - sensors[6][4] = status.homeAlt*10; - sensors[7][4] = math.floor(status.gpsAlt*0.1); - sensors[8][4] = math.floor(status.yaw); - sensors[9][4] = status.imuTemp; - sensors[10][4] = status.statusArmed*100; - -- - for s=1,#sensors - do -#ifdef WIDGET - setTelemetryValue(sensors[s][1], sensors[s][2], sensors[s][3], sensors[s][4], sensors[s][5] , sensors[s][6] , sensors[s][7]) -#else - local skip = false - -- check if sensor - for i=1,4 - do - -- if a sensor created by the script has a user defined override then do not expose it to OpenTX - if customSensors[i] ~= nil and customSensors[i][2] == sensors[s][7] and customSensors[i][5] == "E" then - -- sensor is external ==> disable the internal one - skip = true - end - end - if skip == false then - setTelemetryValue(sensors[s][1], sensors[s][2], sensors[s][3], sensors[s][4], sensors[s][5] , sensors[s][6] , sensors[s][7]) - end -#endif - end -end - --------------------- --- Single long function much more memory efficient than many little functions ---------------------- -local function drawBatteryPane(x,battVolt,cellVolt,current,battmah,battcapacity) - local perc = 0 - #ifdef BATTPERC_BY_VOLTAGE - if conf.enableBattPercByVoltage == true then - --[[ - discharge curve is based on battery under load, when motors are disarmed - cellvoltage needs to be corrected by subtracting the "under load" voltage drop - --]] - if status.statusArmed then - perc = getBattPercByCell(0.01*cellVolt) - else - perc = getBattPercByCell((0.01*cellVolt)-VOLTAGE_DROP) - end - else - #endif --BATTPERC_BY_VOLTAGE - if (battcapacity > 0) then - perc = (1 - (battmah/battcapacity))*100 - if perc > 99 then - perc = 99 - elseif perc < 0 then - perc = 0 - end - end - #ifdef BATTPERC_BY_VOLTAGE - end --conf.enableBattPercByVoltage - #endif --BATTPERC_BY_VOLTAGE - -- battery min cell - local flags = 0 - -- - if showMinMaxValues == false then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) -- white - if status.battLevel2 == false and alarms[ALARMS_BATT_L2][ALARM_START] > 0 then - drawBlinkBitmap("cell_red",x+BATTCELL_X - 4,BATTCELL_Y + 8) - lcdBacklightOn() - elseif status.battLevel2 == true then - lcd.drawBitmap(getBitmap("cell_red"),x+BATTCELL_X - 4,BATTCELL_Y + 8) - elseif status.battLevel1 == false and alarms[ALARMS_BATT_L1][ALARM_START] > 0 then - drawBlinkBitmap("cell_orange",x+BATTCELL_X - 4,BATTCELL_Y + 8) - lcdBacklightOn() - elseif status.battLevel1 == true then - lcd.drawBitmap(getBitmap("cell_orange"),x+BATTCELL_X - 4,BATTCELL_Y + 8) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 0, 0)) -- black - end - flags = CUSTOM_COLOR - end - drawNumberWithTwoDims(x+BATTCELL_X, BATTCELL_Y,x+BATTCELL_XV, BATTCELL_YV, BATTCELL_YS,cellVolt,"V",status.battsource,BATTCELL_FLAGS+flags,flags,flags) - -- battery voltage - drawNumberWithDim(x+BATTVOLT_X,BATTVOLT_Y,x+BATTVOLT_XV, BATTVOLT_YV, battVolt,"V",BATTVOLT_FLAGS,BATTVOLT_FLAGSV) - -- battery current - drawNumberWithDim(x+BATTCURR_X,BATTCURR_Y,x+BATTCURR_XA,BATTCURR_YA,current,"A",BATTCURR_FLAGS,BATTCURR_FLAGSA) - -- display capacity bar % - if perc > 50 then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 255, 0)) - elseif perc <= 50 and perc > 25 then - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 204, 0)) -- yellow - else - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,0, 0)) - end - lcd.drawBitmap(getBitmap("gauge_bg"),x+BATTGAUGE_X-2,BATTGAUGE_Y-2) - lcd.drawGauge(x+BATTGAUGE_X, BATTGAUGE_Y,BATTGAUGE_WIDTH,BATTGAUGE_HEIGHT,perc,100,CUSTOM_COLOR) - -- battery percentage - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0, 0, 0)) -- black - local strperc = string.format("%02d%%",perc) - lcd.drawText(x+BATTPERC_X, BATTPERC_Y, strperc, BATTPERC_FLAGS+CUSTOM_COLOR) - -- battery mah - local strmah = string.format("%.02f/%.01f",battmah/1000,battcapacity/1000) - lcd.drawText(x+BATTMAH_X, BATTMAH_Y+6, "Ah", RIGHT) - lcd.drawText(x+BATTMAH_X - 22, BATTMAH_Y, strmah, BATTMAH_FLAGS+RIGHT) - if showMinMaxValues == true then - drawVArrow(x+BATTCELL_X+140, BATTCELL_Y + 27,6,false,true) - drawVArrow(x+BATTVOLT_X-2,BATTVOLT_Y + 10, 5,false,true) - drawVArrow(x+BATTCURR_X-5,BATTCURR_Y + 10,5,true,false) - end -end - -local function drawNoTelemetryData() - -- no telemetry data - if (not telemetryEnabled()) then -#ifdef SPLASH - lcd.drawBitmap(getBitmap("notelemetry"),(LCD_W-404)/2,(LCD_H-164)/2 + 10) --404x164 - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255,255,255)) - lcd.drawText(130, 208, VERSION, SMLSIZE+CUSTOM_COLOR) -#else --SPLASH - lcd.drawFilledRectangle(75,90, 330, 100, TITLE_BGCOLOR) - lcd.drawText(140, 120, "no telemetry data", MIDSIZE+INVERS) - lcd.drawText(130, 160, VERSION, SMLSIZE+INVERS) -#endif -- SPLAH - end -end - -local function drawFlightMode() - -- flight mode - if frame.flightModes then - local strMode = frame.flightModes[status.flightMode] - if strMode ~= nil then - if ( status.simpleMode > 0 ) then - local strSimpleMode = status.simpleMode == 1 and "(S)" or "(SS)" - strMode = string.format("%s%s",strMode,strSimpleMode) - end - lcd.drawText(FLIGHTMODE_X + 2, FLIGHTMODE_Y, strMode, FLIGHTMODE_FLAGS) - end - end - lcd.drawLine(FLIGHTMODE_X + 2,FLIGHTMODE_Y, FLIGHTMODE_X + 150,FLIGHTMODE_Y, SOLID,0) - lcd.drawText(FLIGHTMODE_X + 2,FLIGHTMODE_Y - 16,"Flight Mode",SMLSIZE) -end - -local function drawTopBar() - -- black bar - lcd.drawFilledRectangle(0,0, LCD_W, 20, TITLE_BGCOLOR) - -- frametype and model name - local info = model.getInfo() -#ifdef WIDGET - -- model change event - if currentModel ~= info.name then - currentModel = info.name - reset() - end -#endif -- WIDGET - local fn = frameNames[status.frameType] - local strmodel = info.name - if fn ~= nil then - strmodel = fn..": "..info.name - end - lcd.drawText(2, RSSI_Y, strmodel, MENU_TITLE_COLOR) -#ifdef DEBUG - -- usage % - local usage = getUsage() - lcd.drawNumber(200, RSSI_Y, usage, MENU_TITLE_COLOR) -#endif --DEBUG - -- flight time - local time = getDateTime() - local strtime = string.format("%02d:%02d:%02d",time.hour,time.min,time.sec) - lcd.drawText(LCD_W, RSSI_Y+4, strtime, SMLSIZE+RIGHT+MENU_TITLE_COLOR) - -- RSSI - lcd.drawText(RSSI_X, RSSI_Y, "RS:", RSSI_FLAGS+MENU_TITLE_COLOR) -#ifdef DEMO - lcd.drawText(RSSI_X + 30,RSSI_Y, 87, RSSI_FLAGS+MENU_TITLE_COLOR) -#else --DEMO - lcd.drawText(RSSI_X + 30,RSSI_Y, getRSSI(), RSSI_FLAGS+MENU_TITLE_COLOR) -#endif --DEMO - -- tx voltage - local vtx = string.format("Tx:%.1fv",getValue(getFieldInfo("tx-voltage").id)) - lcd.drawText(TXVOLTAGE_X,TXVOLTAGE_Y, vtx, TXVOLTAGE_FLAGS+MENU_TITLE_COLOR) -end - -local function drawFlightTime() - -- flight time - lcd.drawText(FLIGHTTIME_X, FLIGHTTIME_Y, "Flight Time", SMLSIZE) - lcd.drawLine(FLIGHTTIME_X,FLIGHTTIME_Y + 16, FLIGHTTIME_X + 140,FLIGHTTIME_Y + 16, SOLID,0) - lcd.drawTimer(FLIGHTTIME_X, FLIGHTTIME_Y + 14, model.getTimer(2).value, FLIGHTTIME_FLAGS) -end - -local function drawScreenTitle(title,page, pages) - lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) - lcd.drawText(1, 5, title, MENU_TITLE_COLOR) - lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR) -end - -local function drawBottomBar() - -- black bar - lcd.drawFilledRectangle(0,BOTTOMBAR_Y, LCD_W, 20, TITLE_BGCOLOR) - -- message text - local now = getTime() - local msg = status.messages[#status.messages] - if (now - status.lastMsgTime ) > 150 or conf.disableMsgBlink then - lcd.drawText(2, BOTTOMBAR_Y + 1, msg,MENU_TITLE_COLOR) - else - lcd.drawText(2, BOTTOMBAR_Y + 1, msg,INVERS+BLINK+MENU_TITLE_COLOR) - end -end - -local function drawAllMessages() - for i=1,#status.messages do - lcd.drawText(1,16*(i-1), status.messages[i],SMLSIZE) - end -end - -local function drawGPSStatus() - -- gps status - local strStatus = gpsStatuses[status.gpsStatus] - local flags = BLINK - local mult = 1 - local gpsData = nil - local hdop = status.gpsHdopC - if status.gpsStatus > 2 then - if status.homeAngle ~= -1 then - flags = PREC1 - end - if hdop > 999 then - hdop = 999 - flags = 0 - mult=0.1 - elseif hdop > 99 then - flags = 0 - mult=0.1 - end - lcd.drawText(GPS_X -1,GPS_Y - 3, strStatus, SMLSIZE) - lcd.drawText(GPS_X -1,GPS_Y + 16 - 3, "fix", 0) - if status.numSats == 15 then - lcd.drawNumber(GPS_X + 80, GPS_Y + 4 , status.numSats, DBLSIZE+RIGHT) - lcd.drawText(GPS_X + 89, GPS_Y + 19, "+", RIGHT) - else - lcd.drawNumber(GPS_X + 87, GPS_Y + 4 , status.numSats, DBLSIZE+RIGHT) - end - -- - lcd.drawText(GPS_X + 94, GPS_Y-3, "hd", SMLSIZE) - lcd.drawNumber(GPS_X + 166, GPS_Y + 4, hdop*mult , DBLSIZE+flags+RIGHT) - -- - lcd.drawLine(GPS_X + 91,GPS_Y ,GPS_X+91,GPS_Y + 36,SOLID,0) - -- - gpsData = getValue("GPS") - -- - if type(gpsData) == "table" and gpsData.lat ~= nil and gpsData.lon ~= nil then - lcd.drawText(2 ,GPS_Y + 38,math.floor(gpsData.lat * 100000) / 100000,SMLSIZE) - lcd.drawText(165 ,GPS_Y + 38,math.floor(gpsData.lon * 100000) / 100000,SMLSIZE+RIGHT) - end - lcd.drawLine(GPS_X ,GPS_Y + 37,GPS_X+160,GPS_Y + 37,SOLID,0) - lcd.drawLine(GPS_X ,GPS_Y + 54,GPS_X+160,GPS_Y + 54,SOLID,0) - elseif status.gpsStatus == 0 then - drawBlinkBitmap("nogpsicon",4,24) - else - drawBlinkBitmap("nolockicon",4,24) - end -end - -local function drawLeftPane(battcurrent,cellsumFC) - if conf.rangeMax > 0 then - flags = 0 - local rng = status.range - if rng > conf.rangeMax then - flags = BLINK+INVERS - end - rng = getMaxValue(rng,MAX_RANGE) - if showMinMaxValues == true then - flags = 0 - end -#ifdef UNIT_SCALE - lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "Range("..UNIT_ALT_LABEL..")", SMLSIZE) - lcd.drawText(ALTASL_X, ALTASL_Y, string.format("%.1f",rng*0.01*UNIT_ALT_SCALE), MIDSIZE+flags+RIGHT) -#else - lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "Range(m)", SMLSIZE) - lcd.drawText(ALTASL_X, ALTASL_Y, string.format("%.1f",rng*0.01), MIDSIZE+flags+RIGHT) -#endif - else - flags = BLINK - -- always display gps altitude even without 3d lock - local alt = status.gpsAlt/10 - if status.gpsStatus > 2 then - flags = 0 - -- update max only with 3d or better lock - alt = getMaxValue(alt,MAX_GPSALT) - end - if showMinMaxValues == true then - flags = 0 - end -#ifdef UNIT_SCALE - lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "AltAsl("..UNIT_ALT_LABEL..")", SMLSIZE) - local stralt = string.format("%d",alt*UNIT_ALT_SCALE) - lcd.drawText(ALTASL_X, ALTASL_Y, stralt, MIDSIZE+flags+RIGHT) -#else - lcd.drawText(ALTASL_XLABEL, ALTASL_YLABEL, "AltAsl(m)", SMLSIZE) - local stralt = string.format("%d",alt) - lcd.drawText(ALTASL_X, ALTASL_Y, stralt, MIDSIZE+flags+RIGHT) -#endif - end - -- home distance - drawHomeIcon(HOMEDIST_XLABEL,HOMEDIST_YLABEL,7) -#ifdef UNIT_SCALE - lcd.drawText(HOMEDIST_X, HOMEDIST_YLABEL, "Dist("..UNIT_DIST_LABEL..")", SMLSIZE+RIGHT) -#else - lcd.drawText(HOMEDIST_X, HOMEDIST_YLABEL, "Dist(m)", SMLSIZE+RIGHT) -#endif - flags = 0 - if status.homeAngle == -1 then - flags = BLINK - end - local dist = getMaxValue(status.homeDist,MAX_DIST) - if showMinMaxValues == true then - flags = 0 - end -#ifdef UNIT_SCALE - local strdist = string.format("%d",dist*UNIT_DIST_SCALE) -#else --UNIT_SCALE - local strdist = string.format("%d",dist) -#endif --UNIT_SCALE - lcd.drawText(HOMEDIST_X, HOMEDIST_Y, strdist, HOMEDIST_FLAGS+flags+RIGHT) - -- hspeed - local speed = getMaxValue(status.hSpeed,MAX_HSPEED) - lcd.drawText(HSPEED_XLABEL, HSPEED_YLABEL, "Spd("..UNIT_HSPEED_LABEL..")", SMLSIZE+RIGHT) - lcd.drawNumber(HSPEED_X,HSPEED_Y,speed * UNIT_HSPEED_SCALE,HSPEED_FLAGS+RIGHT+PREC1) - -- power - --[[ - local power = cellsumFC*battcurrent*0.1 - power = getMaxValue(power,MAX_POWER) - lcd.drawText(BATTPOWER_X, BATTPOWER_Y, "Power(W)", BATTPOWER_FLAGS+RIGHT) - lcd.drawNumber(BATTPOWER_X,BATTPOWER_YW,power,BATTPOWER_FLAGSW+RIGHT) - --]] - -- - local eff = speed > 2 and battcurrent*1000/(speed*UNIT_HSPEED_SCALE) or 0 - lcd.drawText(BATTPOWER_X, BATTPOWER_Y, "Eff(mAh)", BATTPOWER_FLAGS+RIGHT) - lcd.drawNumber(BATTPOWER_X,BATTPOWER_YW,eff,BATTPOWER_FLAGSW+RIGHT) - -- - if showMinMaxValues == true then - drawVArrow(ALTASL_X-81, ALTASL_Y,6,true,false) - drawVArrow(HOMEDIST_X-78, HOMEDIST_Y ,6,true,false) - drawVArrow(HSPEED_XDIM-60,HSPEED_Y,6,true,false) - drawVArrow(BATTPOWER_X-78, BATTPOWER_YW, 5,true,false) - end -end - -local function drawFailsafe() - if status.ekfFailsafe > 0 then - drawBlinkBitmap("ekffailsafe",LCD_W/2 - 90,180) - end - if status.battFailsafe > 0 then - drawBlinkBitmap("battfailsafe",LCD_W/2 - 90,180) - end -end - -local function drawArmStatus() - -- armstatus - if status.ekfFailsafe == 0 and status.battFailsafe == 0 and status.timerRunning == 0 then - if (status.statusArmed == 1) then - lcd.drawBitmap(getBitmap("armed"),LCD_W/2 - 90,180) - else - drawBlinkBitmap("disarmed",LCD_W/2 - 90,180) - end - end -end - --- vertical distance between roll horiz segments -#define R2 10 - -#define YAWICON_Y 3 -#define YAWTEXT_Y 16 -#define YAW_STEPWIDTH 28 - -local yawRibbonPoints = {} --- -yawRibbonPoints[0]={"N",2} -yawRibbonPoints[1]={"NE",-5} -yawRibbonPoints[2]={"E",2} -yawRibbonPoints[3]={"SE",-5} -yawRibbonPoints[4]={"S",2} -yawRibbonPoints[5]={"SW",-5} -yawRibbonPoints[6]={"W",2} -yawRibbonPoints[7]={"NW",-5} - --- optimized yaw ribbon drawing -local function drawCompassRibbon() - -- ribbon centered +/- 90 on yaw - local centerYaw = (status.yaw+270)%360 - -- this is the first point left to be drawn on the compass ribbon - local nextPoint = math.floor(centerYaw/45) * 45 - -- distance in degrees between leftmost ribbon point and first 45° multiple normalized to YAW_WIDTH/8 - local yawMinX = (LCD_W - YAW_WIDTH)/2 - local yawMaxX = (LCD_W + YAW_WIDTH)/2 - -- x coord of first ribbon letter - local nextPointX = yawMinX + (nextPoint - centerYaw)/45 * YAW_STEPWIDTH - local yawY = YAW_Y - -- - local i = (nextPoint / 45) % 8 - for idx=1,6 - do - if nextPointX >= yawMinX - 3 and nextPointX < yawMaxX then - lcd.drawText(nextPointX+yawRibbonPoints[i][2],yawY,yawRibbonPoints[i][1],SMLSIZE) - end - i = (i + 1) % 8 - nextPointX = nextPointX + YAW_STEPWIDTH - end - -- home icon - local leftYaw = (status.yaw + 180)%360 - local rightYaw = status.yaw%360 - local centerHome = (status.homeAngle+270)%360 - -- - local homeIconX = yawMinX - local homeIconY = yawY + 25 - if rightYaw >= leftYaw then - if centerHome > leftYaw and centerHome < rightYaw then - drawHomeIcon(yawMinX + ((centerHome - leftYaw)/180)*YAW_WIDTH - 5,homeIconY) - end - else - if centerHome < rightYaw then - drawHomeIcon(yawMinX + (((360-leftYaw) + centerHome)/180)*YAW_WIDTH - 5,homeIconY) - elseif centerHome >= leftYaw then - drawHomeIcon(yawMinX + ((centerHome-leftYaw)/180)*YAW_WIDTH - 5,homeIconY) - end - end - -- when abs(home angle) > 90 draw home icon close to left/right border - local angle = status.homeAngle - status.yaw - local cos = math.cos(math.rad(angle - 90)) - local sin = math.sin(math.rad(angle - 90)) - if cos > 0 and sin > 0 then - drawHomeIcon(yawMaxX - 5, homeIconY) - elseif cos < 0 and sin > 0 then - drawHomeIcon(yawMinX - 5, homeIconY) - end - -- - lcd.drawLine(yawMinX, yawY + YAWTEXT_Y, yawMaxX, yawY + YAWTEXT_Y, SOLID, 0) - local xx = 0 - if ( status.yaw < 10) then - xx = 0 - elseif (status.yaw < 100) then - xx = -8 - else - xx = -14 - end - lcd.drawNumber(LCD_W/2 + xx - 6, yawY, status.yaw, MIDSIZE+INVERS) -end - - -#ifdef COMPASS_ROSE -#define COMPASS_CHARSIZE 10 -#define COMPASS_RADIUS 30 -#define COMPASS_LINE 5 - -local compassPoints = {} - -compassPoints[0] = "N" -compassPoints[1] = nil -compassPoints[2] = "E" -compassPoints[3] = nil -compassPoints[4] = "S" -compassPoints[5] = nil -compassPoints[6] = "W" -compassPoints[7] = nil - -local function drawCompassRose() - local hw = math.floor(YAW_WIDTH/2) - local yawRounded = roundTo(status.yaw,1) - local homeRounded = roundTo(status.homeAngle,1) - local minY = TOPBAR_Y + TOPBAR_HEIGHT - 1 - local Hdy = math.sin(math.rad(270+homeRounded-yawRounded))*COMPASS_RADIUS - local Hdx = math.cos(math.rad(270+homeRounded-yawRounded))*COMPASS_RADIUS - for ang=0,7 - do - local Rdy = math.sin(math.rad(45*ang+270-yawRounded))*COMPASS_RADIUS - local Rdx = math.cos(math.rad(45*ang+270-yawRounded))*COMPASS_RADIUS - local Ldy = math.sin(math.rad(45*ang+270-yawRounded))*(COMPASS_RADIUS-COMPASS_LINE) - local Ldx = math.cos(math.rad(45*ang+270-yawRounded))*(COMPASS_RADIUS-COMPASS_LINE) - if compassPoints[ang] == nil then - lcd.drawLine(HOMEDIR_X+Ldx,HOMEDIR_Y+Ldy,HOMEDIR_X+Rdx,HOMEDIR_Y+Rdy,SOLID,2) - else - lcd.drawText(HOMEDIR_X+Rdx-(COMPASS_CHARSIZE/2),HOMEDIR_Y+Rdy-(COMPASS_CHARSIZE/2),compassPoints[ang],0) - end - end - drawHomeIcon(HOMEDIR_X+Hdx-(COMPASS_CHARSIZE/2),HOMEDIR_Y+Hdy-(COMPASS_CHARSIZE/2)) - -- - local xx = 0 - if ( status.yaw < 10) then - xx = 1 - elseif (status.yaw < 100) then - xx = -8 - else - xx = -12 - end - lcd.drawNumber(HOMEDIR_X + xx - 5, HOMEDIR_Y - COMPASS_RADIUS - 24, status.yaw, INVERS) -end -#endif - -#define LEFTWIDTH 38 -#define RIGHTWIDTH 38 - -#ifdef HUDTIMER -local hudDrawTime = 0 -local hudDrawCounter = 0 -#endif - -local function fillTriangle(ox, oy, x1, x2, roll, angle,color) - local step = 2 - -- - local y1 = (oy - ox*angle) + x1*angle - local y2 = (oy - ox*angle) + x2*angle - -- - local steps = math.abs(y2-y1) / step - -- - if (0 < roll and roll <= 90) then - for s=0,steps - do - yy = y1 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(x1,yy,xx - x1,step,color) - end - elseif (90 < roll and roll <= 180) then - for s=0,steps - do - yy = y2 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(x1,yy,xx - x1,step,color) - end - elseif (-90 < roll and roll < 0) then - for s=0,steps - do - yy = y2 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(xx,yy,x2-xx+1,step,color) - end - elseif (-180 < roll and roll <= -90) then - for s=0,steps - do - yy = y1 + s*step - xx = (yy - (oy - ox*angle))/angle - lcd.drawRectangle(xx,yy,x2-xx+1,step,color) - end - end -end - -------------------------------------------- -#define VARIO_X 172 -#define VARIO_Y 19 - -local function drawHud(myWidget) -#ifdef HUDTIMER - local hudStart = getTime() -#endif - - local r = -status.roll - local cx,cy,dx,dy,ccx,ccy,cccx,cccy - local yPos = TOPBAR_Y + TOPBAR_HEIGHT + 8 - ----------------------- - -- artificial horizon - ----------------------- - -- no roll ==> segments are vertical, offsets are multiples of R2 - if ( status.roll == 0) then - dx=0 - dy=status.pitch - cx=0 - cy=R2 - ccx=0 - ccy=2*R2 - cccx=0 - cccy=3*R2 - else - -- center line offsets - dx = math.cos(math.rad(90 - r)) * -status.pitch - dy = math.sin(math.rad(90 - r)) * status.pitch - -- 1st line offsets - cx = math.cos(math.rad(90 - r)) * R2 - cy = math.sin(math.rad(90 - r)) * R2 - -- 2nd line offsets - ccx = math.cos(math.rad(90 - r)) * 2 * R2 - ccy = math.sin(math.rad(90 - r)) * 2 * R2 - -- 3rd line offsets - cccx = math.cos(math.rad(90 - r)) * 3 * R2 - cccy = math.sin(math.rad(90 - r)) * 3 * R2 - end - local rollX = math.floor(HUD_X + HUD_WIDTH/2) - ----------------------- - -- dark color for "ground" - ----------------------- -#ifdef HUD_BIG - -- 90x70 - local minY = 44 - local maxY = 114 -#else - -- 70x70 - local minY = 43 - local maxY = 113 -#endif --HUD_BIG - local minX = HUD_X + 1 - local maxX = HUD_X + HUD_WIDTH - -- - local ox = HUD_X + HUD_WIDTH/2 + dx - -- - local oy = HUD_Y_MID + dy - local yy = 0 - - --lcd.setColor(CUSTOM_COLOR,lcd.RGB(179, 204, 255)) -#ifdef HUD_BIG - lcd.setColor(CUSTOM_COLOR,lcd.RGB(0x7a, 0x9c, 0xff)) -#else - lcd.setColor(CUSTOM_COLOR,lcd.RGB(51, 102, 255)) -#endif - - lcd.drawFilledRectangle(minX,minY,HUD_WIDTH,maxY - minY,CUSTOM_COLOR) - -- angle of the line passing on point(ox,oy) - local angle = math.tan(math.rad(-status.roll)) - -- for each pixel of the hud base/top draw vertical black - -- lines from hud border to horizon line - -- horizon line moves with pitch/roll - --lcd.setColor(CUSTOM_COLOR,lcd.RGB(77, 153, 0)) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(102, 51, 0)) - -- - #ifdef HUD_ALGO1 - local step = 2 - local steps = (maxX - minX)/step - local xx = 0 - local xxR = 0 - for s=0,steps - do - xx = minX + s*step - xxR = xx + step - if status.roll > 90 or status.roll < -90 then - yy = (oy - ox*angle) + math.floor(xx*angle) - if yy > minY + 1 and yy < maxY then - lcd.drawFilledRectangle(xx,minY,step,yy-minY,CUSTOM_COLOR) - elseif yy >= maxY then - lcd.drawFilledRectangle(xx,minY,step,maxY-minY,CUSTOM_COLOR) - end - else - yy = (oy - ox*angle) + math.floor(xx*angle) - if yy <= minY then - lcd.drawFilledRectangle(xx,minY,step,maxY-minY,CUSTOM_COLOR) - elseif yy < maxY then - lcd.drawFilledRectangle(xx,yy,step,maxY-yy,CUSTOM_COLOR) - end - end - end - #endif --HUD_ALGO1 - #ifdef HUD_ALGO2 - -- - local minxY = (oy - ox * angle) + minX * angle; - local maxxY = (oy - ox * angle) + maxX * angle; - local maxyX = (maxY - (oy - ox * angle)) / angle; - local minyX = (minY - (oy - ox * angle)) / angle; - -- - if ( 0 <= -status.roll and -status.roll <= 90 ) then - if (minxY > minY and maxxY < maxY) then - -- 5 - lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR) - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY < maxY and maxxY > minY) then - -- 6 - lcd.drawFilledRectangle(minX, minY, minyX - minX, maxxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minX, maxxY, maxX - minX, maxY - maxxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY > maxY) then - -- 7 - lcd.drawFilledRectangle(minX, minY, minyX - minX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < maxY and minxY > minY) then - -- 8 - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle, CUSTOM_COLOR) - elseif (minxY < minY and maxxY < minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - elseif (90 < -status.roll and -status.roll <= 180) then - if (minxY < maxY and maxxY > minY) then - -- 9 - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > minY and maxxY < maxY) then - -- 10 - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minX, maxxY, maxyX - minX, maxY - maxxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxyX < maxX) then - -- 11 - lcd.drawFilledRectangle(minX, minY, maxyX - minX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < maxY and minxY > minY) then - -- 12 - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > maxY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - -- 9,10,11,12 - elseif (-90 < -status.roll and -status.roll < 0) then - if (minxY < maxY and maxxY > minY) then - -- 1 - lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < maxY and maxxY < minY and minxY > minY) then - -- 2 - lcd.drawFilledRectangle(minX, minxY, maxX - minX, maxY - minxY,CUSTOM_COLOR); - lcd.drawFilledRectangle(minyX, minY, maxX - minyX, minxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY < minY) then - -- 3 - lcd.drawFilledRectangle(minyX, minY, maxX - minyX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > minY and maxxY < maxY) then - -- 4 - fillTriangle(ox, oy, math.max(minX, maxyX), math.min(maxX, minyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxxY < minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - elseif (-180 <= -status.roll and -status.roll <= -90) then - if (minxY > minY and maxxY < maxY) then - -- 13 - lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (maxxY > maxY and minxY > minY and minxY < maxY) then - -- 14 - lcd.drawFilledRectangle(minX, minY, maxX - minX, minxY - minY,CUSTOM_COLOR); - lcd.drawFilledRectangle(maxyX, minxY, maxX - maxyX, maxY - minxY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxyX < maxX) then - -- 15 - lcd.drawFilledRectangle(maxyX, minY, maxX - maxyX, maxY - minY,CUSTOM_COLOR); - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY < minY and maxxY > minY) then - -- 16 - fillTriangle(ox, oy, math.max(minX, minyX), math.min(maxX, maxyX), -status.roll, angle,CUSTOM_COLOR); - elseif (minxY > maxY and maxxY > minY) then - -- off screen - lcd.drawFilledRectangle(minX, minY, maxX - minX, maxY - minY,CUSTOM_COLOR); - end - end - #endif --HUD_ALGO2 - -- parallel lines above and below horizon - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) - -- - drawLineWithClipping(rollX + dx - cccx,dy + HUD_Y_MID + cccy,r,40,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx - ccx,dy + HUD_Y_MID + ccy,r,20,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx - cx,dy + HUD_Y_MID + cy,r,40,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + cx,dy + HUD_Y_MID - cy,r,40,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + ccx,dy + HUD_Y_MID - ccy,r,20,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR) - drawLineWithClipping(rollX + dx + cccx,dy + HUD_Y_MID - cccy,r,40,DOTTED,HUD_X,HUD_X + HUD_WIDTH,minY,maxY,CUSTOM_COLOR) - ------------------------------------- - -- hud bitmap - ------------------------------------- -#ifdef HUD_BIG - lcd.drawBitmap(getBitmap("hud_90x70a"),(LCD_W-106)/2,34) --106x90 -#else - lcd.drawBitmap(getBitmap("hud_70x70d"),(LCD_W-86)/2,32) --86x92 -#endif --HUD_BIG - ------------------------------------ - -- synthetic vSpeed based on - -- home altitude when EKF is disabled - -- updated at 1Hz (i.e every 1000ms) - ------------------------------------- - if conf.enableSynthVSpeed == true then - if (status.synthVSpeedTime == 0) then - -- first time do nothing - status.synthVSpeedTime = getTime() - status.prevHomeAlt = status.homeAlt -- dm - elseif (getTime() - status.synthVSpeedTime > 100) then - -- calc vspeed - status.vspd = 1000*(status.homeAlt-status.prevHomeAlt)/(getTime()-status.synthVSpeedTime) -- m/s - -- update counters - status.synthVSpeedTime = getTime() - status.prevHomeAlt = status.homeAlt -- m - end - else - status.vspd = status.vSpeed - end - - ------------------------------------- - -- vario bitmap - ------------------------------------- - local varioMax = math.log(5) - local varioSpeed = math.log(1 + math.min(math.abs(0.05*status.vspd),4)) - local varioH = 0 -#ifdef HUD_BIG - if status.vspd > 0 then - varioY = math.min(79 - varioSpeed/varioMax*55,125) - else - varioY = 78 - end - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) - lcd.drawFilledRectangle(VARIO_X+2, varioY, 7, varioSpeed/varioMax*55, CUSTOM_COLOR, 0) - lcd.drawBitmap(getBitmap("variogauge_big"),VARIO_X,VARIO_Y) - if status.vSpeed > 0 then - lcd.drawBitmap(getBitmap("varioline"),VARIO_X-3,varioY) - else - lcd.drawBitmap(getBitmap("varioline"),VARIO_X-3,77 + varioSpeed/varioMax*55) - end -#else - if status.vspd > 0 then - varioY = math.min(79 - varioSpeed/varioMax*44,125) - else - varioY = 78 - end - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0xce, 0)) - lcd.drawFilledRectangle(VARIO_X+2, varioY, 8, varioSpeed/varioMax*44, CUSTOM_COLOR, 0) - lcd.drawBitmap(getBitmap("variogauge"),VARIO_X + 2,VARIO_Y + 5) - if vspd > 0 then - lcd.drawBitmap(getBitmap("varioline"),VARIO_X-1,varioY) - else - lcd.drawBitmap(getBitmap("varioline"),VARIO_X-1,78 + varioSpeed/varioMax*44) - end -#endif --HUD_BIG - ------------------------------------- - -- left and right indicators on HUD - ------------------------------------- - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 255, 255)) - -- altitude -#ifdef UNIT_SCALE - local alt = getMaxValue(status.homeAlt,MINMAX_ALT) * UNIT_ALT_SCALE - lcd.drawText(ALT_XLABEL,ALT_YLABEL,"alt("..UNIT_ALT_LABEL..")",ALT_FLAGSLABEL) -#else - local alt = getMaxValue(status.homeAlt,MINMAX_ALT) - lcd.drawText(ALT_XLABEL,ALT_YLABEL,"alt(m)",ALT_FLAGSLABEL) -#endif - if math.abs(alt) >= 10 then - lcd.drawNumber(ALT_X,ALT_Y,alt,ALT_FLAGS) - else - lcd.drawNumber(ALT_X,ALT_Y,alt*10,ALT_FLAGS+PREC1) - end - -- vertical speed -#ifdef UNIT_SCALE - local vspd = status.vspd * 0.1 * UNIT_VSPEED_SCALE - lcd.drawText(VSPEED_XLABEL,VSPEED_YLABEL,"vspd("..UNIT_VSPEED_LABEL..")",VSPEED_FLAGSLABEL) -#else - local vspd = status.vspd * 0.1 - lcd.drawText(VSPEED_XLABEL,VSPEED_YLABEL,"vspd(m/s)",VSPEED_FLAGSLABEL) -#endif - if (math.abs(vspd) >= 10) then - lcd.drawNumber(VSPEED_X,VSPEED_Y, vspd ,VSPEED_FLAGS) - else - lcd.drawNumber(VSPEED_X,VSPEED_Y,vspd*10,VSPEED_FLAGS+PREC1) - end -#ifdef HUDTIMER - hudDrawTime = hudDrawTime + (getTime() - hudStart) - hudDrawCounter = hudDrawCounter + 1 -#endif - -- min/max arrows - if showMinMaxValues == true then - drawVArrow(ALT_X+3, ALT_Y + 2,6,true,false) - end -end - -local function drawHomeDirection() - local angle = math.floor(status.homeAngle - status.yaw) - local x1 = HOMEDIR_X + HOMEDIR_R * math.cos(math.rad(angle - 90)) - local y1 = HOMEDIR_Y + HOMEDIR_R * math.sin(math.rad(angle - 90)) - local x2 = HOMEDIR_X + HOMEDIR_R * math.cos(math.rad(angle - 90 + 150)) - local y2 = HOMEDIR_Y + HOMEDIR_R * math.sin(math.rad(angle - 90 + 150)) - local x3 = HOMEDIR_X + HOMEDIR_R * math.cos(math.rad(angle - 90 - 150)) - local y3 = HOMEDIR_Y + HOMEDIR_R * math.sin(math.rad(angle - 90 - 150)) - local x4 = HOMEDIR_X + HOMEDIR_R * 0.5 * math.cos(math.rad(angle - 270)) - local y4 = HOMEDIR_Y + HOMEDIR_R * 0.5 *math.sin(math.rad(angle - 270)) - -- -#ifdef X10_OPENTX_221 - drawLine(x1,y1,x2,y2,SOLID,1) - drawLine(x1,y1,x3,y3,SOLID,1) - drawLine(x2,y2,x4,y4,SOLID,1) - drawLine(x3,y3,x4,y4,SOLID,1) -#else - lcd.drawLine(x1,y1,x2,y2,SOLID,1) - lcd.drawLine(x1,y1,x3,y3,SOLID,1) - lcd.drawLine(x2,y2,x4,y4,SOLID,1) - lcd.drawLine(x3,y3,x4,y4,SOLID,1) -#endif -end - ---------------------------------- --- This function checks alarm condition and as long as the condition persists it plays --- a warning sound. ---------------------------------- -local function checkAlarm(level,value,idx,sign,sound,delay) - -- once landed reset all alarms except battery alerts - if status.timerRunning == 0 then - if alarms[idx][ALARM_TYPE] == ALARM_TYPE_MIN then - alarms[idx] = { false, 0, false, ALARM_TYPE_MIN, 0, false, 0} - elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_MAX then - alarms[idx] = { false, 0, true, ALARM_TYPE_MAX, 0, false, 0} - elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_TIMER then - alarms[idx] = { false, 0, true, ALARM_TYPE_TIMER, 0, false, 0} - elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_BATT then - alarms[idx] = { false, 0 , false, ALARM_TYPE_BATT, ALARM_TYPE_BATT_GRACE, false, 0} - elseif alarms[idx][ALARM_TYPE] == ALARM_TYPE_BATT_CRT then - alarms[idx] = { false, 0 , false, ALARM_TYPE_BATT_CRT, ALARM_TYPE_BATT_GRACE, false, 0} - end - -- reset done - return - end - -- if needed arm the alarm only after value has reached level - if alarms[idx][ALARM_ARMED] == false and level > 0 and -1 * sign*value > -1 * sign*level then - alarms[idx][ALARM_ARMED] = true - end - -- - if alarms[idx][ALARM_TYPE] == ALARM_TYPE_TIMER then - if status.flightTime > 0 and math.floor(status.flightTime) % delay == 0 then - if alarms[idx][ALARM_NOTIFIED] == false then - alarms[idx][ALARM_NOTIFIED] = true - playSound(sound) - -- flightime is a multiple of 1 minute - if (status.flightTime % 60 == 0 ) then - -- minutes - playNumber(status.flightTime / 60,25) --25=minutes,26=seconds - else - -- minutes - if (status.flightTime > 60) then playNumber(status.flightTime / 60,25) end - -- seconds - playNumber(status.flightTime % 60,26) - end - end - else - alarms[idx][ALARM_NOTIFIED] = false - end - else - if alarms[idx][ALARM_ARMED] == true then - if level > 0 and sign*value > sign*level then - -- value is outside level - if alarms[idx][ALARM_START] == 0 then - -- first time outside level after last reset - alarms[idx][ALARM_START] = status.flightTime - -- status: START - end - else - -- value back to normal ==> reset - alarms[idx][ALARM_START] = 0 - alarms[idx][ALARM_NOTIFIED] = false - alarms[idx][ALARM_READY] = false - -- status: RESET - end - if alarms[idx][ALARM_START] > 0 and (status.flightTime ~= alarms[idx][ALARM_START]) and (status.flightTime - alarms[idx][ALARM_START]) >= alarms[idx][ALARM_GRACE] then - -- enough time has passed after START - alarms[idx][ALARM_READY] = true - -- status: READY - end - -- - if alarms[idx][ALARM_READY] == true and alarms[idx][ALARM_NOTIFIED] == false then - playSound(sound) - alarms[idx][ALARM_NOTIFIED] = true - alarms[idx][ALARM_LAST_ALARM] = status.flightTime - -- status: BEEP - end - -- all but battery alarms - if alarms[idx][ALARM_TYPE] ~= ALARM_TYPE_BATT then - if alarms[idx][ALARM_READY] == true and status.flightTime ~= alarms[idx][ALARM_LAST_ALARM] and (status.flightTime - alarms[idx][ALARM_LAST_ALARM]) % delay == 0 then - alarms[idx][ALARM_NOTIFIED] = false - -- status: REPEAT - end - end - end - end -end - -local function loadFlightModes() - if frame.flightModes then - return - end - -- - if status.frameType ~= -1 then -#ifdef LOAD_LUA - if frameTypes[status.frameType] == "c" then - frame = dofile("/SCRIPTS/YAAPU/LIB/copter.lua") - elseif frameTypes[status.frameType] == "p" then - frame = dofile("/SCRIPTS/YAAPU/LIB/plane.lua") - elseif frameTypes[status.frameType] == "r" then - frame = dofile("/SCRIPTS/YAAPU/LIB/rover.lua") - end -#else - if frameTypes[status.frameType] == "c" then - frame = dofile("/SCRIPTS/YAAPU/LIB/copter.luac") - elseif frameTypes[status.frameType] == "p" then - frame = dofile("/SCRIPTS/YAAPU/LIB/plane.luac") - elseif frameTypes[status.frameType] == "r" then - frame = dofile("/SCRIPTS/YAAPU/LIB/rover.luac") - end -#endif -#ifdef COLLECTGARBAGE - collectgarbage() - maxmem = 0 -#endif -#ifdef WIDGETDEBUG - pushMessage(6,"loaded frametype ["..frameTypes[status.frameType].."]") -#endif - end -end - -local function checkEvents(celm) - loadFlightModes() - -- silence alarms when showing min/max values - if showMinMaxValues == false then - checkAlarm(conf.minAltitudeAlert,status.homeAlt,ALARMS_MIN_ALT,-1,"minalt",menuItems[T2][4]) - checkAlarm(conf.maxAltitudeAlert,status.homeAlt,ALARMS_MAX_ALT,1,"maxalt",menuItems[T2][4]) - checkAlarm(conf.maxDistanceAlert,status.homeDist,ALARMS_MAX_DIST,1,"maxdist",menuItems[T2][4]) - checkAlarm(1,2*status.ekfFailsafe,ALARMS_FS_EKF,1,"ekf",menuItems[T2][4]) - checkAlarm(1,2*status.battFailsafe,ALARMS_FS_BATT,1,"lowbat",menuItems[T2][4]) - checkAlarm(conf.timerAlert,status.flightTime,ALARMS_TIMER,1,"timealert",conf.timerAlert) -end - -- default is use battery 1 - local capacity = getBatt1Capacity() - local mah = status.batt1mah - -- only if dual battery has been detected use battery 2 - if status.batt2sources.fc or status.batt2sources.vs then - capacity = capacity + getBatt2Capacity() - mah = mah + status.batt2mah - end - -- -#ifdef BATTPERC_BY_VOLTAGE - if conf.enableBattPercByVoltage == true then - -- discharge curve is based on battery under load, when motors are disarmed - -- cellvoltage needs to be corrected by subtracting the "under load" voltage drop - if status.statusArmed then - status.batLevel = getBattPercByCell(celm*0.01) - else - status.batLevel = getBattPercByCell((celm*0.01)-VOLTAGE_DROP) - end - else -#endif - if (capacity > 0) then - status.batLevel = (1 - (mah/capacity))*100 - else - status.batLevel = 99 - end -#ifdef BATTPERC_BY_VOLTAGE - end -#endif - for l=1,13 do - -- trigger alarm as as soon as it falls below level + 1 (i.e 91%,81%,71%,...) - if status.batLevel <= batLevels[l] + 1 and l < status.lastBattLevel then - status.lastBattLevel = l - playSound("bat"..batLevels[l]) - break - end - end - - if status.statusArmed == 1 and status.lastStatusArmed == 0 then - status.lastStatusArmed = status.statusArmed - playSound("armed") - elseif status.statusArmed == 0 and status.lastStatusArmed == 1 then - status.lastStatusArmed = status.statusArmed - playSound("disarmed") - end - - if status.gpsStatus > 2 and status.lastGpsStatus <= 2 then - status.lastGpsStatus = status.gpsStatus - playSound("gpsfix") - elseif status.gpsStatus <= 2 and status.lastGpsStatus > 2 then - status.lastGpsStatus = status.gpsStatus - playSound("gpsnofix") - end - - if status.frameType ~= -1 and status.flightMode ~= status.lastFlightMode then - status.lastFlightMode = status.flightMode - playSoundByFrameTypeAndFlightMode(status.flightMode) - end - - if status.simpleMode ~= status.lastSimpleMode then - if status.simpleMode == 0 then - playSound( status.lastSimpleMode == 1 and "simpleoff" or "ssimpleoff" ) - else - playSound( status.simpleMode == 1 and "simpleon" or "ssimpleon" ) - end - status.lastSimpleMode = status.simpleMode - end -end - -local function checkCellVoltage(celm) - -- check alarms - checkAlarm(conf.battAlertLevel1,celm,ALARMS_BATT_L1,-1,"batalert1",menuItems[T2][4]) - checkAlarm(conf.battAlertLevel2,celm,ALARMS_BATT_L2,-1,"batalert2",menuItems[T2][4]) - -- cell bgcolor is sticky but gets triggered with alarms - if status.battLevel1 == false then status.battLevel1 = alarms[ALARMS_BATT_L1][ALARM_NOTIFIED] end - if status.battLevel2 == false then status.battLevel2 = alarms[ALARMS_BATT_L2][ALARM_NOTIFIED] end -end - -local function cycleBatteryInfo() - if showDualBattery == false and (status.batt2sources.fc or status.batt2sources.vs) then - showDualBattery = true - return - end - if status.battsource == "vs" then - status.battsource = "fc" - elseif status.battsource == "fc" then - status.battsource = "a2" - elseif status.battsource == "a2" then - status.battsource = "vs" - end -end --------------------------------------------------------------------------------- --- MAIN LOOP --------------------------------------------------------------------------------- --- -local bgclock = 0 -#ifdef BGRATE -local counter = 0 -local bgrate = 0 -local bgstart = 0 -#endif --BGRATE -#ifdef FGRATE -local fgcounter = 0 -local fgrate = 0 -local fgstart = 0 -#endif --FGRATE -#ifndef WIDGET -#ifdef HUDRATE -local hudcounter = 0 -local hudrate = 0 -local hudstart = 0 -#endif --HUDRATE -#endif --WIDGET -#ifdef BGTELERATE -local bgtelecounter = 0 -local bgtelerate = 0 -local bgtelestart = 0 -#endif --BGTELERATE -#ifdef MEMDEBUG -local maxmem = 0 -#endif - -------------------------------- --- running at 20Hz (every 50ms) -------------------------------- -local bgprocessing = false -local bglockcounter = 0 --- -local function backgroundTasks(telemetryLoops) -if bgprocessing == true then - bglockcounter = bglockcounter + 1 - return 0 -end -bgprocessing = true -#ifdef BGRATE - ------------------------ - -- CALC BG LOOP RATE - ------------------------ - -- skip first iteration - local now = getTime()/100 - if counter == 0 then - bgstart = now - else - bgrate = counter / (now - bgstart) - end - -- - counter=counter+1 -#endif --BGRATE - -- FAST: this runs at 60Hz (every 16ms) - for i=1,telemetryLoops - do - processTelemetry() -#ifdef BGTELERATE - ------------------------ - -- CALC BG TELE PROCESSING RATE - ------------------------ - -- skip first iteration - local now = getTime()/100 - if bgtelecounter == 0 then - bgtelestart = now - else - bgtelerate = bgtelecounter / (now - bgtelestart) - end - -- - bgtelecounter=bgtelecounter+1 -#endif --BGTELERATE - end - -- NORMAL: this runs at 20Hz (every 50ms) - calcFlightTime() - -- SLOW: this runs at 4Hz (every 250ms) - if (bgclock % 4 == 0) then - setSensorValues() - collectgarbage() - end - -- SLOWER: this runs at 2Hz (every 500ms) - if (bgclock % 8 == 0) then - -- update battery - calcBattery() - -- prepare celm based on battsource - local count = calcCellCount() - local cellVoltage = 0 - -- - if status.battsource == "vs" then - cellVoltage = getNonZeroMin(status.cell1min, status.cell2min)*100 --FLVSS - elseif status.battsource == "fc" then - cellVoltage = getNonZeroMin(status.cell1sumFC/count,status.cell2sumFC/count)*100 --FC - elseif status.battsource == "a2" then - cellVoltage = (status.cellsumA2/count)*100 --A2 - end - -- - checkEvents(cellVoltage) - checkLandingStatus() - -- no need for alarms if reported voltage is 0 - if cellVoltage > 0 then - checkCellVoltage(cellVoltage) - end - -- aggregate value - minmaxValues[MAX_CURR] = math.max(status.batt1current+status.batt2current,minmaxValues[MAX_CURR]) - -- indipendent values - minmaxValues[MAX_CURR1] = math.max(status.batt1current,minmaxValues[MAX_CURR1]) - minmaxValues[MAX_CURR2] = math.max(status.batt2current,minmaxValues[MAX_CURR2]) - -- reset backlight panel - if (model.getGlobalVariable(BACKLIGHT_GV,0) > 0 and getTime()/100 - backlightLastTime > BACKLIGHT_DURATION) then - model.setGlobalVariable(BACKLIGHT_GV,0,0) - end - bgclock = 0 - end - bgclock = bgclock+1 - -- blinking support - if (getTime() - blinktime) > 65 then - blinkon = not blinkon - blinktime = getTime() - end - bgprocessing = false - return 0 -end - -local showSensorPage = false -local showMessages = false -#ifndef WIDGET -local showConfigMenu = false - -local function background() - backgroundTasks(5) -end --------------------------- --- RUN --------------------------- --- EVT_EXIT_BREAK = RTN -#define EVT_ENTER_LONG 2050 -#define EVT_ENTER_BREAK 514 - -#define EVT_MDL_FIRST 1539 -#define EVT_MDL_LONG 2051 -#define EVT_MDL_BREAK 515 - -#define EVT_SYS_FIRST 1542 -#define EVT_SYS_LONG 2054 -#define EVT_SYS_BREAK 518 - -#define EVT_PAGEUP_FIRST 1536 -#define EVT_PAGEUP_LONG 2048 -#define EVT_PAGEUP_BREAK 512 - -#define EVT_PAGEDN_FIRST 1537 -#define EVT_PAGEDN_LONG 2049 -#define EVT_PAGEDN_BREAK 513 - -#define EVT_TELE_FIRST 1541 -#define EVT_TELE_LONG 2053 - - -local function run(event) -#ifdef DEBUGEVT - if (event ~= 0) then - pushMessage(7,string.format("Event: %d",event)) - end -#endif - background() - lcd.clear() -#ifdef FGRATE - ------------------------ - -- CALC FG LOOP RATE - ------------------------ - -- skip first iteration - local now = getTime()/100 - if fgcounter == 0 then - fgstart = now - else - fgrate = fgcounter / (now - fgstart) - end - -- - fgcounter=fgcounter+1 -#endif --FGRATE - --------------------- - -- SHOW MESSAGES - --------------------- - if showConfigMenu == false and (event == EVT_PLUS_BREAK or event == EVT_ROT_RIGHT) then - showMessages = true - -- stop event processing chain - event = 0 - end - --------------------- - -- SHOW CONFIG MENU - --------------------- - if showMessages == false and (event == EVT_TELE_LONG or event == EVT_MDL_LONG ) then - showConfigMenu = true - -- stop event processing chain - event = 0 - end - --------------------- - -- SHOW SENSORS PAGE - --------------------- - -- - if showSensorPage == false and showConfigMenu == false and showMessages == false and (event == EVT_PAGEDN_FIRST or event == EVT_PAGEUP_FIRST) then - showSensorPage = true - -- stop event processing chain - event = 0 - end - - if showMessages then - --------------------- - -- MESSAGES - --------------------- - if event == EVT_EXIT_BREAK or event == EVT_MINUS_BREAK or event == EVT_ROT_LEFT then - showMessages = false - end - drawAllMessages() - elseif showConfigMenu then - --------------------- - -- CONFIG MENU - --------------------- - drawConfigMenu(event) - -- - if event == EVT_EXIT_BREAK then - menu.editSelected = false - showConfigMenu = false - saveConfig() - end - else - --------------------- - -- MAIN VIEW - --------------------- - if event == EVT_SYS_BREAK then - showMinMaxValues = not showMinMaxValues - -- stop event processing chain - event = 0 - end - if showDualBattery == true and event == EVT_EXIT_BREAK then - showDualBattery = false - -- stop event processing chain - event = 0 - end - if showSensorPage == true and event == EVT_EXIT_BREAK or event == EVT_PAGEDN_FIRST or event == EVT_PAGEUP_FIRST then - showSensorPage = false - -- stop event processing chain - event = 0 - end - if event == EVT_ROT_BREAK then - cycleBatteryInfo() - -- stop event processing chain - event = 0 - end -#ifdef TESTMODE - symMode() -#endif --TESTMODE -#ifdef HUDRATE - ------------------------ - -- CALC HUD REFRESH RATE - ------------------------ - -- skip first iteration - local hudnow = getTime()/100 - if hudcounter == 0 then - hudstart = hudnow - else - hudrate = hudcounter / (hudnow - hudstart) - end - -- - hudcounter=hudcounter+1 -#endif --HUDRATE - drawHomeDirection() - drawHud() - drawCompassRibbon() - -- - -- Note: these can be calculated. not necessary to track them as min/max - -- status.cell1minFC = status.cell1sumFC/calcCellCount() - -- status.cell2minFC = status.cell2sumFC/calcCellCount() - -- status.cell1minA2 = status.cell1sumA2/calcCellCount() - -- - local count = calcCellCount() - local cel1m = getMinVoltageBySource(status.battsource,status.cell1min,status.cell1sumFC/count,status.cellsumA2/count,1,count)*100 - local cel2m = getMinVoltageBySource(status.battsource,status.cell2min,status.cell2sumFC/count,status.cellsumA2/count,2,count)*100 - local batt1 = getMinVoltageBySource(status.battsource,status.cell1sum,status.cell1sumFC,status.cellsumA2,1,count)*10 - local batt2 = getMinVoltageBySource(status.battsource,status.cell2sum,status.cell2sumFC,status.cellsumA2,2,count)*10 - local curr = getMaxValue(status.batt1current+status.batt2current,MAX_CURR) - local curr1 = getMaxValue(status.batt1current,MAX_CURR1) - local curr2 = getMaxValue(status.batt2current,MAX_CURR2) - local mah1 = status.batt1mah - local mah2 = status.batt2mah - local cap1 = getBatt1Capacity() - local cap2 = getBatt2Capacity() - -- - -- with dual battery default is to show aggregate view - if status.batt2sources.fc or status.batt2sources.vs then - if showDualBattery == false then - -- dual battery: aggregate view - lcd.drawText(285+BATTINFO_B1B2_X,BATTINFO_Y,"BATTERY: 1+2",SMLSIZE+INVERS) - drawBatteryPane(285,getNonZeroMin(batt1,batt2),getNonZeroMin(cel1m,cel2m),curr,mah1+mah2,cap1+cap2) - else - -- dual battery: do I have also dual current monitor? - if curr1 > 0 and curr2 == 0 then - -- special case: assume 1 power brick is monitoring batt1+batt2 in parallel - curr1 = curr1/2 - curr2 = curr1 - -- - mah1 = mah1/2 - mah2 = mah1 - -- - cap1 = cap1/2 - cap2 = cap1 - end - -- dual battery:battery 1 right pane - lcd.drawText(285+BATTINFO_B1_X,BATTINFO_Y,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - -- dual battery:battery 2 left pane - lcd.drawText(BATTINFO_B2_X,BATTINFO_Y,"BATTERY: 2",SMLSIZE+INVERS) - drawBatteryPane(-24,batt2,cel2m,curr2,mah2,cap2) - end - else - -- battery 1 right pane in single battery mode - lcd.drawText(285+BATTINFO_B1_X,BATTINFO_Y,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - end - -- left pane info when not in dual battery mode - if showDualBattery == false then - -- power is always based on flight controller values - drawGPSStatus() - if showSensorPage then - drawCustomSensors() - else - drawLeftPane(curr1+curr2,getNonZeroMin(status.cell1sumFC,status.cell2sumFC)) - end - end - drawFlightMode() - drawTopBar() - drawBottomBar() - drawFlightTime() - drawFailsafe() - drawArmStatus() -#ifdef DEBUG - lcd.drawNumber(0,40,status.cell1maxFC,SMLSIZE+PREC1) - lcd.drawNumber(25,40,calcCellCount(),SMLSIZE) -#endif --DEBUG -#ifdef BGRATE - local bgrateTxt = string.format("BG:%.01fHz",bgrate) - lcd.drawText(0,30,bgrateTxt,SMLSIZE+INVERS) -#endif --BGRATE -#ifdef FGRATE - local fgrateTxt = string.format("FG:%.01fHz",fgrate) - lcd.drawText(0,50,fgrateTxt,SMLSIZE+INVERS) -#endif --FGRATE -#ifdef HUDTIMER - local hudtimerTxt = string.format("%.01fms",10*hudDrawTime/hudDrawCounter) - lcd.drawText(95,1,hudtimerTxt,SMLSIZE+INVERS) -#endif --HUDTIMER -#ifdef TELERATE - lcd.drawNumber(0,110,telerate,SMLSIZE+INVERS) -#endif --TELERATE - if showDualBattery == false and showSensorPage == false then -#ifdef HUDRATE - local hudrateTxt = string.format("H:%.01fHz",hudrate) - lcd.drawText(2,76,hudrateTxt,SMLSIZE) -#endif --HUDRATE -#ifdef BGTELERATE - local bgtelerateTxt = string.format("B:%.01fHz",bgtelerate) - lcd.drawText(160,76,bgtelerateTxt,SMLSIZE+RIGHT) -#endif --BGTELERATE - end - drawNoTelemetryData() - end - return 0 -end -#endif --WIDGET - -local function init() -#ifdef COMPILE - loadScript("/SCRIPTS/YAAPU/menu.lua") - loadScript("/SCRIPTS/YAAPU/LIB/init.lua") - loadScript("/SCRIPTS/YAAPU/LIB/copter.lua") - loadScript("/SCRIPTS/YAAPU/LIB/plane.lua") - loadScript("/SCRIPTS/YAAPU/LIB/rover.lua") -#endif - -- initialize flight timer - model.setTimer(2,{mode=0}) -#ifdef TESTMODE - --model.setTimer(2,{value=5000}) -#else - model.setTimer(2,{value=0}) -#endif -#ifdef WIDGET - currentModel = model.getInfo().name -#endif --WIDGET - loadConfig() -#ifdef TESTMODE -#ifdef DEMO - pushMessage(6,"APM:Copter V3.5.4 (284349c3) QUAD") - pushMessage(6,"Calibrating barometer") - pushMessage(6,"Initialising APM") - pushMessage(6,"Barometer calibration complete") - pushMessage(6,"EKF2 IMU0 initial yaw alignment complete") - pushMessage(6,"EKF2 IMU1 initial yaw alignment complete") - pushMessage(6,"GPS 1: detected as u-blox at 115200 baud") - pushMessage(6,"EKF2 IMU0 tilt alignment complete") - pushMessage(6,"EKF2 IMU1 tilt alignment complete") - pushMessage(6,"u-blox 1 HW: 00080000 SW: 2.01 (75331)") -#else -- add some more messages to force memory allocation :-) - pushMessage(6,"APM:Copter V3.5.4 (284349c3) QUAD") - pushMessage(6,"Calibrating barometer") - pushMessage(6,"Initialising APM") - pushMessage(6,"Barometer calibration complete") - pushMessage(6,"EKF2 IMU0 initial yaw alignment complete") - pushMessage(6,"EKF2 IMU1 initial yaw alignment complete") - pushMessage(6,"GPS 1: detected as u-blox at 115200 baud") - pushMessage(6,"EKF2 IMU0 tilt alignment complete") - pushMessage(6,"EKF2 IMU1 tilt alignment complete") -#endif --DEMO -#endif --TESTMODE -#ifdef LOGTELEMETRY - logfilename = getLogFilename(getDateTime()) - logfile = io.open(logfilename,"a") - pushMessage(7,logfilename) -#endif --LOGTELEMETRY - playSound("yaapu") -#ifndef WIDGET -#ifndef DEMO - loadSensors() -#endif --DEMO -#endif --WIDGET -#ifndef DEMO - pushMessage(7,VERSION) -#endif - -- load unit definitions - unitScale = getGeneralSettings().imperial == 0 and 1 or 3.28084 - unitLabel = getGeneralSettings().imperial == 0 and "m" or "ft" -end - --------------------------------------------------------------------------------- --- SCRIPT END --------------------------------------------------------------------------------- -#ifdef WIDGET --- 4 pages --- page 1 single battery view --- page 2 message history --- page 3 min max --- page 4 dual battery view -local options = { - { "page", VALUE, 1, 1, 4}, -} - -local widgetPages = { - {active=false, bgtasks=false, fgtasks=false}, - {active=false, bgtasks=false, fgtasks=false}, - {active=false, bgtasks=false, fgtasks=false}, - {active=false, bgtasks=false, fgtasks=false} -} ---------------------- --- script version ---------------------- --- shared init flag -local initDone = 0 --- This function is runned once at the creation of the widget -local function create(zone, options) - -- this vars are widget scoped, each instance has its own set - local vars = { - #ifdef HUDRATE - hudcounter = 0, - hudrate = 0, - hudstart = 0, - #endif --HUDRATE - } - -- all local vars are shared between widget instances - -- init() needs to be called only once! - if initDone == 0 then - init() - initDone = 1 - end - -- register current page as active - widgetPages[options.page].active = true - -- - return { zone=zone, options=options, vars=vars } -end - --- This function allow updates when you change widgets settings -local function update(myWidget, options) - myWidget.options = options - -- register current page as active - widgetPages[options.page].active = true - -- reload menu settings - loadConfig() -end -local function fullScreenRequired(myWidget) - lcd.setColor(CUSTOM_COLOR,lcd.RGB(255, 0, 0)) - lcd.drawText(myWidget.zone.x,myWidget.zone.y,"Yaapu requires",SMLSIZE+CUSTOM_COLOR) - lcd.drawText(myWidget.zone.x,myWidget.zone.y+16,"full screen",SMLSIZE+CUSTOM_COLOR) - --[[ - if myWidget.zone.h > 100 then - local strsize = string.format("%d x %d",myWidget.zone.w,myWidget.zone.h) - lcd.drawText(myWidget.zone.x,myWidget.zone.y+32,strsize,SMLSIZE+CUSTOM_COLOR) - end - --]] -end --- This size is for top bar widgets -local function zoneTiny(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 160x30 1/8th -local function zoneSmall(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 180x70 1/4th -local function zoneMedium(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 190x150 -local function zoneLarge(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 390x170 -local function zoneXLarge(myWidget) - fullScreenRequired(myWidget) -end ---- Size is 480x272 -local function zoneFullScreen(myWidget) -#ifdef FGRATE - ------------------------ - -- CALC FG LOOP RATE - ------------------------ - -- skip first iteration - local now = getTime()/100 - if fgcounter == 0 then - fgstart = now - else - fgrate = fgcounter / (now - fgstart) - end - -- - fgcounter=fgcounter+1 -#endif --FGRATE -#ifdef TESTMODE - symMode() -#endif --TESTMODE - -------------------------- - -- Widget Page 2 is message history - -------------------------- - if myWidget.options.page == 2 then - drawAllMessages() - else -#ifdef HUDRATE - ------------------------ - -- CALC HUD REFRESH RATE - ------------------------ - -- skip first iteration - local hudnow = getTime()/100 - if myWidget.vars.hudcounter == 0 then - myWidget.vars.hudstart = hudnow - else - myWidget.vars.hudrate = myWidget.vars.hudcounter / (hudnow - myWidget.vars.hudstart) - end - -- - myWidget.vars.hudcounter=myWidget.vars.hudcounter+1 -#endif --HUDRATE - drawHomeDirection() - drawHud(myWidget) - drawCompassRibbon() - -- - -- Note: these can be calculated. not necessary to track them as min/max - -- status.cell1minFC = status.cell1sumFC/calcCellCount() - -- status.cell2minFC = status.cell2sumFC/calcCellCount() - -- status.cell1minA2 = status.cell1sumA2/calcCellCount() - -- - local count = calcCellCount() - local cel1m = getMinVoltageBySource(status.battsource,status.cell1min,status.cell1sumFC/count,status.cellsumA2/count,1,count)*100 - local cel2m = getMinVoltageBySource(status.battsource,status.cell2min,status.cell2sumFC/count,status.cellsumA2/count,2,count)*100 - local batt1 = getMinVoltageBySource(status.battsource,status.cell1sum,status.cell1sumFC,status.cellsumA2,1,count)*10 - local batt2 = getMinVoltageBySource(status.battsource,status.cell2sum,status.cell2sumFC,status.cellsumA2,2,count)*10 - local curr = getMaxValue(status.batt1current+status.batt2current,MAX_CURR) - local curr1 = getMaxValue(status.batt1current,MAX_CURR1) - local curr2 = getMaxValue(status.batt2current,MAX_CURR2) - local mah1 = status.batt1mah - local mah2 = status.batt2mah - local cap1 = getBatt1Capacity() - local cap2 = getBatt2Capacity() - -- - -- with dual battery default is to show aggregate view - if status.batt2sources.fc or status.batt2sources.vs then - if showDualBattery == false then - -- dual battery: aggregate view - lcd.drawText(285+67,85,"BATTERY: 1+2",SMLSIZE+INVERS) - drawBatteryPane(285,getNonZeroMin(batt1,batt2),getNonZeroMin(cel1m,cel2m),curr,mah1+mah2,cap1+cap2) - else - -- dual battery: do I have also dual current monitor? - if curr1 > 0 and curr2 == 0 then - -- special case: assume 1 power brick is monitoring batt1+batt2 in parallel - curr1 = curr1/2 - curr2 = curr1 - -- - mah1 = mah1/2 - mah2 = mah1 - -- - cap1 = cap1/2 - cap2 = cap1 - end - -- dual battery:battery 1 right pane - lcd.drawText(285+75,85,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - -- dual battery:battery 2 left pane - lcd.drawText(50,85,"BATTERY: 2",SMLSIZE+INVERS) - drawBatteryPane(-24,batt2,cel2m,curr2,mah2,cap2) - end - else - -- battery 1 right pane in single battery mode - lcd.drawText(285+75,85,"BATTERY: 1",SMLSIZE+INVERS) - drawBatteryPane(285,batt1,cel1m,curr1,mah1,cap1) - end - -- left pane info when not in dual battery mode - if showDualBattery == false then - -- power is always based on flight controller values - drawGPSStatus() - if showSensorPage then - drawCustomSensors() - else - drawLeftPane(curr1+curr2,getNonZeroMin(status.cell1sumFC,status.cell2sumFC)) - end - end - drawFlightMode() - drawTopBar() - drawBottomBar() - drawFlightTime() - drawFailsafe() - drawArmStatus() -#ifdef DEBUG - lcd.drawNumber(0,40,status.cell1maxFC,SMLSIZE+PREC1) - lcd.drawNumber(25,40,calcCellCount(),SMLSIZE) -#endif --DEBUG -#ifdef BGRATE - local bgrateTxt = string.format("BG:%.01fHz",bgrate) - lcd.drawText(0,30,bgrateTxt,SMLSIZE+INVERS) -#endif --BGRATE -#ifdef FGRATE - local fgrateTxt = string.format("FG:%.01fHz",fgrate) - lcd.drawText(0,50,fgrateTxt,SMLSIZE+INVERS) -#endif --FGRATE -#ifdef HUDTIMER - local hudtimerTxt = string.format("%.01fms",10*hudDrawTime/hudDrawCounter) - lcd.drawText(95,1,hudtimerTxt,SMLSIZE+INVERS) -#endif --HUDTIMER -#ifdef TELERATE - lcd.drawNumber(0,110,telerate,SMLSIZE+INVERS) -#endif --TELERATE - if showDualBattery == false and showSensorPage == false then -#ifdef HUDRATE - local hudrateTxt = string.format("H:%.01fHz",myWidget.vars.hudrate) - lcd.drawText(2,76,hudrateTxt,SMLSIZE) -#endif --HUDRATE -#ifdef BGTELERATE - local bgtelerateTxt = string.format("B:%.01fHz",bgtelerate) - lcd.drawText(160,76,bgtelerateTxt,SMLSIZE+RIGHT) -#endif --BGTELERATE - end - end - drawNoTelemetryData() -#ifdef MEMDEBUG - maxmem = math.max(maxmem,collectgarbage("count")*1024) - -- test with absolute coordinates - lcd.drawNumber(LCD_W,LCD_H-16,maxmem,SMLSIZE+MENU_TITLE_COLOR+RIGHT) -#endif -#ifdef WIDGETDEBUG - local strpages = "" - local p = "" - -- for each registered page - for i=1,4 do - p=i - if widgetPages[i].fgtasks == true then - p="F" - end - if widgetPages[i].bgtasks == true then - p="B" - end - if widgetPages[i].active == true then - if i == myWidget.options.page then - -- this is the current widget - strpages = strpages.."["..p.."]" - else - strpages = strpages..p - end - end - end - lcd.drawText(LCD_W,LCD_H-71,strpages,SMLSIZE+RIGHT) - lcd.drawNumber(LCD_W,LCD_H-36,bglockcounter,SMLSIZE+RIGHT) -#endif --WIDGETDEBUG -end - --- called when widget instance page changes -local function onChangePage(myWidget) -#ifdef WIDGETDEBUG - playTone(300,200,0,PLAY_BACKGROUND) -#endif --WIDGETDEBUG -#ifdef BGTELERATE - bgtelecounter = 0 -#endif --BGTELERATE - -- reset HUD counters - myWidget.vars.hudcounter = 0 - -- refresh config on page change so it's possible to use menu in one time mode - loadConfig() - collectgarbage() -end - --- Called when script is hidden @20Hz -local function background(myWidget) - -- when page 3 goes to background hide minmax values - if myWidget.options.page == 3 then - showMinMaxValues = false - return - end - -- when page 4 goes to background hide dual battery view - if myWidget.options.page == 4 then - showDualBattery = false - return - end - -- when page 1 goes to background run bg tasks only if page 2 is not registered - if myWidget.options.page == 1 and widgetPages[2].active == false then -#ifdef WIDGETDEBUG - -- reset flags - for i=1,4 do - widgetPages[i].fgtasks=false - widgetPages[i].bgtasks=false - end - -- set bg active page - widgetPages[1].bgtasks=true -#endif --WIDGETDEBUG - -- run bg tasks - backgroundTasks(6) - return - end - -- when page 2 goes to background always run bg tasks - if myWidget.options.page == 2 then -#ifdef WIDGETDEBUG - -- reset flags - for i=1,4 do - widgetPages[i].fgtasks=false - widgetPages[i].bgtasks=false - end - -- set bg active page - widgetPages[2].bgtasks=true -#endif --WIDGETDEBUG - -- run bg tasks - backgroundTasks(6) - end -end - --- Called when script is visible -function refresh(myWidget) - -- check if current widget page changed - if currentPage ~= myWidget.options.page then - currentPage = myWidget.options.page - onChangePage(myWidget) - end - -- when page 1 goes to foreground run bg tasks only if page 2 is not registered - if myWidget.options.page == 1 and widgetPages[2].active == false then -#ifdef WIDGETDEBUG - -- reset flags - for i=1,4 do - widgetPages[i].fgtasks=false - widgetPages[i].bgtasks=false - end - -- set fg active page - widgetPages[1].fgtasks=true -#endif --WIDGETDEBUG - -- run bg tasks - backgroundTasks(6) - end - -- if widget page 2 is declared then always run bg tasks when in foreground - if myWidget.options.page == 2 then -#ifdef WIDGETDEBUG - -- reset flags - for i=1,4 do - widgetPages[i].fgtasks=false - widgetPages[i].bgtasks=false - end - -- set fg active page - widgetPages[2].fgtasks=true -#endif --WIDGETDEBUG - -- run bg tasks - backgroundTasks(4) - end - -- when page 3 goes to foreground show minmax values - if myWidget.options.page == 3 then - showMinMaxValues = true - end - -- when page 4 goes to foreground show dual battery view - if myWidget.options.page == 4 then - showDualBattery = true - end - -- - if myWidget.zone.w > 450 and myWidget.zone.h > 250 then zoneFullScreen(myWidget) - elseif myWidget.zone.w > 380 and myWidget.zone.h > 165 then zoneXLarge(myWidget) - elseif myWidget.zone.w > 180 and myWidget.zone.h > 145 then zoneLarge(myWidget) - elseif myWidget.zone.w > 170 and myWidget.zone.h > 65 then zoneMedium(myWidget) - elseif myWidget.zone.w > 150 and myWidget.zone.h > 28 then zoneSmall(myWidget) - elseif myWidget.zone.w > 65 and myWidget.zone.h > 35 then zoneTiny(myWidget) - end -end - -return { name="Yaapu", options=options, create=create, update=update, background=background, refresh=refresh } -#else --WIDGET -return {run=run, init=init} -#endif --WIDGET \ No newline at end of file diff --git a/TARANIS/SD/SOUNDS/yaapu0/en/follow_r.wav b/TARANIS/SD/SOUNDS/yaapu0/en/follow_r.wav new file mode 100644 index 00000000..17ced008 Binary files /dev/null and b/TARANIS/SD/SOUNDS/yaapu0/en/follow_r.wav differ diff --git a/TARANIS/SD/SOUNDS/yaapu0/en/initializing_r.wav b/TARANIS/SD/SOUNDS/yaapu0/en/initializing_r.wav new file mode 100644 index 00000000..31fe6bb7 Binary files /dev/null and b/TARANIS/SD/SOUNDS/yaapu0/en/initializing_r.wav differ diff --git a/TARANIS/SD/SOUNDS/yaapu0/it/follow_r.wav b/TARANIS/SD/SOUNDS/yaapu0/it/follow_r.wav new file mode 100644 index 00000000..e93dfa51 Binary files /dev/null and b/TARANIS/SD/SOUNDS/yaapu0/it/follow_r.wav differ diff --git a/TARANIS/SD/SOUNDS/yaapu0/it/initializing_r.wav b/TARANIS/SD/SOUNDS/yaapu0/it/initializing_r.wav new file mode 100644 index 00000000..e7fa259b Binary files /dev/null and b/TARANIS/SD/SOUNDS/yaapu0/it/initializing_r.wav differ diff --git a/horus-changelog.txt b/horus-changelog.txt index 53fe2aea..6cc85d7d 100644 --- a/horus-changelog.txt +++ b/horus-changelog.txt @@ -63,3 +63,22 @@ Horus version 1.7.3 Horus version 1.7.4 - fix for imperial settings not being picked up at widget start (OpenTX 2.2.3) + +Horus version 1.8.0 + +- removed dependency from blue theme +- added new hud layout, speed on left, alt on right VSI on bottom +- new message history screen with telemetry info +- added support for up to 6 user selectable frsky sensors +- added haptic feedback support +- added total flown distance (calculated from speed) +- added PX4 flight modes support +- added support for mavlinkToPassthru firmware +- added vocal playback of selected mavlink messages +- added support fot series and independent battery configurations with individual cell count override +- added support for battery voltage > 51.1V +- added new message alert silencing options +- added menu option to define a channel to toggle between main screen and message history +- added support for boat frametype +- fix for quick flight mode switch +- fix for rover modes vocal playback