diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index b895ba5ab..897257775 100644 --- a/companion/src/CMakeLists.txt +++ b/companion/src/CMakeLists.txt @@ -87,6 +87,13 @@ add_custom_command( WORKING_DIRECTORY ${RADIO_SRC_DIRECTORY} ) +add_custom_command( + OUTPUT ${RADIO_SRC_DIRECTORY}/lua_exports.inc + COMMAND make lua_exports.cpp + DEPENDS ${RADIO_SRC_DIRECTORY}/myeeprom.h + WORKING_DIRECTORY ${RADIO_SRC_DIRECTORY} +) + include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/../.. @@ -112,6 +119,7 @@ set(common_SRCS firmwares/ersky9x/ersky9xinterface.cpp ${RADIO_SRC_DIRECTORY}/bitmaps/sticks.lbm ${RADIO_SRC_DIRECTORY}/translations/en.h + ${RADIO_SRC_DIRECTORY}/lua_exports.inc firmwares/opentx/opentxeeprom.cpp firmwares/opentx/open9xStockeeprom.cpp firmwares/opentx/open9xGruvin9xeeprom.cpp @@ -312,6 +320,7 @@ set(simu_SRCS ${ERSKY9X_CHECKOUT_DIRECTORY}/ersky9xsimulator.cpp ${RADIO_SRC_DIRECTORY}/bitmaps/sticks.lbm ${RADIO_SRC_DIRECTORY}/translations/en.h + ${RADIO_SRC_DIRECTORY}/lua_exports.inc modeledit/node.cpp modeledit/edge.cpp # TODO not needed simulator.cpp diff --git a/radio/src/.gitignore b/radio/src/.gitignore index 0cc98b78d..a2571c6d7 100644 --- a/radio/src/.gitignore +++ b/radio/src/.gitignore @@ -24,3 +24,5 @@ /gtests /gtest_main.a /gtests.d +/lua_exports.cpp +/lua_exports.txt diff --git a/radio/src/Makefile b/radio/src/Makefile index 60e7b57e1..b06c34edc 100644 --- a/radio/src/Makefile +++ b/radio/src/Makefile @@ -302,6 +302,7 @@ SRC = CPPSRC = INCDIRS = . translations EXTRAINCDIRS = +LUADEP = # MCU name ifneq ($(PCB), $(filter $(PCB), STD 9X 9XR STD128 9X128 9XR128 9X2561 9XR2561 GRUVIN9X MEGA2560 SKY9X 9XRPRO TARANIS)) @@ -729,6 +730,7 @@ ifeq ($(PCB), TARANIS) lua/src/lbaselib.c lua/src/linit.c lua/src/lmathlib.c lua/src/loadlib.c lua/src/lauxlib.c lua/src/ltablib.c lua/src/lcorolib.c # lua/src/loslib.c lua/src/lbitlib.c lua/src/lstrlib.c lua/src/liolib.c lua/src/ldblib.c SRC += $(LUASRC) + LUADEP = lua_exports.cpp endif ifeq ($(SDCARD), YES) @@ -1156,7 +1158,7 @@ all: begin gccversion sizebefore build sizeafter end ifeq ($(ARCH), AVR) build: stamp_header tra lbm allsrc.cpp elf remallsrc hex else ifeq ($(PCB), $(filter $(PCB), SKY9X 9XRPRO TARANIS)) - build: stamp_header tra lbm bootloader.lbm allsrc.cpp elf remallsrc bin + build: stamp_header tra lbm bootloader.lbm $(LUADEP) allsrc.cpp elf remallsrc bin else build: stamp_header tra lbm allsrc.cpp elf remallsrc bin endif @@ -1272,6 +1274,12 @@ bitmaps/sticks.lbm: bitmaps/sticks_4x1.xbm bitmaps/splash_9x.xbm bitmaps/splash_ $(IMG2LBM) bitmaps/about_taranis.png bitmaps/about_taranis.lbm bmp $(IMG2LBM) bitmaps/about_9x.png bitmaps/about_9x.lbm img $(IMG2LBM) bitmaps/asterisk_4bits.png bitmaps/asterisk_4bits.lbm bmp + +lua_exports.cpp: myeeprom.h ../util/luaexport.py + @echo "Generating a list of Lua exported constants in lua_exports.txt" + @cpp -DPCBTARANIS -DCPUARM -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports.txt + @echo "Parsing and generating C Lua exports in lua_exports.cpp" + @python ../util/luaexport.py lua_exports.txt lua_exports.cpp # Eye candy. # AVR Studio 3.x does not check make's exit code but relies on @@ -1313,7 +1321,7 @@ FOXLIB=-L/usr/local/lib \ -lFOX-1.6 \ -Wl,-rpath,$(FOXPATH)/src/.libs -simu: stamp_header $(BOARDSRC) $(CPPSRC) Makefile simu.cpp targets/simu/simpgmspace.cpp *.h tra lbm eeprom.bin +simu: $(LUADEP) stamp_header $(BOARDSRC) $(CPPSRC) Makefile simu.cpp targets/simu/simpgmspace.cpp *.h tra lbm eeprom.bin g++ $(CPPFLAGS) $(INCFLAGS) simu.cpp $(BOARDSRC) $(CPPSRC) $(LUASRC) targets/simu/simpgmspace.cpp -MD -DSIMU -O0 -o simu $(FOXINC) $(FOXLIB) -pthread -fexceptions eeprom.bin: @@ -1410,6 +1418,7 @@ clean_list : $(REMOVE) stamp-opentx.h $(REMOVE) bitmaps/*.lbm $(REMOVE) fonts/*/*.lbm + $(REMOVE) lua_exports.txt lua_exports.cpp $(MAKE) -C bootloader clean #### Install @@ -1492,3 +1501,4 @@ GTEST_TESTS_SRCS = $(shell find tests/ -type f -name '*.cpp') gtests: $(BOARDSRC) $(CPPSRC) $(GTEST_TESTS_SRCS) targets/simu/simpgmspace.cpp *.h gtest_main.a g++ -std=gnu++0x $(CPPFLAGS) $(BOARDSRC) $(CPPSRC) $(GTEST_TESTS_SRCS) targets/simu/simpgmspace.cpp -I$(GTEST_DIR) ${INCFLAGS} -I$(GTEST_DIR)/include -o gtests -lpthread -MD -DSIMU -lQtCore -lQtGui gtest_main.a + diff --git a/radio/src/lua.cpp b/radio/src/lua.cpp index a9a26fa31..ff84ee595 100644 --- a/radio/src/lua.cpp +++ b/radio/src/lua.cpp @@ -34,6 +34,8 @@ * */ +#include +#include #include "opentx.h" #include "stamp-opentx.h" @@ -47,13 +49,16 @@ extern "C" { } #endif +#include "lua_exports.cpp" // this line must be after lua headers + #define lua_registernumber(L, n, i) (lua_pushnumber(L, (i)), lua_setglobal(L, (n))) #define lua_registerint(L, n, i) (lua_pushinteger(L, (i)), lua_setglobal(L, (n))) #define lua_pushtablenil(L, k) (lua_pushstring(L, (k)), lua_pushnil(L), lua_settable(L, -3)) #define lua_pushtableboolean(L, k, v) (lua_pushstring(L, (k)), lua_pushboolean(L, (v)), lua_settable(L, -3)) #define lua_pushtableinteger(L, k, v) (lua_pushstring(L, (k)), lua_pushinteger(L, (v)), lua_settable(L, -3)) #define lua_pushtablenumber(L, k, v) (lua_pushstring(L, (k)), lua_pushnumber(L, (v)), lua_settable(L, -3)) -#define lua_pushtablestring(L, k, v) { char tmp[sizeof(v)+1]; strncpy(tmp, (v), sizeof(v)); tmp[sizeof(v)] = '\0'; lua_pushstring(L, (k)); lua_pushstring(L, tmp); lua_settable(L, -3); } +#define lua_pushtablestring(L, k, v) (lua_pushstring(L, (k)), lua_pushstring(L, (v)), lua_settable(L, -3)) +#define lua_pushtablenzstring(L, k, v) { char tmp[sizeof(v)+1]; strncpy(tmp, (v), sizeof(v)); tmp[sizeof(v)] = '\0'; lua_pushstring(L, (k)); lua_pushstring(L, tmp); lua_settable(L, -3); } #define lua_pushtablezstring(L, k, v) { char tmp[sizeof(v)+1]; zchar2str(tmp, (v), sizeof(v)); lua_pushstring(L, (k)); lua_pushstring(L, tmp); lua_settable(L, -3); } #define lua_registerlib(L, name, tab) (luaL_newmetatable(L, name), luaL_setfuncs(L, tab, 0), lua_setglobal(L, name)) @@ -97,14 +102,17 @@ static int luaGetTime(lua_State *L) static void luaGetValueAndPush(int src) { - /* - Hint about dividers are taken from putsTelemetryChannel() - */ - if (!TELEMETRY_STREAMING() && src>=MIXSRC_FIRST_TELEM && src<=MIXSRC_LAST_TELEM) { - //telemetry not working, return zero for telemetry sources - lua_pushinteger(L, (int)0); - return; + if (src >= MIXSRC_FIRST_TELEM && src <= MIXSRC_LAST_TELEM) { + // telemetry values + if ((src != MIXSRC_FIRST_TELEM-1+TELEM_TX_VOLTAGE) && !TELEMETRY_STREAMING()) { + // telemetry not working, return zero for telemetry sources + // except for "tx voltage" + lua_pushinteger(L, (int)0); + return; + } } + + int idx = src; switch (src) { case MIXSRC_FIRST_TELEM-1+TELEM_TX_VOLTAGE: case MIXSRC_FIRST_TELEM-1+TELEM_VFAS: @@ -113,21 +121,25 @@ static void luaGetValueAndPush(int src) case MIXSRC_FIRST_TELEM-1+TELEM_MIN_CELLS_SUM: case MIXSRC_FIRST_TELEM-1+TELEM_CURRENT: case MIXSRC_FIRST_TELEM-1+TELEM_MAX_CURRENT: - case MIXSRC_FIRST_TELEM-1+TELEM_VSPEED: - //theese need to be divided by 10 + case MIXSRC_FIRST_TELEM-1+TELEM_ASPEED: + case MIXSRC_FIRST_TELEM-1+TELEM_MAX_ASPEED: + // these need to be divided by 10 lua_pushnumber(L, getValue(src)/10.0); break; - case MIXSRC_FIRST_TELEM-1+TELEM_A1: - case MIXSRC_FIRST_TELEM-1+TELEM_A2: - //convert raw A1/2 values to calibrated values - lua_pushnumber(L, applyChannelRatio(src-(MIXSRC_FIRST_TELEM-1+TELEM_A1), getValue(src))/100.0); - break; - case MIXSRC_FIRST_TELEM-1+TELEM_MIN_A1: case MIXSRC_FIRST_TELEM-1+TELEM_MIN_A2: - //convert raw A1/2 values to calibrated values - lua_pushnumber(L, applyChannelRatio(src-(MIXSRC_FIRST_TELEM-1+TELEM_MIN_A1), getValue(src))/100.0); + case MIXSRC_FIRST_TELEM-1+TELEM_MIN_A3: + case MIXSRC_FIRST_TELEM-1+TELEM_MIN_A4: + idx -= TELEM_MIN_A1-TELEM_A1; + // no break + case MIXSRC_FIRST_TELEM-1+TELEM_A1: + case MIXSRC_FIRST_TELEM-1+TELEM_A2: + case MIXSRC_FIRST_TELEM-1+TELEM_A3: + case MIXSRC_FIRST_TELEM-1+TELEM_A4: + // convert raw Ax values to calibrated values + idx -= (MIXSRC_FIRST_TELEM+TELEM_A1-1); + lua_pushnumber(L, applyChannelRatio(idx, getValue(src))/100.0); break; case MIXSRC_FIRST_TELEM-1+TELEM_CELL: @@ -136,7 +148,8 @@ static void luaGetValueAndPush(int src) case MIXSRC_FIRST_TELEM-1+TELEM_ACCx: case MIXSRC_FIRST_TELEM-1+TELEM_ACCy: case MIXSRC_FIRST_TELEM-1+TELEM_ACCz: - //theese need to be divided by 100 + case MIXSRC_FIRST_TELEM-1+TELEM_VSPEED: + // these need to be divided by 100 lua_pushnumber(L, getValue(src)/100.0); break; @@ -148,61 +161,101 @@ static void luaGetValueAndPush(int src) } struct LuaField { - const char * name; - const uint8_t id; - const uint8_t attr; + uint16_t id; + char desc[50]; }; -const LuaField luaFields[] = { - { "altitude-max", MIXSRC_FIRST_TELEM+TELEM_MAX_ALT-1, 0 }, - { "altitude", MIXSRC_FIRST_TELEM+TELEM_ALT-1, PREC2 }, - { "vario", MIXSRC_FIRST_TELEM+TELEM_VSPEED-1, PREC2 }, - { "tx-voltage", MIXSRC_FIRST_TELEM+TELEM_TX_VOLTAGE-1, PREC1 }, - { "rpm", MIXSRC_FIRST_TELEM+TELEM_RPM-1, 0 }, - { NULL, 0, 0 }, -}; +#define FIND_FIELD_DESC 0x01 + +/** + Return field data for a given field name +*/ +bool luaFindFieldByName(const char * name, LuaField & field, unsigned int flags=0) +{ + // TODO better search method (binary lookup) + for (unsigned int n=0; nname; field++) { - if (!strcmp(what, field->name)) { - getvalue_t value = getValue(field->id); - if (field->attr == PREC1) - lua_pushnumber(L, double(value)/10); - else if (field->attr == PREC2) - lua_pushnumber(L, double(value)/100); - else - lua_pushnumber(L, value); - return 1; - } - } - if (frskyData.hub.gpsFix) { - if (!strcmp(what, "latitude")) { - lua_pushnumber(L, gpsToDouble(frskyData.hub.gpsLatitudeNS=='S', frskyData.hub.gpsLatitude_bp, frskyData.hub.gpsLatitude_ap)); - return 1; - } - else if (!strcmp(what, "longitude")) { - lua_pushnumber(L, gpsToDouble(frskyData.hub.gpsLongitudeEW=='W', frskyData.hub.gpsLongitude_bp, frskyData.hub.gpsLongitude_ap)); - return 1; - } - else if (!strcmp(what, "pilot-latitude")) { - lua_pushnumber(L, pilotLatitude); - return 1; - } - else if (!strcmp(what, "pilot-longitude")) { - lua_pushnumber(L, pilotLongitude); - return 1; - } + // convert from field name to its id + const char *name = luaL_checkstring(L, 1); + LuaField field; + bool found = luaFindFieldByName(name, field); + if (found) { + src = field.id; } } - return 0; + if (src >= EXTRA_FIRST ) { + // one of the extra fields + return luaGetExtraValue(src); + } + luaGetValueAndPush(src); + return 1; } static int luaPlayFile(lua_State *L) @@ -313,12 +366,11 @@ static int luaLcdDrawChannel(lua_State *L) channel = luaL_checkinteger(L, 3); } else { - const char *what = luaL_checkstring(L, 3); - for (const LuaField * field = &luaFields[0]; field->name; field++) { - if (!strcmp(what, field->name)) { - channel = field->id; - break; - } + const char * what = luaL_checkstring(L, 3); + LuaField field; + bool found = luaFindFieldByName(what, field); + if (found) { + channel = field.id; } } int att = luaL_checkinteger(L, 4); @@ -854,7 +906,7 @@ static int luaModelGetCustomFunction(lua_State *L) lua_pushtableinteger(L, "switch", CFN_SWITCH(cfn)); lua_pushtableinteger(L, "func", CFN_FUNC(cfn)); if (CFN_FUNC(cfn) == FUNC_PLAY_TRACK || CFN_FUNC(cfn) == FUNC_BACKGND_MUSIC || CFN_FUNC(cfn) == FUNC_PLAY_SCRIPT) { - lua_pushtablestring(L, "name", cfn->play.name); + lua_pushtablenzstring(L, "name", cfn->play.name); } else { lua_pushtableinteger(L, "value", cfn->all.val); @@ -1182,6 +1234,8 @@ void luaInit() lua_register(L, "getVersion", luaGetVersion); lua_register(L, "getGeneralSettings", luaGetGeneralSettings); lua_register(L, "getValue", luaGetValue); + lua_register(L, "getFieldInfo", luaGetFieldInfo); + lua_register(L, "playFile", luaPlayFile); lua_register(L, "playNumber", luaPlayNumber); lua_register(L, "popupInput", luaPopupInput); diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h index bd1c49d62..dfc9b2649 100644 --- a/radio/src/myeeprom.h +++ b/radio/src/myeeprom.h @@ -39,6 +39,18 @@ #include +#if defined(EXPORT) + #define LUA_EXPORT(...) LEXP(__VA_ARGS__) + #define LUA_EXPORT_TELEMETRY(...) LEXP_TELEMETRY(__VA_ARGS__) + #define LUA_EXPORT_MULTIPLE(...) LEXP_MULTIPLE(__VA_ARGS__) + #define LUA_EXPORT_EXTRA(...) LEXP_EXTRA(__VA_ARGS__) +#else + #define LUA_EXPORT(...) + #define LUA_EXPORT_TELEMETRY(...) + #define LUA_EXPORT_MULTIPLE(...) + #define LUA_EXPORT_EXTRA(...) +#endif + #define WARN_THR_BIT 0x01 #define WARN_BEP_BIT 0x80 #define WARN_SW_BIT 0x02 @@ -1023,56 +1035,56 @@ PACK(typedef struct { enum TelemetrySource { TELEM_NONE, - TELEM_TX_VOLTAGE, + TELEM_TX_VOLTAGE, LUA_EXPORT_TELEMETRY("tx-voltage", "Transmitter battery voltage [volts]") #if defined(CPUARM) - TELEM_TX_TIME, + TELEM_TX_TIME, LUA_EXPORT_TELEMETRY("clock", "RTC clock [minutes from midnight]") TELEM_RESERVE1, TELEM_RESERVE2, TELEM_RESERVE3, TELEM_RESERVE4, TELEM_RESERVE5, #endif - TELEM_TIMER1, - TELEM_TIMER2, -#if defined(CPUARM) - TELEM_SWR, -#endif - TELEM_RSSI_TX, - TELEM_RSSI_RX, -#if defined(CPUARM) - TELEM_RESERVE0, -#endif - TELEM_A_FIRST, - TELEM_A1=TELEM_A_FIRST, - TELEM_A2, -#if !defined(CPUARM) - TELEM_A_LAST=TELEM_A2, -#else - TELEM_A3, - TELEM_A4, - TELEM_A_LAST=TELEM_A4, -#endif - TELEM_ALT, - TELEM_RPM, - TELEM_FUEL, - TELEM_T1, - TELEM_T2, - TELEM_SPEED, - TELEM_DIST, - TELEM_GPSALT, - TELEM_CELL, - TELEM_CELLS_SUM, - TELEM_VFAS, - TELEM_CURRENT, - TELEM_CONSUMPTION, - TELEM_POWER, - TELEM_ACCx, - TELEM_ACCy, - TELEM_ACCz, - TELEM_HDG, - TELEM_VSPEED, - TELEM_ASPEED, - TELEM_DTE, + TELEM_TIMER1, LUA_EXPORT_TELEMETRY("timer1", "Timer 1 value [seconds]") + TELEM_TIMER2, LUA_EXPORT_TELEMETRY("timer2", "Timer 2 value [seconds]") +#if defined(CPUARM) + TELEM_SWR, LUA_EXPORT_TELEMETRY("swr", "Transmitter antenna quality [less is better]") +#endif + TELEM_RSSI_TX, + TELEM_RSSI_RX, LUA_EXPORT_TELEMETRY("rssi", "RSSI [more is better]") +#if defined(CPUARM) + TELEM_RESERVE0, +#endif + TELEM_A_FIRST, + TELEM_A1=TELEM_A_FIRST, LUA_EXPORT_TELEMETRY("a1", "A1 analogue value [units as configured]") + TELEM_A2, LUA_EXPORT_TELEMETRY("a2", "A2 analogue value [units as configured]") +#if !defined(CPUARM) + TELEM_A_LAST=TELEM_A2, +#else + TELEM_A3, LUA_EXPORT_TELEMETRY("a3", "A3 analogue value [units as configured]") + TELEM_A4, LUA_EXPORT_TELEMETRY("a4", "A4 analogue value [units as configured]") + TELEM_A_LAST=TELEM_A4, +#endif + TELEM_ALT, LUA_EXPORT_TELEMETRY("altitude", "Variometer altitude [meters]") + TELEM_RPM, LUA_EXPORT_TELEMETRY("rpm", "Rotational speed [revolutions per minute]") + TELEM_FUEL, LUA_EXPORT_TELEMETRY("fuel", "Fuel level [percent]") + TELEM_T1, LUA_EXPORT_TELEMETRY("temp1", "Temperature 1 [degrees celsius]") + TELEM_T2, LUA_EXPORT_TELEMETRY("temp2", "Temperature 2 [degrees celsius]") + TELEM_SPEED, LUA_EXPORT_TELEMETRY("gps-speed", "GPS speed [knots]") + TELEM_DIST, LUA_EXPORT_TELEMETRY("distance", "GPS distance [meters]") + TELEM_GPSALT, LUA_EXPORT_TELEMETRY("gps-altitude", "GPS altitude [meters]") + TELEM_CELL, LUA_EXPORT_TELEMETRY("cell-min", "LiPo sensor - lowest current cell voltage [volts]") + TELEM_CELLS_SUM, LUA_EXPORT_TELEMETRY("cell-sum", "LiPo sensor - current summ of all cell voltages [volts]") + TELEM_VFAS, LUA_EXPORT_TELEMETRY("vfas", "Current sensor - voltage [volts]") + TELEM_CURRENT, LUA_EXPORT_TELEMETRY("current", "Current sensor - current [ampers]") + TELEM_CONSUMPTION, LUA_EXPORT_TELEMETRY("consumption", "Current sensor - consumption [mili amper hours]") + TELEM_POWER, LUA_EXPORT_TELEMETRY("power", "Current sensor - power [wats]") + TELEM_ACCx, LUA_EXPORT_TELEMETRY("accx", "G sensor - acceleration in X axis [g]") + TELEM_ACCy, LUA_EXPORT_TELEMETRY("accy", "G sensor - acceleration in Y axis [g]") + TELEM_ACCz, LUA_EXPORT_TELEMETRY("accz", "G sensor - acceleration in Z axis [g]") + TELEM_HDG, LUA_EXPORT_TELEMETRY("heading", "GPS heading [degrees]") + TELEM_VSPEED, LUA_EXPORT_TELEMETRY("vario-speed", "Variometer vertical speed [m/s]") + TELEM_ASPEED, LUA_EXPORT_TELEMETRY("air-speed", "Air speed [knots]") + TELEM_DTE, LUA_EXPORT_TELEMETRY("dte", "Total energy [???]") #if defined(CPUARM) TELEM_RESERVE6, TELEM_RESERVE7, @@ -1081,28 +1093,29 @@ enum TelemetrySource { TELEM_RESERVE10, #endif TELEM_MIN_A_FIRST, - TELEM_MIN_A1=TELEM_MIN_A_FIRST, - TELEM_MIN_A2, + TELEM_MIN_A1=TELEM_MIN_A_FIRST, LUA_EXPORT_TELEMETRY("a1-min", "A1 analogue value minimum [units as configured]") + TELEM_MIN_A2, LUA_EXPORT_TELEMETRY("a2-min", "A2 analogue value minimum [units as configured]") #if !defined(CPUARM) TELEM_MIN_A_LAST=TELEM_MIN_A2, #else - TELEM_MIN_A3, - TELEM_MIN_A4, + TELEM_MIN_A3, LUA_EXPORT_TELEMETRY("a3-min", "A3 analogue value minimum [units as configured]") + TELEM_MIN_A4, LUA_EXPORT_TELEMETRY("a4-min", "A4 analogue value minimum [units as configured]") TELEM_MIN_A_LAST=TELEM_MIN_A4, #endif - TELEM_MIN_ALT, - TELEM_MAX_ALT, - TELEM_MAX_RPM, - TELEM_MAX_T1, - TELEM_MAX_T2, - TELEM_MAX_SPEED, - TELEM_MAX_DIST, - TELEM_MAX_ASPEED, - TELEM_MIN_CELL, - TELEM_MIN_CELLS_SUM, - TELEM_MIN_VFAS, - TELEM_MAX_CURRENT, - TELEM_MAX_POWER, + // TODO: add A1-4 MAX + TELEM_MIN_ALT, LUA_EXPORT_TELEMETRY("altitude-min", "Lowest altitude [meters]") + TELEM_MAX_ALT, LUA_EXPORT_TELEMETRY("altitude-max", "Highest altitude [meters]") + TELEM_MAX_RPM, LUA_EXPORT_TELEMETRY("rpm-max", "Highest rotational speed [revolutions per minute] [meters]") + TELEM_MAX_T1, LUA_EXPORT_TELEMETRY("temp1-max", "Highest temperature 1 [degrees celsius]") + TELEM_MAX_T2, LUA_EXPORT_TELEMETRY("temp2-max", "Highest temperature 2 [degrees celsius]") + TELEM_MAX_SPEED, LUA_EXPORT_TELEMETRY("gps-speed-max", "Highest GPS speed [knots]") + TELEM_MAX_DIST, LUA_EXPORT_TELEMETRY("distance-max", "Biggest GPS distance [meters]") + TELEM_MAX_ASPEED, LUA_EXPORT_TELEMETRY("air-speed-max", "Highest air speed [knots]") + TELEM_MIN_CELL, LUA_EXPORT_TELEMETRY("cell-min-min", "LiPo sensor - all time lowest cell voltage [volts]") + TELEM_MIN_CELLS_SUM, LUA_EXPORT_TELEMETRY("cell-sum-min", "LiPo sensor - all time lowest summ of all cell voltages [volts]") + TELEM_MIN_VFAS, LUA_EXPORT_TELEMETRY("vfas-min", "Current sensor - lowest voltage [volts]") + TELEM_MAX_CURRENT, LUA_EXPORT_TELEMETRY("current-max", "Current sensor - highest current [ampers]") + TELEM_MAX_POWER, LUA_EXPORT_TELEMETRY("power-max", "Current sensor - highest power [wats]") #if defined(CPUARM) TELEM_RESERVE11, TELEM_RESERVE12, @@ -1446,25 +1459,25 @@ enum MixSources { MIXSRC_NONE, #if defined(PCBTARANIS) - MIXSRC_FIRST_INPUT, + MIXSRC_FIRST_INPUT, LUA_EXPORT_MULTIPLE("input", "Input [I%d]", MAX_INPUTS) MIXSRC_LAST_INPUT = MIXSRC_FIRST_INPUT+MAX_INPUTS-1, MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA = MIXSRC_FIRST_LUA+(MAX_SCRIPTS*MAX_SCRIPT_OUTPUTS)-1, #endif - MIXSRC_Rud, - MIXSRC_Ele, - MIXSRC_Thr, - MIXSRC_Ail, + MIXSRC_Rud, LUA_EXPORT("rud", "Rudder") + MIXSRC_Ele, LUA_EXPORT("ele", "Elevator") + MIXSRC_Thr, LUA_EXPORT("thr", "Throttle") + MIXSRC_Ail, LUA_EXPORT("ail", "Aileron") MIXSRC_FIRST_POT, #if defined(PCBTARANIS) - MIXSRC_POT1 = MIXSRC_FIRST_POT, - MIXSRC_POT2, - MIXSRC_POT3, - MIXSRC_SLIDER1, - MIXSRC_SLIDER2, + MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1") + MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2") + MIXSRC_POT3, LUA_EXPORT("s3", "Potentiometer 3") + MIXSRC_SLIDER1, LUA_EXPORT("ls", "Left slider") + MIXSRC_SLIDER2, LUA_EXPORT("rs", "Right slider") MIXSRC_LAST_POT = MIXSRC_SLIDER2, #else MIXSRC_P1 = MIXSRC_FIRST_POT, @@ -1494,26 +1507,26 @@ enum MixSources { MIXSRC_MAX, - MIXSRC_CYC1, - MIXSRC_CYC2, - MIXSRC_CYC3, + MIXSRC_CYC1, LUA_EXPORT("cyc1", "Cyclic 1") + MIXSRC_CYC2, LUA_EXPORT("cyc2", "Cyclic 2") + MIXSRC_CYC3, LUA_EXPORT("cyc3", "Cyclic 3") - MIXSRC_TrimRud, - MIXSRC_TrimEle, - MIXSRC_TrimThr, - MIXSRC_TrimAil, + MIXSRC_TrimRud, LUA_EXPORT("trim-rud", "Rudder trim") + MIXSRC_TrimEle, LUA_EXPORT("trim-ele", "Elevator trim") + MIXSRC_TrimThr, LUA_EXPORT("trim-thr", "Throttle trim") + MIXSRC_TrimAil, LUA_EXPORT("trim-ail", "Aileron trim") MIXSRC_FIRST_SWITCH, #if defined(PCBTARANIS) - MIXSRC_SA = MIXSRC_FIRST_SWITCH, - MIXSRC_SB, - MIXSRC_SC, - MIXSRC_SD, - MIXSRC_SE, - MIXSRC_SF, - MIXSRC_SG, - MIXSRC_SH, + MIXSRC_SA = MIXSRC_FIRST_SWITCH, LUA_EXPORT("sa", "Switch A") + MIXSRC_SB, LUA_EXPORT("sb", "Switch B") + MIXSRC_SC, LUA_EXPORT("sc", "Switch C") + MIXSRC_SD, LUA_EXPORT("sd", "Switch D") + MIXSRC_SE, LUA_EXPORT("se", "Switch E") + MIXSRC_SF, LUA_EXPORT("sf", "Switch F") + MIXSRC_SG, LUA_EXPORT("sg", "Switch G") + MIXSRC_SH, LUA_EXPORT("sh", "Switch H") #else MIXSRC_3POS = MIXSRC_FIRST_SWITCH, #if defined(EXTRA_3POS) @@ -1527,18 +1540,18 @@ enum MixSources { MIXSRC_TRN, #endif MIXSRC_FIRST_LOGICAL_SWITCH, - MIXSRC_SW1 = MIXSRC_FIRST_LOGICAL_SWITCH, + MIXSRC_SW1 = MIXSRC_FIRST_LOGICAL_SWITCH, LUA_EXPORT_MULTIPLE("ls", "Logical switch L%d", NUM_LOGICAL_SWITCH) MIXSRC_SW9 = MIXSRC_SW1 + 8, MIXSRC_SWA, MIXSRC_SWB, MIXSRC_SWC, MIXSRC_LAST_LOGICAL_SWITCH = MIXSRC_FIRST_LOGICAL_SWITCH+NUM_LOGICAL_SWITCH-1, - MIXSRC_FIRST_TRAINER, + MIXSRC_FIRST_TRAINER, LUA_EXPORT_MULTIPLE("trn", "Trainer input %d", NUM_TRAINER) MIXSRC_LAST_TRAINER = MIXSRC_FIRST_TRAINER+NUM_TRAINER-1, MIXSRC_FIRST_CH, - MIXSRC_CH1 = MIXSRC_FIRST_CH, + MIXSRC_CH1 = MIXSRC_FIRST_CH, LUA_EXPORT_MULTIPLE("ch", "Channel CH%d", NUM_CHNOUT) MIXSRC_CH2, MIXSRC_CH3, MIXSRC_CH4, @@ -1556,13 +1569,33 @@ enum MixSources { MIXSRC_CH16, MIXSRC_LAST_CH = MIXSRC_CH1+NUM_CHNOUT-1, - MIXSRC_GVAR1, + MIXSRC_GVAR1, LUA_EXPORT_MULTIPLE("gvar", "Global variable %d", MAX_GVARS) MIXSRC_LAST_GVAR = MIXSRC_GVAR1+MAX_GVARS-1, MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM = MIXSRC_FIRST_TELEM+NUM_TELEMETRY-1 }; +#if defined(LUA) +#define EXTRA_FIRST 1000 +enum LuaExtraFields { + EXTRA_LATITUDE = EXTRA_FIRST, LUA_EXPORT_EXTRA("latitude", "GPS latitude [degrees, North is positive]", \ + "gpsToDouble(frskyData.hub.gpsLatitudeNS=='S', frskyData.hub.gpsLatitude_bp, frskyData.hub.gpsLatitude_ap)", \ + "frskyData.hub.gpsFix") + EXTRA_LONGITUDE, LUA_EXPORT_EXTRA("longitude", "GPS longitude [degrees, East is positive]", \ + "gpsToDouble(frskyData.hub.gpsLongitudeEW=='W', frskyData.hub.gpsLongitude_bp, frskyData.hub.gpsLongitude_ap)", \ + "frskyData.hub.gpsFix") + EXTRA_PILOT_LATITUDE, LUA_EXPORT_EXTRA("pilot-latitude", "Latitude of frist GPS position [degrees, North is positive]", \ + "pilotLatitude", "frskyData.hub.gpsFix") + EXTRA_PILOT_LONGITUDE, LUA_EXPORT_EXTRA("pilot-longitude", "Longitude of frist GPS position [degrees, East is positive]", \ + "pilotLongitude", "frskyData.hub.gpsFix") + EXTRA_GPS_CLOCK, LUA_EXPORT_EXTRA("gps-clock", "GPS clock [seconds from midnight]", \ + "(int)(frskyData.hub.hour)*3600 + frskyData.hub.min*60 + frskyData.hub.sec", "frskyData.hub.gpsFix") + EXTRA_FLIGHT_MODE LUA_EXPORT_EXTRA("flight-mode", "Current flight mode number [number]", \ + "getFlightMode()", "true") +}; +#endif // #if defined(LUA) + #define MIXSRC_FIRST (MIXSRC_NONE+1) #define MIXSRC_LAST MIXSRC_LAST_CH #define INPUTSRC_FIRST MIXSRC_Rud diff --git a/radio/util/luaexport.py b/radio/util/luaexport.py new file mode 100644 index 000000000..0bfbb1a71 --- /dev/null +++ b/radio/util/luaexport.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + + +import sys +import os +import traceback +import time + +PREC1 = 10 +PREC2 = 100 + +CONSTANT_VALUE = "" +dups_cnst = [] +dups_name = [] +exports = [] +exports_multiple = [] +exports_script_outputs = [] +exports_extra = [] + +warning = None +error = None + +def checkName(name): + global warning + if name in dups_name: + print "WARNING: Duplicate name %s found for constant %s" % (name, CONSTANT_VALUE) + warning = True + dups_name.append(name) + if name != name.lower(): + print "WARNING:Name not in lower case %s found for constant %s" % (name, CONSTANT_VALUE) + warning = True + + +def LEXP(name, description): + # print "LEXP %s, %s" % (name, description) + checkName(name) + exports.append( (CONSTANT_VALUE, name, description) ) + +def LEXP_TELEMETRY(name, description): + # print "LEXP %s, %s" % (name, description) + checkName(name) + exports.append( ("MIXSRC_FIRST_TELEM-1+"+CONSTANT_VALUE, name, description) ) + +def LEXP_MULTIPLE(nameFormat, descriptionFormat, valuesCount): + # print "LEXP_MULTIPLE %s, %s, %s" % (nameFormat, descriptionFormat, valuesCount) + for v in range(valuesCount): + name = nameFormat + str(v) + # print name + checkName(name) + exports_multiple.append( (CONSTANT_VALUE, nameFormat, descriptionFormat, valuesCount) ) + +def LEXP_EXTRA(name, description, value, condition = "true"): + # print "LEXP_EXTRA %s, %s, %s, %s" % (name, description, value, condition) + checkName(name) + exports_extra.append( (CONSTANT_VALUE, name, description, value, condition) ) + # extra also added to normal items to enable searching + exports.append( (CONSTANT_VALUE, name, description) ) + + +inputFile = sys.argv[1] +outputFile = sys.argv[2] +print "Input file %s" % inputFile +print "Output file %s" % outputFile + +inp = open(inputFile, "r") + +while True: + line = inp.readline() + if len(line) == 0: + break + line = line.strip('\r\n') + line = line.strip() + #print "line: %s" % line + + parts = line.split('LEXP') + #print parts + if len(parts) != 2: + print "Wrong line: %s" % line + continue + cmd = 'LEXP' + parts[1] + cnst = parts[0].rstrip(', ') + if cnst.find('=') != -1: + # constant contains = + cnst = cnst.split('=')[0].strip() + #print "Found constant %s with command: %s" % (cnst, cmd) + try: + CONSTANT_VALUE = cnst + # if CONSTANT_VALUE in dups_cnst: + # print "WARNING: Duplicate CONSTANT_VALUE found: %s" % CONSTANT_VALUE + # warning = True + # continue + # dups_cnst.append(CONSTANT_VALUE) + # print cmd + eval(cmd) + except: + print "ERROR: problem with the definition: %s" % line + traceback.print_exc() + error = True + +inp.close() + +out = open(outputFile, "w") + +out.write("//This file was generated by luaexport.py script on %s\n\n\n" % time.asctime()) + +header = """ +struct LuaSingleField { + uint16_t id; + const char * name; + const char * desc; +}; + +struct LuaMultipleField { + uint16_t id; + const char * name; + const char * desc; + uint8_t count; +}; + +""" +out.write(header) + +out.write(""" +// The list of Lua fields +// this aray is alphabetically sorted by the second field (name) +const LuaSingleField luaSingleFields[] = { +""") +exports.sort(key = lambda x: x[1]) #sort by name +data = [" {%s, \"%s\", \"%s\"}" % export for export in exports] +out.write(",\n".join(data)) +out.write("\n};\n\n") +print "Generated %d items in luaFields[]" % len(exports) + +out.write(""" +// The list of Lua fields that have a range of values +const LuaMultipleField luaMultipleFields[] = { +""") +data = [" {%s, \"%s\", \"%s\", %d}" % export for export in exports_multiple] +out.write(",\n".join(data)) +out.write("\n};\n\n") +print "Generated %d items in luaMultipleFields[]" % len(exports_multiple) + +#code generation for extra fields +case = """ case %s: + if (%s) { + lua_pushnumber(L, %s); + return 1; + } + break;""" +case_clauses = [case % (cnst, condition, value) for (cnst, name, description, value, condition) in exports_extra] +case_body = "\n".join(case_clauses) +func_body = """ +extern lua_State *L; + +// The handling of extra Lua fileds that are not +// accesible by the getValue() +static int luaGetExtraValue(int src) +{ + switch (src) { +%s + } + return 0; +} + +""" % case_body +out.write(func_body) +print "Generated %d condtions in luaGetExtraValue()" % len(exports_extra) + + +out.close() + +if warning: + sys.exit(1) +elif error: + os.remove(outputFile) + sys.exit(2) +sys.exit(0)