diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index 781ec3019..ccf420fb7 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..c8e1c6830 100644 --- a/radio/src/lua.cpp +++ b/radio/src/lua.cpp @@ -34,6 +34,7 @@ * */ +#include #include "opentx.h" #include "stamp-opentx.h" @@ -47,6 +48,8 @@ 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)) @@ -97,14 +100,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 +119,24 @@ 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: + case MIXSRC_FIRST_TELEM-1+TELEM_ASPEED: //theese 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,6 +145,7 @@ 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: + case MIXSRC_FIRST_TELEM-1+TELEM_VSPEED: //theese need to be divided by 100 lua_pushnumber(L, getValue(src)/100.0); break; @@ -147,62 +157,136 @@ static void luaGetValueAndPush(int src) } } -struct LuaField { - const char * name; - const uint8_t id; - const uint8_t attr; -}; +//these are used when returning fields that are defined as multiples +static char foundName[10]; +static char foundDesc[50]; +static LuaField foundField = {0, foundName, foundDesc}; -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 }, -}; +/** + Return filed data for a given field name + + Note: function is non-reentrant +*/ +const LuaField * luaFindFieldByName(const char * name) +{ + // TODO better search method (binary lookup) + for(int n = 0; n < (int)DIM(luaFields); ++n) { + if (!strcmp(name, luaFields[n].name)) { + return &luaFields[n]; + } + } + //search in multiples + for(int n = 0; n < (int)DIM(luaMultipleFields); ++n) { + for(int i = luaMultipleFields[n].start; i < luaMultipleFields[n].end; i++){ + //char buf[10]; + snprintf(foundName, sizeof(foundName), luaMultipleFields[n].name, i); + // TRACE("luaFindFieldByName(): %s", foundName); + if (!strcmp(name, foundName)) { + snprintf(foundDesc, sizeof(foundDesc), luaMultipleFields[n].desc, i); + foundField.id = luaMultipleFields[n].id+i-1; + return &foundField; + } + } + } + // search in lua script outputs + // TODO + return 0; // not found +} + +/** + Return filed data for a given field id + + Note: function is non-reentrant +*/ +const LuaField * luaFindFieldById(int id) +{ + for(int n = 0; n < (int)DIM(luaFields); ++n) { + if (id == luaFields[n].id) { + return &luaFields[n]; + } + } + //search in multiples + for(int n = 0; n < (int)DIM(luaMultipleFields); ++n) { + if ((id >= luaMultipleFields[n].id) && (id <= luaMultipleFields[n].id+luaMultipleFields[n].end-luaMultipleFields[n].start)) { + int i = id - luaMultipleFields[n].id + luaMultipleFields[n].start; + snprintf(foundName, sizeof(foundName), luaMultipleFields[n].name, i); + snprintf(foundDesc, sizeof(foundDesc), luaMultipleFields[n].desc, i); + foundField.id = id; + return &foundField; + } + } + // search in lua script outputs + // TODO + return 0; // not found +} + +// TODO this could be removed and luaGetFieldInfo() used instead +// get a filed ids for one or more fields +static int luaGetFields(lua_State *L) +{ + // get number of arguments + int n = lua_gettop(L); + // return requested filed ids as multiple return values + for (int i = 1; i <= n; i++) + { + const char * what = luaL_checkstring(L, i); + TRACE("luaGetFields(): %s", what); + const LuaField * field = luaFindFieldByName(what); + if (field) { + lua_pushinteger(L, field->id); + } + else { + lua_pushnil(L); + } + } + return n; +} + +//get a detailed info about particular field +static int luaGetFieldInfo(lua_State *L) +{ + const LuaField * field; + if (lua_isnumber(L, 1)) { + int id = luaL_checkinteger(L, 1); + // TRACE("luaGetFieldInfo(): int %d", id); + field = luaFindFieldById(id); + } + else { + const char * what = luaL_checkstring(L, 1); + // TRACE("luaGetFieldInfo(): str %s", what); + field = luaFindFieldByName(what); + } + if (field) { + lua_newtable(L); + lua_pushtableinteger(L, "id", field->id); + lua_pushstring(L, "name"); lua_pushstring(L, field->name); lua_settable(L, -3); + lua_pushstring(L, "desc"); lua_pushstring(L, field->desc); lua_settable(L, -3); + return 1; + } + return 0; +} static int luaGetValue(lua_State *L) { + int src = 0; if (lua_isnumber(L, 1)) { - int src = luaL_checkinteger(L, 1); - luaGetValueAndPush(src); - return 1; + src = luaL_checkinteger(L, 1); } else { - const char *what = luaL_checkstring(L, 1); - for (const LuaField * field = &luaFields[0]; field->name; 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 filed name to its id + const char *name = luaL_checkstring(L, 1); + const LuaField * field = luaFindFieldByName(name); + if (field) { + // TRACE("luaGetValue(): %d", field->id); + 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) @@ -314,11 +398,9 @@ static int luaLcdDrawChannel(lua_State *L) } 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 LuaField * field = luaFindFieldByName(what); + if (field) { + channel = field->id; } } int att = luaL_checkinteger(L, 4); @@ -1182,6 +1264,9 @@ void luaInit() lua_register(L, "getVersion", luaGetVersion); lua_register(L, "getGeneralSettings", luaGetGeneralSettings); lua_register(L, "getValue", luaGetValue); + lua_register(L, "getFields", luaGetFields); + 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..5e836a658 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 [???]") + 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 [???]") + 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("currentent", "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", "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 [???]") + 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("currentent-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%d", "Input [I%d]", 1, 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%d", "Logical switch L%d", 1, 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%d", "Trainer input %d", 1, 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%d", "Channel CH%d", 1, 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%d", "Global variable %d", 1, 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..75789dab8 --- /dev/null +++ b/radio/util/luaexport.py @@ -0,0 +1,181 @@ +#!/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, firstValue, numOfValues): + # print "LEXP_MULTIPLE %s, %s, %s, %s" % (nameFormat, descriptionFormat, firstValue, numOfValues) + first = int(firstValue) + last = first + int(numOfValues) - 1 + for v in range(first, last+1): + name = nameFormat % v + # print name + checkName(name) + exports_multiple.append( (CONSTANT_VALUE, nameFormat, descriptionFormat, first, last) ) + +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) + 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 LuaField { + uint16_t id; + const char * name; + const char * desc; + //const uint8_t attr; +}; + +struct LuaMultipleField { + uint16_t id; + const char * name; + const char * desc; + uint8_t start; + uint8_t end; +}; + +""" +out.write(header) + +out.write(""" +// The list of Lua fields +// this aray is alphabetically sorted by the second field (name) +const LuaField luaFields[] = { +""") +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, %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) \ No newline at end of file