Merge remote-tracking branch 'origin/next' into Horus

# Conflicts:
#	companion/src/CMakeLists.txt
#	companion/src/firmwares/opentx/opentxinterface.cpp
#	companion/src/firmwares/opentx/simulator/CMakeLists.txt
#	companion/src/firmwares/opentx/stamp-opentx.h.in
#	radio/src/Makefile
#	radio/src/cli.cpp
#	radio/src/gui/Taranis/helpers.cpp
#	radio/src/gui/Taranis/lcd.cpp
#	radio/src/gui/Taranis/menu_model_setup.cpp
#	radio/src/gui/Taranis/view_main.cpp
#	radio/src/lua_api.cpp
#	radio/src/main_avr.cpp
#	radio/src/myeeprom.h
#	radio/src/opentx.cpp
#	radio/src/pulses/pxx_arm.cpp
#	radio/src/storage/eeprom_conversions.cpp
#	radio/src/targets/Horus/adc_driver.cpp
#	radio/src/targets/Horus/board_horus.cpp
#	radio/src/targets/Horus/board_horus.h
#	radio/src/targets/Horus/diskio.cpp
#	radio/src/targets/Horus/hal.h
#	radio/src/targets/Horus/haptic_driver.cpp
#	radio/src/targets/Horus/i2c_driver.cpp
#	radio/src/targets/Horus/keys_driver.cpp
#	radio/src/targets/Horus/lcd_driver.cpp
#	radio/src/targets/Horus/led_driver.cpp
#	radio/src/targets/Horus/pulses_driver.cpp
#	radio/src/targets/Horus/pwr_driver.c
#	radio/src/targets/Horus/sdio_sd.c
#	radio/src/targets/Horus/sdio_sd.h
#	radio/src/targets/Horus/serial2_driver.cpp
#	radio/src/targets/Horus/telemetry_driver.cpp
#	radio/src/targets/Horus/usb_conf.h
#	radio/src/targets/Horus/usbd_desc.c
#	radio/src/targets/Horus/usbd_storage_msd.cpp
This commit is contained in:
Bertrand Songis
2015-11-15 23:08:34 +01:00
85 changed files with 7036 additions and 3662 deletions
+22 -14
View File
@@ -379,6 +379,10 @@ WATCHDOG_TEST = NO
# Values = NO, YES
WARNINGS_AS_ERRORS = NO
# Enable saving of Lua byte-code of all loaded scripts
# Values = NO, YES
LUA_COMPILER = NO
#------- END BUILD OPTIONS ---------------------------
# Define programs and commands.
@@ -1029,12 +1033,12 @@ ifeq ($(PCB), TARANIS)
endif
CPPDEFS += -DLUA
INCDIRS += $(LUADIR)
CPPSRC += lua_api.cpp
CPPSRC += lua/interface.cpp lua/api_general.cpp lua/api_lcd.cpp lua/api_model.cpp
LUASRC = $(LUADIR)/lapi.c $(LUADIR)/lcode.c $(LUADIR)/lctype.c $(LUADIR)/ldebug.c $(LUADIR)/ldo.c $(LUADIR)/ldump.c $(LUADIR)/lfunc.c $(LUADIR)/lgc.c $(LUADIR)/llex.c $(LUADIR)/lmem.c \
$(LUADIR)/lobject.c $(LUADIR)/lopcodes.c $(LUADIR)/lparser.c $(LUADIR)/lstate.c $(LUADIR)/lstring.c $(LUADIR)/ltable.c $(LUADIR)/lrotable.c $(LUADIR)/ltm.c $(LUADIR)/lundump.c $(LUADIR)/lvm.c $(LUADIR)/lzio.c \
$(LUADIR)/lbaselib.c $(LUADIR)/linit.c $(LUADIR)/lmathlib.c $(LUADIR)/lbitlib.c $(LUADIR)/loadlib.c $(LUADIR)/lauxlib.c $(LUADIR)/ltablib.c $(LUADIR)/lcorolib.c $(LUADIR)/liolib.c
SRC += $(LUASRC)
LUADEP = lua_exports_taranis.inc
LUADEP = lua/lua_exports_taranis.inc
ifeq ($(USE_BIN_ALLOCATOR), YES)
CPPDEFS += -DUSE_BIN_ALLOCATOR
CPPSRC += bin_allocator.cpp
@@ -1157,7 +1161,7 @@ ifeq ($(PCB), FLAMENCO)
$(LUADIR)/lobject.c $(LUADIR)/lopcodes.c $(LUADIR)/lparser.c $(LUADIR)/lstate.c $(LUADIR)/lstring.c $(LUADIR)/ltable.c $(LUADIR)/lrotable.c $(LUADIR)/ltm.c $(LUADIR)/lundump.c $(LUADIR)/lvm.c $(LUADIR)/lzio.c \
$(LUADIR)/lbaselib.c $(LUADIR)/linit.c $(LUADIR)/lmathlib.c $(LUADIR)/lbitlib.c $(LUADIR)/loadlib.c $(LUADIR)/lauxlib.c $(LUADIR)/ltablib.c $(LUADIR)/lcorolib.c $(LUADIR)/liolib.c
SRC += $(LUASRC)
LUADEP = lua_exports_flamenco.inc
LUADEP = lua/lua_exports_flamenco.inc
endif
EXTRABOARDSRC += $(FATFSDIR)/ff.c $(FATFSDIR)/fattime.c $(FATFSDIR)/option/ccsbcs.c targets/Flamenco/diskio.cpp
@@ -1287,7 +1291,7 @@ ifeq ($(PCB), HORUS)
$(LUADIR)/lobject.c $(LUADIR)/lopcodes.c $(LUADIR)/lparser.c $(LUADIR)/lstate.c $(LUADIR)/lstring.c $(LUADIR)/ltable.c $(LUADIR)/lrotable.c $(LUADIR)/ltm.c $(LUADIR)/lundump.c $(LUADIR)/lvm.c $(LUADIR)/lzio.c \
$(LUADIR)/lbaselib.c $(LUADIR)/linit.c $(LUADIR)/lmathlib.c $(LUADIR)/lbitlib.c $(LUADIR)/loadlib.c $(LUADIR)/lauxlib.c $(LUADIR)/ltablib.c $(LUADIR)/lcorolib.c $(LUADIR)/liolib.c
SRC += $(LUASRC)
LUADEP = lua_exports_horus.inc
LUADEP = lua/lua_exports_horus.inc
endif
EXTRABOARDSRC += $(FATFSDIR)/ff.c $(FATFSDIR)/fattime.c $(FATFSDIR)/option/ccsbcs.c targets/Horus/diskio.cpp
@@ -1667,6 +1671,10 @@ ifeq ($(IRPROTOS), YES)
CPPDEFS += -DIRPROTOS
endif
ifeq ($(LUA_COMPILER), YES)
CPPDEFS += -DLUA_COMPILER
endif
#---------------- Compiler Options C++ ----------------
# -g*: generate debugging information
# -O*: optimization level
@@ -1924,25 +1932,25 @@ else
PARSER = gcc -E -x c++
endif
lua_exports_taranis.inc: myeeprom.h ../util/luaexport.py
lua/lua_exports_taranis.inc: myeeprom.h ../util/luaexport.py
@echo "Generating a list of Lua exported constants in lua_exports_taranis.txt"
@$(PARSER) -DPCBTARANIS -DCPUARM -DCPUSTM32 -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports_taranis.txt
@echo "Parsing and generating C Lua exports in lua_exports_taranis.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_taranis.txt lua_exports_taranis.inc lua_fields_taranis.txt
@echo "Parsing and generating C Lua exports in lua/lua_exports_taranis.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_taranis.txt lua/lua_exports_taranis.inc lua_fields_taranis.txt
@rm lua_exports_taranis.txt
lua_exports_horus.inc: myeeprom.h ../util/luaexport.py
lua/lua_exports_horus.inc: myeeprom.h ../util/luaexport.py
@echo "Generating a list of Lua exported constants in lua_exports_horus.txt"
@$(PARSER) -DPCBHORUS -DCPUARM -DCPUSTM32 -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports_horus.txt
@echo "Parsing and generating C Lua exports in lua_exports_horus.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_horus.txt lua_exports_horus.inc lua_fields_horus.txt
@echo "Parsing and generating C Lua exports in lua/lua_exports_horus.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_horus.txt lua/lua_exports_horus.inc lua_fields_horus.txt
@rm lua_exports_horus.txt
lua_exports_flamenco.inc: myeeprom.h ../util/luaexport.py
lua/lua_exports_flamenco.inc: myeeprom.h ../util/luaexport.py
@echo "Generating a list of Lua exported constants in lua_exports_flamenco.txt"
@$(PARSER) -DPCBFLAMENCO -DCPUARM -DCPUSTM32 -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports_flamenco.txt
@echo "Parsing and generating C Lua exports in lua_exports_flamenco.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_flamenco.txt lua_exports_flamenco.inc lua_fields_flamenco.txt
@echo "Parsing and generating C Lua exports in lua/lua_exports_flamenco.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_flamenco.txt lua/lua_exports_flamenco.inc lua_fields_flamenco.txt
@rm lua_exports_flamenco.txt
# Eye candy.
@@ -2101,7 +2109,7 @@ clean_list :
$(REMOVE) bitmaps/*.lbm
$(REMOVE) bitmaps/*/*.lbm
$(REMOVE) fonts/*/*.lbm
$(REMOVE) lua_exports* lua_fields.txt
$(REMOVE) lua_exports*.txt lua_fields.txt lua/lua_exports*.inc
$(MAKE) -C targets/Taranis/bootloader clean
#### Install
+2 -2
View File
@@ -441,8 +441,8 @@ void cliTask(void * pdata)
else if (c == 127) {
// backspace
if (pos) {
line[--pos] = '\0';
serialPutc(c);
line[--pos] = '\0';
serialPutc(c);
}
}
else if (c == '\r' || c == '\n') {
+4 -2
View File
@@ -367,8 +367,10 @@ void evalFunctions()
}
#if defined(CPUARM)
if (CFN_PARAM(cfn)>=FUNC_RESET_PARAM_FIRST_TELEM) {
TelemetryItem * telemetryItem = & telemetryItems[CFN_PARAM(cfn)-FUNC_RESET_PARAM_FIRST_TELEM];
telemetryItem->clear();
uint8_t item = CFN_PARAM(cfn)-FUNC_RESET_PARAM_FIRST_TELEM;
if (item < MAX_SENSORS) {
telemetryItems[item].clear();
}
}
#endif
break;
+2 -1
View File
@@ -881,6 +881,7 @@ void displayGpsCoords(coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFl
void putsTelemetryChannelValue(coord_t x, coord_t y, uint8_t channel, lcdint_t value, LcdFlags att)
{
if (channel >= MAX_SENSORS) return;
TelemetryItem & telemetryItem = telemetryItems[channel];
TelemetrySensor & telemetrySensor = g_model.telemetrySensors[channel];
if (telemetrySensor.unit == UNIT_DATETIME) {
@@ -1096,7 +1097,7 @@ void putsTelemetryChannelValue(coord_t x, coord_t y, uint8_t channel, lcdint_t v
case TELEM_TX_VOLTAGE-1:
lcd_outdezAtt(x, y, val, (att|PREC1) & (~NO_UNIT));
if (!(att & NO_UNIT))
lcd_putc(lcdLastPos/*+1*/, y, 'v');
lcd_putc(lcdLastPos/*+1*/, y, 'V');
break;
}
}
+7
View File
@@ -262,6 +262,13 @@ void lcdInit();
void lcdRefresh();
#if defined(LCD_ST7920)
uint8_t lcdRefresh_ST7920(uint8_t full);
#define IS_LCD_REFRESH_ALLOWED() (0==lcdstate)
#else
#define IS_LCD_REFRESH_ALLOWED() (1)
#endif
#if defined(BOOT)
#define BLINK_ON_PHASE (0)
#else
@@ -185,7 +185,11 @@ void menuModelLogicalSwitchOne(uint8_t event)
else {
#if defined(FRSKY)
if (v1_val >= MIXSRC_FIRST_TELEM) {
#if defined(CPUARM)
putsChannelValue(CSWONE_2ND_COLUMN, y, v1_val, convertLswTelemValue(cs), attr|LEFT);
#else
putsTelemetryChannelValue(CSWONE_2ND_COLUMN, y, v1_val - MIXSRC_FIRST_TELEM, convertLswTelemValue(cs), attr|LEFT);
#endif
v2_max = maxTelemValue(v1_val - MIXSRC_FIRST_TELEM + 1);
if (cs->func == LS_FUNC_DIFFEGREATER)
v2_min = -v2_max;
@@ -295,7 +299,11 @@ void menuModelLogicalSwitches(uint8_t event)
uint8_t v1 = cs->v1;
putsMixerSource(CSW_2ND_COLUMN, y, v1, 0);
if (v1 >= MIXSRC_FIRST_TELEM) {
#if defined(CPUARM)
putsChannelValue(CSW_3RD_COLUMN, y, v1, convertLswTelemValue(cs), LEFT);
#else
putsTelemetryChannelValue(CSW_3RD_COLUMN, y, v1 - MIXSRC_FIRST_TELEM, convertLswTelemValue(cs), LEFT);
#endif
}
else {
lcd_outdezAtt(CSW_3RD_COLUMN, y, cs->v2, LEFT);
+4 -4
View File
@@ -42,7 +42,7 @@
#define RBOX_CENTERX (3*LCD_W/4 - 10)
#define MODELNAME_X (2*FW-2)
#define MODELNAME_Y (0)
#define PHASE_X (6*FW)
#define PHASE_X (6*FW-1)
#define PHASE_Y (2*FH)
#define PHASE_FLAGS 0
#define VBATT_X (6*FW)
@@ -206,13 +206,13 @@ void displayBattVoltage()
{
#if defined(BATTGRAPH)
putsVBat(VBATT_X-8, VBATT_Y+1, 0);
drawFilledRect(VBATT_X-25, VBATT_Y+9, 22, 5);
lcd_vline(VBATT_X-3, VBATT_Y+10, 3);
drawFilledRect(VBATT_X-25, VBATT_Y+9, 21, 5);
lcd_vline(VBATT_X-4, VBATT_Y+10, 3);
uint8_t count = GET_TXBATT_BARS();
for (uint8_t i=0; i<count; i+=2)
lcd_vline(VBATT_X-24+i, VBATT_Y+10, 3);
if (!IS_TXBATT_WARNING() || BLINK_ON_PHASE)
drawFilledRect(VBATT_X-26, VBATT_Y, 25, 15);
drawFilledRect(VBATT_X-26, VBATT_Y, 24, 15);
#else
LcdFlags att = (IS_TXBATT_WARNING() ? BLINK|INVERS : 0) | BIGSIZE;
putsVBat(VBATT_X-1, VBATT_Y, att|NO_UNIT);
+7
View File
@@ -779,6 +779,12 @@ void putsSwitches(coord_t x, coord_t y, int32_t idx, LcdFlags att)
else if (idx == SWSRC_TELEMETRY_STREAMING) {
lcdDrawText(x, y, "Tele", att);
}
else if (idx <= SWSRC_LAST_FLIGHT_MODE) {
putsStrIdx(x, y, STR_FP, idx-SWSRC_FIRST_FLIGHT_MODE, att);
}
else if (idx == SWSRC_TELEMETRY_STREAMING) {
lcdDrawText(x, y, "Tele", att);
}
else {
lcdDrawTextWithLen(x, y, g_model.telemetrySensors[idx-SWSRC_FIRST_SENSOR].label, TELEM_LABEL_LEN, ZCHAR|att);
}
@@ -958,6 +964,7 @@ void displayGpsCoords(coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFl
void putsTelemetryChannelValue(coord_t x, coord_t y, uint8_t channel, int32_t value, LcdFlags att)
{
if (channel >= MAX_SENSORS) return; //Lua luaLcdDrawChannel() can call us with a bad value
TelemetryItem & telemetryItem = telemetryItems[channel];
TelemetrySensor & telemetrySensor = g_model.telemetrySensors[channel];
if (telemetrySensor.unit == UNIT_DATETIME) {
@@ -120,8 +120,10 @@ void menuModelFlightModesAll(uint8_t event)
break;
case ITEM_FLIGHT_MODES_SWITCH:
putsSwitches((5+LEN_FLIGHT_MODE_NAME)*FW+FW/2, y, p->swtch, attr);
if (active) CHECK_INCDEC_MODELSWITCH(event, p->swtch, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, isSwitchAvailableInMixes);
if (k>0) {
putsSwitches((5+LEN_FLIGHT_MODE_NAME)*FW+FW/2, y, p->swtch, attr);
if (active) CHECK_INCDEC_MODELSWITCH(event, p->swtch, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, isSwitchAvailableInMixes);
}
break;
case ITEM_FLIGHT_MODES_TRIM_RUD:
+63 -68
View File
@@ -645,17 +645,14 @@ void menuModelSetup(uint8_t event)
if (checkIncDec_Ret) {
g_model.moduleData[INTERNAL_MODULE].rfProtocol = 0;
g_model.moduleData[INTERNAL_MODULE].channelsStart = 0;
if (g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_PPM)
g_model.moduleData[INTERNAL_MODULE].channelsCount = 0;
else
g_model.moduleData[INTERNAL_MODULE].channelsCount = MAX_INTERNAL_MODULE_CHANNELS();
g_model.moduleData[INTERNAL_MODULE].channelsCount = 0;
}
break;
case 1:
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[INTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST);
if (checkIncDec_Ret) {
g_model.moduleData[INTERNAL_MODULE].channelsStart = 0;
g_model.moduleData[INTERNAL_MODULE].channelsCount = MAX_INTERNAL_MODULE_CHANNELS();
g_model.moduleData[INTERNAL_MODULE].channelsCount = 0;
}
}
}
@@ -667,6 +664,7 @@ void menuModelSetup(uint8_t event)
if (attr) {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[0].rfProtocol, RF_PROTO_OFF, RF_PROTO_LAST);
if (checkIncDec_Ret) {
g_model.moduleData[0].type = MODULE_TYPE_XJT;
g_model.moduleData[0].channelsStart = 0;
g_model.moduleData[0].channelsCount = 0;
}
@@ -695,10 +693,8 @@ void menuModelSetup(uint8_t event)
if (checkIncDec_Ret) {
g_model.moduleData[EXTERNAL_MODULE].rfProtocol = 0;
g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0;
if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM)
g_model.moduleData[EXTERNAL_MODULE].channelsCount = 0;
else
g_model.moduleData[EXTERNAL_MODULE].channelsCount = MAX_EXTERNAL_MODULE_CHANNELS();
g_model.moduleData[EXTERNAL_MODULE].channelsCount = 0;
}
break;
case 1:
@@ -708,7 +704,7 @@ void menuModelSetup(uint8_t event)
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST);
if (checkIncDec_Ret) {
g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0;
g_model.moduleData[EXTERNAL_MODULE].channelsCount = MAX_EXTERNAL_MODULE_CHANNELS();
g_model.moduleData[EXTERNAL_MODULE].channelsCount = 0;
}
}
}
@@ -785,7 +781,7 @@ void menuModelSetup(uint8_t event)
else {
horzpos_t l_posHorz = m_posHorz;
coord_t xOffsetBind = MODEL_SETUP_BIND_OFS;
if (IS_MODULE_XJT(moduleIdx) && !HAS_RF_PROTOCOL_FAILSAFE(g_model.moduleData[moduleIdx].rfProtocol)) {
if (IS_MODULE_XJT(moduleIdx) && g_model.moduleData[moduleIdx].rfProtocol == RF_PROTO_D8) {
xOffsetBind = 0;
lcd_putsLeft(y, INDENT "Receiver");
if (attr) l_posHorz += 1;
@@ -871,14 +867,16 @@ void menuModelFailsafe(uint8_t event)
static bool longNames = false;
bool newLongNames = false;
uint8_t ch = 0;
uint8_t channelStart = g_model.moduleData[g_moduleIdx].channelsStart;
if (event == EVT_KEY_LONG(KEY_ENTER)) {
killEvents(event);
event = 0;
if (s_editMode) {
g_model.moduleData[g_moduleIdx].failsafeChannels[m_posVert] = channelOutputs[m_posVert];
g_model.moduleData[g_moduleIdx].failsafeChannels[m_posVert] = channelOutputs[m_posVert+channelStart];
storageDirty(EE_MODEL);
AUDIO_WARNING1();
s_editMode = 0;
SEND_FAILSAFE_NOW(g_moduleIdx);
}
else {
@@ -888,14 +886,14 @@ void menuModelFailsafe(uint8_t event)
else if (failsafe == FAILSAFE_CHANNEL_HOLD)
failsafe = FAILSAFE_CHANNEL_NOPULSE;
else
failsafe = channelOutputs[m_posVert];
failsafe = 0;
storageDirty(EE_MODEL);
AUDIO_WARNING1();
SEND_FAILSAFE_NOW(g_moduleIdx);
}
}
SIMPLE_SUBMENU_NOTITLE(NUM_CHNOUT);
SIMPLE_SUBMENU_NOTITLE(NUM_CHANNELS(g_moduleIdx));
SET_SCROLLBAR_X(0);
@@ -904,10 +902,6 @@ void menuModelFailsafe(uint8_t event)
// Column separator
lcd_vline(LCD_W/2, FH, LCD_H-FH);
if (m_posVert >= 16) {
ch = 16;
}
lcd_putsCenter(0*FH, FAILSAFESET);
lcd_invert_line(0);
@@ -919,77 +913,78 @@ void menuModelFailsafe(uint8_t event)
// Channels
for (uint8_t line=0; line<8; line++) {
coord_t y = 9+line*7;
int32_t channelValue = channelOutputs[ch];
int32_t channelValue = channelOutputs[ch+channelStart];
int32_t failsafeValue = 0;
bool failsafeEditable = false;
uint8_t ofs = (col ? 0 : 1);
if (ch >= g_model.moduleData[g_moduleIdx].channelsStart && ch < NUM_CHANNELS(g_moduleIdx) + g_model.moduleData[g_moduleIdx].channelsStart) {
if (ch < NUM_CHANNELS(g_moduleIdx)) {
failsafeValue = g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line];
failsafeEditable = true;
}
// Channel name if present, number if not
uint8_t lenLabel = ZLEN(g_model.limitData[ch].name);
if (lenLabel > 4) {
newLongNames = longNames = true;
}
if (failsafeEditable) {
// Channel name if present, number if not
uint8_t lenLabel = ZLEN(g_model.limitData[ch+channelStart].name);
if (lenLabel > 4) {
newLongNames = longNames = true;
}
if (lenLabel > 0)
lcdDrawTextWithLen(x+1-ofs, y, g_model.limitData[ch].name, sizeof(g_model.limitData[ch].name), ZCHAR | SMLSIZE);
else
putsChn(x+1-ofs, y, ch+1, SMLSIZE);
if (lenLabel > 0)
lcdDrawTextWithLen(x+1-ofs, y, g_model.limitData[ch+channelStart].name, sizeof(g_model.limitData[ch+channelStart].name), ZCHAR | SMLSIZE);
else
putsChn(x+1-ofs, y, ch+1, SMLSIZE);
// Value
LcdFlags flags = TINSIZE;
if (m_posVert == ch) {
flags |= INVERS;
if (s_editMode) {
if (!failsafeEditable || failsafeValue == FAILSAFE_CHANNEL_HOLD || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
s_editMode = 0;
}
else {
flags |= BLINK;
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line], -lim, +lim);
// Value
LcdFlags flags = TINSIZE;
if (m_posVert == ch) {
flags |= INVERS;
if (s_editMode) {
if (failsafeValue == FAILSAFE_CHANNEL_HOLD || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
s_editMode = 0;
}
else {
flags |= BLINK;
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line], -lim, +lim);
}
}
}
}
#if defined(PPM_UNIT_PERCENT_PREC1)
uint8_t wbar = (longNames ? SLIDER_W-16 : SLIDER_W-6);
uint8_t wbar = (longNames ? SLIDER_W-16 : SLIDER_W-6);
#else
uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W);
uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W);
#endif
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "HOLD", flags);
failsafeValue = 0;
}
else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "NONE", flags);
failsafeValue = 0;
}
else {
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "HOLD", flags);
failsafeValue = 0;
}
else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "NONE", flags);
failsafeValue = 0;
}
else {
#if defined(PPM_UNIT_US)
lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, PPM_CH_CENTER(ch)+failsafeValue/2, flags);
lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, PPM_CH_CENTER(ch)+failsafeValue/2, flags);
#elif defined(PPM_UNIT_PERCENT_PREC1)
lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(failsafeValue), PREC1|flags);
lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(failsafeValue), PREC1|flags);
#else
lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(failsafeValue)/10, flags);
lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(failsafeValue)/10, flags);
#endif
}
// Gauge
lcdDrawRect(x+COL_W-3-wbar-ofs, y, wbar+1, 6);
unsigned int lenChannel = limit((uint8_t)1, uint8_t((abs(channelValue) * wbar/2 + lim/2) / lim), uint8_t(wbar/2));
unsigned int lenFailsafe = limit((uint8_t)1, uint8_t((abs(failsafeValue) * wbar/2 + lim/2) / lim), uint8_t(wbar/2));
coord_t xChannel = (channelValue>0) ? x+COL_W-ofs-3-wbar/2 : x+COL_W-ofs-2-wbar/2-lenChannel;
coord_t xFailsafe = (failsafeValue>0) ? x+COL_W-ofs-3-wbar/2 : x+COL_W-ofs-2-wbar/2-lenFailsafe;
lcdDrawHorizontalLine(xChannel, y+1, lenChannel, DOTTED, 0);
lcdDrawHorizontalLine(xChannel, y+2, lenChannel, DOTTED, 0);
lcd_hline(xFailsafe, y+3, lenFailsafe);
lcd_hline(xFailsafe, y+4, lenFailsafe);
}
// Gauge
lcdDrawRect(x+COL_W-3-wbar-ofs, y, wbar+1, 6);
unsigned int lenChannel = limit((uint8_t)1, uint8_t((abs(channelValue) * wbar/2 + lim/2) / lim), uint8_t(wbar/2));
unsigned int lenFailsafe = limit((uint8_t)1, uint8_t((abs(failsafeValue) * wbar/2 + lim/2) / lim), uint8_t(wbar/2));
coord_t xChannel = (channelValue>0) ? x+COL_W-ofs-3-wbar/2 : x+COL_W-ofs-2-wbar/2-lenChannel;
coord_t xFailsafe = (failsafeValue>0) ? x+COL_W-ofs-3-wbar/2 : x+COL_W-ofs-2-wbar/2-lenFailsafe;
lcdDrawHorizontalLine(xChannel, y+1, lenChannel, DOTTED, 0);
lcdDrawHorizontalLine(xChannel, y+2, lenChannel, DOTTED, 0);
lcd_hline(xFailsafe, y+3, lenFailsafe);
lcd_hline(xFailsafe, y+4, lenFailsafe);
}
ch++;
}
}
@@ -164,12 +164,8 @@ enum SensorFields {
bool isSensorUnit(int sensor, uint8_t unit)
{
if (sensor == 0)
return true;
sensor -= 1;
return g_model.telemetrySensors[sensor].unit == unit;
if (sensor <= 0 || sensor > MAX_SENSORS ) return true;
return g_model.telemetrySensors[--sensor].unit == unit;
}
bool isCellsSensor(int sensor)
@@ -184,7 +180,7 @@ bool isGPSSensor(int sensor)
bool isAltSensor(int sensor)
{
return isSensorUnit(sensor, UNIT_DIST);
return isSensorUnit(sensor, UNIT_DIST) || isSensorUnit(sensor, UNIT_FEET);
}
bool isVoltsSensor(int sensor)
+18 -13
View File
@@ -236,22 +236,26 @@ void displayTopBar()
/* Rx voltage */
altitude_icon_x = batt_icon_x+7*FW+3;
if (g_model.frsky.voltsSource) {
TelemetryItem & voltsItem = telemetryItems[g_model.frsky.voltsSource-1];
if (voltsItem.isAvailable()) {
putsTelemetryChannelValue(batt_icon_x+7*FW+2, BAR_Y+1, g_model.frsky.voltsSource-1, voltsItem.value, LEFT);
altitude_icon_x = lcdLastPos+1;
uint8_t item = g_model.frsky.voltsSource-1;
if (item < MAX_SENSORS) {
TelemetryItem & voltsItem = telemetryItems[item];
if (voltsItem.isAvailable()) {
putsTelemetryChannelValue(batt_icon_x+7*FW+2, BAR_Y+1, item, voltsItem.value, LEFT);
altitude_icon_x = lcdLastPos+1;
}
}
}
/* Altitude */
if (g_model.frsky.altitudeSource) {
TelemetryItem & altitudeItem = telemetryItems[g_model.frsky.altitudeSource-1];
if (altitudeItem.isAvailable()) {
LCD_ICON(altitude_icon_x, BAR_Y, ICON_ALTITUDE);
int32_t value = altitudeItem.value;
TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1];
if (sensor.prec) value /= sensor.prec == 2 ? 100 : 10;
putsValueWithUnit(altitude_icon_x+2*FW-1, BAR_Y+1, value, UNIT_METERS, LEFT);
uint8_t item = g_model.frsky.altitudeSource-1;
if (item < MAX_SENSORS) {
TelemetryItem & altitudeItem = telemetryItems[item];
if (altitudeItem.isAvailable()) {
LCD_ICON(altitude_icon_x, BAR_Y, ICON_ALTITUDE);
int32_t value = altitudeItem.value / g_model.telemetrySensors[item].getPrecDivisor();
putsValueWithUnit(altitude_icon_x+2*FW-1, BAR_Y+1, value, g_model.telemetrySensors[item].unit, LEFT);
}
}
}
}
@@ -271,11 +275,12 @@ void displayTopBar()
if (TRAINER_CONNECTED()) {
if (SLAVE_MODE()) {
LCD_NOTIF_ICON(x, ICON_TRAINEE);
x -= 12;
}
else {
else if (IS_TRAINER_INPUT_VALID()) {
LCD_NOTIF_ICON(x, ICON_TRAINER);
x -= 12;
}
x -= 12;
}
if (isFunctionActive(FUNCTION_LOGS)) {
+1
View File
@@ -0,0 +1 @@
/lua_exports_*.inc
+749
View File
@@ -0,0 +1,749 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*
*/
#include <ctype.h>
#include <stdio.h>
#include "opentx.h"
#include "stamp-opentx.h"
#include "lua/lua_api.h"
#if defined(PCBHORUS)
#include "lua/lua_exports_horus.inc" // this line must be after lua headers
#elif defined(PCBFLAMENCO)
#include "lua/lua_exports_flamenco.inc"
#elif defined(PCBTARANIS)
#include "lua/lua_exports_taranis.inc"
#endif
#if defined(PCBTARANIS) && defined(REV9E)
#define RADIO "taranisx9e"
#elif defined(PCBTARANIS) && defined(REVPLUS)
#define RADIO "taranisplus"
#elif defined(PCBTARANIS)
#define RADIO "taranis"
#else
#error "Unknown board"
#endif
#if defined(SIMU)
#define RADIO_VERSION RADIO"-simu"
#else
#define RADIO_VERSION RADIO
#endif
#define FIND_FIELD_DESC 0x01
struct LuaField {
uint16_t id;
char desc[50];
};
/*luadoc
@function getVersion()
Returns OpenTX version
@retval string OpenTX version (ie "2.1.5")
@retval list (available since OpenTX 2.1.7) returns two values:
* `string` OpenTX version (ie "2.1.5")
* `string` radio version: `taranisx9e`, `taranisplus` or `taranis`.
If running in simulator the "-simu" is added
@status current Introduced in 2.0.0, expanded in 2.1.7
### Example
This example also runs in OpenTX versions where the radio version was not available:
```lua
local function run(event)
local ver, radio = getVersion()
print("version: "..ver)
if radio then print ("radio: "..radio) end
return 1
end
return { run=run }
```
Output of above script in simulator:
```
version: 2.1.7
radio: taranis-simu
Script finished with status 1
```
*/
static int luaGetVersion(lua_State *L)
{
lua_pushstring(L, VERS_STR);
lua_pushstring(L, RADIO_VERSION);
return 2;
}
/*luadoc
@function getTime()
Returns the time since the radio was started in multiple of 10ms
@retval number Number of 10ms ticks since the radio was started Example:
run time: 12.54 seconds, return value: 1254
@status current Introduced in 2.0.0
*/
static int luaGetTime(lua_State *L)
{
lua_pushunsigned(L, get_tmr10ms());
return 1;
}
static void luaPushDateTime(lua_State *L, uint32_t year, uint32_t mon, uint32_t day,
uint32_t hour, uint32_t min, uint32_t sec)
{
lua_createtable(L, 0, 6);
lua_pushtableinteger(L, "year", year);
lua_pushtableinteger(L, "mon", mon);
lua_pushtableinteger(L, "day", day);
lua_pushtableinteger(L, "hour", hour);
lua_pushtableinteger(L, "min", min);
lua_pushtableinteger(L, "sec", sec);
}
/*luadoc
@function getDateTime()
Returns current system date and time that is kept by the RTC unit
@retval table current date and time, table elements:
* `year` year
* `mon` month
* `day` day of month
* `hour` hours
* `min` minutes
* `sec` seconds
*/
static int luaGetDateTime(lua_State *L)
{
struct gtm utm;
gettime(&utm);
luaPushDateTime(L, utm.tm_year + 1900, utm.tm_mon + 1, utm.tm_mday, utm.tm_hour, utm.tm_min, utm.tm_sec);
return 1;
}
static void luaPushLatLon(TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem)
/* result is lua table containing members ["lat"] and ["lon"] as lua_Number (doubles) in decimal degrees */
{
lua_Number lat = 0.0;
lua_Number lon = 0.0;
uint32_t gpsLat = 0;
uint32_t gpsLon = 0;
telemetryItem.gps.extractLatitudeLongitude(&gpsLat, &gpsLon); /* close, but not the format we want */
lat = gpsLat / 1000000.0;
if (telemetryItem.gps.latitudeNS == 'S') lat = -lat;
lon = gpsLon / 1000000.0;
if (telemetryItem.gps.longitudeEW == 'W') lon = -lon;
lua_createtable(L, 0, 2);
lua_pushtablenumber(L, "lat", lat);
lua_pushtablenumber(L, "lon", lon);
}
static void luaPushTelemetryDateTime(TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem)
{
luaPushDateTime(L, telemetryItem.datetime.year + 2000, telemetryItem.datetime.month, telemetryItem.datetime.day,
telemetryItem.datetime.hour, telemetryItem.datetime.min, telemetryItem.datetime.sec);
}
static void luaPushCells(TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem)
{
if (telemetryItem.cells.count == 0)
lua_pushinteger(L, (int)0); // returns zero if no cells
else {
lua_createtable(L, telemetryItem.cells.count, 0);
for (int i = 0; i < telemetryItem.cells.count; i++) {
lua_pushnumber(L, i + 1);
lua_pushnumber(L, telemetryItem.cells.values[i].value / 100.0);
lua_settable(L, -3);
}
}
}
void luaGetValueAndPush(int src)
{
getvalue_t value = getValue(src); // ignored for GPS, DATETIME, and CELLS
if (src >= MIXSRC_FIRST_TELEM && src <= MIXSRC_LAST_TELEM) {
src = (src-MIXSRC_FIRST_TELEM) / 3;
// telemetry values
if (TELEMETRY_STREAMING() && telemetryItems[src].isAvailable()) {
TelemetrySensor & telemetrySensor = g_model.telemetrySensors[src];
switch (telemetrySensor.unit) {
case UNIT_GPS:
luaPushLatLon(telemetrySensor, telemetryItems[src]);
break;
case UNIT_DATETIME:
luaPushTelemetryDateTime(telemetrySensor, telemetryItems[src]);
break;
case UNIT_CELLS:
luaPushCells(telemetrySensor, telemetryItems[src]);
break;
default:
if (telemetrySensor.prec > 0)
lua_pushnumber(L, float(value)/telemetrySensor.getPrecDivisor());
else
lua_pushinteger(L, value);
break;
}
}
else {
// telemetry not working, return zero for telemetry sources
lua_pushinteger(L, (int)0);
}
}
else if (src == MIXSRC_TX_VOLTAGE) {
lua_pushnumber(L, float(value)/10.0);
}
else {
lua_pushinteger(L, value);
}
}
/**
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; n<DIM(luaSingleFields); ++n) {
if (!strcmp(name, luaSingleFields[n].name)) {
field.id = luaSingleFields[n].id;
if (flags & FIND_FIELD_DESC) {
strncpy(field.desc, luaSingleFields[n].desc, sizeof(field.desc)-1);
field.desc[sizeof(field.desc)-1] = '\0';
}
else {
field.desc[0] = '\0';
}
return true;
}
}
// search in multiples
unsigned int len = strlen(name);
for (unsigned int n=0; n<DIM(luaMultipleFields); ++n) {
const char * fieldName = luaMultipleFields[n].name;
unsigned int fieldLen = strlen(fieldName);
if (!strncmp(name, fieldName, fieldLen)) {
unsigned int index;
if (len == fieldLen+1 && isdigit(name[fieldLen])) {
index = name[fieldLen] - '1';
}
else if (len == fieldLen+2 && isdigit(name[fieldLen]) && isdigit(name[fieldLen+1])) {
index = 10 * (name[fieldLen] - '0') + (name[fieldLen+1] - '1');
}
else {
continue;
}
if (index < luaMultipleFields[n].count) {
field.id = luaMultipleFields[n].id + index;
if (flags & FIND_FIELD_DESC) {
snprintf(field.desc, sizeof(field.desc)-1, luaMultipleFields[n].desc, index+1);
field.desc[sizeof(field.desc)-1] = '\0';
}
else {
field.desc[0] = '\0';
}
return true;
}
}
}
// search in telemetry
field.desc[0] = '\0';
for (int i=0; i<MAX_SENSORS; i++) {
if (isTelemetryFieldAvailable(i)) {
char sensorName[TELEM_LABEL_LEN+1];
int len = zchar2str(sensorName, g_model.telemetrySensors[i].label, TELEM_LABEL_LEN);
if (!strncmp(sensorName, name, len)) {
if (name[len] == '\0') {
field.id = MIXSRC_FIRST_TELEM + 3*i;
field.desc[0] = '\0';
return true;
}
else if (name[len] == '-' && name[len+1] == '\0') {
field.id = MIXSRC_FIRST_TELEM + 3*i + 1;
field.desc[0] = '\0';
return true;
}
else if (name[len] == '+' && name[len+1] == '\0') {
field.id = MIXSRC_FIRST_TELEM + 3*i + 2;
field.desc[0] = '\0';
return true;
}
}
}
}
return false; // not found
}
/*luadoc
@function getFieldInfo(name)
Returns detailed information about field (source)
@param name (string) name of the field
@retval table information about requested field, table elements:
* `id` (number) field identifier
* `name` (string) field name
* `desc` (string) field description
@retval nil the requested field was not found
@status current Introduced in 2.0.8
*/
static int luaGetFieldInfo(lua_State *L)
{
const char * what = luaL_checkstring(L, 1);
LuaField field;
bool found = luaFindFieldByName(what, field, FIND_FIELD_DESC);
if (found) {
lua_newtable(L);
lua_pushtableinteger(L, "id", field.id);
lua_pushtablestring(L, "name", what);
lua_pushtablestring(L, "desc", field.desc);
return 1;
}
return 0;
}
/*luadoc
@function getValue(source)
Returns the value of a source.
The list of valid sources is available:
* for OpenTX 2.0.x at http://downloads-20.open-tx.org/firmware/lua_fields.txt
* for OpenTX 2.1.x at http://downloads-21.open-tx.org/firmware/lua_fields.txt
In OpenTX 2.1.x the telemetry sources no longer have a predefined name.
To get a telemetry value simply use its sensor name. For example:
* Altitude sensor has a name "Alt"
* to get the current altitude use the source "Alt"
* to get the minimum altitude use the source "Alt-", to get the maximum use "Alt+"
@param source can be an identifier (number) (which was obtained by the getFieldInfo())
or a name (string) of the source.
@retval value current source value (number). Zero is returned for:
* non-existing sources
* for all telemetry source when the telemetry stream is not received
@retval table GPS position is returned in a table:
* `lat` latitude, positive is North (number)
* `lon` longitude, positive is East (number)
@retval table GPS date/time is returned in a table, format is the same
as is returned from getDateTime()
@retval table Cells are returned in a table
(except where no cells were detected in which
case the returned value is 0):
* table has one item for each detected cell
* each item name is the cell number (1 to number of cells)
* each item value is the current cell voltage
@status current Introduced in 2.0.0, changed in 2.1.0
@notice Getting a value by its numerical identifier is faster then by its name.
*/
static int luaGetValue(lua_State *L)
{
int src = 0;
if (lua_isnumber(L, 1)) {
src = luaL_checkinteger(L, 1);
}
else {
// 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;
}
}
luaGetValueAndPush(src);
return 1;
}
/*luadoc
@function playFile(name)
Plays a file from the SD card
@param path (string) full path to wav file (i.e. “/SOUNDS/en/system/tada.wav”)
Introduced in 2.1.0: If you use a relative path, the current language is appended
to the path (example for English language: `/SOUNDS/en` is appended)
@status current Introduced in 2.0.0, changed in 2.1.0
*/
static int luaPlayFile(lua_State *L)
{
const char * filename = luaL_checkstring(L, 1);
if (filename[0] != '/') {
// relative sound file path - use current language dir for absolute path
char file[AUDIO_FILENAME_MAXLEN+1];
char * str = getAudioPath(file);
strncpy(str, filename, AUDIO_FILENAME_MAXLEN - (str-file));
file[AUDIO_FILENAME_MAXLEN] = 0;
PLAY_FILE(file, 0, 0);
}
else {
PLAY_FILE(filename, 0, 0);
}
return 0;
}
/*luadoc
@function playNumber(value, unit [, attributes])
Plays a numerical value (text to speech)
@param value (number) number to play. Value is interpreted as integer.
@param unit (number) unit identifier (see table todo)
@param attributes (unsigned number) possible values:
* `0 or not present` plays integral part of the number (for a number 123 it plays 123)
* `PREC1` plays a number with one decimal place (for a number 123 it plays 12.3)
* `PREC2` plays a number with two decimal places (for a number 123 it plays 1.23)
@status current Introduced in 2.0.0
*/
static int luaPlayNumber(lua_State *L)
{
int number = luaL_checkinteger(L, 1);
int unit = luaL_checkinteger(L, 2);
unsigned int att = luaL_optunsigned(L, 3, 0);
playNumber(number, unit, att, 0);
return 0;
}
/*luadoc
@function playDuration(duration [, hourFormat])
Plays a time value (text to speech)
@param duration (number) number of seconds to play. Only integral part is used.
@param hourFormat (number):
* `0 or not present` play format: minutes and seconds.
* `!= 0` play format: hours, minutes and seconds.
@status current Introduced in 2.1.0
*/
static int luaPlayDuration(lua_State *L)
{
int duration = luaL_checkinteger(L, 1);
bool playTime = (luaL_checkinteger(L, 2) != 0);
playDuration(duration, playTime ? PLAY_TIME : 0, 0);
return 0;
}
/*luadoc
@function playTone(frequency, duration, pause [, flags [, freqIncr]])
Plays a tone
@param frequency (number) tone frequency in Hz
@param duration (number) length of the tone in (TODO units)
@param pause (number) length of the pause in (TODO units)
@param flags (number):
* `0 or not present` play with normal priority.
* `PLAY_BACKGROUND` play in background (built in vario function used this context)
* `PLAY_NOW` play immediately
@param freqIncr (number) positive number increases the tone pitch (frequency with time),
negative number decreases it. Bigger number has more effect
@notice Minimum played frequency is 150Hz even if a lower value is specified.
@status current Introduced in 2.1.0
*/
static int luaPlayTone(lua_State *L)
{
int frequency = luaL_checkinteger(L, 1);
int length = luaL_checkinteger(L, 2);
int pause = luaL_checkinteger(L, 3);
int flags = luaL_optinteger(L, 4, 0);
int freqIncr = luaL_optinteger(L, 5, 0);
audioQueue.playTone(frequency, length, pause, flags, freqIncr);
return 0;
}
/*luadoc
@function killEvents(eventMask)
Cancels the key press propagation to the normal user interface algorithm.
@param eventMask (number) events to be suppressed
@status current Introduced in 2.0.0
@notice This function has currently no effect in OpenTX 2.1.x series
TODO table of events/masks
*/
static int luaKillEvents(lua_State *L)
{
int event = luaL_checkinteger(L, 1);
killEvents(event);
return 0;
}
/*luadoc
@function GREY()
Returns gray value which can be used in lcd functions
@retval (number) a value that represents amount of *greyness* (from 0 to 15)
*/
static int luaGrey(lua_State *L)
{
int index = luaL_checkinteger(L, 1);
lua_pushunsigned(L, GREY(index));
return 1;
}
/*luadoc
@function getGeneralSettings()
Returns (some of) the general radio settings
@retval table with elements:
* `battMin` radio battery range - minimum value
* `battMax` radio battery range - maximum value
* `imperial` set to a value different from 0 if the radio is set to the
IMPERIAL units
@status current Introduced in 2.0.6, `imperial` added in TODO
*/
static int luaGetGeneralSettings(lua_State *L)
{
lua_newtable(L);
lua_pushtablenumber(L, "battMin", double(90+g_eeGeneral.vBatMin)/10);
lua_pushtablenumber(L, "battMax", double(120+g_eeGeneral.vBatMax)/10);
lua_pushtableinteger(L, "imperial", g_eeGeneral.imperial);
return 1;
}
/*luadoc
@function popupInput(title, event, input, min, max)
Raises a popup on screen that allows uses input
@param title (string) text to display
@param event (number) the event variable that is passed in from the
Run function (key pressed)
@param input (number) value that can be adjusted by the +/­- keys
@param min (number) min value that input can reach (by pressing the -­ key)
@param max (number) max value that input can reach
@retval number result of the input adjustment
@retval "OK" user pushed ENT key
@retval "CANCEL" user pushed EXIT key
@notice Use only from stand-alone and telemetry scripts.
@status current Introduced in 2.0.0
*/
static int luaPopupInput(lua_State *L)
{
uint8_t event = luaL_checkinteger(L, 2);
s_warning_input_value = luaL_checkinteger(L, 3);
s_warning_input_min = luaL_checkinteger(L, 4);
s_warning_input_max = luaL_checkinteger(L, 5);
s_warning = luaL_checkstring(L, 1);
s_warning_type = WARNING_TYPE_INPUT;
displayWarning(event);
if (s_warning_result) {
s_warning_result = 0;
lua_pushstring(L, "OK");
}
else if (!s_warning) {
lua_pushstring(L, "CANCEL");
}
else {
lua_pushinteger(L, s_warning_input_value);
}
s_warning = NULL;
return 1;
}
/*luadoc
@function defaultStick(channel)
Get stick that is assigned to a channel. See Default Channel Order in General Settings.
@param channel (number) channel number (0 means CH1)
@retval number Stick assigned to this channel (from 0 to 3)
@status current Introduced in 2.0.0
*/
static int luaDefaultStick(lua_State *L)
{
uint8_t channel = luaL_checkinteger(L, 1);
lua_pushinteger(L, channel_order(channel+1)-1);
return 1;
}
/*luadoc
@function defaultChannel(stick)
Get channel assigned to stick. See Default Channel Order in General Settings
@param stick (number) stick number (from 0 to 3)
@retval number channel assigned to this stick (from 0 to 3)
@retval nil stick not found
@status current Introduced in 2.0.0
*/
static int luaDefaultChannel(lua_State *L)
{
uint8_t stick = luaL_checkinteger(L, 1);
for (int i=1; i<=4; i++) {
int tmp = channel_order(i) - 1;
if (tmp == stick) {
lua_pushinteger(L, i-1);
return 1;
}
}
lua_pushnil(L);
return 1;
}
const luaL_Reg opentxLib[] = {
{ "getTime", luaGetTime },
{ "getDateTime", luaGetDateTime },
{ "getVersion", luaGetVersion },
{ "getGeneralSettings", luaGetGeneralSettings },
{ "getValue", luaGetValue },
{ "getFieldInfo", luaGetFieldInfo },
{ "playFile", luaPlayFile },
{ "playNumber", luaPlayNumber },
{ "playDuration", luaPlayDuration },
{ "playTone", luaPlayTone },
{ "popupInput", luaPopupInput },
{ "defaultStick", luaDefaultStick },
{ "defaultChannel", luaDefaultChannel },
{ "killEvents", luaKillEvents },
{ "GREY", luaGrey },
{ NULL, NULL } /* sentinel */
};
const luaR_value_entry opentxConstants[] = {
{ "FULLSCALE", RESX },
{ "XXLSIZE", XXLSIZE },
{ "DBLSIZE", DBLSIZE },
{ "MIDSIZE", MIDSIZE },
{ "SMLSIZE", SMLSIZE },
{ "INVERS", INVERS },
{ "BOLD", BOLD },
{ "BLINK", BLINK },
{ "FIXEDWIDTH", FIXEDWIDTH },
{ "LEFT", LEFT },
{ "PREC1", PREC1 },
{ "PREC2", PREC2 },
{ "VALUE", 0 },
{ "SOURCE", 1 },
{ "REPLACE", MLTPX_REP },
{ "MIXSRC_FIRST_INPUT", MIXSRC_FIRST_INPUT },
{ "MIXSRC_Rud", MIXSRC_Rud },
{ "MIXSRC_Ele", MIXSRC_Ele },
{ "MIXSRC_Thr", MIXSRC_Thr },
{ "MIXSRC_Ail", MIXSRC_Ail },
{ "MIXSRC_SA", MIXSRC_SA },
{ "MIXSRC_SB", MIXSRC_SB },
{ "MIXSRC_SC", MIXSRC_SC },
{ "MIXSRC_SD", MIXSRC_SD },
{ "MIXSRC_SE", MIXSRC_SE },
{ "MIXSRC_SF", MIXSRC_SF },
{ "MIXSRC_SG", MIXSRC_SG },
{ "MIXSRC_SH", MIXSRC_SH },
{ "MIXSRC_CH1", MIXSRC_CH1 },
{ "SWSRC_LAST", SWSRC_LAST_LOGICAL_SWITCH },
{ "EVT_MENU_BREAK", EVT_KEY_BREAK(KEY_MENU) },
{ "EVT_PAGE_BREAK", EVT_KEY_BREAK(KEY_PAGE) },
{ "EVT_PAGE_LONG", EVT_KEY_LONG(KEY_PAGE) },
{ "EVT_ENTER_BREAK", EVT_KEY_BREAK(KEY_ENTER) },
{ "EVT_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER) },
{ "EVT_EXIT_BREAK", EVT_KEY_BREAK(KEY_EXIT) },
{ "EVT_PLUS_BREAK", EVT_KEY_BREAK(KEY_PLUS) },
{ "EVT_MINUS_BREAK", EVT_KEY_BREAK(KEY_MINUS) },
{ "EVT_PLUS_FIRST", EVT_KEY_FIRST(KEY_PLUS) },
{ "EVT_MINUS_FIRST", EVT_KEY_FIRST(KEY_MINUS) },
{ "EVT_PLUS_REPT", EVT_KEY_REPT(KEY_PLUS) },
{ "EVT_MINUS_REPT", EVT_KEY_REPT(KEY_MINUS) },
{ "FILL_WHITE", FILL_WHITE },
{ "GREY_DEFAULT", GREY_DEFAULT },
{ "SOLID", SOLID },
{ "DOTTED", DOTTED },
{ "FORCE", FORCE },
{ "ERASE", ERASE },
{ "ROUND", ROUND },
{ "LCD_W", LCD_W },
{ "LCD_H", LCD_H },
{ "PLAY_NOW", PLAY_NOW },
{ "PLAY_BACKGROUND", PLAY_BACKGROUND },
{ "TIMEHOUR", TIMEHOUR },
{ NULL, 0 } /* sentinel */
};
+352
View File
@@ -0,0 +1,352 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*
*/
#include <ctype.h>
#include <stdio.h>
#include "opentx.h"
#include "lua/lua_api.h"
/*luadoc
@function lcd.lock()
@notice This function has no effect in OpenTX 2.1
*/
static int luaLcdLock(lua_State *L)
{
// disabled in opentx 2.1
// TODO: remove this function completely in opentx 2.2
return 0;
}
/*luadoc
@function lcd.clear()
Erases all contents of LCD.
@notice This function only works in stand-alone and telemetry scripts.
*/
static int luaLcdClear(lua_State *L)
{
if (luaLcdAllowed) lcdClear();
return 0;
}
/*luadoc
@function lcd.drawPoint(x, y)
Draws a single pixel on LCD
@param x (positive number) x position, starts from 0 in top left corner.
@param y (positive number) y position, starts from 0 in top left corner and goes down.
@notice Drawing on an existing black pixel produces white pixel (TODO check this!)
*/
static int luaLcdDrawPoint(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
lcd_plot(x, y);
return 0;
}
/*luadoc
@function lcd.drawLine(x1, y1, x2, y2, pattern, flags)
Draws a straight line on LCD
@param x1,y1 (positive numbers) starting coordinate
@param x2,y2 (positive numbers) end coordinate
@param pattern TODO
@param flags TODO
@notice If the start or the end of the line is outside the LCD dimensions, then the
whole line will not be drawn (starting from OpenTX 2.1.5)
*/
static int luaLcdDrawLine(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x1 = luaL_checkinteger(L, 1);
int y1 = luaL_checkinteger(L, 2);
int x2 = luaL_checkinteger(L, 3);
int y2 = luaL_checkinteger(L, 4);
int pat = luaL_checkinteger(L, 5);
int flags = luaL_checkinteger(L, 6);
lcdDrawLine(x1, y1, x2, y2, pat, flags);
return 0;
}
static int luaLcdGetLastPos(lua_State *L)
{
lua_pushinteger(L, lcdLastPos);
return 1;
}
static int luaLcdDrawText(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
const char * s = luaL_checkstring(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
lcdDrawText(x, y, s, att);
return 0;
}
static int luaLcdDrawTimer(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int seconds = luaL_checkinteger(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
#if defined(PCBFLAMENCO)
putsTimer(x, y, seconds, att|LEFT);
#else
putsTimer(x, y, seconds, att|LEFT, att);
#endif
return 0;
}
static int luaLcdDrawNumber(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
float val = luaL_checknumber(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
int n;
if ((att & PREC2) == PREC2)
n = val * 100;
else if ((att & PREC1) == PREC1)
n = val * 10;
else
n = val;
lcd_outdezAtt(x, y, n, att);
return 0;
}
static int luaLcdDrawChannel(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int channel = -1;
if (lua_isnumber(L, 3)) {
channel = luaL_checkinteger(L, 3);
}
else {
const char * what = luaL_checkstring(L, 3);
LuaField field;
bool found = luaFindFieldByName(what, field);
if (found) {
channel = field.id;
}
}
unsigned int att = luaL_optunsigned(L, 4, 0);
getvalue_t value = getValue(channel);
putsTelemetryChannelValue(x, y, (channel-MIXSRC_FIRST_TELEM)/3, value, att);
return 0;
}
static int luaLcdDrawSwitch(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int s = luaL_checkinteger(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
putsSwitches(x, y, s, att);
return 0;
}
static int luaLcdDrawSource(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int s = luaL_checkinteger(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
putsMixerSource(x, y, s, att);
return 0;
}
#if !defined(COLORLCD)
static int luaLcdDrawPixmap(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
const char * filename = luaL_checkstring(L, 3);
uint8_t bitmap[BITMAP_BUFFER_SIZE(LCD_W/2, LCD_H)]; // width max is LCD_W/2 pixels for saving stack and avoid a malloc here
const pm_char * error = bmpLoad(bitmap, filename, LCD_W/2, LCD_H);
if (!error) {
lcd_bmp(x, y, bitmap);
}
return 0;
}
#endif
static int luaLcdDrawRectangle(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
int h = luaL_checkinteger(L, 4);
unsigned int flags = luaL_optunsigned(L, 5, 0);
lcdDrawRect(x, y, w, h, 0xff, flags);
return 0;
}
static int luaLcdDrawFilledRectangle(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
int h = luaL_checkinteger(L, 4);
unsigned int flags = luaL_optunsigned(L, 5, 0);
drawFilledRect(x, y, w, h, SOLID, flags);
return 0;
}
static int luaLcdDrawGauge(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
int h = luaL_checkinteger(L, 4);
int num = luaL_checkinteger(L, 5);
int den = luaL_checkinteger(L, 6);
// int flags = luaL_checkinteger(L, 7);
lcdDrawRect(x, y, w, h);
uint8_t len = limit((uint8_t)1, uint8_t(w*num/den), uint8_t(w));
for (int i=1; i<h-1; i++) {
lcd_hline(x+1, y+i, len);
}
return 0;
}
#if !defined(COLORLCD)
static int luaLcdDrawScreenTitle(lua_State *L)
{
if (!luaLcdAllowed) return 0;
const char * str = luaL_checkstring(L, 1);
int idx = luaL_checkinteger(L, 2);
int cnt = luaL_checkinteger(L, 3);
if (cnt) displayScreenIndex(idx-1, cnt, 0);
drawFilledRect(0, 0, LCD_W, FH, SOLID, FILL_WHITE|GREY_DEFAULT);
title(str);
return 0;
}
#endif
static int luaLcdDrawCombobox(lua_State *L)
{
if (!luaLcdAllowed) return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
luaL_checktype(L, 4, LUA_TTABLE);
int count = luaL_len(L, 4); /* get size of table */
int idx = luaL_checkinteger(L, 5);
unsigned int flags = luaL_optunsigned(L, 6, 0);
if (idx >= count) {
// TODO error
}
if (flags & BLINK) {
drawFilledRect(x, y, w-9, count*9+2, SOLID, ERASE);
lcdDrawRect(x, y, w-9, count*9+2);
for (int i=0; i<count; i++) {
lua_rawgeti(L, 4, i+1);
const char * item = luaL_checkstring(L, -1);
lcdDrawText(x+2, y+2+9*i, item, 0);
}
drawFilledRect(x+1, y+1+9*idx, w-11, 9);
drawFilledRect(x+w-10, y, 10, 11, SOLID, ERASE);
lcdDrawRect(x+w-10, y, 10, 11);
}
else if (flags & INVERS) {
drawFilledRect(x, y, w, 11);
drawFilledRect(x+w-9, y+1, 8, 9, SOLID, ERASE);
lua_rawgeti(L, 4, idx+1);
const char * item = luaL_checkstring(L, -1);
lcdDrawText(x+2, y+2, item, INVERS);
}
else {
drawFilledRect(x, y, w, 11, SOLID, ERASE);
lcdDrawRect(x, y, w, 11);
drawFilledRect(x+w-10, y+1, 9, 9, SOLID);
lua_rawgeti(L, 4, idx+1);
const char * item = luaL_checkstring(L, -1);
lcdDrawText(x+2, y+2, item, 0);
}
lcd_hline(x+w-8, y+3, 6);
lcd_hline(x+w-8, y+5, 6);
lcd_hline(x+w-8, y+7, 6);
return 0;
}
const luaL_Reg lcdLib[] = {
{ "lock", luaLcdLock },
{ "clear", luaLcdClear },
{ "getLastPos", luaLcdGetLastPos },
{ "drawPoint", luaLcdDrawPoint },
{ "drawLine", luaLcdDrawLine },
{ "drawRectangle", luaLcdDrawRectangle },
{ "drawFilledRectangle", luaLcdDrawFilledRectangle },
{ "drawGauge", luaLcdDrawGauge },
{ "drawText", luaLcdDrawText },
{ "drawTimer", luaLcdDrawTimer },
{ "drawNumber", luaLcdDrawNumber },
{ "drawChannel", luaLcdDrawChannel },
{ "drawSwitch", luaLcdDrawSwitch },
{ "drawSource", luaLcdDrawSource },
{ "drawPixmap", luaLcdDrawPixmap },
{ "drawScreenTitle", luaLcdDrawScreenTitle },
{ "drawCombobox", luaLcdDrawCombobox },
{ NULL, NULL } /* sentinel */
};
+864
View File
@@ -0,0 +1,864 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*
*/
#include <ctype.h>
#include <stdio.h>
#include "opentx.h"
#include "lua/lua_api.h"
#include "timers.h"
static int luaModelGetInfo(lua_State *L)
{
lua_newtable(L);
lua_pushtablezstring(L, "name", g_model.header.name);
lua_pushtablenzstring(L, "bitmap", g_model.header.bitmap);
return 1;
}
static int luaModelSetInfo(lua_State *L)
{
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "name")) {
const char * name = luaL_checkstring(L, -1);
str2zchar(g_model.header.name, name, sizeof(g_model.header.name));
memcpy(modelHeaders[g_eeGeneral.currModel].name, g_model.header.name, sizeof(g_model.header.name));
}
else if (!strcmp(key, "bitmap")) {
const char * name = luaL_checkstring(L, -1);
strncpy(g_model.header.bitmap, name, sizeof(g_model.header.bitmap));
}
}
storageDirty(EE_MODEL);
return 0;
}
static int luaModelGetModule(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_MODULES) {
ModuleData & module = g_model.moduleData[idx];
lua_newtable(L);
lua_pushtableinteger(L, "rfProtocol", module.rfProtocol);
lua_pushtableinteger(L, "modelId", g_model.header.modelId[idx]);
lua_pushtableinteger(L, "firstChannel", module.channelsStart);
lua_pushtableinteger(L, "channelsCount", module.channelsCount + 8);
}
else {
lua_pushnil(L);
}
return 1;
}
static int luaModelSetModule(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_MODULES) {
ModuleData & module = g_model.moduleData[idx];
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "rfProtocol")) {
module.rfProtocol = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "modelId")) {
g_model.header.modelId[idx] = modelHeaders[g_eeGeneral.currModel].modelId[idx] = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "firstChannel")) {
module.channelsStart = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "channelsCount")) {
module.channelsCount = luaL_checkinteger(L, -1) - 8;
}
}
storageDirty(EE_MODEL);
}
return 0;
}
static int luaModelGetTimer(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < MAX_TIMERS) {
TimerData & timer = g_model.timers[idx];
lua_newtable(L);
lua_pushtableinteger(L, "mode", timer.mode);
lua_pushtableinteger(L, "start", timer.start);
lua_pushtableinteger(L, "value", timersStates[idx].val);
lua_pushtableinteger(L, "countdownBeep", timer.countdownBeep);
lua_pushtableboolean(L, "minuteBeep", timer.minuteBeep);
lua_pushtableinteger(L, "persistent", timer.persistent);
}
else {
lua_pushnil(L);
}
return 1;
}
static int luaModelSetTimer(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < MAX_TIMERS) {
TimerData & timer = g_model.timers[idx];
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "mode")) {
timer.mode = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "start")) {
timer.start = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "value")) {
timersStates[idx].val = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "countdownBeep")) {
timer.countdownBeep = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "minuteBeep")) {
timer.minuteBeep = lua_toboolean(L, -1);
}
else if (!strcmp(key, "persistent")) {
timer.persistent = luaL_checkinteger(L, -1);
}
}
storageDirty(EE_MODEL);
}
return 0;
}
static int luaModelResetTimer(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < MAX_TIMERS) {
timerReset(idx);
}
return 0;
}
static unsigned int getFirstInput(unsigned int chn)
{
for (unsigned int i=0; i<MAX_INPUTS; i++) {
ExpoData * expo = expoAddress(i);
if (!expo->srcRaw || expo->chn >= chn) {
return i;
}
}
return 0;
}
static unsigned int getInputsCountFromFirst(unsigned int chn, unsigned int first)
{
unsigned int count = 0;
for (unsigned int i=first; i<MAX_INPUTS; i++) {
ExpoData * expo = expoAddress(i);
if (!expo->srcRaw || expo->chn!=chn) break;
count++;
}
return count;
}
static unsigned int getInputsCount(unsigned int chn)
{
return getInputsCountFromFirst(chn, getFirstInput(chn));
}
/*luadoc
@function model.getInputsCount(input)
Returns number of lines for given input
@param input (unsigned number) input number (use 0 for Input1)
@retval number number of configured lines for given input
@status current Introduced in 2.0.0
*/
static int luaModelGetInputsCount(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
int count = getInputsCount(chn);
lua_pushinteger(L, count);
return 1;
}
/*luadoc
@function model.getInput(input, line)
Returns input data for given input and line number
@param input (unsigned number) input number (use 0 for Input1)
@param line (unsigned number) input line (use 0 for first line)
@retval nil requested input or line does not exist
@retval table input data:
* `name` (string) input line name
* `source` (number) input source index
* `weight` (number) input weight
* `offset` (number) input offset
* `switch` (number) input switch index
@status current Introduced in 2.0.0, `switch` added in TODO
*/
static int luaModelGetInput(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
unsigned int idx = luaL_checkunsigned(L, 2);
unsigned int first = getFirstInput(chn);
unsigned int count = getInputsCountFromFirst(chn, first);
if (idx < count) {
ExpoData * expo = expoAddress(first+idx);
lua_newtable(L);
lua_pushtablezstring(L, "name", expo->name);
lua_pushtableinteger(L, "source", expo->srcRaw);
lua_pushtableinteger(L, "weight", expo->weight);
lua_pushtableinteger(L, "offset", expo->offset);
lua_pushtableinteger(L, "switch", expo->swtch);
}
else {
lua_pushnil(L);
}
return 1;
}
/*luadoc
@function model.insertInput(input, line, value)
Inserts an Input at specified line
@param input (unsigned number) input number (use 0 for Input1)
@param line (unsigned number) input line (use 0 for first line)
@param value (table) input data, see model.getInput()
@status current Introduced in 2.0.0, `switch` added in TODO
*/
static int luaModelInsertInput(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
unsigned int idx = luaL_checkunsigned(L, 2);
unsigned int first = getFirstInput(chn);
unsigned int count = getInputsCountFromFirst(chn, first);
if (chn<MAX_INPUTS && getExpoMixCount(1)<MAX_EXPOS && idx<=count) {
idx = first + idx;
s_currCh = chn + 1;
insertExpoMix(1, idx);
ExpoData * expo = expoAddress(idx);
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "name")) {
const char * name = luaL_checkstring(L, -1);
str2zchar(expo->name, name, sizeof(expo->name));
}
else if (!strcmp(key, "source")) {
expo->srcRaw = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "weight")) {
expo->weight = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "offset")) {
expo->offset = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "switch")) {
expo->swtch = luaL_checkinteger(L, -1);
}
}
}
return 0;
}
/*luadoc
@function model.deleteInput(input, line)
Delete line from specified input
@param input (unsigned number) input number (use 0 for Input1)
@param line (unsigned number) input line (use 0 for first line)
@status current Introduced in 2.0.0
*/
static int luaModelDeleteInput(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
unsigned int idx = luaL_checkunsigned(L, 2);
int first = getFirstInput(chn);
unsigned int count = getInputsCountFromFirst(chn, first);
if (idx < count) {
deleteExpoMix(1, first+idx);
}
return 0;
}
/*luadoc
@function model.deleteInputs()
Delete all Inputs
@status current Introduced in 2.0.0
*/
static int luaModelDeleteInputs(lua_State *L)
{
clearInputs();
return 0;
}
/*luadoc
@function model.defaultInputs()
Set all inputs to defaults
@status current Introduced in 2.0.0
*/
static int luaModelDefaultInputs(lua_State *L)
{
defaultInputs();
return 0;
}
static unsigned int getFirstMix(unsigned int chn)
{
for (unsigned int i=0; i<MAX_MIXERS; i++) {
MixData * mix = mixAddress(i);
if (!mix->srcRaw || mix->destCh>=chn) {
return i;
}
}
return 0;
}
static unsigned int getMixesCountFromFirst(unsigned int chn, unsigned int first)
{
unsigned int count = 0;
for (unsigned int i=first; i<MAX_MIXERS; i++) {
MixData * mix = mixAddress(i);
if (!mix->srcRaw || mix->destCh!=chn) break;
count++;
}
return count;
}
static unsigned int getMixesCount(unsigned int chn)
{
return getMixesCountFromFirst(chn, getFirstMix(chn));
}
static int luaModelGetMixesCount(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
unsigned int count = getMixesCount(chn);
lua_pushinteger(L, count);
return 1;
}
static int luaModelGetMix(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
unsigned int idx = luaL_checkunsigned(L, 2);
unsigned int first = getFirstMix(chn);
unsigned int count = getMixesCountFromFirst(chn, first);
if (idx < count) {
MixData * mix = mixAddress(first+idx);
lua_newtable(L);
lua_pushtablezstring(L, "name", mix->name);
lua_pushtableinteger(L, "source", mix->srcRaw);
lua_pushtableinteger(L, "weight", mix->weight);
lua_pushtableinteger(L, "offset", mix->offset);
lua_pushtableinteger(L, "switch", mix->swtch);
lua_pushtableinteger(L, "curveType", mix->curve.type);
lua_pushtableinteger(L, "curveValue", mix->curve.value);
lua_pushtableinteger(L, "multiplex", mix->mltpx);
lua_pushtableinteger(L, "flightModes", mix->flightModes);
lua_pushtableboolean(L, "carryTrim", mix->carryTrim);
lua_pushtableinteger(L, "mixWarn", mix->mixWarn);
lua_pushtableinteger(L, "delayUp", mix->delayUp);
lua_pushtableinteger(L, "delayDown", mix->delayDown);
lua_pushtableinteger(L, "speedUp", mix->speedUp);
lua_pushtableinteger(L, "speedDown", mix->speedDown);
}
else {
lua_pushnil(L);
}
return 1;
}
static int luaModelInsertMix(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
unsigned int idx = luaL_checkunsigned(L, 2);
unsigned int first = getFirstMix(chn);
unsigned int count = getMixesCountFromFirst(chn, first);
if (chn<NUM_CHNOUT && getExpoMixCount(0)<MAX_MIXERS && idx<=count) {
idx += first;
s_currCh = chn+1;
insertExpoMix(0, idx);
MixData *mix = mixAddress(idx);
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "name")) {
const char * name = luaL_checkstring(L, -1);
str2zchar(mix->name, name, sizeof(mix->name));
}
else if (!strcmp(key, "source")) {
mix->srcRaw = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "weight")) {
mix->weight = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "offset")) {
mix->offset = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "switch")) {
mix->swtch = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "curveType")) {
mix->curve.type = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "curveValue")) {
mix->curve.value = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "multiplex")) {
mix->mltpx = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "flightModes")) {
mix->flightModes = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "carryTrim")) {
mix->carryTrim = lua_toboolean(L, -1);
}
else if (!strcmp(key, "mixWarn")) {
mix->mixWarn = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "delayUp")) {
mix->delayUp = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "delayDown")) {
mix->delayDown = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "speedUp")) {
mix->speedUp = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "speedDown")) {
mix->speedDown = luaL_checkinteger(L, -1);
}
}
}
return 0;
}
static int luaModelDeleteMix(lua_State *L)
{
unsigned int chn = luaL_checkunsigned(L, 1);
unsigned int idx = luaL_checkunsigned(L, 2);
unsigned int first = getFirstMix(chn);
unsigned int count = getMixesCountFromFirst(chn, first);
if (idx < count) {
deleteExpoMix(0, first+idx);
}
return 0;
}
static int luaModelDeleteMixes(lua_State *L)
{
memset(g_model.mixData, 0, sizeof(g_model.mixData));
return 0;
}
static int luaModelGetLogicalSwitch(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_LOGICAL_SWITCH) {
LogicalSwitchData * sw = lswAddress(idx);
lua_newtable(L);
lua_pushtableinteger(L, "func", sw->func);
lua_pushtableinteger(L, "v1", sw->v1);
lua_pushtableinteger(L, "v2", sw->v2);
lua_pushtableinteger(L, "v3", sw->v3);
lua_pushtableinteger(L, "and", sw->andsw);
lua_pushtableinteger(L, "delay", sw->delay);
lua_pushtableinteger(L, "duration", sw->duration);
}
else {
lua_pushnil(L);
}
return 1;
}
static int luaModelSetLogicalSwitch(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_LOGICAL_SWITCH) {
LogicalSwitchData * sw = lswAddress(idx);
memclear(sw, sizeof(LogicalSwitchData));
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "func")) {
sw->func = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "v1")) {
sw->v1 = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "v2")) {
sw->v2 = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "v3")) {
sw->v3 = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "and")) {
sw->andsw = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "delay")) {
sw->delay = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "duration")) {
sw->duration = luaL_checkinteger(L, -1);
}
}
storageDirty(EE_MODEL);
}
return 0;
}
static int luaModelGetCurve(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < MAX_CURVES) {
CurveInfo & curveInfo = g_model.curves[idx];
lua_newtable(L);
lua_pushtablezstring(L, "name", g_model.curveNames[idx]);
lua_pushtableinteger(L, "type", curveInfo.type);
lua_pushtableboolean(L, "smooth", curveInfo.smooth);
lua_pushtableinteger(L, "points", curveInfo.points+5);
lua_pushstring(L, "y");
lua_newtable(L);
int8_t * point = curveAddress(idx);
for (int i=0; i<curveInfo.points+5; i++) {
lua_pushinteger(L, i);
lua_pushinteger(L, *point++);
lua_settable(L, -3);
}
lua_settable(L, -3);
if (curveInfo.type == CURVE_TYPE_CUSTOM) {
lua_pushstring(L, "x");
lua_newtable(L);
lua_pushinteger(L, 0);
lua_pushinteger(L, 0);
lua_settable(L, -3);
for (int i=0; i<curveInfo.points+3; i++) {
lua_pushinteger(L, i+1);
lua_pushinteger(L, *point++);
lua_settable(L, -3);
}
lua_pushinteger(L, curveInfo.points+4);
lua_pushinteger(L, 100);
lua_settable(L, -3);
lua_settable(L, -3);
}
}
else {
lua_pushnil(L);
}
return 1;
}
static int luaModelGetCustomFunction(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_CFN) {
CustomFunctionData * cfn = &g_model.customFn[idx];
lua_newtable(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_pushtablenzstring(L, "name", cfn->play.name);
}
else {
lua_pushtableinteger(L, "value", cfn->all.val);
lua_pushtableinteger(L, "mode", cfn->all.mode);
lua_pushtableinteger(L, "param", cfn->all.param);
}
lua_pushtableinteger(L, "active", CFN_ACTIVE(cfn));
}
else {
lua_pushnil(L);
}
return 1;
}
static int luaModelSetCustomFunction(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_CFN) {
CustomFunctionData * cfn = &g_model.customFn[idx];
memclear(cfn, sizeof(CustomFunctionData));
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "switch")) {
CFN_SWITCH(cfn) = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "func")) {
CFN_FUNC(cfn) = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "name")) {
const char * name = luaL_checkstring(L, -1);
strncpy(cfn->play.name, name, sizeof(cfn->play.name));
}
else if (!strcmp(key, "value")) {
cfn->all.val = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "mode")) {
cfn->all.mode = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "param")) {
cfn->all.param = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "active")) {
CFN_ACTIVE(cfn) = luaL_checkinteger(L, -1);
}
}
storageDirty(EE_MODEL);
}
return 0;
}
static int luaModelGetOutput(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_CHNOUT) {
LimitData * limit = limitAddress(idx);
lua_newtable(L);
lua_pushtablezstring(L, "name", limit->name);
lua_pushtableinteger(L, "min", limit->min-1000);
lua_pushtableinteger(L, "max", limit->max+1000);
lua_pushtableinteger(L, "offset", limit->offset);
lua_pushtableinteger(L, "ppmCenter", limit->ppmCenter);
lua_pushtableinteger(L, "symetrical", limit->symetrical);
lua_pushtableinteger(L, "revert", limit->revert);
if (limit->curve)
lua_pushtableinteger(L, "curve", limit->curve-1);
else
lua_pushtablenil(L, "curve");
}
else {
lua_pushnil(L);
}
return 1;
}
/*luadoc
@function model.setOutput(index, value)
Sets current global variable value. See also model.getGlobalVariable()
@param index zero based output index, use 0 for CH1, 31 for CH32
@param value new value for output. The `value` is a table with following items:
* `name` name of the output (channel)
* `min` negative limit
* `max` positive limit
* `offset` subtrim value
* `ppmCenter` ppm center value
* `symetrical` 1 for symmetric limits, 0 for normal
* `revert` 1 for inverted output, 0 for normal
* `curve` curve reference (zero based index, 0 means Curve 1)
*/
static int luaModelSetOutput(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < NUM_CHNOUT) {
LimitData * limit = limitAddress(idx);
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TSTRING); // key is string
const char * key = luaL_checkstring(L, -2);
if (!strcmp(key, "name")) {
const char * name = luaL_checkstring(L, -1);
str2zchar(limit->name, name, sizeof(limit->name));
}
else if (!strcmp(key, "min")) {
limit->min = luaL_checkinteger(L, -1)+1000;
}
else if (!strcmp(key, "max")) {
limit->max = luaL_checkinteger(L, -1)-1000;
}
else if (!strcmp(key, "offset")) {
limit->offset = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "ppmCenter")) {
limit->ppmCenter = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "symetrical")) {
limit->symetrical = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "revert")) {
limit->revert = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "curve")) {
if (lua_isnil(L, -1))
limit->curve = 0;
else
limit->curve = luaL_checkinteger(L, -1) + 1;
}
}
storageDirty(EE_MODEL);
}
return 0;
}
/*luadoc
@function model.getGlobalVariable(index [, phase])
Returns current global variable value.
See also model.setGlobalVariable()
@notice a simple warning or notice
@param index zero based global variable index, use 0 for GV1, 8 for GV9
@param phase zero based phase index, use 0 for Phase 1, 5 for Phase 6
@retval nil requested global variable does not exist
@retval number current value of global variable
Example:
```lua
-- get GV3 (index = 2) from flight phase 1 (phase = 0)
val = model.getGlobalVariable(2, 0)
```
*/
static int luaModelGetGlobalVariable(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
unsigned int phase = luaL_checkunsigned(L, 2);
if (phase < MAX_FLIGHT_MODES && idx < MAX_GVARS)
lua_pushinteger(L, g_model.flightModeData[phase].gvars[idx]);
else
lua_pushnil(L);
return 1;
}
/*luadoc
@function model.setGlobalVariable(index, phase, value)
Sets current global variable value. See also model.getGlobalVariable()
@param index zero based global variable index, use 0 for GV1, 8 for GV9
@param phase zero based phase index, use 0 for Phase 1, 5 for Phase 6
@param value new value for global variable. Permitted range is
from -1024 to 1024.
@notice Global variable can only store integer values,
any floating point value is converted (todo check how) into integer value.
*/
static int luaModelSetGlobalVariable(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
unsigned int phase = luaL_checkunsigned(L, 2);
int value = luaL_checkinteger(L, 3);
if (phase < MAX_FLIGHT_MODES && idx < MAX_GVARS && value >= -GVAR_MAX && value <= GVAR_MAX) {
g_model.flightModeData[phase].gvars[idx] = value;
storageDirty(EE_MODEL);
}
return 0;
}
const luaL_Reg modelLib[] = {
{ "getInfo", luaModelGetInfo },
{ "setInfo", luaModelSetInfo },
{ "getModule", luaModelGetModule },
{ "setModule", luaModelSetModule },
{ "getTimer", luaModelGetTimer },
{ "setTimer", luaModelSetTimer },
{ "resetTimer", luaModelResetTimer },
{ "getInputsCount", luaModelGetInputsCount },
{ "getInput", luaModelGetInput },
{ "insertInput", luaModelInsertInput },
{ "deleteInput", luaModelDeleteInput },
{ "deleteInputs", luaModelDeleteInputs },
{ "defaultInputs", luaModelDefaultInputs },
{ "getMixesCount", luaModelGetMixesCount },
{ "getMix", luaModelGetMix },
{ "insertMix", luaModelInsertMix },
{ "deleteMix", luaModelDeleteMix },
{ "deleteMixes", luaModelDeleteMixes },
{ "getLogicalSwitch", luaModelGetLogicalSwitch },
{ "setLogicalSwitch", luaModelSetLogicalSwitch },
{ "getCustomFunction", luaModelGetCustomFunction },
{ "setCustomFunction", luaModelSetCustomFunction },
{ "getCurve", luaModelGetCurve },
{ "getOutput", luaModelGetOutput },
{ "setOutput", luaModelSetOutput },
{ "getGlobalVariable", luaModelGetGlobalVariable },
{ "setGlobalVariable", luaModelSetGlobalVariable },
{ NULL, NULL } /* sentinel */
};
+786
View File
@@ -0,0 +1,786 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*
*/
#include <ctype.h>
#include <stdio.h>
#include "opentx.h"
#include "bin_allocator.h"
#include "lua/lua_api.h"
#if defined(LUA_COMPILER) && defined(SIMU)
#include <lundump.h>
#include <lstate.h>
#endif
#define PERMANENT_SCRIPTS_MAX_INSTRUCTIONS (10000/100)
#define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100)
#define SET_LUA_INSTRUCTIONS_COUNT(x) (instructionsPercent=0, lua_sethook(L, hook, LUA_MASKCOUNT, x))
#define LUA_WARNING_INFO_LEN 64
lua_State *L = NULL;
uint8_t luaState = 0;
uint8_t luaScriptsCount = 0;
ScriptInternalData scriptInternalData[MAX_SCRIPTS] = { { SCRIPT_NOFILE, 0 } };
ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS] = { {0} };
ScriptInternalData standaloneScript = { SCRIPT_NOFILE, 0 };
uint16_t maxLuaInterval = 0;
uint16_t maxLuaDuration = 0;
bool luaLcdAllowed;
int instructionsPercent = 0;
char lua_warning_info[LUA_WARNING_INFO_LEN+1];
struct our_longjmp * global_lj = 0;
/* custom panic handler */
static int custom_lua_atpanic(lua_State *lua)
{
TRACE("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1));
if (global_lj) {
longjmp(global_lj->b, 1);
/* will never return */
}
return 0;
}
void hook(lua_State* L, lua_Debug *ar)
{
instructionsPercent++;
if (instructionsPercent > 100) {
// From now on, as soon as a line is executed, error
// keep erroring until you're script reaches the top
lua_sethook(L, hook, LUA_MASKLINE, 0);
luaL_error(L, "");
}
}
int luaGetInputs(ScriptInputsOutputs & sid)
{
if (!lua_istable(L, -1))
return -1;
sid.inputsCount = 0;
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TTABLE); // value is table
if (sid.inputsCount<MAX_SCRIPT_INPUTS) {
uint8_t field = 0;
for (lua_pushnil(L); lua_next(L, -2) && field<5; lua_pop(L, 1), field++) {
switch (field) {
case 0:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TSTRING); // value is string
sid.inputs[sid.inputsCount].name = lua_tostring(L, -1);
break;
case 1:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
sid.inputs[sid.inputsCount].type = lua_tointeger(L, -1);
if (sid.inputs[sid.inputsCount].type == 0) {
sid.inputs[sid.inputsCount].min = -100;
sid.inputs[sid.inputsCount].max = 100;
}
else {
sid.inputs[sid.inputsCount].max = MIXSRC_LAST_TELEM;
}
break;
case 2:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
sid.inputs[sid.inputsCount].min = lua_tointeger(L, -1);
break;
case 3:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
sid.inputs[sid.inputsCount].max = lua_tointeger(L, -1);
break;
case 4:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
sid.inputs[sid.inputsCount].def = lua_tointeger(L, -1);
break;
}
}
sid.inputsCount++;
}
}
return 0;
}
int luaGetOutputs(ScriptInputsOutputs & sid)
{
if (!lua_istable(L, -1))
return -1;
sid.outputsCount = 0;
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TSTRING); // value is string
if (sid.outputsCount<MAX_SCRIPT_OUTPUTS) {
sid.outputs[sid.outputsCount++].name = lua_tostring(L, -1);
}
}
return 0;
}
void luaDisable()
{
POPUP_WARNING("Lua disabled!");
luaState = INTERPRETER_PANIC;
}
void luaClose()
{
if (L) {
PROTECT_LUA() {
lua_close(L); // this should not panic, but we make sure anyway
}
else {
// we can only disable Lua for the rest of the session
luaDisable();
}
UNPROTECT_LUA();
L = NULL;
}
}
void luaRegisterAll()
{
// Init lua
luaL_openlibs(L);
}
void luaInit()
{
luaClose();
if (luaState != INTERPRETER_PANIC) {
#if defined(USE_BIN_ALLOCATOR)
L = lua_newstate(bin_l_alloc, NULL); //we use our own allocator!
#else
L = lua_newstate(l_alloc, NULL); //we use Lua default allocator
#endif
if (L) {
// install our panic handler
lua_atpanic(L, &custom_lua_atpanic);
// protect libs and constants registration
PROTECT_LUA() {
luaRegisterAll();
}
else {
// if we got panic during registration
// we disable Lua for this session
luaDisable();
}
UNPROTECT_LUA();
}
else {
/* log error and return */
luaDisable();
}
}
}
void luaFree(ScriptInternalData & sid)
{
PROTECT_LUA() {
if (sid.run) {
luaL_unref(L, LUA_REGISTRYINDEX, sid.run);
sid.run = 0;
}
if (sid.background) {
luaL_unref(L, LUA_REGISTRYINDEX, sid.background);
sid.background = 0;
}
lua_gc(L, LUA_GCCOLLECT, 0);
}
else {
luaDisable();
}
UNPROTECT_LUA();
}
#if defined(LUA_COMPILER) && defined(SIMU)
static int luaDumpWriter(lua_State* L, const void* p, size_t size, void* u)
{
UNUSED(L);
UINT written;
FRESULT result = f_write((FIL *)u, p, size, &written);
return (result != FR_OK && !written);
}
static void luaCompileAndSave(const char *filename)
{
FIL D;
char bytecodeName[1024];
strcpy(bytecodeName, filename);
strcat(bytecodeName, "c");
if (f_stat(bytecodeName, 0) == FR_OK) {
return; // compiled file already exists
}
if (f_open(&D, bytecodeName, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
TRACE("Could not open Lua bytecode output file %s", bytecodeName);
return;
}
PROTECT_LUA() {
if (luaL_loadfile(L, filename) == 0) {
lua_lock(L);
luaU_dump(L, getproto(L->top - 1), luaDumpWriter, &D, 1);
lua_unlock(L);
TRACE("Saved Lua bytecode to file %s", bytecodeName);
}
}
UNPROTECT_LUA();
f_close(&D);
}
#endif
int luaLoad(const char *filename, ScriptInternalData & sid, ScriptInputsOutputs * sio=NULL)
{
int init = 0;
sid.instructions = 0;
sid.state = SCRIPT_OK;
#if 0
// not needed, we just called luaInit
luaFree(sid);
#endif
if (luaState == INTERPRETER_PANIC) {
return SCRIPT_PANIC;
}
#if defined(LUA_COMPILER) && defined(SIMU)
luaCompileAndSave(filename);
#endif
SET_LUA_INSTRUCTIONS_COUNT(MANUAL_SCRIPTS_MAX_INSTRUCTIONS);
PROTECT_LUA() {
if (luaL_loadfile(L, filename) == 0 &&
lua_pcall(L, 0, 1, 0) == 0 &&
lua_istable(L, -1)) {
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
const char *key = lua_tostring(L, -2);
if (!strcmp(key, "init")) {
init = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (!strcmp(key, "run")) {
sid.run = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (!strcmp(key, "background")) {
sid.background = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (sio && !strcmp(key, "input")) {
luaGetInputs(*sio);
}
else if (sio && !strcmp(key, "output")) {
luaGetOutputs(*sio);
}
}
if (init) {
lua_rawgeti(L, LUA_REGISTRYINDEX, init);
if (lua_pcall(L, 0, 0, 0) != 0) {
TRACE("Error in script %s init: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
luaL_unref(L, LUA_REGISTRYINDEX, init);
lua_gc(L, LUA_GCCOLLECT, 0);
}
}
else {
TRACE("Error in script %s: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
}
else {
luaDisable();
return SCRIPT_PANIC;
}
UNPROTECT_LUA();
if (sid.state != SCRIPT_OK) {
luaFree(sid);
}
return sid.state;
}
bool luaLoadMixScript(uint8_t index)
{
ScriptData & sd = g_model.scriptsData[index];
if (ZEXIST(sd.file)) {
ScriptInternalData & sid = scriptInternalData[luaScriptsCount++];
ScriptInputsOutputs * sio = &scriptInputsOutputs[index];
sid.reference = SCRIPT_MIX_FIRST+index;
sid.state = SCRIPT_NOFILE;
char filename[sizeof(SCRIPTS_MIXES_PATH)+sizeof(sd.file)+sizeof(SCRIPTS_EXT)] = SCRIPTS_MIXES_PATH "/";
strncpy(filename+sizeof(SCRIPTS_MIXES_PATH), sd.file, sizeof(sd.file));
filename[sizeof(SCRIPTS_MIXES_PATH)+sizeof(sd.file)] = '\0';
strcat(filename+sizeof(SCRIPTS_MIXES_PATH), SCRIPTS_EXT);
if (luaLoad(filename, sid, sio) == SCRIPT_PANIC) {
return false;
}
}
return true;
}
bool luaLoadFunctionScript(uint8_t index)
{
CustomFunctionData & fn = g_model.customFn[index];
if (fn.func == FUNC_PLAY_SCRIPT && ZEXIST(fn.play.name)) {
if (luaScriptsCount < MAX_SCRIPTS) {
ScriptInternalData & sid = scriptInternalData[luaScriptsCount++];
sid.reference = SCRIPT_FUNC_FIRST+index;
sid.state = SCRIPT_NOFILE;
char filename[sizeof(SCRIPTS_FUNCS_PATH)+sizeof(fn.play.name)+sizeof(SCRIPTS_EXT)] = SCRIPTS_FUNCS_PATH "/";
strncpy(filename+sizeof(SCRIPTS_FUNCS_PATH), fn.play.name, sizeof(fn.play.name));
filename[sizeof(SCRIPTS_FUNCS_PATH)+sizeof(fn.play.name)] = '\0';
strcat(filename+sizeof(SCRIPTS_FUNCS_PATH), SCRIPTS_EXT);
if (luaLoad(filename, sid) == SCRIPT_PANIC) {
return false;
}
}
else {
POPUP_WARNING(STR_TOO_MANY_LUA_SCRIPTS);
return false;
}
}
return true;
}
bool luaLoadTelemetryScript(uint8_t index)
{
TelemetryScreenType screenType = TELEMETRY_SCREEN_TYPE(index);
if (screenType == TELEMETRY_SCREEN_TYPE_SCRIPT) {
TelemetryScriptData & script = g_model.frsky.screens[index].script;
if (ZEXIST(script.file)) {
if (luaScriptsCount < MAX_SCRIPTS) {
ScriptInternalData & sid = scriptInternalData[luaScriptsCount++];
sid.reference = SCRIPT_TELEMETRY_FIRST+index;
sid.state = SCRIPT_NOFILE;
char filename[sizeof(SCRIPTS_TELEM_PATH)+sizeof(script.file)+sizeof(SCRIPTS_EXT)] = SCRIPTS_TELEM_PATH "/";
strncpy(filename+sizeof(SCRIPTS_TELEM_PATH), script.file, sizeof(script.file));
filename[sizeof(SCRIPTS_TELEM_PATH)+sizeof(script.file)] = '\0';
strcat(filename+sizeof(SCRIPTS_TELEM_PATH), SCRIPTS_EXT);
if (luaLoad(filename, sid) == SCRIPT_PANIC) {
return false;
}
}
else {
POPUP_WARNING(STR_TOO_MANY_LUA_SCRIPTS);
return false;
}
}
}
return true;
}
uint8_t isTelemetryScriptAvailable(uint8_t index)
{
for (int i=0; i<luaScriptsCount; i++) {
ScriptInternalData & sid = scriptInternalData[i];
if (sid.reference == SCRIPT_TELEMETRY_FIRST+index) {
return sid.state;
}
}
return SCRIPT_NOFILE;
}
void luaLoadPermanentScripts()
{
luaScriptsCount = 0;
memset(scriptInternalData, 0, sizeof(scriptInternalData));
memset(scriptInputsOutputs, 0, sizeof(scriptInputsOutputs));
// Load model scripts
for (int i=0; i<MAX_SCRIPTS; i++) {
if (!luaLoadMixScript(i)) {
return;
}
}
// Load custom function scripts
for (int i=0; i<NUM_CFN; i++) {
if (!luaLoadFunctionScript(i)) {
return;
}
}
// Load custom telemetry scripts
for (int i=0; i<MAX_TELEMETRY_SCREENS; i++) {
if (!luaLoadTelemetryScript(i)) {
return;
}
}
}
void displayLuaError(const char * title)
{
#if !defined(COLORLCD)
displayBox(title);
#endif
if (lua_warning_info[0]) {
char * split = strstr(lua_warning_info, ": ");
if (split) {
lcdDrawTextWithLen(WARNING_LINE_X, WARNING_LINE_Y+FH+3, lua_warning_info, split-lua_warning_info, SMLSIZE);
lcdDrawTextWithLen(WARNING_LINE_X, WARNING_LINE_Y+2*FH+2, split+2, lua_warning_info+LUA_WARNING_INFO_LEN-split, SMLSIZE);
}
else {
lcdDrawTextWithLen(WARNING_LINE_X, WARNING_LINE_Y+FH+3, lua_warning_info, 40, SMLSIZE);
}
}
}
void displayAcknowledgeLuaError(uint8_t event)
{
s_warning_result = false;
displayLuaError(s_warning);
if (event == EVT_KEY_BREAK(KEY_EXIT)) {
s_warning = NULL;
}
}
void luaError(uint8_t error, bool acknowledge)
{
const char * errorTitle;
switch (error) {
case SCRIPT_SYNTAX_ERROR:
errorTitle = STR_SCRIPT_SYNTAX_ERROR;
break;
case SCRIPT_KILLED:
errorTitle = STR_SCRIPT_KILLED;
break;
case SCRIPT_PANIC:
errorTitle = STR_SCRIPT_PANIC;
break;
default:
errorTitle = STR_SCRIPT_ERROR;
break;
}
const char * msg = lua_tostring(L, -1);
if (msg) {
#if defined(SIMU)
if (!strncmp(msg, ".", 2)) msg += 1;
#endif
if (!strncmp(msg, "/SCRIPTS/", 9)) msg += 9;
strncpy(lua_warning_info, msg, LUA_WARNING_INFO_LEN);
lua_warning_info[LUA_WARNING_INFO_LEN] = '\0';
}
else {
lua_warning_info[0] = '\0';
}
if (acknowledge) {
s_warning = errorTitle;
popupFunc = displayAcknowledgeLuaError;
}
else {
displayLuaError(errorTitle);
}
}
void luaExec(const char *filename)
{
luaInit();
if (luaState != INTERPRETER_PANIC) {
standaloneScript.state = SCRIPT_NOFILE;
int result = luaLoad(filename, standaloneScript);
// TODO the same with run ...
if (result == SCRIPT_OK) {
luaState = INTERPRETER_RUNNING_STANDALONE_SCRIPT;
}
else {
luaError(result);
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
}
}
void luaDoOneRunStandalone(uint8_t evt)
{
static uint8_t luaDisplayStatistics = false;
if (standaloneScript.state == SCRIPT_OK && standaloneScript.run) {
SET_LUA_INSTRUCTIONS_COUNT(MANUAL_SCRIPTS_MAX_INSTRUCTIONS);
lua_rawgeti(L, LUA_REGISTRYINDEX, standaloneScript.run);
lua_pushinteger(L, evt);
if (lua_pcall(L, 1, 1, 0) == 0) {
if (!lua_isnumber(L, -1)) {
if (instructionsPercent > 100) {
TRACE("Script killed");
standaloneScript.state = SCRIPT_KILLED;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
else if (lua_isstring(L, -1)) {
char nextScript[_MAX_LFN+1];
strncpy(nextScript, lua_tostring(L, -1), _MAX_LFN);
nextScript[_MAX_LFN] = '\0';
luaExec(nextScript);
}
else {
TRACE("Script run function returned unexpected value");
standaloneScript.state = SCRIPT_SYNTAX_ERROR;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
}
else {
int scriptResult = lua_tointeger(L, -1);
lua_pop(L, 1); /* pop returned value */
if (scriptResult != 0) {
TRACE("Script finished with status %d", scriptResult);
standaloneScript.state = SCRIPT_NOFILE;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
return;
}
else if (luaDisplayStatistics) {
lcd_hline(0, 7*FH-1, lcdLastPos+6, ERASE);
lcd_puts(0, 7*FH, "GV Use: ");
lcd_outdezAtt(lcdLastPos, 7*FH, luaGetMemUsed(), LEFT);
lcd_putc(lcdLastPos, 7*FH, 'b');
lcd_hline(0, 7*FH-2, lcdLastPos+6, FORCE);
lcdDrawVerticalLine(lcdLastPos+6, 7*FH-2, FH+2, SOLID, FORCE);
}
}
}
else {
TRACE("Script error: %s", lua_tostring(L, -1));
standaloneScript.state = (instructionsPercent > 100 ? SCRIPT_KILLED : SCRIPT_SYNTAX_ERROR);
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
if (standaloneScript.state != SCRIPT_OK) {
luaError(standaloneScript.state);
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
if (evt == EVT_KEY_LONG(KEY_EXIT)) {
TRACE("Script force exit");
killEvents(evt);
standaloneScript.state = SCRIPT_NOFILE;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
else if (evt == EVT_KEY_LONG(KEY_MENU)) {
killEvents(evt);
luaDisplayStatistics = !luaDisplayStatistics;
}
}
}
bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType)
{
ScriptInternalData & sid = scriptInternalData[i];
if (sid.state != SCRIPT_OK) return false;
SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS);
int inputsCount = 0;
#if defined(SIMU) || defined(DEBUG)
const char *filename;
#endif
ScriptInputsOutputs * sio = NULL;
#if SCRIPT_MIX_FIRST > 0
if ((scriptType & RUN_MIX_SCRIPT) && (sid.reference >= SCRIPT_MIX_FIRST && sid.reference <= SCRIPT_MIX_LAST)) {
#else
if ((scriptType & RUN_MIX_SCRIPT) && (sid.reference <= SCRIPT_MIX_LAST)) {
#endif
ScriptData & sd = g_model.scriptsData[sid.reference-SCRIPT_MIX_FIRST];
sio = &scriptInputsOutputs[sid.reference-SCRIPT_MIX_FIRST];
inputsCount = sio->inputsCount;
#if defined(SIMU) || defined(DEBUG)
filename = sd.file;
#endif
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
for (int j=0; j<sio->inputsCount; j++) {
if (sio->inputs[j].type == 1)
luaGetValueAndPush((uint8_t)sd.inputs[j]);
else
lua_pushinteger(L, sd.inputs[j] + sio->inputs[j].def);
}
}
else if ((scriptType & RUN_FUNC_SCRIPT) && (sid.reference >= SCRIPT_FUNC_FIRST && sid.reference <= SCRIPT_FUNC_LAST)) {
CustomFunctionData & fn = g_model.customFn[sid.reference-SCRIPT_FUNC_FIRST];
if (!getSwitch(fn.swtch)) return false;
#if defined(SIMU) || defined(DEBUG)
filename = fn.play.name;
#endif
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
}
else {
#if defined(SIMU) || defined(DEBUG)
TelemetryScriptData & script = g_model.frsky.screens[sid.reference-SCRIPT_TELEMETRY_FIRST].script;
filename = script.file;
#endif
if ((scriptType & RUN_TELEM_FG_SCRIPT) &&
#if defined(PCBFLAMENCO)
(g_menuStack[0]==menuMainView && sid.reference==SCRIPT_TELEMETRY_FIRST+g_eeGeneral.view-VIEW_TELEM1)) {
#else
(g_menuStack[0]==menuTelemetryFrsky && sid.reference==SCRIPT_TELEMETRY_FIRST+s_frsky_view)) {
#endif
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
lua_pushinteger(L, evt);
inputsCount = 1;
}
else if ((scriptType & RUN_TELEM_BG_SCRIPT) && (sid.background)) {
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.background);
}
else {
return false;
}
}
if (lua_pcall(L, inputsCount, sio ? sio->outputsCount : 0, 0) == 0) {
if (sio) {
for (int j=sio->outputsCount-1; j>=0; j--) {
if (!lua_isnumber(L, -1)) {
sid.state = (instructionsPercent > 100 ? SCRIPT_KILLED : SCRIPT_SYNTAX_ERROR);
TRACE("Script %8s disabled", filename);
break;
}
sio->outputs[j].value = lua_tointeger(L, -1);
lua_pop(L, 1);
}
}
}
else {
if (instructionsPercent > 100) {
TRACE("Script %8s killed", filename);
sid.state = SCRIPT_KILLED;
}
else {
TRACE("Script %8s error: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
}
if (sid.state != SCRIPT_OK) {
luaFree(sid);
}
else {
if (instructionsPercent > sid.instructions) {
sid.instructions = instructionsPercent;
}
}
return true;
}
void luaDoGc()
{
if (L) {
PROTECT_LUA() {
lua_gc(L, LUA_GCCOLLECT, 0);
#if defined(SIMU) || defined(DEBUG)
static int lastgc = 0;
int gc = luaGetMemUsed();
if (gc != lastgc) {
lastgc = gc;
TRACE("GC Use: %dbytes", gc);
}
#endif
}
else {
// we disable Lua for the rest of the session
luaDisable();
}
UNPROTECT_LUA();
}
}
bool luaTask(uint8_t evt, uint8_t scriptType, bool allowLcdUsage)
{
if (luaState == INTERPRETER_PANIC) return false;
luaLcdAllowed = allowLcdUsage;
bool scriptWasRun = false;
// we run either standalone script or permanent scripts
if (luaState & INTERPRETER_RUNNING_STANDALONE_SCRIPT) {
// run standalone script
if ((scriptType & RUN_STNDAL_SCRIPT) == 0) return false;
PROTECT_LUA() {
luaDoOneRunStandalone(evt);
scriptWasRun = true;
}
else {
luaDisable();
return false;
}
UNPROTECT_LUA();
}
else {
// run permanent scripts
if (luaState & INTERPRETER_RELOAD_PERMANENT_SCRIPTS) {
luaState = 0;
luaInit();
if (luaState == INTERPRETER_PANIC) return false;
luaLoadPermanentScripts();
if (luaState == INTERPRETER_PANIC) return false;
}
for (int i=0; i<luaScriptsCount; i++) {
PROTECT_LUA() {
scriptWasRun |= luaDoOneRunPermanentScript(evt, i, scriptType);
}
else {
luaDisable();
break;
}
UNPROTECT_LUA();
//todo gc step between scripts
}
}
luaDoGc();
return scriptWasRun;
}
int luaGetMemUsed()
{
return (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0);
}
+42 -17
View File
@@ -34,18 +34,42 @@
*
*/
#ifndef luaapi_h
#define luaapi_h
#define RUN_MIX_SCRIPT (1 << 0)
#define RUN_FUNC_SCRIPT (1 << 1)
#define RUN_TELEM_BG_SCRIPT (1 << 2)
#define RUN_TELEM_FG_SCRIPT (1 << 3)
#define RUN_STNDAL_SCRIPT (1 << 4)
#ifndef lua_api_h
#define lua_api_h
#if defined(LUA)
#if !defined(SIMU)
extern "C" {
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <lrotable.h>
#if !defined(SIMU)
}
#endif
extern lua_State *L;
extern bool luaLcdAllowed;
#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) (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))
#define RUN_MIX_SCRIPT (1 << 0)
#define RUN_FUNC_SCRIPT (1 << 1)
#define RUN_TELEM_BG_SCRIPT (1 << 2)
#define RUN_TELEM_FG_SCRIPT (1 << 3)
#define RUN_STNDAL_SCRIPT (1 << 4)
struct ScriptInput {
const char *name;
uint8_t type;
@@ -98,11 +122,11 @@
void luaExec(const char * filename);
void luaError(uint8_t error, bool acknowledge=true);
int luaGetMemUsed();
void luaGetValueAndPush(int src);
#define luaGetCpuUsed(idx) scriptInternalData[idx].instructions
uint8_t isTelemetryScriptAvailable(uint8_t index);
#define LUA_LOAD_MODEL_SCRIPTS() luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS
#define LUA_LOAD_MODEL_SCRIPT(idx) luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS
#define LUA_STANDALONE_SCRIPT_RUNNING() (luaState == INTERPRETER_RUNNING_STANDALONE_SCRIPT)
// Lua PROTECT/UNPROTECT
#include <setjmp.h>
struct our_longjmp {
@@ -119,10 +143,11 @@
extern uint16_t maxLuaInterval;
extern uint16_t maxLuaDuration;
#else // #if defined(LUA)
#define LUA_LOAD_MODEL_SCRIPTS()
#define LUA_LOAD_MODEL_SCRIPT(idx)
#define LUA_STANDALONE_SCRIPT_RUNNING() (0)
#endif
#endif // #ifndef luaapi_h
#else // #if defined(LUA)
#define LUA_LOAD_MODEL_SCRIPTS()
#endif // #if defined(LUA)
#endif // #ifndef lua_api_h
File diff suppressed because it is too large Load Diff
+27 -19
View File
@@ -43,6 +43,9 @@ void perMain()
{
#if defined(SIMU)
doMixerCalculations();
#endif
#if defined(LCD_ST7920)
uint8_t lcdstate=0;
#endif
uint16_t t0 = getTmr16KHz();
int16_t delta = (nextMixerEndTime - lastMixerDuration) - t0;
@@ -129,32 +132,37 @@ void perMain()
const char *warn = s_warning;
uint8_t menu = s_menu_count;
lcdClear();
if (menuEvent) {
m_posVert = menuEvent == EVT_ENTRY_UP ? g_menuPos[g_menuStackPtr] : 0;
m_posHorz = 0;
evt = menuEvent;
menuEvent = 0;
AUDIO_MENUS();
}
g_menuStack[g_menuStackPtr]((warn || menu) ? 0 : evt);
if (IS_LCD_REFRESH_ALLOWED()) { // No need to redraw until lcdRefresh_ST7920(0) below completely refreshes the display.
lcdClear();
if (menuEvent) {
m_posVert = menuEvent == EVT_ENTRY_UP ? g_menuPos[g_menuStackPtr] : 0;
m_posHorz = 0;
evt = menuEvent;
menuEvent = 0;
AUDIO_MENUS();
}
g_menuStack[g_menuStackPtr]((warn || menu) ? 0 : evt);
if (warn) DISPLAY_WARNING(evt);
if (warn) DISPLAY_WARNING(evt);
#if defined(NAVIGATION_MENUS)
if (menu) {
const char * result = displayMenu(evt);
if (result) {
menuHandler(result);
if (menu) {
const char * result = displayMenu(evt);
if (result) {
menuHandler(result);
}
}
}
#endif
drawStatusLine();
drawStatusLine();
}
#if defined(LCD_ST7920)
lcdstate = lcdRefresh_ST7920(0);
#else
lcdRefresh();
#endif
#endif // defined(GUI)
if (SLAVE_MODE()) {
JACK_PPM_OUT();
}
+2 -1
View File
@@ -179,6 +179,7 @@ int16_t applyLimits(uint8_t channel, int32_t value)
}
#endif
int16_t ofs = LIMIT_OFS_RESX(lim);
int16_t lim_p = LIMIT_MAX_RESX(lim);
int16_t lim_n = LIMIT_MIN_RESX(lim);
@@ -1107,7 +1108,7 @@ void evalMixes(uint8_t tick10ms)
}
}
#if defined(PCBGRUVIN9X) && defined(DEBUG) && !defined(VOICE)
#if defined(CPU2560) && defined(DEBUG) && !defined(VOICE)
PORTH &= ~0x40; // PORTH:6 HIGH->LOW signals end of mixer interrupt
#endif
}
+7 -9
View File
@@ -560,7 +560,7 @@ enum PotsWarnMode {
TRAINER_MODULE
};
enum TrainerMode {
TRAINER_MODE_MASTER,
TRAINER_MODE_MASTER_TRAINER_JACK,
TRAINER_MODE_SLAVE,
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
@@ -1426,10 +1426,12 @@ PACK(typedef struct {
};
void init(const char *label, uint8_t unit=UNIT_RAW, uint8_t prec=0);
void init(uint16_t id);
bool isAvailable();
bool isAvailable() const;
int32_t getValue(int32_t value, uint8_t unit, uint8_t prec) const;
bool isConfigurable();
bool isPrecConfigurable();
bool isConfigurable() const;
bool isPrecConfigurable() const;
int32_t getPrecMultiplier() const;
int32_t getPrecDivisor() const;
}) TelemetrySensor;
#endif
@@ -2201,11 +2203,7 @@ enum RFProtocols {
#endif
};
#if defined(MODULE_D16_EU_ONLY_SUPPORT)
#define HAS_RF_PROTOCOL_FAILSAFE(protocol) ((protocol) == RF_PROTO_X16)
#else
#define HAS_RF_PROTOCOL_FAILSAFE(protocol) ((protocol) == RF_PROTO_X16 || (protocol) == RF_PROTO_LR12)
#endif
#define HAS_RF_PROTOCOL_FAILSAFE(protocol) ((protocol) == RF_PROTO_X16)
enum DSM2Protocols {
DSM2_PROTO_LP45,
+4 -4
View File
@@ -1173,10 +1173,10 @@ extern const char vers_stamp[];
#endif
extern uint8_t g_vbat100mV;
#if defined(CPUARM)
#define GET_TXBATT_BARS() (min(10, 10 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin)))
#if defined(PCBTARANIS)
#define GET_TXBATT_BARS() (limit<int8_t>(0, 10 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 10))
#else
#define GET_TXBATT_BARS() (limit<uint8_t>(2, 20 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 20))
#define GET_TXBATT_BARS() (limit<int8_t>(2, 20 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 20))
#endif
#define IS_TXBATT_WARNING() (g_vbat100mV <= g_eeGeneral.vBatWarn)
@@ -1783,7 +1783,7 @@ void varioWakeup();
extern void usbPluggedIn();
#endif
#include "lua_api.h"
#include "lua/lua_api.h"
#if defined(SDCARD)
enum ClipboardType {
+5 -7
View File
@@ -231,8 +231,7 @@ void setupPulsesPXX(unsigned int port)
}
else {
if (i < sendUpperChannels) {
int channel = 8 + g_model.moduleData[port].channelsStart + i;
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[channel];
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[8+i];
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
pulseValue = 4095;
}
@@ -240,13 +239,12 @@ void setupPulsesPXX(unsigned int port)
pulseValue = 2048;
}
else {
failsafeValue += 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
failsafeValue += 2*PPM_CH_CENTER(8+g_model.moduleData[port].channelsStart+i) - 2*PPM_CENTER;
pulseValue = limit(2049, (failsafeValue * 512 / 682) + 3072, 4094);
}
}
else {
int channel = g_model.moduleData[port].channelsStart + i;
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[channel];
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[i];
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
pulseValue = 2047;
}
@@ -254,7 +252,7 @@ void setupPulsesPXX(unsigned int port)
pulseValue = 0;
}
else {
failsafeValue += 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
failsafeValue += 2*PPM_CH_CENTER(g_model.moduleData[port].channelsStart+i) - 2*PPM_CENTER;
pulseValue = limit(1, (failsafeValue * 512 / 682) + 1024, 2046);
}
}
@@ -289,7 +287,7 @@ void setupPulsesPXX(unsigned int port)
/* CRC16 */
putPcmByte(0, port);
pulseValue = modulePulsesData[port].pxx.pcmCrc;
putPcmByte(pulseValue>>8, port);
putPcmByte(pulseValue >> 8, port);
putPcmByte(pulseValue, port);
/* Sync */
+1 -5
View File
@@ -60,11 +60,7 @@ const char * sdCheckAndCreateDirectory(const char * path)
bool isFileAvailable(const char * path)
{
FILINFO info;
TCHAR lfn[_MAX_LFN + 1];
info.lfname = lfn;
info.lfsize = sizeof(lfn);
return f_stat(path, &info) == FR_OK;
return f_stat(path, 0) == FR_OK;
}
bool isFileAvailable(const char * filename, const char * directory)
+12 -9
View File
@@ -611,22 +611,25 @@ const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name)
eepromEraseBlock(address+EEPROM_BLOCK_SIZE);
// write header
EepromFileHeader header = { uint16_t(i_fileDst+1), size };
eepromWrite(address, (uint8_t *)&header, sizeof(header));
address += sizeof(header);
EepromFileHeader * header = (EepromFileHeader *)eepromWriteBuffer;
header->fileIndex = i_fileDst+1;
header->size = size;
int offset = 4;
// write model
while (size > 0) {
uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE);
result = f_read(&restoreFile, eepromWriteBuffer, blockSize, &read);
do {
uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE-offset);
result = f_read(&restoreFile, eepromWriteBuffer+offset, blockSize, &read);
if (result != FR_OK || read != blockSize) {
f_close(&g_oLogFile);
return SDCARD_ERROR(result);
}
eepromWrite(address, eepromWriteBuffer, blockSize);
eepromWrite(address, eepromWriteBuffer, blockSize+offset);
size -= blockSize;
address += blockSize;
}
address += EEPROM_BUFFER_SIZE;
offset = 0;
} while (size > 0);
// write FAT
eepromHeader.files[i_fileDst+1].exists = 1;
+70 -10
View File
@@ -150,17 +150,65 @@ void lcdSetRefVolt(uint8_t val)
#endif
}
#if defined(LCD_ST7920)
void lcdRefresh(){
lcdRefresh_ST7920(1);
}
uint8_t lcdRefresh_ST7920(uint8_t full)
{
#else
void lcdRefresh()
{
#endif
LCD_LOCK();
#if defined(LCD_ST7920)
static uint8_t state;
uint8_t yst,yend;
uint8_t x_addr = 0;
uint8_t y_addr = 0;
uint16_t line_offset = 0;
uint8_t col_offset = 0;
uint16_t byte_offset = 0;
uint8_t bit_count = 0;
for (uint8_t y=0; y<64; y++) {
uint8_t result;
uint8_t *p;
if(full!=0){
yst=0;
yend=64;
state=0;
}
else{
switch (state){//Since writing to ST7920 is too slow we need to split it to five bands.
default:
case 0:
yst=0;
yend=13;
state=1;
break;
case 1:
yst=13;
yend=26;
state=2;
break;
case 2:
yst=26;
yend=39;
state=3;
break;
case 3:
yst=39;
yend=52;
state=4;
break;
case 4:
yst=52;
yend=64;
state=0;
break;
}
}
for (uint8_t y=yst; y<yend; y++) {
x_addr = 0;
//Convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays)
if (y > 31) {
@@ -170,20 +218,28 @@ void lcdRefresh()
else {
y_addr = y;
}
lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address
lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address
_delay_us(49);
lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address
lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address
_delay_us(49);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); //HIGH RS and LOW RW will put the LCD to
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); //Write data register mode
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); //HIGH RS and LOW RW will put the LCD to
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); //Write data register mode
bit_count = y & 0x07; //Count from 0 bis 7 -> 0=0, 1=1..7=7, 8=0, 9=1...
col_offset = 1 << bit_count; //Build a value for a AND operation with the vorrect bitposition
line_offset = ( y / 8 ) * 128; //On the ST7565 there are 8 lines with each 128 bytes width
for (coord_t x=0; x<16; x++) { //Walk through 16 bytes form left to right (128 Pixel)
byte_offset = line_offset + ( x * 8 ); //Calculate the position of the first byte im array
// adressing the bytes sequential and shift the bits at the correct position, afterwards a OR operation to get all bits in one byte
// the position of the LSB is the left-most position of the byte to the ST7920
PORTA_LCD_DAT = (((displayBuf[byte_offset] & col_offset) >> bit_count) << 7) | (((displayBuf[byte_offset + 1] & col_offset) >> bit_count) << 6) | (((displayBuf[byte_offset + 2] & col_offset) >> bit_count ) << 5) | (((displayBuf[byte_offset + 3] & col_offset) >> bit_count ) << 4) | (((displayBuf[byte_offset + 4] & col_offset) >> bit_count ) << 3) | (((displayBuf[byte_offset + 5] & col_offset) >> bit_count ) << 2) | (((displayBuf[byte_offset + 6] & col_offset) >> bit_count ) << 1) | (((displayBuf[byte_offset + 7] & col_offset) >> bit_count ) << 0);
p=displayBuf + line_offset + ( x * 8 ); //Calculate the position of the first byte im array
// adressing the bytes sequential and set the bits at the correct position merging them with an OR operation to get all bits in one byte
// the position of the LSB is the right-most position of the byte to the ST7920
result = ((*p++ & col_offset)!=0?0x80:0);
result|= ((*p++ & col_offset)!=0?0x40:0);
result|= ((*p++ & col_offset)!=0?0x20:0);
result|= ((*p++ & col_offset)!=0?0x10:0);
result|= ((*p++ & col_offset)!=0?0x08:0);
result|= ((*p++ & col_offset)!=0?0x04:0);
result|= ((*p++ & col_offset) !=0?0x02:0);
result|= ((*p++ & col_offset)!=0?0x01:0);
PORTA_LCD_DAT = result;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
_delay_us(8);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
@@ -216,4 +272,8 @@ void lcdRefresh()
}
#endif
LCD_UNLOCK();
#if defined(LCD_ST7920)
return state;
#endif
}
@@ -0,0 +1,120 @@
/**
******************************************************************************
* @file usbd_desc.h
* @author MCD Application Team
* @version V1.1.0
* @date 19-March-2012
* @brief header file for the usbd_desc.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USB_DESC_H
#define __USB_DESC_H
/* Includes ------------------------------------------------------------------*/
#include "STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_def.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USB_DESC
* @brief general defines for the usb device library file
* @{
*/
/** @defgroup USB_DESC_Exported_Defines
* @{
*/
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
#define USB_SIZ_DEVICE_DESC 18
#define USB_SIZ_STRING_LANGID 4
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Variables
* @{
*/
extern const uint8_t USBD_DeviceDesc [USB_SIZ_DEVICE_DESC];
extern uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ];
extern const uint8_t USBD_OtherSpeedCfgDesc[USB_LEN_CFG_DESC];
extern const uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC];
extern const uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID];
extern const USBD_DEVICE USR_desc;
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_FunctionsPrototype
* @{
*/
uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ManufacturerStrDescriptor ( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ProductStrDescriptor ( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length);
#ifdef USB_SUPPORT_USER_STRING_DESC
uint8_t * USBD_USR_USRStringDesc (uint8_t speed, uint8_t idx , uint16_t *length);
#endif /* USB_SUPPORT_USER_STRING_DESC */
/**
* @}
*/
#endif /* __USBD_DESC_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+1 -2
View File
@@ -4,6 +4,5 @@ MEGA2560 board
DIY radio wih :
- Arduino MEGA2560 or compatible
- Gruvin9x features (soft-off, SD-Card, RTC, haptic, voice, rotary encoders)
- LCD 128x64 Artronic (ST7565R) or Zolen (ST7565P)
- Aurora9 or T9X gimballs
- LCD 128x64 8 bits parallel mode
- home made case
@@ -42,13 +42,17 @@ inline void boardInit()
{
// Set up I/O port data directions and initial states (unused pin setting : input, pull-up on)
DDRA = 0b11111111; PORTA = 0b00000000; // LCD data
DDRB = 0b01110111; PORTB = 0b00101111; // 7:PPM_IN 6:PPM_OUT, 5:SimCTRL, 4:Buzzer, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS]
DDRB = 0b01110111; PORTB = 0b10101111; // 7:N/A 6:PPM_OUT, 5:SimCTRL, 4:Buzzer, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS]
DDRC = 0b11111100; PORTC = 0b00000011; // 7-3:LCD, 2:BackLight, 1:ID2_SW, 0:ID1_SW
DDRD = 0b00000000; PORTD = 0b11111100; // 7:AilDR_SW, 6:N/A, 5:N/A, 4:N/A, 3:RENC2_B, 2:RENC2_A, 1:I2C_SDA, 0:I2C_SCL
DDRE = 0b00000010; PORTE = 0b11111100; // 7:N/A, 6:N/A, 5:RENC1_B, 4:RENC1_A, 3:N/A, 2:N/A, 1:TELEM_TX, 0:TELEM_RX
DDRE = 0b00000010; PORTE = 0b01111100; // 7:PPM_IN, 6:N/A, 5:RENC1_B, 4:RENC1_A, 3:N/A, 2:N/A, 1:TELEM_TX, 0:TELEM_RX
DDRF = 0b00000000; PORTF = 0b11111111; // 7-0:Trim switch inputs
DDRG = 0b00000000; PORTG = 0b11111111; // 7:N/A, 6:N/A, 5:N/A, 4:N/A, 3:N/A, 2:TCut_SW, 1:Gear_SW, 0: RudDr_SW
#if defined(PCBMEGA2560) && defined(DEBUG)
DDRH = 0b01011000; PORTH = 0b11110110; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:N/A, 0:Haptic
#else
DDRH = 0b00011000; PORTH = 0b11110110; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:N/A, 0:Haptic
#endif
DDRJ = 0b00000000; PORTJ = 0b11111111; // 7:N/A, 6:N/A, 5:N/A, 4:N/A, 3:N/A, 2:N/A, 1:RENC2_push, 0:RENC1_push
DDRK = 0b00000000; PORTK = 0b00000000; // Analogic input (no pull-ups)
DDRL = 0b00000000; PORTL = 0b11111111; // 7:TRN_SW 6:EleDR_SW, 5:ESC, 4:MENU 3:Keyb_Left, 2:Keyb_Right, 1:Keyb_Up, 0:Keyb_Down
+1 -1
View File
@@ -111,7 +111,7 @@ void sdPoll10ms(void);
# define INP_L_Trainer 7
// Servitudes driver
# define INP_B_PPM_IN 7
//#define INP_E_PPM_IN 7 //reserved PPM_IN
# define OUT_B_PPM 6
# define OUT_B_SIM_CTL 5
# define OUT_B_BUZZER 4
+114 -117
View File
@@ -51,7 +51,7 @@
// LCD_D6 PC2
// LCD_D7 PC1
#define LCD_DATA 0x000000FFL
#define LCD_DATA 0x000000FFL
#if !defined(REVA)
#define LCD_A0 0x00000080L
#else
@@ -66,111 +66,105 @@
#if defined(REVA)
const uint8_t Lcd_lookup[] =
{
0x00,0x01,0x80,0x81,0x40,0x41,0xC0,0xC1,0x20,0x21,0xA0,0xA1,0x60,0x61,0xE0,0xE1,
0x10,0x11,0x90,0x91,0x50,0x51,0xD0,0xD1,0x30,0x31,0xB0,0xB1,0x70,0x71,0xF0,0xF1,
0x08,0x09,0x88,0x89,0x48,0x49,0xC8,0xC9,0x28,0x29,0xA8,0xA9,0x68,0x69,0xE8,0xE9,
0x18,0x19,0x98,0x99,0x58,0x59,0xD8,0xD9,0x38,0x39,0xB8,0xB9,0x78,0x79,0xF8,0xF9,
0x04,0x05,0x84,0x85,0x44,0x45,0xC4,0xC5,0x24,0x25,0xA4,0xA5,0x64,0x65,0xE4,0xE5,
0x14,0x15,0x94,0x95,0x54,0x55,0xD4,0xD5,0x34,0x35,0xB4,0xB5,0x74,0x75,0xF4,0xF5,
0x0C,0x0D,0x8C,0x8D,0x4C,0x4D,0xCC,0xCD,0x2C,0x2D,0xAC,0xAD,0x6C,0x6D,0xEC,0xED,
0x1C,0x1D,0x9C,0x9D,0x5C,0x5D,0xDC,0xDD,0x3C,0x3D,0xBC,0xBD,0x7C,0x7D,0xFC,0xFD,
0x02,0x03,0x82,0x83,0x42,0x43,0xC2,0xC3,0x22,0x23,0xA2,0xA3,0x62,0x63,0xE2,0xE3,
0x12,0x13,0x92,0x93,0x52,0x53,0xD2,0xD3,0x32,0x33,0xB2,0xB3,0x72,0x73,0xF2,0xF3,
0x0A,0x0B,0x8A,0x8B,0x4A,0x4B,0xCA,0xCB,0x2A,0x2B,0xAA,0xAB,0x6A,0x6B,0xEA,0xEB,
0x1A,0x1B,0x9A,0x9B,0x5A,0x5B,0xDA,0xDB,0x3A,0x3B,0xBA,0xBB,0x7A,0x7B,0xFA,0xFB,
0x06,0x07,0x86,0x87,0x46,0x47,0xC6,0xC7,0x26,0x27,0xA6,0xA7,0x66,0x67,0xE6,0xE7,
0x16,0x17,0x96,0x97,0x56,0x57,0xD6,0xD7,0x36,0x37,0xB6,0xB7,0x76,0x77,0xF6,0xF7,
0x0E,0x0F,0x8E,0x8F,0x4E,0x4F,0xCE,0xCF,0x2E,0x2F,0xAE,0xAF,0x6E,0x6F,0xEE,0xEF,
0x1E,0x1F,0x9E,0x9F,0x5E,0x5F,0xDE,0xDF,0x3E,0x3F,0xBE,0xBF,0x7E,0x7F,0xFE,0xFF
} ;
0x00,0x01,0x80,0x81,0x40,0x41,0xC0,0xC1,0x20,0x21,0xA0,0xA1,0x60,0x61,0xE0,0xE1,
0x10,0x11,0x90,0x91,0x50,0x51,0xD0,0xD1,0x30,0x31,0xB0,0xB1,0x70,0x71,0xF0,0xF1,
0x08,0x09,0x88,0x89,0x48,0x49,0xC8,0xC9,0x28,0x29,0xA8,0xA9,0x68,0x69,0xE8,0xE9,
0x18,0x19,0x98,0x99,0x58,0x59,0xD8,0xD9,0x38,0x39,0xB8,0xB9,0x78,0x79,0xF8,0xF9,
0x04,0x05,0x84,0x85,0x44,0x45,0xC4,0xC5,0x24,0x25,0xA4,0xA5,0x64,0x65,0xE4,0xE5,
0x14,0x15,0x94,0x95,0x54,0x55,0xD4,0xD5,0x34,0x35,0xB4,0xB5,0x74,0x75,0xF4,0xF5,
0x0C,0x0D,0x8C,0x8D,0x4C,0x4D,0xCC,0xCD,0x2C,0x2D,0xAC,0xAD,0x6C,0x6D,0xEC,0xED,
0x1C,0x1D,0x9C,0x9D,0x5C,0x5D,0xDC,0xDD,0x3C,0x3D,0xBC,0xBD,0x7C,0x7D,0xFC,0xFD,
0x02,0x03,0x82,0x83,0x42,0x43,0xC2,0xC3,0x22,0x23,0xA2,0xA3,0x62,0x63,0xE2,0xE3,
0x12,0x13,0x92,0x93,0x52,0x53,0xD2,0xD3,0x32,0x33,0xB2,0xB3,0x72,0x73,0xF2,0xF3,
0x0A,0x0B,0x8A,0x8B,0x4A,0x4B,0xCA,0xCB,0x2A,0x2B,0xAA,0xAB,0x6A,0x6B,0xEA,0xEB,
0x1A,0x1B,0x9A,0x9B,0x5A,0x5B,0xDA,0xDB,0x3A,0x3B,0xBA,0xBB,0x7A,0x7B,0xFA,0xFB,
0x06,0x07,0x86,0x87,0x46,0x47,0xC6,0xC7,0x26,0x27,0xA6,0xA7,0x66,0x67,0xE6,0xE7,
0x16,0x17,0x96,0x97,0x56,0x57,0xD6,0xD7,0x36,0x37,0xB6,0xB7,0x76,0x77,0xF6,0xF7,
0x0E,0x0F,0x8E,0x8F,0x4E,0x4F,0xCE,0xCF,0x2E,0x2F,0xAE,0xAF,0x6E,0x6F,0xEE,0xEF,
0x1E,0x1F,0x9E,0x9F,0x5E,0x5F,0xDE,0xDF,0x3E,0x3F,0xBE,0xBF,0x7E,0x7F,0xFE,0xFF
};
#endif
void lcdSendCtl(uint8_t val)
{
register Pio *pioptr ;
register Pio *pioptr;
#if defined(REVA)
pioptr = PIOC ;
pioptr->PIO_CODR = LCD_CS1 ; // Select LCD
pioptr->PIO_CODR = LCD_A0 ; // Control
pioptr->PIO_CODR = LCD_RnW ; // Write
pioptr->PIO_ODSR = Lcd_lookup[val] ;
pioptr = PIOC;
pioptr->PIO_CODR = LCD_CS1; // Select LCD
pioptr->PIO_CODR = LCD_A0; // Control
pioptr->PIO_CODR = LCD_RnW; // Write
pioptr->PIO_ODSR = Lcd_lookup[val];
#else
pioptr = PIOC ;
pioptr = PIOC;
#if !defined(REVX)
pioptr->PIO_CODR = LCD_CS1 ; // Select LCD
pioptr->PIO_CODR = LCD_CS1; // Select LCD
#endif
PIOA->PIO_CODR = LCD_A0 ;
PIOA->PIO_CODR = LCD_A0;
#if !defined(REVX)
pioptr->PIO_CODR = LCD_RnW ; // Write
pioptr->PIO_CODR = LCD_RnW; // Write
#endif
pioptr->PIO_ODSR = val ;
pioptr->PIO_ODSR = val;
#endif
pioptr->PIO_SODR = LCD_E ; // Start E pulse
pioptr->PIO_SODR = LCD_E; // Start E pulse
// Need a delay here (250nS)
TC0->TC_CHANNEL[0].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
TC0->TC_CHANNEL[0].TC_CCR = 5; // Enable clock and trigger it (may only need trigger)
while ( TC0->TC_CHANNEL[0].TC_CV < 9 ) // Value depends on MCK/2 (used 18MHz)
{
// Wait
}
pioptr->PIO_CODR = LCD_E ; // End E pulse
pioptr->PIO_CODR = LCD_E; // End E pulse
#if defined(REVA)
pioptr->PIO_SODR = LCD_A0 ; // Data
pioptr->PIO_SODR = LCD_A0; // Data
#else
PIOA->PIO_SODR = LCD_A0 ; // Data
PIOA->PIO_SODR = LCD_A0; // Data
#endif
#if !defined(REVX)
pioptr->PIO_SODR = LCD_CS1 ; // Deselect LCD
pioptr->PIO_SODR = LCD_CS1; // Deselect LCD
#endif
}
void lcdInit()
{
register Pio *pioptr ;
register Pio *pioptr;
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
// read the inputs, and lock the LCD lines
lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP ()
lcdLock = 1 ;
lcdLock = 1;
#if defined(REVA)
pioptr = PIOC ;
pioptr->PIO_PER = 0x0C00B0FFL ; // Enable bits 27,26,15,13,12,7-0
pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_A0 ;
pioptr->PIO_SODR = LCD_RES | LCD_CS1 ;
pioptr->PIO_OER = 0x0C00B0FFL ; // Set bits 27,26,15,13,12,7-0 output
pioptr->PIO_OWER = 0x000000FFL ; // Allow write to ls 8 bits in ODSR
pioptr = PIOC;
pioptr->PIO_PER = 0x0C00B0FFL; // Enable bits 27,26,15,13,12,7-0
pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_A0;
pioptr->PIO_SODR = LCD_RES | LCD_CS1;
pioptr->PIO_OER = 0x0C00B0FFL; // Set bits 27,26,15,13,12,7-0 output
pioptr->PIO_OWER = 0x000000FFL; // Allow write to ls 8 bits in ODSR
#else
configure_pins( LCD_A0, PIN_ENABLE | PIN_LOW | PIN_OUTPUT | PIN_PORTA | PIN_NO_PULLUP ) ;
pioptr = PIOC ;
#if defined(REVX)
pioptr->PIO_PER = PIO_PC27 | PIO_PC12 | 0xFF ;
pioptr->PIO_CODR = LCD_E ;
pioptr->PIO_CODR = LCD_RnW | LCD_CS1 ; // No longer needed, used elsewhere
#else
pioptr->PIO_PER = PIO_PC27 | PIO_PC26 | PIO_PC13 | PIO_PC12 | 0xFF ;
pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_CS1 ;
#endif
pioptr->PIO_SODR = LCD_RES ;
pioptr->PIO_OER = PIO_PC27 | PIO_PC26 | PIO_PC13 | PIO_PC12 | 0xFF ; // Set bits 27,26,13,12,7-0 output
pioptr->PIO_OWER = 0x000000FFL ; // Allow write to ls 8 bits in ODSR
configure_pins( LCD_A0, PIN_ENABLE | PIN_LOW | PIN_OUTPUT | PIN_PORTA | PIN_NO_PULLUP );
pioptr = PIOC;
#if defined(REVX)
pioptr->PIO_PER = PIO_PC27 | PIO_PC12 | 0xFF;
pioptr->PIO_CODR = LCD_E;
pioptr->PIO_CODR = LCD_RnW | LCD_CS1; // No longer needed, used elsewhere
#else
pioptr->PIO_PER = PIO_PC27 | PIO_PC26 | PIO_PC13 | PIO_PC12 | 0xFF;
pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_CS1;
#endif
pioptr->PIO_SODR = LCD_RES;
pioptr->PIO_OER = PIO_PC27 | PIO_PC26 | PIO_PC13 | PIO_PC12 | 0xFF; // Set bits 27,26,13,12,7-0 output
pioptr->PIO_OWER = 0x000000FFL; // Allow write to ls 8 bits in ODSR
#endif
pioptr->PIO_CODR = LCD_RES ; // Reset LCD
TC0->TC_CHANNEL[0].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
while ( TC0->TC_CHANNEL[0].TC_CV < 200 ) // > 10us, Value depends on MCK/2 (used 18MHz)
{
// Wait
}
pioptr->PIO_SODR = LCD_RES ; // Remove LCD reset
TC0->TC_CHANNEL[0].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
while ( TC0->TC_CHANNEL[0].TC_CV < 27000 ) // 1500us, Value depends on MCK/2 (used 18MHz)
{
// Wait
}
TC0->TC_CHANNEL[0].TC_CCR = 5; // Enable clock and trigger it (may only need trigger)
pioptr->PIO_CODR = LCD_RES; // Reset LCD
while ( TC0->TC_CHANNEL[0].TC_CV < 500 ) ; // > 10us, Value depends on MCK/2 (used 18MHz)
TC0->TC_CHANNEL[0].TC_CCR = 5; // Enable clock and trigger it (may only need trigger)
pioptr->PIO_SODR = LCD_RES; // Remove LCD reset
while ( TC0->TC_CHANNEL[0].TC_CV < 27000 ) ; // 1500us, Value depends on MCK/2 (used 18MHz)
lcdSendCtl(0xe2); //Initialize the internal functions
lcdSendCtl(0xae); //DON = 0: display OFF
lcdSendCtl(0xa1); //ADC = 1: reverse direction(SEG132->SEG1)
@@ -182,50 +176,63 @@ void lcdInit()
lcdSendCtl(0x25); //Select int resistance ratio R2 R1 R0 =5
lcdSendCtl(0x81); //Set reference voltage Mode
lcdSendCtl(0x22); // 24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
lcdSendCtl(0xAF); //DON = 1: display ON
// g_eeGeneral.contrast = 0x22;
#if defined(REVA)
pioptr->PIO_ODR = 0x0000003CL ; // Set bits 2, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003CL ; // Set bits 2, 3, 4, 5 with pullups
pioptr->PIO_ODSR = 0 ; // Drive D0 low
#else
pioptr->PIO_ODR = 0x0000003AL ; // Set bits 1, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003AL ; // Set bits 1, 3, 4, 5 with pullups
pioptr->PIO_ODSR = 0 ; // Drive D0 low
#if defined(REVX)
// 200mS delay (only if not wdt reset)
if ( ( ( ResetReason & RSTC_SR_RSTTYP ) != (2 << 8) ) && !unexpectedShutdown ) {
for (uint32_t j = 0; j < 100; j += 1 ) {
TC0->TC_CHANNEL[0].TC_CCR = 5; // Enable clock and trigger it (may only need trigger)
while ( TC0->TC_CHANNEL[0].TC_CV < 36000 ) {
// Value depends on MCK/2 (used 18MHz) give 2mS delay
wdt_reset(); // Wait
}
}
}
#endif
lcdLock = 0 ;
lcdSendCtl(0xAF); // DON = 1: display ON
#if defined(REVA)
pioptr->PIO_ODR = 0x0000003CL; // Set bits 2, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003CL; // Set bits 2, 3, 4, 5 with pullups
pioptr->PIO_ODSR = 0; // Drive D0 low
#else
pioptr->PIO_ODR = 0x0000003AL; // Set bits 1, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003AL; // Set bits 1, 3, 4, 5 with pullups
pioptr->PIO_ODSR = 0; // Drive D0 low
#endif
lcdLock = 0;
}
void lcdSetRefVolt(uint8_t val)
{
register Pio *pioptr ;
pioptr = PIOC ;
register Pio *pioptr;
pioptr = PIOC;
// read the inputs, and lock the LCD lines
lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP ()
lcdLock = 1 ;
lcdLock = 1;
pioptr->PIO_OER = 0x0C00B0FFL ; // Set bits 27,26,15,13,12,7-0 output
pioptr->PIO_OER = 0x0C00B0FFL; // Set bits 27,26,15,13,12,7-0 output
lcdSendCtl(0x81);
if ( val == 0 )
{
val = 0x22 ;
val = 0x22;
}
lcdSendCtl(val);
#if defined(REVA)
pioptr->PIO_ODR = 0x0000003CL ; // Set bits 2, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003CL ; // Set bits 2, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x000000FEL; // Set bits 2, 3, 4, 5 input
pioptr->PIO_PUER = 0x000000FEL; // Set bits 2, 3, 4, 5 with pullups
#else
pioptr->PIO_ODR = 0x0000003AL ; // Set bits 1, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003AL ; // Set bits 1, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x000000FEL; // Set bits 1, 3, 4, 5 input
pioptr->PIO_PUER = 0x000000FEL; // Set bits 1, 3, 4, 5 with pullups
#endif
pioptr->PIO_ODSR = lcdInputs; // Drive D0 low
lcdLock = 0 ;
pioptr->PIO_ODSR = 0; // Drive D0 low
lcdLock = 0;
}
void lcdRefresh()
@@ -251,7 +258,7 @@ void lcdRefresh()
// read the inputs, and lock the LCD lines
lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP ()
lcdLock = 1 ;
lcdLock = 1;
pioptr = PIOC;
#if defined(REVA)
@@ -264,13 +271,13 @@ void lcdRefresh()
lcdSendCtl(0x10); //column addr 0
lcdSendCtl(y | 0xB0); //page addr y
#if !defined(REVX)
pioptr->PIO_CODR = LCD_CS1; // Select LCD
#endif
#if !defined(REVX)
pioptr->PIO_CODR = LCD_CS1; // Select LCD
#endif
PIOA->PIO_SODR = LCD_A0; // Data
#if !defined(REVX)
pioptr->PIO_CODR = LCD_RnW; // Write
#endif
#if !defined(REVX)
pioptr->PIO_CODR = LCD_RnW; // Write
#endif
#if defined(REVA)
x = lookup[*p];
@@ -278,16 +285,6 @@ void lcdRefresh()
x = *p;
#endif
for (z = 0; z < LCD_W; z += 1) {
// The following 7 lines replaces by a lookup table
// x = __RBIT( *p++ ) ;
// x >>= 23 ;
// if ( x & 0x00000100 )
// {
// x |= 1 ;
// }
// pioptr->PIO_ODSR = x ;
pioptr->PIO_ODSR = x;
pioptr->PIO_SODR = ebit; // Start E pulse
// Need a delay here (250nS)
@@ -297,27 +294,27 @@ void lcdRefresh()
#else
x = *p;
#endif
// TC0->TC_CHANNEL[0].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
// TC0->TC_CHANNEL[0].TC_CCR = 5; // Enable clock and trigger it (may only need trigger)
// while ( TC0->TC_CHANNEL[0].TC_CV < 3 ) // Value depends on MCK/2 (used 6MHz)
// {
// // Wait
// }
pioptr->PIO_CODR = ebit; // End E pulse
}
#if !defined(REVX)
pioptr->PIO_SODR = LCD_CS1; // Deselect LCD
#endif
#if !defined(REVX)
pioptr->PIO_SODR = LCD_CS1; // Deselect LCD
#endif
}
pioptr->PIO_ODSR = 0xFF ; // Drive lines high
pioptr->PIO_ODSR = 0xFF; // Drive lines high
#if defined(REVA)
pioptr->PIO_PUER = 0x0000003CL ; // Set bits 2, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x0000003CL ; // Set bits 2, 3, 4, 5 input
pioptr->PIO_PUER = 0x000000FEL; // Set bits 2, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x000000FEL; // Set bits 2, 3, 4, 5 input
#else
pioptr->PIO_PUER = 0x0000003AL ; // Set bits 1, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x0000003AL ; // Set bits 1, 3, 4, 5 input
pioptr->PIO_PUER = 0x000000FEL; // Set bits 1, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x000000FEL; // Set bits 1, 3, 4, 5 input
#endif
pioptr->PIO_ODSR = lcdInputs; // Drive D0 low
pioptr->PIO_ODSR = 0xFE; // Drive D0 low
lcdLock = 0;
}
+7 -1
View File
@@ -131,7 +131,11 @@ void boardInit()
RCC_APB1PeriphClockCmd(LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | INTERRUPT_5MS_APB1Periph | TIMER_2MHz_APB1Periph | I2C_RCC_APB1Periph | SD_RCC_APB1Periph | TRAINER_RCC_APB1Periph | TELEMETRY_RCC_APB1Periph | SERIAL_RCC_APB1Periph, ENABLE);
RCC_APB2PeriphClockCmd(BACKLIGHT_RCC_APB2Periph | ADC_RCC_APB2Periph | HAPTIC_RCC_APB2Periph | INTMODULE_RCC_APB2Periph | EXTMODULE_RCC_APB2Periph | HEARTBEAT_RCC_APB2Periph, ENABLE);
#if !defined(REV9E)
// some REV9E boards need that the pwrInit() is moved a little bit later
pwrInit();
#endif
keysInit();
adcInit();
delaysInit();
@@ -179,6 +183,7 @@ void boardInit()
else {
if (pwr_on != 1) {
pwr_on = 1;
pwrInit();
backlightInit();
haptic.play(15, 3, PLAY_NOW);
}
@@ -191,6 +196,7 @@ void boardInit()
}
}
else {
pwrInit();
backlightInit();
}
toplcdInit();
@@ -264,7 +270,7 @@ void checkTrainerSettings()
uint8_t requiredTrainerMode = g_model.trainerMode;
if (requiredTrainerMode != currentTrainerMode) {
switch (currentTrainerMode) {
case TRAINER_MODE_MASTER:
case TRAINER_MODE_MASTER_TRAINER_JACK:
stop_trainer_capture();
break;
case TRAINER_MODE_SLAVE:
@@ -143,7 +143,12 @@ void configure_pins( uint32_t pins, uint16_t config );
extern uint16_t sessionTimer;
#define SLAVE_MODE() (g_model.trainerMode == TRAINER_MODE_SLAVE)
#if defined(REV9E)
#define TRAINER_CONNECTED() (true)
#else
#define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_GPIO_DETECT, TRAINER_GPIO_PIN_DETECT) == Bit_RESET)
#endif
#ifdef __cplusplus
extern "C" {
+8 -4
View File
@@ -127,13 +127,15 @@ extern "C" void TIM3_IRQHandler()
if ( (TRAINER_TIMER->DIER & TIM_DIER_CC3IE ) && ( TRAINER_TIMER->SR & TIM_SR_CC3IF ) ) {
// capture mode on trainer jack
capture = TRAINER_TIMER->CCR3 ;
doCapture = true;
if (TRAINER_CONNECTED() && currentTrainerMode == TRAINER_MODE_MASTER_TRAINER_JACK)
doCapture = true;
}
if ( ( TRAINER_TIMER->DIER & TIM_DIER_CC2IE ) && ( TRAINER_TIMER->SR & TIM_SR_CC2IF ) ) {
// capture mode on heartbeat pin (external module)
capture = TRAINER_TIMER->CCR2 ;
doCapture = true ;
if (currentTrainerMode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)
doCapture = true ;
}
if (doCapture) {
@@ -247,8 +249,10 @@ extern "C" void HEARTBEAT_USART_IRQHandler()
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
data = HEARTBEAT_USART->DR;
if (!(status & USART_FLAG_ERRORS))
sbusFifo.push(data);
if (!(status & USART_FLAG_ERRORS)) {
if (currentTrainerMode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE)
sbusFifo.push(data);
}
status = HEARTBEAT_USART->SR;
}
File diff suppressed because it is too large Load Diff
+17 -2
View File
@@ -795,10 +795,12 @@ char *findTrueFileName(const char *path)
strcat(result, res->d_name);
TRACE("\tfound: %s", res->d_name);
fileMap.insert(filemap_t:: value_type(path, result));
simu::closedir(dir);
return result;
}
}
}
simu::closedir(dir);
}
#endif
}
@@ -840,10 +842,10 @@ FRESULT f_open (FIL * fil, const TCHAR *name, BYTE flag)
fil->fsize = tmp.st_size;
fil->fptr = 0;
}
fil->fs = (FATFS*)fopen(realPath, (flag & FA_WRITE) ? "wb+" : "rb+");
fil->fs = (FATFS*)fopen(realPath, (flag & FA_WRITE) ? ((flag & FA_CREATE_ALWAYS) ? "wb+" : "ab+") : "rb+");
fil->fptr = 0;
if (fil->fs) {
TRACE("f_open(%s) = %p", path, (FILE*)fil->fs);
TRACE("f_open(%s, %x) = %p", path, flag, (FILE*)fil->fs);
return FR_OK;
}
TRACE("f_open(%s) = error %d (%s)", path, errno, strerror(errno));
@@ -877,6 +879,19 @@ FRESULT f_lseek (FIL* fil, DWORD offset)
return FR_OK;
}
UINT f_size(FIL* fil)
{
if (fil && fil->fs) {
long curr = ftell((FILE*)fil->fs);
fseek((FILE*)fil->fs, 0, SEEK_END);
long size = ftell((FILE*)fil->fs);
fseek((FILE*)fil->fs, curr, SEEK_SET);
TRACE("f_size(%p) %u", fil->fs, size);
return size;
}
return 0;
}
FRESULT f_close (FIL * fil)
{
if (fil && fil->fs) {
+58 -36
View File
@@ -366,10 +366,7 @@ void TelemetryItem::eval(const TelemetrySensor & sensor)
result += dist*dist;
if (altItem) {
dist = abs(altItem->value);
uint8_t prec = g_model.telemetrySensors[sensor.dist.alt-1].prec;
if (prec > 0)
dist /= (prec==2 ? 100 : 10);
dist = abs(altItem->value) / g_model.telemetrySensors[sensor.dist.alt-1].getPrecDivisor();
result += dist*dist;
}
@@ -545,49 +542,56 @@ void TelemetrySensor::init(uint16_t id)
init(label);
}
bool TelemetrySensor::isAvailable()
bool TelemetrySensor::isAvailable() const
{
return ZLEN(label) > 0;
}
PACK(typedef struct {
uint8_t unitFrom;
uint8_t unitTo;
int16_t multiplier;
int16_t divisor;
}) UnitConversionRule;
const UnitConversionRule unitConversionTable[] = {
/* unitFrom unitTo multiplier divisor */
{ UNIT_METERS, UNIT_FEET, 105, 32},
{ UNIT_METERS_PER_SECOND, UNIT_FEET_PER_SECOND, 105, 32},
{ UNIT_KTS, UNIT_KMH, 1852, 1000}, // 1 knot = 1.85200 kilometers per hour
{ UNIT_KTS, UNIT_MPH, 1151, 1000}, // 1 knot = 1.15077945 miles per hour
{ UNIT_KTS, UNIT_METERS_PER_SECOND, 1000, 1944}, // 1 knot = 0.514444444 meters / second (divide with 1.94384449)
{ UNIT_KTS, UNIT_FEET_PER_SECOND, 1688, 1000}, // 1 knot = 1.68780986 feet per second
{ UNIT_KMH, UNIT_KTS, 1000, 1852}, // 1 km/h = 0.539956803 knots (divide with 1.85200)
{ UNIT_KMH, UNIT_MPH, 1000, 1609}, // 1 km/h = 0.621371192 miles per hour (divide with 1.60934400)
{ UNIT_KMH, UNIT_METERS_PER_SECOND, 10, 36}, // 1 km/h = 0.277777778 meters / second (divide with 3.6)
{ UNIT_KMH, UNIT_FEET_PER_SECOND, 911, 1000}, // 1 km/h = 0.911344415 feet per second
{ UNIT_MILLILITERS, UNIT_FLOZ, 100, 2957},
{ 0, 0, 0, 0} // termination
};
int32_t convertTelemetryValue(int32_t value, uint8_t unit, uint8_t prec, uint8_t destUnit, uint8_t destPrec)
{
for (int i=prec; i<destPrec; i++)
value *= 10;
if (unit == UNIT_METERS || unit == UNIT_METERS_PER_SECOND) {
if (destUnit == UNIT_FEET || destUnit == UNIT_FEET_PER_SECOND) {
// m to ft *105/32
value = (value * 105) / 32;
}
}
else if (unit == UNIT_KTS) {
if (destUnit == UNIT_KMH) {
// kts to km/h (1 knot = 1.85200 kilometers per hour)
value = (value * 1852) / 1000;
}
else if (destUnit == UNIT_MPH) {
// kts to mph (1 knot = 1.15077945 miles per hour)
value = (value * 1151) / 1000;
}
else if (destUnit == UNIT_METERS_PER_SECOND) {
// kts to m/s (1 knot = 0.514444444 meters / second)
value = (value * 514) / 1000;
}
else if (destUnit == UNIT_FEET_PER_SECOND) {
// kts to f/s (1 knot = 1.68780986 feet per second)
value = (value * 1688) / 1000;
}
}
else if (unit == UNIT_CELSIUS) {
if (unit == UNIT_CELSIUS) {
if (destUnit == UNIT_FAHRENHEIT) {
// T(°F) = T(°C)×1,8 + 32
value = 32 + (value*18)/10;
value = 32 + (value*18) / 10;
}
}
else if (unit == UNIT_MILLILITERS) {
if (destUnit == UNIT_FLOZ) {
value = (value * 100) / 2957;
else {
const UnitConversionRule * p = unitConversionTable;
while (p->divisor) {
if (p->unitFrom == unit && p->unitTo == destUnit) {
value = (value * (int32_t)p->multiplier) / (int32_t)p->divisor;
break;
}
++p;
}
}
@@ -622,7 +626,7 @@ int32_t TelemetrySensor::getValue(int32_t value, uint8_t unit, uint8_t prec) con
return value;
}
bool TelemetrySensor::isConfigurable()
bool TelemetrySensor::isConfigurable() const
{
if (type == TELEM_TYPE_CALCULATED) {
if (formula >= TELEM_FORMULA_CELL) {
@@ -637,7 +641,7 @@ bool TelemetrySensor::isConfigurable()
return true;
}
bool TelemetrySensor::isPrecConfigurable()
bool TelemetrySensor::isPrecConfigurable() const
{
if (isConfigurable()) {
return true;
@@ -649,3 +653,21 @@ bool TelemetrySensor::isPrecConfigurable()
return false;
}
}
int32_t TelemetrySensor::getPrecMultiplier() const
{
/*
Important: the return type must be signed, otherwise
mathematic operations with a negative telemetry value won't work
*/
if (prec == 2) return 1;
if (prec == 1) return 10;
return 100;
}
int32_t TelemetrySensor::getPrecDivisor() const
{
if (prec == 2) return 100;
if (prec == 1) return 10;
return 1;
}
-4
View File
@@ -42,10 +42,6 @@
#define SWAP_DEFINED
#include "opentx.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
extern const char * zchar2string(const char * zstring, int size);
#define EXPECT_ZSTREQ(c_string, z_string) EXPECT_STREQ(c_string, zchar2string(z_string, sizeof(z_string)))
extern void luaInit();
+5 -1
View File
@@ -238,7 +238,11 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize)
#if !defined(SIMU)
#define f_size(fp) ((fp)->fsize)
#else
UINT f_size(FIL* fil);
#endif
#ifndef EOF
#define EOF (-1)
+11 -13
View File
@@ -19,6 +19,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define liolib_c
@@ -183,14 +184,10 @@ static LStream *newprefile (lua_State *L) {
#if !defined(USE_FATFS)
static int aux_close (lua_State *L) {
#if !defined(USE_FATFS)
LStream *p = tolstream(L);
lua_CFunction cf = p->closef;
p->closef = NULL; /* mark stream as closed */
return (*cf)(L); /* close it */
#else
return 0;
#endif
}
#endif
@@ -249,14 +246,14 @@ static int io_open (lua_State *L) {
const char *md = luaL_optstring(L, 2, "r");
LStream *p = newfile(L);
#if defined(USE_FATFS)
BYTE mode;
if (strchr(md, 'w') || strchr(md, 'a'))
mode = FA_WRITE;
else
mode = FA_READ;
BYTE mode = FA_READ;
if (*md == 'w')
mode = FA_WRITE | FA_CREATE_ALWAYS; // always create file and truncate it
else if (*md == 'a')
mode = FA_WRITE | FA_OPEN_ALWAYS; // always open file (create it if necessary)
FRESULT result = f_open(&p->f, filename, mode);
if (result == FR_OK && strchr(md, 'a'))
result = f_lseek(&p->f, f_size(&p->f));
if (result == FR_OK && *md == 'a')
result = f_lseek(&p->f, f_size(&p->f)); // seek to the end of the file
return result == FR_OK ? 1 : 0;
#else
const char *mode = md; /* to traverse/check mode */
@@ -559,8 +556,9 @@ static int g_write (lua_State *L, FILE *f, int arg) {
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
f_printf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
char s[LUAI_MAXNUMBER2STR];
sprintf(s, LUA_NUMBER_FMT, lua_tonumber(L, arg));
status = status && f_puts(s, f) > 0;
}
else {
size_t l;
+1 -1
View File
@@ -391,7 +391,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
+1 -1
View File
@@ -395,7 +395,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
+1 -1
View File
@@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
+1 -1
View File
@@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
+1 -1
View File
@@ -393,7 +393,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
+6 -6
View File
@@ -396,7 +396,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
@@ -849,10 +849,10 @@
#define TR_NO_MODELS_ON_SD "No Model. su SD"
#define TR_NO_BITMAPS_ON_SD "No Immag. su SD"
#define TR_NO_SCRIPTS_ON_SD "No Scripts su SD"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
#define TR_PLAY_FILE "Suona"
#define TR_DELETE_FILE "Elimina"
#define TR_COPY_FILE "Copia"
@@ -1115,7 +1115,7 @@
#define ZSTR_A4 "A4"
#define ZSTR_BATT "RxBt"
#define ZSTR_ALT "Alt"
#define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP2 "Tmp2"
#define ZSTR_RPM "RPM"
#define ZSTR_FUEL "Fuel"
+1 -1
View File
@@ -397,7 +397,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
+11 -11
View File
@@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
@@ -801,10 +801,10 @@
#define TR_NO_MODELS_ON_SD "Sem Modelo no SD"
#define TR_NO_BITMAPS_ON_SD "No Bitmaps on SD"
#define TR_NO_SCRIPTS_ON_SD "No Scripts on SD"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
#define TR_PLAY_FILE "Play"
#define TR_DELETE_FILE "Apagar"
#define TR_COPY_FILE "Copiar"
@@ -902,10 +902,10 @@
#define TR_SMOOTH "Smooth"
#define TR_COPY_STICKS_TO_OFS "Copy Sticks To Offset"
#define TR_COPY_TRIMS_TO_OFS "Copy trims to subtrim"
#define TR_INCDEC "Inc/Decrement"
#define TR_GLOBALVAR "Global Var"
#define TR_MIXSOURCE "Mixer Source"
#define TR_CONSTANT "Constant"
#define TR_INCDEC "Inc/Decrement"
#define TR_GLOBALVAR "Global Var"
#define TR_MIXSOURCE "Mixer Source"
#define TR_CONSTANT "Constant"
#define TR_PERSISTENT_MAH INDENT "Store mAh"
#define TR_PREFLIGHT "Preflight Checks"
#define TR_CHECKLIST INDENT "Display Checklist"
@@ -1041,7 +1041,7 @@
#define TR_DISCOVER_SENSORS INDENT "Discover new sensors"
#define TR_STOP_DISCOVER_SENSORS INDENT "Stop discovery"
#define TR_DELETE_ALL_SENSORS INDENT "Delete all sensors"
#define TR_CONFIRMDELETE "Really delete all?"
#define TR_CONFIRMDELETE "Really delete all?"
#define TR_MENU_INPUTS "\314Inputs"
#define TR_MENU_LUA "\322Lua scripts"
@@ -1067,7 +1067,7 @@
#define ZSTR_A4 "A4"
#define ZSTR_BATT "RxBt"
#define ZSTR_ALT "Alt"
#define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP2 "Tmp2"
#define ZSTR_RPM "RPM"
#define ZSTR_FUEL "Fuel"
+11 -11
View File
@@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR
#endif
#define LEN_VTELEMUNIT "\003"
#define TR_VTELEMUNIT "v\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#define TR_VTELEMUNIT "V\0 ""A\0 ""m/s""-\0 " SPEED_UNIT LENGTH_UNIT "@\0 ""%\0 ""mA\0""mAh""W\0 "
#endif
#define STR_V (STR_VTELEMUNIT+1)
@@ -801,10 +801,10 @@
#define TR_NO_MODELS_ON_SD "Ingen modell i SD"
#define TR_NO_BITMAPS_ON_SD "Ikoner saknas på SD"
#define TR_NO_SCRIPTS_ON_SD "Programkod saknas på SD"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error"
#define TR_PLAY_FILE "Spela"
#define TR_DELETE_FILE "Radera"
#define TR_COPY_FILE "Kopia"
@@ -902,10 +902,10 @@
#define TR_SMOOTH "Mjuk"
#define TR_COPY_STICKS_TO_OFS "Spara spakar som offset"
#define TR_COPY_TRIMS_TO_OFS "Spara trimmar som offset"
#define TR_INCDEC "Inc/Decrement"
#define TR_GLOBALVAR "Global Var"
#define TR_MIXSOURCE "Mixer Source"
#define TR_CONSTANT "Constant"
#define TR_INCDEC "Inc/Decrement"
#define TR_GLOBALVAR "Global Var"
#define TR_MIXSOURCE "Mixer Source"
#define TR_CONSTANT "Constant"
#define TR_PERSISTENT_MAH INDENT "Lagra mAh"
#define TR_PREFLIGHT "Startkontroller"
#define TR_CHECKLIST TR(INDENT "Checklista", INDENT "Visa Checklista")
@@ -1041,7 +1041,7 @@
#define TR_DISCOVER_SENSORS INDENT "Discover new sensors"
#define TR_STOP_DISCOVER_SENSORS INDENT "Stop discovery"
#define TR_DELETE_ALL_SENSORS INDENT "Delete all sensors"
#define TR_CONFIRMDELETE "Really delete all?"
#define TR_CONFIRMDELETE "Really delete all?"
#define TR_MENU_INPUTS "\314Inputs"
#define TR_MENU_LUA "\322Lua scripts"
@@ -1067,7 +1067,7 @@
#define ZSTR_A4 "A4"
#define ZSTR_BATT "RxBt"
#define ZSTR_ALT "Alt"
#define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP2 "Tmp2"
#define ZSTR_RPM "RPM"
#define ZSTR_FUEL "Fuel"
+4 -4
View File
@@ -47,10 +47,10 @@ void varioWakeup()
int verticalSpeed = 0;
if (g_model.frsky.varioSource) {
TelemetryItem & varioItem = telemetryItems[g_model.frsky.varioSource-1];
verticalSpeed = varioItem.value;
TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.varioSource-1];
if (sensor.prec != 2) verticalSpeed *= sensor.prec == 0 ? 100 : 10;
uint8_t item = g_model.frsky.varioSource-1;
if (item < MAX_SENSORS) {
verticalSpeed = telemetryItems[item].value * g_model.telemetrySensors[item].getPrecMultiplier();
}
}
int varioCenterMin = (int)g_model.frsky.varioCenterMin * 10 - 50;