1
0
Fork 0
mirror of https://github.com/EdgeTX/edgetx.git synced 2025-07-23 08:15:13 +03:00

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 22:01:24 +01:00
commit de733579d5
85 changed files with 7038 additions and 3664 deletions

View file

@ -26,7 +26,6 @@ Chris Guy
Adrien Gravouille Adrien Gravouille
Thomas Black Thomas Black
Marc Lucht Marc Lucht
Michel Baily
Zdenek Trojanek Zdenek Trojanek
Martin Hotar Martin Hotar
Stefan Grundevik Stefan Grundevik
@ -113,7 +112,6 @@ Erhard Werner
Stig Jøran Moen Stig Jøran Moen
Keith Hertzog Keith Hertzog
Christophe Dauvergne Christophe Dauvergne
Michel Baily
Tauno Rautakorpi Tauno Rautakorpi
Sven Assmus Sven Assmus
Paul Dittman Paul Dittman
@ -417,7 +415,6 @@ Andrea Montefusco
Paul Luby Paul Luby
Donald L Webster Donald L Webster
Kenneth Frehafer Kenneth Frehafer
Peter McHenry
Matthias Hase Matthias Hase
Markus Wolf Markus Wolf
Andrew Fazio Andrew Fazio
@ -588,7 +585,6 @@ Dietmar Drees
Jürgen Monden Jürgen Monden
David Morgan David Morgan
Andrew Fernie Andrew Fernie
Michel Baily
Donald Burke Donald Burke
Ronald Donker Ronald Donker
Fredie Singh Fredie Singh
@ -837,3 +833,20 @@ Jay Warren
Marian Matej Marian Matej
Alastair Smith Alastair Smith
Timothy Senecal Timothy Senecal
Dietmar Drees
Bruce Jones
Adil Busaidy
Herman Hofman
Jean Paul Michel
Peter McHenry
Julien lecoquierre
Jean-Marie Clay
Robert Nicoll
Dan Nixon
Ewald Moehring
Giovanni Carnesecchi
Paul Dumsday
Tadeusz Adamowski
Andrew Newton
Neil Horne
Kerstin Appelqvist

View file

@ -1,4 +1,14 @@
<h2>Version 2.1.4 / <set date></h2> <h2>Version 2.1.6 / 2015-11-11</h2>
[Taranis]
<ul>
<li>Telemetry custom screen changes didn't emit modified signal (<a href=https://github.com/opentx/opentx/issues/3029>#3029</a>)</li>
<li>Hide D8/LR12 when eu firmware option is selected</li>
</ul>
<h2>Version 2.1.5 / 2015-11-05</h2>
Notice: version 2.1.4 was skipped by the OpenTX team to avoid confusion with FrSky's release of OpenTX 2.1.4
<ul> <ul>
<li>Fixed: changing any setting on the telemetry panel does not set the file as being modified (<a href=https://github.com/opentx/opentx/issues/2875>#2875</a>)</li> <li>Fixed: changing any setting on the telemetry panel does not set the file as being modified (<a href=https://github.com/opentx/opentx/issues/2875>#2875</a>)</li>
@ -11,10 +21,17 @@
<li>Fixed wrong import of Logical switches from OpenTX 2.0.x version (<a href=https://github.com/opentx/opentx/issues/2942>#2942</a>)</li> <li>Fixed wrong import of Logical switches from OpenTX 2.0.x version (<a href=https://github.com/opentx/opentx/issues/2942>#2942</a>)</li>
<li>Fixed a problem with updates path on Windows (<a href=https://github.com/opentx/opentx/issues/2876>#2876</a>)</li> <li>Fixed a problem with updates path on Windows (<a href=https://github.com/opentx/opentx/issues/2876>#2876</a>)</li>
<li>Edge representation unified (changed from "no release" to "instant") (<a href=https://github.com/opentx/opentx/issues/2837>#2837</a>)</li> <li>Edge representation unified (changed from "no release" to "instant") (<a href=https://github.com/opentx/opentx/issues/2837>#2837</a>)</li>
<li>Added channel names on failsafe sliders (<a href=https://github.com/opentx/opentx/issues/3021>#3021</a>)</li>
<li>Corrected failsafe mapping when using Custom failsafe mode, D16 protocol and channel range different from from 1-8.
Users with such setups are advised to re-check their failsafe settings (<a href=https://github.com/opentx/opentx/issues/2975>#2975</a>)</li>
<li>Various texts and translations corrections</li>
<li>Various small bug-fixes: <a href=https://github.com/opentx/opentx/issues/2994>#2994</a>,
<a href=https://github.com/opentx/opentx/issues/3016>#3016</a>,
<a href=https://github.com/opentx/opentx/issues/3012>#3012</a>
</li>
</ul> </ul>
<h2>Version 2.1.3 / 2015-09-09</h2> <h2>Version 2.1.3 / 2015-09-09</h2>
<ul> <ul>

View file

@ -103,6 +103,11 @@ ELSE( )
LINK_DIRECTORIES( /usr/local/lib ) LINK_DIRECTORIES( /usr/local/lib )
ENDIF( ) ENDIF( )
IF( MSVC )
MESSAGE( STATUS "Adding include C:/Programs/dirent/include for dirent.h" )
INCLUDE_DIRECTORIES( C:/Programs/dirent/include )
ENDIF( )
set(RADIO_SRC_DIRECTORY ${PROJECT_SOURCE_DIR}/../../radio/src) set(RADIO_SRC_DIRECTORY ${PROJECT_SOURCE_DIR}/../../radio/src)
set(SIMU_SRC_DIRECTORY ${PROJECT_SOURCE_DIR}/simulation) set(SIMU_SRC_DIRECTORY ${PROJECT_SOURCE_DIR}/simulation)
set(COMPANION_SRC_DIRECTORY ${PROJECT_SOURCE_DIR}) set(COMPANION_SRC_DIRECTORY ${PROJECT_SOURCE_DIR})
@ -274,7 +279,6 @@ NOW(TIME)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/translations.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/translations.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc @ONLY)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/firmwares/opentx/stamp-opentx.h.in ${CMAKE_CURRENT_BINARY_DIR}/stamp-opentx.h @ONLY)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/companion.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/companion.desktop @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/companion.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/companion.desktop @ONLY)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/simulator.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/simulator.desktop @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/simulator.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/simulator.desktop @ONLY)
@ -446,7 +450,11 @@ ENDIF()
SET(CPACK_PACKAGE_NAME "companion${C9X_NAME_SUFFIX}") SET(CPACK_PACKAGE_NAME "companion${C9X_NAME_SUFFIX}")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Models and settings editor for the OpenTx open source firmware") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Models and settings editor for the OpenTx open source firmware")
string(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_PACKAGE_NAME_LOWERCASE) string(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_PACKAGE_NAME_LOWERCASE)
SET( CPACK_STRIP_FILES TRUE )
# The file stripping is deliberately disabled, with the stripped file we get
# very poor trace-backs from the users when they report Companion crash
SET(CPACK_STRIP_FILES FALSE)
find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems") find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
if(DPKG_PROGRAM) if(DPKG_PROGRAM)
SET(CPACK_GENERATOR "DEB") SET(CPACK_GENERATOR "DEB")

View file

@ -627,7 +627,7 @@ Mode 4:
<item row="10" column="2" colspan="2"> <item row="10" column="2" colspan="2">
<widget class="QPushButton" name="sdPathButton"> <widget class="QPushButton" name="sdPathButton">
<property name="text"> <property name="text">
<string>Open Folder</string> <string>Select Folder</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -637,7 +637,7 @@ Mode 4:
<string>The profile specific folder, if set, will override general Backup folder</string> <string>The profile specific folder, if set, will override general Backup folder</string>
</property> </property>
<property name="text"> <property name="text">
<string>Open Folder</string> <string>Select Folder</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -854,7 +854,7 @@ Mode 4:
<item row="12" column="2" colspan="2"> <item row="12" column="2" colspan="2">
<widget class="QPushButton" name="backupPathButton"> <widget class="QPushButton" name="backupPathButton">
<property name="text"> <property name="text">
<string>Open Folder</string> <string>Select Folder</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -874,14 +874,14 @@ Mode 4:
<item row="0" column="2" colspan="2"> <item row="0" column="2" colspan="2">
<widget class="QPushButton" name="ge_pathButton"> <widget class="QPushButton" name="ge_pathButton">
<property name="text"> <property name="text">
<string>Find Executable</string> <string>Select Executable</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="16" column="2" colspan="2"> <item row="16" column="2" colspan="2">
<widget class="QPushButton" name="libraryPathButton"> <widget class="QPushButton" name="libraryPathButton">
<property name="text"> <property name="text">
<string>Open Folder</string> <string>Select Folder</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -1001,7 +1001,7 @@ Mode 4:
<item row="0" column="3"> <item row="0" column="3">
<widget class="QPushButton" name="snapshotPathButton"> <widget class="QPushButton" name="snapshotPathButton">
<property name="text"> <property name="text">
<string>Open Folder</string> <string>Select Folder</string>
</property> </property>
<property name="flat"> <property name="flat">
<bool>false</bool> <bool>false</bool>

View file

@ -156,7 +156,8 @@ int main(int argc, char *argv[])
delete splash; delete splash;
delete mainWin; delete mainWin;
unregisterFirmwares(); unregisterSimulators();
unregisterOpenTxFirmwares();
unregisterEEpromInterfaces(); unregisterEEpromInterfaces();
#if defined(JOYSTICKS) || defined(SIMU_AUDIO) #if defined(JOYSTICKS) || defined(SIMU_AUDIO)

View file

@ -783,7 +783,7 @@ QString CustomFunctionData::funcToString() const
else if (func == FuncPlayScript) else if (func == FuncPlayScript)
return QObject::tr("Play Script"); return QObject::tr("Play Script");
else if (func == FuncLogs) else if (func == FuncLogs)
return QObject::tr("Start Logs"); return QObject::tr("SD Logs");
else if (func == FuncVolume) else if (func == FuncVolume)
return QObject::tr("Volume"); return QObject::tr("Volume");
else if (func == FuncBacklight) else if (func == FuncBacklight)
@ -1628,13 +1628,6 @@ QList<Firmware *> firmwares;
Firmware * default_firmware_variant; Firmware * default_firmware_variant;
Firmware * current_firmware_variant; Firmware * current_firmware_variant;
void unregisterFirmwares()
{
foreach (Firmware * f, firmwares) {
delete f;
}
}
void ShowEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound) void ShowEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound)
{ {
std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound); std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound);

View file

@ -755,6 +755,22 @@ enum TelemetryCurrentSources {
TELEMETRY_CURRENT_SOURCE_FAS TELEMETRY_CURRENT_SOURCE_FAS
}; };
enum UartModes {
UART_MODE_NONE,
UART_MODE_TELEMETRY_MIRROR,
UART_MODE_TELEMETRY,
UART_MODE_SBUS_TRAINER,
UART_MODE_DEBUG
};
enum TrainerMode {
TRAINER_MODE_MASTER_TRAINER_JACK,
TRAINER_MODE_SLAVE,
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
TRAINER_MODE_MASTER_BATTERY_COMPARTMENT,
};
class FrSkyData { class FrSkyData {
public: public:
FrSkyData() { clear(); } FrSkyData() { clear(); }
@ -1284,7 +1300,6 @@ enum Capability {
HasExpoNames, HasExpoNames,
HasNoExpo, HasNoExpo,
HasMixerNames, HasMixerNames,
HasChNames,
HasCvNames, HasCvNames,
HasPxxCountry, HasPxxCountry,
HasPPMStart, HasPPMStart,
@ -1376,8 +1391,6 @@ class EEPROMInterface
virtual int getSize(const GeneralSettings &) = 0; virtual int getSize(const GeneralSettings &) = 0;
virtual int isAvailable(PulsesProtocol proto, int port=0) = 0;
virtual const int getEEpromSize() = 0; virtual const int getEEpromSize() = 0;
virtual const int getMaxModels() = 0; virtual const int getMaxModels() = 0;
@ -1489,7 +1502,7 @@ inline void applyStickModeToModel(ModelData &model, unsigned int mode)
void registerEEpromInterfaces(); void registerEEpromInterfaces();
void unregisterEEpromInterfaces(); void unregisterEEpromInterfaces();
void registerOpenTxFirmwares(); void registerOpenTxFirmwares();
void unregisterFirmwares(); void unregisterOpenTxFirmwares();
enum EepromLoadErrors { enum EepromLoadErrors {
NO_ERROR, NO_ERROR,
@ -1613,6 +1626,8 @@ class Firmware {
virtual bool isTelemetrySourceAvailable(int source) = 0; virtual bool isTelemetrySourceAvailable(int source) = 0;
virtual int isAvailable(PulsesProtocol proto, int port=0) = 0;
public: public:
QList<const char *> languages; QList<const char *> languages;
QList<const char *> ttslanguages; QList<const char *> ttslanguages;

View file

@ -121,20 +121,16 @@ PACK(struct EepromFileHeader
bool RleFile::searchFat() bool RleFile::searchFat()
{ {
int bestFatIndex = -1; eepromFatHeader = NULL;
uint32_t bestFatIndex = 0;
for (int i=0; i<EEPROM_ZONE_SIZE/EEPROM_FAT_SIZE; i++) { for (int i=0; i<EEPROM_ZONE_SIZE/EEPROM_FAT_SIZE; i++) {
EepromHeader * header = (EepromHeader *)(eeprom+i*EEPROM_FAT_SIZE); EepromHeader * header = (EepromHeader *)(eeprom+i*EEPROM_FAT_SIZE);
if (header->mark == EEPROM_MARK && (int)header->index >= bestFatIndex) { if (header->mark == EEPROM_MARK && (int)header->index >= bestFatIndex) {
bestFatIndex = i; eepromFatHeader = header;
bestFatIndex = header->index;
} }
} }
if (bestFatIndex >= 0) { return (eepromFatHeader != NULL);
eepromFatHeader = (EepromHeader *)(eeprom+bestFatIndex*EEPROM_FAT_SIZE);;
return true;
}
else {
return false;
}
} }
bool RleFile::EeFsOpen(uint8_t *eeprom, int size, BoardEnum board) bool RleFile::EeFsOpen(uint8_t *eeprom, int size, BoardEnum board)

View file

@ -392,8 +392,8 @@ template <int N>
class SwitchField: public ConversionField< SignedField<N> > { class SwitchField: public ConversionField< SignedField<N> > {
public: public:
SwitchField(RawSwitch & sw, BoardEnum board, unsigned int version, unsigned long flags=0): SwitchField(RawSwitch & sw, BoardEnum board, unsigned int version, unsigned long flags=0):
ConversionField< SignedField<N> >(_switch, SwitchesConversionTable::getInstance(board, version, flags), "Switch", ConversionField< SignedField<N> >(_switch, SwitchesConversionTable::getInstance(board, version, flags), QObject::tr("Switch").toAscii(),
"Switch "+ sw.toString()+" cannot be exported on this board!"), QObject::tr("Switch ").toAscii()+ sw.toString()+ QObject::tr(" cannot be exported on this board!").toAscii()),
sw(sw), sw(sw),
_switch(0) _switch(0)
{ {

View file

@ -586,8 +586,6 @@ int OpenTxFirmware::getCapability(const Capability capability)
return (IS_TARANIS(board) ? 10 : 6); return (IS_TARANIS(board) ? 10 : 6);
case GvarsName: case GvarsName:
return (IS_9X(board) ? 0 : 6); return (IS_9X(board) ? 0 : 6);
case HasChNames:
return (IS_TARANIS(board) ? 1 : 0);
case GvarsInCS: case GvarsInCS:
case HasFAIMode: case HasFAIMode:
return 1; return 1;
@ -807,7 +805,7 @@ int OpenTxFirmware::getCapability(const Capability capability)
case MixersMonitor: case MixersMonitor:
return id.contains("mixersmon") ? 1 : 0; return id.contains("mixersmon") ? 1 : 0;
case HasBatMeterRange: case HasBatMeterRange:
return (IS_TARANIS(board) ? true : false); return (IS_TARANIS(board) ? true : id.contains("battgraph"));
case DangerousFunctions: case DangerousFunctions:
return id.contains("danger") ? 1 : 0; return id.contains("danger") ? 1 : 0;
default: default:
@ -826,7 +824,7 @@ bool OpenTxFirmware::isTelemetrySourceAvailable(int source)
return true; return true;
} }
int OpenTxEepromInterface::isAvailable(PulsesProtocol proto, int port) int OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
{ {
if (IS_TARANIS(board)) { if (IS_TARANIS(board)) {
switch (port) { switch (port) {
@ -834,9 +832,12 @@ int OpenTxEepromInterface::isAvailable(PulsesProtocol proto, int port)
switch (proto) { switch (proto) {
case PULSES_OFF: case PULSES_OFF:
case PULSES_PXX_XJT_X16: case PULSES_PXX_XJT_X16:
return 1;
case PULSES_PXX_XJT_D8: case PULSES_PXX_XJT_D8:
case PULSES_PXX_XJT_LR12: case PULSES_PXX_XJT_LR12:
return 1; return id.contains("eu") ? 0 : 1;
case PULSES_PPM:
return id.contains("internalppm") ? 1 : 0;
default: default:
return 0; return 0;
} }
@ -903,7 +904,7 @@ int OpenTxEepromInterface::isAvailable(PulsesProtocol proto, int port)
case PULSES_DSMX: case PULSES_DSMX:
case PULSES_LP45: case PULSES_LP45:
case PULSES_DSM2: case PULSES_DSM2:
case PULSES_PXX_DJT: // case PULSES_PXX_DJT: // Unavailable for now
case PULSES_PPM16: case PULSES_PPM16:
case PULSES_PPMSIM: case PULSES_PPMSIM:
return 1; return 1;
@ -1452,3 +1453,9 @@ void registerOpenTxFirmwares()
current_firmware_variant = default_firmware_variant; current_firmware_variant = default_firmware_variant;
} }
void unregisterOpenTxFirmwares()
{
foreach (Firmware * f, firmwares) {
delete f;
}
}

View file

@ -45,8 +45,6 @@ class OpenTxEepromInterface : public EEPROMInterface
virtual int getSize(const GeneralSettings &); virtual int getSize(const GeneralSettings &);
virtual int isAvailable(PulsesProtocol proto, int port=0);
protected: protected:
const char * getName(); const char * getName();
@ -123,6 +121,8 @@ class OpenTxFirmware: public Firmware {
virtual bool isTelemetrySourceAvailable(int source); virtual bool isTelemetrySourceAvailable(int source);
virtual int isAvailable(PulsesProtocol proto, int port=0);
protected: protected:
QString getFirmwareBaseUrl(); QString getFirmwareBaseUrl();
@ -130,5 +130,6 @@ class OpenTxFirmware: public Firmware {
}; };
void registerOpenTxFirmwares(); void registerOpenTxFirmwares();
void unregisterOpenTxFirmwares();
#endif #endif

View file

@ -31,9 +31,9 @@ add_custom_target(commondeps
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${RADIO_SRC_DIRECTORY}/stamp-opentx.h) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${RADIO_SRC_DIRECTORY}/stamp-opentx.h)
add_custom_target(lua_exports add_custom_target(lua_exports
COMMAND make PCB=TARANIS lua_exports_taranis.inc COMMAND make PCB=TARANIS lua/lua_exports_taranis.inc
COMMAND make PCB=FLAMENCO lua_exports_flamenco.inc COMMAND make PCB=FLAMENCO lua/lua_exports_flamenco.inc
COMMAND make PCB=HORUS lua_exports_horus.inc COMMAND make PCB=HORUS lua/lua_exports_horus.inc
DEPENDS ${RADIO_SRC_DIRECTORY}/myeeprom.h DEPENDS ${RADIO_SRC_DIRECTORY}/myeeprom.h
WORKING_DIRECTORY ${RADIO_SRC_DIRECTORY} WORKING_DIRECTORY ${RADIO_SRC_DIRECTORY}
) )

View file

@ -387,7 +387,10 @@ namespace NAMESPACE {
#endif #endif
#if defined(LUA) #if defined(LUA)
#include "radio/src/lua_api.cpp" #include "radio/src/lua/interface.cpp"
#include "radio/src/lua/api_general.cpp"
#include "radio/src/lua/api_lcd.cpp"
#include "radio/src/lua/api_model.cpp"
#include "radio/src/thirdparty/Lua/src/lapi.c" #include "radio/src/thirdparty/Lua/src/lapi.c"
#include "radio/src/thirdparty/Lua/src/lcode.c" #include "radio/src/thirdparty/Lua/src/lcode.c"
#include "radio/src/thirdparty/Lua/src/lctype.c" #include "radio/src/thirdparty/Lua/src/lctype.c"

View file

@ -1,4 +0,0 @@
// Automatically generated file (CMake) - do not edit
#define DATE_STR "@DATE@"
#define TIME_STR "@TIME@"
#define VERS_STR "@VERSION@"

View file

@ -137,6 +137,9 @@ ModulePanel::ModulePanel(QWidget *parent, ModelData & model, ModuleData & module
QString label; QString label;
if (moduleIdx < 0) { if (moduleIdx < 0) {
label = tr("Trainer Port"); label = tr("Trainer Port");
if (generalSettings.hw_uartMode != UART_MODE_SBUS_TRAINER) {
ui->trainerMode->setItemData(TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, 0, Qt::UserRole - 1);
}
ui->trainerMode->setCurrentIndex(model.trainerMode); ui->trainerMode->setCurrentIndex(model.trainerMode);
if (!IS_TARANIS(firmware->getBoard())) { if (!IS_TARANIS(firmware->getBoard())) {
ui->label_trainerMode->hide(); ui->label_trainerMode->hide();
@ -168,7 +171,7 @@ ModulePanel::ModulePanel(QWidget *parent, ModelData & model, ModuleData & module
// The protocols available on this board // The protocols available on this board
for (int i=0; i<PULSES_PROTOCOL_LAST; i++) { for (int i=0; i<PULSES_PROTOCOL_LAST; i++) {
if (GetEepromInterface()->isAvailable((PulsesProtocol)i, moduleIdx)) { if (firmware->isAvailable((PulsesProtocol)i, moduleIdx)) {
ui->protocol->addItem(ModelPrinter::printModuleProtocol(i), (QVariant)i); ui->protocol->addItem(ModelPrinter::printModuleProtocol(i), (QVariant)i);
if (i == module.protocol) ui->protocol->setCurrentIndex(ui->protocol->count()-1); if (i == module.protocol) ui->protocol->setCurrentIndex(ui->protocol->count()-1);
} }
@ -190,12 +193,12 @@ ModulePanel::ModulePanel(QWidget *parent, ModelData & model, ModuleData & module
spinbox->setDecimals(1); spinbox->setDecimals(1);
label->setProperty("index", i); label->setProperty("index", i);
spinbox->setProperty("index", i); spinbox->setProperty("index", i);
failsafeSpins << spinbox;
ui->failsafesLayout->addWidget(label, 3*(i/8), i%8, Qt::AlignHCenter); ui->failsafesLayout->addWidget(label, 3*(i/8), i%8, Qt::AlignHCenter);
ui->failsafesLayout->addWidget(combo, 1+3*(i/8), i%8, Qt::AlignHCenter); ui->failsafesLayout->addWidget(combo, 1+3*(i/8), i%8, Qt::AlignHCenter);
ui->failsafesLayout->addWidget(spinbox, 2+3*(i/8), i%8, Qt::AlignHCenter); ui->failsafesLayout->addWidget(spinbox, 2+3*(i/8), i%8, Qt::AlignHCenter);
failsafeGroups[i].combo = combo; failsafeGroups[i].combo = combo;
failsafeGroups[i].spinbox = spinbox; failsafeGroups[i].spinbox = spinbox;
failsafeGroups[i].label = label;
updateFailsafe(i); updateFailsafe(i);
connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(onFailsafeComboIndexChanged(int))); connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(onFailsafeComboIndexChanged(int)));
connect(spinbox, SIGNAL(valueChanged(double)), this, SLOT(onFailsafeSpinChanged(double))); connect(spinbox, SIGNAL(valueChanged(double)), this, SLOT(onFailsafeSpinChanged(double)));
@ -234,7 +237,8 @@ void ModulePanel::update()
case PULSES_PXX_XJT_LR12: case PULSES_PXX_XJT_LR12:
case PULSES_PXX_DJT: case PULSES_PXX_DJT:
mask |= MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT; mask |= MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
if ((protocol==PULSES_PXX_XJT_X16) || (protocol==PULSES_PXX_XJT_LR12)) mask |= MASK_FAILSAFES | MASK_RX_NUMBER; if (protocol==PULSES_PXX_XJT_X16) mask |= MASK_FAILSAFES | MASK_RX_NUMBER;
if (protocol==PULSES_PXX_XJT_LR12) mask |= MASK_RX_NUMBER;
break; break;
case PULSES_LP45: case PULSES_LP45:
case PULSES_DSM2: case PULSES_DSM2:
@ -255,15 +259,8 @@ void ModulePanel::update()
} }
} }
else if (IS_TARANIS(firmware->getBoard())) { else if (IS_TARANIS(firmware->getBoard())) {
switch(model->trainerMode) { if (model->trainerMode == TRAINER_SLAVE_JACK) {
case TRAINER_MASTER_JACK: mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
break;
case TRAINER_SLAVE_JACK:
mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
break;
default:
mask |= MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
break;
} }
} }
else if (model->trainerMode != TRAINER_MASTER_JACK) { else if (model->trainerMode != TRAINER_MASTER_JACK) {
@ -306,6 +303,17 @@ void ModulePanel::update()
ui->failsafeMode->setVisible(mask & MASK_FAILSAFES); ui->failsafeMode->setVisible(mask & MASK_FAILSAFES);
ui->failsafeMode->setCurrentIndex(module.failsafeMode); ui->failsafeMode->setCurrentIndex(module.failsafeMode);
ui->failsafesFrame->setEnabled(module.failsafeMode == FAILSAFE_CUSTOM); ui->failsafesFrame->setEnabled(module.failsafeMode == FAILSAFE_CUSTOM);
if (firmware->getCapability(ChannelsName) > 0) {
for(int i=0; i<maxChannels;i++) {
QString name = QString(model->limitData[i+module.channelsStart].name).trimmed();
if (!name.isEmpty()) {
failsafeGroups[i].label->setText(name);
}
else {
failsafeGroups[i].label->setText(QString::number(i+1));
}
}
}
} }
else { else {
mask = 0; mask = 0;
@ -313,6 +321,11 @@ void ModulePanel::update()
ui->failsafesLayoutLabel->setVisible(mask & MASK_FAILSAFES); ui->failsafesLayoutLabel->setVisible(mask & MASK_FAILSAFES);
ui->failsafesFrame->setVisible(mask & MASK_FAILSAFES); ui->failsafesFrame->setVisible(mask & MASK_FAILSAFES);
if (mask & MASK_CHANNELS_RANGE) {
ui->channelsStart->setMaximum(32 - ui->channelsCount->value());
ui->channelsCount->setMaximum(qMin(16, 32-ui->channelsStart->value()));
}
} }
void ModulePanel::on_trainerMode_currentIndexChanged(int index) void ModulePanel::on_trainerMode_currentIndexChanged(int index)
@ -656,6 +669,7 @@ SetupPanel::SetupPanel(QWidget *parent, ModelData & model, GeneralSettings & gen
if (firmware->getCapability(ModelTrainerEnable)) { if (firmware->getCapability(ModelTrainerEnable)) {
modules[C9X_NUM_MODULES] = new ModulePanel(this, model, model.moduleData[C9X_NUM_MODULES], generalSettings, firmware, -1); modules[C9X_NUM_MODULES] = new ModulePanel(this, model, model.moduleData[C9X_NUM_MODULES], generalSettings, firmware, -1);
ui->modulesLayout->addWidget(modules[C9X_NUM_MODULES]); ui->modulesLayout->addWidget(modules[C9X_NUM_MODULES]);
connect(modules[C9X_NUM_MODULES], SIGNAL(modified()), this, SLOT(onChildModified()));
} }
disableMouseScrolling(); disableMouseScrolling();

View file

@ -45,6 +45,7 @@ class ModulePanel : public ModelPanel
struct ChannelFailsafeWidgetsGroup { struct ChannelFailsafeWidgetsGroup {
QComboBox * combo; QComboBox * combo;
QDoubleSpinBox * spinbox; QDoubleSpinBox * spinbox;
QLabel * label;
}; };
Q_OBJECT Q_OBJECT
@ -75,7 +76,6 @@ class ModulePanel : public ModelPanel
ModuleData & module; ModuleData & module;
int moduleIdx; int moduleIdx;
Ui::Module *ui; Ui::Module *ui;
QVector<QDoubleSpinBox *> failsafeSpins;
ChannelFailsafeWidgetsGroup failsafeGroups[maxChannels]; ChannelFailsafeWidgetsGroup failsafeGroups[maxChannels];
}; };

View file

@ -67,12 +67,12 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
<layout class="QGridLayout" name="gridLayout_69" rowstretch="0,0,0,0,0,0,0,0,0" columnstretch="0,0,0,0,0,0,0"> <layout class="QGridLayout" name="gridLayout_69" rowstretch="0,0,0,0,0,0,0,0,0" columnstretch="0,0,0,0,0,0,0">
<property name="verticalSpacing">
<number>6</number>
</property>
<property name="margin"> <property name="margin">
<number>0</number> <number>0</number>
</property> </property>
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="2" column="3" alignment="Qt::AlignLeft"> <item row="2" column="3" alignment="Qt::AlignLeft">
<widget class="QSpinBox" name="channelsStart"> <widget class="QSpinBox" name="channelsStart">
<property name="maximumSize"> <property name="maximumSize">
@ -353,7 +353,7 @@
<string/> <string/>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>1</number> <number>4</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>16</number> <number>16</number>

View file

@ -745,6 +745,7 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin
TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware); TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware);
ui->customScreens->addTab(tab, tr("Telemetry screen %1").arg(i+1)); ui->customScreens->addTab(tab, tr("Telemetry screen %1").arg(i+1));
telemetryCustomScreens[i] = tab; telemetryCustomScreens[i] = tab;
connect(tab, SIGNAL(modified()), this, SLOT(onModified()));
} }
disableMouseScrolling(); disableMouseScrolling();

View file

@ -57,7 +57,7 @@ QString ModelPrinter::printChannelName(int idx)
QString ModelPrinter::printOutputName(int idx) QString ModelPrinter::printOutputName(int idx)
{ {
QString name = QString(model.limitData[idx].name).trimmed(); QString name = QString(model.limitData[idx].name).trimmed();
if (firmware->getCapability(HasChNames) && !name.isEmpty()) { if (firmware->getCapability(ChannelsName) > 0 && !name.isEmpty()) {
return name; return name;
} }
else { else {
@ -313,7 +313,7 @@ QString ModelPrinter::printInputLine(const ExpoData & input)
QString ModelPrinter::printMixerName(int curDest) QString ModelPrinter::printMixerName(int curDest)
{ {
QString str = printChannelName(curDest-1) + " "; QString str = printChannelName(curDest-1) + " ";
if (firmware->getCapability(HasChNames)) { if (firmware->getCapability(ChannelsName) > 0) {
QString name = model.limitData[curDest-1].name; QString name = model.limitData[curDest-1].name;
if (!name.isEmpty()) { if (!name.isEmpty()) {
name = QString("(") + name + QString(")"); name = QString("(") + name + QString(")");

View file

@ -922,4 +922,19 @@ read_file_system_list (bool need_fs_type)
} }
} }
void free_file_system_list(struct mount_entry * mount_list)
{
struct mount_entry * me;
while (mount_list)
{
me = mount_list->me_next;
free (mount_list->me_devname);
free (mount_list->me_mountdir);
if (mount_list->me_type_malloced)
free (mount_list->me_type);
free (mount_list);
mount_list = me;
}
}
#endif #endif

View file

@ -49,4 +49,6 @@ struct mount_entry
struct mount_entry *read_file_system_list (bool need_fs_type); struct mount_entry *read_file_system_list (bool need_fs_type);
void free_file_system_list(struct mount_entry * mount_list);
#endif #endif

View file

@ -270,7 +270,7 @@ QString MultiModelPrinter::printLimits()
columns.append("<table border='0' cellspacing='0' cellpadding='1' width='100%'>" \ columns.append("<table border='0' cellspacing='0' cellpadding='1' width='100%'>" \
"<tr>" \ "<tr>" \
" <td><b>" + tr("Channel") + "</b></td>" \ " <td><b>" + tr("Channel") + "</b></td>" \
" <td><b>" + (firmware->getCapability(HasChNames) ? tr("Name") : "") + "</b></td>" \ " <td><b>" + (firmware->getCapability(ChannelsName) > 0 ? tr("Name") : "") + "</b></td>" \
" <td><b>" + tr("Offset") + "</b></td>" \ " <td><b>" + tr("Offset") + "</b></td>" \
" <td><b>" + tr("Min") + "</b></td>" \ " <td><b>" + tr("Min") + "</b></td>" \
" <td><b>" + tr("Max") + "</b></td>" \ " <td><b>" + tr("Max") + "</b></td>" \

View file

@ -411,7 +411,8 @@ QString findMassstoragePath(const QString &filename)
} }
#else #else
struct mount_entry *entry; struct mount_entry *entry;
entry = read_file_system_list(true); struct mount_entry *firstEntry;
firstEntry = entry = read_file_system_list(true);
while (entry != NULL) { while (entry != NULL) {
if (!drives.contains(entry->me_devname)) { if (!drives.contains(entry->me_devname)) {
drives.append(entry->me_devname); drives.append(entry->me_devname);
@ -426,11 +427,13 @@ QString findMassstoragePath(const QString &filename)
#else #else
if (QFile::exists(eepromfile)) { if (QFile::exists(eepromfile)) {
#endif #endif
free_file_system_list(firstEntry);
return eepromfile; return eepromfile;
} }
} }
entry = entry->me_next; entry = entry->me_next;
} }
free_file_system_list(firstEntry);
#endif #endif
return QString(); return QString();

View file

@ -6,6 +6,9 @@
#include <QMap> #include <QMap>
#include <QMessageBox> #include <QMessageBox>
#include "version.h" #include "version.h"
#if defined WIN32 || !defined __GNUC__
#include <windows.h>
#endif
QMap<QString, SimulatorFactory *> registered_simulators; QMap<QString, SimulatorFactory *> registered_simulators;
@ -47,10 +50,15 @@ void registerSimulators()
simulatorsFound = true; simulatorsFound = true;
} }
#if defined(__APPLE__) || !( (!defined __GNUC__) || (defined __CYGWIN__) )
if (!simulatorsFound) { if (!simulatorsFound) {
#if defined(__APPLE__) #if defined(__APPLE__)
dir = QLibraryInfo::location(QLibraryInfo::PrefixPath) + "/Resources"; dir = QLibraryInfo::location(QLibraryInfo::PrefixPath) + "/Resources";
#elif (!defined __GNUC__)
char name[MAX_PATH];
GetModuleFileName(NULL, name, MAX_PATH);
QString path(name);
path.truncate(path.lastIndexOf('\\'));
dir.setPath(path);
#else #else
dir = SIMULATOR_LIB_SEARCH_PATH; dir = SIMULATOR_LIB_SEARCH_PATH;
#endif #endif
@ -59,7 +67,6 @@ void registerSimulators()
simulatorsFound = true; simulatorsFound = true;
} }
} }
#endif
} }
SimulatorFactory *getSimulatorFactory(const QString &name) SimulatorFactory *getSimulatorFactory(const QString &name)
@ -81,3 +88,9 @@ SimulatorFactory *getSimulatorFactory(const QString &name)
return NULL; return NULL;
} }
void unregisterSimulators()
{
foreach(SimulatorFactory *factory, registered_simulators) {
delete factory;
}
}

View file

@ -118,6 +118,7 @@ class SimulatorFactory {
}; };
void registerSimulators(); void registerSimulators();
void unregisterSimulators();
SimulatorFactory *getSimulatorFactory(const QString &name); SimulatorFactory *getSimulatorFactory(const QString &name);
extern QMap<QString, SimulatorFactory *> registered_simulators; extern QMap<QString, SimulatorFactory *> registered_simulators;

View file

@ -180,6 +180,9 @@ int main(int argc, char *argv[])
delete dialog; delete dialog;
unregisterSimulators();
unregisterOpenTxFirmwares();
#if defined(JOYSTICKS) || defined(SIMU_AUDIO) #if defined(JOYSTICKS) || defined(SIMU_AUDIO)
SDL_Quit(); SDL_Quit();
#endif #endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,7 @@ $Descr A4 11693 8268
encoding utf-8 encoding utf-8
Sheet 1 1 Sheet 1 1
Title "OpenTX board based on Arduino MEGA2560" Title "OpenTX board based on Arduino MEGA2560"
Date "18 jun 2015" Date "21 oct 2015"
Rev "0" Rev "0"
Comp "Copyright 2015 F. Aguerre" Comp "Copyright 2015 F. Aguerre"
Comment1 "" Comment1 ""
@ -1057,13 +1057,13 @@ Text Label 5650 5850 2 42 ~ 0
SW_Trn SW_Trn
Text GLabel 4850 5850 2 42 Input ~ 0 Text GLabel 4850 5850 2 42 Input ~ 0
port L 7 (1) port L 7 (1)
Text GLabel 4850 6250 2 42 Output ~ 0 Text GLabel 4850 6250 2 42 Input ~ 0
port B 3 (1) port B 3 (1)
Text Label 5650 6250 2 42 ~ 0 Text Label 5650 6250 2 42 ~ 0
SD_MISO SD_MISO
Text Label 6600 6250 2 42 ~ 0 Text Label 6600 6250 2 42 ~ 0
SD_MOSI SD_MOSI
Text GLabel 5800 6250 2 42 Input ~ 0 Text GLabel 5800 6250 2 42 Output ~ 0
port B 2 (1) port B 2 (1)
Text GLabel 5800 6350 2 42 Input ~ 0 Text GLabel 5800 6350 2 42 Input ~ 0
port B 0 (1) port B 0 (1)
@ -1278,7 +1278,7 @@ PPM_OUT
Text GLabel 2100 4600 1 42 Output ~ 0 Text GLabel 2100 4600 1 42 Output ~ 0
port B 6 (0) port B 6 (0)
Text GLabel 2000 4600 1 42 Input ~ 0 Text GLabel 2000 4600 1 42 Input ~ 0
port B 7 (0) port E 7 (0)
Text Label 5650 4850 2 42 ~ 0 Text Label 5650 4850 2 42 ~ 0
LCD_DATA0 LCD_DATA0
Text GLabel 4850 4850 2 42 Output ~ 0 Text GLabel 4850 4850 2 42 Output ~ 0
@ -41110,7 +41110,7 @@ CA 3B B1 B4 D6 FB 76 3A 4D 11 32 4D 1E A1 3D 78 1C 8B 1E 14 74 10 57 46 8C 97 FB
33 B3 93 2C A5 90 EC 7D 2B A5 BC 7A F5 EA E1 E1 5E 44 C8 BD 2E 90 84 08 60 87 C2 BB D7 FD 40 85 33 B3 93 2C A5 90 EC 7D 2B A5 BC 7A F5 EA E1 E1 5E 44 C8 BD 2E 90 84 08 60 87 C2 BB D7 FD 40 85
4A 52 6F 3D D0 6D 9E 6E 41 36 CA 77 04 97 99 83 92 6E D1 7C 20 6D 2C 33 D2 7F 5B 16 F2 83 51 39 4A 52 6F 3D D0 6D 9E 6E 41 36 CA 77 04 97 99 83 92 6E D1 7C 20 6D 2C 33 D2 7F 5B 16 F2 83 51 39
A0 3F CF F3 A7 9F 7E FA CB 5F FE F5 EB D7 AF 45 64 59 96 6D DB F6 23 3E B3 52 CA B3 1B C5 00 F7 A0 3F CF F3 A7 9F 7E FA CB 5F FE F5 EB D7 AF 45 64 59 96 6D DB F6 23 3E B3 52 CA B3 1B C5 00 F7
08 C0 CC FE 1F 15 4F 30 6D 3D C2 80 DE 00 00 00 00 49 45 4E 44 AE 42 60 82 00 $EndBitmap 08 C0 CC FE 1F 15 4F 30 6D 3D C2 80 DE 00 00 00 00 49 45 4E 44 AE 42 60 82 04 $EndBitmap
EndData EndData
$EndBitmap $EndBitmap
$Comp $Comp
@ -41427,7 +41427,7 @@ Wire Wire Line
Wire Wire Line Wire Wire Line
2100 4750 2100 4600 2100 4750 2100 4600
Wire Wire Line Wire Wire Line
2000 4750 2000 4600 2000 4600 2000 5550
Wire Wire Line Wire Wire Line
4700 4850 4850 4850 4700 4850 4850 4850
Wire Wire Line Wire Wire Line
@ -41863,4 +41863,8 @@ Wire Wire Line
5300 7500 5300 7600 5300 7500 5300 7600
Wire Wire Line Wire Wire Line
4800 7500 5300 7500 4800 7500 5300 7500
Wire Wire Line
2000 5550 2500 5550
Text Notes 2550 5550 0 50 ~ 0
Pin 9, can be soldered\nwith pin 8 (unused)
$EndSCHEMATC $EndSCHEMATC

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,14 @@
<h2>Version 2.1.4 / <set date></h2> <h2>Version 2.1.6 / 2015-11-11</h2>
[Taranis]
<ul>
<li>Fix for some X9E units which could not shutdown properly</li>
<li>Fixed a bug with negative altitudes in the Top bar (<a href=https://github.com/opentx/opentx/issues/3047>#3047</a>)</li>
</ul>
<h2>Version 2.1.5 / 2015-11-05</h2>
Notice: version 2.1.4 was skipped by the OpenTX team to avoid confusion with FrSky's release of OpenTX 2.1.4
[Taranis] [Taranis]
<ul> <ul>
@ -10,6 +20,11 @@
<li>Trainer mode fixes for X9E (<a href=https://github.com/opentx/opentx/issues/2913>#2913</a>)</li> <li>Trainer mode fixes for X9E (<a href=https://github.com/opentx/opentx/issues/2913>#2913</a>)</li>
<li>Fixed a bug that caused no servo movement when certain firmware option combinations were used (<a href=https://github.com/opentx/opentx/issues/2945>#2945</a>)</li> <li>Fixed a bug that caused no servo movement when certain firmware option combinations were used (<a href=https://github.com/opentx/opentx/issues/2945>#2945</a>)</li>
<li>Fixed missing arrows on RS, LS2, RS2 pot warnings on X9E (<a href=https://github.com/opentx/opentx/issues/2961>#2961</a>)</li> <li>Fixed missing arrows on RS, LS2, RS2 pot warnings on X9E (<a href=https://github.com/opentx/opentx/issues/2961>#2961</a>)</li>
<li>Fixed erroneous haptic feedback when using high powered UHF RF modules (<a href=https://github.com/opentx/opentx/issues/2722>#2722</a>)</li>
<li>The trainer icon will be shown only if valid PPM is received</li>
<li>Several Lua io library fixes (<a href=https://github.com/opentx/opentx/issues/3001>#3001</a>, <a href=https://github.com/opentx/opentx/issues/3003>#3003</a>)</li>
<li>Corrected failsafe mapping when using Custom failsafe mode, D16 protocol and channel range different from from 1-8.
Users with such setups are advised to re-check their failsafe settings (<a href=https://github.com/opentx/opentx/issues/2975>#2975</a>)</li>
</ul> </ul>
[ARM boards] [ARM boards]
@ -24,6 +39,8 @@
[Sky9x / 9XR-PRO / AR9X] [Sky9x / 9XR-PRO / AR9X]
<ul> <ul>
<li>Fixed navigation problem in Telemetry setup (<a href=https://github.com/opentx/opentx/issues/2951>#2951</a>)</li> <li>Fixed navigation problem in Telemetry setup (<a href=https://github.com/opentx/opentx/issues/2951>#2951</a>)</li>
<li>Fixed: Model Restore broken (<a href=https://github.com/opentx/opentx/issues/2797>#2797</a>)</li>
<li>Fixed battery indicator graphics (<a href=https://github.com/opentx/opentx/issues/2989>#2989</a>)</li>
</ul> </ul>
[AVR boards] [AVR boards]
@ -31,6 +48,11 @@
<li>Mavlink build option was not working (<a href=https://github.com/opentx/opentx/issues/2950>#2950</a>)</li> <li>Mavlink build option was not working (<a href=https://github.com/opentx/opentx/issues/2950>#2950</a>)</li>
</ul> </ul>
[Mega2560]
<ul>
<li>Fixed : mixer update rate was too slow (<a href=https://github.com/opentx/opentx/issues/2750>#2750</a>)</li>
</ul>
<h2>Version 2.1.3 / 2015-09-09</h2> <h2>Version 2.1.3 / 2015-09-09</h2>
@ -691,4 +713,4 @@ Nothing new (only Companion fixes)
<li>New menu in Main Views / Telemetry Views</li> <li>New menu in Main Views / Telemetry Views</li>
<li>Vario sounds improved!</li> <li>Vario sounds improved!</li>
<li>SD Folders renamed. "9XSOUNDS" becomes "SOUNDS", don't forget to update your SD card!</li> <li>SD Folders renamed. "9XSOUNDS" becomes "SOUNDS", don't forget to update your SD card!</li>
</ul> </ul>

View file

@ -379,6 +379,10 @@ WATCHDOG_TEST = NO
# Values = NO, YES # Values = NO, YES
WARNINGS_AS_ERRORS = NO WARNINGS_AS_ERRORS = NO
# Enable saving of Lua byte-code of all loaded scripts
# Values = NO, YES
LUA_COMPILER = NO
#------- END BUILD OPTIONS --------------------------- #------- END BUILD OPTIONS ---------------------------
# Define programs and commands. # Define programs and commands.
@ -1029,12 +1033,12 @@ ifeq ($(PCB), TARANIS)
endif endif
CPPDEFS += -DLUA CPPDEFS += -DLUA
INCDIRS += $(LUADIR) 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 \ 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)/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 $(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) SRC += $(LUASRC)
LUADEP = lua_exports_taranis.inc LUADEP = lua/lua_exports_taranis.inc
ifeq ($(USE_BIN_ALLOCATOR), YES) ifeq ($(USE_BIN_ALLOCATOR), YES)
CPPDEFS += -DUSE_BIN_ALLOCATOR CPPDEFS += -DUSE_BIN_ALLOCATOR
CPPSRC += bin_allocator.cpp 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)/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 $(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) SRC += $(LUASRC)
LUADEP = lua_exports_flamenco.inc LUADEP = lua/lua_exports_flamenco.inc
endif endif
EXTRABOARDSRC += $(FATFSDIR)/ff.c $(FATFSDIR)/fattime.c $(FATFSDIR)/option/ccsbcs.c targets/Flamenco/diskio.cpp 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)/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 $(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) SRC += $(LUASRC)
LUADEP = lua_exports_horus.inc LUADEP = lua/lua_exports_horus.inc
endif endif
EXTRABOARDSRC += $(FATFSDIR)/ff.c $(FATFSDIR)/fattime.c $(FATFSDIR)/option/ccsbcs.c targets/Horus/diskio.cpp EXTRABOARDSRC += $(FATFSDIR)/ff.c $(FATFSDIR)/fattime.c $(FATFSDIR)/option/ccsbcs.c targets/Horus/diskio.cpp
@ -1667,6 +1671,10 @@ ifeq ($(IRPROTOS), YES)
CPPDEFS += -DIRPROTOS CPPDEFS += -DIRPROTOS
endif endif
ifeq ($(LUA_COMPILER), YES)
CPPDEFS += -DLUA_COMPILER
endif
#---------------- Compiler Options C++ ---------------- #---------------- Compiler Options C++ ----------------
# -g*: generate debugging information # -g*: generate debugging information
# -O*: optimization level # -O*: optimization level
@ -1924,25 +1932,25 @@ else
PARSER = gcc -E -x c++ PARSER = gcc -E -x c++
endif 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" @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 @$(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" @echo "Parsing and generating C Lua exports in lua/lua_exports_taranis.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_taranis.txt lua_exports_taranis.inc lua_fields_taranis.txt @$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_taranis.txt lua/lua_exports_taranis.inc lua_fields_taranis.txt
@rm lua_exports_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" @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 @$(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" @echo "Parsing and generating C Lua exports in lua/lua_exports_horus.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_horus.txt lua_exports_horus.inc lua_fields_horus.txt @$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_horus.txt lua/lua_exports_horus.inc lua_fields_horus.txt
@rm lua_exports_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" @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 @$(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" @echo "Parsing and generating C Lua exports in lua/lua_exports_flamenco.inc"
@$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_flamenco.txt lua_exports_flamenco.inc lua_fields_flamenco.txt @$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_flamenco.txt lua/lua_exports_flamenco.inc lua_fields_flamenco.txt
@rm lua_exports_flamenco.txt @rm lua_exports_flamenco.txt
# Eye candy. # Eye candy.
@ -2101,7 +2109,7 @@ clean_list :
$(REMOVE) bitmaps/*.lbm $(REMOVE) bitmaps/*.lbm
$(REMOVE) bitmaps/*/*.lbm $(REMOVE) bitmaps/*/*.lbm
$(REMOVE) fonts/*/*.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 $(MAKE) -C targets/Taranis/bootloader clean
#### Install #### Install

View file

@ -441,8 +441,8 @@ void cliTask(void * pdata)
else if (c == 127) { else if (c == 127) {
// backspace // backspace
if (pos) { if (pos) {
line[--pos] = '\0'; line[--pos] = '\0';
serialPutc(c); serialPutc(c);
} }
} }
else if (c == '\r' || c == '\n') { else if (c == '\r' || c == '\n') {

View file

@ -367,8 +367,10 @@ void evalFunctions()
} }
#if defined(CPUARM) #if defined(CPUARM)
if (CFN_PARAM(cfn)>=FUNC_RESET_PARAM_FIRST_TELEM) { if (CFN_PARAM(cfn)>=FUNC_RESET_PARAM_FIRST_TELEM) {
TelemetryItem * telemetryItem = & telemetryItems[CFN_PARAM(cfn)-FUNC_RESET_PARAM_FIRST_TELEM]; uint8_t item = CFN_PARAM(cfn)-FUNC_RESET_PARAM_FIRST_TELEM;
telemetryItem->clear(); if (item < MAX_SENSORS) {
telemetryItems[item].clear();
}
} }
#endif #endif
break; break;

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) 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]; TelemetryItem & telemetryItem = telemetryItems[channel];
TelemetrySensor & telemetrySensor = g_model.telemetrySensors[channel]; TelemetrySensor & telemetrySensor = g_model.telemetrySensors[channel];
if (telemetrySensor.unit == UNIT_DATETIME) { 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: case TELEM_TX_VOLTAGE-1:
lcd_outdezAtt(x, y, val, (att|PREC1) & (~NO_UNIT)); lcd_outdezAtt(x, y, val, (att|PREC1) & (~NO_UNIT));
if (!(att & NO_UNIT)) if (!(att & NO_UNIT))
lcd_putc(lcdLastPos/*+1*/, y, 'v'); lcd_putc(lcdLastPos/*+1*/, y, 'V');
break; break;
} }
} }

View file

@ -262,6 +262,13 @@ void lcdInit();
void lcdRefresh(); 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) #if defined(BOOT)
#define BLINK_ON_PHASE (0) #define BLINK_ON_PHASE (0)
#else #else

View file

@ -185,7 +185,11 @@ void menuModelLogicalSwitchOne(uint8_t event)
else { else {
#if defined(FRSKY) #if defined(FRSKY)
if (v1_val >= MIXSRC_FIRST_TELEM) { 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); putsTelemetryChannelValue(CSWONE_2ND_COLUMN, y, v1_val - MIXSRC_FIRST_TELEM, convertLswTelemValue(cs), attr|LEFT);
#endif
v2_max = maxTelemValue(v1_val - MIXSRC_FIRST_TELEM + 1); v2_max = maxTelemValue(v1_val - MIXSRC_FIRST_TELEM + 1);
if (cs->func == LS_FUNC_DIFFEGREATER) if (cs->func == LS_FUNC_DIFFEGREATER)
v2_min = -v2_max; v2_min = -v2_max;
@ -295,7 +299,11 @@ void menuModelLogicalSwitches(uint8_t event)
uint8_t v1 = cs->v1; uint8_t v1 = cs->v1;
putsMixerSource(CSW_2ND_COLUMN, y, v1, 0); putsMixerSource(CSW_2ND_COLUMN, y, v1, 0);
if (v1 >= MIXSRC_FIRST_TELEM) { 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); putsTelemetryChannelValue(CSW_3RD_COLUMN, y, v1 - MIXSRC_FIRST_TELEM, convertLswTelemValue(cs), LEFT);
#endif
} }
else { else {
lcd_outdezAtt(CSW_3RD_COLUMN, y, cs->v2, LEFT); lcd_outdezAtt(CSW_3RD_COLUMN, y, cs->v2, LEFT);

View file

@ -42,7 +42,7 @@
#define RBOX_CENTERX (3*LCD_W/4 - 10) #define RBOX_CENTERX (3*LCD_W/4 - 10)
#define MODELNAME_X (2*FW-2) #define MODELNAME_X (2*FW-2)
#define MODELNAME_Y (0) #define MODELNAME_Y (0)
#define PHASE_X (6*FW) #define PHASE_X (6*FW-1)
#define PHASE_Y (2*FH) #define PHASE_Y (2*FH)
#define PHASE_FLAGS 0 #define PHASE_FLAGS 0
#define VBATT_X (6*FW) #define VBATT_X (6*FW)
@ -206,13 +206,13 @@ void displayBattVoltage()
{ {
#if defined(BATTGRAPH) #if defined(BATTGRAPH)
putsVBat(VBATT_X-8, VBATT_Y+1, 0); putsVBat(VBATT_X-8, VBATT_Y+1, 0);
drawFilledRect(VBATT_X-25, VBATT_Y+9, 22, 5); drawFilledRect(VBATT_X-25, VBATT_Y+9, 21, 5);
lcd_vline(VBATT_X-3, VBATT_Y+10, 3); lcd_vline(VBATT_X-4, VBATT_Y+10, 3);
uint8_t count = GET_TXBATT_BARS(); uint8_t count = GET_TXBATT_BARS();
for (uint8_t i=0; i<count; i+=2) for (uint8_t i=0; i<count; i+=2)
lcd_vline(VBATT_X-24+i, VBATT_Y+10, 3); lcd_vline(VBATT_X-24+i, VBATT_Y+10, 3);
if (!IS_TXBATT_WARNING() || BLINK_ON_PHASE) if (!IS_TXBATT_WARNING() || BLINK_ON_PHASE)
drawFilledRect(VBATT_X-26, VBATT_Y, 25, 15); drawFilledRect(VBATT_X-26, VBATT_Y, 24, 15);
#else #else
LcdFlags att = (IS_TXBATT_WARNING() ? BLINK|INVERS : 0) | BIGSIZE; LcdFlags att = (IS_TXBATT_WARNING() ? BLINK|INVERS : 0) | BIGSIZE;
putsVBat(VBATT_X-1, VBATT_Y, att|NO_UNIT); putsVBat(VBATT_X-1, VBATT_Y, att|NO_UNIT);

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) { else if (idx == SWSRC_TELEMETRY_STREAMING) {
lcdDrawText(x, y, "Tele", att); 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 { else {
lcdDrawTextWithLen(x, y, g_model.telemetrySensors[idx-SWSRC_FIRST_SENSOR].label, TELEM_LABEL_LEN, ZCHAR|att); 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) 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]; TelemetryItem & telemetryItem = telemetryItems[channel];
TelemetrySensor & telemetrySensor = g_model.telemetrySensors[channel]; TelemetrySensor & telemetrySensor = g_model.telemetrySensors[channel];
if (telemetrySensor.unit == UNIT_DATETIME) { if (telemetrySensor.unit == UNIT_DATETIME) {

View file

@ -120,8 +120,10 @@ void menuModelFlightModesAll(uint8_t event)
break; break;
case ITEM_FLIGHT_MODES_SWITCH: case ITEM_FLIGHT_MODES_SWITCH:
putsSwitches((5+LEN_FLIGHT_MODE_NAME)*FW+FW/2, y, p->swtch, attr); if (k>0) {
if (active) CHECK_INCDEC_MODELSWITCH(event, p->swtch, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, isSwitchAvailableInMixes); 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; break;
case ITEM_FLIGHT_MODES_TRIM_RUD: case ITEM_FLIGHT_MODES_TRIM_RUD:

View file

@ -645,17 +645,14 @@ void menuModelSetup(uint8_t event)
if (checkIncDec_Ret) { if (checkIncDec_Ret) {
g_model.moduleData[INTERNAL_MODULE].rfProtocol = 0; g_model.moduleData[INTERNAL_MODULE].rfProtocol = 0;
g_model.moduleData[INTERNAL_MODULE].channelsStart = 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;
g_model.moduleData[INTERNAL_MODULE].channelsCount = 0;
else
g_model.moduleData[INTERNAL_MODULE].channelsCount = MAX_INTERNAL_MODULE_CHANNELS();
} }
break; break;
case 1: case 1:
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[INTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST); CHECK_INCDEC_MODELVAR(event, g_model.moduleData[INTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST);
if (checkIncDec_Ret) { if (checkIncDec_Ret) {
g_model.moduleData[INTERNAL_MODULE].channelsStart = 0; 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) { if (attr) {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[0].rfProtocol, RF_PROTO_OFF, RF_PROTO_LAST); CHECK_INCDEC_MODELVAR(event, g_model.moduleData[0].rfProtocol, RF_PROTO_OFF, RF_PROTO_LAST);
if (checkIncDec_Ret) { if (checkIncDec_Ret) {
g_model.moduleData[0].type = MODULE_TYPE_XJT;
g_model.moduleData[0].channelsStart = 0; g_model.moduleData[0].channelsStart = 0;
g_model.moduleData[0].channelsCount = 0; g_model.moduleData[0].channelsCount = 0;
} }
@ -695,10 +693,8 @@ void menuModelSetup(uint8_t event)
if (checkIncDec_Ret) { if (checkIncDec_Ret) {
g_model.moduleData[EXTERNAL_MODULE].rfProtocol = 0; g_model.moduleData[EXTERNAL_MODULE].rfProtocol = 0;
g_model.moduleData[EXTERNAL_MODULE].channelsStart = 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;
g_model.moduleData[EXTERNAL_MODULE].channelsCount = 0;
else
g_model.moduleData[EXTERNAL_MODULE].channelsCount = MAX_EXTERNAL_MODULE_CHANNELS();
} }
break; break;
case 1: 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); CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST);
if (checkIncDec_Ret) { if (checkIncDec_Ret) {
g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0; 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 { else {
horzpos_t l_posHorz = m_posHorz; horzpos_t l_posHorz = m_posHorz;
coord_t xOffsetBind = MODEL_SETUP_BIND_OFS; 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; xOffsetBind = 0;
lcd_putsLeft(y, INDENT "Receiver"); lcd_putsLeft(y, INDENT "Receiver");
if (attr) l_posHorz += 1; if (attr) l_posHorz += 1;
@ -871,14 +867,16 @@ void menuModelFailsafe(uint8_t event)
static bool longNames = false; static bool longNames = false;
bool newLongNames = false; bool newLongNames = false;
uint8_t ch = 0; uint8_t ch = 0;
uint8_t channelStart = g_model.moduleData[g_moduleIdx].channelsStart;
if (event == EVT_KEY_LONG(KEY_ENTER)) { if (event == EVT_KEY_LONG(KEY_ENTER)) {
killEvents(event); killEvents(event);
event = 0; event = 0;
if (s_editMode) { 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); storageDirty(EE_MODEL);
AUDIO_WARNING1(); AUDIO_WARNING1();
s_editMode = 0;
SEND_FAILSAFE_NOW(g_moduleIdx); SEND_FAILSAFE_NOW(g_moduleIdx);
} }
else { else {
@ -888,14 +886,14 @@ void menuModelFailsafe(uint8_t event)
else if (failsafe == FAILSAFE_CHANNEL_HOLD) else if (failsafe == FAILSAFE_CHANNEL_HOLD)
failsafe = FAILSAFE_CHANNEL_NOPULSE; failsafe = FAILSAFE_CHANNEL_NOPULSE;
else else
failsafe = channelOutputs[m_posVert]; failsafe = 0;
storageDirty(EE_MODEL); storageDirty(EE_MODEL);
AUDIO_WARNING1(); AUDIO_WARNING1();
SEND_FAILSAFE_NOW(g_moduleIdx); SEND_FAILSAFE_NOW(g_moduleIdx);
} }
} }
SIMPLE_SUBMENU_NOTITLE(NUM_CHNOUT); SIMPLE_SUBMENU_NOTITLE(NUM_CHANNELS(g_moduleIdx));
SET_SCROLLBAR_X(0); SET_SCROLLBAR_X(0);
@ -904,10 +902,6 @@ void menuModelFailsafe(uint8_t event)
// Column separator // Column separator
lcd_vline(LCD_W/2, FH, LCD_H-FH); lcd_vline(LCD_W/2, FH, LCD_H-FH);
if (m_posVert >= 16) {
ch = 16;
}
lcd_putsCenter(0*FH, FAILSAFESET); lcd_putsCenter(0*FH, FAILSAFESET);
lcd_invert_line(0); lcd_invert_line(0);
@ -919,77 +913,78 @@ void menuModelFailsafe(uint8_t event)
// Channels // Channels
for (uint8_t line=0; line<8; line++) { for (uint8_t line=0; line<8; line++) {
coord_t y = 9+line*7; coord_t y = 9+line*7;
int32_t channelValue = channelOutputs[ch]; int32_t channelValue = channelOutputs[ch+channelStart];
int32_t failsafeValue = 0; int32_t failsafeValue = 0;
bool failsafeEditable = false; bool failsafeEditable = false;
uint8_t ofs = (col ? 0 : 1); 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]; failsafeValue = g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line];
failsafeEditable = true; failsafeEditable = true;
} }
// Channel name if present, number if not if (failsafeEditable) {
uint8_t lenLabel = ZLEN(g_model.limitData[ch].name); // Channel name if present, number if not
if (lenLabel > 4) { uint8_t lenLabel = ZLEN(g_model.limitData[ch+channelStart].name);
newLongNames = longNames = true; if (lenLabel > 4) {
} newLongNames = longNames = true;
}
if (lenLabel > 0) if (lenLabel > 0)
lcdDrawTextWithLen(x+1-ofs, y, g_model.limitData[ch].name, sizeof(g_model.limitData[ch].name), ZCHAR | SMLSIZE); lcdDrawTextWithLen(x+1-ofs, y, g_model.limitData[ch+channelStart].name, sizeof(g_model.limitData[ch+channelStart].name), ZCHAR | SMLSIZE);
else else
putsChn(x+1-ofs, y, ch+1, SMLSIZE); putsChn(x+1-ofs, y, ch+1, SMLSIZE);
// Value // Value
LcdFlags flags = TINSIZE; LcdFlags flags = TINSIZE;
if (m_posVert == ch) { if (m_posVert == ch) {
flags |= INVERS; flags |= INVERS;
if (s_editMode) { if (s_editMode) {
if (!failsafeEditable || failsafeValue == FAILSAFE_CHANNEL_HOLD || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) { if (failsafeValue == FAILSAFE_CHANNEL_HOLD || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
s_editMode = 0; s_editMode = 0;
} }
else { else {
flags |= BLINK; flags |= BLINK;
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line], -lim, +lim); CHECK_INCDEC_MODELVAR(event, g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line], -lim, +lim);
}
} }
} }
}
#if defined(PPM_UNIT_PERCENT_PREC1) #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 #else
uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W); uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W);
#endif #endif
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) { if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "HOLD", flags); lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "HOLD", flags);
failsafeValue = 0; failsafeValue = 0;
} }
else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) { else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "NONE", flags); lcdDrawText(x+COL_W-4-wbar-ofs-16, y, "NONE", flags);
failsafeValue = 0; failsafeValue = 0;
} }
else { else {
#if defined(PPM_UNIT_US) #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) #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 #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 #endif
} }
// Gauge // Gauge
lcdDrawRect(x+COL_W-3-wbar-ofs, y, wbar+1, 6); 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 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)); 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 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; 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+1, lenChannel, DOTTED, 0);
lcdDrawHorizontalLine(xChannel, y+2, lenChannel, DOTTED, 0); lcdDrawHorizontalLine(xChannel, y+2, lenChannel, DOTTED, 0);
lcd_hline(xFailsafe, y+3, lenFailsafe); lcd_hline(xFailsafe, y+3, lenFailsafe);
lcd_hline(xFailsafe, y+4, lenFailsafe); lcd_hline(xFailsafe, y+4, lenFailsafe);
}
ch++; ch++;
} }
} }

View file

@ -164,12 +164,8 @@ enum SensorFields {
bool isSensorUnit(int sensor, uint8_t unit) bool isSensorUnit(int sensor, uint8_t unit)
{ {
if (sensor == 0) if (sensor <= 0 || sensor > MAX_SENSORS ) return true;
return true; return g_model.telemetrySensors[--sensor].unit == unit;
sensor -= 1;
return g_model.telemetrySensors[sensor].unit == unit;
} }
bool isCellsSensor(int sensor) bool isCellsSensor(int sensor)
@ -184,7 +180,7 @@ bool isGPSSensor(int sensor)
bool isAltSensor(int sensor) bool isAltSensor(int sensor)
{ {
return isSensorUnit(sensor, UNIT_DIST); return isSensorUnit(sensor, UNIT_DIST) || isSensorUnit(sensor, UNIT_FEET);
} }
bool isVoltsSensor(int sensor) bool isVoltsSensor(int sensor)

View file

@ -236,22 +236,26 @@ void displayTopBar()
/* Rx voltage */ /* Rx voltage */
altitude_icon_x = batt_icon_x+7*FW+3; altitude_icon_x = batt_icon_x+7*FW+3;
if (g_model.frsky.voltsSource) { if (g_model.frsky.voltsSource) {
TelemetryItem & voltsItem = telemetryItems[g_model.frsky.voltsSource-1]; uint8_t item = g_model.frsky.voltsSource-1;
if (voltsItem.isAvailable()) { if (item < MAX_SENSORS) {
putsTelemetryChannelValue(batt_icon_x+7*FW+2, BAR_Y+1, g_model.frsky.voltsSource-1, voltsItem.value, LEFT); TelemetryItem & voltsItem = telemetryItems[item];
altitude_icon_x = lcdLastPos+1; if (voltsItem.isAvailable()) {
putsTelemetryChannelValue(batt_icon_x+7*FW+2, BAR_Y+1, item, voltsItem.value, LEFT);
altitude_icon_x = lcdLastPos+1;
}
} }
} }
/* Altitude */ /* Altitude */
if (g_model.frsky.altitudeSource) { if (g_model.frsky.altitudeSource) {
TelemetryItem & altitudeItem = telemetryItems[g_model.frsky.altitudeSource-1]; uint8_t item = g_model.frsky.altitudeSource-1;
if (altitudeItem.isAvailable()) { if (item < MAX_SENSORS) {
LCD_ICON(altitude_icon_x, BAR_Y, ICON_ALTITUDE); TelemetryItem & altitudeItem = telemetryItems[item];
int32_t value = altitudeItem.value; if (altitudeItem.isAvailable()) {
TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1]; LCD_ICON(altitude_icon_x, BAR_Y, ICON_ALTITUDE);
if (sensor.prec) value /= sensor.prec == 2 ? 100 : 10; int32_t value = altitudeItem.value / g_model.telemetrySensors[item].getPrecDivisor();
putsValueWithUnit(altitude_icon_x+2*FW-1, BAR_Y+1, value, UNIT_METERS, LEFT); 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 (TRAINER_CONNECTED()) {
if (SLAVE_MODE()) { if (SLAVE_MODE()) {
LCD_NOTIF_ICON(x, ICON_TRAINEE); LCD_NOTIF_ICON(x, ICON_TRAINEE);
x -= 12;
} }
else { else if (IS_TRAINER_INPUT_VALID()) {
LCD_NOTIF_ICON(x, ICON_TRAINER); LCD_NOTIF_ICON(x, ICON_TRAINER);
x -= 12;
} }
x -= 12;
} }
if (isFunctionActive(FUNCTION_LOGS)) { if (isFunctionActive(FUNCTION_LOGS)) {

1
radio/src/lua/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/lua_exports_*.inc

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
radio/src/lua/api_lcd.cpp Normal file
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
radio/src/lua/api_model.cpp Normal file
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
radio/src/lua/interface.cpp Normal file
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);
}

View file

@ -34,18 +34,42 @@
* *
*/ */
#ifndef luaapi_h #ifndef lua_api_h
#define luaapi_h #define lua_api_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)
#if defined(LUA) #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 { struct ScriptInput {
const char *name; const char *name;
uint8_t type; uint8_t type;
@ -98,11 +122,11 @@
void luaExec(const char * filename); void luaExec(const char * filename);
void luaError(uint8_t error, bool acknowledge=true); void luaError(uint8_t error, bool acknowledge=true);
int luaGetMemUsed(); int luaGetMemUsed();
void luaGetValueAndPush(int src);
#define luaGetCpuUsed(idx) scriptInternalData[idx].instructions #define luaGetCpuUsed(idx) scriptInternalData[idx].instructions
uint8_t isTelemetryScriptAvailable(uint8_t index); uint8_t isTelemetryScriptAvailable(uint8_t index);
#define LUA_LOAD_MODEL_SCRIPTS() luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS #define LUA_LOAD_MODEL_SCRIPTS() luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS
#define LUA_LOAD_MODEL_SCRIPT(idx) 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 // Lua PROTECT/UNPROTECT
#include <setjmp.h> #include <setjmp.h>
struct our_longjmp { struct our_longjmp {
@ -119,10 +143,11 @@
extern uint16_t maxLuaInterval; extern uint16_t maxLuaInterval;
extern uint16_t maxLuaDuration; 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

View file

@ -43,6 +43,9 @@ void perMain()
{ {
#if defined(SIMU) #if defined(SIMU)
doMixerCalculations(); doMixerCalculations();
#endif
#if defined(LCD_ST7920)
uint8_t lcdstate=0;
#endif #endif
uint16_t t0 = getTmr16KHz(); uint16_t t0 = getTmr16KHz();
int16_t delta = (nextMixerEndTime - lastMixerDuration) - t0; int16_t delta = (nextMixerEndTime - lastMixerDuration) - t0;
@ -129,32 +132,37 @@ void perMain()
const char *warn = s_warning; const char *warn = s_warning;
uint8_t menu = s_menu_count; uint8_t menu = s_menu_count;
lcdClear(); if (IS_LCD_REFRESH_ALLOWED()) { // No need to redraw until lcdRefresh_ST7920(0) below completely refreshes the display.
if (menuEvent) { lcdClear();
m_posVert = menuEvent == EVT_ENTRY_UP ? g_menuPos[g_menuStackPtr] : 0; if (menuEvent) {
m_posHorz = 0; m_posVert = menuEvent == EVT_ENTRY_UP ? g_menuPos[g_menuStackPtr] : 0;
evt = menuEvent; m_posHorz = 0;
menuEvent = 0; evt = menuEvent;
AUDIO_MENUS(); menuEvent = 0;
} AUDIO_MENUS();
g_menuStack[g_menuStackPtr]((warn || menu) ? 0 : evt); }
g_menuStack[g_menuStackPtr]((warn || menu) ? 0 : evt);
if (warn) DISPLAY_WARNING(evt); if (warn) DISPLAY_WARNING(evt);
#if defined(NAVIGATION_MENUS) #if defined(NAVIGATION_MENUS)
if (menu) { if (menu) {
const char * result = displayMenu(evt); const char * result = displayMenu(evt);
if (result) { if (result) {
menuHandler(result); menuHandler(result);
}
} }
}
#endif #endif
drawStatusLine();
drawStatusLine(); }
#if defined(LCD_ST7920)
lcdstate = lcdRefresh_ST7920(0);
#else
lcdRefresh(); lcdRefresh();
#endif #endif
#endif // defined(GUI)
if (SLAVE_MODE()) { if (SLAVE_MODE()) {
JACK_PPM_OUT(); JACK_PPM_OUT();
} }

View file

@ -179,6 +179,7 @@ int16_t applyLimits(uint8_t channel, int32_t value)
} }
#endif #endif
int16_t ofs = LIMIT_OFS_RESX(lim); int16_t ofs = LIMIT_OFS_RESX(lim);
int16_t lim_p = LIMIT_MAX_RESX(lim); int16_t lim_p = LIMIT_MAX_RESX(lim);
int16_t lim_n = LIMIT_MIN_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 PORTH &= ~0x40; // PORTH:6 HIGH->LOW signals end of mixer interrupt
#endif #endif
} }

View file

@ -560,7 +560,7 @@ enum PotsWarnMode {
TRAINER_MODULE TRAINER_MODULE
}; };
enum TrainerMode { enum TrainerMode {
TRAINER_MODE_MASTER, TRAINER_MODE_MASTER_TRAINER_JACK,
TRAINER_MODE_SLAVE, TRAINER_MODE_SLAVE,
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE, TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
TRAINER_MODE_MASTER_CPPM_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(const char *label, uint8_t unit=UNIT_RAW, uint8_t prec=0);
void init(uint16_t id); void init(uint16_t id);
bool isAvailable(); bool isAvailable() const;
int32_t getValue(int32_t value, uint8_t unit, uint8_t prec) const; int32_t getValue(int32_t value, uint8_t unit, uint8_t prec) const;
bool isConfigurable(); bool isConfigurable() const;
bool isPrecConfigurable(); bool isPrecConfigurable() const;
int32_t getPrecMultiplier() const;
int32_t getPrecDivisor() const;
}) TelemetrySensor; }) TelemetrySensor;
#endif #endif
@ -2201,11 +2203,7 @@ enum RFProtocols {
#endif #endif
}; };
#if defined(MODULE_D16_EU_ONLY_SUPPORT) #define HAS_RF_PROTOCOL_FAILSAFE(protocol) ((protocol) == RF_PROTO_X16)
#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
enum DSM2Protocols { enum DSM2Protocols {
DSM2_PROTO_LP45, DSM2_PROTO_LP45,

View file

@ -1173,10 +1173,10 @@ extern const char vers_stamp[];
#endif #endif
extern uint8_t g_vbat100mV; extern uint8_t g_vbat100mV;
#if defined(CPUARM) #if defined(PCBTARANIS)
#define GET_TXBATT_BARS() (min(10, 10 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin))) #define GET_TXBATT_BARS() (limit<int8_t>(0, 10 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 10))
#else #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 #endif
#define IS_TXBATT_WARNING() (g_vbat100mV <= g_eeGeneral.vBatWarn) #define IS_TXBATT_WARNING() (g_vbat100mV <= g_eeGeneral.vBatWarn)
@ -1783,7 +1783,7 @@ void varioWakeup();
extern void usbPluggedIn(); extern void usbPluggedIn();
#endif #endif
#include "lua_api.h" #include "lua/lua_api.h"
#if defined(SDCARD) #if defined(SDCARD)
enum ClipboardType { enum ClipboardType {

View file

@ -231,8 +231,7 @@ void setupPulsesPXX(unsigned int port)
} }
else { else {
if (i < sendUpperChannels) { if (i < sendUpperChannels) {
int channel = 8 + g_model.moduleData[port].channelsStart + i; int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[8+i];
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[channel];
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) { if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
pulseValue = 4095; pulseValue = 4095;
} }
@ -240,13 +239,12 @@ void setupPulsesPXX(unsigned int port)
pulseValue = 2048; pulseValue = 2048;
} }
else { 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); pulseValue = limit(2049, (failsafeValue * 512 / 682) + 3072, 4094);
} }
} }
else { else {
int channel = g_model.moduleData[port].channelsStart + i; int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[i];
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[channel];
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) { if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
pulseValue = 2047; pulseValue = 2047;
} }
@ -254,7 +252,7 @@ void setupPulsesPXX(unsigned int port)
pulseValue = 0; pulseValue = 0;
} }
else { 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); pulseValue = limit(1, (failsafeValue * 512 / 682) + 1024, 2046);
} }
} }
@ -289,7 +287,7 @@ void setupPulsesPXX(unsigned int port)
/* CRC16 */ /* CRC16 */
putPcmByte(0, port); putPcmByte(0, port);
pulseValue = modulePulsesData[port].pxx.pcmCrc; pulseValue = modulePulsesData[port].pxx.pcmCrc;
putPcmByte(pulseValue>>8, port); putPcmByte(pulseValue >> 8, port);
putPcmByte(pulseValue, port); putPcmByte(pulseValue, port);
/* Sync */ /* Sync */

View file

@ -60,11 +60,7 @@ const char * sdCheckAndCreateDirectory(const char * path)
bool isFileAvailable(const char * path) bool isFileAvailable(const char * path)
{ {
FILINFO info; return f_stat(path, 0) == FR_OK;
TCHAR lfn[_MAX_LFN + 1];
info.lfname = lfn;
info.lfsize = sizeof(lfn);
return f_stat(path, &info) == FR_OK;
} }
bool isFileAvailable(const char * filename, const char * directory) bool isFileAvailable(const char * filename, const char * directory)

View file

@ -611,22 +611,25 @@ const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name)
eepromEraseBlock(address+EEPROM_BLOCK_SIZE); eepromEraseBlock(address+EEPROM_BLOCK_SIZE);
// write header // write header
EepromFileHeader header = { uint16_t(i_fileDst+1), size }; EepromFileHeader * header = (EepromFileHeader *)eepromWriteBuffer;
eepromWrite(address, (uint8_t *)&header, sizeof(header)); header->fileIndex = i_fileDst+1;
address += sizeof(header); header->size = size;
int offset = 4;
// write model // write model
while (size > 0) { do {
uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE); uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE-offset);
result = f_read(&restoreFile, eepromWriteBuffer, blockSize, &read); result = f_read(&restoreFile, eepromWriteBuffer+offset, blockSize, &read);
if (result != FR_OK || read != blockSize) { if (result != FR_OK || read != blockSize) {
f_close(&g_oLogFile); f_close(&g_oLogFile);
return SDCARD_ERROR(result); return SDCARD_ERROR(result);
} }
eepromWrite(address, eepromWriteBuffer, blockSize); eepromWrite(address, eepromWriteBuffer, blockSize+offset);
size -= blockSize; size -= blockSize;
address += blockSize; address += EEPROM_BUFFER_SIZE;
} offset = 0;
} while (size > 0);
// write FAT // write FAT
eepromHeader.files[i_fileDst+1].exists = 1; eepromHeader.files[i_fileDst+1].exists = 1;

View file

@ -150,17 +150,65 @@ void lcdSetRefVolt(uint8_t val)
#endif #endif
} }
#if defined(LCD_ST7920)
void lcdRefresh(){
lcdRefresh_ST7920(1);
}
uint8_t lcdRefresh_ST7920(uint8_t full)
{
#else
void lcdRefresh() void lcdRefresh()
{ {
#endif
LCD_LOCK(); LCD_LOCK();
#if defined(LCD_ST7920) #if defined(LCD_ST7920)
static uint8_t state;
uint8_t yst,yend;
uint8_t x_addr = 0; uint8_t x_addr = 0;
uint8_t y_addr = 0; uint8_t y_addr = 0;
uint16_t line_offset = 0; uint16_t line_offset = 0;
uint8_t col_offset = 0; uint8_t col_offset = 0;
uint16_t byte_offset = 0;
uint8_t bit_count = 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; x_addr = 0;
//Convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays) //Convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays)
if (y > 31) { if (y > 31) {
@ -170,20 +218,28 @@ void lcdRefresh()
else { else {
y_addr = y; y_addr = y;
} }
lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address
_delay_us(49); _delay_us(49);
lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address
_delay_us(49); _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_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_RnW); //Write data register mode
bit_count = y & 0x07; //Count from 0 bis 7 -> 0=0, 1=1..7=7, 8=0, 9=1... 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 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 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) 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 p=displayBuf + 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 // 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 left-most position of the byte to the ST7920 // the position of the LSB is the right-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); 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); PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
_delay_us(8); _delay_us(8);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E); PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
@ -216,4 +272,8 @@ void lcdRefresh()
} }
#endif #endif
LCD_UNLOCK(); LCD_UNLOCK();
#if defined(LCD_ST7920)
return state;
#endif
} }

View file

@ -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****/

View file

@ -4,6 +4,5 @@ MEGA2560 board
DIY radio wih : DIY radio wih :
- Arduino MEGA2560 or compatible - Arduino MEGA2560 or compatible
- Gruvin9x features (soft-off, SD-Card, RTC, haptic, voice, rotary encoders) - Gruvin9x features (soft-off, SD-Card, RTC, haptic, voice, rotary encoders)
- LCD 128x64 Artronic (ST7565R) or Zolen (ST7565P) - LCD 128x64 8 bits parallel mode
- Aurora9 or T9X gimballs
- home made case - home made case

View file

@ -42,13 +42,17 @@ inline void boardInit()
{ {
// Set up I/O port data directions and initial states (unused pin setting : input, pull-up on) // Set up I/O port data directions and initial states (unused pin setting : input, pull-up on)
DDRA = 0b11111111; PORTA = 0b00000000; // LCD data 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 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 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 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 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 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 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) 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 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

View file

@ -111,7 +111,7 @@ void sdPoll10ms(void);
# define INP_L_Trainer 7 # define INP_L_Trainer 7
// Servitudes driver // 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_PPM 6
# define OUT_B_SIM_CTL 5 # define OUT_B_SIM_CTL 5
# define OUT_B_BUZZER 4 # define OUT_B_BUZZER 4

View file

@ -51,7 +51,7 @@
// LCD_D6 PC2 // LCD_D6 PC2
// LCD_D7 PC1 // LCD_D7 PC1
#define LCD_DATA 0x000000FFL #define LCD_DATA 0x000000FFL
#if !defined(REVA) #if !defined(REVA)
#define LCD_A0 0x00000080L #define LCD_A0 0x00000080L
#else #else
@ -66,111 +66,105 @@
#if defined(REVA) #if defined(REVA)
const uint8_t Lcd_lookup[] = const uint8_t Lcd_lookup[] =
{ {
0x00,0x01,0x80,0x81,0x40,0x41,0xC0,0xC1,0x20,0x21,0xA0,0xA1,0x60,0x61,0xE0,0xE1, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 0x1E,0x1F,0x9E,0x9F,0x5E,0x5F,0xDE,0xDF,0x3E,0x3F,0xBE,0xBF,0x7E,0x7F,0xFE,0xFF
} ; };
#endif #endif
void lcdSendCtl(uint8_t val) void lcdSendCtl(uint8_t val)
{ {
register Pio *pioptr ; register Pio *pioptr;
#if defined(REVA) #if defined(REVA)
pioptr = PIOC ; pioptr = PIOC;
pioptr->PIO_CODR = LCD_CS1 ; // Select LCD pioptr->PIO_CODR = LCD_CS1; // Select LCD
pioptr->PIO_CODR = LCD_A0 ; // Control pioptr->PIO_CODR = LCD_A0; // Control
pioptr->PIO_CODR = LCD_RnW ; // Write pioptr->PIO_CODR = LCD_RnW; // Write
pioptr->PIO_ODSR = Lcd_lookup[val] ; pioptr->PIO_ODSR = Lcd_lookup[val];
#else #else
pioptr = PIOC ; pioptr = PIOC;
#if !defined(REVX) #if !defined(REVX)
pioptr->PIO_CODR = LCD_CS1 ; // Select LCD pioptr->PIO_CODR = LCD_CS1; // Select LCD
#endif #endif
PIOA->PIO_CODR = LCD_A0 ; PIOA->PIO_CODR = LCD_A0;
#if !defined(REVX) #if !defined(REVX)
pioptr->PIO_CODR = LCD_RnW ; // Write pioptr->PIO_CODR = LCD_RnW; // Write
#endif #endif
pioptr->PIO_ODSR = val ; pioptr->PIO_ODSR = val;
#endif #endif
pioptr->PIO_SODR = LCD_E ; // Start E pulse pioptr->PIO_SODR = LCD_E; // Start E pulse
// Need a delay here (250nS) // 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) while ( TC0->TC_CHANNEL[0].TC_CV < 9 ) // Value depends on MCK/2 (used 18MHz)
{ {
// Wait // Wait
} }
pioptr->PIO_CODR = LCD_E ; // End E pulse pioptr->PIO_CODR = LCD_E; // End E pulse
#if defined(REVA) #if defined(REVA)
pioptr->PIO_SODR = LCD_A0 ; // Data pioptr->PIO_SODR = LCD_A0; // Data
#else #else
PIOA->PIO_SODR = LCD_A0 ; // Data PIOA->PIO_SODR = LCD_A0; // Data
#endif #endif
#if !defined(REVX) #if !defined(REVX)
pioptr->PIO_SODR = LCD_CS1 ; // Deselect LCD pioptr->PIO_SODR = LCD_CS1; // Deselect LCD
#endif #endif
} }
void lcdInit() void lcdInit()
{ {
register Pio *pioptr ; register Pio *pioptr;
// /home/thus/txt/datasheets/lcd/KS0713.pdf // /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid= // ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
// read the inputs, and lock the LCD lines // read the inputs, and lock the LCD lines
lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP () lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP ()
lcdLock = 1 ; lcdLock = 1;
#if defined(REVA) #if defined(REVA)
pioptr = PIOC ; pioptr = PIOC;
pioptr->PIO_PER = 0x0C00B0FFL ; // Enable bits 27,26,15,13,12,7-0 pioptr->PIO_PER = 0x0C00B0FFL; // Enable bits 27,26,15,13,12,7-0
pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_A0 ; pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_A0;
pioptr->PIO_SODR = LCD_RES | LCD_CS1 ; pioptr->PIO_SODR = LCD_RES | LCD_CS1;
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
pioptr->PIO_OWER = 0x000000FFL ; // Allow write to ls 8 bits in ODSR pioptr->PIO_OWER = 0x000000FFL; // Allow write to ls 8 bits in ODSR
#else #else
configure_pins( LCD_A0, PIN_ENABLE | PIN_LOW | PIN_OUTPUT | PIN_PORTA | PIN_NO_PULLUP ) ; configure_pins( LCD_A0, PIN_ENABLE | PIN_LOW | PIN_OUTPUT | PIN_PORTA | PIN_NO_PULLUP );
pioptr = PIOC ; pioptr = PIOC;
#if defined(REVX) #if defined(REVX)
pioptr->PIO_PER = PIO_PC27 | PIO_PC12 | 0xFF ; pioptr->PIO_PER = PIO_PC27 | PIO_PC12 | 0xFF;
pioptr->PIO_CODR = LCD_E ; pioptr->PIO_CODR = LCD_E;
pioptr->PIO_CODR = LCD_RnW | LCD_CS1 ; // No longer needed, used elsewhere pioptr->PIO_CODR = LCD_RnW | LCD_CS1; // No longer needed, used elsewhere
#else #else
pioptr->PIO_PER = PIO_PC27 | PIO_PC26 | PIO_PC13 | PIO_PC12 | 0xFF ; pioptr->PIO_PER = PIO_PC27 | PIO_PC26 | PIO_PC13 | PIO_PC12 | 0xFF;
pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_CS1 ; pioptr->PIO_CODR = LCD_E | LCD_RnW | LCD_CS1;
#endif #endif
pioptr->PIO_SODR = LCD_RES ; 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_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 pioptr->PIO_OWER = 0x000000FFL; // Allow write to ls 8 bits in ODSR
#endif #endif
pioptr->PIO_CODR = LCD_RES ; // Reset LCD 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) pioptr->PIO_CODR = LCD_RES; // Reset LCD
while ( TC0->TC_CHANNEL[0].TC_CV < 200 ) // > 10us, Value depends on MCK/2 (used 18MHz) 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)
// Wait pioptr->PIO_SODR = LCD_RES; // Remove LCD reset
} while ( TC0->TC_CHANNEL[0].TC_CV < 27000 ) ; // 1500us, Value depends on MCK/2 (used 18MHz)
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
}
lcdSendCtl(0xe2); //Initialize the internal functions lcdSendCtl(0xe2); //Initialize the internal functions
lcdSendCtl(0xae); //DON = 0: display OFF lcdSendCtl(0xae); //DON = 0: display OFF
lcdSendCtl(0xa1); //ADC = 1: reverse direction(SEG132->SEG1) 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(0x25); //Select int resistance ratio R2 R1 R0 =5
lcdSendCtl(0x81); //Set reference voltage Mode lcdSendCtl(0x81); //Set reference voltage Mode
lcdSendCtl(0x22); // 24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18 lcdSendCtl(0x22); // 24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
lcdSendCtl(0xAF); //DON = 1: display ON
// g_eeGeneral.contrast = 0x22;
#if defined(REVA) #if defined(REVX)
pioptr->PIO_ODR = 0x0000003CL ; // Set bits 2, 3, 4, 5 input // 200mS delay (only if not wdt reset)
pioptr->PIO_PUER = 0x0000003CL ; // Set bits 2, 3, 4, 5 with pullups if ( ( ( ResetReason & RSTC_SR_RSTTYP ) != (2 << 8) ) && !unexpectedShutdown ) {
pioptr->PIO_ODSR = 0 ; // Drive D0 low for (uint32_t j = 0; j < 100; j += 1 ) {
#else TC0->TC_CHANNEL[0].TC_CCR = 5; // Enable clock and trigger it (may only need trigger)
pioptr->PIO_ODR = 0x0000003AL ; // Set bits 1, 3, 4, 5 input while ( TC0->TC_CHANNEL[0].TC_CV < 36000 ) {
pioptr->PIO_PUER = 0x0000003AL ; // Set bits 1, 3, 4, 5 with pullups // Value depends on MCK/2 (used 18MHz) give 2mS delay
pioptr->PIO_ODSR = 0 ; // Drive D0 low wdt_reset(); // Wait
}
}
}
#endif #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) void lcdSetRefVolt(uint8_t val)
{ {
register Pio *pioptr ; register Pio *pioptr;
pioptr = PIOC ; pioptr = PIOC;
// read the inputs, and lock the LCD lines // read the inputs, and lock the LCD lines
lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP () 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); lcdSendCtl(0x81);
if ( val == 0 ) if ( val == 0 )
{ {
val = 0x22 ; val = 0x22;
} }
lcdSendCtl(val); lcdSendCtl(val);
#if defined(REVA) #if defined(REVA)
pioptr->PIO_ODR = 0x0000003CL ; // Set bits 2, 3, 4, 5 input pioptr->PIO_ODR = 0x000000FEL; // Set bits 2, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003CL ; // Set bits 2, 3, 4, 5 with pullups pioptr->PIO_PUER = 0x000000FEL; // Set bits 2, 3, 4, 5 with pullups
#else #else
pioptr->PIO_ODR = 0x0000003AL ; // Set bits 1, 3, 4, 5 input pioptr->PIO_ODR = 0x000000FEL; // Set bits 1, 3, 4, 5 input
pioptr->PIO_PUER = 0x0000003AL ; // Set bits 1, 3, 4, 5 with pullups pioptr->PIO_PUER = 0x000000FEL; // Set bits 1, 3, 4, 5 with pullups
#endif #endif
pioptr->PIO_ODSR = lcdInputs; // Drive D0 low pioptr->PIO_ODSR = 0; // Drive D0 low
lcdLock = 0 ; lcdLock = 0;
} }
void lcdRefresh() void lcdRefresh()
@ -251,7 +258,7 @@ void lcdRefresh()
// read the inputs, and lock the LCD lines // read the inputs, and lock the LCD lines
lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP () lcdInputs = PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP ()
lcdLock = 1 ; lcdLock = 1;
pioptr = PIOC; pioptr = PIOC;
#if defined(REVA) #if defined(REVA)
@ -264,13 +271,13 @@ void lcdRefresh()
lcdSendCtl(0x10); //column addr 0 lcdSendCtl(0x10); //column addr 0
lcdSendCtl(y | 0xB0); //page addr y lcdSendCtl(y | 0xB0); //page addr y
#if !defined(REVX) #if !defined(REVX)
pioptr->PIO_CODR = LCD_CS1; // Select LCD pioptr->PIO_CODR = LCD_CS1; // Select LCD
#endif #endif
PIOA->PIO_SODR = LCD_A0; // Data PIOA->PIO_SODR = LCD_A0; // Data
#if !defined(REVX) #if !defined(REVX)
pioptr->PIO_CODR = LCD_RnW; // Write pioptr->PIO_CODR = LCD_RnW; // Write
#endif #endif
#if defined(REVA) #if defined(REVA)
x = lookup[*p]; x = lookup[*p];
@ -278,16 +285,6 @@ void lcdRefresh()
x = *p; x = *p;
#endif #endif
for (z = 0; z < LCD_W; z += 1) { 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_ODSR = x;
pioptr->PIO_SODR = ebit; // Start E pulse pioptr->PIO_SODR = ebit; // Start E pulse
// Need a delay here (250nS) // Need a delay here (250nS)
@ -297,27 +294,27 @@ void lcdRefresh()
#else #else
x = *p; x = *p;
#endif #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) // while ( TC0->TC_CHANNEL[0].TC_CV < 3 ) // Value depends on MCK/2 (used 6MHz)
// { // {
// // Wait // // Wait
// } // }
pioptr->PIO_CODR = ebit; // End E pulse pioptr->PIO_CODR = ebit; // End E pulse
} }
#if !defined(REVX) #if !defined(REVX)
pioptr->PIO_SODR = LCD_CS1; // Deselect LCD pioptr->PIO_SODR = LCD_CS1; // Deselect LCD
#endif #endif
} }
pioptr->PIO_ODSR = 0xFF ; // Drive lines high pioptr->PIO_ODSR = 0xFF; // Drive lines high
#if defined(REVA) #if defined(REVA)
pioptr->PIO_PUER = 0x0000003CL ; // Set bits 2, 3, 4, 5 with pullups pioptr->PIO_PUER = 0x000000FEL; // Set bits 2, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x0000003CL ; // Set bits 2, 3, 4, 5 input pioptr->PIO_ODR = 0x000000FEL; // Set bits 2, 3, 4, 5 input
#else #else
pioptr->PIO_PUER = 0x0000003AL ; // Set bits 1, 3, 4, 5 with pullups pioptr->PIO_PUER = 0x000000FEL; // Set bits 1, 3, 4, 5 with pullups
pioptr->PIO_ODR = 0x0000003AL ; // Set bits 1, 3, 4, 5 input pioptr->PIO_ODR = 0x000000FEL; // Set bits 1, 3, 4, 5 input
#endif #endif
pioptr->PIO_ODSR = lcdInputs; // Drive D0 low pioptr->PIO_ODSR = 0xFE; // Drive D0 low
lcdLock = 0; lcdLock = 0;
} }

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_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); 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(); pwrInit();
#endif
keysInit(); keysInit();
adcInit(); adcInit();
delaysInit(); delaysInit();
@ -179,6 +183,7 @@ void boardInit()
else { else {
if (pwr_on != 1) { if (pwr_on != 1) {
pwr_on = 1; pwr_on = 1;
pwrInit();
backlightInit(); backlightInit();
haptic.play(15, 3, PLAY_NOW); haptic.play(15, 3, PLAY_NOW);
} }
@ -191,6 +196,7 @@ void boardInit()
} }
} }
else { else {
pwrInit();
backlightInit(); backlightInit();
} }
toplcdInit(); toplcdInit();
@ -264,7 +270,7 @@ void checkTrainerSettings()
uint8_t requiredTrainerMode = g_model.trainerMode; uint8_t requiredTrainerMode = g_model.trainerMode;
if (requiredTrainerMode != currentTrainerMode) { if (requiredTrainerMode != currentTrainerMode) {
switch (currentTrainerMode) { switch (currentTrainerMode) {
case TRAINER_MODE_MASTER: case TRAINER_MODE_MASTER_TRAINER_JACK:
stop_trainer_capture(); stop_trainer_capture();
break; break;
case TRAINER_MODE_SLAVE: case TRAINER_MODE_SLAVE:

View file

@ -143,7 +143,12 @@ void configure_pins( uint32_t pins, uint16_t config );
extern uint16_t sessionTimer; extern uint16_t sessionTimer;
#define SLAVE_MODE() (g_model.trainerMode == TRAINER_MODE_SLAVE) #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) #define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_GPIO_DETECT, TRAINER_GPIO_PIN_DETECT) == Bit_RESET)
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View file

@ -127,13 +127,15 @@ extern "C" void TIM3_IRQHandler()
if ( (TRAINER_TIMER->DIER & TIM_DIER_CC3IE ) && ( TRAINER_TIMER->SR & TIM_SR_CC3IF ) ) { if ( (TRAINER_TIMER->DIER & TIM_DIER_CC3IE ) && ( TRAINER_TIMER->SR & TIM_SR_CC3IF ) ) {
// capture mode on trainer jack // capture mode on trainer jack
capture = TRAINER_TIMER->CCR3 ; 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 ) ) { if ( ( TRAINER_TIMER->DIER & TIM_DIER_CC2IE ) && ( TRAINER_TIMER->SR & TIM_SR_CC2IF ) ) {
// capture mode on heartbeat pin (external module) // capture mode on heartbeat pin (external module)
capture = TRAINER_TIMER->CCR2 ; capture = TRAINER_TIMER->CCR2 ;
doCapture = true ; if (currentTrainerMode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)
doCapture = true ;
} }
if (doCapture) { if (doCapture) {
@ -247,8 +249,10 @@ extern "C" void HEARTBEAT_USART_IRQHandler()
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
data = HEARTBEAT_USART->DR; data = HEARTBEAT_USART->DR;
if (!(status & USART_FLAG_ERRORS)) if (!(status & USART_FLAG_ERRORS)) {
sbusFifo.push(data); if (currentTrainerMode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE)
sbusFifo.push(data);
}
status = HEARTBEAT_USART->SR; status = HEARTBEAT_USART->SR;
} }

File diff suppressed because it is too large Load diff

View file

@ -795,10 +795,12 @@ char *findTrueFileName(const char *path)
strcat(result, res->d_name); strcat(result, res->d_name);
TRACE("\tfound: %s", res->d_name); TRACE("\tfound: %s", res->d_name);
fileMap.insert(filemap_t:: value_type(path, result)); fileMap.insert(filemap_t:: value_type(path, result));
simu::closedir(dir);
return result; return result;
} }
} }
} }
simu::closedir(dir);
} }
#endif #endif
} }
@ -840,10 +842,10 @@ FRESULT f_open (FIL * fil, const TCHAR *name, BYTE flag)
fil->fsize = tmp.st_size; fil->fsize = tmp.st_size;
fil->fptr = 0; 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; fil->fptr = 0;
if (fil->fs) { 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; return FR_OK;
} }
TRACE("f_open(%s) = error %d (%s)", path, errno, strerror(errno)); 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; 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) FRESULT f_close (FIL * fil)
{ {
if (fil && fil->fs) { if (fil && fil->fs) {

View file

@ -366,10 +366,7 @@ void TelemetryItem::eval(const TelemetrySensor & sensor)
result += dist*dist; result += dist*dist;
if (altItem) { if (altItem) {
dist = abs(altItem->value); dist = abs(altItem->value) / g_model.telemetrySensors[sensor.dist.alt-1].getPrecDivisor();
uint8_t prec = g_model.telemetrySensors[sensor.dist.alt-1].prec;
if (prec > 0)
dist /= (prec==2 ? 100 : 10);
result += dist*dist; result += dist*dist;
} }
@ -545,49 +542,56 @@ void TelemetrySensor::init(uint16_t id)
init(label); init(label);
} }
bool TelemetrySensor::isAvailable() bool TelemetrySensor::isAvailable() const
{ {
return ZLEN(label) > 0; 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) 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++) for (int i=prec; i<destPrec; i++)
value *= 10; value *= 10;
if (unit == UNIT_METERS || unit == UNIT_METERS_PER_SECOND) { if (unit == UNIT_CELSIUS) {
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 (destUnit == UNIT_FAHRENHEIT) { if (destUnit == UNIT_FAHRENHEIT) {
// T(°F) = T(°C)×1,8 + 32 // T(°F) = T(°C)×1,8 + 32
value = 32 + (value*18)/10; value = 32 + (value*18) / 10;
} }
} }
else if (unit == UNIT_MILLILITERS) { else {
if (destUnit == UNIT_FLOZ) { const UnitConversionRule * p = unitConversionTable;
value = (value * 100) / 2957; 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; return value;
} }
bool TelemetrySensor::isConfigurable() bool TelemetrySensor::isConfigurable() const
{ {
if (type == TELEM_TYPE_CALCULATED) { if (type == TELEM_TYPE_CALCULATED) {
if (formula >= TELEM_FORMULA_CELL) { if (formula >= TELEM_FORMULA_CELL) {
@ -637,7 +641,7 @@ bool TelemetrySensor::isConfigurable()
return true; return true;
} }
bool TelemetrySensor::isPrecConfigurable() bool TelemetrySensor::isPrecConfigurable() const
{ {
if (isConfigurable()) { if (isConfigurable()) {
return true; return true;
@ -649,3 +653,21 @@ bool TelemetrySensor::isPrecConfigurable()
return false; 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;
}

View file

@ -42,10 +42,6 @@
#define SWAP_DEFINED #define SWAP_DEFINED
#include "opentx.h" #include "opentx.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
extern const char * zchar2string(const char * zstring, int size); 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))) #define EXPECT_ZSTREQ(c_string, z_string) EXPECT_STREQ(c_string, zchar2string(z_string, sizeof(z_string)))
extern void luaInit(); extern void luaInit();

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_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
#define f_error(fp) ((fp)->err) #define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr) #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 #ifndef EOF
#define EOF (-1) #define EOF (-1)

View file

@ -19,6 +19,7 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#define liolib_c #define liolib_c
@ -183,14 +184,10 @@ static LStream *newprefile (lua_State *L) {
#if !defined(USE_FATFS) #if !defined(USE_FATFS)
static int aux_close (lua_State *L) { static int aux_close (lua_State *L) {
#if !defined(USE_FATFS)
LStream *p = tolstream(L); LStream *p = tolstream(L);
lua_CFunction cf = p->closef; lua_CFunction cf = p->closef;
p->closef = NULL; /* mark stream as closed */ p->closef = NULL; /* mark stream as closed */
return (*cf)(L); /* close it */ return (*cf)(L); /* close it */
#else
return 0;
#endif
} }
#endif #endif
@ -249,14 +246,14 @@ static int io_open (lua_State *L) {
const char *md = luaL_optstring(L, 2, "r"); const char *md = luaL_optstring(L, 2, "r");
LStream *p = newfile(L); LStream *p = newfile(L);
#if defined(USE_FATFS) #if defined(USE_FATFS)
BYTE mode; BYTE mode = FA_READ;
if (strchr(md, 'w') || strchr(md, 'a')) if (*md == 'w')
mode = FA_WRITE; mode = FA_WRITE | FA_CREATE_ALWAYS; // always create file and truncate it
else else if (*md == 'a')
mode = FA_READ; mode = FA_WRITE | FA_OPEN_ALWAYS; // always open file (create it if necessary)
FRESULT result = f_open(&p->f, filename, mode); FRESULT result = f_open(&p->f, filename, mode);
if (result == FR_OK && strchr(md, 'a')) if (result == FR_OK && *md == 'a')
result = f_lseek(&p->f, f_size(&p->f)); result = f_lseek(&p->f, f_size(&p->f)); // seek to the end of the file
return result == FR_OK ? 1 : 0; return result == FR_OK ? 1 : 0;
#else #else
const char *mode = md; /* to traverse/check mode */ 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++) { for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) { if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */ /* optimization: could be done exactly as for strings */
status = status && char s[LUAI_MAXNUMBER2STR];
f_printf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; sprintf(s, LUA_NUMBER_FMT, lua_tonumber(L, arg));
status = status && f_puts(s, f) > 0;
} }
else { else {
size_t l; size_t l;

View file

@ -391,7 +391,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)

View file

@ -395,7 +395,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)

View file

@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)

View file

@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)

View file

@ -393,7 +393,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)

View file

@ -396,7 +396,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)
@ -849,10 +849,10 @@
#define TR_NO_MODELS_ON_SD "No Model. su SD" #define TR_NO_MODELS_ON_SD "No Model. su SD"
#define TR_NO_BITMAPS_ON_SD "No Immag. su SD" #define TR_NO_BITMAPS_ON_SD "No Immag. su SD"
#define TR_NO_SCRIPTS_ON_SD "No Scripts su SD" #define TR_NO_SCRIPTS_ON_SD "No Scripts su SD"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" #define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error" #define TR_SCRIPT_ERROR "Unknown error"
#define TR_PLAY_FILE "Suona" #define TR_PLAY_FILE "Suona"
#define TR_DELETE_FILE "Elimina" #define TR_DELETE_FILE "Elimina"
#define TR_COPY_FILE "Copia" #define TR_COPY_FILE "Copia"
@ -1115,7 +1115,7 @@
#define ZSTR_A4 "A4" #define ZSTR_A4 "A4"
#define ZSTR_BATT "RxBt" #define ZSTR_BATT "RxBt"
#define ZSTR_ALT "Alt" #define ZSTR_ALT "Alt"
#define ZSTR_TEMP1 "Tmp1" #define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP2 "Tmp2" #define ZSTR_TEMP2 "Tmp2"
#define ZSTR_RPM "RPM" #define ZSTR_RPM "RPM"
#define ZSTR_FUEL "Fuel" #define ZSTR_FUEL "Fuel"

View file

@ -397,7 +397,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)

View file

@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)
@ -801,10 +801,10 @@
#define TR_NO_MODELS_ON_SD "Sem Modelo no SD" #define TR_NO_MODELS_ON_SD "Sem Modelo no SD"
#define TR_NO_BITMAPS_ON_SD "No Bitmaps on SD" #define TR_NO_BITMAPS_ON_SD "No Bitmaps on SD"
#define TR_NO_SCRIPTS_ON_SD "No Scripts on SD" #define TR_NO_SCRIPTS_ON_SD "No Scripts on SD"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" #define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error" #define TR_SCRIPT_ERROR "Unknown error"
#define TR_PLAY_FILE "Play" #define TR_PLAY_FILE "Play"
#define TR_DELETE_FILE "Apagar" #define TR_DELETE_FILE "Apagar"
#define TR_COPY_FILE "Copiar" #define TR_COPY_FILE "Copiar"
@ -902,10 +902,10 @@
#define TR_SMOOTH "Smooth" #define TR_SMOOTH "Smooth"
#define TR_COPY_STICKS_TO_OFS "Copy Sticks To Offset" #define TR_COPY_STICKS_TO_OFS "Copy Sticks To Offset"
#define TR_COPY_TRIMS_TO_OFS "Copy trims to subtrim" #define TR_COPY_TRIMS_TO_OFS "Copy trims to subtrim"
#define TR_INCDEC "Inc/Decrement" #define TR_INCDEC "Inc/Decrement"
#define TR_GLOBALVAR "Global Var" #define TR_GLOBALVAR "Global Var"
#define TR_MIXSOURCE "Mixer Source" #define TR_MIXSOURCE "Mixer Source"
#define TR_CONSTANT "Constant" #define TR_CONSTANT "Constant"
#define TR_PERSISTENT_MAH INDENT "Store mAh" #define TR_PERSISTENT_MAH INDENT "Store mAh"
#define TR_PREFLIGHT "Preflight Checks" #define TR_PREFLIGHT "Preflight Checks"
#define TR_CHECKLIST INDENT "Display Checklist" #define TR_CHECKLIST INDENT "Display Checklist"
@ -1041,7 +1041,7 @@
#define TR_DISCOVER_SENSORS INDENT "Discover new sensors" #define TR_DISCOVER_SENSORS INDENT "Discover new sensors"
#define TR_STOP_DISCOVER_SENSORS INDENT "Stop discovery" #define TR_STOP_DISCOVER_SENSORS INDENT "Stop discovery"
#define TR_DELETE_ALL_SENSORS INDENT "Delete all sensors" #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_INPUTS "\314Inputs"
#define TR_MENU_LUA "\322Lua scripts" #define TR_MENU_LUA "\322Lua scripts"
@ -1067,7 +1067,7 @@
#define ZSTR_A4 "A4" #define ZSTR_A4 "A4"
#define ZSTR_BATT "RxBt" #define ZSTR_BATT "RxBt"
#define ZSTR_ALT "Alt" #define ZSTR_ALT "Alt"
#define ZSTR_TEMP1 "Tmp1" #define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP2 "Tmp2" #define ZSTR_TEMP2 "Tmp2"
#define ZSTR_RPM "RPM" #define ZSTR_RPM "RPM"
#define ZSTR_FUEL "Fuel" #define ZSTR_FUEL "Fuel"

View file

@ -389,7 +389,7 @@
#define SPEED_UNIT SPEED_UNIT_METR #define SPEED_UNIT SPEED_UNIT_METR
#endif #endif
#define LEN_VTELEMUNIT "\003" #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 #endif
#define STR_V (STR_VTELEMUNIT+1) #define STR_V (STR_VTELEMUNIT+1)
@ -801,10 +801,10 @@
#define TR_NO_MODELS_ON_SD "Ingen modell i SD" #define TR_NO_MODELS_ON_SD "Ingen modell i SD"
#define TR_NO_BITMAPS_ON_SD "Ikoner saknas på SD" #define TR_NO_BITMAPS_ON_SD "Ikoner saknas på SD"
#define TR_NO_SCRIPTS_ON_SD "Programkod saknas på SD" #define TR_NO_SCRIPTS_ON_SD "Programkod saknas på SD"
#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" #define TR_SCRIPT_SYNTAX_ERROR "Script syntax error"
#define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_PANIC "Script panic"
#define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_KILLED "Script killed"
#define TR_SCRIPT_ERROR "Unknown error" #define TR_SCRIPT_ERROR "Unknown error"
#define TR_PLAY_FILE "Spela" #define TR_PLAY_FILE "Spela"
#define TR_DELETE_FILE "Radera" #define TR_DELETE_FILE "Radera"
#define TR_COPY_FILE "Kopia" #define TR_COPY_FILE "Kopia"
@ -902,10 +902,10 @@
#define TR_SMOOTH "Mjuk" #define TR_SMOOTH "Mjuk"
#define TR_COPY_STICKS_TO_OFS "Spara spakar som offset" #define TR_COPY_STICKS_TO_OFS "Spara spakar som offset"
#define TR_COPY_TRIMS_TO_OFS "Spara trimmar som offset" #define TR_COPY_TRIMS_TO_OFS "Spara trimmar som offset"
#define TR_INCDEC "Inc/Decrement" #define TR_INCDEC "Inc/Decrement"
#define TR_GLOBALVAR "Global Var" #define TR_GLOBALVAR "Global Var"
#define TR_MIXSOURCE "Mixer Source" #define TR_MIXSOURCE "Mixer Source"
#define TR_CONSTANT "Constant" #define TR_CONSTANT "Constant"
#define TR_PERSISTENT_MAH INDENT "Lagra mAh" #define TR_PERSISTENT_MAH INDENT "Lagra mAh"
#define TR_PREFLIGHT "Startkontroller" #define TR_PREFLIGHT "Startkontroller"
#define TR_CHECKLIST TR(INDENT "Checklista", INDENT "Visa Checklista") #define TR_CHECKLIST TR(INDENT "Checklista", INDENT "Visa Checklista")
@ -1041,7 +1041,7 @@
#define TR_DISCOVER_SENSORS INDENT "Discover new sensors" #define TR_DISCOVER_SENSORS INDENT "Discover new sensors"
#define TR_STOP_DISCOVER_SENSORS INDENT "Stop discovery" #define TR_STOP_DISCOVER_SENSORS INDENT "Stop discovery"
#define TR_DELETE_ALL_SENSORS INDENT "Delete all sensors" #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_INPUTS "\314Inputs"
#define TR_MENU_LUA "\322Lua scripts" #define TR_MENU_LUA "\322Lua scripts"
@ -1067,7 +1067,7 @@
#define ZSTR_A4 "A4" #define ZSTR_A4 "A4"
#define ZSTR_BATT "RxBt" #define ZSTR_BATT "RxBt"
#define ZSTR_ALT "Alt" #define ZSTR_ALT "Alt"
#define ZSTR_TEMP1 "Tmp1" #define ZSTR_TEMP1 "Tmp1"
#define ZSTR_TEMP2 "Tmp2" #define ZSTR_TEMP2 "Tmp2"
#define ZSTR_RPM "RPM" #define ZSTR_RPM "RPM"
#define ZSTR_FUEL "Fuel" #define ZSTR_FUEL "Fuel"

View file

@ -47,10 +47,10 @@ void varioWakeup()
int verticalSpeed = 0; int verticalSpeed = 0;
if (g_model.frsky.varioSource) { if (g_model.frsky.varioSource) {
TelemetryItem & varioItem = telemetryItems[g_model.frsky.varioSource-1]; uint8_t item = g_model.frsky.varioSource-1;
verticalSpeed = varioItem.value; if (item < MAX_SENSORS) {
TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.varioSource-1]; verticalSpeed = telemetryItems[item].value * g_model.telemetrySensors[item].getPrecMultiplier();
if (sensor.prec != 2) verticalSpeed *= sensor.prec == 0 ? 100 : 10; }
} }
int varioCenterMin = (int)g_model.frsky.varioCenterMin * 10 - 50; int varioCenterMin = (int)g_model.frsky.varioCenterMin * 10 - 50;

View file

@ -51,12 +51,17 @@ def ParseSWR(packet, dataId, prim, appId, data, crc):
print "packet: %s (%4d)" % (dump(packet), lineNumber) , print "packet: %s (%4d)" % (dump(packet), lineNumber) ,
print " SWR: %d" % (data & 0xFF) print " SWR: %d" % (data & 0xFF)
def ParseAirSpeed(packet, dataId, prim, appId, data, crc):
print "packet: %s (%4d)" % (dump(packet), lineNumber) ,
print " Aspd: %.1f km/h" % (data/10.0)
appIdParsers = ( appIdParsers = (
(0x0300, 0x030f, ParseFlVSS), (0x0300, 0x030f, ParseFlVSS),
(0xf101, 0xf101, ParseRSSI), (0xf101, 0xf101, ParseRSSI),
(0xf102, 0xf103, ParseAdc), (0xf102, 0xf103, ParseAdc),
(0xf104, 0xf104, ParseBatt), (0xf104, 0xf104, ParseBatt),
(0xf105, 0xf105, ParseSWR), (0xf105, 0xf105, ParseSWR),
(0x0a00, 0x0a0f, ParseAirSpeed),
) )
def dump(data, maxLen = None): def dump(data, maxLen = None):