From 661de78464f520f5f34c04861a0ccd200c997fac Mon Sep 17 00:00:00 2001 From: philmoz Date: Thu, 21 Sep 2023 18:54:50 +1000 Subject: [PATCH 01/29] chore: Reduce AFHDS3 console noise when running simulator (#4075) --- radio/src/pulses/afhds3.cpp | 58 +++++++++++++-------------- radio/src/pulses/afhds3_transport.cpp | 20 ++++----- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/radio/src/pulses/afhds3.cpp b/radio/src/pulses/afhds3.cpp index 4dd2ed2ea2f..e1a52ecc086 100644 --- a/radio/src/pulses/afhds3.cpp +++ b/radio/src/pulses/afhds3.cpp @@ -417,7 +417,7 @@ void ProtoState::setupFrame() } if (this->state == ModuleState::STATE_NOT_READY) { - TRACE("AFHDS3 [GET MODULE READY]"); +// TRACE("AFHDS3 [GET MODULE READY]"); trsp.putFrame(COMMAND::MODULE_READY, FRAME_TYPE::REQUEST_GET_DATA); return; } @@ -429,7 +429,7 @@ void ProtoState::setupFrame() if (moduleMode == ::ModuleSettingsMode::MODULE_MODE_BIND) { if (state != STATE_BINDING) { - TRACE("AFHDS3 [BIND]"); +// TRACE("AFHDS3 [BIND]"); applyConfigFromModel(); trsp.putFrame(COMMAND::MODULE_SET_CONFIG, @@ -457,12 +457,12 @@ void ProtoState::setupFrame() if (modelID != newModelID) { if (this->state != ModuleState::STATE_STANDBY) { - TRACE("AFHDS3 [Model ID Changed] Switch to STATE_STANDBY"); +// TRACE("AFHDS3 [Model ID Changed] Switch to STATE_STANDBY"); auto mode = (uint8_t)MODULE_MODE_E::STANDBY; trsp.putFrame(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &mode, 1); return; } else { - TRACE("AFHDS3 [Model ID Changed] Set ModelID to %d", newModelID); +// TRACE("AFHDS3 [Model ID Changed] Set ModelID to %d", newModelID); modelID = newModelID; trsp.putFrame(COMMAND::MODEL_ID, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &modelID, 1); @@ -510,7 +510,7 @@ void ProtoState::setupFrame() uint16_t failSafe[AFHDS3_MAX_CHANNELS + 1] = { ((AFHDS3_MAX_CHANNELS << 8) | CHANNELS_DATA_MODE::FAIL_SAFE), 0}; setFailSafe((int16_t*)(&failSafe[1]), len); - TRACE("AFHDS ONE WAY FAILSAFE"); +// TRACE("AFHDS ONE WAY FAILSAFE"); trsp.putFrame(COMMAND::CHANNELS_FAILSAFE_DATA, FRAME_TYPE::REQUEST_SET_NO_RESP, (uint8_t*)failSafe, AFHDS3_MAX_CHANNELS * 2 + 2); @@ -557,7 +557,7 @@ void ProtoState::init(uint8_t moduleIndex, void* buffer, void ProtoState::clearFrameData() { - TRACE("AFHDS3 clearFrameData"); +// TRACE("AFHDS3 clearFrameData"); trsp.clear(); cmdCount = 0; @@ -600,7 +600,7 @@ void ProtoState::setState(ModuleState state) if (state == ModuleState::STATE_SYNC_DONE) { // Update power config - TRACE("Added PWM CMD"); +// TRACE("Added PWM CMD"); DIRTY_CMD((&cfg), afhds3::DirtyConfig::DC_RX_CMD_TX_PWR); } } @@ -626,7 +626,7 @@ void ProtoState::parseData(uint8_t* rxBuffer, uint8_t rxBufferCount) if (containsData((enum FRAME_TYPE) responseFrame->frameType)) { switch (responseFrame->command) { case COMMAND::MODULE_READY: - TRACE("AFHDS3 [MODULE_READY] %02X", responseFrame->value); +// TRACE("AFHDS3 [MODULE_READY] %02X", responseFrame->value); if (responseFrame->value == MODULE_STATUS_READY) { setState(ModuleState::STATE_READY); // requestInfoAndRun(); @@ -637,22 +637,22 @@ void ProtoState::parseData(uint8_t* rxBuffer, uint8_t rxBufferCount) break; case COMMAND::MODULE_GET_CONFIG: { // modelcfgGet = false; - TRACE("AFHDS3 [MODULE_GET_CONFIG]"); +// TRACE("AFHDS3 [MODULE_GET_CONFIG]"); size_t len = min(sizeof(cfg.buffer), rxBufferCount); std::memcpy((void*) cfg.buffer, &responseFrame->value, len); moduleData->afhds3.emi = cfg.v0.EMIStandard; moduleData->afhds3.telemetry = cfg.v0.IsTwoWay; moduleData->afhds3.phyMode = cfg.v0.PhyMode; cfg.others.ExternalBusType = cfg.v0.ExternalBusType; - TRACE("PhyMode %d, emi %d", moduleData->afhds3.phyMode, moduleData->afhds3.emi); +// TRACE("PhyMode %d, emi %d", moduleData->afhds3.phyMode, moduleData->afhds3.emi); SET_DIRTY(); cfg.others.lastUpdated = get_tmr10ms(); } break; case COMMAND::MODULE_VERSION: std::memcpy((void*) &version, &responseFrame->value, sizeof(version)); - TRACE("AFHDS3 [MODULE_VERSION] Product %d, HW %d, BOOT %d, FW %d", - version.productNumber, version.hardwareVersion, - version.bootloaderVersion, version.firmwareVersion); +// TRACE("AFHDS3 [MODULE_VERSION] Product %d, HW %d, BOOT %d, FW %d", +// version.productNumber, version.hardwareVersion, +// version.bootloaderVersion, version.firmwareVersion); break; case COMMAND::MODULE_STATE: // TRACE("AFHDS3 [MODULE_STATE] %02X", responseFrame->value); @@ -677,7 +677,7 @@ void ProtoState::parseData(uint8_t* rxBuffer, uint8_t rxBufferCount) } break; case COMMAND::MODULE_MODE: - TRACE("AFHDS3 [MODULE_MODE] %02X", responseFrame->value); +// TRACE("AFHDS3 [MODULE_MODE] %02X", responseFrame->value); if (responseFrame->value != CMD_RESULT::SUCCESS) { setState(ModuleState::STATE_NOT_READY); } @@ -686,12 +686,12 @@ void ProtoState::parseData(uint8_t* rxBuffer, uint8_t rxBufferCount) if (responseFrame->value != CMD_RESULT::SUCCESS) { setState(ModuleState::STATE_NOT_READY); } - TRACE("AFHDS3 [MODULE_SET_CONFIG], %02X", responseFrame->value); +// TRACE("AFHDS3 [MODULE_SET_CONFIG], %02X", responseFrame->value); break; case COMMAND::MODEL_ID: - TRACE("AFHDS3 [MODEL_ID]"); +// TRACE("AFHDS3 [MODEL_ID]"); if (responseFrame->value == CMD_RESULT::SUCCESS) { - TRACE("Enqueue get config"); +// TRACE("Enqueue get config"); // trsp.enqueue(COMMAND::MODULE_GET_CONFIG, FRAME_TYPE::REQUEST_GET_DATA); // trsp.enqueue(COMMAND::MODULE_GET_CONFIG, FRAME_TYPE::REQUEST_GET_DATA); // modelcfgGet = true; @@ -770,7 +770,7 @@ void ProtoState::parseData(uint8_t* rxBuffer, uint8_t rxBufferCount) default: break; } - TRACE("AFHDS3 [CMD Result] Cmd: %X, Result: %d, DirtyFlag: %X", cmd_code, result, cfg->others.dirtyFlag); +// TRACE("AFHDS3 [CMD Result] Cmd: %X, Result: %d, DirtyFlag: %X", cmd_code, result, cfg->others.dirtyFlag); } break; } } @@ -806,7 +806,7 @@ bool ProtoState::syncSettings() // Sync settings when dirty flag is set if (checkDirtyFlag(DC_RX_CMD_TX_PWR)) { - TRACE("AFHDS3 [RX_CMD_TX_PWR] %d", AFHDS3_POWER[moduleData->afhds3.rfPower] / 4); +// TRACE("AFHDS3 [RX_CMD_TX_PWR] %d", AFHDS3_POWER[moduleData->afhds3.rfPower] / 4); uint8_t data[] = { (uint8_t)(RX_CMD_TX_PWR&0xFF), (uint8_t)((RX_CMD_TX_PWR>>8)&0xFF), 2, (uint8_t)(AFHDS3_POWER[moduleData->afhds3.rfPower]&0xFF), (uint8_t)((AFHDS3_POWER[moduleData->afhds3.rfPower]>>8)&0xFF)}; trsp.putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data)); @@ -816,7 +816,7 @@ bool ProtoState::syncSettings() if (checkDirtyFlag(DC_RX_CMD_RSSI_CHANNEL_SETUP)) { - TRACE("AFHDS3 [RX_CMD_RSSI_CHANNEL_SETUP]"); +// TRACE("AFHDS3 [RX_CMD_RSSI_CHANNEL_SETUP]"); uint8_t data[] = { (uint8_t)(RX_CMD_RSSI_CHANNEL_SETUP&0xFF), (uint8_t)((RX_CMD_RSSI_CHANNEL_SETUP>>8)&0xFF), 1, cfg->v1.SignalStrengthRCChannelNb }; trsp.putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data)); return true; @@ -824,14 +824,14 @@ bool ProtoState::syncSettings() if (checkDirtyFlag(DC_RX_CMD_OUT_PWM_PPM_MODE)) { - TRACE("AFHDS3 [RX_CMD_OUT_PWM_PPM_MODE]"); +// TRACE("AFHDS3 [RX_CMD_OUT_PWM_PPM_MODE]"); uint8_t data[] = { (uint8_t)(RX_CMD_OUT_PWM_PPM_MODE&0xFF), (uint8_t)((RX_CMD_OUT_PWM_PPM_MODE>>8)&0xFF), 1, cfg->v0.AnalogOutput }; trsp.putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data)); return true; } if (checkDirtyFlag(DC_RX_CMD_FREQUENCY_V0)) { - TRACE("AFHDS3 [RX_CMD_FREQUENCY_V0]"); +// TRACE("AFHDS3 [RX_CMD_FREQUENCY_V0]"); uint16_t Frequency = ((cfg->v0.PWMFrequency.Synchronized<<15)| cfg->v0.PWMFrequency.Frequency); uint8_t data[] = { (uint8_t)(RX_CMD_FREQUENCY_V0&0xFF), (uint8_t)((RX_CMD_FREQUENCY_V0>>8)&0xFF), 2, (uint8_t)(Frequency&0xFF), (uint8_t)((Frequency>>8)&0xFF) }; @@ -841,7 +841,7 @@ bool ProtoState::syncSettings() if (checkDirtyFlag(DC_RX_CMD_PORT_TYPE_V1)) { - TRACE("AFHDS3 [RX_CMD_PORT_TYPE_V1]"); +// TRACE("AFHDS3 [RX_CMD_PORT_TYPE_V1]"); uint8_t data[] = { (uint8_t)(RX_CMD_PORT_TYPE_V1&0xFF), (uint8_t)((RX_CMD_PORT_TYPE_V1>>8)&0xFF), 4, 0, 0, 0, 0 }; std::memcpy(&data[3], &cfg->v1.NewPortTypes, SES_NPT_NB_MAX_PORTS); trsp.putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data)); @@ -850,7 +850,7 @@ bool ProtoState::syncSettings() if (checkDirtyFlag(DC_RX_CMD_FREQUENCY_V1)) { - TRACE("AFHDS3 [RX_CMD_FREQUENCY_V1]"); +// TRACE("AFHDS3 [RX_CMD_FREQUENCY_V1]"); uint8_t data[32 + 3 + 3] = { (uint8_t)(RX_CMD_FREQUENCY_V1&0xFF), (uint8_t)((RX_CMD_FREQUENCY_V1>>8)&0xFF), 32+3}; data[3] = 0; std::memcpy(&data[4], &cfg->v1.PWMFrequenciesV1.PWMFrequencies[0], 32); @@ -863,7 +863,7 @@ bool ProtoState::syncSettings() if (checkDirtyFlag(DC_RX_CMD_FREQUENCY_V1_2)) { - TRACE("AFHDS3 [RX_CMD_FREQUENCY_V1_2]"); +// TRACE("AFHDS3 [RX_CMD_FREQUENCY_V1_2]"); uint8_t data[32 + 3 + 3] = { (uint8_t)(RX_CMD_FREQUENCY_V1_2&0xFF), (uint8_t)((RX_CMD_FREQUENCY_V1_2>>8)&0xFF), 32+3}; data[3] = 1; std::memcpy(&data[4], &cfg->v1.PWMFrequenciesV1.PWMFrequencies[16], 32); @@ -875,7 +875,7 @@ bool ProtoState::syncSettings() if (checkDirtyFlag(DC_RX_CMD_BUS_TYPE_V0)) { - TRACE("AFHDS3 [RX_CMD_BUS_TYPE_V0]"); +// TRACE("AFHDS3 [RX_CMD_BUS_TYPE_V0]"); bool onlySupportIBUSOut = (1==receiver_type(rx_version.ProductNumber)); if (onlySupportIBUSOut && cfg->others.ExternalBusType == EB_BT_IBUS1_IN) @@ -889,7 +889,7 @@ bool ProtoState::syncSettings() if (checkDirtyFlag(DC_RX_CMD_BUS_TYPE_V0_2)) { - TRACE("AFHDS3 [RX_CMD_BUS_TYPE_V0]"); +// TRACE("AFHDS3 [RX_CMD_BUS_TYPE_V0]"); bool onlySupportIBUSOut = (1==receiver_type(rx_version.ProductNumber)); if (onlySupportIBUSOut && cfg->others.ExternalBusType == EB_BT_IBUS1_IN) @@ -912,7 +912,7 @@ bool ProtoState::syncSettings() bus_dir = BUS_OUT; else bus_dir = BUS_IN; - TRACE("AFHDS3 [RX_CMD_IBUS_DIRECTION]"); +// TRACE("AFHDS3 [RX_CMD_IBUS_DIRECTION]"); uint8_t data[4] = { (uint8_t)(RX_CMD_IBUS_DIRECTION&0xFF), (uint8_t)((RX_CMD_IBUS_DIRECTION>>8)&0xFF), 1, bus_dir }; trsp.putFrame( COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data) ); return true; @@ -948,7 +948,7 @@ void ProtoState::sendChannelsData() void ProtoState::stop() { - TRACE("AFHDS3 STOP"); +// TRACE("AFHDS3 STOP"); auto mode = (uint8_t)MODULE_MODE_E::STANDBY; trsp.putFrame(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &mode, 1); } diff --git a/radio/src/pulses/afhds3_transport.cpp b/radio/src/pulses/afhds3_transport.cpp index 8647ed926b5..b6f02372bea 100644 --- a/radio/src/pulses/afhds3_transport.cpp +++ b/radio/src/pulses/afhds3_transport.cpp @@ -135,7 +135,7 @@ bool FrameTransport::processTelemetryData(uint8_t byte, uint8_t* rxBuffer, uint8_t maxSize) { if (rxBufferCount == 0 && byte != START) { - TRACE("AFHDS3 [SKIP] %02X", byte); +// TRACE("AFHDS3 [SKIP] %02X", byte); this->esc_state = 0; return false; } @@ -280,11 +280,11 @@ bool Transport::processQueue() trsp.putFrame(f->command, f->frameType, &f->payload, f->payloadSize, f->useFrameNumber ? f->frameNumber : frameIndex); - TRACE( - "AFHDS3 [CMD QUEUE] cmd: 0x%02x frameType 0x%02x, useFrameNumber %d " - "frame Number %d size %d", - f->command, f->frameType, f->useFrameNumber, f->frameNumber, - f->payloadSize); +// TRACE( +// "AFHDS3 [CMD QUEUE] cmd: 0x%02x frameType 0x%02x, useFrameNumber %d " +// "frame Number %d size %d", +// f->command, f->frameType, f->useFrameNumber, f->frameNumber, +// f->payloadSize); if (!f->useFrameNumber) frameIndex++; fifo.skip(); @@ -300,7 +300,7 @@ bool Transport::handleRetransmissions(bool& error) return true; // re-send } - TRACE("AFHDS3 [NO RESP]"); +// TRACE("AFHDS3 [NO RESP]"); error = true; return false; } @@ -333,9 +333,9 @@ bool Transport::handleReply(uint8_t* buffer, uint8_t len) return true; } - TRACE("AFHDS3 [SEND ACK] cmd %02X type %02X number %02X", - responseFrame->command, responseFrame->frameType, - responseFrame->frameNumber); +// TRACE("AFHDS3 [SEND ACK] cmd %02X type %02X number %02X", +// responseFrame->command, responseFrame->frameType, +// responseFrame->frameNumber); auto command = (enum COMMAND)responseFrame->command; trsp.putFrame(command, FRAME_TYPE::RESPONSE_ACK, nullptr, 0, From 4d148e5c0c624eb5630ed18c4842dc7f4efcf45f Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Thu, 21 Sep 2023 11:25:46 +0200 Subject: [PATCH 02/29] fix(radio): Use SWRC_NONE if switch cannot be found (#4005) --- radio/src/storage/yaml/yaml_datastructs_funcs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index 92b5a9fae07..ea5bc9b6b23 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -845,6 +845,7 @@ static uint32_t r_swtchSrc(const YamlNode* node, const char* val, uint8_t val_le && val[3] >= '0' && val[3] <= '2') { ival = switchLookupIdx(val, val_len - 1) * 3; + if (ival < 0) return SWSRC_NONE; ival += yaml_str2int(val + 3, val_len - 2); ival += SWSRC_FIRST_SWITCH; @@ -853,6 +854,7 @@ static uint32_t r_swtchSrc(const YamlNode* node, const char* val, uint8_t val_le && val[2] >= '0' && val[2] <= '2') { ival = switchLookupIdx(val, val_len - 1) * 3; + if (ival < 0) return SWSRC_NONE; ival += yaml_str2int(val + 2, val_len - 2); ival += SWSRC_FIRST_SWITCH; From 0aff002c8a81910993e1fc4f184910742a3b12a0 Mon Sep 17 00:00:00 2001 From: philmoz Date: Thu, 21 Sep 2023 19:39:05 +1000 Subject: [PATCH 03/29] chore(color): Cleanup and optimise EdgeTxTheme class (#4013) --- .../src/firmwares/customisation_data.cpp | 17 - companion/src/firmwares/customisation_data.h | 18 -- .../firmwares/edgetx/yaml_generalsettings.cpp | 6 - companion/src/firmwares/generalsettings.h | 2 - .../src/firmwares/opentx/opentxeeprom.cpp | 16 - .../src/modeledit/colorcustomscreens.cpp | 7 - radio/src/datastructs.h | 6 +- radio/src/datastructs_private.h | 13 - radio/src/gui/colorlcd/curve.cpp | 1 + radio/src/gui/colorlcd/draw_functions.cpp | 1 + radio/src/gui/colorlcd/fab_button.cpp | 2 +- radio/src/gui/colorlcd/fullscreen_dialog.cpp | 1 + radio/src/gui/colorlcd/gui.h | 1 - radio/src/gui/colorlcd/layout.cpp | 1 + radio/src/gui/colorlcd/layout.h | 3 - .../colorlcd/layouts/layout_factory_impl.h | 5 - .../src/gui/colorlcd/layouts/topbar_impl.cpp | 1 + radio/src/gui/colorlcd/page.cpp | 1 + radio/src/gui/colorlcd/tabsgroup.cpp | 1 + radio/src/gui/colorlcd/theme.cpp | 295 ++++++++++-------- radio/src/gui/colorlcd/theme.h | 118 ++----- radio/src/gui/colorlcd/theme_manager.cpp | 22 +- radio/src/gui/colorlcd/themes/480_default.cpp | 239 -------------- radio/src/gui/colorlcd/view_main.cpp | 1 + radio/src/gui/colorlcd/widget.cpp | 1 + radio/src/gui/colorlcd/widgets/radio_info.cpp | 15 +- radio/src/lua/api_colorlcd.cpp | 3 +- radio/src/main.cpp | 1 + radio/src/myeeprom.h | 1 - radio/src/opentx.cpp | 10 +- radio/src/storage/sdcard_common.cpp | 6 +- .../storage/yaml/yaml_datastructs_nv14.cpp | 54 ++-- .../src/storage/yaml/yaml_datastructs_x10.cpp | 54 ++-- .../storage/yaml/yaml_datastructs_x12s.cpp | 54 ++-- .../libopenui/src/libopenui_defines.h | 3 +- 35 files changed, 306 insertions(+), 674 deletions(-) delete mode 100644 radio/src/gui/colorlcd/themes/480_default.cpp diff --git a/companion/src/firmwares/customisation_data.cpp b/companion/src/firmwares/customisation_data.cpp index ad91cfc8358..ebca3c3b61b 100644 --- a/companion/src/firmwares/customisation_data.cpp +++ b/companion/src/firmwares/customisation_data.cpp @@ -132,23 +132,6 @@ bool RadioLayout::CustomScreenData::isEmpty() const return strlen(layoutId) == 0; } -void RadioTheme::init(const char* themeName, ThemeData& themeData) -{ - memset(&themeData, 0, sizeof(ThemeData)); - - memcpy(&themeData.themeName, themeName, THEME_NAME_LEN); - - PersistentData& persistentData = themeData.themePersistentData; - - persistentData.options[0].type = - zoneValueEnumFromType(ZoneOption::Type::Color); - setZoneOptionValue(persistentData.options[0].value, (unsigned int)WHITE); - - persistentData.options[1].type = - zoneValueEnumFromType(ZoneOption::Type::Color); - setZoneOptionValue(persistentData.options[1].value, (unsigned int)RED); -} - void RadioLayout::init(const char* layoutId, CustomScreens& customScreens) { memset(&customScreens, 0, sizeof(CustomScreens)); diff --git a/companion/src/firmwares/customisation_data.h b/companion/src/firmwares/customisation_data.h index 7496bcca1ad..043707fac47 100644 --- a/companion/src/firmwares/customisation_data.h +++ b/companion/src/firmwares/customisation_data.h @@ -31,7 +31,6 @@ */ constexpr int MAX_CUSTOM_SCREENS {10}; -constexpr int THEME_NAME_LEN {8}; constexpr int MAX_THEME_OPTIONS {5}; constexpr int LEN_ZONE_OPTION_STRING {8}; constexpr int MAX_LAYOUT_ZONES {10}; @@ -146,23 +145,6 @@ typedef WidgetsContainerPersistentData typedef WidgetsContainerPersistentData TopBarPersistentData; -class RadioTheme -{ - Q_DECLARE_TR_FUNCTIONS(RadioTheme) - - public: - struct PersistentData { - ZoneOptionValueTyped options[MAX_THEME_OPTIONS]; - }; - - struct ThemeData { - char themeName[THEME_NAME_LEN + 1]; - PersistentData themePersistentData; - }; - - static void init(const char * themeName, ThemeData & themeData); -}; - class RadioLayout { Q_DECLARE_TR_FUNCTIONS(RadioLayout) diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp index 6e0cd4eee3c..373e4d42307 100644 --- a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp @@ -299,9 +299,6 @@ Node convert::encode(const GeneralSettings& rhs) node["potsConfig"] = potsConfig; } - // Color lcd theme settings are not used in EdgeTx - // RadioTheme::ThemeData themeData; - node["ownerRegistrationID"] = rhs.registrationId; // Gyro (for now only xlites) @@ -573,9 +570,6 @@ bool convert::decode(const Node& node, GeneralSettings& rhs) } } - // Color lcd theme settings are not used in EdgeTx - // RadioTheme::ThemeData themeData; - node["ownerRegistrationID"] >> rhs.registrationId; // Gyro (for now only xlites) diff --git a/companion/src/firmwares/generalsettings.h b/companion/src/firmwares/generalsettings.h index f5b40e23ca2..f651716f40c 100644 --- a/companion/src/firmwares/generalsettings.h +++ b/companion/src/firmwares/generalsettings.h @@ -277,8 +277,6 @@ class GeneralSettings { char sliderName[CPN_MAX_SLIDERS][HARDWARE_NAME_LEN + 1]; unsigned int sliderConfig[CPN_MAX_SLIDERS]; - RadioTheme::ThemeData themeData; - char registrationId[REGISTRATION_ID_LEN + 1]; int gyroMax; int gyroOffset; diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index d6247523368..1199208ecb0 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -3304,15 +3304,6 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type internalField.Append(new ZCharField<10>(this, generalData.bluetoothName, "Bluetooth name")); } - if (IS_FAMILY_HORUS_OR_T16(board)) { - if (version >= 220) { // data from earlier versions cannot be converted so fields initialised in afterImport - internalField.Append(new CharField<8>(this, generalData.themeData.themeName, true, "Theme name")); - for (int i = 0; i < MAX_THEME_OPTIONS; i++) { - internalField.Append(new ZoneOptionValueTypedField(this, generalData.themeData.themePersistentData.options[i], board, version)); - } - } - } - if (version >= 220) { internalField.Append(new CharField<8>(this, generalData.registrationId, "ACCESS Registration ID")); } @@ -3357,13 +3348,6 @@ void OpenTxGeneralData::beforeExport() void OpenTxGeneralData::afterImport() { - if (IS_FAMILY_HORUS_OR_T16(board)) { - if (version < 220) { // re-initialise as no conversion possible - const char * themeName = IS_FLYSKY_NV14(board) ? "FlySky" : "EdgeTX"; - RadioTheme::init(themeName, generalData.themeData); - } - } - if (Boards::getCapability((Board::Type)generalData.variant, Board::SportMaxBaudRate) >= 400000) generalData.internalModuleBaudrate = diff --git a/companion/src/modeledit/colorcustomscreens.cpp b/companion/src/modeledit/colorcustomscreens.cpp index 90a8d5fd941..6b7736fb28a 100644 --- a/companion/src/modeledit/colorcustomscreens.cpp +++ b/companion/src/modeledit/colorcustomscreens.cpp @@ -39,8 +39,6 @@ UserInterfacePanel::UserInterfacePanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): ModelPanel(parent, model, generalSettings, firmware) { - RadioTheme::ThemeData & td = generalSettings.themeData; - QString sdPath = QString(g.profile[g.id()].sdPath()).trimmed(); grid = new QGridLayout(this); @@ -191,11 +189,6 @@ UserInterfacePanel::UserInterfacePanel(QWidget * parent, ModelData & model, Gene col = 0; - if (SHOW_RAW_INFO) { - addGridLabel(grid, tr("Theme"), row, col++); - grid->addLayout(addOptionsLayout(td.themePersistentData, MAX_THEME_OPTIONS), row, col); - } - // the grid must be fully built for the rowspan to work as required foreach (QWidget * wgt, optswidgets) { grid->addWidget(wgt, widgetdetailsrow, widgetdetailscol, 3, Qt::AlignTop); diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 4907f81ab1d..f35d37e2ae9 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -147,14 +147,14 @@ static inline void check_struct() CHKSIZE(ModelData, 6706); #elif defined(PCBHORUS) #if defined(PCBX10) - CHKSIZE(RadioData, 916); + CHKSIZE(RadioData, 848); CHKSIZE(ModelData, 15607); #else - CHKSIZE(RadioData, 916); + CHKSIZE(RadioData, 848); CHKSIZE(ModelData, 15607); #endif #elif defined(PCBNV14) - CHKSIZE(RadioData, 916); + CHKSIZE(RadioData, 848); CHKSIZE(ModelData, 15463); #endif diff --git a/radio/src/datastructs_private.h b/radio/src/datastructs_private.h index 0dd13401e08..347730b1357 100644 --- a/radio/src/datastructs_private.h +++ b/radio/src/datastructs_private.h @@ -830,16 +830,6 @@ PACK(struct TrainerData { BLUETOOTH_FIELDS #endif -#if defined(COLORLCD) && !defined(BACKUP) - #include "theme.h" - #define THEME_NAME_LEN 8 - #define THEME_DATA \ - NOBACKUP(char themeName[THEME_NAME_LEN]); \ - NOBACKUP(EdgeTxTheme::PersistentData themeData); -#else - #define THEME_DATA -#endif - #if defined(BUZZER) #define BUZZER_FIELD int8_t buzzerMode:2 // -2=quiet, -1=only alarms, 0=no keys, 1=all (only used on AVR radios without audio hardware) #else @@ -934,8 +924,6 @@ PACK(struct RadioData { EXTRA_GENERAL_FIELDS - THEME_DATA - char ownerRegistrationID[PXX2_LEN_REGISTRATION_ID]; CUST_ATTR(rotEncDirection, r_rotEncDirection, nullptr); @@ -992,5 +980,4 @@ PACK(struct RadioData { #undef SCRIPTS_DATA #undef CUSTOM_SCREENS_DATA #undef EXTRA_GENERAL_FIELDS -#undef THEME_DATA #undef NOBACKUP diff --git a/radio/src/gui/colorlcd/curve.cpp b/radio/src/gui/colorlcd/curve.cpp index e096d8a7fcb..14ee870db27 100644 --- a/radio/src/gui/colorlcd/curve.cpp +++ b/radio/src/gui/colorlcd/curve.cpp @@ -25,6 +25,7 @@ #include "bitmaps.h" #include "strhelpers.h" #include "font.h" +#include "theme.h" const uint8_t _LBM_CURVE_POINT[] = { #include "mask_cvpoint.lbm" diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp index 06f9e736473..1823203b104 100644 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ b/radio/src/gui/colorlcd/draw_functions.cpp @@ -23,6 +23,7 @@ #include "lcd.h" #include "theme_manager.h" #include "libopenui.h" +#include "theme.h" #include "watchdog_driver.h" diff --git a/radio/src/gui/colorlcd/fab_button.cpp b/radio/src/gui/colorlcd/fab_button.cpp index 8fb211b1660..424d4b443c5 100644 --- a/radio/src/gui/colorlcd/fab_button.cpp +++ b/radio/src/gui/colorlcd/fab_button.cpp @@ -57,7 +57,7 @@ void FabButton::paint(BitmapBuffer * dc) dc->drawBitmap((width() - bitmap->width()) / 2, (FAB_BUTTON_SIZE - bitmap->height()) / 2, bitmap); - const BitmapBuffer* mask = theme->getIconMask(icon); + const BitmapBuffer* mask = EdgeTxTheme::instance()->getIconMask(icon); if (mask) { dc->drawMask((width() - mask->width()) / 2, (FAB_BUTTON_SIZE - mask->height()) / 2, mask, COLOR2FLAGS(WHITE)); diff --git a/radio/src/gui/colorlcd/fullscreen_dialog.cpp b/radio/src/gui/colorlcd/fullscreen_dialog.cpp index b5306f54f75..f973bb74dcd 100644 --- a/radio/src/gui/colorlcd/fullscreen_dialog.cpp +++ b/radio/src/gui/colorlcd/fullscreen_dialog.cpp @@ -24,6 +24,7 @@ #include "mainwindow.h" #include "opentx.h" #include "libopenui.h" +#include "theme.h" #include "watchdog_driver.h" diff --git a/radio/src/gui/colorlcd/gui.h b/radio/src/gui/colorlcd/gui.h index 00b49c06893..b8f9fcfa502 100644 --- a/radio/src/gui/colorlcd/gui.h +++ b/radio/src/gui/colorlcd/gui.h @@ -28,7 +28,6 @@ #include "popups.h" #include "draw_functions.h" #include "bitmaps.h" -#include "theme.h" #define LOAD_MODEL_BITMAP() diff --git a/radio/src/gui/colorlcd/layout.cpp b/radio/src/gui/colorlcd/layout.cpp index cddf6fabe51..8b5651da222 100644 --- a/radio/src/gui/colorlcd/layout.cpp +++ b/radio/src/gui/colorlcd/layout.cpp @@ -22,6 +22,7 @@ #include "opentx.h" #include "view_main.h" #include "topbar_impl.h" +#include "theme.h" WidgetsContainer * customScreens[MAX_CUSTOM_SCREENS] = {}; diff --git a/radio/src/gui/colorlcd/layout.h b/radio/src/gui/colorlcd/layout.h index 6fc86412780..301b11a0c76 100644 --- a/radio/src/gui/colorlcd/layout.h +++ b/radio/src/gui/colorlcd/layout.h @@ -52,9 +52,6 @@ class LayoutFactory virtual const uint8_t* getBitmap() const = 0; - virtual void drawThumb(BitmapBuffer* dc, uint16_t x, uint16_t y, - LcdFlags flags) const = 0; - virtual const ZoneOption* getOptions() const = 0; virtual WidgetsContainer* create(Window* parent, diff --git a/radio/src/gui/colorlcd/layouts/layout_factory_impl.h b/radio/src/gui/colorlcd/layouts/layout_factory_impl.h index 56d0d62518c..b2e043c5972 100644 --- a/radio/src/gui/colorlcd/layouts/layout_factory_impl.h +++ b/radio/src/gui/colorlcd/layouts/layout_factory_impl.h @@ -206,11 +206,6 @@ class BaseLayoutFactory: public LayoutFactory const uint8_t* getBitmap() const override { return bitmap; } - void drawThumb(BitmapBuffer * dc, uint16_t x, uint16_t y, uint32_t flags) const override - { - dc->drawBitmapPattern(x, y, bitmap, flags); - } - const ZoneOption * getOptions() const override { return options; diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp index d6d8d7b233c..474855672b9 100644 --- a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp @@ -21,6 +21,7 @@ #include "topbar_impl.h" #include "opentx.h" +#include "theme.h" constexpr uint32_t TOPBAR_REFRESH = 1000 / 10; // 10 Hz diff --git a/radio/src/gui/colorlcd/page.cpp b/radio/src/gui/colorlcd/page.cpp index a75966db427..aa749585a98 100644 --- a/radio/src/gui/colorlcd/page.cpp +++ b/radio/src/gui/colorlcd/page.cpp @@ -23,6 +23,7 @@ #include "mainwindow.h" #include "keyboard_base.h" #include "opentx.h" +#include "theme.h" PageHeader::PageHeader(Page * parent, uint8_t icon): FormWindow(parent, { 0, 0, LCD_W, MENU_HEADER_HEIGHT }, OPAQUE), diff --git a/radio/src/gui/colorlcd/tabsgroup.cpp b/radio/src/gui/colorlcd/tabsgroup.cpp index b9be76edae3..4e87c61a5a4 100644 --- a/radio/src/gui/colorlcd/tabsgroup.cpp +++ b/radio/src/gui/colorlcd/tabsgroup.cpp @@ -24,6 +24,7 @@ #include "mainwindow.h" #include "view_main.h" #include "static.h" +#include "theme.h" #if defined(HARDWARE_TOUCH) #include "keyboard_base.h" diff --git a/radio/src/gui/colorlcd/theme.cpp b/radio/src/gui/colorlcd/theme.cpp index 319a905a2e4..74d5c88bcb0 100644 --- a/radio/src/gui/colorlcd/theme.cpp +++ b/radio/src/gui/colorlcd/theme.cpp @@ -21,14 +21,8 @@ #include "opentx.h" #include "libopenui.h" - -extern EdgeTxTheme * defaultTheme; -const BitmapBuffer * EdgeTxTheme::error = nullptr; -const BitmapBuffer * EdgeTxTheme::busy = nullptr; -const BitmapBuffer * EdgeTxTheme::shutdown = nullptr; - -constexpr coord_t LBM_USB_PLUGGED_W = 211; -constexpr coord_t LBM_USB_PLUGGED_H = 110; +#include "theme.h" +#include "theme_manager.h" const uint8_t _LBM_USB_PLUGGED[] = { #include "mask_usb_symbol.lbm" @@ -47,166 +41,217 @@ const uint8_t shutdown_bitmap[] = { #include "mask_shutdown.lbm" }; -std::list & getRegisteredThemes() -{ - static std::list themes; - return themes; -} +const uint8_t mask_topleft[] = { +#include "mask_topleft.lbm" +}; -void registerTheme(EdgeTxTheme * theme) -{ - TRACE("register theme %s", theme->getName()); - getRegisteredThemes().push_back(theme); -} +const uint8_t mask_currentmenu_bg[] = { +#include "mask_currentmenu_bg.lbm" +}; + +const uint8_t mask_currentmenu_dot[] = { +#include "mask_currentmenu_dot.lbm" +}; + +const uint8_t mask_currentmenu_shadow[] = { +#include "mask_currentmenu_shadow.lbm" +}; + +uint16_t EdgeTxTheme::defaultColors[LCD_COLOR_COUNT] = { + RGB(18, 94, 153), // DEFAULT + RGB(0, 0, 0), // PRIMARY1 + RGB(255, 255, 255), // PRIMARY2 + RGB(12, 63, 102), // PRIMARY3 + RGB(18, 94, 153), // SECONDARY1 + RGB(182, 224, 242), // SECONDARY2 + RGB(228, 238, 242), // SECONDARY3 + RGB(20, 161, 229), // FOCUS + RGB(0, 153, 9), // EDIT + RGB(255, 222, 0), // ACTIVE + RGB(224, 0, 0), // WARNING + RGB(140, 140, 140), // DISABLED + RGB(170, 85, 0) // CUSTOM +}; -void EdgeTxTheme::init() const +EdgeTxTheme::EdgeTxTheme(): name("EdgeTX") { - memset(&g_eeGeneral.themeData, 0, sizeof(EdgeTxTheme::PersistentData)); - if (options) { - int i = 0; - for (const ZoneOption * option = options; option->name; option++, i++) { - // TODO compiler bug? The CPU freezes ... g_eeGeneral.themeData.options[i] = &option->deflt; - memcpy(&g_eeGeneral.themeData.options[i].value, &option->deflt, sizeof(ZoneOptionValue)); - g_eeGeneral.themeData.options[i].type = zoneValueEnumFromType(option->type); - } - } + loadColors(); } -void EdgeTxTheme::load() const +void EdgeTxTheme::load() { + loadColors(); + ThemePersistance::instance()->loadDefaultTheme(); + if (!error) error = BitmapBuffer::load8bitMaskLZ4(error_bitmap); if (!busy) busy = BitmapBuffer::load8bitMaskLZ4(busy_bitmap); if (!shutdown) shutdown = BitmapBuffer::load8bitMaskLZ4(shutdown_bitmap); + + update(); +} + +void EdgeTxTheme::update() +{ + createIcons(); + loadIcons(); + if (!backgroundBitmap) { + backgroundBitmap = BitmapBuffer::loadBitmap(getFilePath("background.png")); + } + initLvglTheme(); +} + +void EdgeTxTheme::loadColors() const +{ + TRACE("Load EdgeTX theme colors"); + memcpy(lcdColorTable, defaultColors, sizeof(defaultColors)); +} + +void EdgeTxTheme::createIcons() +{ + if (!iconsLoaded) { + iconsLoaded = true; + + iconMask = new BitmapBuffer*[MENUS_ICONS_COUNT]; + for (int id = ICON_EDGETX; id != MENUS_ICONS_COUNT; id++) { + iconMask[id] = BitmapBuffer::load8bitMaskLZ4(getBuiltinIcon((MenuIcons)id)); + } + + // Get mask with max size. Extract size from shadow LBM file. + uint16_t* shadow = (uint16_t*)mask_currentmenu_shadow; + currentMenuBackground = new BitmapBuffer(BMP_RGB565, shadow[0], shadow[1]); + + topleftBitmap = BitmapBuffer::load8bitMaskLZ4(mask_topleft); + + loadBuiltinBitmaps(); + } +} + +void EdgeTxTheme::loadIcons() const +{ + if (currentMenuBackground) { + currentMenuBackground->drawSolidFilledRect( + 0, 0, currentMenuBackground->width(), currentMenuBackground->height(), + COLOR_THEME_SECONDARY1); + + currentMenuBackground->drawSolidFilledRect( + 0, MENU_HEADER_HEIGHT, currentMenuBackground->width(), + MENU_TITLE_TOP - MENU_HEADER_HEIGHT, COLOR_THEME_SECONDARY3); + + std::unique_ptr background(BitmapBuffer::load8bitMaskLZ4(mask_currentmenu_bg)); + currentMenuBackground->drawMask(0, 0, background.get(), COLOR_THEME_FOCUS); + + std::unique_ptr shadow(BitmapBuffer::load8bitMaskLZ4(mask_currentmenu_shadow)); + currentMenuBackground->drawMask(0, 0, shadow.get(), COLOR_THEME_PRIMARY1); + + std::unique_ptr dot(BitmapBuffer::load8bitMaskLZ4(mask_currentmenu_dot)); + currentMenuBackground->drawMask(10, 39, dot.get(), COLOR_THEME_PRIMARY2); + } } -ZoneOptionValue * EdgeTxTheme::getOptionValue(unsigned int index) const +void EdgeTxTheme::setBackgroundImageFileName(const char *fileName) { - return &g_eeGeneral.themeData.options[index].value; + // ensure you delete old bitmap + if (backgroundBitmap != nullptr) + delete backgroundBitmap; + + strncpy(backgroundImageFileName, fileName, FF_MAX_LFN); + backgroundImageFileName[FF_MAX_LFN] = '\0'; // ensure string termination + + // Try to load bitmap. If this fails backgroundBitmap will be NULL and default will be loaded in update() method + backgroundBitmap = BitmapBuffer::loadBitmap(backgroundImageFileName); } const char * EdgeTxTheme::getFilePath(const char * filename) const { static char path[FF_MAX_LFN+1] = THEMES_PATH "/"; - strcpy(path + sizeof(THEMES_PATH), getName()); + strcpy(path + sizeof(THEMES_PATH), name); int len = sizeof(THEMES_PATH) + strlen(path + sizeof(THEMES_PATH)); path[len] = '/'; strcpy(path+len+1, filename); return path; } -void EdgeTxTheme::drawThumb(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t flags) -{ - #define THUMB_WIDTH 51 - #define THUMB_HEIGHT 31 - if (!thumb) { - thumb = BitmapBuffer::loadBitmap(getFilePath("thumb.bmp")); - } - lcd->drawBitmap(x, y, thumb); - if (flags == COLOR_THEME_PRIMARY3) { - dc->drawFilledRect(x, y, THUMB_WIDTH, THUMB_HEIGHT, SOLID, COLOR_THEME_PRIMARY1); - } -} - -void EdgeTxTheme::drawBackground(BitmapBuffer * dc) const +const BitmapBuffer * EdgeTxTheme::getIconMask(uint8_t index) const { - dc->drawSolidFilledRect(0, 0, LCD_W, LCD_H, COLOR_THEME_SECONDARY3); -} - -//void EdgeTxTheme::drawMessageBox(const char *title, const char *text, -// const char *action, uint32_t type) const -//{ -// //if (flags & MESSAGEBOX_TYPE_ALERT) { -// drawBackground(); -// lcdDrawFilledRect(0, POPUP_Y, LCD_W, POPUP_H, SOLID, COLOR_THEME_PRIMARY2 | -// OPACITY(8)); -// //} -// -// if (type == WARNING_TYPE_ALERT || type == WARNING_TYPE_ASTERISK) -// lcd->drawBitmap(POPUP_X-80, POPUP_Y+12, asterisk); -// else if (type == WARNING_TYPE_INFO) -// lcd->drawBitmap(POPUP_X-80, POPUP_Y+12, busy); -// else -// lcd->drawBitmap(POPUP_X-80, POPUP_Y+12, question); -// -// if (type == WARNING_TYPE_ALERT) { -//#if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || -//defined(TRANSLATIONS_CZ) -// lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y, STR_WARNING, -// COLOR_THEME_WARNING|FONT(XL)); lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y+28, -// title, COLOR_THEME_WARNING|FONT(XL)); -//#else -// lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y, title, COLOR_THEME_WARNING|FONT(XL)); -// lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y+28, STR_WARNING, -// COLOR_THEME_WARNING|FONT(XL)); -//#endif -// } -// else if (title) { -// lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y, title, COLOR_THEME_WARNING|FONT(XL)); -// } -// -// if (text) { -// lcdDrawText(WARNING_LINE_X, WARNING_INFOLINE_Y, text); -// } -// -// if (action) { -// lcdDrawText(WARNING_LINE_X, WARNING_INFOLINE_Y+24, action); -// } -//} - -void EdgeTxTheme::drawCheckBox(BitmapBuffer *dc, bool checked, coord_t x, - coord_t y, bool focus) const -{ - dc->drawSolidFilledRect(x, y, 16, 16, COLOR_THEME_PRIMARY2); - if (focus) { - dc->drawSolidRect(x, y, 16, 16, 2, COLOR_THEME_FOCUS); - } - else { - dc->drawSolidRect(x, y, 16, 16, 1, COLOR_THEME_SECONDARY2); - } - if (checked) { - dc->drawSolidFilledRect(x + 3, y + 3, 10, 10, COLOR_THEME_FOCUS); - } + return iconMask[index]; } void EdgeTxTheme::drawUsbPluggedScreen(BitmapBuffer * dc) const { // draw USB icon dc->clear(COLOR_THEME_SECONDARY3); - dc->drawBitmapPattern((LCD_W - LBM_USB_PLUGGED_W) / 2, - (LCD_H - LBM_USB_PLUGGED_H) / 2, + uint16_t* usb_icon_hdr = (uint16_t*)_LBM_USB_PLUGGED; + dc->drawBitmapPattern((LCD_W - usb_icon_hdr[0]) / 2, + (LCD_H - usb_icon_hdr[1]) / 2, LBM_USB_PLUGGED, COLOR_THEME_SECONDARY1); } +void EdgeTxTheme::drawBackground(BitmapBuffer * dc) const +{ + dc->clear(COLOR_THEME_SECONDARY3); + if (backgroundBitmap) + dc->drawBitmap(0, 0, backgroundBitmap); +} + +void EdgeTxTheme::drawHeaderIcon(BitmapBuffer * dc, uint8_t icon) const +{ + dc->drawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, COLOR_THEME_SECONDARY1); + + if (topleftBitmap) + dc->drawMask(0, 0, topleftBitmap, COLOR_THEME_FOCUS); + + if (icon == ICON_EDGETX) + dc->drawMask(4, 10, iconMask[icon], COLOR_THEME_PRIMARY2); + else + dc->drawMask(5, 7, iconMask[icon], COLOR_THEME_PRIMARY2); +} -EdgeTxTheme * getTheme(const char * name) +void EdgeTxTheme::drawPageHeaderBackground(BitmapBuffer *dc, uint8_t icon, const char *title) const { - std::list::const_iterator it = getRegisteredThemes().cbegin(); - for (; it != getRegisteredThemes().cend(); ++it) { - if (!strcmp(name, (*it)->getName())) { - return (*it); - } + drawHeaderIcon(dc, icon); + + dc->drawSolidFilledRect(0, MENU_HEADER_HEIGHT, LCD_W, + MENU_TITLE_TOP - MENU_HEADER_HEIGHT, + COLOR_THEME_SECONDARY3); // the white separation line + + dc->drawSolidFilledRect(0, MENU_TITLE_TOP, LCD_W, MENU_TITLE_HEIGHT, + COLOR_THEME_SECONDARY1); // the title line background + if (title) { + dc->drawText(MENUS_MARGIN_LEFT, MENU_TITLE_TOP + 1, title, COLOR_THEME_PRIMARY2); } - return nullptr; + + drawMenuDatetime(dc, DATETIME_MIDDLE, DATETIME_LINE1, COLOR_THEME_PRIMARY2); } -void loadTheme(EdgeTxTheme * newTheme) +void EdgeTxTheme::drawMenuDatetime(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags color) const { - TRACE("load theme %s", newTheme->getName()); - theme = newTheme; - newTheme->load(); + const TimerOptions timerOptions = {.options = SHOW_TIME}; + struct gtm t; + gettime(&t); + char str[10]; +#if defined(TRANSLATIONS_CN) || defined(TRANSLATIONS_TW) + sprintf(str, "%02d-%02d", t.tm_mon + 1, t.tm_mday); +#else + sprintf(str, "%d %s", t.tm_mday, STR_MONTHS[t.tm_mon]); +#endif + dc->drawText(x, y, str, FONT(XS)|color|CENTERED); + getTimerString(str, getValue(MIXSRC_TX_TIME), timerOptions); + dc->drawText(x, y + 15, str, FONT(XS)|color|CENTERED); } -void loadTheme() +void EdgeTxTheme::drawMenuIcon(BitmapBuffer *dc, uint8_t icon, bool checked) const { - char name[THEME_NAME_LEN + 1]; - memset(name, 0, sizeof(name)); - strncpy(name, g_eeGeneral.themeName, THEME_NAME_LEN); - EdgeTxTheme * newTheme = getTheme(name); - if (newTheme) - loadTheme(newTheme); - else - loadTheme(defaultTheme); + if (checked) + dc->drawBitmap(0, 0, currentMenuBackground); + dc->drawMask(2, 7, iconMask[icon], COLOR_THEME_PRIMARY2); +} + +EdgeTxTheme defaultTheme; + +EdgeTxTheme * EdgeTxTheme::instance() +{ + return &defaultTheme; } diff --git a/radio/src/gui/colorlcd/theme.h b/radio/src/gui/colorlcd/theme.h index df99cad2fdb..4f4b7d58970 100644 --- a/radio/src/gui/colorlcd/theme.h +++ b/radio/src/gui/colorlcd/theme.h @@ -19,17 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _COLORLCD_THEME_H_ -#define _COLORLCD_THEME_H_ - -#include -#include -#include "zone.h" - -enum IconState { - STATE_DEFAULT, - STATE_PRESSED, -}; +#pragma once // TODO: hotfix, through FatFS out of libopenui instead #if !defined(YAML_GENERATOR) @@ -39,104 +29,54 @@ enum IconState { #endif class BitmapBuffer; -class PageTab; - -#define MAX_THEME_OPTIONS 5 - -class EdgeTxTheme; -void registerTheme(EdgeTxTheme * theme); - -// YAML_GENERATOR defs -#if !defined(USE_IDX) -#define USE_IDX -#endif - -class EdgeTxTheme; -extern EdgeTxTheme * theme; class EdgeTxTheme { public: - struct PersistentData { - ZoneOptionValueTyped options[MAX_THEME_OPTIONS] USE_IDX; - }; - - explicit EdgeTxTheme(const char * name, const ZoneOption * options = nullptr): - name(name), - options(options), - thumb(nullptr) - { - registerTheme(this); - } - - static EdgeTxTheme * instance() - { - return theme; - } - - inline const char * getName() const - { - return name; - } - - const char * getFilePath(const char * filename) const; + EdgeTxTheme(); - void drawThumb(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t flags); + static EdgeTxTheme * instance(); - inline const ZoneOption * getOptions() const - { - return options; - } - - void init() const; - - virtual void update(bool reload = true) const - { - } - - ZoneOptionValue * getOptionValue(unsigned int index) const; + const char * getFilePath(const char * filename) const; - virtual void setBackgroundImageFileName(const char *fileName) - { - strncpy(backgroundImageFileName, fileName, FF_MAX_LFN); - backgroundImageFileName[FF_MAX_LFN] = '\0'; // ensure string termination - } + void createIcons(); + void loadColors() const; + void loadIcons() const; + virtual void load(); + void update(); - virtual void load() const; + void setBackgroundImageFileName(const char *fileName); - virtual void drawBackground(BitmapBuffer * dc) const; + void drawBackground(BitmapBuffer * dc) const; - virtual void drawPageHeaderBackground(BitmapBuffer *dc, uint8_t icon, - const char *title) const = 0; + void drawPageHeaderBackground(BitmapBuffer *dc, uint8_t icon, const char *title) const; - virtual void drawMenuIcon(BitmapBuffer *dc, uint8_t icon, bool checked) const = 0; + void drawMenuIcon(BitmapBuffer *dc, uint8_t icon, bool checked) const; - virtual void drawCheckBox(BitmapBuffer * dc, bool checked, coord_t x, coord_t y, bool focus) const; + void drawMenuDatetime(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags color) const; - virtual void drawHeaderIcon(BitmapBuffer * dc, uint8_t icon) const = 0; + void drawHeaderIcon(BitmapBuffer * dc, uint8_t icon) const; - virtual void drawUsbPluggedScreen(BitmapBuffer * dc) const; + void drawUsbPluggedScreen(BitmapBuffer * dc) const; - virtual const BitmapBuffer * getIconMask(uint8_t index) const = 0; + const BitmapBuffer * getIconMask(uint8_t index) const; - virtual uint16_t* getDefaultColors() const = 0; + uint16_t* getDefaultColors() const { return defaultColors; } protected: + bool iconsLoaded = false; const char * name; - const ZoneOption * options; - BitmapBuffer * thumb; char backgroundImageFileName[FF_MAX_LFN + 1]; - public: - static const BitmapBuffer * error; - static const BitmapBuffer * busy; - static const BitmapBuffer * shutdown; -}; - -EdgeTxTheme * getTheme(const char * name); -void loadTheme(EdgeTxTheme * theme); -void loadTheme(); + const BitmapBuffer * backgroundBitmap = nullptr; + const BitmapBuffer * topleftBitmap = nullptr; + BitmapBuffer * currentMenuBackground = nullptr; + BitmapBuffer ** iconMask = nullptr; -std::list & getRegisteredThemes(); + static uint16_t defaultColors[LCD_COLOR_COUNT]; -#endif // _COLORLCD_THEME_H_ + public: + const BitmapBuffer * error = nullptr; + const BitmapBuffer * busy = nullptr; + const BitmapBuffer * shutdown = nullptr; +}; diff --git a/radio/src/gui/colorlcd/theme_manager.cpp b/radio/src/gui/colorlcd/theme_manager.cpp index 7e442fe67e0..3d733a9a71d 100644 --- a/radio/src/gui/colorlcd/theme_manager.cpp +++ b/radio/src/gui/colorlcd/theme_manager.cpp @@ -20,6 +20,7 @@ */ #include "theme_manager.h" #include "view_main.h" +#include "theme.h" #include "../../storage/yaml/yaml_tree_walker.h" #include "../../storage/yaml/yaml_bits.h" @@ -245,26 +246,20 @@ void ThemeFile::applyBackground() if (isFileAvailable(rootDir.c_str())) { instance->setBackgroundImageFileName((char *)rootDir.c_str()); - } else { - // TODO: This needs to be made user configurable, not - // require the file be deleted to remove global background - std::string fileName = THEMES_PATH PATH_SEPARATOR "EdgeTX/background.png"; - if (isFileAvailable(fileName.c_str())) { - instance->setBackgroundImageFileName(fileName.c_str()); - } else { - instance->setBackgroundImageFileName(""); + return; } - } - } else { - instance->setBackgroundImageFileName(""); } + + // Use EdgeTxTheme default background + // TODO: This needs to be made user configurable + instance->setBackgroundImageFileName(""); } void ThemeFile::applyTheme() { applyColors(); applyBackground(); - EdgeTxTheme::instance()->update(false); + EdgeTxTheme::instance()->update(); // Update views with new theme // Currently, on startup, active theme is loaded after ViewMain is created so ViewMain instance is defined @@ -467,8 +462,7 @@ class DefaultEdgeTxTheme : public ThemeFile setInfo("Default EdgeTX Color Scheme"); // initializze the default color table - extern EdgeTxTheme * defaultTheme; - uint16_t* defaultColors = defaultTheme->getDefaultColors(); + uint16_t* defaultColors = EdgeTxTheme::instance()->getDefaultColors(); for (uint8_t i = COLOR_THEME_PRIMARY1_INDEX; i <= COLOR_THEME_DISABLED_INDEX; i += 1) colorList.emplace_back(ColorEntry { (LcdColorIndex)i, defaultColors[i] }); } diff --git a/radio/src/gui/colorlcd/themes/480_default.cpp b/radio/src/gui/colorlcd/themes/480_default.cpp deleted file mode 100644 index 19ad556c1b2..00000000000 --- a/radio/src/gui/colorlcd/themes/480_default.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * 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 "opentx.h" -#include "tabsgroup.h" -#include "bitmaps.h" -#include "theme_manager.h" - -#include -using std::unique_ptr; - -const ZoneOption OPTIONS_THEME_DEFAULT[] = { - { STR_BACKGROUND_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(COLOR_THEME_PRIMARY2 >> 16) }, - { STR_MAIN_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(COLOR_THEME_WARNING >> 16) }, - { nullptr, ZoneOption::Bool } -}; - -const uint8_t mask_topleft[] = { -#include "mask_topleft.lbm" -}; -const uint8_t mask_currentmenu_bg[] = { -#include "mask_currentmenu_bg.lbm" -}; -const uint8_t mask_currentmenu_dot[] = { -#include "mask_currentmenu_dot.lbm" -}; -const uint8_t mask_currentmenu_shadow[] = { -#include "mask_currentmenu_shadow.lbm" -}; - -class Theme480: public EdgeTxTheme -{ - public: - Theme480(): - EdgeTxTheme("EdgeTX", OPTIONS_THEME_DEFAULT) - { - loadColors(); - } - - void loadColors() const - { - TRACE("Load EdgeTX theme colors"); - memcpy(lcdColorTable, defaultColors, sizeof(defaultColors)); - } - - void createIcons() const - { - if (iconsLoaded) - return; - - iconsLoaded = true; - - for (int id = ICON_EDGETX; id != MENUS_ICONS_COUNT; id++) { - iconMask[id] = BitmapBuffer::load8bitMaskLZ4(getBuiltinIcon((MenuIcons)id)); - } - - // Get mask with max size - unique_ptr shadow(BitmapBuffer::load8bitMaskLZ4(mask_currentmenu_shadow)); - currentMenuBackground = new BitmapBuffer(BMP_RGB565, shadow->width(), shadow->height()); - - topleftBitmap = BitmapBuffer::load8bitMaskLZ4(mask_topleft); - - loadBuiltinBitmaps(); - } - - void loadIcons() const - { - if (currentMenuBackground) { - currentMenuBackground->drawSolidFilledRect( - 0, 0, currentMenuBackground->width(), currentMenuBackground->height(), - COLOR_THEME_SECONDARY1); - - currentMenuBackground->drawSolidFilledRect( - 0, MENU_HEADER_HEIGHT, currentMenuBackground->width(), - MENU_TITLE_TOP - MENU_HEADER_HEIGHT, COLOR_THEME_SECONDARY3); - - unique_ptr background(BitmapBuffer::load8bitMaskLZ4(mask_currentmenu_bg)); - currentMenuBackground->drawMask(0, 0, background.get(), COLOR_THEME_FOCUS); - - unique_ptr shadow(BitmapBuffer::load8bitMaskLZ4(mask_currentmenu_shadow)); - currentMenuBackground->drawMask(0, 0, shadow.get(), COLOR_THEME_PRIMARY1); - - unique_ptr dot(BitmapBuffer::load8bitMaskLZ4(mask_currentmenu_dot)); - currentMenuBackground->drawMask(10, 39, dot.get(), COLOR_THEME_PRIMARY2); - } - } - - void setBackgroundImageFileName(const char *fileName) override - { - // ensure you delete old bitmap - if (backgroundBitmap != nullptr) - delete backgroundBitmap; - EdgeTxTheme::setBackgroundImageFileName(fileName); // set the filename - backgroundBitmap = BitmapBuffer::loadBitmap(backgroundImageFileName); - } - - void load() const override - { - loadColors(); - ThemePersistance::instance()->loadDefaultTheme(); - EdgeTxTheme::load(); - if (!backgroundBitmap) { - backgroundBitmap = BitmapBuffer::loadBitmap(getFilePath("background.png")); - } - update(); - } - - void update(bool reload = true) const override - { - createIcons(); - loadIcons(); - initLvglTheme(); - } - - void drawBackground(BitmapBuffer * dc) const override - { - dc->clear(COLOR_THEME_SECONDARY3); - if (backgroundBitmap) - dc->drawBitmap(0, 0, backgroundBitmap); - } - - void drawHeaderIcon(BitmapBuffer * dc, uint8_t icon) const override - { - dc->drawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, COLOR_THEME_SECONDARY1); - - if (topleftBitmap) - dc->drawMask(0, 0, topleftBitmap, COLOR_THEME_FOCUS); - - if (icon == ICON_EDGETX) - dc->drawMask(4, 10, iconMask[icon], COLOR_THEME_PRIMARY2); - else - dc->drawMask(5, 7, iconMask[icon], COLOR_THEME_PRIMARY2); - } - - void drawPageHeaderBackground(BitmapBuffer *dc, uint8_t icon, - const char *title) const override - { - drawHeaderIcon(dc, icon); - - dc->drawSolidFilledRect(0, MENU_HEADER_HEIGHT, LCD_W, - MENU_TITLE_TOP - MENU_HEADER_HEIGHT, - COLOR_THEME_SECONDARY3); // the white separation line - - dc->drawSolidFilledRect(0, MENU_TITLE_TOP, LCD_W, MENU_TITLE_HEIGHT, - COLOR_THEME_SECONDARY1); // the title line background - if (title) { - dc->drawText(MENUS_MARGIN_LEFT, MENU_TITLE_TOP + 1, title, COLOR_THEME_PRIMARY2); - } - - drawMenuDatetime(dc); - } - - const BitmapBuffer * getIconMask(uint8_t index) const override - { - return iconMask[index]; - } - - void drawMenuIcon(BitmapBuffer *dc, uint8_t icon, bool checked) const override - { - if (checked) - dc->drawBitmap(0, 0, currentMenuBackground); - dc->drawMask(2, 7, iconMask[icon], COLOR_THEME_PRIMARY2); - } - - void drawMenuDatetime(BitmapBuffer * dc) const - { - //dc->drawSolidVerticalLine(DATETIME_SEPARATOR_X, 7, 31, COLOR_THEME_PRIMARY2); - const TimerOptions timerOptions = {.options = SHOW_TIME}; - struct gtm t; - gettime(&t); - char str[10]; -#if defined(TRANSLATIONS_CN) || defined(TRANSLATIONS_TW) - sprintf(str, "%02d-%02d", t.tm_mon + 1, t.tm_mday); -#else - sprintf(str, "%d %s", t.tm_mday, STR_MONTHS[t.tm_mon]); -#endif - dc->drawText(DATETIME_MIDDLE, DATETIME_LINE1, str, FONT(XS)|COLOR_THEME_PRIMARY2|CENTERED); - getTimerString(str, getValue(MIXSRC_TX_TIME), timerOptions); - dc->drawText(DATETIME_MIDDLE, DATETIME_LINE2, str, FONT(XS)|COLOR_THEME_PRIMARY2|CENTERED); - } - - uint16_t* getDefaultColors() const override { return defaultColors; } - - protected: - static bool iconsLoaded; - static const BitmapBuffer * backgroundBitmap; - static BitmapBuffer * topleftBitmap; - static BitmapBuffer * iconMask[MENUS_ICONS_COUNT]; - static BitmapBuffer * currentMenuBackground; - static uint16_t defaultColors[LCD_COLOR_COUNT]; -}; - -bool Theme480::iconsLoaded = false; - -const BitmapBuffer * Theme480::backgroundBitmap = nullptr; -BitmapBuffer * Theme480::topleftBitmap = nullptr; -BitmapBuffer * Theme480::iconMask[MENUS_ICONS_COUNT] = { nullptr }; -BitmapBuffer * Theme480::currentMenuBackground = nullptr; - -uint16_t Theme480::defaultColors[LCD_COLOR_COUNT] = { - RGB(18, 94, 153), // DEFAULT - RGB(0, 0, 0), // PRIMARY1 - RGB(255, 255, 255), // PRIMARY2 - RGB(12, 63, 102), // PRIMARY3 - RGB(18, 94, 153), // SECONDARY1 - RGB(182, 224, 242), // SECONDARY2 - RGB(228, 238, 242), // SECONDARY3 - RGB(20, 161, 229), // FOCUS - RGB(0, 153, 9), // EDIT - RGB(255, 222, 0), // ACTIVE - RGB(224, 0, 0), // WARNING - RGB(140, 140, 140), // DISABLED - RGB(170, 85, 0) // CUSTOM -}; - -Theme480 theme480; - -#if LCD_W == 480 || LCD_H == 480 -EdgeTxTheme * defaultTheme = &theme480; -EdgeTxTheme * theme = &theme480; -#endif diff --git a/radio/src/gui/colorlcd/view_main.cpp b/radio/src/gui/colorlcd/view_main.cpp index 9012faa7ab1..8c4bc52d827 100644 --- a/radio/src/gui/colorlcd/view_main.cpp +++ b/radio/src/gui/colorlcd/view_main.cpp @@ -26,6 +26,7 @@ #include "menu_screen.h" #include "topbar_impl.h" #include "view_main_menu.h" +#include "theme.h" #include "opentx.h" diff --git a/radio/src/gui/colorlcd/widget.cpp b/radio/src/gui/colorlcd/widget.cpp index 69f2e7b201e..19e0436fa2d 100644 --- a/radio/src/gui/colorlcd/widget.cpp +++ b/radio/src/gui/colorlcd/widget.cpp @@ -25,6 +25,7 @@ #include "widget_settings.h" #include "view_main.h" #include "lcd.h" +#include "theme.h" #if defined(HARDWARE_TOUCH) #include "touch.h" diff --git a/radio/src/gui/colorlcd/widgets/radio_info.cpp b/radio/src/gui/colorlcd/widgets/radio_info.cpp index 4cb2c7de02d..c2e4f9a2c2e 100644 --- a/radio/src/gui/colorlcd/widgets/radio_info.cpp +++ b/radio/src/gui/colorlcd/widgets/radio_info.cpp @@ -21,6 +21,7 @@ #include "opentx.h" #include "widgets_container_impl.h" +#include "theme.h" #define W_AUDIO_X 0 #define W_USB_X 32 @@ -192,19 +193,7 @@ class DateTimeWidget: public Widget { // get color from options LcdFlags color = COLOR2FLAGS(persistentData->options[0].value.unsignedValue); - - const TimerOptions timerOptions = {.options = SHOW_TIME}; - struct gtm t; - gettime(&t); - char str[10]; -#if defined(TRANSLATIONS_CN) || defined(TRANSLATIONS_TW) - sprintf(str, "%02d-%02d", t.tm_mon + 1, t.tm_mday); -#else - sprintf(str, "%d %s", t.tm_mday, STR_MONTHS[t.tm_mon]); -#endif - dc->drawText(width()/2+DT_OFFSET, 3, str, FONT(XS) | CENTERED | color); - getTimerString(str, getValue(MIXSRC_TX_TIME), timerOptions); - dc->drawText(width()/2+DT_OFFSET, 18, str, FONT(XS) | CENTERED | color); + EdgeTxTheme::instance()->drawMenuDatetime(dc, width()/2+DT_OFFSET, 3, color); } void checkEvents() override diff --git a/radio/src/lua/api_colorlcd.cpp b/radio/src/lua/api_colorlcd.cpp index 09cfc62bf46..9993e76c410 100644 --- a/radio/src/lua/api_colorlcd.cpp +++ b/radio/src/lua/api_colorlcd.cpp @@ -27,6 +27,7 @@ #include "opentx.h" #include "libopenui.h" #include "widget.h" +#include "theme.h" #include "lua_api.h" #include "api_colorlcd.h" @@ -971,7 +972,7 @@ static int luaLcdSetColor(lua_State *L) if (index < LCD_COLOR_COUNT && lcdColorTable[index] != color) { lcdColorTable[index] = color; if (index != CUSTOM_COLOR_INDEX) - EdgeTxTheme::instance()->update(false); + EdgeTxTheme::instance()->update(); } return 0; } diff --git a/radio/src/main.cpp b/radio/src/main.cpp index 0957794f4fc..2a2d4c2394e 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -26,6 +26,7 @@ #include "libopenui.h" #include "gui/colorlcd/LvglWrapper.h" #include "gui/colorlcd/view_main.h" + #include "theme.h" #endif #if defined(CLI) diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h index 90982531459..f68d61e0e56 100644 --- a/radio/src/myeeprom.h +++ b/radio/src/myeeprom.h @@ -118,7 +118,6 @@ #if defined(COLORLCD) && !defined(BOOT) #include "layout.h" - #include "theme.h" #include "topbar.h" #endif diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 725b328fee6..145e6e1cdf6 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -43,6 +43,7 @@ #include "radio_calibration.h" #include "view_main.h" #include "view_text.h" + #include "theme.h" #include "gui/colorlcd/LvglWrapper.h" #endif @@ -322,11 +323,6 @@ void generalDefault() strcpy(g_eeGeneral.currModelFilename, DEFAULT_MODEL_FILENAME); #endif -#if defined(COLORLCD) - strcpy(g_eeGeneral.themeName, static_cast(theme)->getName()); - static_cast(theme)->init(); -#endif - #if defined(PXX2) setDefaultOwnerId(); #endif @@ -1171,7 +1167,7 @@ void opentxResume() #if defined(COLORLCD) //TODO: needs to go into storageReadAll() TRACE("reloading theme"); - loadTheme(); + EdgeTxTheme::instance()->load(); // Force redraw ViewMain::instance()->invalidate(); @@ -1534,7 +1530,7 @@ void opentxInit() BACKLIGHT_ENABLE(); #if defined(COLORLCD) - loadTheme(); + EdgeTxTheme::instance()->load(); if (g_eeGeneral.backlightMode == e_backlight_mode_off) { // no backlight mode off on color lcd radios g_eeGeneral.backlightMode = e_backlight_mode_keys; diff --git a/radio/src/storage/sdcard_common.cpp b/radio/src/storage/sdcard_common.cpp index 6d3708fb82b..74badbb1b43 100644 --- a/radio/src/storage/sdcard_common.cpp +++ b/radio/src/storage/sdcard_common.cpp @@ -25,6 +25,10 @@ #include "modelslist.h" #include "model_init.h" +#if defined(COLORLCD) + #include "theme.h" +#endif + void getModelPath(char * path, const char * filename, const char* pathName) { unsigned int len = strlen(pathName); @@ -39,7 +43,7 @@ void storageEraseAll(bool warn) #if defined(COLORLCD) // the theme has not been loaded before - static_cast(theme)->load(); + EdgeTxTheme::instance()->load(); #endif // Init backlight mode before entering alert screens diff --git a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp index 623476a51ad..bfd7c0a05eb 100644 --- a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp @@ -87,15 +87,6 @@ const struct YamlIdStr enum_Functions[] = { { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, { 0, NULL } }; -const struct YamlIdStr enum_ZoneOptionValueEnum[] = { - { ZOV_Unsigned, "Unsigned" }, - { ZOV_Signed, "Signed" }, - { ZOV_Bool, "Bool" }, - { ZOV_String, "String" }, - { ZOV_Source, "Source" }, - { ZOV_Color, "Color" }, - { 0, NULL } -}; const struct YamlIdStr enum_TimerModes[] = { { TMRMODE_OFF, "OFF" }, { TMRMODE_ON, "ON" }, @@ -203,6 +194,15 @@ const struct YamlIdStr enum_TelemetrySensorType[] = { { TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" }, { 0, NULL } }; +const struct YamlIdStr enum_ZoneOptionValueEnum[] = { + { ZOV_Unsigned, "Unsigned" }, + { ZOV_Signed, "Signed" }, + { ZOV_Bool, "Bool" }, + { ZOV_String, "String" }, + { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, + { 0, NULL } +}; const struct YamlIdStr enum_USBJoystickIfMode[] = { { USBJOYS_JOYSTICK, "JOYSTICK" }, { USBJOYS_GAMEPAD, "GAMEPAD" }, @@ -276,25 +276,6 @@ static const struct YamlNode struct_CustomFunctionData[] = { YAML_PADDING( 8 ), YAML_END }; -static const struct YamlNode union_ZoneOptionValue_elmts[] = { - YAML_UNSIGNED( "unsignedValue", 32 ), - YAML_SIGNED( "signedValue", 32 ), - YAML_UNSIGNED( "boolValue", 32 ), - YAML_STRING("stringValue", 8), - YAML_CUSTOM("source",r_zov_source,w_zov_source), - YAML_CUSTOM("color",r_zov_color,w_zov_color), - YAML_END -}; -static const struct YamlNode struct_ZoneOptionValueTyped[] = { - YAML_IDX, - YAML_ENUM("type", 32, enum_ZoneOptionValueEnum), - YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov), - YAML_END -}; -static const struct YamlNode struct_EdgeTxTheme__PersistentData[] = { - YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL), - YAML_END -}; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "manuallyEdited", 1 ), YAML_SIGNED( "timezoneMinutes", 3 ), @@ -376,8 +357,6 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "blOffBright", 7 ), YAML_STRING("bluetoothName", 10), - YAML_STRING("themeName", 8), - YAML_STRUCT("themeData", 480, struct_EdgeTxTheme__PersistentData, NULL), YAML_STRING("ownerRegistrationID", 8), YAML_CUSTOM("rotEncDirection",r_rotEncDirection,nullptr), YAML_UNSIGNED( "rotEncMode", 2 ), @@ -767,6 +746,21 @@ static const struct YamlNode struct_TelemetrySensor[] = { YAML_UNION("cfg", 32, union_anonymous_17_elmts, select_sensor_cfg), YAML_END }; +static const struct YamlNode union_ZoneOptionValue_elmts[] = { + YAML_UNSIGNED( "unsignedValue", 32 ), + YAML_SIGNED( "signedValue", 32 ), + YAML_UNSIGNED( "boolValue", 32 ), + YAML_STRING("stringValue", 8), + YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), + YAML_END +}; +static const struct YamlNode struct_ZoneOptionValueTyped[] = { + YAML_IDX, + YAML_ENUM("type", 32, enum_ZoneOptionValueEnum), + YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov), + YAML_END +}; static const struct YamlNode struct_WidgetPersistentData[] = { YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL), YAML_END diff --git a/radio/src/storage/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/yaml/yaml_datastructs_x10.cpp index 35c2de0c4cd..df08bc1915b 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x10.cpp @@ -87,15 +87,6 @@ const struct YamlIdStr enum_Functions[] = { { FUNC_SET_SCREEN, "SET_SCREEN" }, { 0, NULL } }; -const struct YamlIdStr enum_ZoneOptionValueEnum[] = { - { ZOV_Unsigned, "Unsigned" }, - { ZOV_Signed, "Signed" }, - { ZOV_Bool, "Bool" }, - { ZOV_String, "String" }, - { ZOV_Source, "Source" }, - { ZOV_Color, "Color" }, - { 0, NULL } -}; const struct YamlIdStr enum_TimerModes[] = { { TMRMODE_OFF, "OFF" }, { TMRMODE_ON, "ON" }, @@ -210,6 +201,15 @@ const struct YamlIdStr enum_TelemetrySensorType[] = { { TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" }, { 0, NULL } }; +const struct YamlIdStr enum_ZoneOptionValueEnum[] = { + { ZOV_Unsigned, "Unsigned" }, + { ZOV_Signed, "Signed" }, + { ZOV_Bool, "Bool" }, + { ZOV_String, "String" }, + { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, + { 0, NULL } +}; const struct YamlIdStr enum_USBJoystickIfMode[] = { { USBJOYS_JOYSTICK, "JOYSTICK" }, { USBJOYS_GAMEPAD, "GAMEPAD" }, @@ -283,25 +283,6 @@ static const struct YamlNode struct_CustomFunctionData[] = { YAML_PADDING( 8 ), YAML_END }; -static const struct YamlNode union_ZoneOptionValue_elmts[] = { - YAML_UNSIGNED( "unsignedValue", 32 ), - YAML_SIGNED( "signedValue", 32 ), - YAML_UNSIGNED( "boolValue", 32 ), - YAML_STRING("stringValue", 8), - YAML_CUSTOM("source",r_zov_source,w_zov_source), - YAML_CUSTOM("color",r_zov_color,w_zov_color), - YAML_END -}; -static const struct YamlNode struct_ZoneOptionValueTyped[] = { - YAML_IDX, - YAML_ENUM("type", 32, enum_ZoneOptionValueEnum), - YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov), - YAML_END -}; -static const struct YamlNode struct_EdgeTxTheme__PersistentData[] = { - YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL), - YAML_END -}; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "manuallyEdited", 1 ), YAML_SIGNED( "timezoneMinutes", 3 ), @@ -381,8 +362,6 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "blOffBright", 7 ), YAML_STRING("bluetoothName", 10), - YAML_STRING("themeName", 8), - YAML_STRUCT("themeData", 480, struct_EdgeTxTheme__PersistentData, NULL), YAML_STRING("ownerRegistrationID", 8), YAML_CUSTOM("rotEncDirection",r_rotEncDirection,nullptr), YAML_UNSIGNED( "rotEncMode", 2 ), @@ -774,6 +753,21 @@ static const struct YamlNode struct_TelemetrySensor[] = { YAML_UNION("cfg", 32, union_anonymous_17_elmts, select_sensor_cfg), YAML_END }; +static const struct YamlNode union_ZoneOptionValue_elmts[] = { + YAML_UNSIGNED( "unsignedValue", 32 ), + YAML_SIGNED( "signedValue", 32 ), + YAML_UNSIGNED( "boolValue", 32 ), + YAML_STRING("stringValue", 8), + YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), + YAML_END +}; +static const struct YamlNode struct_ZoneOptionValueTyped[] = { + YAML_IDX, + YAML_ENUM("type", 32, enum_ZoneOptionValueEnum), + YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov), + YAML_END +}; static const struct YamlNode struct_WidgetPersistentData[] = { YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL), YAML_END diff --git a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp index 35c2de0c4cd..df08bc1915b 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp @@ -87,15 +87,6 @@ const struct YamlIdStr enum_Functions[] = { { FUNC_SET_SCREEN, "SET_SCREEN" }, { 0, NULL } }; -const struct YamlIdStr enum_ZoneOptionValueEnum[] = { - { ZOV_Unsigned, "Unsigned" }, - { ZOV_Signed, "Signed" }, - { ZOV_Bool, "Bool" }, - { ZOV_String, "String" }, - { ZOV_Source, "Source" }, - { ZOV_Color, "Color" }, - { 0, NULL } -}; const struct YamlIdStr enum_TimerModes[] = { { TMRMODE_OFF, "OFF" }, { TMRMODE_ON, "ON" }, @@ -210,6 +201,15 @@ const struct YamlIdStr enum_TelemetrySensorType[] = { { TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" }, { 0, NULL } }; +const struct YamlIdStr enum_ZoneOptionValueEnum[] = { + { ZOV_Unsigned, "Unsigned" }, + { ZOV_Signed, "Signed" }, + { ZOV_Bool, "Bool" }, + { ZOV_String, "String" }, + { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, + { 0, NULL } +}; const struct YamlIdStr enum_USBJoystickIfMode[] = { { USBJOYS_JOYSTICK, "JOYSTICK" }, { USBJOYS_GAMEPAD, "GAMEPAD" }, @@ -283,25 +283,6 @@ static const struct YamlNode struct_CustomFunctionData[] = { YAML_PADDING( 8 ), YAML_END }; -static const struct YamlNode union_ZoneOptionValue_elmts[] = { - YAML_UNSIGNED( "unsignedValue", 32 ), - YAML_SIGNED( "signedValue", 32 ), - YAML_UNSIGNED( "boolValue", 32 ), - YAML_STRING("stringValue", 8), - YAML_CUSTOM("source",r_zov_source,w_zov_source), - YAML_CUSTOM("color",r_zov_color,w_zov_color), - YAML_END -}; -static const struct YamlNode struct_ZoneOptionValueTyped[] = { - YAML_IDX, - YAML_ENUM("type", 32, enum_ZoneOptionValueEnum), - YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov), - YAML_END -}; -static const struct YamlNode struct_EdgeTxTheme__PersistentData[] = { - YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL), - YAML_END -}; static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "manuallyEdited", 1 ), YAML_SIGNED( "timezoneMinutes", 3 ), @@ -381,8 +362,6 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "blOffBright", 7 ), YAML_STRING("bluetoothName", 10), - YAML_STRING("themeName", 8), - YAML_STRUCT("themeData", 480, struct_EdgeTxTheme__PersistentData, NULL), YAML_STRING("ownerRegistrationID", 8), YAML_CUSTOM("rotEncDirection",r_rotEncDirection,nullptr), YAML_UNSIGNED( "rotEncMode", 2 ), @@ -774,6 +753,21 @@ static const struct YamlNode struct_TelemetrySensor[] = { YAML_UNION("cfg", 32, union_anonymous_17_elmts, select_sensor_cfg), YAML_END }; +static const struct YamlNode union_ZoneOptionValue_elmts[] = { + YAML_UNSIGNED( "unsignedValue", 32 ), + YAML_SIGNED( "signedValue", 32 ), + YAML_UNSIGNED( "boolValue", 32 ), + YAML_STRING("stringValue", 8), + YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), + YAML_END +}; +static const struct YamlNode struct_ZoneOptionValueTyped[] = { + YAML_IDX, + YAML_ENUM("type", 32, enum_ZoneOptionValueEnum), + YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov), + YAML_END +}; static const struct YamlNode struct_WidgetPersistentData[] = { YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL), YAML_END diff --git a/radio/src/thirdparty/libopenui/src/libopenui_defines.h b/radio/src/thirdparty/libopenui/src/libopenui_defines.h index f85d843720b..20198b8552f 100644 --- a/radio/src/thirdparty/libopenui/src/libopenui_defines.h +++ b/radio/src/thirdparty/libopenui/src/libopenui_defines.h @@ -71,8 +71,7 @@ constexpr uint32_t CURVE_COORD_WIDTH = 36; constexpr uint32_t CURVE_COORD_HEIGHT = 17; constexpr uint32_t DATETIME_SEPARATOR_X = LCD_W - 53; -constexpr uint32_t DATETIME_LINE1 = 7; -constexpr uint32_t DATETIME_LINE2 = 22; +constexpr uint32_t DATETIME_LINE1 = 6; constexpr uint32_t DATETIME_MIDDLE = (LCD_W + DATETIME_SEPARATOR_X + 1) / 2; constexpr uint32_t PAGE_TITLE_TOP = 2; From cd88057d02c9181f42131113427e7acc32cb7636 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Thu, 21 Sep 2023 19:41:42 +1000 Subject: [PATCH 04/29] chore(radio): Cleanup from #3753 & #3639 --- radio/src/storage/yaml/yaml_datastructs_nv14.cpp | 1 - radio/src/storage/yaml/yaml_datastructs_t20.cpp | 1 + radio/src/storage/yaml/yaml_datastructs_x10.cpp | 2 +- radio/src/storage/yaml/yaml_datastructs_x12s.cpp | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp index bfd7c0a05eb..cd51f89baf6 100644 --- a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp @@ -104,7 +104,6 @@ const struct YamlIdStr enum_MixerMultiplex[] = { }; const struct YamlIdStr enum_MixSources[] = { { MIXSRC_NONE, "NONE" }, - { MIXSRC_MIN, "MIN" }, { MIXSRC_MAX, "MAX" }, { MIXSRC_TrimRud, "TrimRud" }, diff --git a/radio/src/storage/yaml/yaml_datastructs_t20.cpp b/radio/src/storage/yaml/yaml_datastructs_t20.cpp index 2a788f32ca4..d62ea630724 100644 --- a/radio/src/storage/yaml/yaml_datastructs_t20.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_t20.cpp @@ -82,6 +82,7 @@ const struct YamlIdStr enum_Functions[] = { { FUNC_BACKLIGHT, "BACKLIGHT" }, { FUNC_SCREENSHOT, "SCREENSHOT" }, { FUNC_RACING_MODE, "RACING_MODE" }, + { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { diff --git a/radio/src/storage/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/yaml/yaml_datastructs_x10.cpp index df08bc1915b..25e150d391a 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x10.cpp @@ -82,9 +82,9 @@ const struct YamlIdStr enum_Functions[] = { { FUNC_BACKLIGHT, "BACKLIGHT" }, { FUNC_SCREENSHOT, "SCREENSHOT" }, { FUNC_RACING_MODE, "RACING_MODE" }, - { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, { FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" }, { FUNC_SET_SCREEN, "SET_SCREEN" }, + { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { diff --git a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp index df08bc1915b..25e150d391a 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp @@ -82,9 +82,9 @@ const struct YamlIdStr enum_Functions[] = { { FUNC_BACKLIGHT, "BACKLIGHT" }, { FUNC_SCREENSHOT, "SCREENSHOT" }, { FUNC_RACING_MODE, "RACING_MODE" }, - { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, { FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" }, { FUNC_SET_SCREEN, "SET_SCREEN" }, + { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, { 0, NULL } }; const struct YamlIdStr enum_TimerModes[] = { From 22a4e671177dba07015ff28419763d8f35bc1dd2 Mon Sep 17 00:00:00 2001 From: philmoz Date: Thu, 21 Sep 2023 19:47:46 +1000 Subject: [PATCH 05/29] feat(color): Add support for information bubble popups (#3903) * Add information bubble popup window. * Use fixed BLACK and WHITE colors. --- radio/src/gui/colorlcd/popups.cpp | 36 ++++++++++++++++++ radio/src/gui/colorlcd/popups.h | 1 + .../src/gui/colorlcd/themes/etx_lv_theme.cpp | 37 +++++++++++++++++++ .../thirdparty/libopenui/src/mainwindow.cpp | 7 ++++ .../libopenui/src/widgets/etx_obj_create.h | 1 + radio/src/thirdparty/libopenui/src/window.h | 2 + 6 files changed, 84 insertions(+) diff --git a/radio/src/gui/colorlcd/popups.cpp b/radio/src/gui/colorlcd/popups.cpp index 2aaf51f4da3..3a35b8c0783 100644 --- a/radio/src/gui/colorlcd/popups.cpp +++ b/radio/src/gui/colorlcd/popups.cpp @@ -111,3 +111,39 @@ void POPUP_WARNING_ON_UI_TASK(const char * message, const char * info, bool wait } } } + +class BubbleDialog : public Window +{ + public: + BubbleDialog(const char* message, int timeout) : + Window(MainWindow::instance(), rect_t{50, LCD_H - 100, LCD_W - 100, 50}, OPAQUE, 0, etx_bubble_popup_create) + { + lv_obj_set_parent(lvobj, lv_layer_top()); + + auto label = lv_label_create(lvobj); + lv_label_set_text(label, message); + lv_obj_center(label); + lv_obj_set_width(label, lv_pct(100)); + lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); + + endTime = RTOS_GET_MS() + timeout; + } + + bool isBubblePopup() override { return true; } + + void checkEvents() override + { + if (RTOS_GET_MS() >= endTime) { + deleteLater(); + } + } + + protected: + uint32_t endTime; +}; + +void POPUP_BUBBLE(const char* message, uint32_t timeout) +{ + new BubbleDialog(message, timeout); +} diff --git a/radio/src/gui/colorlcd/popups.h b/radio/src/gui/colorlcd/popups.h index 7cc4b9e8920..028a67018ad 100644 --- a/radio/src/gui/colorlcd/popups.h +++ b/radio/src/gui/colorlcd/popups.h @@ -28,5 +28,6 @@ typedef std::function ProgressHandle void POPUP_INFORMATION(const char * message); void POPUP_WARNING(const char * message, const char * info = nullptr); void POPUP_WARNING_ON_UI_TASK(const char * message, const char * info = nullptr, bool waitForClose = true); +void POPUP_BUBBLE(const char * message, uint32_t timeout); void show_ui_popup(); diff --git a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp index c47ace5a4a5..99bff6ba2a6 100644 --- a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp +++ b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp @@ -107,6 +107,8 @@ typedef struct { lv_style_t cb_marker; lv_style_t cb_marker_checked; + // Bubble popup + lv_style_t bubble_popup; } my_theme_styles_t; /********************** @@ -327,6 +329,14 @@ static void style_init(void) lv_style_init(&styles.cb_marker_checked); lv_style_set_bg_img_src(&styles.cb_marker_checked, LV_SYMBOL_OK); lv_style_set_text_font(&styles.cb_marker_checked, theme.font_small); + + // Bubble popup + lv_style_init(&styles.bubble_popup); + lv_style_set_bg_opa(&styles.bubble_popup, LV_OPA_COVER); + lv_style_set_pad_all(&styles.bubble_popup, 4); + lv_style_set_border_opa(&styles.bubble_popup, LV_OPA_COVER); + lv_style_set_border_width(&styles.bubble_popup, 3); + lv_style_set_radius(&styles.bubble_popup, 10); } // Always update colors in case theme changes @@ -395,6 +405,10 @@ static void style_init(void) lv_style_set_border_color(&styles.cb_marker_checked, makeLvColor(COLOR_THEME_SECONDARY1)); lv_style_set_bg_color(&styles.cb_marker_checked, makeLvColor(COLOR_THEME_SECONDARY1)); lv_style_set_text_color(&styles.cb_marker_checked, makeLvColor(COLOR_THEME_PRIMARY2)); + + lv_style_set_bg_color(&styles.bubble_popup, makeLvColor(COLOR2FLAGS(WHITE))); + lv_style_set_border_color(&styles.bubble_popup, makeLvColor(COLOR2FLAGS(BLACK))); + lv_style_set_text_color(&styles.bubble_popup, makeLvColor(COLOR2FLAGS(BLACK))); } /********************** @@ -598,6 +612,11 @@ void etx_checkbox_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) lv_obj_add_style(obj, &styles.disabled, LV_PART_INDICATOR | LV_STATE_DISABLED); } +void bubble_popup_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) +{ + lv_obj_add_style(obj, &styles.bubble_popup, 0); +} + } // Object classes @@ -796,6 +815,19 @@ const lv_obj_class_t etx_checkbox_class = { .instance_size = sizeof(lv_checkbox_t), }; +const lv_obj_class_t etx_bubble_popup_class = { + .base_class = &window_base_class, + .constructor_cb = bubble_popup_constructor, + .destructor_cb = nullptr, + .user_data = nullptr, + .event_cb = nullptr, + .width_def = LV_DPI_DEF, + .height_def = LV_DPI_DEF, + .editable = LV_OBJ_CLASS_EDITABLE_FALSE, + .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, + .instance_size = sizeof(lv_obj_t) +}; + // Event handlers static void field_edit_event(const lv_obj_class_t* class_p, lv_event_t* e) { @@ -913,6 +945,11 @@ lv_obj_t* etx_choice_create(lv_obj_t* parent) return etx_create(&etx_choice_class, parent); } +lv_obj_t* etx_bubble_popup_create(lv_obj_t* parent) +{ + return etx_create(&etx_bubble_popup_class, parent); +} + lv_obj_t* etx_bar_create(lv_obj_t* parent) { return etx_create(&etx_bar_class, parent); diff --git a/radio/src/thirdparty/libopenui/src/mainwindow.cpp b/radio/src/thirdparty/libopenui/src/mainwindow.cpp index 939e57eeb3e..da340e14001 100644 --- a/radio/src/thirdparty/libopenui/src/mainwindow.cpp +++ b/radio/src/thirdparty/libopenui/src/mainwindow.cpp @@ -43,6 +43,13 @@ void MainWindow::run(bool trash) auto opaque = Layer::getFirstOpaque(); if (opaque) opaque->checkEvents(); + auto copy = children; + for (auto child: copy) { + if (!child->deleted() && child->isBubblePopup()) { + child->checkEvents(); + } + } + if (trash) emptyTrash(); auto delta = ticksNow() - start; diff --git a/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h b/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h index e7c2902ee0c..ba71c6a80bd 100644 --- a/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h +++ b/radio/src/thirdparty/libopenui/src/widgets/etx_obj_create.h @@ -41,6 +41,7 @@ lv_obj_t* etx_modal_content_create(lv_obj_t* parent); lv_obj_t* etx_modal_title_create(lv_obj_t* parent); lv_obj_t* etx_bar_create(lv_obj_t* parent); lv_obj_t* etx_checkbox_create(lv_obj_t* parent); +lv_obj_t* etx_bubble_popup_create(lv_obj_t* parent); lv_obj_t* input_mix_line_create(lv_obj_t* parent); lv_obj_t* input_mix_group_create(lv_obj_t* parent); diff --git a/radio/src/thirdparty/libopenui/src/window.h b/radio/src/thirdparty/libopenui/src/window.h index 0eb72d082b9..4f464a81b52 100644 --- a/radio/src/thirdparty/libopenui/src/window.h +++ b/radio/src/thirdparty/libopenui/src/window.h @@ -204,6 +204,8 @@ class Window virtual bool isTopBar() { return false; } virtual bool isWidgetsContainer() { return false; } + virtual bool isBubblePopup() { return false; } + protected: static std::list trash; From ce03cbf65171e951d4d6d1a82086d7c3c5438210 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Thu, 21 Sep 2023 15:17:42 +0200 Subject: [PATCH 06/29] fix: yaml generator for clang 15 and up (#4076) * fix(yaml): use find_clang as for datacopy * fix: use library path provided by clang python package first * fix: anonymous structs and unions * fix: typedefd struct attributes --- radio/util/find_clang.py | 19 ++++++++++--------- radio/util/generate_yaml.py | 32 +++++++++++++------------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/radio/util/find_clang.py b/radio/util/find_clang.py index b240f62e66a..b3da3473682 100644 --- a/radio/util/find_clang.py +++ b/radio/util/find_clang.py @@ -4,6 +4,7 @@ # import os import sys + from clang.cindex import * # Check if libclang is able to find the builtin include files. @@ -28,6 +29,9 @@ def canFindBuiltinHeaders(index, args = []): # for all manual installations (the ones where the builtin header path problem # is very common) as well as a set of very common distributions. def getBuiltinHeaderPath(library_path): + if not library_path: + return None + if os.path.isfile(library_path): library_path = os.path.dirname(library_path) @@ -56,10 +60,11 @@ def getBuiltinHeaderPath(library_path): def findLibClang(): if sys.platform == "darwin": knownPaths = [ - "/usr/local/Cellar/llvm/6.0.0/lib", "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib", "/Library/Developer/CommandLineTools/usr/lib" ] + if Config.library_path: + knownPaths.insert(0, Config.library_path) libSuffix = ".dylib" elif sys.platform.startswith("linux"): knownPaths = [ @@ -90,17 +95,14 @@ def initLibClang(): library_path = findLibClang() if library_path: - #print("libclang found: " + library_path) + print("libclang found: " + library_path, file=sys.stderr) if os.path.isdir(library_path): Config.set_library_path(library_path) else: Config.set_library_file(library_path) - else: - print("ERROR: libclang not found!", file=sys.stderr) - return False Config.set_compatibility_check(False) - + try: index = Index.create() except Exception as e: @@ -109,9 +111,8 @@ def initLibClang(): global builtin_hdr_path builtin_hdr_path = getBuiltinHeaderPath(library_path) - if not builtin_hdr_path: - print("ERROR: builtin header path not found", file=sys.stderr) - return False + if builtin_hdr_path: + print("builtin header path found: " + builtin_hdr_path, file=sys.stderr) # Everything is OK, libclang can be used return True diff --git a/radio/util/generate_yaml.py b/radio/util/generate_yaml.py index 437e4f14668..7c7d0ccb4b2 100644 --- a/radio/util/generate_yaml.py +++ b/radio/util/generate_yaml.py @@ -1,6 +1,8 @@ #!/usr/bin/python import os import sys +import find_clang + from clang.cindex import * # debug @@ -145,7 +147,7 @@ def __init__(self, name, cursor): if self.type == 'char': self.type = 'string' else: - self.type = map_type(t.spelling) + self.type = map_type(t.get_canonical().spelling) class StructAST(AST_Element): @@ -158,7 +160,7 @@ def __init__(self, name, cursor, alt_name=''): if len(alt_name) > 0: name = alt_name - if name == '': + if name == '' or (isinstance(cursor,Cursor) and cursor.is_anonymous()): name = self.name_prefix() + 'anonymous_' + get_next_anon() else: name = self.name_prefix() + name @@ -491,23 +493,15 @@ def print_ast_node(ast_node): if len(sys.argv) < 2: bail_out(f"usage: {sys.argv[0]} [header file name] [template] [node name] [additional compile args]") -CLANG_LIB_LOCATIONS = [ - '/usr/local/Cellar/llvm/6.0.0/lib/libclang.dylib', - '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib', - '/Library/Developer/CommandLineTools/usr/lib/libclang.dylib', - '/usr/lib/x86_64-linux-gnu/libclang-6.0.so.1', - '/usr/lib/aarch64-linux-gnu/libclang-6.0.so.1' -] - -# set clang lib file -for lib in CLANG_LIB_LOCATIONS: - if os.path.exists(lib): - Config.set_library_file(lib) - break - -# compile source file -index = Index.create() -translation_unit = index.parse(sys.argv[1], ['-x', 'c++', '-std=c++11', '-Wno-deprecated-register'] + sys.argv[4:]) +if not find_clang.initLibClang(): + sys.exit(-1) + +index = find_clang.index +args = ['-x', 'c++', '-std=c++11', '-Wno-deprecated-register'] + sys.argv[4:] +if find_clang.builtin_hdr_path: + args.append("-I" + find_clang.builtin_hdr_path) + +translation_unit = index.parse(sys.argv[1], args) def show_tu_diags(diags, prefix=''): tu_errors = 0 From 45011771c0bc994252c5adbb46089bee9fbf2a9e Mon Sep 17 00:00:00 2001 From: philmoz Date: Fri, 22 Sep 2023 15:21:41 +1000 Subject: [PATCH 07/29] chore(radio): Use existing 'hash' function to detect USB joystick settings change (#4081) --- radio/src/usb_joystick.cpp | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/radio/src/usb_joystick.cpp b/radio/src/usb_joystick.cpp index 07f37e3147e..fc7178111bc 100644 --- a/radio/src/usb_joystick.cpp +++ b/radio/src/usb_joystick.cpp @@ -109,23 +109,6 @@ static const uint8_t HID_JOYSTICK_ReportDesc[] = static bool isUniqueAxisType(int type) { return type < 6; } static bool isUniqueSimType(int type) { return true; } -const uint32_t MOD_ADLER = 65521; - -uint32_t adler32(uint8_t *data, size_t len) -{ - uint32_t a = 1, b = 0; - size_t index; - - // Process each byte of the data in order - for (index = 0; index < len; ++index) - { - a = (a + data[index]) % MOD_ADLER; - b = (b + a) % MOD_ADLER; - } - - return (b << 16) | a; -} - int usbJoystickExtMode() { return g_model.usbJoystickExtMode; @@ -148,7 +131,7 @@ int usbJoystickSettingsChanged() return true; uint32_t oldChecksum = settingsChecksum; - settingsChecksum = adler32((uint8_t*)&g_model.usbJoystickCh, sizeof(g_model.usbJoystickCh)); + settingsChecksum = hash((uint8_t*)&g_model.usbJoystickCh, sizeof(g_model.usbJoystickCh)); return oldChecksum != settingsChecksum; } @@ -180,7 +163,7 @@ int setupUSBJoystick() // properties to detect change uint8_t oldHIDReportDescSize = _hidReportDescSize; - uint32_t oldChecksum = adler32(_hidReportDesc, _hidReportDescSize); + uint32_t oldChecksum = hash(_hidReportDesc, _hidReportDescSize); // copy the model snapshot _usbJoystickIfMode = g_model.usbJoystickIfMode; @@ -374,7 +357,7 @@ int setupUSBJoystick() //compare with the old description if (_hidReportDescSize != oldHIDReportDescSize) return true; - uint32_t newChecksum = adler32(_hidReportDesc, _hidReportDescSize); + uint32_t newChecksum = hash(_hidReportDesc, _hidReportDescSize); return oldChecksum != newChecksum; } From 752954fec5efdddfe942ba2e2f6582054fc84a6d Mon Sep 17 00:00:00 2001 From: philmoz Date: Fri, 22 Sep 2023 15:34:32 +1000 Subject: [PATCH 08/29] fix(color): Update background color on user interface page when theme changed (#4078) * Update background color on user interface page when theme is changed. * Refresh without redrawing entire page when theme changes. * chore: Remove completed TODOs, formatting --- .../gui/colorlcd/screen_user_interface.cpp | 135 ++++++++++-------- .../src/gui/colorlcd/screen_user_interface.h | 2 + 2 files changed, 77 insertions(+), 60 deletions(-) diff --git a/radio/src/gui/colorlcd/screen_user_interface.cpp b/radio/src/gui/colorlcd/screen_user_interface.cpp index cabc37f835f..a79ca9b6350 100644 --- a/radio/src/gui/colorlcd/screen_user_interface.cpp +++ b/radio/src/gui/colorlcd/screen_user_interface.cpp @@ -24,37 +24,6 @@ #include "file_preview.h" #include "menu_screen.h" -struct ThemeDetails : public Window { - ThemeDetails(Window* parent, ThemeFile* theme) : Window(parent, rect_t{}) - { - // vertical flow layout - lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_pad_row(lvobj, 2, LV_PART_MAIN); - - // make the object fill the grid cell - lv_obj_set_style_grid_cell_x_align(lvobj, LV_GRID_ALIGN_STRETCH, 0); - - // TODO: translation - new StaticText(this, rect_t{}, "Author", 0, - COLOR_THEME_PRIMARY1 | FONT(BOLD)); - auto txt = new StaticText(this, rect_t{}, theme->getAuthor(), 0, - COLOR_THEME_PRIMARY1); - - // labels default to LV_SIZE_CONTENT, - // which could overflow the width avail - auto obj = txt->getLvObj(); - lv_obj_set_width(obj, lv_pct(100)); - - // TODO: translation - new StaticText(this, rect_t{}, "Description", 0, - COLOR_THEME_PRIMARY1 | FONT(BOLD)); - txt = new StaticText(this, rect_t{}, theme->getInfo(), 0, - COLOR_THEME_PRIMARY1); - obj = txt->getLvObj(); - lv_obj_set_width(obj, lv_pct(100)); - } -}; - #if LCD_W > LCD_H // landscape // form grid @@ -85,6 +54,76 @@ static const lv_coord_t theme_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, constexpr coord_t MAX_PREVIEW_WIDTH = (100 * LV_DPI_DEF) / 57; constexpr coord_t MAX_PREVIEW_HEIGHT = LV_DPI_DEF; +class ThemeView : public FormWindow +{ + public: + ThemeView(Window* parent) : FormWindow(parent, rect_t{}) + { + padAll(0); + setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); + + update(); + } + + void update() + { + auto tp = ThemePersistance::instance(); + auto theme = tp->getCurrentTheme(); + + if (theme) { + if (!details) { + FlexGridLayout theme_grid(theme_col_dsc, theme_row_dsc); + auto line = newLine(&theme_grid); + + details = new Window(line, rect_t{}); + // vertical flow layout + lv_obj_set_flex_flow(details->getLvObj(), LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_row(details->getLvObj(), 2, LV_PART_MAIN); + + // make the object fill the grid cell + lv_obj_set_style_grid_cell_x_align(details->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); + + new StaticText(details, rect_t{}, STR_AUTHOR, 0, COLOR_THEME_PRIMARY1 | FONT(BOLD)); + author = new StaticText(details, rect_t{}, "", 0, COLOR_THEME_PRIMARY1); + + // labels default to LV_SIZE_CONTENT, + // which could overflow the width avail + lv_obj_set_width(author->getLvObj(), lv_pct(100)); + + new StaticText(details, rect_t{}, STR_DESCRIPTION, 0, COLOR_THEME_PRIMARY1 | FONT(BOLD)); + description = new StaticText(details, rect_t{}, "", 0, COLOR_THEME_PRIMARY1); + + lv_obj_set_width(description->getLvObj(), lv_pct(100)); + + preview = new FilePreview(line, rect_t{}, false); + + // center within cell + lv_obj_set_style_grid_cell_x_align(preview->getLvObj(), LV_GRID_ALIGN_CENTER, 0); + } + + author->setText(theme->getAuthor()); + description->setText(theme->getInfo()); + + auto themeImage = theme->getThemeImageFileNames(); + if (themeImage.size() > 0) { + preview->setFile(themeImage[0].c_str()); + + // adjust width according to max + preview->setWidth(min(MAX_PREVIEW_WIDTH, preview->getBitmapWidth())); + preview->setHeight(min(MAX_PREVIEW_HEIGHT, preview->getBitmapHeight())); + } else { + preview->setFile(""); + } + } + } + + protected: + Window* details = nullptr; + FilePreview* preview = nullptr; + StaticText* author = nullptr; + StaticText* description = nullptr; +}; + ScreenUserInterfacePage::ScreenUserInterfacePage(ScreenMenu* menu): PageTab(STR_USER_INTERFACE, ICON_THEME_SETUP), menu(menu) @@ -126,36 +165,12 @@ void ScreenUserInterfacePage::build(FormWindow* window) tp->setThemeIndex(value); tp->applyTheme(value); tp->setDefaultTheme(value); - - // TODO: shouldn't be necessary, would be better to send LV_EVENT_CHANGED - window->clear(); - build(window); + TabsGroup::refreshTheme(); + themeView->update(); }); - auto theme = tp->getCurrentTheme(); - FilePreview* preview = nullptr; - - if (theme) { - FlexGridLayout theme_grid(theme_col_dsc, theme_row_dsc); - line = window->newLine(&theme_grid); - - new ThemeDetails(line, theme); - - auto themeImage = theme->getThemeImageFileNames(); - if (themeImage.size() > 0) { - preview = new FilePreview(line, rect_t{}, false); - preview->setFile(themeImage[0].c_str()); - - // adjust width according to max - preview->setWidth(min(MAX_PREVIEW_WIDTH, preview->getBitmapWidth())); - preview->setHeight(min(MAX_PREVIEW_HEIGHT, preview->getBitmapHeight())); - - // center within cell - auto obj = preview->getLvObj(); - lv_obj_set_style_grid_cell_x_align(obj, LV_GRID_ALIGN_CENTER, 0); - } - } - - window->updateSize(); + grid.setColSpan(2); + line = window->newLine(&grid); + themeView = new ThemeView(line); } diff --git a/radio/src/gui/colorlcd/screen_user_interface.h b/radio/src/gui/colorlcd/screen_user_interface.h index 6f90ee57257..7f1bc19e18b 100644 --- a/radio/src/gui/colorlcd/screen_user_interface.h +++ b/radio/src/gui/colorlcd/screen_user_interface.h @@ -24,6 +24,7 @@ #include "tabsgroup.h" class ScreenMenu; +class ThemeView; class ScreenUserInterfacePage : public PageTab { @@ -34,4 +35,5 @@ class ScreenUserInterfacePage : public PageTab protected: ScreenMenu* menu; + ThemeView* themeView = nullptr; }; From d43f71b568c7685126ab78c1ab3ab5c648027385 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Fri, 22 Sep 2023 18:19:43 +1000 Subject: [PATCH 09/29] chore: Remove T-Lite F4 build from Buddy (#4003) --- fw.json | 1 - 1 file changed, 1 deletion(-) diff --git a/fw.json b/fw.json index c9cfd836e5c..27b4c54869a 100644 --- a/fw.json +++ b/fw.json @@ -22,7 +22,6 @@ ["Jumper T16", "t16-"], ["Jumper T18", "t18-"], ["Jumper T-Lite", "tlite-"], - ["Jumper T-Lite (F4 MCU)", "tlitef4-"], ["Jumper T-Pro", "tpro-"], ["Jumper T-Pro V2", "tprov2-"], ["Jumper T20", "t20-"], From 9bec7721e73b2dcf3df4a7d1f2e42ada37d9851f Mon Sep 17 00:00:00 2001 From: philmoz Date: Fri, 22 Sep 2023 18:55:24 +1000 Subject: [PATCH 10/29] fix(color): Ensure all items are updated on theme change in user interface settings (#4084) --- radio/src/gui/colorlcd/screen_user_interface.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/radio/src/gui/colorlcd/screen_user_interface.cpp b/radio/src/gui/colorlcd/screen_user_interface.cpp index a79ca9b6350..b8922d707e1 100644 --- a/radio/src/gui/colorlcd/screen_user_interface.cpp +++ b/radio/src/gui/colorlcd/screen_user_interface.cpp @@ -62,11 +62,6 @@ class ThemeView : public FormWindow padAll(0); setFlexLayout(LV_FLEX_FLOW_COLUMN, 0); - update(); - } - - void update() - { auto tp = ThemePersistance::instance(); auto theme = tp->getCurrentTheme(); @@ -166,7 +161,10 @@ void ScreenUserInterfacePage::build(FormWindow* window) tp->applyTheme(value); tp->setDefaultTheme(value); TabsGroup::refreshTheme(); - themeView->update(); + + // Force redraw to ensure all items are updated with new theme colors + window->clear(); + build(window); }); grid.setColSpan(2); From 497540b4a232264311a17f2799290845af1980aa Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 23 Sep 2023 10:54:42 +1000 Subject: [PATCH 11/29] fix(color): Invalid popup menu entries for Trainer SF (#4091) --- radio/src/gui/colorlcd/special_functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/gui/colorlcd/special_functions.cpp b/radio/src/gui/colorlcd/special_functions.cpp index 38eb310d701..9ee93642e3d 100644 --- a/radio/src/gui/colorlcd/special_functions.cpp +++ b/radio/src/gui/colorlcd/special_functions.cpp @@ -136,7 +136,7 @@ class SpecialFunctionEditPage : public Page else if (value == MAX_STICKS + 1) return std::string(STR_CHANS); - return std::string(getMainControlLabel(value)); + return std::string(getMainControlLabel(value - 1)); }); break; } From c783f16b2098ebad7ea7a34808f985dd6ade27bc Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 23 Sep 2023 10:57:21 +1000 Subject: [PATCH 12/29] chore(color): Remove unused code from 'About EdgeTX' popup (#4092) --- radio/src/gui/colorlcd/view_about.cpp | 2 -- radio/src/gui/colorlcd/view_about.h | 3 --- 2 files changed, 5 deletions(-) diff --git a/radio/src/gui/colorlcd/view_about.cpp b/radio/src/gui/colorlcd/view_about.cpp index 6eaeb47d50e..6dfd1e100f2 100644 --- a/radio/src/gui/colorlcd/view_about.cpp +++ b/radio/src/gui/colorlcd/view_about.cpp @@ -63,5 +63,3 @@ AboutUs::AboutUs() : lv_obj_set_pos(qr, (content->width() - 150) / 2, TOP_PADDING + (NUM_LINES * PAGE_LINE_HEIGHT) - 5); lv_qrcode_update(qr, edgetx_url.c_str(), edgetx_url.length()); } - -AboutUs::~AboutUs() { delete qrcode; } diff --git a/radio/src/gui/colorlcd/view_about.h b/radio/src/gui/colorlcd/view_about.h index e76048878b3..c1773cd5295 100644 --- a/radio/src/gui/colorlcd/view_about.h +++ b/radio/src/gui/colorlcd/view_about.h @@ -23,9 +23,6 @@ class AboutUs : public MessageDialog { - BitmapBuffer* qrcode = nullptr; - public: AboutUs(); - ~AboutUs(); }; From 55217dc303972ade1e46baf5f7b4f6cf9bf44245 Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 23 Sep 2023 11:21:12 +1000 Subject: [PATCH 13/29] fix(color): Multiple fixes and improvements to switch and source popup menus (#4055) * Fixes for switch and source select popup menus. - Fix missing GV filter in source select - Ensure all options are included in one of the filters - Add misc filter to switch select (for TELE and ACT options) - Show inverted and no-selection options when filter selected - Make menu line height consistent. * Fix selected item in list when filter applied. --- radio/src/gui/colorlcd/sourcechoice.cpp | 25 ++++++++++++++++--- radio/src/gui/colorlcd/switchchoice.cpp | 15 ++++++++--- .../src/gui/colorlcd/themes/etx_lv_theme.cpp | 1 + radio/src/targets/horus/libopenui_config.h | 4 +-- radio/src/targets/nv14/libopenui_config.h | 4 +-- radio/src/thirdparty/libopenui/src/choice.cpp | 14 +++++++++-- .../thirdparty/libopenui/src/menutoolbar.cpp | 10 +++++--- .../thirdparty/libopenui/src/menutoolbar.h | 5 ++-- 8 files changed, 60 insertions(+), 18 deletions(-) diff --git a/radio/src/gui/colorlcd/sourcechoice.cpp b/radio/src/gui/colorlcd/sourcechoice.cpp index 7c4884b42fc..ff6a95bdfc6 100644 --- a/radio/src/gui/colorlcd/sourcechoice.cpp +++ b/radio/src/gui/colorlcd/sourcechoice.cpp @@ -40,20 +40,39 @@ class SourceChoiceMenuToolbar : public MenuToolbar if (modelCustomScriptsEnabled()) addButton(STR_CHAR_LUA, MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA); #endif - addButton(STR_CHAR_STICK, MIXSRC_FIRST_STICK, MIXSRC_LAST_STICK); +#if defined(PCBHORUS) + auto lastSource = MIXSRC_LAST_SPACEMOUSE; +#elif defined(IMU) + auto lastSource = MIXSRC_TILT_Y; +#else + auto lastSource = MIXSRC_LAST_STICK; +#endif + addButton(STR_CHAR_STICK, MIXSRC_FIRST_STICK, lastSource, [=](int16_t index) { + if (index >= MIXSRC_FIRST_POT && index <= MIXSRC_LAST_POT) + return false; +#if MAX_AXIS > 0 + if (index >= MIXSRC_FIRST_AXIS && index <= MIXSRC_LAST_AXIS) + return false; +#endif + return index >= MIXSRC_FIRST_STICK && index <= lastSource; + }); addButton(STR_CHAR_POT, MIXSRC_FIRST_POT, MIXSRC_LAST_POT); - addButton(STR_CHAR_FUNCTION, MIXSRC_MIN, MIXSRC_MAX); + addButton(STR_CHAR_FUNCTION, MIXSRC_MIN, MIXSRC_LAST_TIMER, [=](int16_t index) { + return (index >= MIXSRC_MIN && index <= MIXSRC_MAX) || (index >= MIXSRC_TX_VOLTAGE && index <= MIXSRC_LAST_TIMER); + }); #if defined(HELI) if (modelHeliEnabled()) addButton(STR_CHAR_CYC, MIXSRC_FIRST_HELI, MIXSRC_LAST_HELI); #endif addButton(STR_CHAR_TRIM, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM); addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_SWITCH, MIXSRC_LAST_SWITCH); + if (modelLSEnabled()) + addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_LOGICAL_SWITCH, MIXSRC_LAST_LOGICAL_SWITCH); addButton(STR_CHAR_TRAINER, MIXSRC_FIRST_TRAINER, MIXSRC_LAST_TRAINER); addButton(STR_CHAR_CHANNEL, MIXSRC_FIRST_CH, MIXSRC_LAST_CH); #if defined(GVARS) if (modelGVEnabled()) - addButton(STR_CHAR_SLIDER, MIXSRC_LAST_GVAR, MIXSRC_FIRST_GVAR); + addButton(STR_CHAR_SLIDER, MIXSRC_FIRST_GVAR, MIXSRC_LAST_GVAR); #endif if (modelTelemetryEnabled()) addButton(STR_CHAR_TELEMETRY, MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM); diff --git a/radio/src/gui/colorlcd/switchchoice.cpp b/radio/src/gui/colorlcd/switchchoice.cpp index c13a5c74b3a..50165e848fa 100644 --- a/radio/src/gui/colorlcd/switchchoice.cpp +++ b/radio/src/gui/colorlcd/switchchoice.cpp @@ -34,10 +34,19 @@ class SwitchChoiceMenuToolbar : public MenuToolbar SwitchChoiceMenuToolbar(SwitchChoice* choice, Menu* menu) : MenuToolbar(choice, menu) { - addButton(STR_CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_SWITCH); + addButton(STR_CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_MULTIPOS_SWITCH); addButton(STR_CHAR_TRIM, SWSRC_FIRST_TRIM, SWSRC_LAST_TRIM); - addButton(STR_CHAR_SWITCH, SWSRC_FIRST_LOGICAL_SWITCH, - SWSRC_LAST_LOGICAL_SWITCH); + addButton(STR_CHAR_SWITCH, SWSRC_FIRST_LOGICAL_SWITCH, SWSRC_LAST_LOGICAL_SWITCH); + addButton(STR_CHAR_TELEMETRY, SWSRC_FIRST_SENSOR, SWSRC_LAST_SENSOR); +#if defined(DEBUG_LATENCY) + auto lastSource = SWSRC_LATENCY_TOGGLE; +#else + auto lastSource = SWSRC_RADIO_ACTIVITY; +#endif + addButton(STR_CHAR_FUNCTION, SWSRC_TELEMETRY_STREAMING, lastSource, [=](int16_t index) { + index = abs(index); + return index == 0 || (index >= SWSRC_TELEMETRY_STREAMING && index <= lastSource && !(index >= SWSRC_FIRST_SENSOR && index <= SWSRC_LAST_SENSOR)); + }); } }; diff --git a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp index 99bff6ba2a6..c9fe7a634fd 100644 --- a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp +++ b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp @@ -511,6 +511,7 @@ void table_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) lv_obj_add_style(obj, &styles.pad_small, LV_PART_ITEMS); lv_obj_add_style(obj, &styles.pressed, LV_PART_ITEMS | LV_STATE_PRESSED); lv_obj_add_style(obj, &styles.bg_color_focus, LV_PART_ITEMS | LV_STATE_EDITED); + lv_obj_set_style_pad_ver(obj, 7, LV_PART_ITEMS); } void etx_keyboard_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) diff --git a/radio/src/targets/horus/libopenui_config.h b/radio/src/targets/horus/libopenui_config.h index 26431102b63..9830de204fd 100644 --- a/radio/src/targets/horus/libopenui_config.h +++ b/radio/src/targets/horus/libopenui_config.h @@ -32,9 +32,9 @@ constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT; constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 132; constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH; -constexpr coord_t MENUS_LINE_HEIGHT = 30; +constexpr coord_t MENUS_LINE_HEIGHT = 35; constexpr coord_t MENUS_WIDTH = 200; -constexpr coord_t MENUS_MAX_HEIGHT = LCD_H * 0.9; +constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 7); constexpr rect_t MENUS_TOOLBAR_RECT = { 100, 51, 30, 209 }; diff --git a/radio/src/targets/nv14/libopenui_config.h b/radio/src/targets/nv14/libopenui_config.h index 8c4d233d795..21fc2f17e7a 100644 --- a/radio/src/targets/nv14/libopenui_config.h +++ b/radio/src/targets/nv14/libopenui_config.h @@ -32,9 +32,9 @@ constexpr uint32_t ALERT_MESSAGE_LEFT = 15; constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 176; constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = 132; -constexpr coord_t MENUS_LINE_HEIGHT = 40; +constexpr coord_t MENUS_LINE_HEIGHT = 35; constexpr coord_t MENUS_WIDTH = 200; -constexpr coord_t MENUS_MAX_HEIGHT = 7 * MENUS_LINE_HEIGHT - 1; +constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 10); constexpr rect_t MENUS_TOOLBAR_RECT = { 35, (LCD_H - MENUS_MAX_HEIGHT) / 2, 50, MENUS_MAX_HEIGHT }; diff --git a/radio/src/thirdparty/libopenui/src/choice.cpp b/radio/src/thirdparty/libopenui/src/choice.cpp index 3f2604a9a2b..712291351b1 100644 --- a/radio/src/thirdparty/libopenui/src/choice.cpp +++ b/radio/src/thirdparty/libopenui/src/choice.cpp @@ -194,9 +194,10 @@ void Choice::fillMenu(Menu *menu, const FilterFct& filter) { menu->removeLines(); auto value = _getValue(); - + int count = 0; int selectedIx = -1; + int selectedIx0 = -1; for (int i = vmin; i <= vmax; ++i) { if (filter && !filter(i)) continue; if (isValueAvailable && !isValueAvailable(i)) continue; @@ -208,10 +209,19 @@ void Choice::fillMenu(Menu *menu, const FilterFct& filter) menu->addLineBuffered(std::to_string(i), [=]() { setValue(i); }); } if (value == i) { selectedIx = count; } + if (i == 0) { selectedIx0 = count; } ++count; } menu->updateLines(); - if (selectedIx >= 0) { menu->select(selectedIx); } + // Force update - in case selected row is first row + menu->select(-1); + if (selectedIx >= 0) + menu->select(selectedIx); + else if (selectedIx0 >= 0) + menu->select(selectedIx0); + else { + menu->select(0); + } } void Choice::openMenu() diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp index 259e837ec3b..74142858edd 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.cpp +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.cpp @@ -106,14 +106,16 @@ rect_t MenuToolbar::getButtonRect(size_t buttons) } bool MenuToolbar::filterMenu(MenuToolbarButton* btn, int16_t filtermin, - int16_t filtermax) + int16_t filtermax, const FilterFct& filterFunc) { btn->check(!btn->checked()); Choice::FilterFct filter = nullptr; if (btn->checked()) { filter = [=](int16_t index) { - return index >= filtermin && index <= filtermax; + if (filterFunc) + return filterFunc(index); + return index == 0 || (abs(index) >= filtermin && abs(index) <= filtermax); }; } @@ -135,7 +137,7 @@ static int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable } void MenuToolbar::addButton(const char* picto, int16_t filtermin, - int16_t filtermax) + int16_t filtermax, const FilterFct& filterFunc) { int vmin = choice->vmin; int vmax = choice->vmax; @@ -150,7 +152,7 @@ void MenuToolbar::addButton(const char* picto, int16_t filtermin, auto button = new MenuToolbarButton(this, r, picto); button->setPressHandler( - std::bind(&MenuToolbar::filterMenu, this, button, filtermin, filtermax)); + std::bind(&MenuToolbar::filterMenu, this, button, filtermin, filtermax, filterFunc)); lv_group_add_obj(group, button->getLvObj()); } diff --git a/radio/src/thirdparty/libopenui/src/menutoolbar.h b/radio/src/thirdparty/libopenui/src/menutoolbar.h index 2098ad1feec..4207ca5f8fa 100644 --- a/radio/src/thirdparty/libopenui/src/menutoolbar.h +++ b/radio/src/thirdparty/libopenui/src/menutoolbar.h @@ -47,11 +47,12 @@ class MenuToolbar : public Window protected: Choice* choice; Menu* menu; + typedef std::function FilterFct; lv_group_t* group; - void addButton(const char* picto, int16_t filtermin, int16_t filtermax); - bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax); + void addButton(const char* picto, int16_t filtermin, int16_t filtermax, const FilterFct& filterFunc = nullptr); + bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax, const FilterFct& filterFunc = nullptr); rect_t getButtonRect(size_t buttons); From 70fcc900c2c0b6b51324c0b3c99bbab79c8a4328 Mon Sep 17 00:00:00 2001 From: 3djc Date: Sat, 23 Sep 2023 05:21:55 +0200 Subject: [PATCH 14/29] fix(tprov2): Use same rotary encoder defaults as previous model (#4014) --- radio/src/opentx.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 145e6e1cdf6..5f855f8a268 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -341,10 +341,6 @@ void generalDefault() g_eeGeneral.pwrOffSpeed = 2; #endif -#if defined(RADIO_TPROV2) - g_eeGeneral.rotEncMode = ROTARY_ENCODER_MODE_INVERT_BOTH; -#endif - #if defined(MANUFACTURER_RADIOMASTER) g_eeGeneral.audioMuteEnable = 1; #endif From 5597cf6476a9598e2ae41de493a5b99f6a9f40e5 Mon Sep 17 00:00:00 2001 From: b14ckyy <33039058+b14ckyy@users.noreply.github.com> Date: Sat, 23 Sep 2023 05:50:15 +0200 Subject: [PATCH 15/29] fix: Bluetooth power level set too low (#4019) --- radio/src/bluetooth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/bluetooth.cpp b/radio/src/bluetooth.cpp index 6aba80ac3c7..47c7ed34ae5 100644 --- a/radio/src/bluetooth.cpp +++ b/radio/src/bluetooth.cpp @@ -470,7 +470,7 @@ void Bluetooth::wakeup() } else if (state == BLUETOOTH_STATE_NAME_SENT && (line != nullptr) && (!strncmp(line, "OK+", 3) || !strncmp(line, "Central:", 8) || !strncmp(line, "Peripheral:", 11))) { - writeString("AT+TXPW0"); + writeString("AT+TXPW2"); state = BLUETOOTH_STATE_POWER_SENT; } else if (state == BLUETOOTH_STATE_POWER_SENT && (line != nullptr) && From 60ccd852e34f08c13f70c1339ba6606128c14460 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sat, 23 Sep 2023 06:45:15 +0200 Subject: [PATCH 16/29] fix: Prevent enabling USART IRQ if not supported (#4086) Fixes #4073 --- radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp index c046f129cb9..71f5130044e 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp @@ -289,7 +289,9 @@ void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) if (params->direction & ETX_Dir_RX) { // IRQ based RX - LL_USART_EnableIT_RXNE(usart->USARTx); + if ((int32_t)(usart->IRQn) >= 0) { + LL_USART_EnableIT_RXNE(usart->USARTx); + } // half-duplex: start in input mode if (usart->set_input) From 8778856d26faee45a2b9848c20f03c97118662b6 Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 23 Sep 2023 14:57:44 +1000 Subject: [PATCH 17/29] fix(color): Allow scrolling of the version info popup with rotary encoder (#3987) --- radio/src/gui/colorlcd/radio_version.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/radio/src/gui/colorlcd/radio_version.cpp b/radio/src/gui/colorlcd/radio_version.cpp index 6c5f23c1d88..ce97935bd25 100644 --- a/radio/src/gui/colorlcd/radio_version.cpp +++ b/radio/src/gui/colorlcd/radio_version.cpp @@ -100,7 +100,13 @@ class VersionDialog : public Dialog // define form auto form = &content->form; form->setFlexLayout(); - + + auto g = lv_group_get_default(); + lv_group_set_editing(g, true); + + lv_obj_add_flag(form->getLvObj(), LV_OBJ_FLAG_SCROLLABLE); + lv_group_add_obj(g, form->getLvObj()); + // headline "Internal module" new StaticText(form, rect_t{}, STR_INTERNAL_MODULE, 0, COLOR_THEME_PRIMARY1); From daf6918f5aff2a87b5d291115ade6280c5c19a54 Mon Sep 17 00:00:00 2001 From: philmoz Date: Sat, 23 Sep 2023 16:17:33 +1000 Subject: [PATCH 18/29] fix(color): Make direction of shutdown animation consistent with B&W (#3988) --- radio/src/gui/colorlcd/draw_functions.cpp | 35 +++++++++-------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp index 1823203b104..dd68c0d2378 100644 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ b/radio/src/gui/colorlcd/draw_functions.cpp @@ -112,13 +112,20 @@ void drawSleepBitmap() lcdRefresh(); } -#define SHUTDOWN_CIRCLE_DIAMETER 150 +#define SHUTDOWN_CIRCLE_RADIUS 75 const uint8_t _LBM_SHUTDOWN_CIRCLE[] = { #include "mask_shutdown_circle.lbm" }; STATIC_LZ4_BITMAP(LBM_SHUTDOWN_CIRCLE); +const int8_t bmp_shutdown_xo[] = { + 0, 0, -SHUTDOWN_CIRCLE_RADIUS, -SHUTDOWN_CIRCLE_RADIUS +}; +const int8_t bmp_shutdown_yo[] = { + -SHUTDOWN_CIRCLE_RADIUS, 0, 0, -SHUTDOWN_CIRCLE_RADIUS +}; + void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char* message) { @@ -140,31 +147,17 @@ void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, lcdInitDirectDrawing(); lcd->clear(bgColor); + int quarter = duration / (totalDuration / 5); + if (shutdown) { lcd->drawMask((LCD_W - shutdown->width()) / 2, (LCD_H - shutdown->height()) / 2, shutdown, fgColor); - int quarter = duration / (totalDuration / 5); - if (quarter >= 1) - lcd->drawBitmapPattern(LCD_W / 2, (LCD_H - SHUTDOWN_CIRCLE_DIAMETER) / 2, - LBM_SHUTDOWN_CIRCLE, fgColor, 0, - SHUTDOWN_CIRCLE_DIAMETER / 2); - if (quarter >= 2) - lcd->drawBitmapPattern(LCD_W / 2, LCD_H / 2, LBM_SHUTDOWN_CIRCLE, fgColor, - SHUTDOWN_CIRCLE_DIAMETER / 2, - SHUTDOWN_CIRCLE_DIAMETER / 2); - if (quarter >= 3) - lcd->drawBitmapPattern((LCD_W - SHUTDOWN_CIRCLE_DIAMETER) / 2, LCD_H / 2, - LBM_SHUTDOWN_CIRCLE, fgColor, - SHUTDOWN_CIRCLE_DIAMETER, - SHUTDOWN_CIRCLE_DIAMETER / 2); - if (quarter >= 4) - lcd->drawBitmapPattern( - (LCD_W - SHUTDOWN_CIRCLE_DIAMETER) / 2, - (LCD_H - SHUTDOWN_CIRCLE_DIAMETER) / 2, LBM_SHUTDOWN_CIRCLE, fgColor, - SHUTDOWN_CIRCLE_DIAMETER * 3 / 2, SHUTDOWN_CIRCLE_DIAMETER / 2); + for (int i = 0; i <= 3 - quarter; i += 1) { + lcd->drawBitmapPattern(LCD_W / 2 + bmp_shutdown_xo[i], LCD_H / 2 + bmp_shutdown_yo[i], + LBM_SHUTDOWN_CIRCLE, fgColor, i * SHUTDOWN_CIRCLE_RADIUS, SHUTDOWN_CIRCLE_RADIUS); + } } else { - int quarter = duration / (totalDuration / 5); for (int i = 1; i <= 4; i++) { if (quarter >= i) { lcd->drawSolidFilledRect(LCD_W / 2 - 70 + 24 * i, LCD_H / 2 - 10, 20, From bf9d811c021d54772dd6d0c02f882cbade5f30c3 Mon Sep 17 00:00:00 2001 From: 3djc Date: Sat, 23 Sep 2023 10:34:21 +0200 Subject: [PATCH 19/29] fix(t20): Inaccurate batt measurement offset (#4087) --- radio/src/targets/taranis/board.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index e986e3fcd2f..c5eb1b55f9a 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -473,7 +473,7 @@ void setTopBatteryValue(uint32_t volts); #if defined(RADIO_ZORRO) || defined(RADIO_TX12MK2) || defined(RADIO_BOXER) || defined(RADIO_POCKET) #define VOLTAGE_DROP 45 -#elif defined(RADIO_TPROV2) +#elif defined(RADIO_TPROV2) || defined(RADIO_T20) #define VOLTAGE_DROP 60 #else #define VOLTAGE_DROP 20 From 870fe7eca3e96f97c6a744087a109fa9556eb080 Mon Sep 17 00:00:00 2001 From: Risto Date: Sat, 23 Sep 2023 10:46:50 +0200 Subject: [PATCH 20/29] feat(color): Show custom image during shutdown if present If `IMAGES\shutdown.png` is present, a custom shutdown image will be displayed while powering off the radio --- radio/src/gui/colorlcd/draw_functions.cpp | 21 ++++++++++++++++----- radio/src/sdcard.h | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp index dd68c0d2378..cf0ffeb9fd9 100644 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ b/radio/src/gui/colorlcd/draw_functions.cpp @@ -129,6 +129,7 @@ const int8_t bmp_shutdown_yo[] = { void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char* message) { + static BitmapBuffer* shutdownSplashImg = nullptr; if (totalDuration == 0) return; LcdFlags fgColor; @@ -150,12 +151,22 @@ void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, int quarter = duration / (totalDuration / 5); if (shutdown) { - lcd->drawMask((LCD_W - shutdown->width()) / 2, - (LCD_H - shutdown->height()) / 2, shutdown, fgColor); + if (!sdMounted()) sdInit(); + shutdownSplashImg = BitmapBuffer::loadBitmap( + BITMAPS_PATH "/" SHUTDOWN_SPLASH_FILE, BMP_RGB565); - for (int i = 0; i <= 3 - quarter; i += 1) { - lcd->drawBitmapPattern(LCD_W / 2 + bmp_shutdown_xo[i], LCD_H / 2 + bmp_shutdown_yo[i], - LBM_SHUTDOWN_CIRCLE, fgColor, i * SHUTDOWN_CIRCLE_RADIUS, SHUTDOWN_CIRCLE_RADIUS); + if (shutdownSplashImg) { + lcd->drawBitmap(0, 0, shutdownSplashImg); + } else { + lcd->drawMask((LCD_W - shutdown->width()) / 2, + (LCD_H - shutdown->height()) / 2, shutdown, fgColor); + + for (int i = 0; i <= 3 - quarter; i += 1) { + lcd->drawBitmapPattern( + LCD_W / 2 + bmp_shutdown_xo[i], LCD_H / 2 + bmp_shutdown_yo[i], + LBM_SHUTDOWN_CIRCLE, fgColor, i * SHUTDOWN_CIRCLE_RADIUS, + SHUTDOWN_CIRCLE_RADIUS); + } } } else { for (int i = 1; i <= 4; i++) { diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index 4a83cfe7948..ab18bc7abde 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -78,6 +78,7 @@ const char RADIO_SETTINGS_ERRORFILE_YAML_PATH[] = RADIO_PATH PATH_SEPARATOR "rad const char YAMLFILE_CHECKSUM_TAG_NAME[] = "checksum"; #endif #define SPLASH_FILE "splash.png" +#define SHUTDOWN_SPLASH_FILE "shutdown.png" #endif #define MODELS_EXT ".bin" From 87df8a4f2cc741c99d4c52e9f99c4af5ca2c9b2d Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sat, 23 Sep 2023 11:31:56 +0200 Subject: [PATCH 21/29] refactor: SD card SPI HAL (#3957) * refactor: SD card SPI driver * Removed SPI and DMA StdPeriph drivers * Allow for disabling SPI DMA support * Disable SPI sdcard CRC support * Fix 2MHz timer on NV14 * Shared VS1053b driver * Fix: SPI2 uses PCLK1 * feat: new generic diskio API * More generic SD_CARD_PRESENT() * Fixes * Flush incoming block on token mismatch * Scratch buffer test * Incredible hack to re-sync sd card * fix: SDIO driver --- radio/src/CMakeLists.txt | 9 +- radio/src/cli.cpp | 18 +- radio/src/crc.cpp | 4 +- radio/src/disk_cache.cpp | 69 +- radio/src/disk_cache.h | 37 +- radio/src/gui/colorlcd/radio_sdmanager.cpp | 2 +- .../src/gui/common/stdlcd/radio_sdmanager.cpp | 28 +- radio/src/hal/CMakeLists.txt | 21 + radio/src/hal/fatfs_diskio.cpp | 163 +++ radio/src/hal/fatfs_diskio.h | 47 + radio/src/hal/storage.cpp | 80 ++ radio/src/hal/storage.h | 40 + radio/src/main.cpp | 1 + radio/src/opentx.cpp | 6 +- radio/src/rtos.h | 15 +- radio/src/sdcard.cpp | 58 +- radio/src/sdcard.h | 16 - radio/src/serial.cpp | 5 +- .../src/targets/common/arm/stm32/ads79xx.cpp | 77 +- .../arm/stm32/bootloader/CMakeLists.txt | 11 +- .../common/arm/stm32/bootloader/bin_files.cpp | 3 + .../common/arm/stm32/bootloader/boot.cpp | 75 +- .../targets/common/arm/stm32/diskio_sdio.cpp | 498 ++++++---- .../targets/common/arm/stm32/diskio_sdio.h | 26 + .../targets/common/arm/stm32/diskio_spi.cpp | 147 +++ .../src/targets/common/arm/stm32/diskio_spi.h | 26 + .../common/arm/stm32/f2/CMakeLists.txt | 3 +- .../common/arm/stm32/f4/CMakeLists.txt | 2 - .../targets/common/arm/stm32/pwr_driver.cpp | 6 - .../targets/common/arm/stm32/sdcard_spi.cpp | 864 ++++++++++++++++ .../src/targets/common/arm/stm32/sdcard_spi.h | 291 ++++++ .../src/targets/common/arm/stm32/sdio_sd.cpp | 420 -------- radio/src/targets/common/arm/stm32/sdio_sd.h | 70 -- .../src/targets/common/arm/stm32/stm32_dma.h | 16 + .../targets/common/arm/stm32/stm32_hal_ll.h | 1 + .../targets/common/arm/stm32/stm32_spi.cpp | 288 ++++++ .../src/targets/common/arm/stm32/stm32_spi.h | 35 + .../targets/common/arm/stm32/stm32_spi_adc.h | 14 +- .../common/arm/stm32/timers_driver.cpp | 26 +- .../targets/common/arm/stm32/timers_driver.h | 1 + .../common/arm/stm32/usbd_storage_msd.cpp | 21 +- .../arm/stm32/vs1053b.cpp} | 165 ++-- radio/src/targets/horus/CMakeLists.txt | 6 +- radio/src/targets/horus/audio_spi_driver.cpp | 459 --------- radio/src/targets/horus/board.h | 6 - radio/src/targets/horus/hal.h | 3 + radio/src/targets/nv14/CMakeLists.txt | 3 +- radio/src/targets/nv14/board.h | 6 - radio/src/targets/nv14/hal.h | 3 + radio/src/targets/simu/simudisk.cpp | 4 +- radio/src/targets/simu/simufatfs.cpp | 5 + radio/src/targets/taranis/CMakeLists.txt | 3 +- radio/src/targets/taranis/board.cpp | 2 - radio/src/targets/taranis/board.h | 10 - radio/src/targets/taranis/diskio.cpp | 933 ------------------ radio/src/targets/taranis/hal.h | 41 +- radio/src/thirdparty/FatFs/diskio.h | 8 - radio/src/thirdparty/FatFs/fattime.c | 53 - .../Class/msc/src/usbd_msc_scsi.c | 20 +- radio/util/hw_defs/hal_adc.py | 1 - radio/util/hw_defs/stm32_adc_inputs.jinja | 12 +- 61 files changed, 2676 insertions(+), 2607 deletions(-) create mode 100644 radio/src/hal/fatfs_diskio.cpp create mode 100644 radio/src/hal/fatfs_diskio.h create mode 100644 radio/src/hal/storage.cpp create mode 100644 radio/src/hal/storage.h create mode 100644 radio/src/targets/common/arm/stm32/diskio_sdio.h create mode 100644 radio/src/targets/common/arm/stm32/diskio_spi.cpp create mode 100644 radio/src/targets/common/arm/stm32/diskio_spi.h create mode 100644 radio/src/targets/common/arm/stm32/sdcard_spi.cpp create mode 100644 radio/src/targets/common/arm/stm32/sdcard_spi.h delete mode 100644 radio/src/targets/common/arm/stm32/sdio_sd.cpp delete mode 100644 radio/src/targets/common/arm/stm32/sdio_sd.h rename radio/src/targets/{nv14/audio_spi_driver.cpp => common/arm/stm32/vs1053b.cpp} (71%) delete mode 100644 radio/src/targets/horus/audio_spi_driver.cpp delete mode 100644 radio/src/targets/taranis/diskio.cpp delete mode 100644 radio/src/thirdparty/FatFs/fattime.c diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 2bdd9c8a074..a5ce3292344 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -84,12 +84,6 @@ set(GVARS_VARIANT 1) set(FRSKY_VARIANT 2) set(3POS_VARIANT 4) -set(FATFS_SRC - ${FATFS_DIR}/ff.c - ${FATFS_DIR}/ffunicode.c - ${FATFS_DIR}/fattime.c -) - if(PCB STREQUAL X12S OR PCB STREQUAL X10) include(targets/horus/CMakeLists.txt) elseif(PCB STREQUAL NV14) @@ -252,9 +246,8 @@ endif() if(SDCARD) add_definitions(-DSDCARD) - include_directories(${FATFS_DIR} ${FATFS_DIR}/option) set(SRC ${SRC} sdcard.cpp rtc.cpp logs.cpp thirdparty/libopenui/src/libopenui_file.cpp) - set(FIRMWARE_SRC ${FIRMWARE_SRC} ${FATFS_SRC}) + set(FIRMWARE_SRC ${FIRMWARE_SRC}) endif() if(SHUTDOWN_CONFIRMATION) diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 754c8d1cbfc..2bb1fa937ec 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -23,7 +23,6 @@ #include #include "opentx.h" -#include "diskio.h" #include "timers_driver.h" #include "watchdog_driver.h" @@ -33,6 +32,8 @@ #include "hal/adc_driver.h" #include "hal/module_port.h" +#include "hal/fatfs_diskio.h" +#include "hal/storage.h" #include "tasks.h" #include "tasks/mixer_task.h" @@ -347,8 +348,9 @@ int cliReadSD(const char ** argv) uint32_t bytesRead = numberOfSectors * 512; tmr10ms_t start = get_tmr10ms(); + auto drv = storageGetDefaultDriver(); while (numberOfSectors > 0) { - DRESULT res = __disk_read(0, buffer, startSector, bufferSectors); + DRESULT res = drv->read(0, buffer, startSector, bufferSectors); if (res != RES_OK) { cliSerialPrint("disk_read error: %d, sector: %d(%d)", res, startSector, numberOfSectors); } @@ -385,10 +387,11 @@ int cliReadSD(const char ** argv) int cliTestSD(const char ** argv) { // Do the read test on the SD card and report back the result + auto drv = storageGetDefaultDriver(); // get sector count uint32_t sectorCount; - if (disk_ioctl(0, GET_SECTOR_COUNT, §orCount) != RES_OK) { + if (drv->ioctl(0, GET_SECTOR_COUNT, §orCount) != RES_OK) { cliSerialPrint("Error: can't read sector count"); return 0; } @@ -401,8 +404,9 @@ int cliTestSD(const char ** argv) cliSerialPrint("Not enough memory"); return 0; } + for (uint32_t s = sectorCount - 16; sread(0, buffer, s, 1); if (res != RES_OK) { cliSerialPrint("sector %d read FAILED, err: %d", s, res); } @@ -421,8 +425,8 @@ int cliTestSD(const char ** argv) } cliSerialPrint("Starting multiple sector read test, reading two sectors at the time"); - for (uint32_t s = sectorCount - 16; sread(0, buffer, s, 2); if (res != RES_OK) { cliSerialPrint("sector %d-%d read FAILED, err: %d", s, s+1, res); } @@ -441,7 +445,7 @@ int cliTestSD(const char ** argv) } cliSerialPrint("Starting multiple sector read test, reading 16 sectors at the time"); - DRESULT res = __disk_read(0, buffer, sectorCount-16, 16); + DRESULT res = drv->read(0, buffer, sectorCount - 16, 16); if (res != RES_OK) { cliSerialPrint("sector %d-%d read FAILED, err: %d", sectorCount-16, sectorCount-1, res); } diff --git a/radio/src/crc.cpp b/radio/src/crc.cpp index 50383d59376..5f8c6b1d14f 100644 --- a/radio/src/crc.cpp +++ b/radio/src/crc.cpp @@ -101,8 +101,8 @@ uint16_t crc16(uint8_t index, const uint8_t * buf, uint32_t len, uint16_t start) { uint16_t crc = start; const unsigned short * tab = crc16tab[index]; - for (uint32_t i=0; i>8) ^ *buf++) & 0x00FF]; + for (uint32_t i = 0; i < len; i++) { + crc = (crc << 8) ^ tab[((crc >> 8) ^ *buf++) & 0x00FF]; } return crc; } diff --git a/radio/src/disk_cache.cpp b/radio/src/disk_cache.cpp index d54f6af5ac9..4280b075b9f 100644 --- a/radio/src/disk_cache.cpp +++ b/radio/src/disk_cache.cpp @@ -24,11 +24,6 @@ #include -#if defined(SIMU) && !defined(SIMU_DISKIO) - #define __disk_read(...) (RES_OK) - #define __disk_write(...) (RES_OK) -#endif - #if 0 // set to 1 to enable traces #include "debug.h" #define TRACE_DISK_CACHE(...) TRACE(__VA_ARGS__) @@ -47,15 +42,16 @@ DiskCache diskCache; class DiskCacheBlock { -public: + public: DiskCacheBlock(); bool read(BYTE* buff, DWORD sector, UINT count); - DRESULT fill(BYTE drv, BYTE* buff, DWORD sector, UINT count); + DRESULT fill(const diskio_driver_t* drv, BYTE lun, BYTE* buff, DWORD sector, + UINT count); void free(DWORD sector, UINT count); void free(); bool empty() const; -private: + private: uint8_t data[DISK_CACHE_BLOCK_SIZE]; DWORD startSector; DWORD endSector; @@ -77,16 +73,17 @@ bool DiskCacheBlock::read(BYTE * buff, DWORD sector, UINT count) return false; } -DRESULT DiskCacheBlock::fill(BYTE drv, BYTE * buff, DWORD sector, UINT count) +DRESULT DiskCacheBlock::fill(const diskio_driver_t* drv, BYTE lun, BYTE * buff, + DWORD sector, UINT count) { - DRESULT res = __disk_read(drv, data, sector, DISK_CACHE_BLOCK_SECTORS); + DRESULT res = drv->read(lun, data, sector, DISK_CACHE_BLOCK_SECTORS); if (res != RES_OK) { return res; } startSector = sector; endSector = sector + DISK_CACHE_BLOCK_SECTORS; memcpy(buff, data, count * BLOCK_SIZE); - TRACE_DISK_CACHE("\tcache %p FILLED from read(%u, %u)", this, (uint32_t)sector, (uint32_t)count); + TRACE_DISK_CACHE("cache %p FILLED from read(%u, %u)", this, (uint32_t)sector, (uint32_t)count); return RES_OK; } @@ -108,13 +105,17 @@ bool DiskCacheBlock::empty() const return (endSector == 0); } -DiskCache::DiskCache(): - lastBlock(0) +DiskCache::DiskCache() : lastBlock(0), blocks(nullptr), diskDrv(nullptr) { stats.noHits = 0; stats.noMisses = 0; stats.noWrites = 0; +} + +void DiskCache::initialize(const diskio_driver_t* drv) +{ blocks = new DiskCacheBlock[DISK_CACHE_BLOCKS_NUM]; + diskDrv = drv; } void DiskCache::clear() @@ -128,24 +129,28 @@ void DiskCache::clear() } } -DRESULT DiskCache::read(BYTE drv, BYTE * buff, DWORD sector, UINT count) +uint32_t DiskCache::getSectors(uint8_t lun) { - // TODO: check if not caching first sectors would improve anything - // if (sector < 1000) { - // ++stats.noMisses; - // return __disk_read(drv, buff, sector, count); - // } + if (sectors == 0) { + diskDrv->ioctl(lun, GET_SECTOR_COUNT, §ors); + } + return sectors; +} +DRESULT DiskCache::read(BYTE lun, BYTE * buff, DWORD sector, UINT count) +{ // if read is bigger than cache block, then read it directly without using cache if (count > DISK_CACHE_BLOCK_SECTORS) { - TRACE_DISK_CACHE("\t\t big read(%u, %u)", (uint32_t)sector, (uint32_t)count); - return __disk_read(drv, buff, sector, count); + TRACE_DISK_CACHE("big read(%u, %u)", (uint32_t)sector, (uint32_t)count); + return diskDrv->read(lun, buff, sector, count); } - // if block + cache block size is beyond the end of the disk, then read it directly without using cache - if (sector + DISK_CACHE_BLOCK_SECTORS >= sdGetNoSectors()) { - TRACE_DISK_CACHE("\t\t cache would be beyond end of disk %u (%u)", (uint32_t)sector, sdGetNoSectors()); - return __disk_read(drv, buff, sector, count); + // if block + cache block size is beyond the end of the disk, + // then read it directly without using cache + if (sector + DISK_CACHE_BLOCK_SECTORS >= getSectors(lun)) { + TRACE_DISK_CACHE("cache would be beyond end of disk %u (%u)", + (uint32_t)sector, getSectors(lun)); + return diskDrv->read(lun, buff, sector, count); } for (int n = 0; n < DISK_CACHE_BLOCKS_NUM; ++n) { @@ -161,7 +166,7 @@ DRESULT DiskCache::read(BYTE drv, BYTE * buff, DWORD sector, UINT count) for (int n = 0; n < DISK_CACHE_BLOCKS_NUM; ++n) { if (blocks[n].empty()) { TRACE_DISK_CACHE("\t\t using free block"); - return blocks[n].fill(drv, buff, sector, count); + return blocks[n].fill(diskDrv, lun, buff, sector, count); } } @@ -171,16 +176,16 @@ DRESULT DiskCache::read(BYTE drv, BYTE * buff, DWORD sector, UINT count) lastBlock = 0; } - return blocks[lastBlock].fill(drv, buff, sector, count); + return blocks[lastBlock].fill(diskDrv, lun, buff, sector, count); } -DRESULT DiskCache::write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) +DRESULT DiskCache::write(BYTE lun, const BYTE* buff, DWORD sector, UINT count) { ++stats.noWrites; for(int n = 0; n < DISK_CACHE_BLOCKS_NUM; ++n) { blocks[n].free(sector, count); } - return __disk_write(drv, buff, sector, count); + return diskDrv->write(lun, buff, sector, count); } const DiskCacheStats & DiskCache::getStats() const @@ -195,13 +200,13 @@ int DiskCache::getHitRate() const return (stats.noHits * 1000) / all; } -DRESULT disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count) +DRESULT disk_cache_read(BYTE drv, BYTE * buff, DWORD sector, UINT count) { return diskCache.read(drv, buff, sector, count); } - -DRESULT disk_write(BYTE drv, const BYTE * buff, DWORD sector, UINT count) +DRESULT disk_cache_write(BYTE drv, const BYTE * buff, DWORD sector, UINT count) { return diskCache.write(drv, buff, sector, count); } + diff --git a/radio/src/disk_cache.h b/radio/src/disk_cache.h index ef5fbaeca65..b8869107fa0 100644 --- a/radio/src/disk_cache.h +++ b/radio/src/disk_cache.h @@ -19,10 +19,9 @@ * GNU General Public License for more details. */ -#ifndef _DISK_CACHE_H_ -#define _DISK_CACHE_H_ +#pragma once -#include "FatFs/diskio.h" +#include "hal/fatfs_diskio.h" // tunable parameters #define DISK_CACHE_BLOCKS_NUM 32 // no cache blocks @@ -39,23 +38,31 @@ class DiskCacheBlock; class DiskCache { - public: - DiskCache(); + public: + DiskCache(); - void clear(); + void initialize(const diskio_driver_t* drv); + void clear(); - DRESULT read(BYTE drv, BYTE* buff, DWORD sector, UINT count); - DRESULT write(BYTE drv, const BYTE* buff, DWORD sector, UINT count); + DRESULT read(BYTE drv, BYTE* buff, DWORD sector, UINT count); + DRESULT write(BYTE drv, const BYTE* buff, DWORD sector, UINT count); - const DiskCacheStats & getStats() const; - int getHitRate() const; + const DiskCacheStats& getStats() const; + int getHitRate() const; - private: - DiskCacheStats stats; - uint32_t lastBlock; - DiskCacheBlock * blocks; + private: + DiskCacheStats stats; + uint32_t lastBlock; + DiskCacheBlock* blocks; + const diskio_driver_t* diskDrv; + uint32_t sectors; + + uint32_t getSectors(uint8_t lun); }; extern DiskCache diskCache; -#endif // _DISK_CACHE_H_ +DRESULT disk_cache_read(BYTE drv, BYTE* buff, DWORD sector, UINT count); +DRESULT disk_cache_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count); + + diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index 01c72cafae8..30ec61e5d7e 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -106,7 +106,7 @@ class FileNameEditWindow : public Page }; RadioSdManagerPage::RadioSdManagerPage() : - PageTab(SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD, ICON_RADIO_SD_MANAGER) + PageTab(STR_SD_CARD, ICON_RADIO_SD_MANAGER) { } diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index ea93f2200b3..3cc28967e03 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -25,6 +25,7 @@ #include "io/multi_firmware_update.h" #include "io/bootloader_flash.h" #include "libopenui/src/libopenui_file.h" +#include "hal/storage.h" #define NODE_TYPE(fname) fname[SD_SCREEN_FILE_LENGTH+1] #define IS_DIRECTORY(fname) ((bool)(!NODE_TYPE(fname))) @@ -39,26 +40,15 @@ void menuRadioSdManagerInfo(event_t event) { SIMPLE_SUBMENU(STR_SD_INFO_TITLE, 1); - lcdDrawTextAlignedLeft(2*FH, STR_SD_TYPE); - lcdDrawText(10*FW, 2*FH, SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD); - - lcdDrawTextAlignedLeft(3*FH, STR_SD_SIZE); - lcdDrawNumber(10*FW, 3*FH, sdGetSize(), LEFT); + lcdDrawTextAlignedLeft(2*FH, STR_SD_SIZE); + lcdDrawNumber(10*FW, 2*FH, sdGetSize(), LEFT); lcdDrawChar(lcdLastRightPos, 3*FH, 'M'); - lcdDrawTextAlignedLeft(4*FH, STR_SD_SECTORS); -#if defined(SD_GET_FREE_BLOCKNR) - lcdDrawNumber(10*FW, 4*FH, SD_GET_FREE_BLOCKNR()/1000, LEFT); - lcdDrawChar(lcdLastRightPos, 4*FH, '/'); - lcdDrawNumber(lcdLastRightPos+FW, 4*FH, sdGetNoSectors()/1000, LEFT); -#else - lcdDrawNumber(10*FW, 4*FH, sdGetNoSectors()/1000, LEFT); -#endif - lcdDrawChar(lcdLastRightPos, 4*FH, 'k'); - - lcdDrawTextAlignedLeft(5*FH, STR_SD_SPEED); - lcdDrawNumber(10*FW, 5*FH, SD_GET_SPEED()/1000, LEFT); - lcdDrawText(lcdLastRightPos, 5*FH, "kb/s"); + lcdDrawTextAlignedLeft(3*FH, STR_SD_SECTORS); + lcdDrawNumber(10*FW, 3*FH, sdGetFreeSectors()/1000, LEFT); + lcdDrawChar(lcdLastRightPos, 3*FH, '/'); + lcdDrawNumber(lcdLastRightPos+FW, 3*FH, sdGetNoSectors()/1000, LEFT); + lcdDrawChar(lcdLastRightPos, 3*FH, 'k'); } inline bool isFilenameGreater(bool isfile, const char * fn, const char * line) @@ -298,7 +288,7 @@ void menuRadioSdManager(event_t _event) event_t event = (EVT_KEY_MASK(_event) == KEY_ENTER ? 0 : _event); uint8_t old_editMode = s_editMode; - SIMPLE_MENU(SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD, menuTabGeneral, MENU_RADIO_SD_MANAGER, HEADER_LINE + reusableBuffer.sdManager.count); + SIMPLE_MENU(STR_SD_CARD, menuTabGeneral, MENU_RADIO_SD_MANAGER, HEADER_LINE + reusableBuffer.sdManager.count); switch (_event) { case EVT_ENTRY: diff --git a/radio/src/hal/CMakeLists.txt b/radio/src/hal/CMakeLists.txt index 92b0f5ee2c5..ac7c8a2329f 100644 --- a/radio/src/hal/CMakeLists.txt +++ b/radio/src/hal/CMakeLists.txt @@ -8,3 +8,24 @@ set(SRC ${SRC} hal/adc_driver.cpp hal/key_driver.cpp ) + +include_directories(${FATFS_DIR} ${FATFS_DIR}/option) + +set(BOOTLOADER_SRC ${BOOTLOADER_SRC} + ${CMAKE_CURRENT_SOURCE_DIR}/hal/key_driver.cpp +) + +if (NOT NATIVE_BUILD) + set(SRC ${SRC} + hal/storage.cpp + hal/fatfs_diskio.cpp + ${FATFS_DIR}/ff.c + ${FATFS_DIR}/ffunicode.c + ) + set(BOOTLOADER_SRC ${BOOTLOADER_SRC} + ${CMAKE_CURRENT_SOURCE_DIR}/hal/storage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/hal/fatfs_diskio.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/${FATFS_DIR}/ff.c + ${CMAKE_CURRENT_SOURCE_DIR}/${FATFS_DIR}/ffunicode.c + ) +endif() diff --git a/radio/src/hal/fatfs_diskio.cpp b/radio/src/hal/fatfs_diskio.cpp new file mode 100644 index 00000000000..ed5b544f223 --- /dev/null +++ b/radio/src/hal/fatfs_diskio.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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 "fatfs_diskio.h" +#include "FatFs/diskio.h" + +#if FF_FS_REENTRANT != 0 +#include "rtos.h" +#endif + +struct fatfs_drive_t { + const diskio_driver_t* drv; + uint8_t lun; + bool initialized; +#if FF_FS_REENTRANT != 0 + RTOS_MUTEX_HANDLE mutex; +#endif +}; + +static fatfs_drive_t _fatfs_drives[FF_VOLUMES]; +static uint8_t _fatfs_n_drives = 0; + +int fatfsRegisterDriver(const diskio_driver_t* drv, uint8_t lun) +{ + if (_fatfs_n_drives >= FF_VOLUMES) { + return 0; + } + + uint8_t vol = _fatfs_n_drives++; + auto& drive = _fatfs_drives[vol]; + drive.drv = drv; + drive.lun = lun; + drive.initialized = false; + +#if FF_FS_REENTRANT != 0 + // init IO mutex only once + RTOS_CREATE_MUTEX(drive.mutex); +#endif + + return 1; +} + +const diskio_driver_t* fatfsGetDriver(uint8_t pdrv) +{ + if (pdrv >= _fatfs_n_drives) { + return nullptr; + } + + return _fatfs_drives[pdrv].drv; +} + +uint8_t fatfsGetLun(uint8_t pdrv) +{ + if (pdrv >= _fatfs_n_drives) { + return 0; + } + + return _fatfs_drives[pdrv].lun; +} + +#if FF_FS_REENTRANT != 0 + +int ff_cre_syncobj(BYTE vol, FF_SYNC_t* mutex) +{ + *mutex = _fatfs_drives[vol].mutex; + return 1; +} + +int ff_req_grant(FF_SYNC_t mutex) +{ + RTOS_LOCK_MUTEX(mutex); + return 1; +} + +void ff_rel_grant(FF_SYNC_t mutex) { RTOS_UNLOCK_MUTEX(mutex); } + +int ff_del_syncobj(FF_SYNC_t mutex) { return 1; } + +#endif + +DSTATUS disk_initialize(BYTE pdrv) +{ + if (pdrv >= _fatfs_n_drives) { + return STA_NODISK; + } + + DSTATUS stat = RES_OK; + auto drive = &_fatfs_drives[pdrv]; + if (!drive->initialized) { + stat = drive->drv->initialize(drive->lun); + if (stat == RES_OK) { + drive->initialized = true; + } + } + + return stat; +} + +DSTATUS disk_status(BYTE pdrv) +{ + auto drv = _fatfs_drives[pdrv].drv; + uint8_t lun = _fatfs_drives[pdrv].lun; + return drv->status(lun); +} + +DRESULT disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) +{ + auto drv = _fatfs_drives[pdrv].drv; + uint8_t lun = _fatfs_drives[pdrv].lun; + return drv->read(lun, buff, sector, count); +} + +DRESULT disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) +{ + auto drv = _fatfs_drives[pdrv].drv; + uint8_t lun = _fatfs_drives[pdrv].lun; + return drv->write(lun, buff, sector, count); +} + +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) +{ + auto drv = _fatfs_drives[pdrv].drv; + uint8_t lun = _fatfs_drives[pdrv].lun; + return drv->ioctl(lun, cmd, buff); +} + +#if FF_FS_NORTC == 0 + +#include "rtc.h" + +DWORD get_fattime(void) +{ + struct gtm t; + + gettime(&t); + + /* Pack date and time into a DWORD variable */ + return ((DWORD)(t.tm_year - 80) << 25) + | ((uint32_t)(t.tm_mon+1) << 21) + | ((uint32_t)t.tm_mday << 16) + | ((uint32_t)t.tm_hour << 11) + | ((uint32_t)t.tm_min << 5) + | ((uint32_t)t.tm_sec >> 1); +} +#endif diff --git a/radio/src/hal/fatfs_diskio.h b/radio/src/hal/fatfs_diskio.h new file mode 100644 index 00000000000..548e66ad389 --- /dev/null +++ b/radio/src/hal/fatfs_diskio.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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. + */ + +#pragma once + +#include "FatFs/diskio.h" +#include + +struct diskio_driver_t +{ + DSTATUS (*initialize)(BYTE pdrv); + + DSTATUS (*status)(BYTE pdrv); + + DRESULT (*read)(BYTE pdrv, BYTE* buff, DWORD sector, UINT count); + + DRESULT (*write)(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); + + DRESULT (*ioctl)(BYTE pdrv, BYTE cmd, void* buff); +}; + +// returns 1 if successful, 0 otherwise +int fatfsRegisterDriver(const diskio_driver_t* drv, uint8_t lun); + +// returns a pyhsical disk driver or NULL +const diskio_driver_t* fatfsGetDriver(uint8_t pdrv); + +// returns a physical LUN or 0 +uint8_t fatfsGetLun(uint8_t pdrv); diff --git a/radio/src/hal/storage.cpp b/radio/src/hal/storage.cpp new file mode 100644 index 00000000000..e5cbbaa5c5a --- /dev/null +++ b/radio/src/hal/storage.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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 "hal/storage.h" +#include "hal.h" + +#include "debug.h" + +#if defined(STORAGE_USE_SDIO) + #include "diskio_sdio.h" + #define _STORAGE_DRIVER sdio_diskio_driver +#elif defined(STORAGE_USE_SDCARD_SPI) + #include "diskio_spi.h" + #define _STORAGE_DRIVER sdcard_spi_driver +#else + #error "No supported storage driver configured" +#endif + +#if defined(DISK_CACHE) + #include "disk_cache.h" + const diskio_driver_t disk_cache_shim = { + .initialize = _STORAGE_DRIVER.initialize, + .status = _STORAGE_DRIVER.status, + .read = disk_cache_read, + .write = disk_cache_write, + .ioctl = _STORAGE_DRIVER.ioctl, + }; +#endif + +void storageInit() +{ + if (fatfsGetDriver(0) != nullptr) + return; + + const diskio_driver_t* drv = &_STORAGE_DRIVER; + +#if defined(DISK_CACHE) + diskCache.initialize(drv); + drv = &disk_cache_shim; +#endif + + if (!fatfsRegisterDriver(drv, 0)) { + TRACE("fatfsRegisterDriver: [FAILED]"); + } +} + +void storagePreMountHook() +{ +#if defined(DISK_CACHE) + diskCache.clear(); +#endif +} + +bool storageIsPresent() +{ + return (_STORAGE_DRIVER.status(0) & STA_NODISK) == 0; +} + +const diskio_driver_t* storageGetDefaultDriver() +{ + return &_STORAGE_DRIVER; +} diff --git a/radio/src/hal/storage.h b/radio/src/hal/storage.h new file mode 100644 index 00000000000..7a018f95354 --- /dev/null +++ b/radio/src/hal/storage.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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. + */ + +#pragma once + +// Called when the storage is initialized +// +// Note: can be used to attach the pyhsical volume driver +// to the generic FatFs driver +void storageInit(); + +// Called before the storage is mounted +void storagePreMountHook(); + +bool storageIsPresent(); + +#define SD_CARD_PRESENT() storageIsPresent() + +struct diskio_driver_t; + +// returns the default storage's IO driver +const diskio_driver_t* storageGetDefaultDriver(); diff --git a/radio/src/main.cpp b/radio/src/main.cpp index 2a2d4c2394e..3026090e22e 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -21,6 +21,7 @@ #include "opentx.h" #include "hal/adc_driver.h" +#include "hal/storage.h" #if defined(LIBOPENUI) #include "libopenui.h" diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 5f855f8a268..245c2fe8bc7 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -23,6 +23,8 @@ #include "io/frsky_firmware_update.h" #include "hal/adc_driver.h" #include "hal/switch_driver.h" +#include "hal/storage.h" + #include "timers_driver.h" #include "watchdog_driver.h" @@ -198,10 +200,6 @@ void per10ms() if (mixWarning & 4) if(((g_tmr10ms&0xFF)==128) || ((g_tmr10ms&0xFF)==136) || ((g_tmr10ms&0xFF)==144)) AUDIO_MIX_WARNING(3); #endif -#if defined(SDCARD) && defined(PCBTARANIS) - sdPoll10ms(); -#endif - outputTelemetryBuffer.per10ms(); heartbeat |= HEART_TIMER_10MS; diff --git a/radio/src/rtos.h b/radio/src/rtos.h index 96a61cc0c65..69c54aab8d3 100644 --- a/radio/src/rtos.h +++ b/radio/src/rtos.h @@ -22,7 +22,8 @@ #ifndef _RTOS_H_ #define _RTOS_H_ -#include "definitions.h" +#include +#include #ifdef __cplusplus extern "C++" { @@ -114,15 +115,17 @@ extern "C++" { #endif } -template -inline void RTOS_CREATE_TASK(pthread_t &taskId, void * (*task)(void *), const char * name, TaskStack &, unsigned size = 0, unsigned priority = 0) + template + inline void RTOS_CREATE_TASK(pthread_t &taskId, void *(*task)(void *), + const char *name, TaskStack &, + unsigned size = 0, unsigned priority = 0) { - UNUSED(size); - UNUSED(priority); + (void)size; + (void)priority; RTOS_CREATE_TASK(taskId, task, name); } - #define TASK_RETURN() return nullptr +#define TASK_RETURN() return nullptr constexpr uint32_t mainStackAvailable() { diff --git a/radio/src/sdcard.cpp b/radio/src/sdcard.cpp index 07ffe88ad43..9555ebb60ca 100644 --- a/radio/src/sdcard.cpp +++ b/radio/src/sdcard.cpp @@ -22,8 +22,10 @@ #include #include +#include "hal/fatfs_diskio.h" +#include "hal/storage.h" + #include "opentx.h" -#include "diskio.h" #if defined(LIBOPENUI) #include "libopenui.h" @@ -479,7 +481,8 @@ uint32_t sdGetSize() uint32_t sdGetFreeSectors() { - return ((SDCARD_MIN_FREE_SPACE_MB*1024*1024)/BLOCK_SIZE)+1; // SIMU SD card is always above threshold + // SIMU SD card is always above threshold + return ((SDCARD_MIN_FREE_SPACE_MB*1024*1024)/BLOCK_SIZE)+1; } uint32_t sdGetFreeKB() { return SDCARD_MIN_FREE_SPACE_MB * 1024 + 1; } @@ -501,41 +504,11 @@ FIL g_bluetoothFile = {}; #include "audio.h" #include "sdcard.h" -#include "disk_cache.h" - -/*-----------------------------------------------------------------------*/ -/* Lock / unlock functions */ -/*-----------------------------------------------------------------------*/ -static RTOS_MUTEX_HANDLE ioMutex; -uint32_t ioMutexReq = 0, ioMutexRel = 0; -int ff_cre_syncobj (BYTE vol, FF_SYNC_t * mutex) -{ - *mutex = ioMutex; - return 1; -} - -int ff_req_grant (FF_SYNC_t mutex) -{ - ioMutexReq += 1; - RTOS_LOCK_MUTEX(mutex); - return 1; -} - -void ff_rel_grant (FF_SYNC_t mutex) -{ - ioMutexRel += 1; - RTOS_UNLOCK_MUTEX(mutex); -} - -int ff_del_syncobj (FF_SYNC_t mutex) -{ - return 1; -} void sdInit() { TRACE("sdInit"); - RTOS_CREATE_MUTEX(ioMutex); + storageInit(); sdMount(); } @@ -543,9 +516,7 @@ void sdMount() { TRACE("sdMount"); -#if defined(DISK_CACHE) - diskCache.clear(); -#endif + storagePreMountHook(); if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) { // call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called @@ -598,18 +569,3 @@ uint32_t sdMounted() return _g_FATFS_init && (g_FATFS_Obj.fs_type != 0); #endif } - - -uint32_t sdIsHC() -{ - // defined in diskio - #define CT_BLOCK 0x08 - extern uint32_t SD_GetCardType(); - - return SD_GetCardType() & CT_BLOCK; -} - -uint32_t sdGetSpeed() -{ - return 330000; -} diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index ab18bc7abde..c106c301a3f 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -135,21 +135,6 @@ uint32_t sdGetFreeSectors(); uint32_t sdGetFreeKB(); bool sdIsFull(); -#if defined(PCBTARANIS) -void sdPoll10ms(); -#endif - -#if !defined(SIMU) || defined(SIMU_DISKIO) - uint32_t sdIsHC(); - uint32_t sdGetSpeed(); - #define SD_IS_HC() (sdIsHC()) - #define SD_GET_SPEED() (sdGetSpeed()) - #define SD_GET_FREE_BLOCKNR() (sdGetFreeSectors()) -#else - #define SD_IS_HC() (0) - #define SD_GET_SPEED() (0) -#endif - const char * sdCheckAndCreateDirectory(const char * path); #if !defined(BOOT) @@ -162,7 +147,6 @@ inline const char * SDCARD_ERROR(FRESULT result) } #endif -// NOTE: 'size' must = 0 or be a valid character position within 'filename' array -- it is NOT validated const char * getBasename(const char * path); bool isFileAvailable(const char * filename, bool exclDir = false); diff --git a/radio/src/serial.cpp b/radio/src/serial.cpp index 303deb60379..dcaf703ea68 100644 --- a/radio/src/serial.cpp +++ b/radio/src/serial.cpp @@ -83,16 +83,13 @@ extern "C" void dbgSerialPrintf(const char * format, ...) va_list arglist; char tmp[PRINTF_BUFFER_SIZE+1]; - // no need to do anything if we don't have an output - if (!dbg_serial_putc) return; - va_start(arglist, format); vsnprintf(tmp, PRINTF_BUFFER_SIZE, format, arglist); tmp[PRINTF_BUFFER_SIZE] = '\0'; va_end(arglist); const char *t = tmp; - while (*t && dbg_serial_putc) { + while (*t) { SEGGER_RTT_Write(0, (const void *)t++, 1); } } diff --git a/radio/src/targets/common/arm/stm32/ads79xx.cpp b/radio/src/targets/common/arm/stm32/ads79xx.cpp index b91b5113ff1..1f05954114c 100644 --- a/radio/src/targets/common/arm/stm32/ads79xx.cpp +++ b/radio/src/targets/common/arm/stm32/ads79xx.cpp @@ -30,69 +30,43 @@ #define MANUAL_MODE 0x1000 // manual mode channel 0 #define MANUAL_MODE_CHANNEL(x) (MANUAL_MODE | ((x) << 7)) -static uint16_t ads79xx_rw(SPI_TypeDef* SPIx, uint16_t value) -{ - while (!LL_SPI_IsActiveFlag_TXE(SPIx)); - LL_SPI_TransmitData16(SPIx, value); +#define ADS79XX_MAX_FREQ (20000000UL) - while (!LL_SPI_IsActiveFlag_RXNE(SPIx)); - return LL_SPI_ReceiveData16(SPIx); +static inline uint16_t ads79xx_rw(const stm32_spi_t* spi, uint16_t value) +{ + return stm32_spi_transfer_word(spi, value); } void ads79xx_init(const stm32_spi_adc_t* adc) { - stm32_gpio_enable_clock(adc->GPIOx); - LL_GPIO_InitTypeDef pinInit; - LL_GPIO_StructInit(&pinInit); - - pinInit.Pin = adc->GPIO_Pins; - pinInit.Mode = LL_GPIO_MODE_ALTERNATE; - pinInit.Alternate = adc->GPIO_AF; - LL_GPIO_Init(adc->GPIOx, &pinInit); - - pinInit.Pin = adc->GPIO_CS; - pinInit.Mode = LL_GPIO_MODE_OUTPUT; - pinInit.Alternate = LL_GPIO_AF_0; - LL_GPIO_Init(adc->GPIOx, &pinInit); - - auto SPIx = adc->SPIx; - stm32_spi_enable_clock(SPIx); - LL_SPI_DeInit(SPIx); - - LL_SPI_InitTypeDef spiInit; - LL_SPI_StructInit(&spiInit); + const auto* spi = &adc->spi; - spiInit.TransferDirection = LL_SPI_FULL_DUPLEX; - spiInit.Mode = LL_SPI_MODE_MASTER; - spiInit.DataWidth = LL_SPI_DATAWIDTH_16BIT; - spiInit.NSS = LL_SPI_NSS_SOFT; - spiInit.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8; - LL_SPI_Init(SPIx, &spiInit); - - LL_SPI_Enable(SPIx); - - LL_SPI_DisableIT_TXE(SPIx); - LL_SPI_DisableIT_RXNE(SPIx); - - _SPI_ADC_CS_HIGH(adc); + stm32_spi_init(spi); + stm32_spi_set_max_baudrate(spi, ADS79XX_MAX_FREQ); + LL_SPI_SetDataWidth(spi->SPIx, LL_SPI_DATAWIDTH_16BIT); + + stm32_spi_unselect(spi); delay_01us(1); - _SPI_ADC_CS_LOW(adc); - ads79xx_rw(SPIx, RESETCMD); - _SPI_ADC_CS_HIGH(adc); + + stm32_spi_select(spi); + ads79xx_rw(spi, RESETCMD); + stm32_spi_unselect(spi); delay_01us(1); - _SPI_ADC_CS_LOW(adc); - ads79xx_rw(SPIx, MANUAL_MODE); - _SPI_ADC_CS_HIGH(adc); + + stm32_spi_select(spi); + ads79xx_rw(spi, MANUAL_MODE); + stm32_spi_unselect(spi); } static void ads79xx_dummy_read(const stm32_spi_adc_t* adc, uint16_t start_channel) { // A dummy command to get things started // (because the sampled data is lagging behind for two command cycles) - _SPI_ADC_CS_LOW(adc); + const auto* spi = &adc->spi; + stm32_spi_select(spi); delay_01us(1); - ads79xx_rw(adc->SPIx, MANUAL_MODE_CHANNEL(start_channel)); - _SPI_ADC_CS_HIGH(adc); + ads79xx_rw(spi, MANUAL_MODE_CHANNEL(start_channel)); + stm32_spi_unselect(spi); delay_01us(1); } @@ -115,8 +89,9 @@ static uint32_t ads79xx_read_next_channel(const stm32_spi_adc_t* adc, // 62 0 0.225ms - 0.243ms delay_01us(40); + const auto* spi = &adc->spi; for (uint8_t i = 0; i < 4; i++) { - _SPI_ADC_CS_LOW(adc); + stm32_spi_select(spi); delay_01us(1); // command is changed to the next index for the last two readings @@ -126,7 +101,7 @@ static uint32_t ads79xx_read_next_channel(const stm32_spi_adc_t* adc, auto input_idx = chan[chan_idx]; auto spi_chan = inputs[input_idx].ADC_Channel; - uint16_t val = (0x0fff & ads79xx_rw(adc->SPIx, MANUAL_MODE_CHANNEL(spi_chan))); + uint16_t val = (0x0fff & ads79xx_rw(spi, MANUAL_MODE_CHANNEL(spi_chan))); #if defined(JITTER_MEASURE) if (JITTER_MEASURE_ACTIVE()) { @@ -134,7 +109,7 @@ static uint32_t ads79xx_read_next_channel(const stm32_spi_adc_t* adc, } #endif - _SPI_ADC_CS_HIGH(adc); + stm32_spi_unselect(spi); delay_01us(1); result += val; } diff --git a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt index 77df75fa3f9..8170b0e90fc 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt @@ -21,14 +21,11 @@ set(BOOTLOADER_SRC ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/src/usbd_msc_bot.c ../../../../../${STM32USB_DIR}/STM32_USB_Device_Library/Class/msc/src/usbd_msc_core.c - ../../../../../${FATFS_DIR}/ff.c - ../../../../../${FATFS_DIR}/ffunicode.c ../../../../../targets/${TARGET_DIR}/${LCD_DRIVER} ../../../../../targets/${TARGET_DIR}/backlight_driver.cpp ../../../../../targets/${TARGET_DIR}/board.cpp ../../../../../targets/${TARGET_DIR}/bootloader/boot_menu.cpp ${CMAKE_CURRENT_BINARY_DIR}/hal_keys.inc - ../../../../../hal/key_driver.cpp ../pwr_driver.cpp ../usbd_usr.cpp ../usbd_storage_msd.cpp @@ -77,7 +74,6 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14) ../../../../../fonts/lvgl/lv_font_roboto_bl_16.c ../../../../../thirdparty/libopenui/src/bitmapbuffer.cpp ../../../../../thirdparty/libopenui/thirdparty/lz4/lz4.c - ../../../../../targets/common/arm/stm32/sdio_sd.cpp ../../../../../targets/common/arm/stm32/diskio_sdio.cpp ../../../../../targets/common/arm/stm32/rtc_driver.cpp ../../../../../targets/${TARGET_DIR}/sdram_driver.c @@ -119,8 +115,11 @@ else() ${BOOTLOADER_SRC} ../../../../../gui/common/stdlcd/fonts.cpp ../../../../../gui/common/stdlcd/utf8.cpp - ../../../../../targets/${TARGET_DIR}/eeprom_driver.cpp - ../../../../../targets/${TARGET_DIR}/diskio.cpp + ../../../../../targets/common/arm/stm32/stm32_gpio_driver.cpp + ../../../../../targets/common/arm/stm32/stm32_spi.cpp + ../../../../../targets/common/arm/stm32/sdcard_spi.cpp + ../../../../../targets/common/arm/stm32/diskio_spi.cpp + ../../../../../crc.cpp ) remove_definitions(-DDEBUG) endif() diff --git a/radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp b/radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp index f909d2f8b2f..f3703287126 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/bin_files.cpp @@ -28,6 +28,7 @@ #include "bin_files.h" #include "fw_version.h" #include "strhelpers.h" +#include "hal/storage.h" // 'private' static DIR dir; @@ -42,6 +43,8 @@ void sdInit(void) { static FATFS fatFS __DMA; + storageInit(); + if (f_mount(&fatFS, "", 1) == FR_OK) { f_chdir("/"); } diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 0839e8d7f4b..6daef795998 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -94,8 +94,8 @@ uint32_t eepromWritten = 0; FlashCheckRes valid; MemoryType memoryType; uint32_t unlocked = 0; -uint32_t timer10MsCount; +volatile uint32_t timer10MsCount; void interrupt10ms() { @@ -117,30 +117,52 @@ void interrupt10ms() #endif } -void init10msTimer() +extern "C" uint32_t HAL_GetTick(void) +{ + return timer10MsCount * 10; +} + +#if !defined(SIMU) +static volatile uint32_t _us_overflow_cnt; + +void initTimers() { timer10MsCount = 0; INTERRUPT_xMS_TIMER->ARR = 9999; // 10mS in uS INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS - INTERRUPT_xMS_TIMER->CCER = 0; - INTERRUPT_xMS_TIMER->CCMR1 = 0; - INTERRUPT_xMS_TIMER->EGR = 0; - INTERRUPT_xMS_TIMER->CR1 = 5; - INTERRUPT_xMS_TIMER->DIER |= 1; + INTERRUPT_xMS_TIMER->CR1 = TIM_CR1_CEN; + INTERRUPT_xMS_TIMER->DIER = TIM_DIER_UIE; NVIC_EnableIRQ(INTERRUPT_xMS_IRQn); + + _us_overflow_cnt = 0; + TIMER_2MHz_TIMER->ARR = 65535; + TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5 uS, 2 MHz + TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; + TIMER_2MHz_TIMER->DIER = TIM_DIER_UIE; + NVIC_EnableIRQ(TIMER_2MHz_IRQn); + + while(timer10MsCount < 10); } -extern "C" uint32_t HAL_GetTick(void) +uint32_t timersGetUsTick() { - return timer10MsCount*10; + uint32_t us; + us = TIMER_2MHz_TIMER->CNT >> 1; + us += _us_overflow_cnt << 15; + return us; } -#if !defined(SIMU) extern "C" void INTERRUPT_xMS_IRQHandler() { INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF; interrupt10ms(); } + +extern "C" void TIMER_2MHz_IRQHandler() +{ + TIMER_2MHz_TIMER->SR &= ~TIM_SR_UIF; + _us_overflow_cnt += 1; +} #endif uint32_t isValidBufferStart(const uint8_t * buffer) @@ -226,14 +248,15 @@ void writeEepromBlock() #if !defined(SIMU) void bootloaderInitApp() { - RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | - LCD_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | - KEYS_BACKLIGHT_RCC_AHB1Periph | SD_RCC_AHB1Periph, + RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | LCD_RCC_AHB1Periph | + BACKLIGHT_RCC_AHB1Periph | + KEYS_BACKLIGHT_RCC_AHB1Periph, ENABLE); RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | LCD_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | - INTERRUPT_xMS_RCC_APB1Periph | SD_RCC_APB1Periph, + INTERRUPT_xMS_RCC_APB1Periph | + TIMER_2MHz_RCC_APB1Periph, ENABLE); RCC_APB2PeriphClockCmd( @@ -251,18 +274,6 @@ void bootloaderInitApp() pwrInit(); keysInit(); -#if defined(SWSERIALPOWER) - // TODO: replace with proper serial port query... - // #if defined(AUX_SERIAL) - // void set_aux_pwr(uint8_t on); - // set_aux_pwr(0); - // #endif - // #if defined(AUX2_SERIAL) - // void set_aux2_pwr(uint8_t on); - // set_aux2_pwr(0); - // #endif -#endif - // wait a bit for the inputs to stabilize... if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) { for (uint32_t i = 0; i < 150000; i++) { @@ -311,7 +322,7 @@ void bootloaderInitApp() eepromInit(); #endif - init10msTimer(); + initTimers(); // SD card detect pin sdInit(); @@ -578,16 +589,6 @@ int bootloaderMain() lcdRefresh(); -#if defined(SDCARD) && defined(PCBTARANIS) - static uint32_t PowerUpDelay = 0; - - if (PowerUpDelay < 20) { // 200 mS - PowerUpDelay += 1; - } - else { - sdPoll10ms(); - } -#endif } if (state != ST_FLASHING && state != ST_USB) { diff --git a/radio/src/targets/common/arm/stm32/diskio_sdio.cpp b/radio/src/targets/common/arm/stm32/diskio_sdio.cpp index a156849a13e..5e8d6e47f91 100644 --- a/radio/src/targets/common/arm/stm32/diskio_sdio.cpp +++ b/radio/src/targets/common/arm/stm32/diskio_sdio.cpp @@ -19,20 +19,38 @@ * GNU General Public License for more details. */ -/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */ -/*-----------------------------------------------------------------------*/ -/* This is a stub disk I/O module that acts as front end of the existing */ -/* disk I/O modules and attach it to FatFs module with common interface. */ -/*-----------------------------------------------------------------------*/ +#include "diskio_sdio.h" +#include "stm32_dma.h" #include "stm32_hal.h" -#include "sdio_sd.h" +#include "stm32_hal_ll.h" +#include "stm32_gpio_driver.h" -#include "FatFs/diskio.h" +#include "hal.h" -#include +// #include "delays_driver.h" #include "debug.h" +#include + +/* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */ +#if !defined(SD_SDIO_DATA_GPIO) && !defined(SD_SDIO_DATA_GPIO_PINS) +#define SD_SDIO_DATA_GPIO GPIOC +#define SD_SDIO_DATA_GPIO_PINS \ + (LL_GPIO_PIN_8 | LL_GPIO_PIN_9 | LL_GPIO_PIN_10 | LL_GPIO_PIN_11) +#endif + +/* Configure PD.02 CMD line */ +#if !defined(SD_SDIO_CMD_GPIO) && !defined(SD_SDIO_CMD_GPIO_PIN) +#define SD_SDIO_CMD_GPIO GPIOD +#define SD_SDIO_CMD_GPIO_PIN LL_GPIO_PIN_2 +#endif + +#if !defined(SD_SDIO_CLK_GPIO) && !defined(SD_SDIO_CLK_GPIO_PIN) +#define SD_SDIO_CLK_GPIO GPIOC +#define SD_SDIO_CLK_GPIO_PIN LL_GPIO_PIN_12 +#endif + #if FF_MAX_SS != FF_MIN_SS #error "Variable sector size is not supported" #endif @@ -40,33 +58,103 @@ #define BLOCK_SIZE FF_MAX_SS #define SD_TIMEOUT 300 /* 300ms */ -// Disk status -extern volatile uint32_t WriteStatus; -extern volatile uint32_t ReadStatus; +// HAL state +static SD_HandleTypeDef sdio; +static DMA_HandleTypeDef sdioTxDma; -/*-----------------------------------------------------------------------*/ -/* Inidialize a Drive */ +// Disk status +static volatile uint32_t WriteStatus; +static volatile uint32_t ReadStatus; -DSTATUS disk_initialize ( - BYTE drv /* Physical drive nmuber (0..) */ -) +static void sdio_low_level_init(void) { - DSTATUS stat = 0; + /* Enable the SDIO APB2 Clock */ + __HAL_RCC_SDIO_CLK_ENABLE(); + + LL_GPIO_InitTypeDef GPIO_InitStructure; + LL_GPIO_StructInit(&GPIO_InitStructure); + + stm32_gpio_enable_clock(SD_SDIO_DATA_GPIO); + stm32_gpio_enable_clock(SD_SDIO_CMD_GPIO); + stm32_gpio_enable_clock(SD_SDIO_CLK_GPIO); + + GPIO_InitStructure.Pin = SD_SDIO_DATA_GPIO_PINS; + GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStructure.Pull = LL_GPIO_PULL_UP; + GPIO_InitStructure.Alternate = LL_GPIO_AF_12; // SDIO + LL_GPIO_Init(SD_SDIO_DATA_GPIO, &GPIO_InitStructure); + + GPIO_InitStructure.Pin = SD_SDIO_CMD_GPIO_PIN; + LL_GPIO_Init(SD_SDIO_CMD_GPIO, &GPIO_InitStructure); + + /* Configure PC.12 pin: CLK pin */ + GPIO_InitStructure.Pin = SD_SDIO_CLK_GPIO_PIN; + GPIO_InitStructure.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(SD_SDIO_CLK_GPIO, &GPIO_InitStructure); + + // SDIO Interrupt ENABLE + NVIC_SetPriority(SDIO_IRQn, 0); + NVIC_EnableIRQ(SDIO_IRQn); + + // Init SDIO DMA instance + sdioTxDma.Instance = SD_SDIO_DMA_STREAM; + sdioTxDma.Init.Channel = SD_SDIO_DMA_CHANNEL; + sdioTxDma.Init.PeriphInc = DMA_PINC_DISABLE; + sdioTxDma.Init.MemInc = DMA_MINC_ENABLE; + sdioTxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + sdioTxDma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + sdioTxDma.Init.Mode = DMA_PFCTRL; + sdioTxDma.Init.Priority = DMA_PRIORITY_VERY_HIGH; + sdioTxDma.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + sdioTxDma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + sdioTxDma.Init.MemBurst = DMA_MBURST_INC4; + sdioTxDma.Init.PeriphBurst = DMA_PBURST_INC4; + + stm32_dma_enable_clock(SD_SDIO_DMA); + HAL_DMA_Init(&sdioTxDma); + + __HAL_LINKDMA(&sdio, hdmatx, sdioTxDma); + __HAL_LINKDMA(&sdio, hdmarx, sdioTxDma); + + // DMA2 STREAMx Interrupt ENABLE + NVIC_SetPriority(SD_SDIO_DMA_IRQn, 0); + NVIC_EnableIRQ(SD_SDIO_DMA_IRQn); +} - /* Supports only single drive */ - if (drv) - { - stat |= STA_NOINIT; +static DSTATUS sdio_initialize(BYTE lun) +{ + /* SDIO Peripheral Low Level Init */ + sdio_low_level_init(); + + /*!< Configure the SDIO peripheral */ + /*!< SDIO_CK = SDIOCLK / (SDIO_TRANSFER_CLK_DIV + 2) */ + /*!< on STM32F4xx devices, SDIOCLK is fixed to 48MHz */ + sdio.Instance = SDIO; + sdio.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + sdio.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + sdio.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + sdio.Init.BusWide = SDIO_BUS_WIDE_1B; + sdio.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + sdio.Init.ClockDiv = SD_SDIO_TRANSFER_CLK_DIV; + HAL_SD_DeInit(&sdio); + + HAL_StatusTypeDef halStatus = HAL_SD_Init(&sdio); + if (halStatus != HAL_OK) { + TRACE("HAL_SD_Init() status=%d", halStatus); + /*!< CMD Response TimeOut (wait for CMDSENT flag) */ + return STA_NOINIT; } - /*-------------------------- SD Init ----------------------------- */ - SD_Error res = SD_Init(); - if (res != SD_OK) - { - TRACE("SD_Init() failed: %d", res); - stat |= STA_NOINIT; + HAL_SD_CardInfoTypeDef cardInfo; + HAL_StatusTypeDef es = HAL_SD_GetCardInfo(&sdio, &cardInfo); + if(es != HAL_OK) { + return STA_NOINIT; } + HAL_SD_ConfigWideBusOperation(&sdio, SDIO_BUS_WIDE_4B); + TRACE("SD card info:"); TRACE("type: %u", (uint32_t)(SD_GetCardType())); TRACE("class: %u", (uint32_t)(SD_GetCardClass())); @@ -74,110 +162,95 @@ DSTATUS disk_initialize ( TRACE("sector size: %u", (uint32_t)(SD_GetSectorSize())); TRACE("block size: %u", (uint32_t)(SD_GetBlockSize())); - return(stat); + return RES_OK; } -DWORD scratch[BLOCK_SIZE / 4] __DMA; - -/*-----------------------------------------------------------------------*/ -/* Return Disk Status */ +// DMA scratch buffer used in case the input buffer is not aligned +static uint8_t scratch[BLOCK_SIZE] __DMA; -DSTATUS disk_status ( - BYTE drv /* Physical drive nmuber (0..) */ -) +typedef enum { - DSTATUS stat = 0; + SD_TRANSFER_OK = 0, + SD_TRANSFER_BUSY = 1, + SD_TRANSFER_ERROR +} SDTransferState; - if (SD_Detect() != SD_PRESENT) - stat |= STA_NODISK; - - // STA_NOTINIT - Subsystem not initailized - // STA_PROTECTED - Write protected, MMC/SD switch if available +static SDTransferState sdio_check_card_state() +{ + HAL_SD_CardStateTypeDef cardstate = HAL_SD_GetCardState(&sdio); - return(stat); + if (cardstate == HAL_SD_CARD_TRANSFER) { + return SD_TRANSFER_OK; + } + else if (cardstate == HAL_SD_CARD_ERROR) { + return SD_TRANSFER_ERROR; + } + + return SD_TRANSFER_BUSY; } -uint32_t sdReadRetries = 0; - -/*-----------------------------------------------------------------------*/ -/* Read Sector(s) */ +static int sdio_check_card_state_with_timeout(uint32_t timeout) +{ + uint32_t timer = HAL_GetTick(); + /* block until SDIO IP is ready again or a timeout occur */ + while(HAL_GetTick() - timer < timeout) { + auto state = sdio_check_card_state(); + if (state != SD_TRANSFER_BUSY) { + return state == SD_TRANSFER_OK ? 0 : -1; + } + } + return -1; +} -// Please note: -// this functions assumes that buff is properly aligned -// and in the right RAM segment for DMA -// -DRESULT disk_read_dma(BYTE drv, BYTE * buff, DWORD sector, UINT count) +static DSTATUS sdio_status(BYTE lun) { - DRESULT res = RES_ERROR; - - for (int retry = 0; retry < 3; retry++) { + DSTATUS stat = RES_OK; - ReadStatus = 0; - SD_Error Status = SD_ReadBlocks(buff, sector, BLOCK_SIZE, count); - if (Status != SD_OK) { - TRACE("SD ReadBlocks=%d, s:%u c: %u", Status, sector, (uint32_t)count); - ++sdReadRetries; - continue; - } +#if defined(SD_PRESENT_GPIO) + if ((LL_GPIO_ReadInputPort(SD_PRESENT_GPIO) & SD_PRESENT_LL_GPIO_PIN) != 0) { + stat |= STA_NODISK; + } +#endif - // Wait that the reading process is completed or a timeout occurs - uint32_t timeout = HAL_GetTick(); - while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT)); + return stat; +} - if (ReadStatus == 0) { - TRACE("SD read timeout, s:%u c:%u", sector, (uint32_t)count); - ++sdReadRetries; - continue; - } - - ReadStatus = 0; - timeout = HAL_GetTick(); - - while((HAL_GetTick() - timeout) < SD_TIMEOUT) { - if (SD_GetStatus() == SD_TRANSFER_OK) { - res = RES_OK; - break; - } - } +static DRESULT _read_dma(BYTE* buff, DWORD sector, UINT count) +{ + ReadStatus = 0; + if (HAL_SD_ReadBlocks_DMA(&sdio, buff, sector, count) != HAL_OK) { + TRACE("SD ReadBlocks failed (s:%u/c:%u)", sector, (uint32_t)count); + return RES_ERROR; + } - if (res == RES_OK) { - // exit retry loop - break; - } + // Wait for the reading process to complete or a timeout to occur + uint32_t timeout = HAL_GetTick(); + while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT)); - TRACE("SD getstatus timeout, s:%u c:%u", sector, (uint32_t)count); + if (ReadStatus == 0) { + TRACE("SD read timeout (s:%u c:%u)", sector, (uint32_t)count); + return RES_ERROR; } - - return res; + + ReadStatus = 0; + return RES_OK; } -DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count) +static DRESULT sdio_read(BYTE lun, BYTE * buff, DWORD sector, UINT count) { - // If unaligned, do the single block reads with a scratch buffer. - // If aligned and single sector, do a single block read. - // If aligned and multiple sectors, try multi block read. - // If multi block read fails, try single block reads without - // an intermediate buffer (move trough the provided buffer) + DRESULT res = RES_OK; // TRACE("disk_read %d %p %10d %d", drv, buff, sector, count); - if (SD_Detect() != SD_PRESENT) { - TRACE("SD_Detect() != SD_PRESENT"); - return RES_NOTRDY; - } - if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0) { + if (sdio_check_card_state_with_timeout(SD_TIMEOUT) < 0) { return RES_ERROR; } - - DRESULT res = RES_OK; - if (count == 0) return res; - if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) { - // buffer is not aligned, use scratch buffer that is aligned - TRACE("disk_read bad alignment (%p)", buff); + if ((DWORD)buff < SRAM_BASE || ((DWORD)buff & 3)) { + // TRACE("disk_read bad alignment (%p)", buff); while (count--) { - res = disk_read_dma(drv, (BYTE *)scratch, sector++, 1); + res = _read_dma(scratch, sector++, 1); if (res != RES_OK) break; memcpy(buff, scratch, BLOCK_SIZE); buff += BLOCK_SIZE; @@ -185,156 +258,175 @@ DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count) return res; } - res = disk_read_dma(drv, buff, sector, count); - if (res != RES_OK && count > 1) { - // multi-read failed, try reading same sectors, one by one - TRACE("disk_read() multi-block failed, trying single block reads..."); - while (count--) { - res = disk_read_dma(drv, buff, sector++, 1); - if (res != RES_OK) break; - buff += BLOCK_SIZE; + res = _read_dma(buff, sector, count); + if (res != RES_OK) return res; + + uint32_t timeout = HAL_GetTick(); + while((HAL_GetTick() - timeout) < SD_TIMEOUT) { + if (sdio_check_card_state() == SD_TRANSFER_OK) { + return RES_OK; } } - return res; + TRACE("SD getstatus timeout, s:%u c:%u", sector, (uint32_t)count); + return RES_ERROR; } -/*-----------------------------------------------------------------------*/ -/* Write Sector(s) */ +static DRESULT _write_dma(const BYTE *buff, DWORD sector, UINT count) +{ + WriteStatus = 0; + if (HAL_SD_WriteBlocks_DMA(&sdio, (uint8_t*)buff, sector, count) != HAL_OK) { + TRACE("SD WriteBlocks failed (s:%u/c:%u)", sector, (uint32_t)count); + return RES_ERROR; + } + + // Wait that the reading process is completed or a timeout occurs + uint32_t timeout = HAL_GetTick(); + while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT)); + + if (WriteStatus == 0) { + TRACE("SD write timeout (s:%u/c:%u)", sector, (uint32_t)count); + return RES_ERROR; + } + + WriteStatus = 0; + return RES_OK; +} -#if _READONLY == 0 -DRESULT __disk_write( - BYTE drv, /* Physical drive nmuber (0..) */ - const BYTE *buff, /* Data to be written */ - DWORD sector, /* Sector address (LBA) */ - UINT count /* Number of sectors to write (1..255) */ -) +static DRESULT sdio_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count) { DRESULT res = RES_OK; // TRACE("disk_write %d %p %10d %d", drv, buff, sector, count); - if (SD_Detect() != SD_PRESENT) - return RES_NOTRDY; - - if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0) { + if (sdio_check_card_state_with_timeout(SD_TIMEOUT) < 0) { return RES_ERROR; } - if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) { + if ((DWORD)buff < SRAM_BASE || ((DWORD)buff & 3)) { //TRACE("disk_write bad alignment (%p)", buff); while(count--) { memcpy(scratch, buff, BLOCK_SIZE); - - res = __disk_write(drv, (BYTE *)scratch, sector++, 1); - - if (res != RES_OK) - break; - + res = _write_dma((BYTE *)scratch, sector++, 1); + if (res != RES_OK) break; buff += BLOCK_SIZE; } - return(res); + return res; } - SD_Error Status = SD_WriteBlocks((uint8_t *)buff, sector, BLOCK_SIZE, count); - if (Status != SD_OK) { - TRACE("SD WriteBlocks=%d, s:%u c: %u", Status, sector, (uint32_t)count); - return RES_ERROR; + res = _write_dma(buff, sector, count); + if (res != RES_OK) return res; + + uint32_t timeout = HAL_GetTick(); + while((HAL_GetTick() - timeout) < SD_TIMEOUT) { + if (sdio_check_card_state() == SD_TRANSFER_OK) { + return RES_OK; + } } - // Wait that the reading process is completed or a timeout occurs - uint32_t timeout = HAL_GetTick(); - while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT)); + TRACE("SD getstatus timeout, s:%u c: %u", sector, (uint32_t)count); + return RES_ERROR; +} - if (WriteStatus == 0) { - TRACE("SD write timeout, s:%u c:%u", sector, (uint32_t)count); +static DRESULT sdio_get_sector_count(DWORD* sectors) +{ + HAL_SD_CardInfoTypeDef cardInfo; + if(HAL_SD_GetCardInfo(&sdio, &cardInfo) != HAL_OK) { return RES_ERROR; } - WriteStatus = 0; - res = RES_ERROR; - timeout = HAL_GetTick(); + *sectors = cardInfo.LogBlockNbr; + return RES_OK; +} - while((HAL_GetTick() - timeout) < SD_TIMEOUT) { - if (SD_GetStatus() == SD_TRANSFER_OK) { - res = RES_OK; - break; - } +static DRESULT sdio_get_sector_size(DWORD* sector_size) +{ + HAL_SD_CardInfoTypeDef cardInfo; + if(HAL_SD_GetCardInfo(&sdio, &cardInfo) != HAL_OK) { + return RES_ERROR; } - if (res != RES_OK) { - TRACE("SD getstatus timeout, s:%u c: %u", sector, (uint32_t)count); - res = RES_ERROR; - } + *sector_size = cardInfo.LogBlockSize; + return RES_OK; +} +static DRESULT sdio_get_block_size(DWORD* block_size) +{ + DWORD sector_size; + DRESULT res = sdio_get_sector_size(§or_size); + if (res == RES_OK) { + *block_size = sector_size / BLOCK_SIZE; + } return res; } -#endif /* _READONLY */ - -/*-----------------------------------------------------------------------*/ -/* Miscellaneous Functions */ -DRESULT disk_ioctl ( - BYTE drv, /* Physical drive nmuber (0..) */ - BYTE ctrl, /* Control code */ - void *buff /* Buffer to send/receive control data */ -) +DRESULT sdio_ioctl(BYTE lun, BYTE ctrl, void *buff) { - DRESULT res; - uint32_t tmp; - - if (drv) return RES_PARERR; - - res = RES_ERROR; - + DRESULT res = RES_OK; switch (ctrl) { case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ - tmp = SD_GetSectorCount(); - - if(tmp == 0) { - res = RES_ERROR; - break; - } - - *(DWORD*)buff = tmp; - res = RES_OK; + res = sdio_get_sector_count((DWORD*)buff); break; case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */ - tmp = SD_GetSectorSize(); - - if(tmp == 0) { - res = RES_ERROR; - break; - } - - *(WORD*)buff = tmp; - res = RES_OK; + res = sdio_get_sector_size((DWORD*)buff); break; case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ - tmp = SD_GetBlockSize() / BLOCK_SIZE; - - if(tmp == 0) { - res = RES_ERROR; - break; - } - - *(DWORD*)buff = tmp; - res = RES_OK; + res = sdio_get_block_size((DWORD*)buff); break; case CTRL_SYNC: - /* Complete pending write process (needed at _FS_READONLY == 0) */ - while (SD_GetStatus() == SD_TRANSFER_BUSY); - res = RES_OK; + /* Complete pending write process */ + while (sdio_check_card_state() == SD_TRANSFER_BUSY); break; default: - res = RES_OK; break; - } return res; } + +const diskio_driver_t sdio_diskio_driver = { + .initialize = sdio_initialize, + .status = sdio_status, + .read = sdio_read, + .write = sdio_write, + .ioctl = sdio_ioctl, +}; + +/** +* @brief Tx Transfer completed callbacks +* @param hsd: SD handle +* @retval None +*/ + +extern "C" void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + UNUSED(hsd); + WriteStatus = 1; +} + +/** +* @brief Rx Transfer completed callbacks +* @param hsd: SD handle +* @retval None +*/ + +extern "C" void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + UNUSED(hsd); + ReadStatus = 1; +} + +extern "C" void SDIO_IRQHandler(void) +{ + DEBUG_INTERRUPT(INT_SDIO); + HAL_SD_IRQHandler(&sdio); +} +extern "C" void SD_SDIO_DMA_IRQHANDLER(void) +{ + DEBUG_INTERRUPT(INT_SDIO_DMA); + HAL_DMA_IRQHandler(&sdioTxDma); +} diff --git a/radio/src/targets/common/arm/stm32/diskio_sdio.h b/radio/src/targets/common/arm/stm32/diskio_sdio.h new file mode 100644 index 00000000000..04dbfbe9d0b --- /dev/null +++ b/radio/src/targets/common/arm/stm32/diskio_sdio.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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. + */ + +#pragma once + +#include "hal/fatfs_diskio.h" + +extern const diskio_driver_t sdio_diskio_driver; diff --git a/radio/src/targets/common/arm/stm32/diskio_spi.cpp b/radio/src/targets/common/arm/stm32/diskio_spi.cpp new file mode 100644 index 00000000000..3f923444c1e --- /dev/null +++ b/radio/src/targets/common/arm/stm32/diskio_spi.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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. + */ + +/*-----------------------------------------------------------------------*/ +/* This is a stub disk I/O module that acts as front end of the existing */ +/* disk I/O modules and attach it to FatFs module with common interface. */ +/*-----------------------------------------------------------------------*/ + +#include "diskio_spi.h" +#include "stm32_gpio_driver.h" +#include "sdcard_spi.h" + +#include "hal.h" + +#include +#include "debug.h" + +static const stm32_spi_t _sd_spi_hw = { + .SPIx = SD_SPI, + .SPI_GPIOx = SD_GPIO, + .SPI_Pins = SD_GPIO_PIN_SCK | SD_GPIO_PIN_MISO | SD_GPIO_PIN_MOSI, + .CS_GPIOx = SD_GPIO, + .CS_Pin = SD_GPIO_PIN_CS, + .DMA = SD_SPI_DMA, + .DMA_Channel = SD_SPI_DMA_CHANNEL, + .txDMA_Stream = SD_SPI_DMA_TX_STREAM, + .rxDMA_Stream = SD_SPI_DMA_RX_STREAM, +}; + +static uint32_t _sdcard_sectors; + +static void _sd_present_gpio_init() +{ +#if defined(SD_PRESENT_GPIO) + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + pinInit.Pin = SD_PRESENT_GPIO_PIN; + pinInit.Mode = LL_GPIO_MODE_INPUT; + pinInit.Pull = LL_GPIO_PULL_UP; + + stm32_gpio_enable_clock(SD_PRESENT_GPIO); + LL_GPIO_Init(SD_PRESENT_GPIO, &pinInit); +#endif +} + +static DSTATUS sdcard_spi_initialize(BYTE lun) +{ + _sd_present_gpio_init(); + + sdcard_info_t card_info; + if (sdcard_spi_init(&_sd_spi_hw, &card_info) != SDCARD_SPI_OK) { + return STA_NOINIT; + } + + _sdcard_sectors = sdcard_spi_get_sector_count(&card_info); + + return 0; +} + +static DSTATUS sdcard_spi_status(BYTE lun) +{ + DSTATUS stat = 0; + +#if defined(SD_PRESENT_GPIO) + if (LL_GPIO_IsInputPinSet(SD_PRESENT_GPIO, SD_PRESENT_GPIO_PIN)) { + stat |= STA_NODISK; + } +#endif + + return stat; +} + +static DRESULT sdcard_spi_read(BYTE lun, BYTE * buff, DWORD sector, UINT count) +{ + // TRACE("disk_read %d %p %10d %d", lun, buff, sector, count); + + sd_rw_response_t state; + sdcard_spi_read_blocks(sector, buff, SD_HC_BLOCK_SIZE, count, &state); + if (state == SD_RW_OK) { + return RES_OK; + } + + return RES_ERROR; +} + +static DRESULT sdcard_spi_write(BYTE lun, const BYTE* buff, DWORD sector, UINT count) +{ + // TRACE("disk_write %d %p %10d %d", lun, buff, sector, count); + + sd_rw_response_t state; + sdcard_spi_write_blocks(sector, buff, SD_HC_BLOCK_SIZE, count, &state); + if (state == SD_RW_OK) { + return RES_OK; + } + + return RES_ERROR; +} + +static DRESULT sdcard_spi_ioctl(BYTE lun, BYTE ctrl, void *buff) +{ + DRESULT res = RES_OK; + + switch (ctrl) { + case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ + *(DWORD*)buff = _sdcard_sectors; + break; + + case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */ + *(WORD*)buff = SD_HC_BLOCK_SIZE; + break; + + case CTRL_SYNC: + sdcard_spi_wait_for_not_busy(); + break; + + default: + break; + } + + return res; +} + +const diskio_driver_t sdcard_spi_driver = { + .initialize = sdcard_spi_initialize, + .status = sdcard_spi_status, + .read = sdcard_spi_read, + .write = sdcard_spi_write, + .ioctl = sdcard_spi_ioctl, +}; diff --git a/radio/src/targets/common/arm/stm32/diskio_spi.h b/radio/src/targets/common/arm/stm32/diskio_spi.h new file mode 100644 index 00000000000..f73970e526a --- /dev/null +++ b/radio/src/targets/common/arm/stm32/diskio_spi.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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. + */ + +#pragma once + +#include "hal/fatfs_diskio.h" + +extern const diskio_driver_t sdcard_spi_driver; diff --git a/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt b/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt index 43e14eabb96..6c2001a1e75 100644 --- a/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt @@ -16,6 +16,7 @@ if(NOT NATIVE_BUILD) ${STM32CUBE_DIR}/Src/stm32f2xx_ll_rcc.c ${STM32CUBE_DIR}/Src/stm32f2xx_ll_exti.c ${STM32CUBE_DIR}/Src/stm32f2xx_ll_adc.c + ${STM32CUBE_DIR}/Src/stm32f2xx_ll_spi.c # HAL drivers ${STM32CUBE_DIR}/Src/stm32f2xx_hal.c ${STM32CUBE_DIR}/Src/stm32f2xx_hal_pwr.c @@ -51,8 +52,6 @@ add_library(stm32_stdperiph OBJECT EXCLUDE_FROM_ALL ${STM32_STDPERIPH_DIR}/src/stm32f2xx_gpio.c ${STM32_STDPERIPH_DIR}/src/stm32f2xx_dbgmcu.c ${STM32_STDPERIPH_DIR}/src/stm32f2xx_rcc.c - ${STM32_STDPERIPH_DIR}/src/stm32f2xx_spi.c - ${STM32_STDPERIPH_DIR}/src/stm32f2xx_dma.c ) set(FIRMWARE_SRC ${FIRMWARE_SRC} $) diff --git a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt index de78096c176..3c684234695 100644 --- a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt @@ -55,8 +55,6 @@ set(STM32_STDPERIPH_SRC ${STM32_STDPERIPH_DIR}/src/stm32f4xx_gpio.c ${STM32_STDPERIPH_DIR}/src/stm32f4xx_dbgmcu.c ${STM32_STDPERIPH_DIR}/src/stm32f4xx_rcc.c - ${STM32_STDPERIPH_DIR}/src/stm32f4xx_spi.c - ${STM32_STDPERIPH_DIR}/src/stm32f4xx_dma.c ${STM32_STDPERIPH_DIR}/src/stm32f4xx_flash.c ) diff --git a/radio/src/targets/common/arm/stm32/pwr_driver.cpp b/radio/src/targets/common/arm/stm32/pwr_driver.cpp index 59c34778a5e..2fa175d585f 100644 --- a/radio/src/targets/common/arm/stm32/pwr_driver.cpp +++ b/radio/src/targets/common/arm/stm32/pwr_driver.cpp @@ -70,12 +70,6 @@ void pwrInit() GPIO_Init(PCBREV_GPIO, &GPIO_InitStructure); hardwareOptions.pcbrev = PCBREV_VALUE(); #endif - -#if defined(SD_PRESENT_GPIO_PIN) - GPIO_ResetBits(SD_PRESENT_GPIO, SD_PRESENT_GPIO_PIN); - GPIO_InitStructure.GPIO_Pin = SD_PRESENT_GPIO_PIN; - GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure); -#endif } void pwrOn() diff --git a/radio/src/targets/common/arm/stm32/sdcard_spi.cpp b/radio/src/targets/common/arm/stm32/sdcard_spi.cpp new file mode 100644 index 00000000000..7141c464edb --- /dev/null +++ b/radio/src/targets/common/arm/stm32/sdcard_spi.cpp @@ -0,0 +1,864 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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 "sdcard_spi.h" +#include "stm32_spi.h" +#include "timers_driver.h" +#include "delays_driver.h" + +#include "debug.h" +#include "crc.h" + +#include + +#define SD_SPI_CLK_400K (400000UL) + +#if !defined(SD_SPI_CLK_MAX) +#define SD_SPI_CLK_MAX (25000000UL) +#endif + +// Disable CRC support by default +// +// #if !defined(SD_CARD_SPI_DISABLE_CRC) +// #define SD_CARD_SPI_ENABLE_CRC +// #endif + +#define US_PER_MS (1000UL) +#define INIT_CMD_RETRY_US (500 * US_PER_MS) +#define INIT_CMD0_RETRY_US (100UL) +#define R1_POLLING_RETRY_US (100 * US_PER_MS) +#define SD_DATA_TOKEN_RETRY_US (100 * US_PER_MS) +#define SD_WAIT_FOR_NOT_BUSY_US (250 * US_PER_MS) + +#define SD_BLOCK_READ_CMD_RETRY_US (100UL) +#define SD_BLOCK_WRITE_CMD_RETRY_US (100UL) + +#define SD_CARD_DUMMY_BYTE (0xFF) + +typedef enum { + SD_INIT_START, + SD_INIT_SPI_POWER_SEQ, + SD_INIT_SEND_CMD0, + SD_INIT_SEND_CMD8, + SD_INIT_CARD_UNKNOWN, + SD_INIT_SEND_ACMD41_HCS, + SD_INIT_SEND_ACMD41, + SD_INIT_SEND_CMD1, + SD_INIT_SEND_CMD58, + SD_INIT_SEND_CMD16, + SD_INIT_ENABLE_CRC, + SD_INIT_READ_CID, + SD_INIT_READ_CSD, + SD_INIT_SET_MAX_SPI_SPEED, + SD_INIT_FINISH +} sd_init_fsm_state_t; + +static sdcard_spi_t _sdcard_spi = {nullptr, false}; + +static inline void _send_dummy_byte(const stm32_spi_t* spi) +{ + stm32_spi_transfer_byte(spi, SD_CARD_DUMMY_BYTE); +} + +static bool _wait_for_not_busy(const stm32_spi_t* spi, uint32_t retry_us) +{ + uint32_t timeout = timersGetUsTick(); + + do { + uint8_t read_byte = stm32_spi_transfer_byte(spi, SD_CARD_DUMMY_BYTE); + if (read_byte == 0xFF) { + return true; + } + if ((read_byte & 0x0F) != 0x00) { + // shift by some bits??? + stm32_spi_unselect(spi); + _send_dummy_byte(spi); + stm32_spi_select(spi); + } + } while (timersGetUsTick() - timeout < retry_us); + + TRACE("_wait_for_not_busy: [FAILED]"); + return false; +} + +static uint8_t _crc_7(const uint8_t* data, int n) +{ + uint8_t crc = 0; + + for (int i = 0; i < n; i++) { + uint8_t d = data[i]; + for (int j = 0; j < 8; j++) { + crc <<= 1; + if ((d & 0x80) ^ (crc & 0x80)) { + crc ^= 0x09; + } + d <<= 1; + } + } + return (crc << 1) | 1; +} + +static inline uint16_t _transfer_bytes(const stm32_spi_t* spi, const uint8_t* out, + uint8_t* in, uint16_t length) +{ + return stm32_spi_transfer_bytes(spi, out, in, length); +} + +static void _flush_block(const stm32_spi_t* spi) +{ + for (int i = 0; i < 512 + 2; i++) { + _send_dummy_byte(spi); + } +} + +static inline uint8_t _wait_for_r1(const stm32_spi_t* spi, uint32_t retry_us) +{ + uint32_t timeout = timersGetUsTick(); + uint8_t r1; + + do { + r1 = stm32_spi_transfer_byte(spi, SD_CARD_DUMMY_BYTE); + + if (R1_VALID(r1)) { + return r1; + } + + } while (timersGetUsTick() - timeout < retry_us); + + return r1; +} + +static inline bool _wait_for_token(const stm32_spi_t* spi, uint8_t token, uint32_t retry_us) +{ + uint32_t timeout = timersGetUsTick(); + uint8_t read_byte; + + do { + read_byte = stm32_spi_transfer_byte(spi, SD_CARD_DUMMY_BYTE); + if (read_byte == token) { + return true; + } + + } while ((read_byte == 0xFF) && (timersGetUsTick() - timeout < retry_us)); + + // hack to get rid of a packet in case + // the token was shifted + if (read_byte != 0xFF) { + _flush_block(spi); + } + + return false; +} + +static uint8_t sdcard_spi_send_cmd(const stm32_spi_t* spi, uint8_t sd_cmd_idx, + uint32_t argument, uint32_t retry_us) +{ + uint8_t r1_resu; + uint8_t cmd_data[6]; + + cmd_data[0] = SD_CMD_PREFIX_MASK | sd_cmd_idx; + cmd_data[1] = argument >> (3 * 8); + cmd_data[2] = (argument >> (2 * 8)) & 0xFF; + cmd_data[3] = (argument >> 8) & 0xFF; + cmd_data[4] = argument & 0xFF; + cmd_data[5] = _crc_7(cmd_data, sizeof(cmd_data) - 1); + + uint32_t timeout = timersGetUsTick(); + do { + if (!_wait_for_not_busy(spi, SD_WAIT_FOR_NOT_BUSY_US)) { + TRACE( + "sdcard_spi_send_cmd: timeout while waiting for bus to be not busy!"); + r1_resu = SD_INVALID_R1_RESPONSE; + continue; + } + + if (_transfer_bytes(spi, cmd_data, 0, sizeof(cmd_data)) != sizeof(cmd_data)) { + TRACE("sdcard_spi_send_cmd: _transfer_bytes: send cmd [%d]: [ERROR]", + sd_cmd_idx); + r1_resu = SD_INVALID_R1_RESPONSE; + continue; + } + + /* received byte after cmd12 is a dummy byte and should be ignored */ + if (sd_cmd_idx == SD_CMD_12) { + _send_dummy_byte(spi); + } + + r1_resu = _wait_for_r1(spi, R1_POLLING_RETRY_US); + + if (R1_VALID(r1_resu)) { + break; + } else { + TRACE("sdcard_spi_send_cmd: R1_TIMEOUT (0x%02x)", r1_resu); + r1_resu = SD_INVALID_R1_RESPONSE; + } + + } while (timersGetUsTick() - timeout < retry_us); + + return r1_resu; +} + +static uint8_t sdcard_spi_send_acmd(const stm32_spi_t* spi, uint8_t sd_cmd_idx, + uint32_t argument, uint32_t retry_us) +{ + uint32_t timeout = timersGetUsTick(); + uint8_t r1_resu; + + do { + r1_resu = sdcard_spi_send_cmd(spi, SD_CMD_55, SD_CMD_NO_ARG, 0); + if (R1_VALID(r1_resu) && !R1_ERROR(r1_resu)) { + r1_resu = sdcard_spi_send_cmd(spi, sd_cmd_idx, argument, 0); + + if (R1_VALID(r1_resu) && !R1_ERROR(r1_resu)) { + return r1_resu; + } + } + } while (timersGetUsTick() - timeout < retry_us); + + TRACE("sdcard_spi_send_acmd: [TIMEOUT]"); + return r1_resu; +} + +static sd_rw_response_t _read_cid(const stm32_spi_t* spi, sdcard_info_t* card); +static sd_rw_response_t _read_csd(const stm32_spi_t* spi, sdcard_info_t* card); + +static sd_init_fsm_state_t _init_sd_fsm_step(const stm32_spi_t* spi, + sdcard_info_t* card, + sd_init_fsm_state_t state) +{ + switch (state) { + case SD_INIT_START: + TRACE("SD_INIT_START"); + stm32_spi_init(spi); + stm32_spi_set_max_baudrate(spi, SD_SPI_CLK_400K); + return SD_INIT_SPI_POWER_SEQ; + + case SD_INIT_SPI_POWER_SEQ: + TRACE("SD_INIT_SPI_POWER_SEQ"); + { + // wait minimum 50 ms until card is powered + uint32_t power_on_timeout = timersGetUsTick(); + while(timersGetUsTick() - power_on_timeout < 50 * US_PER_MS); + } + + // unselect sdcard for power up sequence + stm32_spi_unselect(spi); + + // powersequence: perform at least 74 clock cycles with mosi_pin being + // high (same as sending dummy bytes with 0xFF) + for (int i = 0; i < 10; i++) { + stm32_spi_transfer_byte(spi, 0xff); + } + { + // wait for "end of transfer" + uint32_t power_on_timeout = timersGetUsTick(); + while(timersGetUsTick() - power_on_timeout <= 200); + } + return SD_INIT_SEND_CMD0; + + case SD_INIT_SEND_CMD0: + TRACE("SD_INIT_SEND_CMD0"); + stm32_spi_select(spi); + { + uint8_t cmd0_r1 = sdcard_spi_send_cmd(spi, SD_CMD_0, SD_CMD_NO_ARG, INIT_CMD0_RETRY_US); + stm32_spi_unselect(spi); + + if (R1_VALID(cmd0_r1) && !R1_ERROR(cmd0_r1) && R1_IDLE_BIT_SET(cmd0_r1)) { + TRACE("CMD0: [OK]"); + return SD_INIT_ENABLE_CRC; + } else { + TRACE("CMD0: [FAILED]"); + } + } + + return SD_INIT_CARD_UNKNOWN; + + case SD_INIT_ENABLE_CRC: +#if defined(SD_CARD_SPI_ENABLE_CRC) + TRACE("SD_INIT_ENABLE_CRC"); + stm32_spi_select(spi); + { + uint8_t r1 = sdcard_spi_send_cmd(spi, SD_CMD_59, SD_CMD_59_ARG_EN, + INIT_CMD_RETRY_US); + stm32_spi_unselect(spi); + + if (R1_VALID(r1) && !R1_ERROR(r1)) { + TRACE("CMD59: [OK]"); + return SD_INIT_SEND_CMD8; + } + } + return SD_INIT_CARD_UNKNOWN; +#endif + /* if SD_CARD_SPI_ENABLE_CRC is not enabled, + let's continue directly with CMD8 + */ + + case SD_INIT_SEND_CMD8: + TRACE("SD_INIT_SEND_CMD8"); + stm32_spi_select(spi); + { + int cmd8_arg = (SD_CMD_8_VHS_2_7_V_TO_3_6_V << 8) | SD_CMD_8_CHECK_PATTERN; + uint8_t cmd8_r1 = sdcard_spi_send_cmd(spi, SD_CMD_8, cmd8_arg, INIT_CMD_RETRY_US); + + if (R1_VALID(cmd8_r1) && !R1_ERROR(cmd8_r1)) { + TRACE("CMD8: [OK] --> reading remaining bytes for R7"); + + uint8_t r7[4]; + + if (_transfer_bytes(spi, 0, &r7[0], sizeof(r7)) == sizeof(r7)) { + TRACE("R7 response: 0x%02x 0x%02x 0x%02x 0x%02x", r7[0], r7[1], r7[2], r7[3]); + /* check if lower 12 bits (voltage range and check pattern) of + response and arg are equal to verify compatibility and + communication is working properly */ + if (((r7[2] & 0x0F) == ((cmd8_arg >> 8) & 0x0F)) && + (r7[3] == (cmd8_arg & 0xFF))) { + TRACE("CMD8: [R7 MATCH]"); + return SD_INIT_SEND_ACMD41_HCS; + } + + TRACE("CMD8: [R7 MISMATCH]"); + } else { + TRACE("CMD8: _transfer_bytes (R7): [ERROR]"); + } + + stm32_spi_unselect(spi); + return SD_INIT_CARD_UNKNOWN; + } + } + + TRACE("CMD8: [ERROR / NO RESPONSE]"); + return SD_INIT_SEND_ACMD41; + + case SD_INIT_CARD_UNKNOWN: + TRACE("SD_INIT_CARD_UNKNOWN"); + card->card_type = SD_UNKNOWN; + return SD_INIT_FINISH; + + case SD_INIT_SEND_ACMD41_HCS: + TRACE("SD_INIT_SEND_ACMD41_HCS"); + { + uint32_t acmd41_hcs_retry_timeout = timersGetUsTick(); + do { + uint8_t acmd41hcs_r1 = sdcard_spi_send_acmd(spi, SD_CMD_41, SD_ACMD_41_ARG_HC, 0); + if (R1_VALID(acmd41hcs_r1) && !R1_ERROR(acmd41hcs_r1) && + !R1_IDLE_BIT_SET(acmd41hcs_r1)) { + TRACE("ACMD41: [OK]"); + return SD_INIT_SEND_CMD58; + } + } while (timersGetUsTick() - acmd41_hcs_retry_timeout < INIT_CMD_RETRY_US); + } + stm32_spi_unselect(spi); + TRACE("ACMD41_HCS: [ERROR]"); + return SD_INIT_CARD_UNKNOWN; + + case SD_INIT_SEND_ACMD41: + TRACE("SD_INIT_SEND_ACMD41"); + { + uint32_t acmd41_retry_timeout = timersGetUsTick(); + do { + uint8_t acmd41_r1 = + sdcard_spi_send_acmd(spi, SD_CMD_41, SD_CMD_NO_ARG, 0); + if (R1_VALID(acmd41_r1) && !R1_ERROR(acmd41_r1) && + !R1_IDLE_BIT_SET(acmd41_r1)) { + TRACE("ACMD41: [OK]"); + card->use_block_addr = false; + card->card_type = SD_V1; + return SD_INIT_SEND_CMD16; + } + } while (timersGetUsTick() - acmd41_retry_timeout < INIT_CMD_RETRY_US); + } + TRACE("ACMD41: [ERROR]"); + return SD_INIT_SEND_CMD1; + + case SD_INIT_SEND_CMD1: + TRACE("SD_INIT_SEND_CMD1"); + TRACE("COULD TRY CMD1 (for MMC-card)-> currently not supported"); + stm32_spi_unselect(spi); + return SD_INIT_CARD_UNKNOWN; + + case SD_INIT_SEND_CMD58: + TRACE("SD_INIT_SEND_CMD58"); + { + uint8_t cmd58_r1 = sdcard_spi_send_cmd(spi, SD_CMD_58, SD_CMD_NO_ARG, + INIT_CMD_RETRY_US); + if (R1_VALID(cmd58_r1) && !R1_ERROR(cmd58_r1)) { + TRACE("CMD58: [OK]"); + card->card_type = SD_V2; + + uint8_t r3[4]; + if (_transfer_bytes(spi, 0, r3, sizeof(r3)) == sizeof(r3)) { + uint32_t ocr = ((uint32_t)r3[0] << (3 * 8)) | + ((uint32_t)r3[1] << (2 * 8)) | (r3[2] << 8) | r3[3]; + TRACE("R3 RESPONSE: 0x%02x 0x%02x 0x%02x 0x%02x", + r3[0], r3[1], r3[2], r3[3]); + TRACE("OCR: 0x%" PRIx32, ocr); + + if ((ocr & SYSTEM_VOLTAGE) != 0) { + TRACE("OCR: SYS VOLTAGE SUPPORTED"); + + /* if power up outine is finished */ + if ((ocr & OCR_POWER_UP_STATUS) != 0) { + TRACE("OCR: POWER UP ROUTINE FINISHED"); + /* if sd card is sdhc */ + if ((ocr & OCR_CCS) != 0) { + TRACE("OCR: CARD TYPE IS SDHC (SD_V2 with block addressing)"); + card->use_block_addr = true; + stm32_spi_unselect(spi); + return SD_INIT_READ_CID; + } + + TRACE("OCR: CARD TYPE IS SDSC (SD_v2 with byte addressing)"); + card->use_block_addr = false; + return SD_INIT_SEND_CMD16; + } + + TRACE("OCR: POWER UP ROUTINE NOT FINISHED!"); + /* poll status till power up is finished */ + return SD_INIT_SEND_CMD58; + } + + TRACE("OCR: SYS VOLTAGE NOT SUPPORTED!"); + } + + TRACE("CMD58 response: [READ ERROR]"); + } + } + + TRACE("CMD58: [ERROR]"); + stm32_spi_unselect(spi); + return SD_INIT_CARD_UNKNOWN; + + case SD_INIT_SEND_CMD16: + TRACE("SD_INIT_SEND_CMD16"); + { + uint8_t r1_16 = sdcard_spi_send_cmd(spi, SD_CMD_16, SD_HC_BLOCK_SIZE, + INIT_CMD_RETRY_US); + if (R1_VALID(r1_16) && !R1_ERROR(r1_16)) { + TRACE("CARD TYPE IS SDSC (SD_V1 with byte addressing)"); + stm32_spi_unselect(spi); + return SD_INIT_READ_CID; + } else { + stm32_spi_unselect(spi); + return SD_INIT_CARD_UNKNOWN; + } + } + // unreachable + break; + + case SD_INIT_READ_CID: + TRACE("SD_INIT_READ_CID"); + if (_read_cid(spi, card) == SD_RW_OK) { + return SD_INIT_READ_CSD; + } else { + TRACE("reading cid register failed!"); + return SD_INIT_CARD_UNKNOWN; + } + + case SD_INIT_READ_CSD: + TRACE("SD_INIT_READ_CSD"); + if (_read_csd(spi, card) == SD_RW_OK) { + if (card->csd_structure == SD_CSD_V1) { + TRACE("csd_structure is version 1"); + } else if (card->csd_structure == SD_CSD_V2) { + TRACE("csd_structure is version 2"); + } + return SD_INIT_SET_MAX_SPI_SPEED; + } else { + TRACE("reading csd register failed!"); + return SD_INIT_CARD_UNKNOWN; + } + + case SD_INIT_SET_MAX_SPI_SPEED: + TRACE("SD_INIT_SET_MAX_SPI_SPEED"); + stm32_spi_set_max_baudrate(spi, SD_SPI_CLK_MAX); + TRACE("SD_INIT_SET_MAX_SPI_SPEED: [OK]"); + return SD_INIT_FINISH; + + default: + TRACE("SD-INIT-FSM REACHED INVALID STATE!"); + return SD_INIT_CARD_UNKNOWN; + } +} + +int sdcard_spi_init(const stm32_spi_t* spi, sdcard_info_t* card) +{ + sd_init_fsm_state_t state = SD_INIT_START; + + do { + state = _init_sd_fsm_step(spi, card, state); + } while (state != SD_INIT_FINISH); + + if (card->card_type != SD_UNKNOWN) { + _sdcard_spi.spi = spi; + _sdcard_spi.use_block_addr = card->use_block_addr; + return SDCARD_SPI_OK; + } + + TRACE("sdcard_spi_init: [FAILED]"); + return SDCARD_SPI_INIT_ERROR; +} + +static sd_rw_response_t _read_data_packet(const stm32_spi_t* spi, uint8_t token, + uint8_t *data, uint16_t size) +{ + if (!_wait_for_token(spi, token, SD_DATA_TOKEN_RETRY_US)) { + return SD_RW_NO_TOKEN; + } + + if (stm32_spi_dma_receive_bytes(spi, data, size) == size) { + + uint8_t crc_bytes[2]; + if (_transfer_bytes(spi, 0, crc_bytes, sizeof(crc_bytes)) == sizeof(crc_bytes)) { + +#if defined(SD_CARD_SPI_ENABLE_CRC) + uint16_t data_crc16 = (crc_bytes[0] << 8) | crc_bytes[1]; + if (crc16(CRC_1021, data, size) != data_crc16) { + return SD_RW_CRC_MISMATCH; + } +#endif + return SD_RW_OK; + } + + return SD_RW_RX_TX_ERROR; + } + + return SD_RW_RX_TX_ERROR; +} + +static uint16_t _read_blocks(const sdcard_spi_t* card, uint8_t cmd_idx, + uint32_t bladdr, uint8_t* data, + uint16_t blsz, uint16_t nbl, + sd_rw_response_t* state) +{ + const auto* spi = card->spi; + stm32_spi_select(spi); + uint16_t reads = 0; + + uint32_t addr = card->use_block_addr ? bladdr : (bladdr * SD_HC_BLOCK_SIZE); + uint8_t cmd_r1_resu = sdcard_spi_send_cmd(spi, cmd_idx, addr, SD_BLOCK_READ_CMD_RETRY_US); + + if (R1_VALID(cmd_r1_resu) && !R1_ERROR(cmd_r1_resu)) { + + for (uint16_t i = 0; i < nbl; i++) { + *state = _read_data_packet(spi, SD_DATA_TOKEN_CMD_17_18_24, &(data[i * blsz]), blsz); + if (*state != SD_RW_OK) { break; } + reads++; + } + + /* if this was a multi-block read */ + if (cmd_idx == SD_CMD_18) { + cmd_r1_resu = sdcard_spi_send_cmd(spi, SD_CMD_12, 0, 1); + if (!R1_VALID(cmd_r1_resu) || R1_ERROR(cmd_r1_resu)) { + *state = SD_RW_RX_TX_ERROR; + } + } + } + else { + TRACE("_read_blocks: send CMD%d: [RX_TX_ERROR]", cmd_idx); + *state = SD_RW_RX_TX_ERROR; + } + + stm32_spi_unselect(spi); + _send_dummy_byte(spi); + // TODO: delay 100us? + delay_us(100); + + return reads; +} + +int sdcard_spi_read_blocks(uint32_t blockaddr, uint8_t* data, + uint16_t blocksize, uint16_t nblocks, + sd_rw_response_t* state) +{ + *state = SD_RW_OK; + if (nblocks > 1) { + return _read_blocks(&_sdcard_spi, SD_CMD_18, blockaddr, data, blocksize, + nblocks, state); + } else { + return _read_blocks(&_sdcard_spi, SD_CMD_17, blockaddr, data, blocksize, + nblocks, state); + } +} + +static sd_rw_response_t _write_data_packet(const stm32_spi_t* spi, uint8_t token, + const uint8_t *data, uint16_t size) +{ + if (!_wait_for_not_busy(spi, SD_WAIT_FOR_NOT_BUSY_US)) { + return SD_RW_TIMEOUT; + } + + stm32_spi_transfer_byte(spi, token); + + if (stm32_spi_dma_transmit_bytes(spi, data, size) != size) { + TRACE("_write_data_packet: [RX_TX_ERROR] (while transmitting payload)"); + return SD_RW_RX_TX_ERROR; + } + +#if defined(SD_CARD_SPI_ENABLE_CRC) + uint16_t data_crc16 = crc16(CRC_1021, data, size); + uint8_t crc[sizeof(uint16_t)] = { + (uint8_t)(data_crc16 >> 8), + (uint8_t)(data_crc16 & 0xFF) + }; +#else + uint8_t crc[sizeof(uint16_t)] = { 0xFF, 0xFF }; +#endif + + if (_transfer_bytes(spi, crc, 0, sizeof(crc)) != sizeof(crc)) { + TRACE("_write_data_packet: [RX_TX_ERROR] (while transmitting CRC16)"); + return SD_RW_RX_TX_ERROR; + } + + uint32_t timeout = timersGetUsTick(); + + do { + uint8_t data_response = stm32_spi_transfer_byte(spi, SD_CARD_DUMMY_BYTE); + if (data_response == 0xFF) continue; + + if (!DATA_RESPONSE_IS_VALID(data_response)) { + return SD_RW_RX_TX_ERROR; + } + + if (DATA_RESPONSE_ACCEPTED(data_response)) { + return SD_RW_OK; + } + + if (DATA_RESPONSE_WRITE_ERR(data_response) || + DATA_RESPONSE_CRC_ERR(data_response)) { + break; + } + + } while(timersGetUsTick() - timeout < 10 * US_PER_MS); + + return SD_RW_WRITE_ERROR; +} + +static uint16_t _write_blocks(const sdcard_spi_t* card, uint8_t cmd_idx, + uint32_t bladdr, const uint8_t *data, + uint16_t blsz, uint16_t nbl, + sd_rw_response_t *state) +{ + const auto* spi = card->spi; + stm32_spi_select(spi); + uint16_t written = 0; + + uint8_t token; + if (cmd_idx == SD_CMD_25) { + token = SD_DATA_TOKEN_CMD_25; + sdcard_spi_send_acmd(spi, SD_CMD_23, nbl, SD_BLOCK_WRITE_CMD_RETRY_US); + } else { + token = SD_DATA_TOKEN_CMD_17_18_24; + } + + uint32_t addr = card->use_block_addr ? bladdr : (bladdr * SD_HC_BLOCK_SIZE); + uint8_t cmd_r1_resu = sdcard_spi_send_cmd(spi, cmd_idx, addr, SD_BLOCK_WRITE_CMD_RETRY_US); + + if (R1_VALID(cmd_r1_resu) && !R1_ERROR(cmd_r1_resu)) { + + for (uint16_t i = 0; i < nbl; i++) { + *state = _write_data_packet(spi, token, &(data[i * blsz]), blsz); + if (*state != SD_RW_OK) { + break; + } + written++; + } + + /* if this is a multi-block write it is needed to issue a stop + command */ + if (cmd_idx == SD_CMD_25) { + if (!_wait_for_not_busy(spi, SD_WAIT_FOR_NOT_BUSY_US)) { + *state = SD_RW_TIMEOUT; + } else { + stm32_spi_transfer_byte(spi, SD_DATA_TOKEN_CMD_25_STOP); + } + } + } + else { + *state = SD_RW_RX_TX_ERROR; + } + + stm32_spi_unselect(spi); + _send_dummy_byte(spi); + // TODO: delay 100us? + delay_us(100); + + return written; +} + +int sdcard_spi_write_blocks(uint32_t blockaddr, const uint8_t* data, + uint16_t blocksize, uint16_t nblocks, + sd_rw_response_t* state) +{ + *state = SD_RW_OK; + if (nblocks > 1) { + return _write_blocks(&_sdcard_spi, SD_CMD_25, blockaddr, data, blocksize, + nblocks, state); + } else { + return _write_blocks(&_sdcard_spi, SD_CMD_24, blockaddr, data, blocksize, + nblocks, state); + } +} + +int sdcard_spi_wait_for_not_busy() +{ + auto spi = _sdcard_spi.spi; + int res = -1; + + stm32_spi_select(spi); + if (_wait_for_not_busy(spi, SD_WAIT_FOR_NOT_BUSY_US)) { + res = 0; + } + stm32_spi_unselect(spi); + + return res; +} + +static sd_rw_response_t _read_cid(const stm32_spi_t* spi, sdcard_info_t* card) +{ + uint8_t cid_raw_data[SD_SIZE_OF_CID_AND_CSD_REG]; + sd_rw_response_t state; + + sdcard_spi_t card_spi = { spi, card->use_block_addr }; + int nbl = _read_blocks(&card_spi, SD_CMD_10, 0, cid_raw_data, SD_SIZE_OF_CID_AND_CSD_REG, + SD_BLOCKS_FOR_REG_READ, &state); + + uint8_t crc7 = _crc_7(&(cid_raw_data[0]), SD_SIZE_OF_CID_AND_CSD_REG - 1); + + if (nbl == SD_BLOCKS_FOR_REG_READ) { + if (crc7 == cid_raw_data[SD_SIZE_OF_CID_AND_CSD_REG - 1]) { + card->cid.MID = cid_raw_data[0]; + memcpy(&card->cid.OID[0], &cid_raw_data[1], SD_SIZE_OF_OID); + memcpy(&card->cid.PNM[0], &cid_raw_data[2], SD_SIZE_OF_PNM); + card->cid.PRV = cid_raw_data[8]; + memcpy((uint8_t *)&card->cid.PSN, &cid_raw_data[9], 4); + card->cid.MDT = (cid_raw_data[13] << 4) | cid_raw_data[14]; + card->cid.CID_CRC = cid_raw_data[15]; + TRACE("_read_cid: [OK]"); + return SD_RW_OK; + } + else { + TRACE("_read_cid: [SD_RW_CRC_MISMATCH] (data-crc: 0x%02x | calc-crc: 0x%02x)", + cid_raw_data[SD_SIZE_OF_CID_AND_CSD_REG - 1], crc7); + return SD_RW_CRC_MISMATCH; + } + } + return state; +} + +static sd_rw_response_t _read_csd(const stm32_spi_t* spi, sdcard_info_t* card) +{ + uint8_t c[SD_SIZE_OF_CID_AND_CSD_REG]; + sd_rw_response_t state; + + sdcard_spi_t card_spi = { spi, card->use_block_addr }; + int read_resu = _read_blocks(&card_spi, SD_CMD_9, 0, c, SD_SIZE_OF_CID_AND_CSD_REG, + SD_BLOCKS_FOR_REG_READ, &state); + + if (read_resu == SD_BLOCKS_FOR_REG_READ) { + if (_crc_7(c, SD_SIZE_OF_CID_AND_CSD_REG - 1) == c[SD_SIZE_OF_CID_AND_CSD_REG - 1]) { + if (SD_GET_CSD_STRUCTURE(c) == SD_CSD_V1) { + card->csd.v1.CSD_STRUCTURE = c[0] >> 6; + card->csd.v1.TAAC = c[1]; + card->csd.v1.NSAC = c[2]; + card->csd.v1.TRAN_SPEED = c[3]; + card->csd.v1.CCC = (c[4] << 4) | ((c[5] & 0xF0) >> 4); + card->csd.v1.READ_BL_LEN = (c[5] & 0x0F); + card->csd.v1.READ_BL_PARTIAL = (c[6] & (1 << 7)) >> 7; + card->csd.v1.WRITE_BLK_MISALIGN = (c[6] & (1 << 6)) >> 6; + card->csd.v1.READ_BLK_MISALIGN = (c[6] & (1 << 5)) >> 5; + card->csd.v1.DSR_IMP = (c[6] & (1 << 4)) >> 4; + card->csd.v1.C_SIZE = ((c[6] & 0x03) << 10) | (c[7] << 2) | (c[8] >> 6); + card->csd.v1.VDD_R_CURR_MIN = (c[8] & 0x38) >> 3; + card->csd.v1.VDD_R_CURR_MAX = (c[8] & 0x07); + card->csd.v1.VDD_W_CURR_MIN = (c[9] & 0xE0) >> 5; + card->csd.v1.VDD_W_CURR_MAX = (c[9] & 0x1C) >> 2; + card->csd.v1.C_SIZE_MULT = ((c[9] & 0x03) << 1) | (c[10] >> 7); + card->csd.v1.ERASE_BLK_EN = (c[10] & (1 << 6)) >> 6; + card->csd.v1.SECTOR_SIZE = ((c[10] & 0x3F) << 1) | (c[11] >> 7); + card->csd.v1.WP_GRP_SIZE = (c[11] & 0x7F); + card->csd.v1.WP_GRP_ENABLE = c[12] >> 7; + card->csd.v1.R2W_FACTOR = (c[12] & 0x1C) >> 2; + card->csd.v1.WRITE_BL_LEN = (c[12] & 0x03) << 2 | (c[13] >> 6); + card->csd.v1.WRITE_BL_PARTIAL = (c[13] & (1 << 5)) >> 5; + card->csd.v1.FILE_FORMAT_GRP = (c[14] & (1 << 7)) >> 7; + card->csd.v1.COPY = (c[14] & (1 << 6)) >> 6; + card->csd.v1.PERM_WRITE_PROTECT = (c[14] & (1 << 5)) >> 5; + card->csd.v1.TMP_WRITE_PROTECT = (c[14] & (1 << 4)) >> 4; + card->csd.v1.FILE_FORMAT = (c[14] & 0x0C) >> 2; + card->csd.v1.CSD_CRC = c[15]; + card->csd_structure = SD_CSD_V1; + return SD_RW_OK; + } else if (SD_GET_CSD_STRUCTURE(c) == SD_CSD_V2) { + card->csd.v2.CSD_STRUCTURE = c[0] >> 6; + card->csd.v2.TAAC = c[1]; + card->csd.v2.NSAC = c[2]; + card->csd.v2.TRAN_SPEED = c[3]; + card->csd.v2.CCC = (c[4] << 4) | ((c[5] & 0xF0) >> 4); + card->csd.v2.READ_BL_LEN = (c[5] & 0x0F); + card->csd.v2.READ_BL_PARTIAL = (c[6] & (1 << 7)) >> 7; + card->csd.v2.WRITE_BLK_MISALIGN = (c[6] & (1 << 6)) >> 6; + card->csd.v2.READ_BLK_MISALIGN = (c[6] & (1 << 5)) >> 5; + card->csd.v2.DSR_IMP = (c[6] & (1 << 4)) >> 4; + card->csd.v2.C_SIZE = (((uint32_t)c[7] & 0x3F) << 16) | (c[8] << 8) | c[9]; + card->csd.v2.ERASE_BLK_EN = (c[10] & (1 << 6)) >> 6; + card->csd.v2.SECTOR_SIZE = (c[10] & 0x3F) << 1 | (c[11] >> 7); + card->csd.v2.WP_GRP_SIZE = (c[11] & 0x7F); + card->csd.v2.WP_GRP_ENABLE = (c[12] & (1 << 7)) >> 7; + card->csd.v2.R2W_FACTOR = (c[12] & 0x1C) >> 2; + card->csd.v2.WRITE_BL_LEN = ((c[12] & 0x03) << 2) | (c[13] >> 6); + card->csd.v2.WRITE_BL_PARTIAL = (c[13] & (1 << 5)) >> 5; + card->csd.v2.FILE_FORMAT_GRP = (c[14] & (1 << 7)) >> 7; + card->csd.v2.COPY = (c[14] & (1 << 6)) >> 6; + card->csd.v2.PERM_WRITE_PROTECT = (c[14] & (1 << 5)) >> 5; + card->csd.v2.TMP_WRITE_PROTECT = (c[14] & (1 << 4)) >> 4; + card->csd.v2.FILE_FORMAT = (c[14] & 0x0C) >> 2; + card->csd.v2.CSD_CRC = c[15]; + card->csd_structure = SD_CSD_V2; + return SD_RW_OK; + } else { + return SD_RW_NOT_SUPPORTED; + } + + } else { + return SD_RW_CRC_MISMATCH; + } + } + return state; +} + +uint64_t sdcard_spi_get_capacity(sdcard_info_t *card) +{ + if (card->csd_structure == SD_CSD_V1) { + uint32_t block_len = (1 << card->csd.v1.READ_BL_LEN); + uint32_t mult = 1 << (card->csd.v1.C_SIZE_MULT + 2); + uint32_t blocknr = (card->csd.v1.C_SIZE + 1) * mult; + return blocknr * block_len; + } + else if (card->csd_structure == SD_CSD_V2) { + return (card->csd.v2.C_SIZE + 1) * (((uint64_t)SD_HC_BLOCK_SIZE) << 10); + } + return 0; +} + +uint32_t sdcard_spi_get_sector_count(sdcard_info_t *card) +{ + return sdcard_spi_get_capacity(card) / SD_HC_BLOCK_SIZE; +} diff --git a/radio/src/targets/common/arm/stm32/sdcard_spi.h b/radio/src/targets/common/arm/stm32/sdcard_spi.h new file mode 100644 index 00000000000..2d60ba99a5f --- /dev/null +++ b/radio/src/targets/common/arm/stm32/sdcard_spi.h @@ -0,0 +1,291 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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. + */ + +#pragma once + +#include "stm32_spi.h" +#include + + +/* R1 response bits (see sd spec. 7.3.2.1 Format R1) */ +#define SD_R1_RESPONSE_PARAM_ERROR (1<<6) +#define SD_R1_RESPONSE_ADDR_ERROR (1<<5) +#define SD_R1_RESPONSE_ERASE_SEQ_ERROR (1<<4) +#define SD_R1_RESPONSE_CMD_CRC_ERROR (1<<3) +#define SD_R1_RESPONSE_ILLEGAL_CMD_ERROR (1<<2) +#define SD_R1_RESPONSE_ERASE_RESET (1<<1) +#define SD_R1_RESPONSE_IN_IDLE_STATE (0x01) +#define SD_INVALID_R1_RESPONSE (1<<7) + +#define R1_VALID(X) (((X) >> 7) == 0) +#define R1_PARAM_ERR(X) ((((X) &SD_R1_RESPONSE_PARAM_ERROR) != 0)) +#define R1_ADDR_ERR(X) ((((X) &SD_R1_RESPONSE_ADDR_ERROR) != 0)) +#define R1_ERASE_ERR(X) ((((X) &SD_R1_RESPONSE_ERASE_SEQ_ERROR) != 0)) +#define R1_CMD_CRC_ERR(X) ((((X) &SD_R1_RESPONSE_CMD_CRC_ERROR) != 0)) +#define R1_ILL_CMD_ERR(X) ((((X) &SD_R1_RESPONSE_ILLEGAL_CMD_ERROR) != 0)) +#define R1_IDLE_BIT_SET(X) (((X) &SD_R1_RESPONSE_IN_IDLE_STATE) != 0) +#define R1_ERROR(X) (R1_PARAM_ERR(X) || R1_ADDR_ERR(X) || R1_ERASE_ERR(X) || \ + R1_CMD_CRC_ERR(X) || R1_ILL_CMD_ERR(X)) + +/* see sd spec. 7.3.3.1 Data Response Token */ +#define DATA_RESPONSE_IS_VALID(X) (((X) & 0x11) == 0x01) +#define DATA_RESPONSE_ACCEPTED(X) (((X) & 0x0E) == 0x04) +#define DATA_RESPONSE_CRC_ERR(X) (((X) & 0x0E) == 0x0A) +#define DATA_RESPONSE_WRITE_ERR(X) (((X) & 0x0E) == 0x0C) + +/* see sd spec. 5.1 OCR register */ +#define OCR_VOLTAGE_3_2_TO_3_3 (1L << 20) +#define OCR_VOLTAGE_3_3_TO_3_4 (1L << 21) + +/* card capacity status (CCS=0: the card is SDSD; CCS=1: card is SDHC or SDXC) */ +#define OCR_CCS (1L << 30) + +/* This bit is set to low if the card has not finished power up routine */ +#define OCR_POWER_UP_STATUS (1L << 31) + +/* to ensure the voltage range check on init is done properly you need to + define this according to your actual interface/wiring with the sd-card */ +#define SYSTEM_VOLTAGE (OCR_VOLTAGE_3_2_TO_3_3 | OCR_VOLTAGE_3_2_TO_3_3) + +/* see sd spec. 7.3.1.3 Detailed Command Description */ +#define SD_CMD_PREFIX_MASK (1<<6) + +#define SD_CMD_0 0 /* Resets the SD Memory Card */ +#define SD_CMD_1 1 /* Sends host capacity support info and starts the cards init process */ +#define SD_CMD_8 8 /* Sends SD Card interface condition incl. host supply voltage info */ +#define SD_CMD_9 9 /* Asks the selected card to send its card-specific data (CSD) */ +#define SD_CMD_10 10 /* Asks the selected card to send its card identification (CID) */ +#define SD_CMD_12 12 /* Forces the card to stop transmission in Multiple Block Read Operation */ +#define SD_CMD_13 13 /* Sent as ACMD13 asks the card to send it's SD status */ + +#define SD_CMD_16 16 /* In case of SDSC Card, block length is set by this command */ +#define SD_CMD_17 17 /* Reads a block of the size selected by the SET_BLOCKLEN command */ +#define SD_CMD_18 18 /* Continuously transfers data blocks from card to host + until interrupted by a STOP_TRANSMISSION command */ +#define SD_CMD_23 23 /* Used for ACMD23: write block erase count */ +#define SD_CMD_24 24 /* Writes a block of the size selected by the SET_BLOCKLEN command */ +#define SD_CMD_25 25 /* Continuously writes blocks of data until 'Stop Tran'token is sent */ +#define SD_CMD_41 41 /* Reserved (used for ACMD41) */ +#define SD_CMD_55 55 /* Defines to the card that the next command is an application specific + command rather than a standard command */ +#define SD_CMD_58 58 /* Reads the OCR register of a card */ +#define SD_CMD_59 59 /* Turns the CRC option on or off. Argument: 1:on; 0:off */ + +#define SD_CMD_8_VHS_2_7_V_TO_3_6_V 0x01 +#define SD_CMD_8_CHECK_PATTERN 0xB5 +#define SD_CMD_NO_ARG 0x00000000 +#define SD_ACMD_41_ARG_HC 0x40000000 +#define SD_CMD_59_ARG_EN 0x00000001 +#define SD_CMD_59_ARG_DIS 0x00000000 + +/* see sd spec. 7.3.3 Control Tokens */ +#define SD_DATA_TOKEN_CMD_17_18_24 0xFE +#define SD_DATA_TOKEN_CMD_25 0xFC +#define SD_DATA_TOKEN_CMD_25_STOP 0xFD + +#define SD_SIZE_OF_CID_AND_CSD_REG 16 +#define SD_SIZE_OF_SD_STATUS 64 +#define SD_BLOCKS_FOR_REG_READ 1 +#define SD_GET_CSD_STRUCTURE(CSD_RAW_DATA) ((CSD_RAW_DATA)[0] >> 6) +#define SD_CSD_V1 0 +#define SD_CSD_V2 1 +#define SD_CSD_VUNSUPPORTED -1 + +#define SD_HC_BLOCK_SIZE (512) + +#define SDCARD_SPI_INIT_ERROR (-1) /* returned on failed init */ +#define SDCARD_SPI_OK (0) /* returned on successful init */ + +#define SD_SIZE_OF_OID 2 /* OID (OEM/application ID field in CID reg) */ +#define SD_SIZE_OF_PNM 5 /* PNM (product name field in CID reg) */ + +#define SD_SIZE_OF_CID_AND_CSD_REG 16 +#define SD_SIZE_OF_SD_STATUS 64 +#define SD_BLOCKS_FOR_REG_READ 1 +#define SD_GET_CSD_STRUCTURE(CSD_RAW_DATA) ((CSD_RAW_DATA)[0] >> 6) + +#define SD_CSD_V1 0 +#define SD_CSD_V2 1 +#define SD_CSD_VUNSUPPORTED -1 + +/** + * @brief CID register see section 5.2 in SD-Spec v5.00 + */ +typedef struct { + uint8_t MID; /**< Manufacturer ID */ + char OID[SD_SIZE_OF_OID]; /**< OEM/Application ID*/ + char PNM[SD_SIZE_OF_PNM]; /**< Product name */ + uint8_t PRV; /**< Product revision */ + uint32_t PSN; /**< Product serial number */ + uint16_t MDT; /**< Manufacturing date */ + uint8_t CID_CRC; /**< CRC7 checksum */ +} cid_t; + +/** + * @brief CSD register with csd structure version 1.0 + * see section 5.3.2 in SD-Spec v5.00 + */ +typedef struct { + uint8_t CSD_STRUCTURE : 2; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t TAAC : 8; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t NSAC : 8; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t TRAN_SPEED : 8; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint16_t CCC : 12; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t READ_BL_LEN : 4; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t READ_BL_PARTIAL : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t WRITE_BLK_MISALIGN : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t READ_BLK_MISALIGN : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t DSR_IMP : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint16_t C_SIZE : 12; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t VDD_R_CURR_MIN : 3; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t VDD_R_CURR_MAX : 3; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t VDD_W_CURR_MIN : 3; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t VDD_W_CURR_MAX : 3; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t C_SIZE_MULT : 3; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t ERASE_BLK_EN : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t SECTOR_SIZE : 7; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t WP_GRP_SIZE : 7; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t WP_GRP_ENABLE : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t R2W_FACTOR : 3; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t WRITE_BL_LEN : 4; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t WRITE_BL_PARTIAL : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t FILE_FORMAT_GRP : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t COPY : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t PERM_WRITE_PROTECT : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t TMP_WRITE_PROTECT : 1; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t FILE_FORMAT : 2; /**< see section 5.3.2 in SD-Spec v5.00 */ + uint8_t CSD_CRC : 8; /**< see section 5.3.2 in SD-Spec v5.00 */ +} csd_v1_t; + +/** + * @brief CSD register with csd structure version 2.0 + * see section 5.3.3 in SD-Spec v5.00 + */ +typedef struct { + uint8_t CSD_STRUCTURE : 2; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t TAAC : 8; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t NSAC : 8; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t TRAN_SPEED : 8; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint16_t CCC : 12; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t READ_BL_LEN : 4; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t READ_BL_PARTIAL : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t WRITE_BLK_MISALIGN : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t READ_BLK_MISALIGN : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t DSR_IMP : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint32_t C_SIZE : 22; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t ERASE_BLK_EN : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t SECTOR_SIZE : 7; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t WP_GRP_SIZE : 7; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t WP_GRP_ENABLE : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t R2W_FACTOR : 3; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t WRITE_BL_LEN : 4; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t WRITE_BL_PARTIAL : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t FILE_FORMAT_GRP : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t COPY : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t PERM_WRITE_PROTECT : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t TMP_WRITE_PROTECT : 1; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t FILE_FORMAT : 2; /**< see section 5.3.3 in SD-Spec v5.00 */ + uint8_t CSD_CRC : 8; /**< see section 5.3.3 in SD-Spec v5.00 */ +} csd_v2_t; + +/** + * @brief CSD register (see section 5.3 in SD-Spec v5.00) + */ +typedef union { + csd_v1_t v1; /**< see section 5.3.2 in SD-Spec v5.00 */ + csd_v2_t v2; /**< see section 5.3.3 in SD-Spec v5.00 */ +} csd_t; + +/** + * @brief SD status register (see section 4.10.2 in SD-Spec v5.00) + */ +typedef struct { + uint32_t SIZE_OF_PROTECTED_AREA : 32; /**< see section 4.10.2 in SD-Spec v5.00 */ + uint32_t SUS_ADDR : 22; /**< see section 4.10.2.12 in SD-Spec v5.00 */ + uint32_t VSC_AU_SIZE : 10; /**< see section 4.10.2.11 in SD-Spec v5.00 */ + uint16_t SD_CARD_TYPE : 16; /**< see section 4.10.2 in SD-Spec v5.00 */ + uint16_t ERASE_SIZE : 16; /**< see section 4.10.2.5 in SD-Spec v5.00 */ + uint8_t SPEED_CLASS : 8; /**< see section 4.10.2.2 in SD-Spec v5.00 */ + uint8_t PERFORMANCE_MOVE : 8; /**< see section 4.10.2.3 in SD-Spec v5.00 */ + uint8_t VIDEO_SPEED_CLASS : 8; /**< see section 4.10.2.10 in SD-Spec v5.00 */ + uint8_t ERASE_TIMEOUT : 6; /**< see section 4.10.2.6 in SD-Spec v5.00 */ + uint8_t ERASE_OFFSET : 2; /**< see section 4.10.2.7 in SD-Spec v5.00 */ + uint8_t UHS_SPEED_GRADE : 4; /**< see section 4.10.2.8 in SD-Spec v5.00 */ + uint8_t UHS_AU_SIZE : 4; /**< see section 4.10.2.9 in SD-Spec v5.00 */ + uint8_t AU_SIZE : 4; /**< see section 4.10.2.4 in SD-Spec v5.00 */ + uint8_t DAT_BUS_WIDTH : 2; /**< see section 4.10.2 in SD-Spec v5.00 */ + uint8_t SECURED_MODE : 1; /**< see section 4.10.2 in SD-Spec v5.00 */ +} sd_status_t; + +/** + * @brief version type of SD-card + */ +typedef enum { + SD_V2, /**< SD version 2 */ + SD_V1, /**< SD version 1 */ + MMC_V3, /**< MMC version 3 */ + SD_UNKNOWN /**< SD-version unknown */ +} sd_version_t; + +/** + * @brief sdcard info + */ +typedef struct { + sd_version_t card_type; + cid_t cid; + csd_t csd; + int csd_structure; + bool use_block_addr; +} sdcard_info_t; + +typedef struct { + const stm32_spi_t* spi; + bool use_block_addr; +} sdcard_spi_t; + +/** + * @brief sdcard_spi r/w-operation return values + */ +typedef enum { + SD_RW_OK = 0, /**< no error */ + SD_RW_NO_TOKEN, /**< no token was received (on block read) */ + SD_RW_TIMEOUT, /**< cmd timed out (not-busy-state wasn't entered) */ + SD_RW_RX_TX_ERROR, /**< error while performing SPI read/write */ + SD_RW_WRITE_ERROR, /**< data-packet response indicates error */ + SD_RW_CRC_MISMATCH, /**< CRC-mismatch of received data */ + SD_RW_NOT_SUPPORTED /**< operation not supported on used card */ +} sd_rw_response_t; + +int sdcard_spi_init(const stm32_spi_t* spi, sdcard_info_t* card); + +uint64_t sdcard_spi_get_capacity(sdcard_info_t* card); + +uint32_t sdcard_spi_get_sector_count(sdcard_info_t* card); + +int sdcard_spi_read_blocks(uint32_t blockaddr, uint8_t* data, + uint16_t blocksize, uint16_t nblocks, + sd_rw_response_t* state); + +int sdcard_spi_write_blocks(uint32_t blockaddr, const uint8_t* data, + uint16_t blocksize, uint16_t nblocks, + sd_rw_response_t* state); + +int sdcard_spi_wait_for_not_busy(); diff --git a/radio/src/targets/common/arm/stm32/sdio_sd.cpp b/radio/src/targets/common/arm/stm32/sdio_sd.cpp deleted file mode 100644 index 547e21ce527..00000000000 --- a/radio/src/targets/common/arm/stm32/sdio_sd.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * 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 "sdio_sd.h" -#include "stm32_dma.h" -#include "stm32_gpio_driver.h" - -#include "stm32_hal_ll.h" -#include "stm32_hal.h" - -#include "hal.h" - -#include "delays_driver.h" -#include "debug.h" - -/* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */ -#if !defined(SD_SDIO_DATA_GPIO) && !defined(SD_SDIO_DATA_GPIO_PINS) -#define SD_SDIO_DATA_GPIO GPIOC -#define SD_SDIO_DATA_GPIO_PINS \ - (LL_GPIO_PIN_8 | LL_GPIO_PIN_9 | LL_GPIO_PIN_10 | LL_GPIO_PIN_11) -#endif - -/* Configure PD.02 CMD line */ -#if !defined(SD_SDIO_CMD_GPIO) && !defined(SD_SDIO_CMD_GPIO_PIN) -#define SD_SDIO_CMD_GPIO GPIOD -#define SD_SDIO_CMD_GPIO_PIN LL_GPIO_PIN_2 -#endif - -#if !defined(SD_SDIO_CLK_GPIO) && !defined(SD_SDIO_CLK_GPIO_PIN) -#define SD_SDIO_CLK_GPIO GPIOC -#define SD_SDIO_CLK_GPIO_PIN LL_GPIO_PIN_12 -#endif - -static SD_HandleTypeDef sdio; -static DMA_HandleTypeDef sdioTxDma; - -// Disk status -volatile uint32_t WriteStatus = 0; -volatile uint32_t ReadStatus = 0; - -static void SD_LowLevel_Init(void) -{ - /* Enable the SDIO APB2 Clock */ - __HAL_RCC_SDIO_CLK_ENABLE(); - - LL_GPIO_InitTypeDef GPIO_InitStructure; - LL_GPIO_StructInit(&GPIO_InitStructure); - - stm32_gpio_enable_clock(SD_SDIO_DATA_GPIO); - stm32_gpio_enable_clock(SD_SDIO_CMD_GPIO); - stm32_gpio_enable_clock(SD_SDIO_CLK_GPIO); - - GPIO_InitStructure.Pin = SD_SDIO_DATA_GPIO_PINS; - GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStructure.Mode = LL_GPIO_MODE_ALTERNATE; - GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL; - GPIO_InitStructure.Pull = LL_GPIO_PULL_UP; - GPIO_InitStructure.Alternate = LL_GPIO_AF_12; // SDIO - LL_GPIO_Init(SD_SDIO_DATA_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.Pin = SD_SDIO_CMD_GPIO_PIN; - LL_GPIO_Init(SD_SDIO_CMD_GPIO, &GPIO_InitStructure); - - /* Configure PC.12 pin: CLK pin */ - GPIO_InitStructure.Pin = SD_SDIO_CLK_GPIO_PIN; - GPIO_InitStructure.Pull = LL_GPIO_PULL_NO; - LL_GPIO_Init(SD_SDIO_CLK_GPIO, &GPIO_InitStructure); - - // SDIO Interrupt ENABLE - NVIC_SetPriority(SDIO_IRQn, 0); - NVIC_EnableIRQ(SDIO_IRQn); - - // Init SDIO DMA instance - sdioTxDma.Instance = SD_SDIO_DMA_STREAM; - sdioTxDma.Init.Channel = SD_SDIO_DMA_CHANNEL; - sdioTxDma.Init.PeriphInc = DMA_PINC_DISABLE; - sdioTxDma.Init.MemInc = DMA_MINC_ENABLE; - sdioTxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; - sdioTxDma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; - sdioTxDma.Init.Mode = DMA_PFCTRL; - sdioTxDma.Init.Priority = DMA_PRIORITY_VERY_HIGH; - sdioTxDma.Init.FIFOMode = DMA_FIFOMODE_ENABLE; - sdioTxDma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - sdioTxDma.Init.MemBurst = DMA_MBURST_INC4; - sdioTxDma.Init.PeriphBurst = DMA_PBURST_INC4; - - stm32_dma_enable_clock(SD_SDIO_DMA); - HAL_DMA_Init(&sdioTxDma); - - __HAL_LINKDMA(&sdio, hdmatx, sdioTxDma); - __HAL_LINKDMA(&sdio, hdmarx, sdioTxDma); - - // DMA2 STREAMx Interrupt ENABLE - NVIC_SetPriority(SD_SDIO_DMA_IRQn, 0); - NVIC_EnableIRQ(SD_SDIO_DMA_IRQn); -} - -SD_Error SD_Init(void) -{ - static bool _sdio_init = false; - - if(_sdio_init) return SD_OK; - _sdio_init = true; - - __IO SD_Error errorstatus = SD_OK; - - /* SDIO Peripheral Low Level Init */ - SD_LowLevel_Init(); - - /*!< Configure the SDIO peripheral */ - /*!< SDIO_CK = SDIOCLK / (SDIO_TRANSFER_CLK_DIV + 2) */ - /*!< on STM32F4xx devices, SDIOCLK is fixed to 48MHz */ - sdio.Instance = SDIO; - sdio.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; - sdio.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; - sdio.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; - sdio.Init.BusWide = SDIO_BUS_WIDE_1B; - sdio.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; - sdio.Init.ClockDiv = SD_SDIO_TRANSFER_CLK_DIV; - HAL_SD_DeInit(&sdio); - - HAL_StatusTypeDef halStatus = HAL_SD_Init(&sdio); - if (halStatus != HAL_OK) { - TRACE("SD_PowerON() status=%d", halStatus); - /*!< CMD Response TimeOut (wait for CMDSENT flag) */ - return SD_ERROR; - } - - HAL_SD_CardInfoTypeDef cardInfo; - HAL_StatusTypeDef es = HAL_SD_GetCardInfo(&sdio, &cardInfo); - if(es != HAL_OK) - return SD_ERROR; - - HAL_SD_ConfigWideBusOperation(&sdio, SDIO_BUS_WIDE_4B); - - return errorstatus; -} - -/** - * @brief Gets the cuurent sd card data transfer status. - * @param None - * @retval SDTransferState: Data Transfer state. - * This value can be: - * - SD_TRANSFER_OK: No data transfer is acting - * - SD_TRANSFER_BUSY: Data transfer is acting - */ -SDTransferState SD_GetStatus(void) -{ - HAL_SD_CardStateTypeDef cardstate = HAL_SD_GetCardState(&sdio); - - if (cardstate == HAL_SD_CARD_TRANSFER) { - return SD_TRANSFER_OK; - } - else if (cardstate == HAL_SD_CARD_ERROR) { - return SD_TRANSFER_ERROR; - } - - return SD_TRANSFER_BUSY; -} - -int SD_CheckStatusWithTimeout(uint32_t timeout) -{ - uint32_t timer = HAL_GetTick(); - /* block until SDIO IP is ready again or a timeout occur */ - while(HAL_GetTick() - timer < timeout) { - auto state = SD_GetStatus(); - if (state != SD_TRANSFER_BUSY) { - return state == SD_TRANSFER_OK ? 0 : -1; - } - } - - return -1; -} - -/** - * @brief Detect if SD card is correctly plugged in the memory slot. - * @param None - * @retval Return if SD is detected or not - */ -uint8_t SD_Detect(void) -{ - __IO uint8_t status = SD_PRESENT; - - /*!< Check GPIO to detect SD */ - if ((LL_GPIO_ReadInputPort(SD_PRESENT_GPIO) & SD_PRESENT_LL_GPIO_PIN) != 0) { - status = SD_NOT_PRESENT; - } - - return status; -} - -/** - * @brief Returns information about specific card. - * @param cardinfo: pointer to a SD_CardInfo structure that contains all SD card - * information. - * @retval SD_Error: SD Card Error code. - */ -SD_Error SD_GetCardInfo(HAL_SD_CardInfoTypeDef *cardinfo) -{ - if(HAL_SD_GetCardInfo(&sdio, cardinfo) != HAL_OK) - return SD_ERROR; - - return SD_OK; -} - -/** - * @brief Allows to read blocks from a specified address in a card. The Data - * transfer can be managed by DMA mode or Polling mode. - * @note This operation should be followed by two functions to check if the - * DMA Controller and SD Card status. - * - SD_ReadWaitOperation(): this function insure that the DMA - * controller has finished all data transfer. - * - SD_GetStatus(): to check that the SD Card has finished the - * data transfer and it is ready for data. - * @param readbuff: pointer to the buffer that will contain the received data. - * @param ReadAddr: Address from where data are to be read. - * @param BlockSize: the SD card Data block size. The Block size should be 512. - * @param NumberOfBlocks: number of blocks to be read. - * @retval SD_Error: SD Card Error code. - */ -SD_Error SD_ReadBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks) -{ - HAL_StatusTypeDef res = HAL_SD_ReadBlocks_DMA(&sdio, readbuff, ReadAddr, NumberOfBlocks); - if(res == HAL_OK) - return SD_OK; - - return SD_ERROR; -} - -// /** -// * @brief This function waits until the SDIO DMA data transfer is finished. -// * This function should be called after SDIO_ReadMultiBlocks() function -// * to insure that all data sent by the card are already transferred by -// * the DMA controller. -// * @param None. -// * @retval SD_Error: SD Card Error code. -// */ -// SD_Error SD_WaitReadOperation(uint32_t timeout) -// { -// volatile HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(&sdio); -// if(state == HAL_SD_CARD_READY || state == HAL_SD_CARD_TRANSFER) -// return SD_OK; -// timeout = 100; - -// while((HAL_SD_GetCardState(&sdio) == HAL_SD_CARD_SENDING) && (timeout > 0)) { -// delay_ms(1); -// timeout--; -// } - -// state = HAL_SD_GetCardState(&sdio); -// if(timeout > 0 && state == HAL_SD_CARD_TRANSFER) -// return SD_OK; - -// return SD_ERROR; -// } - -/** - * @brief Allows to write blocks starting from a specified address in a card. - * The Data transfer can be managed by DMA mode only. - * @note This operation should be followed by two functions to check if the - * DMA Controller and SD Card status. - * - SD_ReadWaitOperation(): this function insure that the DMA - * controller has finished all data transfer. - * - SD_GetStatus(): to check that the SD Card has finished the - * data transfer and it is ready for data. - * @param WriteAddr: Address from where data are to be read. - * @param writebuff: pointer to the buffer that contain the data to be transferred. - * @param BlockSize: the SD card Data block size. The Block size should be 512. - * @param NumberOfBlocks: number of blocks to be written. - * @retval SD_Error: SD Card Error code. - */ -SD_Error SD_WriteBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks) -{ - HAL_StatusTypeDef res = HAL_SD_WriteBlocks_DMA(&sdio, writebuff, WriteAddr, NumberOfBlocks); - if(res == HAL_OK) - return SD_OK; - return SD_ERROR; -} - -// /** -// * @brief This function waits until the SDIO DMA data transfer is finished. -// * This function should be called after SDIO_WriteBlock() and -// * SDIO_WriteMultiBlocks() function to insure that all data sent by the -// * card are already transferred by the DMA controller. -// * @param None. -// * @retval SD_Error: SD Card Error code. -// */ -// OPTIMIZE("O0") SD_Error SD_WaitWriteOperation(uint32_t timeout) -// { -// HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(&sdio); -// if(state == HAL_SD_CARD_READY || state == HAL_SD_CARD_TRANSFER) -// return SD_OK; - -// timeout = 1000; - -// state = HAL_SD_GetCardState(&sdio); -// while((state == HAL_SD_CARD_RECEIVING || state == HAL_SD_CARD_PROGRAMMING) && (timeout > 0)) { -// delay_ms(1); -// timeout--; -// state = HAL_SD_GetCardState(&sdio); -// } - -// state = HAL_SD_GetCardState(&sdio); -// if(timeout > 0 && state == HAL_SD_CARD_TRANSFER) -// return SD_OK; - -// return SD_ERROR; -// } - -uint32_t SD_GetSectorCount() -{ - HAL_SD_CardInfoTypeDef cardInfo; - - if(SD_GetCardInfo(&cardInfo) != SD_OK) - return 0; - - return cardInfo.LogBlockNbr; -} - -uint32_t SD_GetSectorSize() -{ - HAL_SD_CardInfoTypeDef cardInfo; - - if(SD_GetCardInfo(&cardInfo) != SD_OK) - return 0; - - return cardInfo.LogBlockSize; -} - -uint32_t SD_GetBlockSize() -{ - HAL_SD_CardInfoTypeDef cardInfo; - - if(SD_GetCardInfo(&cardInfo) != SD_OK) - return 0; - - return cardInfo.LogBlockSize; -} - -uint32_t SD_GetCardType() -{ - HAL_SD_CardInfoTypeDef cardInfo; - - if(SD_GetCardInfo(&cardInfo) != SD_OK) - return 0; - - return cardInfo.CardType; -} - -uint32_t SD_GetCardVersion() -{ - HAL_SD_CardInfoTypeDef cardInfo; - - if(SD_GetCardInfo(&cardInfo) != SD_OK) - return 0; - - return cardInfo.CardVersion; -} - -uint32_t SD_GetCardClass() -{ - HAL_SD_CardInfoTypeDef cardInfo; - - if(SD_GetCardInfo(&cardInfo) != SD_OK) - return 0; - - return cardInfo.Class; -} - -/** -* @brief Tx Transfer completed callbacks -* @param hsd: SD handle -* @retval None -*/ - -extern "C" void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) -{ - UNUSED(hsd); - WriteStatus = 1; -} - -/** -* @brief Rx Transfer completed callbacks -* @param hsd: SD handle -* @retval None -*/ - -extern "C" void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) -{ - UNUSED(hsd); - ReadStatus = 1; -} - -extern "C" void SDIO_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_SDIO); - HAL_SD_IRQHandler(&sdio); -} -extern "C" void SD_SDIO_DMA_IRQHANDLER(void) -{ - DEBUG_INTERRUPT(INT_SDIO_DMA); - HAL_DMA_IRQHandler(&sdioTxDma); -} diff --git a/radio/src/targets/common/arm/stm32/sdio_sd.h b/radio/src/targets/common/arm/stm32/sdio_sd.h deleted file mode 100644 index 7e87224efc1..00000000000 --- a/radio/src/targets/common/arm/stm32/sdio_sd.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * 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. - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef _SDIO_SD_H_ -#define _SDIO_SD_H_ - -#include - -/* Includes ------------------------------------------------------------------*/ -typedef enum -{ - SD_ERROR, - SD_OK = 0 -} SD_Error; - -/** - * @brief SDIO Transfer state - */ -typedef enum -{ - SD_TRANSFER_OK = 0, - SD_TRANSFER_BUSY = 1, - SD_TRANSFER_ERROR -} SDTransferState; - -/** - * @brief SD detection on its memory slot - */ -#define SD_PRESENT ((uint8_t)0x01) -#define SD_NOT_PRESENT ((uint8_t)0x00) - -SD_Error SD_Init(void); -SDTransferState SD_GetStatus(void); -int SD_CheckStatusWithTimeout(uint32_t timeout); -uint8_t SD_Detect(void); -SD_Error SD_PowerOFF(void); -SD_Error SD_ReadBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks); -SD_Error SD_WriteBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks); -SDTransferState SD_GetTransferState(void); -SD_Error SD_WaitReadOperation(uint32_t timeout); -SD_Error SD_WaitWriteOperation(uint32_t timeout); - -uint32_t SD_GetSectorCount(); -uint32_t SD_GetSectorSize(); -uint32_t SD_GetBlockSize(); -uint32_t SD_GetCardType(); -uint32_t SD_GetCardVersion(); -uint32_t SD_GetCardClass(); - -#endif // _SDIO_SD_H_ - diff --git a/radio/src/targets/common/arm/stm32/stm32_dma.h b/radio/src/targets/common/arm/stm32/stm32_dma.h index 9a1af355932..e40ad5a4ae3 100644 --- a/radio/src/targets/common/arm/stm32/stm32_dma.h +++ b/radio/src/targets/common/arm/stm32/stm32_dma.h @@ -27,10 +27,26 @@ inline static bool stm32_dma_check_tc_flag(DMA_TypeDef* DMAx, uint32_t DMA_Stream) { switch(DMA_Stream) { + case LL_DMA_STREAM_0: + if (!LL_DMA_IsActiveFlag_TC0(DMAx)) return false; + LL_DMA_ClearFlag_TC0(DMAx); + break; case LL_DMA_STREAM_1: if (!LL_DMA_IsActiveFlag_TC1(DMAx)) return false; LL_DMA_ClearFlag_TC1(DMAx); break; + case LL_DMA_STREAM_2: + if (!LL_DMA_IsActiveFlag_TC2(DMAx)) return false; + LL_DMA_ClearFlag_TC2(DMAx); + break; + case LL_DMA_STREAM_3: + if (!LL_DMA_IsActiveFlag_TC3(DMAx)) return false; + LL_DMA_ClearFlag_TC3(DMAx); + break; + case LL_DMA_STREAM_4: + if (!LL_DMA_IsActiveFlag_TC4(DMAx)) return false; + LL_DMA_ClearFlag_TC4(DMAx); + break; case LL_DMA_STREAM_5: if (!LL_DMA_IsActiveFlag_TC5(DMAx)) return false; LL_DMA_ClearFlag_TC5(DMAx); diff --git a/radio/src/targets/common/arm/stm32/stm32_hal_ll.h b/radio/src/targets/common/arm/stm32/stm32_hal_ll.h index 15ca88669cf..526318d29ce 100644 --- a/radio/src/targets/common/arm/stm32/stm32_hal_ll.h +++ b/radio/src/targets/common/arm/stm32/stm32_hal_ll.h @@ -49,6 +49,7 @@ extern "C" { #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_system.h" #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_rcc.h" #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_adc.h" + #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_spi.h" #endif #if defined(__cplusplus) diff --git a/radio/src/targets/common/arm/stm32/stm32_spi.cpp b/radio/src/targets/common/arm/stm32/stm32_spi.cpp index 711f03790db..7b1a2a15f22 100644 --- a/radio/src/targets/common/arm/stm32/stm32_spi.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_spi.cpp @@ -20,6 +20,18 @@ */ #include "stm32_spi.h" +#include "stm32_dma.h" +#include "stm32_gpio_driver.h" +#include "definitions.h" + +#include +#include + +#if !defined(SPI_DISABLE_DMA) +#define USE_SPI_DMA +#endif + +#define SPI_DUMMY_BYTE (0xFF) void stm32_spi_enable_clock(SPI_TypeDef *SPIx) { @@ -53,3 +65,279 @@ void stm32_spi_enable_clock(SPI_TypeDef *SPIx) #endif } +static inline uint32_t _get_spi_af(SPI_TypeDef *SPIx) +{ +#if defined(SPI3) + if (SPIx == SPI3) return LL_GPIO_AF_6; +#endif + return LL_GPIO_AF_5; +} + +static uint32_t _get_spi_prescaler(SPI_TypeDef *SPIx, uint32_t max_freq) +{ + LL_RCC_ClocksTypeDef RCC_Clocks; + LL_RCC_GetSystemClocksFreq(&RCC_Clocks); + + uint32_t pclk = RCC_Clocks.PCLK2_Frequency; +#if defined(SPI2) + if (SPIx == SPI2) { + pclk = RCC_Clocks.PCLK1_Frequency; + } +#endif +#if defined(SPI3) + if (SPIx == SPI3) { + pclk = RCC_Clocks.PCLK1_Frequency; + } +#endif + + uint32_t divider = (pclk + max_freq) / max_freq; + uint32_t presc; + if (divider > 128) { + presc = LL_SPI_BAUDRATEPRESCALER_DIV256; + } else if (divider > 64) { + presc = LL_SPI_BAUDRATEPRESCALER_DIV128; + } else if (divider > 32) { + presc = LL_SPI_BAUDRATEPRESCALER_DIV64; + } else if (divider > 16) { + presc = LL_SPI_BAUDRATEPRESCALER_DIV32; + } else if (divider > 8) { + presc = LL_SPI_BAUDRATEPRESCALER_DIV16; + } else if (divider > 4) { + presc = LL_SPI_BAUDRATEPRESCALER_DIV8; + } else if (divider > 2) { + presc = LL_SPI_BAUDRATEPRESCALER_DIV4; + } else { + presc = LL_SPI_BAUDRATEPRESCALER_DIV2; + } + + return presc; +} + +static void _init_gpios(const stm32_spi_t* spi) +{ + stm32_gpio_enable_clock(spi->SPI_GPIOx); + stm32_gpio_enable_clock(spi->CS_GPIOx); + + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + // SCK, MISO, MOSI + pinInit.Pin = spi->SPI_Pins; + pinInit.Mode = LL_GPIO_MODE_ALTERNATE; + pinInit.Alternate = _get_spi_af(spi->SPIx); + pinInit.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; + pinInit.Pull = LL_GPIO_PULL_UP; + LL_GPIO_Init(spi->SPI_GPIOx, &pinInit); + + // CS + pinInit.Pin = spi->CS_Pin; + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + pinInit.Alternate = LL_GPIO_AF_0; + pinInit.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(spi->CS_GPIOx, &pinInit); +} + +#if defined(USE_SPI_DMA) +static void _config_dma_streams(const stm32_spi_t* spi) +{ + stm32_dma_enable_clock(spi->DMA); + LL_DMA_DeInit(spi->DMA, spi->rxDMA_Stream); + LL_DMA_DeInit(spi->DMA, spi->txDMA_Stream); + + LL_DMA_InitTypeDef dmaInit; + LL_DMA_StructInit(&dmaInit); + + dmaInit.Channel = spi->DMA_Channel; + dmaInit.PeriphOrM2MSrcAddress = (uint32_t)&spi->SPIx->DR; + dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; + dmaInit.FIFOMode = LL_DMA_FIFOMODE_ENABLE; + dmaInit.FIFOThreshold = LL_DMA_FIFOTHRESHOLD_FULL; + + dmaInit.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + LL_DMA_Init(spi->DMA, spi->rxDMA_Stream, &dmaInit); + + dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + LL_DMA_Init(spi->DMA, spi->txDMA_Stream, &dmaInit); +} +#endif + +void stm32_spi_init(const stm32_spi_t* spi) +{ + _init_gpios(spi); + + auto SPIx = spi->SPIx; + stm32_spi_enable_clock(SPIx); + LL_SPI_DeInit(SPIx); + + LL_SPI_InitTypeDef spiInit; + LL_SPI_StructInit(&spiInit); + + spiInit.TransferDirection = LL_SPI_FULL_DUPLEX; + spiInit.Mode = LL_SPI_MODE_MASTER; + spiInit.NSS = LL_SPI_NSS_SOFT; + + LL_SPI_Init(SPIx, &spiInit); + LL_SPI_Enable(SPIx); + +#if defined(USE_SPI_DMA) + if (spi->DMA) { + _config_dma_streams(spi); + } +#endif +} + +// void stm32_spi_deinit(const stm32_spi_t* spi); + +void stm32_spi_select(const stm32_spi_t* spi) +{ + LL_GPIO_ResetOutputPin(spi->CS_GPIOx, spi->CS_Pin); +} + +void stm32_spi_unselect(const stm32_spi_t* spi) +{ + LL_GPIO_SetOutputPin(spi->CS_GPIOx, spi->CS_Pin); +} + +void stm32_spi_set_max_baudrate(const stm32_spi_t* spi, uint32_t baudrate) +{ + auto* SPIx = spi->SPIx; + uint32_t presc = _get_spi_prescaler(SPIx, baudrate); + LL_SPI_SetBaudRatePrescaler(SPIx, presc); +} + +uint8_t stm32_spi_transfer_byte(const stm32_spi_t* spi, uint8_t out) +{ + auto* SPIx = spi->SPIx; + while (!LL_SPI_IsActiveFlag_TXE(SPIx)); + LL_SPI_TransmitData8(SPIx, out); + + while (!LL_SPI_IsActiveFlag_RXNE(SPIx)); + return LL_SPI_ReceiveData8(SPIx); +} + +uint16_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out, + uint8_t* in, uint16_t length) +{ + unsigned trans_bytes = 0; + uint8_t in_temp; + + for (trans_bytes = 0; trans_bytes < length; trans_bytes++) { + if (out != nullptr) { + in_temp = stm32_spi_transfer_byte(spi, out[trans_bytes]); + } else { + in_temp = stm32_spi_transfer_byte(spi, SPI_DUMMY_BYTE); + } + if (in != nullptr) { + in[trans_bytes] = in_temp; + } + } + + return trans_bytes; +} + +uint16_t stm32_spi_transfer_word(const stm32_spi_t* spi, uint16_t out) +{ + auto* SPIx = spi->SPIx; + while (!LL_SPI_IsActiveFlag_TXE(SPIx)); + LL_SPI_TransmitData16(SPIx, out); + + while (!LL_SPI_IsActiveFlag_RXNE(SPIx)); + return LL_SPI_ReceiveData16(SPIx); +} + +#if defined(USE_SPI_DMA) +static uint16_t _scratch_byte __DMA; +static uint8_t _scratch_buffer[512] __DMA; + +static void _dma_enable_stream(DMA_TypeDef* DMAx, uint32_t stream, + const void* data, uint32_t length) +{ + stm32_dma_check_tc_flag(DMAx, stream); + LL_DMA_SetMemoryAddress(DMAx, stream, (uintptr_t)data); + LL_DMA_SetDataLength(DMAx, stream, length); + LL_DMA_EnableStream(DMAx, stream); +} +#endif + +uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, + uint8_t* data, uint16_t length) +{ +#if defined(USE_SPI_DMA) + if (!spi->DMA) { + return stm32_spi_transfer_bytes(spi, 0, data, length); + } + + if (((uintptr_t)data < SRAM_BASE) || ((uintptr_t)data & 3)) { + _dma_enable_stream(spi->DMA, spi->rxDMA_Stream, _scratch_buffer, length); + } else { + _dma_enable_stream(spi->DMA, spi->rxDMA_Stream, data, length); + } + LL_SPI_EnableDMAReq_RX(spi->SPIx); + + _scratch_byte = 0xFFFF; + LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_NOINCREMENT); + _dma_enable_stream(spi->DMA, spi->txDMA_Stream, &_scratch_byte, length); + LL_SPI_EnableDMAReq_TX(spi->SPIx); + + // Wait for end of DMA transfer + while(!stm32_dma_check_tc_flag(spi->DMA, spi->rxDMA_Stream)); + + // Disable SPI TX/RX DMA requests + CLEAR_BIT(spi->SPIx->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); + + // Wait for TXE=1 + while(!LL_SPI_IsActiveFlag_TXE(spi->SPIx)); + + // Wait for BSY=0 + while(LL_SPI_IsActiveFlag_BSY(spi->SPIx)); + + if (((uintptr_t)data < SRAM_BASE) || ((uintptr_t)data & 3)) { + memcpy(data, _scratch_buffer, length); + } + + return length; +#else + return stm32_spi_transfer_bytes(spi, 0, data, length); +#endif +} + +uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi, + const uint8_t* data, uint16_t length) +{ +#if defined(USE_SPI_DMA) + if (!spi->DMA) { + return stm32_spi_transfer_bytes(spi, data, 0, length); + } + + if (((uintptr_t)data < SRAM_BASE) || ((uintptr_t)data & 3)) { + memcpy(_scratch_buffer, data, length); + data = _scratch_buffer; + } + + LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_INCREMENT); + _dma_enable_stream(spi->DMA, spi->txDMA_Stream, data, length); + LL_SPI_EnableDMAReq_TX(spi->SPIx); + + // Wait for end of DMA transfer + while (!stm32_dma_check_tc_flag(spi->DMA, spi->txDMA_Stream)); + + // Disable SPI TX DMA requests + CLEAR_BIT(spi->SPIx->CR2, SPI_CR2_TXDMAEN); + + // Wait for TXE=1 + while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx)); + + // Wait for BSY=0 + while (LL_SPI_IsActiveFlag_BSY(spi->SPIx)); + + // Clear data register + if (LL_SPI_IsActiveFlag_RXNE(spi->SPIx)) { + (void)LL_SPI_ReceiveData8(spi->SPIx); + } + + return length; +#else + return stm32_spi_transfer_bytes(spi, data, 0, length); +#endif +} diff --git a/radio/src/targets/common/arm/stm32/stm32_spi.h b/radio/src/targets/common/arm/stm32/stm32_spi.h index 77dbd72db51..114e411b0a5 100644 --- a/radio/src/targets/common/arm/stm32/stm32_spi.h +++ b/radio/src/targets/common/arm/stm32/stm32_spi.h @@ -22,5 +22,40 @@ #pragma once #include "stm32_hal_ll.h" +#include + + +struct stm32_spi_t { + SPI_TypeDef* SPIx; + GPIO_TypeDef* SPI_GPIOx; + uint32_t SPI_Pins; // SCK, MISO, MOSI + GPIO_TypeDef* CS_GPIOx; + uint32_t CS_Pin; // CS + + DMA_TypeDef* DMA; + uint32_t DMA_Channel; + uint32_t txDMA_Stream; + uint32_t rxDMA_Stream; +}; void stm32_spi_enable_clock(SPI_TypeDef *SPIx); + +void stm32_spi_init(const stm32_spi_t* spi); +void stm32_spi_deinit(const stm32_spi_t* spi); + +void stm32_spi_select(const stm32_spi_t* spi); +void stm32_spi_unselect(const stm32_spi_t* spi); + +void stm32_spi_set_max_baudrate(const stm32_spi_t* spi, uint32_t baudrate); + +uint8_t stm32_spi_transfer_byte(const stm32_spi_t* spi, uint8_t out); +uint16_t stm32_spi_transfer_word(const stm32_spi_t* spi, uint16_t out); + +uint16_t stm32_spi_transfer_bytes(const stm32_spi_t* spi, const uint8_t* out, + uint8_t* in, uint16_t length); + +uint16_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, uint8_t* data, + uint16_t length); + +uint16_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi, const uint8_t* data, + uint16_t length); diff --git a/radio/src/targets/common/arm/stm32/stm32_spi_adc.h b/radio/src/targets/common/arm/stm32/stm32_spi_adc.h index eeadbcc5e25..db80a798282 100644 --- a/radio/src/targets/common/arm/stm32/stm32_spi_adc.h +++ b/radio/src/targets/common/arm/stm32/stm32_spi_adc.h @@ -22,17 +22,11 @@ #pragma once #include "stm32_hal_ll.h" +#include "stm32_spi.h" struct stm32_spi_adc_t { - SPI_TypeDef* SPIx; - GPIO_TypeDef* GPIOx; - uint32_t GPIO_Pins; - uint32_t GPIO_AF; - uint32_t GPIO_CS; - const uint8_t* channels; - uint8_t n_channels; + stm32_spi_t spi; + const uint8_t* channels; + uint8_t n_channels; }; -#define _SPI_ADC_CS_HIGH(adc) LL_GPIO_SetOutputPin(adc->GPIOx, adc->GPIO_CS) -#define _SPI_ADC_CS_LOW(adc) LL_GPIO_ResetOutputPin(adc->GPIOx, adc->GPIO_CS) - diff --git a/radio/src/targets/common/arm/stm32/timers_driver.cpp b/radio/src/targets/common/arm/stm32/timers_driver.cpp index ffa904b9928..d7f92cda151 100644 --- a/radio/src/targets/common/arm/stm32/timers_driver.cpp +++ b/radio/src/targets/common/arm/stm32/timers_driver.cpp @@ -22,15 +22,21 @@ #include "opentx.h" #include "watchdog_driver.h" -static volatile uint32_t msTickCount; // Used to get 1 kHz counter +static volatile uint32_t msTickCount; // Used to get 1 kHz counter +static volatile uint32_t _us_overflow_cnt; // Start TIMER at 2000000Hz void init2MhzTimer() { + _us_overflow_cnt = 0; TIMER_2MHz_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5 uS, 2 MHz TIMER_2MHz_TIMER->ARR = 65535; TIMER_2MHz_TIMER->CR2 = 0; TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; + TIMER_2MHz_TIMER->DIER = TIM_DIER_UIE; + + NVIC_EnableIRQ(TIMER_2MHz_IRQn); + NVIC_SetPriority(TIMER_2MHz_IRQn, 4); } // Start TIMER at 1000Hz @@ -38,13 +44,13 @@ void init1msTimer() { msTickCount = 0; - INTERRUPT_xMS_TIMER->ARR = 999; // 5mS in uS + INTERRUPT_xMS_TIMER->ARR = 999; // 1mS in uS INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS INTERRUPT_xMS_TIMER->CCER = 0; INTERRUPT_xMS_TIMER->CCMR1 = 0; INTERRUPT_xMS_TIMER->EGR = 0; INTERRUPT_xMS_TIMER->CR1 = TIM_CR1_CEN | TIM_CR1_URS; - INTERRUPT_xMS_TIMER->DIER |= TIM_DIER_UIE; + INTERRUPT_xMS_TIMER->DIER = TIM_DIER_UIE; NVIC_EnableIRQ(INTERRUPT_xMS_IRQn); NVIC_SetPriority(INTERRUPT_xMS_IRQn, 4); } @@ -60,6 +66,14 @@ uint32_t timersGetMsTick() return msTickCount; } +uint32_t timersGetUsTick() +{ + uint32_t us; + us = TIMER_2MHz_TIMER->CNT >> 1; + us += _us_overflow_cnt << 15; + return us; +} + static uint32_t watchdogTimeout = 0; void watchdogSuspend(uint32_t timeout) @@ -105,3 +119,9 @@ extern "C" void INTERRUPT_xMS_IRQHandler() interrupt1ms(); DEBUG_INTERRUPT(INT_5MS); } + +extern "C" void TIMER_2MHz_IRQHandler() +{ + TIMER_2MHz_TIMER->SR &= ~TIM_SR_UIF; + _us_overflow_cnt += 1; +} diff --git a/radio/src/targets/common/arm/stm32/timers_driver.h b/radio/src/targets/common/arm/stm32/timers_driver.h index f6381ab7bae..3c5344067b8 100644 --- a/radio/src/targets/common/arm/stm32/timers_driver.h +++ b/radio/src/targets/common/arm/stm32/timers_driver.h @@ -50,3 +50,4 @@ static inline tmr10ms_t get_tmr10ms() } uint32_t timersGetMsTick(); +uint32_t timersGetUsTick(); diff --git a/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp b/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp index 8d7152fc431..5865e18a408 100644 --- a/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp +++ b/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp @@ -21,7 +21,9 @@ /* Includes ------------------------------------------------------------------*/ -#include "FatFs/diskio.h" +#include "hal/fatfs_diskio.h" +#include "hal/storage.h" + #include "fw_version.h" #include "board.h" #include "debug.h" @@ -181,14 +183,14 @@ int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint32_t *block_si static DWORD sector_count = 0; if (sector_count == 0) { - if (disk_ioctl(0, GET_SECTOR_COUNT, §or_count) != RES_OK) { + auto drv = storageGetDefaultDriver(); + if (drv->ioctl(0, GET_SECTOR_COUNT, §or_count) != RES_OK) { sector_count = 0; return -1; } } *block_num = sector_count; - return 0; } @@ -214,7 +216,8 @@ int8_t STORAGE_IsReady (uint8_t lun) return (lunReady[STORAGE_EEPROM_LUN] != 0) ? 0 : -1; } #endif - return (lunReady[STORAGE_SDCARD_LUN] != 0 && SD_CARD_PRESENT()) ? 0 : -1; + // return (lunReady[STORAGE_SDCARD_LUN] != 0 && SD_CARD_PRESENT()) ? 0 : -1; + return 0; // debug: "always ON" } /** @@ -224,7 +227,7 @@ int8_t STORAGE_IsReady (uint8_t lun) */ int8_t STORAGE_IsWriteProtected (uint8_t lun) { - return 0; + return 0; } /** @@ -249,8 +252,8 @@ int8_t STORAGE_Read (uint8_t lun, } #endif - // read without cache - return (__disk_read(0, buf, blk_addr, blk_len) == RES_OK) ? 0 : -1; + auto drv = storageGetDefaultDriver(); + return (drv->read(0, buf, blk_addr, blk_len) == RES_OK) ? 0 : -1; } /** * @brief Write data to the medium @@ -274,8 +277,8 @@ int8_t STORAGE_Write (uint8_t lun, } #endif - // write without cache - return (__disk_write(0, buf, blk_addr, blk_len) == RES_OK) ? 0 : -1; + auto drv = storageGetDefaultDriver(); + return (drv->write(0, buf, blk_addr, blk_len) == RES_OK) ? 0 : -1; } /** diff --git a/radio/src/targets/nv14/audio_spi_driver.cpp b/radio/src/targets/common/arm/stm32/vs1053b.cpp similarity index 71% rename from radio/src/targets/nv14/audio_spi_driver.cpp rename to radio/src/targets/common/arm/stm32/vs1053b.cpp index 20265d3898c..6da8164fec7 100644 --- a/radio/src/targets/nv14/audio_spi_driver.cpp +++ b/radio/src/targets/common/arm/stm32/vs1053b.cpp @@ -19,6 +19,10 @@ * GNU General Public License for more details. */ +#include "stm32_hal_ll.h" +#include "stm32_gpio_driver.h" +#include "stm32_spi.h" + #include "opentx.h" #if !defined(SIMU) @@ -70,69 +74,44 @@ #define MP3_BUFFER_SIZE 32 -#define CS_HIGH() do { AUDIO_CS_GPIO->BSRRL = AUDIO_CS_GPIO_PIN; } while (0) -#define CS_LOW() do { AUDIO_CS_GPIO->BSRRH = AUDIO_CS_GPIO_PIN; } while (0) -#define XDCS_HIGH() do { AUDIO_XDCS_GPIO->BSRRL = AUDIO_XDCS_GPIO_PIN; } while (0) -#define XDCS_LOW() do { AUDIO_XDCS_GPIO->BSRRH = AUDIO_XDCS_GPIO_PIN; } while (0) -#define RST_HIGH() do { AUDIO_RST_GPIO->BSRRL = AUDIO_RST_GPIO_PIN; } while (0) -#define RST_LOW() do { AUDIO_RST_GPIO->BSRRH = AUDIO_RST_GPIO_PIN; } while (0) - -#define READ_DREQ() (GPIO_ReadInputDataBit(AUDIO_DREQ_GPIO, AUDIO_DREQ_GPIO_PIN)) +#define CS_HIGH() stm32_spi_unselect(&_audio_spi) +#define CS_LOW() stm32_spi_select(&_audio_spi) +#define XDCS_HIGH() do { AUDIO_XDCS_GPIO->BSRR = AUDIO_XDCS_GPIO_PIN; } while (0) +#define XDCS_LOW() do { AUDIO_XDCS_GPIO->BSRR = AUDIO_XDCS_GPIO_PIN << 16; } while (0) +#define RST_HIGH() do { AUDIO_RST_GPIO->BSRR = AUDIO_RST_GPIO_PIN; } while (0) +#define RST_LOW() do { AUDIO_RST_GPIO->BSRR = AUDIO_RST_GPIO_PIN << 16; } while (0) + +#define READ_DREQ() (LL_GPIO_IsInputPinSet(AUDIO_DREQ_GPIO, AUDIO_DREQ_GPIO_PIN)) + +static const stm32_spi_t _audio_spi = { + .SPIx = AUDIO_SPI, + .SPI_GPIOx = AUDIO_SPI_SCK_GPIO, + .SPI_Pins = AUDIO_SPI_SCK_GPIO_PIN | AUDIO_SPI_MISO_GPIO_PIN | AUDIO_SPI_MOSI_GPIO_PIN, + .CS_GPIOx = AUDIO_CS_GPIO, + .CS_Pin = AUDIO_CS_GPIO_PIN, +}; void audioSpiInit(void) { - GPIO_InitTypeDef GPIO_InitStructure; - SPI_InitTypeDef SPI_InitStructure; + stm32_gpio_enable_clock(AUDIO_XDCS_GPIO); + stm32_gpio_enable_clock(AUDIO_RST_GPIO); + stm32_gpio_enable_clock(AUDIO_DREQ_GPIO); + + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); - GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_MISO_GPIO_PIN; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(AUDIO_SPI_MISO_GPIO, &GPIO_InitStructure); + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + pinInit.Pin = AUDIO_XDCS_GPIO_PIN; + LL_GPIO_Init(AUDIO_XDCS_GPIO, &pinInit); - GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_SCK_GPIO_PIN; - GPIO_Init(AUDIO_SPI_SCK_GPIO, &GPIO_InitStructure); + pinInit.Pin = AUDIO_RST_GPIO_PIN; + LL_GPIO_Init(AUDIO_RST_GPIO, &pinInit); - GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_MOSI_GPIO_PIN; - GPIO_Init(AUDIO_SPI_MOSI_GPIO, &GPIO_InitStructure); + pinInit.Pin = AUDIO_DREQ_GPIO_PIN; + pinInit.Mode = LL_GPIO_MODE_INPUT; + LL_GPIO_Init(AUDIO_DREQ_GPIO, &pinInit); - GPIO_InitStructure.GPIO_Pin = AUDIO_CS_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_Init(AUDIO_CS_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_XDCS_GPIO_PIN; - GPIO_Init(AUDIO_XDCS_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_RST_GPIO_PIN; - GPIO_Init(AUDIO_RST_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_DREQ_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_Init(AUDIO_DREQ_GPIO, &GPIO_InitStructure); - - GPIO_PinAFConfig(AUDIO_SPI_SCK_GPIO, AUDIO_SPI_SCK_GPIO_PinSource, AUDIO_SPI_GPIO_AF); - GPIO_PinAFConfig(AUDIO_SPI_MISO_GPIO, AUDIO_SPI_MISO_GPIO_PinSource, AUDIO_SPI_GPIO_AF); - GPIO_PinAFConfig(AUDIO_SPI_MOSI_GPIO, AUDIO_SPI_MOSI_GPIO_PinSource, AUDIO_SPI_GPIO_AF); - - RCC_ClocksTypeDef RCC_Clocks; - RCC_GetClocksFreq(&RCC_Clocks); - - SPI_I2S_DeInit(AUDIO_SPI); - SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; - SPI_InitStructure.SPI_Mode = SPI_Mode_Master; - SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; - SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; - SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; - SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; - SPI_InitStructure.SPI_CRCPolynomial = 7; - SPI_Init(AUDIO_SPI, &SPI_InitStructure); - SPI_Cmd(AUDIO_SPI, ENABLE); - - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_RXNE); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TXE); + stm32_spi_init(&_audio_spi); } void audioWaitReady() @@ -175,35 +154,7 @@ void audioSpiSetSpeed(uint8_t speed) uint8_t audioSpiReadWriteByte(uint8_t value) { - uint16_t time_out = 0x0FFF; - while (SPI_I2S_GetFlagStatus(AUDIO_SPI, SPI_I2S_FLAG_TXE) == RESET) { - if (--time_out == 0) { - // reset SPI - SPI_Cmd(AUDIO_SPI, DISABLE); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_OVR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_BSY); - SPI_I2S_ClearFlag(AUDIO_SPI, I2S_FLAG_UDR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TIFRFE); - SPI_Cmd(AUDIO_SPI, ENABLE); - break; - } - } - SPI_I2S_SendData(AUDIO_SPI, value); - - time_out = 0x0FFF; - while (SPI_I2S_GetFlagStatus(AUDIO_SPI, SPI_I2S_FLAG_RXNE) == RESET) { - if (--time_out == 0) { - // reset SPI - SPI_Cmd(AUDIO_SPI, DISABLE); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_OVR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_BSY); - SPI_I2S_ClearFlag(AUDIO_SPI, I2S_FLAG_UDR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TIFRFE); - SPI_Cmd(AUDIO_SPI, ENABLE); - break; - } - } - return SPI_I2S_ReceiveData(AUDIO_SPI); + return stm32_spi_transfer_byte(&_audio_spi, value); } uint8_t audioWaitDreq(int32_t delay_us) @@ -283,7 +234,7 @@ uint8_t audioHardReset(void) delay_ms(100); // 100ms RST_HIGH(); - if (!audioWaitDreq(5000)) + if (!audioWaitDreq(100)) return 0; delay_ms(20); // 20ms @@ -296,15 +247,14 @@ uint8_t audioSoftReset(void) if (!audioWaitDreq(100)) return 0; - audioSpiReadWriteByte(0Xff); + audioSpiReadWriteByte(0x00); // start the transfer + + audioSpiWriteCmd(SPI_MODE, 0x0816); // SOFT RESET, new model + if (!audioWaitDreq(100)) + return 0; - uint8_t retry = 0; - while (audioSpiReadReg(SPI_MODE) != 0x0800 && retry < 100) { - retry++; - audioSpiWriteCmd(SPI_MODE, 0x0804); - } // wait for set up successful - retry = 0; + uint8_t retry = 0; while (audioSpiReadReg(SPI_CLOCKF) != 0x9800 && retry < 100) { retry++; audioSpiWriteCmd(SPI_CLOCKF, 0x9800); @@ -403,10 +353,10 @@ void audioMute() void audioUnmute() { -if(isFunctionActive(FUNCTION_DISABLE_AUDIO_AMP)) { - setMutePin(true); - return; -} + if(isFunctionActive(FUNCTION_DISABLE_AUDIO_AMP)) { + setMutePin(true); + return; + } #if defined(AUDIO_UNMUTE_DELAY) // if muted @@ -435,12 +385,31 @@ void audioMuteInit() } #endif +#if defined(PCBX12S) +void audioShutdownInit() +{ + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + pinInit.Pin = AUDIO_SHUTDOWN_GPIO_PIN; + LL_GPIO_Init(AUDIO_SHUTDOWN_GPIO, &pinInit); + + // we never RESET it, there is a 2s delay on STARTUP + LL_GPIO_SetOutputPin(AUDIO_SHUTDOWN_GPIO, AUDIO_SHUTDOWN_GPIO_PIN); +} +#endif + void audioInit() { #if defined(AUDIO_MUTE_GPIO_PIN) audioMuteInit(); #endif + #if defined(PCBX12S) + audioShutdownInit(); +#endif + audioSpiInit(); audioHardReset(); audioSoftReset(); @@ -510,7 +479,7 @@ void setScaledVolume(uint8_t volume) } // maximum volume is 0x00 and total silence is 0xFE if (volume == 0) { - setVolume(0xFE); // silence + setVolume(0xFE); // silence } else { uint32_t vol = (VOLUME_MIN_DB * 2) - ((uint32_t)volume * (VOLUME_MIN_DB * 2)) / VOLUME_LEVEL_MAX; diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 843ec6bf34e..3e3c851b6bf 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -146,10 +146,7 @@ elseif (PCB STREQUAL X12S) endif() set(INTERNAL_GPS_BAUDRATE "9600" CACHE STRING "Baud rate for internal GPS") set(AUX2_SERIAL ON) # wire to GPS - set(FIRMWARE_TARGET_SRC - ${FIRMWARE_TARGET_SRC} - audio_spi_driver.cpp - ) + set(FIRMWARE_SRC ${FIRMWARE_SRC} targets/common/arm/stm32/vs1053b.cpp) set(BITMAPS_TARGET x12s_bitmaps) set(FONTS_TARGET x12s_fonts) set(LCD_DRIVER lcd_driver.cpp) @@ -274,7 +271,6 @@ set(FIRMWARE_SRC targets/common/arm/stm32/heartbeat_driver.cpp targets/common/arm/stm32/trainer_driver.cpp targets/common/arm/stm32/ads79xx.cpp - targets/common/arm/stm32/sdio_sd.cpp targets/common/arm/stm32/diskio_sdio.cpp ) diff --git a/radio/src/targets/horus/audio_spi_driver.cpp b/radio/src/targets/horus/audio_spi_driver.cpp deleted file mode 100644 index 7bb4d609f57..00000000000 --- a/radio/src/targets/horus/audio_spi_driver.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * 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 "opentx.h" - -#if !defined(SIMU) - -#define VS_WRITE_COMMAND 0x02 -#define VS_READ_COMMAND 0x03 - -#define SPI_MODE 0x00 -#define SPI_STATUS 0x01 -#define SPI_BASS 0x02 -#define SPI_CLOCKF 0x03 -#define SPI_DECODE_TIME 0x04 -#define SPI_AUDATA 0x05 -#define SPI_WRAM 0x06 -#define SPI_WRAMADDR 0x07 -#define SPI_HDAT0 0x08 -#define SPI_HDAT1 0x09 -#define SPI_AIADDR 0x0a -#define SPI_VOL 0x0b -#define SPI_AICTRL0 0x0c -#define SPI_AICTRL1 0x0d -#define SPI_AICTRL2 0x0e -#define SPI_AICTRL3 0x0f - -#define SM_DIFF 0x01 -#define SM_LAYER12 0x02 -#define SM_RESET 0x04 -#define SM_CANCEL 0x08 -#define SM_EARSPEAKER_LO 0x10 -#define SM_TESTS 0x20 -#define SM_STREAM 0x40 -#define SM_EARSPEAKER_HI 0x80 -#define SM_DACT 0x100 -#define SM_SDIORD 0x200 -#define SM_SDISHARE 0x400 -#define SM_SDINEW 0x800 -#define SM_ADPCM 0x1000 -#define SM_LINE1 0x4000 -#define SM_CLK_RANGE 0x8000 - -#define SPI_SPEED_2 0 -#define SPI_SPEED_4 1 -#define SPI_SPEED_8 2 -#define SPI_SPEED_16 3 -#define SPI_SPEED_32 4 -#define SPI_SPEED_64 5 -#define SPI_SPEED_128 6 -#define SPI_SPEED_256 7 - -#define MP3_BUFFER_SIZE 32 - -#define CS_HIGH() do { AUDIO_CS_GPIO->BSRRL = AUDIO_CS_GPIO_PIN; } while (0) -#define CS_LOW() do { AUDIO_CS_GPIO->BSRRH = AUDIO_CS_GPIO_PIN; } while (0) -#define XDCS_HIGH() do { AUDIO_XDCS_GPIO->BSRRL = AUDIO_XDCS_GPIO_PIN; } while (0) -#define XDCS_LOW() do { AUDIO_XDCS_GPIO->BSRRH = AUDIO_XDCS_GPIO_PIN; } while (0) -#define RST_HIGH() do { AUDIO_RST_GPIO->BSRRL = AUDIO_RST_GPIO_PIN; } while (0) -#define RST_LOW() do { AUDIO_RST_GPIO->BSRRH = AUDIO_RST_GPIO_PIN; } while (0) - -#define READ_DREQ() (GPIO_ReadInputDataBit(AUDIO_DREQ_GPIO, AUDIO_DREQ_GPIO_PIN)) - -void audioSpiInit(void) -{ - GPIO_InitTypeDef GPIO_InitStructure; - SPI_InitTypeDef SPI_InitStructure; - - GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_MISO_GPIO_PIN; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(AUDIO_SPI_MISO_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_SCK_GPIO_PIN; - GPIO_Init(AUDIO_SPI_SCK_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_SPI_MOSI_GPIO_PIN; - GPIO_Init(AUDIO_SPI_MOSI_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_CS_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_Init(AUDIO_CS_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_XDCS_GPIO_PIN; - GPIO_Init(AUDIO_XDCS_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_RST_GPIO_PIN; - GPIO_Init(AUDIO_RST_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = AUDIO_DREQ_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_Init(AUDIO_DREQ_GPIO, &GPIO_InitStructure); - - GPIO_PinAFConfig(AUDIO_SPI_SCK_GPIO, AUDIO_SPI_SCK_GPIO_PinSource, AUDIO_SPI_GPIO_AF); - GPIO_PinAFConfig(AUDIO_SPI_MISO_GPIO, AUDIO_SPI_MISO_GPIO_PinSource, AUDIO_SPI_GPIO_AF); - GPIO_PinAFConfig(AUDIO_SPI_MOSI_GPIO, AUDIO_SPI_MOSI_GPIO_PinSource, AUDIO_SPI_GPIO_AF); - - RCC_ClocksTypeDef RCC_Clocks; - RCC_GetClocksFreq(&RCC_Clocks); - - SPI_I2S_DeInit(AUDIO_SPI); - SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; - SPI_InitStructure.SPI_Mode = SPI_Mode_Master; - SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; - SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; - SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; - SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; - SPI_InitStructure.SPI_CRCPolynomial = 7; - SPI_Init(AUDIO_SPI, &SPI_InitStructure); - SPI_Cmd(AUDIO_SPI, ENABLE); - - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_RXNE); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TXE); -} - -void audioWaitReady() -{ - // The audio amp needs ~2s to start - RTOS_WAIT_MS(2000); // 2s -} - -void audioSpiSetSpeed(uint8_t speed) -{ - AUDIO_SPI->CR1 &= 0xFFC7; // Fsck=Fcpu/256 - switch (speed) { - case SPI_SPEED_2: - AUDIO_SPI->CR1 |= 0x00 << 3; // Fsck=Fpclk/2=36Mhz - break; - case SPI_SPEED_4: - AUDIO_SPI->CR1 |= 0x01 << 3; // Fsck=Fpclk/4=18Mhz - break; - case SPI_SPEED_8: - AUDIO_SPI->CR1 |= 0x02 << 3; // Fsck=Fpclk/8=9Mhz - break; - case SPI_SPEED_16: - AUDIO_SPI->CR1 |= 0x03 << 3; // Fsck=Fpclk/16=4.5Mhz - break; - case SPI_SPEED_32: - AUDIO_SPI->CR1 |= 0x04 << 3; // Fsck=Fpclk/32=2.25Mhz - break; - case SPI_SPEED_64: - AUDIO_SPI->CR1 |= 0x05 << 3; // Fsck=Fpclk/16=1.125Mhz - break; - case SPI_SPEED_128: - AUDIO_SPI->CR1 |= 0x06 << 3; // Fsck=Fpclk/16=562.5Khz - break; - case SPI_SPEED_256: - AUDIO_SPI->CR1 |= 0x07 << 3; // Fsck=Fpclk/16=281.25Khz - break; - } - AUDIO_SPI->CR1 |= 0x01 << 6; -} - -uint8_t audioSpiReadWriteByte(uint8_t value) -{ - uint16_t time_out = 0x0FFF; - while (SPI_I2S_GetFlagStatus(AUDIO_SPI, SPI_I2S_FLAG_TXE) == RESET) { - if (--time_out == 0) { - // reset SPI - SPI_Cmd(AUDIO_SPI, DISABLE); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_OVR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_BSY); - SPI_I2S_ClearFlag(AUDIO_SPI, I2S_FLAG_UDR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TIFRFE); - SPI_Cmd(AUDIO_SPI, ENABLE); - break; - } - } - SPI_I2S_SendData(AUDIO_SPI, value); - - time_out = 0x0FFF; - while (SPI_I2S_GetFlagStatus(AUDIO_SPI, SPI_I2S_FLAG_RXNE) == RESET) { - if (--time_out == 0) { - // reset SPI - SPI_Cmd(AUDIO_SPI, DISABLE); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_OVR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_BSY); - SPI_I2S_ClearFlag(AUDIO_SPI, I2S_FLAG_UDR); - SPI_I2S_ClearFlag(AUDIO_SPI, SPI_I2S_FLAG_TIFRFE); - SPI_Cmd(AUDIO_SPI, ENABLE); - break; - } - } - return SPI_I2S_ReceiveData(AUDIO_SPI); -} - -uint8_t audioWaitDreq(int32_t delay_us) -{ - while (READ_DREQ() == 0) { - if (delay_us-- == 0) return 0; - delay_01us(10); - } - return 1; -} - -uint16_t audioSpiReadReg(uint8_t address) -{ - if (!audioWaitDreq(100)) - return 0; - - audioSpiSetSpeed(SPI_SPEED_64); - XDCS_HIGH(); - CS_LOW(); - audioSpiReadWriteByte(VS_READ_COMMAND); - audioSpiReadWriteByte(address); - uint16_t result = audioSpiReadWriteByte(0xff) << 8; - result += audioSpiReadWriteByte(0xff); - delay_01us(100); // 10us - CS_HIGH(); - audioSpiSetSpeed(SPI_SPEED_8); - return result; -} - -uint16_t audioSpiReadCmd(uint8_t address) -{ - if (!audioWaitDreq(100)) - return 0; - - audioSpiSetSpeed(SPI_SPEED_64); - XDCS_HIGH(); - CS_LOW(); - audioSpiReadWriteByte(VS_READ_COMMAND); - audioSpiReadWriteByte(address); - uint16_t result = audioSpiReadWriteByte(0) << 8; - result |= audioSpiReadWriteByte(0); - delay_01us(50); // 5us - CS_HIGH(); - audioSpiSetSpeed(SPI_SPEED_8); - return result; -} - -uint8_t audioSpiWriteCmd(uint8_t address, uint16_t data) -{ - if (!audioWaitDreq(100)) - return 0; - - audioSpiSetSpeed(SPI_SPEED_64); - XDCS_HIGH(); - CS_LOW(); - audioSpiReadWriteByte(VS_WRITE_COMMAND); - audioSpiReadWriteByte(address); - audioSpiReadWriteByte(data >> 8); - audioSpiReadWriteByte(data); - delay_01us(50); // 5us - CS_HIGH(); - audioSpiSetSpeed(SPI_SPEED_8); - return 1; -} - -void audioResetDecodeTime(void) -{ - audioSpiWriteCmd(SPI_DECODE_TIME, 0x0000); - audioSpiWriteCmd(SPI_DECODE_TIME, 0x0000); -} - -uint8_t audioHardReset(void) -{ - XDCS_HIGH(); - CS_HIGH(); - RST_LOW(); - delay_ms(100); // 100ms - RST_HIGH(); - - if (!audioWaitDreq(100)) - return 0; - - delay_ms(20); // 20ms - return 1; -} - -uint8_t audioSoftReset(void) -{ - audioSpiSetSpeed(SPI_SPEED_64); - if (!audioWaitDreq(100)) - return 0; - - audioSpiReadWriteByte(0x00); // start the transfer - - audioSpiWriteCmd(SPI_MODE, 0x0816); // SOFT RESET, new model - if (!audioWaitDreq(100)) - return 0; - - // wait for set up successful - uint8_t retry = 0; - while (audioSpiReadReg(SPI_CLOCKF) != 0x9800 && retry < 100) { - retry++; - audioSpiWriteCmd(SPI_CLOCKF, 0x9800); - } - - audioResetDecodeTime(); // reset the decoding time - audioSpiSetSpeed(SPI_SPEED_8); - XDCS_LOW(); - audioSpiReadWriteByte(0X0); - audioSpiReadWriteByte(0X0); - audioSpiReadWriteByte(0X0); - audioSpiReadWriteByte(0X0); - delay_01us(100); // 10us - XDCS_HIGH(); - return 1; -} - -uint32_t audioSpiWriteData(const uint8_t * buffer, uint32_t size) -{ - XDCS_LOW(); - - uint32_t index = 0; - while (index < size && READ_DREQ() != 0) { - for (int i=0; i 0) { - uint32_t written = audioSpiWriteData(p, size); - p += written; - size -= written; - } -} - -const uint8_t RiffHeader[] = { - 0x52, 0x49, 0x46, 0x46, 0xff, 0xff, 0xff, 0xff, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, - 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, - 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -void audioSendRiffHeader() -{ - audioSpiWriteBuffer(RiffHeader, sizeof(RiffHeader)); -} - -#if defined(PCBX12S) -void audioShutdownInit() -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = AUDIO_SHUTDOWN_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(AUDIO_SHUTDOWN_GPIO, &GPIO_InitStructure); - GPIO_SetBits(AUDIO_SHUTDOWN_GPIO, AUDIO_SHUTDOWN_GPIO_PIN); // we never RESET it, there is a 2s delay on STARTUP -} -#endif - -void audioInit() -{ -#if defined(PCBX12S) - audioShutdownInit(); - // TODO X10 code missing -#endif - - audioSpiInit(); - audioHardReset(); - audioSoftReset(); - audioSpiSetSpeed(SPI_SPEED_8); - delay_ms(1); // 1ms - audioSendRiffHeader(); -} - -uint8_t * currentBuffer = nullptr; -uint32_t currentSize = 0; -int16_t newVolume = -1; - -void audioSetCurrentBuffer(const AudioBuffer * buffer) -{ - if (buffer) { - currentBuffer = (uint8_t *)buffer->data; - currentSize = buffer->size * 2; - } - else { - currentBuffer = nullptr; - currentSize = 0; - } -} - -void audioConsumeCurrentBuffer() -{ - if (newVolume >= 0) { - uint8_t value = newVolume; - audioSpiWriteCmd(SPI_VOL, (value << 8) + value); - // audioSendRiffHeader(); - newVolume = -1; - } - - if (!currentBuffer) { - audioSetCurrentBuffer(audioQueue.buffersFifo.getNextFilledBuffer()); - } - - if (currentBuffer) { - uint32_t written = audioSpiWriteData(currentBuffer, currentSize); - currentBuffer += written; - currentSize -= written; - if (currentSize == 0) { - audioQueue.buffersFifo.freeNextFilledBuffer(); - currentBuffer = nullptr; - currentSize = 0; - } - } -} - -// adjust this value for a volume level just above the silence -// values is attenuation in dB, higher value - less volume -// max value is 126 -#define VOLUME_MIN_DB 40 - -void setScaledVolume(uint8_t volume) -{ - if (volume > VOLUME_LEVEL_MAX) { - volume = VOLUME_LEVEL_MAX; - } - // maximum volume is 0x00 and total silence is 0xFE - if (volume == 0) { - setVolume(0xFE); // silence - } - else { - uint32_t vol = (VOLUME_MIN_DB * 2) - ((uint32_t)volume * (VOLUME_MIN_DB * 2)) / VOLUME_LEVEL_MAX; - setVolume(vol); - } -} - -void setVolume(uint8_t volume) -{ - newVolume = volume; -} - -int32_t getVolume() -{ - return -1; // TODO -} - -#endif diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 42f7e1c2098..c1cb19955bd 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -92,12 +92,6 @@ enum { #endif #endif -#if defined(SIMU) - #define SD_CARD_PRESENT() true -#else - #define SD_CARD_PRESENT() (~SD_PRESENT_GPIO->IDR & SD_PRESENT_GPIO_PIN) -#endif - // Flash Write driver #define FLASH_PAGESIZE 256 void unlockFlash(); diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 87be953467f..9985428dd74 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -631,6 +631,7 @@ #define SD_SDIO_CLK_DIV(fq) ((48000000 / (fq)) - 2) #define SD_SDIO_INIT_CLK_DIV SD_SDIO_CLK_DIV(400000) #define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000) +#define STORAGE_USE_SDIO // EEPROM #if defined(PCBX12S) && PCBREV >= 13 @@ -996,6 +997,8 @@ // 2MHz Timer #define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 #define TIMER_2MHz_TIMER TIM7 +#define TIMER_2MHz_IRQn TIM7_IRQn +#define TIMER_2MHz_IRQHandler TIM7_IRQHandler // Mixer scheduler timer #define MIXER_SCHEDULER_TIMER_RCC_APB1Periph RCC_APB1Periph_TIM13 diff --git a/radio/src/targets/nv14/CMakeLists.txt b/radio/src/targets/nv14/CMakeLists.txt index 14d07b8d9c3..c8814d96b41 100644 --- a/radio/src/targets/nv14/CMakeLists.txt +++ b/radio/src/targets/nv14/CMakeLists.txt @@ -140,7 +140,6 @@ set(FIRMWARE_TARGET_SRC ${TOUCH_DRIVER} sdram_driver.c battery_driver.cpp - audio_spi_driver.cpp backlight_driver.cpp ) @@ -153,8 +152,8 @@ set(FIRMWARE_SRC targets/common/arm/stm32/stm32_usart_driver.cpp targets/common/arm/stm32/trainer_driver.cpp targets/common/arm/stm32/pwr_driver.cpp - targets/common/arm/stm32/sdio_sd.cpp targets/common/arm/stm32/diskio_sdio.cpp + targets/common/arm/stm32/vs1053b.cpp ) # Make malloc() thread-safe diff --git a/radio/src/targets/nv14/board.h b/radio/src/targets/nv14/board.h index af66f9c1472..b35e196e68c 100644 --- a/radio/src/targets/nv14/board.h +++ b/radio/src/targets/nv14/board.h @@ -53,12 +53,6 @@ void boardOff(); #define LEN_CPU_UID (3*8+2) void getCPUUniqueID(char * s); -#if defined(SIMU) - #define SD_CARD_PRESENT() true -#else - #define SD_CARD_PRESENT() (~SD_PRESENT_GPIO->IDR & SD_PRESENT_GPIO_PIN) -#endif - // Flash Write driver #define FLASH_PAGESIZE 256 void unlockFlash(); diff --git a/radio/src/targets/nv14/hal.h b/radio/src/targets/nv14/hal.h index 8b50df5a51d..b5565deb4b8 100644 --- a/radio/src/targets/nv14/hal.h +++ b/radio/src/targets/nv14/hal.h @@ -305,6 +305,7 @@ #define SD_SDIO_CLK_DIV(fq) ((48000000 / (fq)) - 2) #define SD_SDIO_INIT_CLK_DIV SD_SDIO_CLK_DIV(400000) #define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000) +#define STORAGE_USE_SDIO // SDRAM #define SDRAM_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH) @@ -549,6 +550,8 @@ // 2MHz Timer #define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 #define TIMER_2MHz_TIMER TIM7 +#define TIMER_2MHz_IRQn TIM7_IRQn +#define TIMER_2MHz_IRQHandler TIM7_IRQHandler // Mixer scheduler timer #define MIXER_SCHEDULER_TIMER_RCC_APB1Periph RCC_APB1Periph_TIM12 diff --git a/radio/src/targets/simu/simudisk.cpp b/radio/src/targets/simu/simudisk.cpp index d3a1d3fc097..9ef85300abf 100644 --- a/radio/src/targets/simu/simudisk.cpp +++ b/radio/src/targets/simu/simudisk.cpp @@ -95,7 +95,7 @@ DSTATUS disk_status (BYTE pdrv) return (DSTATUS)0; } -DRESULT __disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) +DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { if (diskImage == 0) return RES_NOTRDY; traceDiskStatus(); @@ -105,7 +105,7 @@ DRESULT __disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) return RES_OK; } -DRESULT __disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) +DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { if (diskImage == 0) return RES_NOTRDY; traceDiskStatus(); diff --git a/radio/src/targets/simu/simufatfs.cpp b/radio/src/targets/simu/simufatfs.cpp index e3ed95f47aa..bd6abc90c0c 100644 --- a/radio/src/targets/simu/simufatfs.cpp +++ b/radio/src/targets/simu/simufatfs.cpp @@ -613,5 +613,10 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs) return FR_OK; } +#include "hal/storage.h" + +void storageInit() {} +void storagePreMountHook() {} +bool storageIsPresent() { return true; } #endif // #if defined(SIMU_USE_SDCARD) diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index 226b1002e73..84a4957f419 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -574,7 +574,6 @@ set(FIRMWARE_TARGET_SRC volume_i2c.cpp eeprom_driver.cpp backlight_driver.cpp - diskio.cpp ) if(PCB STREQUAL XLITE OR PCB STREQUAL XLITES OR PCBREV STREQUAL COMMANDO8) @@ -595,6 +594,8 @@ set(FIRMWARE_SRC targets/common/arm/stm32/stm32_pulse_driver.cpp targets/common/arm/stm32/stm32_usart_driver.cpp targets/common/arm/stm32/trainer_driver.cpp + targets/common/arm/stm32/sdcard_spi.cpp + targets/common/arm/stm32/diskio_spi.cpp ) if(LCD_DUAL_BUFFER) diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index 219255bb658..647190c7520 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -92,7 +92,6 @@ void boardInit() LCD_RCC_AHB1Periph | AUDIO_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | - SD_RCC_AHB1Periph | HAPTIC_RCC_AHB1Periph | INTMODULE_RCC_AHB1Periph | EXTMODULE_RCC_AHB1Periph | @@ -110,7 +109,6 @@ void boardInit() HAPTIC_RCC_APB1Periph | INTERRUPT_xMS_RCC_APB1Periph | TIMER_2MHz_RCC_APB1Periph | - SD_RCC_APB1Periph | TELEMETRY_RCC_APB1Periph | MIXER_SCHEDULER_TIMER_RCC_APB1Periph | BT_RCC_APB1Periph, diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index c5eb1b55f9a..f41c8610360 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -64,16 +64,6 @@ enum { PCBREV_X7_40 = 1, }; -// SD driver -#define __disk_read disk_read -#define __disk_write disk_write - -#if defined(SIMU) || !defined(SD_PRESENT_GPIO) - #define SD_CARD_PRESENT() true -#else - #define SD_CARD_PRESENT() ((SD_PRESENT_GPIO->IDR & SD_PRESENT_GPIO_PIN) == 0) -#endif - // Flash Write driver #define FLASH_PAGESIZE 256 void unlockFlash(); diff --git a/radio/src/targets/taranis/diskio.cpp b/radio/src/targets/taranis/diskio.cpp deleted file mode 100644 index 08bb8617f31..00000000000 --- a/radio/src/targets/taranis/diskio.cpp +++ /dev/null @@ -1,933 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * 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 "board.h" -#include "debug.h" -#include "FatFs/diskio.h" -#include "FatFs/ff.h" - -#include "sdcard.h" -#include "audio.h" - -#define RAM_START 0x20000000 - -/* Definitions for MMC/SDC command */ -#define CMD0 (0x40+0) /* GO_IDLE_STATE */ -#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */ -#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */ -#define CMD8 (0x40+8) /* SEND_IF_COND */ -#define CMD9 (0x40+9) /* SEND_CSD */ -#define CMD10 (0x40+10) /* SEND_CID */ -#define CMD12 (0x40+12) /* STOP_TRANSMISSION */ -#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */ -#define CMD16 (0x40+16) /* SET_BLOCKLEN */ -#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ -#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */ -#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */ -#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ -#define CMD24 (0x40+24) /* WRITE_BLOCK */ -#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */ -#define CMD55 (0x40+55) /* APP_CMD */ -#define CMD58 (0x40+58) /* READ_OCR */ - -/* Card-Select Controls (Platform dependent) */ -#define SD_SELECT() GPIO_ResetBits(SD_GPIO, SD_GPIO_PIN_CS) /* MMC CS = L */ -#define SD_DESELECT() GPIO_SetBits(SD_GPIO, SD_GPIO_PIN_CS) /* MMC CS = H */ - -#define BOOL bool -#define FALSE false -#define TRUE true - -/* Card type flags (CardType) */ -#define CT_MMC 0x01 -#define CT_SD1 0x02 -#define CT_SD2 0x04 -#define CT_SDC (CT_SD1|CT_SD2) -#define CT_BLOCK 0x08 - -static const DWORD socket_state_mask_cp = (1 << 0); -static const DWORD socket_state_mask_wp = (1 << 1); - -/* Disk status */ -static volatile DSTATUS Stat = STA_NOINIT; - -/* 100Hz decrement timers */ -static volatile DWORD Timer1, Timer2; - -/* Card type flags */ -BYTE CardType; - -enum speed_setting { INTERFACE_SLOW, INTERFACE_FAST }; - -static void interface_speed( enum speed_setting speed ) -{ - DWORD tmp; - - tmp = SD_SPI->CR1; - if ( speed == INTERFACE_SLOW ) { - /* Set slow clock (100k-400k) */ - tmp = ( tmp | SPI_BaudRatePrescaler_128 ); - } else { - /* Set fast clock (depends on the CSD) */ - tmp = ( tmp & ~SPI_BaudRatePrescaler_128 ) | SD_SPI_BaudRatePrescaler; - } - SD_SPI->CR1 = tmp; -} - -static inline DWORD socket_is_write_protected(void) -{ - return 0; /* fake not protected */ -} - -static inline DWORD socket_is_empty(void) -{ - return !SD_CARD_PRESENT(); /* fake inserted */ -} - -static void card_power(BYTE on) -{ - on=on; -} - -static int chk_power(void) -{ - return 1; /* fake powered */ -} - -/*-----------------------------------------------------------------------*/ -/* Transmit/Receive a byte to MMC via SPI (Platform dependent) */ -/*-----------------------------------------------------------------------*/ -static BYTE stm32_spi_rw( BYTE out ) -{ - /* Loop while DR register in not empty */ - /// not needed: while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_TXE) == RESET) { ; } - - /* Send byte through the SPI peripheral */ - SPI_I2S_SendData(SD_SPI, out); - - /* Wait to receive a byte */ - while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_RXNE) == RESET) { ; } - - /* Return the byte read from the SPI bus */ - return SPI_I2S_ReceiveData(SD_SPI); -} - - - -/*-----------------------------------------------------------------------*/ -/* Transmit a byte to MMC via SPI (Platform dependent) */ -/*-----------------------------------------------------------------------*/ - -#define xmit_spi(dat) stm32_spi_rw(dat) - -/*-----------------------------------------------------------------------*/ -/* Receive a byte from MMC via SPI (Platform dependent) */ -/*-----------------------------------------------------------------------*/ - -static -BYTE rcvr_spi (void) -{ - return stm32_spi_rw(0xff); -} - -/* Alternative macro to receive data fast */ -#define rcvr_spi_m(dst) *(dst)=stm32_spi_rw(0xff) - - - -/*-----------------------------------------------------------------------*/ -/* Wait for card ready */ -/*-----------------------------------------------------------------------*/ -static BYTE wait_ready (void) -{ - BYTE res; - - Timer2 = 50; /* Wait for ready in timeout of 500ms */ - rcvr_spi(); - do { - res = rcvr_spi(); - } while ((res != 0xFF) && Timer2); - - return res; -} - -static void spi_reset() -{ - for (int n=0; n<520; ++n) { - stm32_spi_rw(0xFF); - } - TRACE_SD_CARD_EVENT(1, sd_spi_reset, 0); -} - -/*-----------------------------------------------------------------------*/ -/* Deselect the card and release SPI bus */ -/*-----------------------------------------------------------------------*/ - -static -void release_spi (void) -{ - SD_DESELECT(); - rcvr_spi(); - delay_us(100); -} - -#ifdef SD_USE_DMA - -#if defined(STM32F4) && !defined(BOOT) -WORD rw_workbyte[1] __DMA; -#endif - -/*-----------------------------------------------------------------------*/ -/* Transmit/Receive Block using DMA (Platform dependent. STM32 here) */ -/*-----------------------------------------------------------------------*/ -static -void stm32_dma_transfer( - BOOL receive, /* FALSE for buff->SPI, TRUE for SPI->buff */ - const BYTE *buff, /* receive TRUE : 512 byte data block to be transmitted - receive FALSE : Data buffer to store received data */ - UINT btr /* receive TRUE : Byte count (must be multiple of 2) - receive FALSE : Byte count (must be 512) */ -) -{ - DMA_InitTypeDef DMA_InitStructure; -#if defined(STM32F4) && !defined(BOOT) - rw_workbyte[0] = 0xffff; -#else - WORD rw_workbyte[] = { 0xffff }; -#endif - - DMA_DeInit(SD_DMA_Stream_SPI_RX); - DMA_DeInit(SD_DMA_Stream_SPI_TX); - - /* shared DMA configuration values between SPI2 RX & TX*/ - DMA_InitStructure.DMA_Channel = SD_DMA_Channel_SPI;//the same channel - DMA_InitStructure.DMA_PeripheralBaseAddr = (DWORD)(&(SD_SPI->DR)); - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_BufferSize = btr; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - - // separate RX & TX - if (receive) { - DMA_InitStructure.DMA_Memory0BaseAddr = (DWORD)buff; - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_Init(SD_DMA_Stream_SPI_RX, &DMA_InitStructure); - DMA_InitStructure.DMA_Memory0BaseAddr = (DWORD)rw_workbyte; - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; - DMA_Init(SD_DMA_Stream_SPI_TX, &DMA_InitStructure); - } - else { -#if _FS_READONLY == 0 - DMA_InitStructure.DMA_Memory0BaseAddr = (DWORD)rw_workbyte; - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; - DMA_Init(SD_DMA_Stream_SPI_RX, &DMA_InitStructure); - DMA_InitStructure.DMA_Memory0BaseAddr = (DWORD)buff; - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_Init(SD_DMA_Stream_SPI_TX, &DMA_InitStructure); -#endif - } - - /* Enable DMA Channels */ - DMA_Cmd(SD_DMA_Stream_SPI_RX, ENABLE); - DMA_Cmd(SD_DMA_Stream_SPI_TX, ENABLE); - - /* Enable SPI TX/RX request */ - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE); - - while (DMA_GetFlagStatus(SD_DMA_Stream_SPI_TX, SD_DMA_FLAG_SPI_TC_TX) == RESET) { ; } - while (DMA_GetFlagStatus(SD_DMA_Stream_SPI_RX, SD_DMA_FLAG_SPI_TC_RX) == RESET) { ; } - - /* Disable DMA Channels */ - DMA_Cmd(SD_DMA_Stream_SPI_RX, DISABLE); - DMA_Cmd(SD_DMA_Stream_SPI_TX, DISABLE); - - /* Disable SPI RX/TX request */ - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, DISABLE); -} -#endif /* SD_USE_DMA */ - - -/*-----------------------------------------------------------------------*/ -/* Power Control and interface-initialization (Platform dependent) */ -/*-----------------------------------------------------------------------*/ - -static -void power_on (void) -{ - SPI_InitTypeDef SPI_InitStructure; - GPIO_InitTypeDef GPIO_InitStructure; - volatile BYTE dummyread; - - card_power(1); - -#if defined(SD_PRESENT_GPIO) - GPIO_InitStructure.GPIO_Pin = SD_PRESENT_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure); -#endif - - for (uint32_t Timer = 25000; Timer>0;Timer--); /* Wait for 250ms */ - - /* Configure I/O for Flash Chip select */ - GPIO_InitStructure.GPIO_Pin = SD_GPIO_PIN_CS; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(SD_GPIO, &GPIO_InitStructure); - - /* De-select the Card: Chip Select high */ - SD_DESELECT(); - - /* Configure SPI pins: SCK MISO and MOSI with alternate function push-down */ - GPIO_InitStructure.GPIO_Pin = SD_GPIO_PIN_SCK | SD_GPIO_PIN_MOSI|SD_GPIO_PIN_MISO; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(SD_GPIO, &GPIO_InitStructure); - GPIO_PinAFConfig(SD_GPIO,SD_GPIO_PinSource_SCK ,SD_GPIO_AF); - GPIO_PinAFConfig(SD_GPIO,SD_GPIO_PinSource_MISO,SD_GPIO_AF); - GPIO_PinAFConfig(SD_GPIO,SD_GPIO_PinSource_MOSI,SD_GPIO_AF); - - /* SPI configuration */ - SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; - SPI_InitStructure.SPI_Mode = SPI_Mode_Master; - SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; - SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; - SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; - SPI_InitStructure.SPI_BaudRatePrescaler = SD_SPI_BaudRatePrescaler; - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; - SPI_InitStructure.SPI_CRCPolynomial = 7; - SPI_Init(SD_SPI, &SPI_InitStructure); - SPI_CalculateCRC(SD_SPI, DISABLE); - SPI_Cmd(SD_SPI, ENABLE); - - /* drain SPI */ - while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_TXE) == RESET) { ; } - dummyread = SPI_I2S_ReceiveData(SD_SPI); - - (void) dummyread; // Discard value - prevents compiler warning -} - -static -void power_off (void) -{ - GPIO_InitTypeDef GPIO_InitStructure; - - if (!(Stat & STA_NOINIT)) { - SD_SELECT(); - wait_ready(); - release_spi(); - } - - SPI_I2S_DeInit(SD_SPI); - SPI_Cmd(SD_SPI, DISABLE); - - //All SPI-Pins to input with weak internal pull-downs - GPIO_InitStructure.GPIO_Pin = SD_GPIO_PIN_SCK | SD_GPIO_PIN_MISO | SD_GPIO_PIN_MOSI; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; - GPIO_Init(SD_GPIO, &GPIO_InitStructure); - - card_power(0); - - Stat |= STA_NOINIT; /* Set STA_NOINIT */ -} - -/*-----------------------------------------------------------------------*/ -/* Receive a data packet from MMC */ -/*-----------------------------------------------------------------------*/ - -#if defined(SD_USE_DMA) && defined(STM32F4) && !defined(BOOT) - uint8_t sd_buff[512] __DMA; -#endif - -static -BOOL rcvr_datablock ( - BYTE *buff, /* Data buffer to store received data */ - UINT btr /* Byte count (must be multiple of 4) */ -) -{ - BYTE token; - - - Timer1 = 10; - do { /* Wait for data packet in timeout of 100ms */ - token = rcvr_spi(); - } while ((token == 0xFF) && Timer1); - if(token != 0xFE) { - TRACE_SD_CARD_EVENT(1, sd_rcvr_datablock, ((uint32_t)(Timer1) << 24) + ((uint32_t)(btr) << 8) + token); - spi_reset(); - return FALSE; /* If not valid data token, return with error */ - } - -#if defined(SD_USE_DMA) - #if defined(STM32F4) && !defined(BOOT) - if ((DWORD)buff < RAM_START || ((DWORD)buff & 3)) { - stm32_dma_transfer(TRUE, sd_buff, btr); - memcpy(buff, sd_buff, btr); - } else { - stm32_dma_transfer(TRUE, buff, btr); - } - #else - stm32_dma_transfer(TRUE, buff, btr); - #endif -#else - do { /* Receive the data block into buffer */ - rcvr_spi_m(buff++); - rcvr_spi_m(buff++); - rcvr_spi_m(buff++); - rcvr_spi_m(buff++); - } while (btr -= 4); -#endif /* SD_USE_DMA */ - - rcvr_spi(); /* Discard CRC */ - rcvr_spi(); - - return TRUE; /* Return with success */ -} - - - -/*-----------------------------------------------------------------------*/ -/* Send a data packet to MMC */ -/*-----------------------------------------------------------------------*/ - -#define DATA_RESPONSE_TIMEOUT 10 - -static -BOOL xmit_datablock ( - const BYTE *buff, /* 512 byte data block to be transmitted */ - BYTE token /* Data/Stop token */ -) -{ - BYTE resp; -#ifndef SD_USE_DMA - BYTE wc; -#endif - - if (wait_ready() != 0xFF) { - TRACE_SD_CARD_EVENT(1, sd_xmit_datablock_wait_ready, token); - spi_reset(); - return FALSE; - } - - xmit_spi(token); /* transmit data token */ - if (token != 0xFD) { /* Is data token */ - -#if defined(SD_USE_DMA) - #if defined(STM32F4) && !defined(BOOT) - if ((DWORD)buff < RAM_START || ((DWORD)buff & 3)) { - memcpy(sd_buff, buff, 512); - stm32_dma_transfer(FALSE, sd_buff, 512); - } else { - stm32_dma_transfer(FALSE, buff, 512); - } - #else - stm32_dma_transfer(FALSE, buff, 512); - #endif -#else - wc = 0; - do { /* transmit the 512 byte data block to MMC */ - xmit_spi(*buff++); - xmit_spi(*buff++); - } while (--wc); -#endif /* SD_USE_DMA */ - - xmit_spi(0xFF); /* CRC (Dummy) */ - xmit_spi(0xFF); - - /* - Despite what the SD card standard says, the reality is that (at least for some SD cards) - the Data Response byte does not come immediately after the last byte of data. - - This delay only happens very rarely, but it does happen. Typical response delay is some 10ms - */ - Timer2 = DATA_RESPONSE_TIMEOUT; - do { - resp = rcvr_spi(); /* Receive data response */ - if ((resp & 0x1F) == 0x05) { - TRACE_SD_CARD_EVENT((Timer2 != DATA_RESPONSE_TIMEOUT), sd_xmit_datablock_rcvr_spi, ((uint32_t)(Timer2) << 16) + ((uint32_t)(resp) << 8) + token); - return TRUE; - } - if (resp != 0xFF) { - TRACE_SD_CARD_EVENT(1, sd_xmit_datablock_rcvr_spi, ((uint32_t)(Timer2) << 16) + ((uint32_t)(resp) << 8) + token); - spi_reset(); - return FALSE; - } - } while (Timer2); - TRACE_SD_CARD_EVENT(1, sd_xmit_datablock_rcvr_spi, ((uint32_t)(Timer2) << 16) + ((uint32_t)(resp) << 8) + token); - return FALSE; - } - return TRUE; -} - - -/*-----------------------------------------------------------------------*/ -/* Send a command packet to MMC */ -/*-----------------------------------------------------------------------*/ - -static -BYTE send_cmd ( - BYTE cmd, /* Command byte */ - DWORD arg /* Argument */ -) -{ - BYTE n, res; - - - if (cmd & 0x80) { /* ACMD is the command sequence of CMD55-CMD */ - cmd &= 0x7F; - res = send_cmd(CMD55, 0); - if (res > 1) return res; - } - - /* Select the card and wait for ready */ - SD_SELECT(); - if (wait_ready() != 0xFF) { - TRACE_SD_CARD_EVENT(1, sd_send_cmd_wait_ready, cmd); - spi_reset(); - return 0xFF; - } - - /* Send command packet */ - xmit_spi(cmd); /* Start + Command index */ - xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ - xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ - xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ - xmit_spi((BYTE)arg); /* Argument[7..0] */ - n = 0x01; /* Dummy CRC + Stop */ - if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ - if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ - xmit_spi(n); - - /* Receive command response */ - if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */ - - n = 10; /* Wait for a valid response in timeout of 10 attempts */ - do { - res = rcvr_spi(); - } while ((res & 0x80) && --n); - - TRACE_SD_CARD_EVENT((res > 1), sd_send_cmd_rcvr_spi, ((uint32_t)(n) << 16) + ((uint32_t)(res) << 8) + cmd); - - return res; /* Return with the response value */ -} - - - -/*-------------------------------------------------------------------------- - - Public Functions - ----------------------------------------------------------------------------*/ - - -/*-----------------------------------------------------------------------*/ -/* Initialize Disk Drive */ -/*-----------------------------------------------------------------------*/ - -DSTATUS disk_initialize ( - BYTE drv /* Physical drive number (0) */ -) -{ - BYTE n, cmd, ty, ocr[4]; - - if (drv) return STA_NOINIT; /* Supports only single drive */ - if (Stat & STA_NODISK) return Stat; /* No card in the socket */ - - power_on(); /* Force socket power on and initialize interface */ - interface_speed(INTERFACE_SLOW); - for (n = 10; n; n--) rcvr_spi(); /* 80 dummy clocks */ - - ty = 0; - if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ - Timer1 = 100; /* Initialization timeout of 1000 milliseconds */ - if (send_cmd(CMD8, 0x1AA) == 1) { /* SDHC */ - for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 response */ - if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at VDD range of 2.7-3.6V */ - while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */ - if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ - for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); - ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; - } - } - } else { /* SDSC or MMC */ - if (send_cmd(ACMD41, 0) <= 1) { - ty = CT_SD1; cmd = ACMD41; /* SDSC */ - } else { - ty = CT_MMC; cmd = CMD1; /* MMC */ - } - while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */ - if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ - ty = 0; - } - } - CardType = ty; - release_spi(); - - if (ty) { /* Initialization succeeded */ - Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ - interface_speed(INTERFACE_FAST); - } - else { /* Initialization failed */ - power_off(); - } - - return Stat; -} - - - -/*-----------------------------------------------------------------------*/ -/* Get Disk Status */ -/*-----------------------------------------------------------------------*/ -DSTATUS disk_status ( - BYTE drv /* Physical drive number (0) */ -) -{ - if (drv) return STA_NOINIT; /* Supports only single drive */ - return Stat; -} - - -/*-----------------------------------------------------------------------*/ -/* Read Sector(s) */ -/*-----------------------------------------------------------------------*/ - -int8_t SD_ReadSectors(uint8_t * buff, uint32_t sector, uint32_t count) -{ - if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ - - if (count == 1) { /* Single block read */ - if (send_cmd(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */ - if (rcvr_datablock(buff, 512)) { - count = 0; - } - } - else { - spi_reset(); - } - } - else { /* Multiple block read */ - if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */ - do { - if (!rcvr_datablock(buff, 512)) { - break; - } - buff += 512; - } while (--count); - send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ - } - else { - spi_reset(); - } - } - release_spi(); - TRACE_SD_CARD_EVENT((count != 0), sd_SD_ReadSectors, (count << 24) + ((sector/((CardType & CT_BLOCK) ? 1 : 512)) & 0x00FFFFFF)); - - return count ? -1 : 0; -} - -DRESULT disk_read ( - BYTE drv, /* Physical drive number (0) */ - BYTE *buff, /* Pointer to the data buffer to store read data */ - DWORD sector, /* Start sector number (LBA) */ - UINT count /* Sector count (1..255) */ -) -{ - if (drv || !count) return RES_PARERR; - if (Stat & STA_NOINIT) return RES_NOTRDY; - int8_t res = SD_ReadSectors(buff, sector, count); - TRACE_SD_CARD_EVENT((res != 0), sd_disk_read, (count << 24) + (sector & 0x00FFFFFF)); - return (res != 0) ? RES_ERROR : RES_OK; -} - - - -/*-----------------------------------------------------------------------*/ -/* Write Sector(s) */ -/*-----------------------------------------------------------------------*/ - -int8_t SD_WriteSectors(const uint8_t * buff, uint32_t sector, uint32_t count) -{ - if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ - - if (count == 1) { /* Single block write */ - if (send_cmd(CMD24, sector) == 0) { /* WRITE_BLOCK */ - if (xmit_datablock(buff, 0xFE)) { - count = 0; - } - } - else { - spi_reset(); - } - } - else { /* Multiple block write */ - if (CardType & CT_SDC) send_cmd(ACMD23, count); - if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ - do { - if (!xmit_datablock(buff, 0xFC)) break; - buff += 512; - } while (--count); - if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ - count = 1; - } - else { - spi_reset(); - } - } - release_spi(); - TRACE_SD_CARD_EVENT((count != 0), sd_SD_WriteSectors, (count << 24) + ((sector/((CardType & CT_BLOCK) ? 1 : 512)) & 0x00FFFFFF)); - - return count ? -1 : 0; -} - -DRESULT disk_write ( - BYTE drv, /* Physical drive number (0) */ - const BYTE *buff, /* Pointer to the data to be written */ - DWORD sector, /* Start sector number (LBA) */ - UINT count /* Sector count (1..255) */ -) -{ - if (drv || !count) return RES_PARERR; - if (Stat & STA_NOINIT) return RES_NOTRDY; - if (Stat & STA_PROTECT) return RES_WRPRT; - int8_t res = SD_WriteSectors(buff, sector, count); - TRACE_SD_CARD_EVENT((res != 0), sd_disk_write, (count << 24) + (sector & 0x00FFFFFF)); - return (res != 0) ? RES_ERROR : RES_OK; -} - - -/*-----------------------------------------------------------------------*/ -/* Miscellaneous Functions */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_ioctl ( - BYTE drv, /* Physical drive number (0) */ - BYTE ctrl, /* Control code */ - void *buff /* Buffer to send/receive control data */ -) -{ - DRESULT res; - BYTE n, csd[16], *ptr = (BYTE *)buff; - WORD csize; - - if (drv) return RES_PARERR; - - res = RES_ERROR; - - if (ctrl == CTRL_POWER) { - switch (*ptr) { - case 0: /* Sub control code == 0 (POWER_OFF) */ - if (chk_power()) - power_off(); /* Power off */ - res = RES_OK; - break; - case 1: /* Sub control code == 1 (POWER_ON) */ - power_on(); /* Power on */ - res = RES_OK; - break; - case 2: /* Sub control code == 2 (POWER_GET) */ - *(ptr+1) = (BYTE)chk_power(); - res = RES_OK; - break; - default : - res = RES_PARERR; - } - } - else { - if (Stat & STA_NOINIT) { - return RES_NOTRDY; - } - - switch (ctrl) { - case CTRL_SYNC : /* Make sure that no pending write process */ - SD_SELECT(); - if (wait_ready() == 0xFF) { - res = RES_OK; - } - else { - TRACE_SD_CARD_EVENT(1, sd_disk_ioctl_CTRL_SYNC, 0); - } - break; - - case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ - if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { - if ((csd[0] >> 6) == 1) { /* SDC version 2.00 */ - csize = csd[9] + ((WORD)csd[8] << 8) + 1; - *(DWORD*)buff = (DWORD)csize << 10; - } - else { /* SDC version 1.XX or MMC*/ - n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; - csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; - *(DWORD*)buff = (DWORD)csize << (n - 9); - } - res = RES_OK; - } - else { - TRACE_SD_CARD_EVENT(1, sd_disk_ioctl_GET_SECTOR_COUNT, 0); - } - break; - - case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */ - *(WORD*)buff = 512; - res = RES_OK; - break; - - case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ - if (CardType & CT_SD2) { /* SDC version 2.00 */ - if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ - rcvr_spi(); - if (rcvr_datablock(csd, 16)) { /* Read partial block */ - for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */ - *(DWORD*)buff = 16UL << (csd[10] >> 4); - res = RES_OK; - } - } - } else { /* SDC version 1.XX or MMC */ - if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ - if (CardType & CT_SD1) { /* SDC version 1.XX */ - *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); - } else { /* MMC */ - *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); - } - res = RES_OK; - } - } - break; - - case MMC_GET_TYPE : /* Get card type flags (1 byte) */ - *ptr = CardType; - res = RES_OK; - break; - - case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */ - if (send_cmd(CMD9, 0) == 0 /* READ_CSD */ - && rcvr_datablock(ptr, 16)) { - res = RES_OK; - } - else { - TRACE_SD_CARD_EVENT(1, sd_disk_ioctl_MMC_GET_CSD, 0); - } - break; - - case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */ - if (send_cmd(CMD10, 0) == 0 /* READ_CID */ - && rcvr_datablock(ptr, 16)) { - res = RES_OK; - } - else { - TRACE_SD_CARD_EVENT(1, sd_disk_ioctl_MMC_GET_CID, 0); - } - break; - - case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */ - if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */ - for (n = 4; n; n--) *ptr++ = rcvr_spi(); - res = RES_OK; - } - else { - TRACE_SD_CARD_EVENT(1, sd_disk_ioctl_MMC_GET_OCR, 0); - } - break; - - case MMC_GET_SDSTAT : /* Receive SD status as a data block (64 bytes) */ - if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */ - rcvr_spi(); - if (rcvr_datablock(ptr, 64)) { - res = RES_OK; - } - else { - TRACE_SD_CARD_EVENT(1, sd_disk_ioctl_MMC_GET_SDSTAT_1, 0); - } - } - else { - TRACE_SD_CARD_EVENT(1, sd_disk_ioctl_MMC_GET_SDSTAT_2, 0); - } - break; - - default: - res = RES_PARERR; - } - - release_spi(); - } - - return res; -} - - -/*-----------------------------------------------------------------------*/ -/* Device Timer Interrupt Procedure (Platform dependent) */ -/*-----------------------------------------------------------------------*/ -/* This function must be called in period of 10ms */ - -void sdPoll10ms() -{ - static DWORD pv; - DWORD ns; - BYTE n, s; - - - n = Timer1; /* 100Hz decrement timers */ - if (n) Timer1 = --n; - n = Timer2; - if (n) Timer2 = --n; - - ns = pv; - pv = socket_is_empty() | socket_is_write_protected(); /* Sample socket switch */ - - if (ns == pv) { /* Have contacts stabled? */ - s = Stat; - - if (pv & socket_state_mask_wp) /* WP is H (write protected) */ - s |= STA_PROTECT; - else /* WP is L (write enabled) */ - s &= ~STA_PROTECT; - - if (pv & socket_state_mask_cp) /* INS = H (Socket empty) */ - s |= (STA_NODISK | STA_NOINIT); - else /* INS = L (Card inserted) */ - s &= ~STA_NODISK; - - Stat = s; - } -} - -uint32_t SD_GetCardType() -{ - return CardType; -} diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 1a4ca4678a8..168a70619b5 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -2575,41 +2575,32 @@ #endif // SD - SPI2 -#define SD_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1) -#define SD_RCC_APB1Periph RCC_APB1Periph_SPI2 #if defined(RADIO_T20) // Using chip, so no detect #else #define SD_PRESENT_GPIO GPIOD #if defined(PCBXLITE) || defined(PCBX9LITE) - #define SD_PRESENT_GPIO_PIN GPIO_Pin_10 // PD.10 + #define SD_PRESENT_GPIO_PIN LL_GPIO_PIN_10 // PD.10 #elif defined(RADIO_COMMANDO8) - #define SD_PRESENT_GPIO_PIN GPIO_Pin_8 // PD.08 + #define SD_PRESENT_GPIO_PIN LL_GPIO_PIN_8 // PD.08 #else - #define SD_PRESENT_GPIO_PIN GPIO_Pin_9 // PD.09 + #define SD_PRESENT_GPIO_PIN LL_GPIO_PIN_9 // PD.09 #endif #endif + +#define STORAGE_USE_SDCARD_SPI + #define SD_GPIO GPIOB -#define SD_GPIO_PIN_CS GPIO_Pin_12 // PB.12 -#define SD_GPIO_PIN_SCK GPIO_Pin_13 // PB.13 -#define SD_GPIO_PIN_MISO GPIO_Pin_14 // PB.14 -#define SD_GPIO_PIN_MOSI GPIO_Pin_15 // PB.15 -#define SD_GPIO_AF GPIO_AF_SPI2 -#define SD_GPIO_PinSource_CS GPIO_PinSource12 -#define SD_GPIO_PinSource_SCK GPIO_PinSource13 -#define SD_GPIO_PinSource_MISO GPIO_PinSource14 -#define SD_GPIO_PinSource_MOSI GPIO_PinSource15 +#define SD_GPIO_PIN_CS LL_GPIO_PIN_12 // PB.12 +#define SD_GPIO_PIN_SCK LL_GPIO_PIN_13 // PB.13 +#define SD_GPIO_PIN_MISO LL_GPIO_PIN_14 // PB.14 +#define SD_GPIO_PIN_MOSI LL_GPIO_PIN_15 // PB.15 + #define SD_SPI SPI2 -#define SD_SPI_BaudRatePrescaler SPI_BaudRatePrescaler_4 // 10.5<20MHZ, make sure < 20MHZ - -#if !defined(BOOT) - #define SD_USE_DMA // Enable the DMA for SD - #define SD_DMA_Stream_SPI_RX DMA1_Stream3 - #define SD_DMA_Stream_SPI_TX DMA1_Stream4 - #define SD_DMA_FLAG_SPI_TC_RX DMA_FLAG_TCIF3 - #define SD_DMA_FLAG_SPI_TC_TX DMA_FLAG_TCIF4 - #define SD_DMA_Channel_SPI DMA_Channel_0 -#endif +#define SD_SPI_DMA DMA1 +#define SD_SPI_DMA_RX_STREAM LL_DMA_STREAM_3 +#define SD_SPI_DMA_TX_STREAM LL_DMA_STREAM_4 +#define SD_SPI_DMA_CHANNEL LL_DMA_CHANNEL_0 // Audio #define AUDIO_RCC_APB1Periph (RCC_APB1Periph_TIM6 | RCC_APB1Periph_DAC) @@ -2818,6 +2809,8 @@ // 2MHz Timer #define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 #define TIMER_2MHz_TIMER TIM7 +#define TIMER_2MHz_IRQn TIM7_IRQn +#define TIMER_2MHz_IRQHandler TIM7_IRQHandler // Mixer scheduler timer #define MIXER_SCHEDULER_TIMER_RCC_APB1Periph RCC_APB1Periph_TIM12 diff --git a/radio/src/thirdparty/FatFs/diskio.h b/radio/src/thirdparty/FatFs/diskio.h index 1c8bba0425c..4b7d6113970 100644 --- a/radio/src/thirdparty/FatFs/diskio.h +++ b/radio/src/thirdparty/FatFs/diskio.h @@ -34,14 +34,6 @@ DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); -#if defined(DISK_CACHE) -DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count); -DRESULT __disk_write(BYTE drv, const BYTE * buff, DWORD sector, UINT count); -#else -#define __disk_read disk_read -#define __disk_write disk_write -#endif - /* Disk Status Bits (DSTATUS) */ #define STA_NOINIT 0x01 /* Drive not initialized */ diff --git a/radio/src/thirdparty/FatFs/fattime.c b/radio/src/thirdparty/FatFs/fattime.c deleted file mode 100644 index 0b1adf71d15..00000000000 --- a/radio/src/thirdparty/FatFs/fattime.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Authors (alphabetical order) - * - Andre Bernet - * - Andreas Weitl - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Gabriel Birkus - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - 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 "integer.h" -#include "../rtc.h" - -DWORD get_fattime(void) -{ - struct gtm t; - - gettime(&t); - - /* Pack date and time into a DWORD variable */ - return ((DWORD)(t.tm_year - 80) << 25) - | ((uint32_t)(t.tm_mon+1) << 21) - | ((uint32_t)t.tm_mday << 16) - | ((uint32_t)t.tm_hour << 11) - | ((uint32_t)t.tm_min << 5) - | ((uint32_t)t.tm_sec >> 1); -} diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c index d552a89ecc5..05ce9be3c1a 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.2.0/Libraries/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c @@ -147,7 +147,9 @@ int8_t SCSI_ProcessCmd(USB_OTG_CORE_HANDLE *pdev, return SCSI_StartStopUnit(lun, params); case SCSI_ALLOW_MEDIUM_REMOVAL: - return SCSI_AllowRemoval( lun, params); // ST lib 2.2.0 uses SCSI_StartStopUnit which doesn't work // modified by OpenTX + // Modified by OpenTX: + // ST lib 2.2.0 uses SCSI_StartStopUnit which doesn't work + return SCSI_AllowRemoval(lun, params); case SCSI_MODE_SENSE6: return SCSI_ModeSense6 (lun, params); @@ -436,16 +438,18 @@ void SCSI_SenseCode(uint8_t lun, uint8_t sKey, uint8_t ASC) extern uint8_t lunReady[]; // modified by OpenTX +#if defined(FWDRIVE) + #define _MAX_LUN 2 +#else + #define _MAX_LUN 1 +#endif + static int8_t SCSI_StartStopUnit(uint8_t lun, uint8_t *params) { MSC_BOT_DataLen = 0; - -#if defined(BOOT) // modified by OpenTX - if (lun < 2) -#else - if (lun < 1) -#endif - { + + /* modified by OpenTX */ + if (lun < _MAX_LUN) { if (params[4] & 1) { // lun to be active lunReady[lun] = 1 ; diff --git a/radio/util/hw_defs/hal_adc.py b/radio/util/hw_defs/hal_adc.py index d2b996b1479..4cd52b853f7 100644 --- a/radio/util/hw_defs/hal_adc.py +++ b/radio/util/hw_defs/hal_adc.py @@ -176,7 +176,6 @@ def _parse_adcs(self): adc.gpio_pin_mosi = self.hw_defs['ADC_SPI_GPIO_PIN_MOSI'] adc.gpio_pin_sck = self.hw_defs['ADC_SPI_GPIO_PIN_SCK'] adc.gpio_pin_cs = self.hw_defs['ADC_SPI_GPIO_PIN_CS'] - adc.gpio_af = self.hw_defs['ADC_SPI_GPIO_AF'] adcs.append(adc) adc_main = self._parse_adc('MAIN', 'ADC_MAIN', 'ADC') diff --git a/radio/util/hw_defs/stm32_adc_inputs.jinja b/radio/util/hw_defs/stm32_adc_inputs.jinja index 3fc0d0dfd74..b30ce7d2c2c 100644 --- a/radio/util/hw_defs/stm32_adc_inputs.jinja +++ b/radio/util/hw_defs/stm32_adc_inputs.jinja @@ -49,11 +49,13 @@ static const stm32_spi_adc_t _ADC_spi[] = { {% set inputs = adc_inputs.inputs | selectattr('adc', '==', adc.name) | selectattr('channel','defined') %} {% set input_count = inputs | list | count %} { - {{ adc.adc }}, - {{ adc.gpio }}, - {{ adc.gpio_pin_miso }} | {{ adc.gpio_pin_mosi }} | {{ adc.gpio_pin_sck }}, - {{ adc.gpio_af }}, - {{ adc.gpio_pin_cs }}, + .spi = { + {{ adc.adc }}, + {{ adc.gpio }}, + {{ adc.gpio_pin_miso }} | {{ adc.gpio_pin_mosi }} | {{ adc.gpio_pin_sck }}, + {{ adc.gpio }}, + {{ adc.gpio_pin_cs }}, + }, _ADC_{{ adc.name }}_channels, {{ input_count }} }, From bb7deefc4f23b0c3c950b1adbce70ccad2a350ed Mon Sep 17 00:00:00 2001 From: philmoz Date: Sun, 24 Sep 2023 10:43:42 +1000 Subject: [PATCH 22/29] fix(radio): Size of fields on sensor edit page for portrait layout (#4096) --- radio/src/gui/colorlcd/model_telemetry.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/radio/src/gui/colorlcd/model_telemetry.cpp b/radio/src/gui/colorlcd/model_telemetry.cpp index 74879353dfa..5c6ac08100e 100644 --- a/radio/src/gui/colorlcd/model_telemetry.cpp +++ b/radio/src/gui/colorlcd/model_telemetry.cpp @@ -604,13 +604,21 @@ class SensorEditWindow : public Page { paramLines[P_ID] = form->newLine(&grid2); new StaticText(paramLines[P_ID], rect_t{}, STR_ID, 0, COLOR_THEME_PRIMARY1); - auto hex = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xFFFF, GET_SET_DEFAULT(sensor->id)); - hex->setDisplayHandler([](int32_t value) { + auto num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xFFFF, GET_SET_DEFAULT(sensor->id)); +#if LCD_H > LCD_W + // Portrait layout - need to limit width of edit box + num->setWidth((lv_pct(28))); +#endif + num->setDisplayHandler([](int32_t value) { std::stringstream stream; stream << std::hex << value; return stream.str(); }); - new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xff, GET_SET_DEFAULT(sensor->instance)); + num = new NumberEdit(paramLines[P_ID], rect_t{}, 0, 0xff, GET_SET_DEFAULT(sensor->instance)); +#if LCD_H > LCD_W + // Portrait layout - need to limit width of edit box + num->setWidth(lv_pct(28)); +#endif paramLines[P_UNIT] = form->newLine(&grid); new StaticText(paramLines[P_UNIT], rect_t{}, STR_UNIT, 0, COLOR_THEME_PRIMARY1); From c502dbeaee53855d06613ad4612889164b2959a9 Mon Sep 17 00:00:00 2001 From: philmoz Date: Sun, 24 Sep 2023 14:18:11 +1000 Subject: [PATCH 23/29] chore(radio): Reduce size of the data structures in FLASH storage (#3979) * Reduce size of the YamlNode structure in FLASH storage. Fix compiler warning. * Further reduction of FLASH used by YamlNode structures. * Reduce size of sensor definition arrays and audio tone volumes array. --- radio/src/audio.cpp | 2 +- .../storage/yaml/yaml_datastructs_funcs.cpp | 2 +- radio/src/storage/yaml/yaml_node.h | 76 ++--- radio/src/storage/yaml/yaml_tree_walker.cpp | 24 +- radio/src/telemetry/crossfire.cpp | 66 ++-- radio/src/telemetry/crossfire.h | 2 +- radio/src/telemetry/flysky_ibus.cpp | 99 +++--- radio/src/telemetry/frsky_d.cpp | 48 +-- radio/src/telemetry/frsky_sport.cpp | 146 +++++---- radio/src/telemetry/ghost.cpp | 56 ++-- radio/src/telemetry/hitec.cpp | 60 ++-- radio/src/telemetry/hott.cpp | 116 +++---- radio/src/telemetry/mlink.cpp | 42 +-- radio/src/telemetry/spektrum.cpp | 308 +++++++++--------- 14 files changed, 532 insertions(+), 515 deletions(-) diff --git a/radio/src/audio.cpp b/radio/src/audio.cpp index c8fbc65bf14..f53eaf4095f 100644 --- a/radio/src/audio.cpp +++ b/radio/src/audio.cpp @@ -637,7 +637,7 @@ int WavContext::mixBuffer(AudioBuffer *buffer, int volume, unsigned int fade) } #endif -const unsigned int toneVolumes[] = { 10, 8, 6, 4, 2 }; +const uint8_t toneVolumes[] = { 10, 8, 6, 4, 2 }; inline float evalVolumeRatio(int freq, int volume) { float result = toneVolumes[2+volume]; diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index ea5bc9b6b23..33d88b46ae5 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -2162,7 +2162,7 @@ static void r_serialMode(void* user, uint8_t* data, uint32_t bitoffs, auto tw = reinterpret_cast(user); auto node = tw->getAttr(); - if (!node || node->tag_len < 4) return; + if (!node || node->tag_len() < 4) return; uint8_t port_nr; if (node->tag[3] == 'S') diff --git a/radio/src/storage/yaml/yaml_node.h b/radio/src/storage/yaml/yaml_node.h index 1eed24cb1f7..c5a43a7d0e0 100644 --- a/radio/src/storage/yaml/yaml_node.h +++ b/radio/src/storage/yaml/yaml_node.h @@ -74,18 +74,15 @@ struct YamlNode typedef bool (*cust_write_func)(void* user, uint8_t* data, uint32_t bitoffs, yaml_writer_func wf, void* opaque); - uint8_t type; - uint32_t size; // bits - uint8_t tag_len; + uint16_t size; // bits + uint8_t type:4; + uint16_t elmts:12; // maximum number of array elements const char* tag; union { struct { const YamlNode* child; union { - struct { - is_active_func is_active; - uint16_t elmts; // maximum number of elements - } _a; + is_active_func is_active; select_member_func select_member; } u; } _array; @@ -109,105 +106,108 @@ struct YamlNode cust_write_func write; } _cust_attr; } u; + + uint8_t tag_len() const { return tag ? strlen(tag) : 0; } }; #if !defined(_MSC_VER) + #define YAML_TAG(str) \ - .tag_len=(sizeof(str)-1), .tag=(str) + .tag=(str) #define YAML_IDX \ - { .type=YDT_IDX, .size=0, YAML_TAG("idx") } + { .size=0, .type=YDT_IDX, 0, YAML_TAG("idx") } #define YAML_IDX_CUST(tag, f_read, f_write) \ - { .type=YDT_IDX, .size=0, YAML_TAG(tag), .u={._cust_idx={.read=(f_read), .write=(f_write) }} } + { .size=0, .type=YDT_IDX, 0, YAML_TAG(tag), .u={._cust_idx={.read=(f_read), .write=(f_write) }} } #define YAML_SIGNED(tag, bits) \ - { .type=YDT_SIGNED, .size=(bits), YAML_TAG(tag) } + { .size=(bits), .type=YDT_SIGNED, 0, YAML_TAG(tag) } #define YAML_UNSIGNED(tag, bits) \ - { .type=YDT_UNSIGNED, .size=(bits), YAML_TAG(tag) } + { .size=(bits), .type=YDT_UNSIGNED, 0, YAML_TAG(tag) } #define YAML_SIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \ - { .type=YDT_SIGNED, .size=(bits), YAML_TAG(tag), .u={._cust={ .cust_to_uint=f_cust_to_uint, .uint_to_cust=f_uint_to_cust }} } + { .size=(bits), .type=YDT_SIGNED, 0, YAML_TAG(tag), .u={._cust={ .cust_to_uint=f_cust_to_uint, .uint_to_cust=f_uint_to_cust }} } #define YAML_UNSIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \ - { .type=YDT_UNSIGNED, .size=(bits), YAML_TAG(tag), .u={._cust={ .cust_to_uint=f_cust_to_uint, .uint_to_cust=f_uint_to_cust }} } + { .size=(bits), .type=YDT_UNSIGNED, 0, YAML_TAG(tag), .u={._cust={ .cust_to_uint=f_cust_to_uint, .uint_to_cust=f_uint_to_cust }} } #define YAML_STRING(tag, max_len) \ - { .type=YDT_STRING, .size=((max_len)<<3), YAML_TAG(tag) } + { .size=((max_len)<<3), .type=YDT_STRING, 0, YAML_TAG(tag) } #define YAML_STRUCT(tag, bits, nodes, f_is_active) \ - { .type=YDT_ARRAY, .size=(bits), YAML_TAG(tag), .u={._array={ .child=(nodes), .u={ ._a={.is_active=(f_is_active), .elmts=1 }}}} } + { .size=(bits), .type=YDT_ARRAY, .elmts=1, YAML_TAG(tag), .u={._array={ .child=(nodes), .u={.is_active=(f_is_active)}}} } #define YAML_ARRAY(tag, bits, max_elmts, nodes, f_is_active) \ - { .type=YDT_ARRAY, .size=(bits), YAML_TAG(tag), .u={._array={ .child=(nodes), .u={ ._a={.is_active=(f_is_active), .elmts=(max_elmts) }}}} } + { .size=(bits), .type=YDT_ARRAY, .elmts=(max_elmts), YAML_TAG(tag), .u={._array={ .child=(nodes), .u={.is_active=(f_is_active)}}} } #define YAML_ENUM(tag, bits, id_strs) \ - { .type=YDT_ENUM, .size=(bits), YAML_TAG(tag), .u={._enum={ .choices=(id_strs) }} } + { .size=(bits), .type=YDT_ENUM, 0, YAML_TAG(tag), .u={._enum={ .choices=(id_strs) }} } #define YAML_UNION(tag, bits, nodes, f_sel_m) \ - { .type=YDT_UNION, .size=(bits), YAML_TAG(tag), .u={._array={ .child=(nodes), .u={.select_member=(f_sel_m) }}} } + { .size=(bits), .type=YDT_UNION, 0, YAML_TAG(tag), .u={._array={ .child=(nodes), .u={.select_member=(f_sel_m) }}} } #define YAML_PADDING(bits) \ - { .type=YDT_PADDING, .size=(bits) } + { .size=(bits), .type=YDT_PADDING } #define YAML_CUSTOM(tag, f_read, f_write) \ - { .type=YDT_CUSTOM, .size=0, YAML_TAG(tag), .u={._cust_attr={.read=(f_read), .write=(f_write) }} } + { .size=0, .type=YDT_CUSTOM, 0, YAML_TAG(tag), .u={._cust_attr={.read=(f_read), .write=(f_write) }} } #define YAML_END \ - { .type=YDT_NONE } + { .size=0, .type=YDT_NONE } #define YAML_ROOT(nodes) \ - { .type=YDT_ARRAY, .size=0, .tag_len=0, .tag=NULL, \ + { .size=0, .type=YDT_ARRAY, .elmts=1, .tag=NULL, \ .u={ \ ._array={ .child=(nodes), \ - .u={._a={.is_active=NULL, .elmts=1 }} \ + .u={.is_active=NULL} \ }} \ } #else // MSVC++ compat #define YAML_TAG(str) \ - (sizeof(str)-1), (str) + (str) #define YAML_IDX \ - { YDT_IDX , 0, YAML_TAG("idx") } + { 0, YDT_IDX, 0, YAML_TAG("idx") } #define YAML_SIGNED(tag, bits) \ - { YDT_SIGNED, (bits), YAML_TAG(tag) } + { (bits), YDT_SIGNED, 0, YAML_TAG(tag) } #define YAML_UNSIGNED(tag, bits) \ - { YDT_UNSIGNED, (bits), YAML_TAG(tag) } + { (bits), YDT_UNSIGNED, 0, YAML_TAG(tag) } #define YAML_SIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \ - { YDT_SIGNED, (bits), YAML_TAG(tag), {{ (const YamlNode*)f_cust_to_uint, {{ (YamlNode::is_active_func)f_uint_to_cust, 0 }}}} } + { (bits), YDT_SIGNED, 0, YAML_TAG(tag), {{ (const YamlNode*)f_cust_to_uint, {{ (YamlNode::is_active_func)f_uint_to_cust, 0 }}}} } #define YAML_UNSIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \ - { YDT_UNSIGNED, (bits), YAML_TAG(tag), {{ (const YamlNode*)f_cust_to_uint, {{ (YamlNode::is_active_func)f_uint_to_cust, 0}}}} } + { (bits), YDT_UNSIGNED, 0, YAML_TAG(tag), {{ (const YamlNode*)f_cust_to_uint, {{ (YamlNode::is_active_func)f_uint_to_cust, 0}}}} } #define YAML_STRING(tag, max_len) \ - { YDT_STRING, ((max_len)<<3), YAML_TAG(tag) } + { ((max_len)<<3), YDT_STRING, 0, YAML_TAG(tag) } #define YAML_STRUCT(tag, bits, nodes, f_is_active) \ - { YDT_ARRAY, (bits), YAML_TAG(tag), {{ (nodes), {{ (f_is_active), 1 }}}} } + { (bits), YDT_ARRAY, 1, YAML_TAG(tag), {{ (nodes), {{ (f_is_active) }}}} } #define YAML_ARRAY(tag, bits, max_elmts, nodes, f_is_active) \ - { YDT_ARRAY, (bits), YAML_TAG(tag), {{ (nodes), {{ (f_is_active), (max_elmts) }}}} } + { (bits), YDT_ARRAY, (max_elmts), YAML_TAG(tag), {{ (nodes), {{ (f_is_active) }}}} } #define YAML_ENUM(tag, bits, id_strs) \ - { YDT_ENUM, (bits), YAML_TAG(tag), {{ (const YamlNode*)(id_strs) }} } + { (bits), YDT_ENUM, 0, YAML_TAG(tag), {{ (const YamlNode*)(id_strs) }} } #define YAML_UNION(tag, bits, nodes, f_sel_m) \ - { YDT_UNION, (bits), YAML_TAG(tag), {{ (nodes), {{ (YamlNode::is_active_func)(f_sel_m), 0 }}}} } + { (bits), YDT_UNION, 0, YAML_TAG(tag), {{ (nodes), {{ (YamlNode::is_active_func)(f_sel_m) }}}} } #define YAML_PADDING(bits) \ - { YDT_PADDING, (bits) } + { (bits), YDT_PADDING } #define YAML_END \ - { YDT_NONE } + { 0, YDT_NONE } #define YAML_ROOT(nodes) \ - { YDT_ARRAY, 0, 0, NULL, {{ (nodes), {{ NULL, 1 }}}} } + { 0, YDT_ARRAY, 1, NULL, {{ (nodes), {{ NULL }}}} } #endif diff --git a/radio/src/storage/yaml/yaml_tree_walker.cpp b/radio/src/storage/yaml/yaml_tree_walker.cpp index 235bf68bd20..d13c7422b5d 100644 --- a/radio/src/storage/yaml/yaml_tree_walker.cpp +++ b/radio/src/storage/yaml/yaml_tree_walker.cpp @@ -19,14 +19,14 @@ * GNU General Public License for more details. */ +#include + #include "debug.h" #include "yaml_node.h" #include "yaml_bits.h" #include "yaml_tree_walker.h" #include "yaml_parser.h" -#include - #define MIN(a,b) (a < b ? a : b) static void copy_string(char* dst, uint16_t dst_len, const char* src, @@ -146,7 +146,7 @@ static bool yaml_output_attr(void* user, uint8_t* ptr, uint32_t bit_ofs, if (node->type == YDT_CUSTOM && !node->u._cust_attr.write) return true; // output tag - if (!wf(opaque, node->tag, node->tag_len)) return false; + if (!wf(opaque, node->tag, node->tag_len())) return false; if (!wf(opaque, ": ", 2)) return false; @@ -268,7 +268,7 @@ bool YamlTreeWalker::findNode(const char* tag, uint8_t tag_len) while(attr && attr->type != YDT_NONE) { - if ((tag_len == attr->tag_len) + if ((tag_len == attr->tag_len()) && !strncmp(tag, attr->tag, tag_len)) { return true; // attribute found! } @@ -312,7 +312,7 @@ bool YamlTreeWalker::toChild() bool is_array = false; if (attr->type == YDT_ARRAY - && attr->u._array.u._a.elmts > 1) { + && attr->elmts > 1) { is_array = true; } @@ -333,7 +333,7 @@ bool YamlTreeWalker::toChild() if (!attr) return false; - if ((attr->type == YDT_UNION) && (attr->tag_len == 0)) { + if ((attr->type == YDT_UNION) && (attr->tag_len() == 0)) { toChild(); anon_union++; } @@ -359,7 +359,7 @@ bool YamlTreeWalker::toNextElmt() setElmts(0); } - if (getElmts() < node->u._array.u._a.elmts - 1) { + if (getElmts() < node->elmts - 1) { incElmts(); rewind(); } else { @@ -388,8 +388,8 @@ bool YamlTreeWalker::isElmtEmpty(uint8_t* data) + getLevelOfs(); // assume structs aligned on 8bit boundaries - if (node->u._array.u._a.is_active) - return !node->u._array.u._a.is_active(this, data, bit_ofs); + if (node->u._array.u.is_active) + return !node->u._array.u.is_active(this, data, bit_ofs); return yaml_is_zero(data, bit_ofs, node->size); } @@ -417,7 +417,7 @@ void YamlTreeWalker::toNextAttr() uint32_t attr_bit_ofs = getAttrOfs(); if (attr->type == YDT_ARRAY) - attr_bit_ofs += ((uint32_t)attr->u._array.u._a.elmts * attr->size); + attr_bit_ofs += ((uint32_t)attr->elmts * attr->size); else attr_bit_ofs += attr->size; @@ -428,7 +428,7 @@ void YamlTreeWalker::toNextAttr() // anonymous union handling attr = getAttr(); - if ((attr->type == YDT_UNION) && (attr->tag_len == 0)) { + if ((attr->type == YDT_UNION) && (strlen(attr->tag) == 0)) { toChild(); anon_union++; } @@ -457,7 +457,7 @@ void YamlTreeWalker::setAttrValue(char* buf, uint16_t len) i = yaml_str2uint(buf, len); const YamlNode* node = getNode(); - if (i < node->u._array.u._a.elmts) { + if (i < node->elmts) { setElmts(i); rewind(); } else { diff --git a/radio/src/telemetry/crossfire.cpp b/radio/src/telemetry/crossfire.cpp index 15347a286cb..c0320a1b401 100644 --- a/radio/src/telemetry/crossfire.cpp +++ b/radio/src/telemetry/crossfire.cpp @@ -23,39 +23,41 @@ #include "opentx.h" +#define CS(id,subId,name,unit,precision) {id,subId,unit,precision,name} + const CrossfireSensor crossfireSensors[] = { - {LINK_ID, 0, STR_SENSOR_RX_RSSI1, UNIT_DB, 0}, - {LINK_ID, 1, STR_SENSOR_RX_RSSI2, UNIT_DB, 0}, - {LINK_ID, 2, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0}, - {LINK_ID, 3, STR_SENSOR_RX_SNR, UNIT_DB, 0}, - {LINK_ID, 4, STR_SENSOR_ANTENNA, UNIT_RAW, 0}, - {LINK_ID, 5, STR_SENSOR_RF_MODE, UNIT_RAW, 0}, - {LINK_ID, 6, STR_SENSOR_TX_POWER, UNIT_MILLIWATTS, 0}, - {LINK_ID, 7, STR_SENSOR_TX_RSSI, UNIT_DB, 0}, - {LINK_ID, 8, STR_SENSOR_TX_QUALITY, UNIT_PERCENT, 0}, - {LINK_ID, 9, STR_SENSOR_TX_SNR, UNIT_DB, 0}, - {LINK_RX_ID, 0, STR_SENSOR_RX_RSSI_PERC, UNIT_PERCENT, 0}, - {LINK_RX_ID, 1, STR_SENSOR_RX_RF_POWER, UNIT_DBM, 0}, - {LINK_TX_ID, 0, STR_SENSOR_TX_RSSI_PERC, UNIT_PERCENT, 0}, - {LINK_TX_ID, 1, STR_SENSOR_TX_POWER, UNIT_DBM, 0}, - {LINK_TX_ID, 2, STR_SENSOR_TX_FPS, UNIT_HERTZ, 0}, - {BATTERY_ID, 0, STR_SENSOR_BATT, UNIT_VOLTS, 1}, - {BATTERY_ID, 1, STR_SENSOR_CURR, UNIT_AMPS, 1}, - {BATTERY_ID, 2, STR_SENSOR_CAPACITY, UNIT_MAH, 0}, - {BATTERY_ID, 3, STR_SENSOR_BATT_PERCENT, UNIT_PERCENT, 0}, - {GPS_ID, 0, STR_SENSOR_GPS, UNIT_GPS_LATITUDE, 0}, - {GPS_ID, 0, STR_SENSOR_GPS, UNIT_GPS_LONGITUDE, 0}, - {GPS_ID, 2, STR_SENSOR_GSPD, UNIT_KMH, 1}, - {GPS_ID, 3, STR_SENSOR_HDG, UNIT_DEGREE, 2}, - {GPS_ID, 4, STR_SENSOR_ALT, UNIT_METERS, 0}, - {GPS_ID, 5, STR_SENSOR_SATELLITES, UNIT_RAW, 0}, - {ATTITUDE_ID, 0, STR_SENSOR_PITCH, UNIT_RADIANS, 3}, - {ATTITUDE_ID, 1, STR_SENSOR_ROLL, UNIT_RADIANS, 3}, - {ATTITUDE_ID, 2, STR_SENSOR_YAW, UNIT_RADIANS, 3}, - {FLIGHT_MODE_ID, 0, STR_SENSOR_FLIGHT_MODE, UNIT_TEXT, 0}, - {CF_VARIO_ID, 0, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2}, - {BARO_ALT_ID, 0, STR_SENSOR_ALT, UNIT_METERS, 2}, - {0, 0, "UNKNOWN", UNIT_RAW, 0}, + CS(LINK_ID, 0, STR_SENSOR_RX_RSSI1, UNIT_DB, 0), + CS(LINK_ID, 1, STR_SENSOR_RX_RSSI2, UNIT_DB, 0), + CS(LINK_ID, 2, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0), + CS(LINK_ID, 3, STR_SENSOR_RX_SNR, UNIT_DB, 0), + CS(LINK_ID, 4, STR_SENSOR_ANTENNA, UNIT_RAW, 0), + CS(LINK_ID, 5, STR_SENSOR_RF_MODE, UNIT_RAW, 0), + CS(LINK_ID, 6, STR_SENSOR_TX_POWER, UNIT_MILLIWATTS, 0), + CS(LINK_ID, 7, STR_SENSOR_TX_RSSI, UNIT_DB, 0), + CS(LINK_ID, 8, STR_SENSOR_TX_QUALITY, UNIT_PERCENT, 0), + CS(LINK_ID, 9, STR_SENSOR_TX_SNR, UNIT_DB, 0), + CS(LINK_RX_ID, 0, STR_SENSOR_RX_RSSI_PERC, UNIT_PERCENT, 0), + CS(LINK_RX_ID, 1, STR_SENSOR_RX_RF_POWER, UNIT_DBM, 0), + CS(LINK_TX_ID, 0, STR_SENSOR_TX_RSSI_PERC, UNIT_PERCENT, 0), + CS(LINK_TX_ID, 1, STR_SENSOR_TX_POWER, UNIT_DBM, 0), + CS(LINK_TX_ID, 2, STR_SENSOR_TX_FPS, UNIT_HERTZ, 0), + CS(BATTERY_ID, 0, STR_SENSOR_BATT, UNIT_VOLTS, 1), + CS(BATTERY_ID, 1, STR_SENSOR_CURR, UNIT_AMPS, 1), + CS(BATTERY_ID, 2, STR_SENSOR_CAPACITY, UNIT_MAH, 0), + CS(BATTERY_ID, 3, STR_SENSOR_BATT_PERCENT, UNIT_PERCENT, 0), + CS(GPS_ID, 0, STR_SENSOR_GPS, UNIT_GPS_LATITUDE, 0), + CS(GPS_ID, 0, STR_SENSOR_GPS, UNIT_GPS_LONGITUDE, 0), + CS(GPS_ID, 2, STR_SENSOR_GSPD, UNIT_KMH, 1), + CS(GPS_ID, 3, STR_SENSOR_HDG, UNIT_DEGREE, 2), + CS(GPS_ID, 4, STR_SENSOR_ALT, UNIT_METERS, 0), + CS(GPS_ID, 5, STR_SENSOR_SATELLITES, UNIT_RAW, 0), + CS(ATTITUDE_ID, 0, STR_SENSOR_PITCH, UNIT_RADIANS, 3), + CS(ATTITUDE_ID, 1, STR_SENSOR_ROLL, UNIT_RADIANS, 3), + CS(ATTITUDE_ID, 2, STR_SENSOR_YAW, UNIT_RADIANS, 3), + CS(FLIGHT_MODE_ID, 0, STR_SENSOR_FLIGHT_MODE, UNIT_TEXT, 0), + CS(CF_VARIO_ID, 0, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2), + CS(BARO_ALT_ID, 0, STR_SENSOR_ALT, UNIT_METERS, 2), + CS(0, 0, "UNKNOWN", UNIT_RAW, 0), }; const CrossfireSensor & getCrossfireSensor(uint8_t id, uint8_t subId) diff --git a/radio/src/telemetry/crossfire.h b/radio/src/telemetry/crossfire.h index 957ffb7676e..77e4d8889aa 100644 --- a/radio/src/telemetry/crossfire.h +++ b/radio/src/telemetry/crossfire.h @@ -54,9 +54,9 @@ struct CrossfireSensor { const uint8_t id; const uint8_t subId; - const char * name; const TelemetryUnit unit; const uint8_t precision; + const char * name; }; enum CrossfireSensorIndexes { diff --git a/radio/src/telemetry/flysky_ibus.cpp b/radio/src/telemetry/flysky_ibus.cpp index de03fa88dbb..296562ac8ab 100644 --- a/radio/src/telemetry/flysky_ibus.cpp +++ b/radio/src/telemetry/flysky_ibus.cpp @@ -37,9 +37,9 @@ struct FlySkySensor { const uint16_t type; - const char * name; const TelemetryUnit unit; const uint8_t precision; + const char * name; }; // telemetry sensors type @@ -144,59 +144,60 @@ enum AFHDS2A_ID_END = 0xFF, }; +#define FS(type,name,unit,precision) {type,unit,precision,name} const FlySkySensor flySkySensors[] = { // flysky start - { SENSOR_TYPE_RX_VOL, STR_SENSOR_A1, UNIT_VOLTS, 2 }, // RX Voltage (remapped, really 0x0) - { SENSOR_TYPE_TEMPERATURE, STR_SENSOR_TEMP1, UNIT_CELSIUS, 1 }, // Temperature - { SENSOR_TYPE_MOT, STR_SENSOR_RPM, UNIT_RAW, 0 }, // RPM - { SENSOR_TYPE_EXT_VOL, STR_SENSOR_A3, UNIT_VOLTS, 2 }, // External voltage - { SENSOR_TYPE_BVD, "BVD", UNIT_VOLTS, 2 }, // BVD - { SENSOR_TYPE_GYROSCOPE_1_AXIS, STR_SENSOR_CELLS, UNIT_DEGREE, 1 }, // - { SENSOR_TYPE_PRES, STR_SENSOR_PRES, UNIT_RAW, 2 }, // 4 bytes In fact Temperature + Pressure -> Altitude - { SENSOR_TYPE_ALT, STR_SENSOR_ALT, UNIT_METERS, 2 }, - { SENSOR_TYPE_RF_MODULE_TEMP, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0 }, // 1 bytes temperature - { SENSOR_TYPE_RF_MODULE_VOL, STR_SENSOR_TXV, UNIT_VOLTS, 2 }, // 2 bytes voltage - { SENSOR_TYPE_RF_MODULE_POWER, STR_SENSOR_TX_POWER, UNIT_DBM, 0 }, // 2 bytes DBM -// { SENSOR_TYPE_RF_MODULE_RAW, STR_SENSOR_TX_POWER, UNIT_RAW, 0 }, // 2 bytes DBM - { SENSOR_TYPE_TX_V, STR_SENSOR_TXV, UNIT_VOLTS, 2 }, // TX Voltage - { SENSOR_TYPE_RX_SNR, STR_SENSOR_RX_SNR, UNIT_DB, 0 }, // RX SNR - { SENSOR_TYPE_RX_NOISE, STR_SENSOR_RX_NOISE, UNIT_DBM, 0 }, // RX Noise - { SENSOR_TYPE_RX_RSSI, STR_SENSOR_RSSI, UNIT_DBM, 0 }, // RX RSSI (0xfc) - { SENSOR_TYPE_RX_ERR_RATE, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0 }, // RX error rate + FS( SENSOR_TYPE_RX_VOL, STR_SENSOR_A1, UNIT_VOLTS, 2 ), // RX Voltage (remapped, really 0x0) + FS( SENSOR_TYPE_TEMPERATURE, STR_SENSOR_TEMP1, UNIT_CELSIUS, 1 ), // Temperature + FS( SENSOR_TYPE_MOT, STR_SENSOR_RPM, UNIT_RAW, 0 ), // RPM + FS( SENSOR_TYPE_EXT_VOL, STR_SENSOR_A3, UNIT_VOLTS, 2 ), // External voltage + FS( SENSOR_TYPE_BVD, "BVD", UNIT_VOLTS, 2 ), // BVD + FS( SENSOR_TYPE_GYROSCOPE_1_AXIS, STR_SENSOR_CELLS, UNIT_DEGREE, 1 ), // + FS( SENSOR_TYPE_PRES, STR_SENSOR_PRES, UNIT_RAW, 2 ), // 4 bytes In fact Temperature + Pressure -> Altitude + FS( SENSOR_TYPE_ALT, STR_SENSOR_ALT, UNIT_METERS, 2 ), + FS( SENSOR_TYPE_RF_MODULE_TEMP, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0 ), // 1 bytes temperature + FS( SENSOR_TYPE_RF_MODULE_VOL, STR_SENSOR_TXV, UNIT_VOLTS, 2 ), // 2 bytes voltage + FS( SENSOR_TYPE_RF_MODULE_POWER, STR_SENSOR_TX_POWER, UNIT_DBM, 0 ), // 2 bytes DBM +// FS( SENSOR_TYPE_RF_MODULE_RAW, STR_SENSOR_TX_POWER, UNIT_RAW, 0 ), // 2 bytes DBM + FS( SENSOR_TYPE_TX_V, STR_SENSOR_TXV, UNIT_VOLTS, 2 ), // TX Voltage + FS( SENSOR_TYPE_RX_SNR, STR_SENSOR_RX_SNR, UNIT_DB, 0 ), // RX SNR + FS( SENSOR_TYPE_RX_NOISE, STR_SENSOR_RX_NOISE, UNIT_DBM, 0 ), // RX Noise + FS( SENSOR_TYPE_RX_RSSI, STR_SENSOR_RSSI, UNIT_DBM, 0 ), // RX RSSI (0xfc) + FS( SENSOR_TYPE_RX_ERR_RATE, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0 ), // RX error rate //////////////////////////////////////////////////////////////// - { AFHDS2A_ID_BAT_CURR, STR_SENSOR_CURR, UNIT_AMPS, 2 }, // battery current A * 100 - { AFHDS2A_ID_FUEL, STR_SENSOR_CAPACITY, UNIT_RAW, 0 }, // remaining battery percentage / mah drawn otherwise or fuel level no unit! - { AFHDS2A_ID_RPM, STR_SENSOR_RPM, UNIT_RAW, 0 }, // throttle value / battery capacity - { AFHDS2A_ID_CMP_HEAD, STR_SENSOR_HDG, UNIT_DEGREE, 0 }, // Heading 0..360 deg, 0=north 2bytes - { AFHDS2A_ID_CLIMB_RATE, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 }, // 2 bytes m/s *100 - { AFHDS2A_ID_COG, STR_SENSOR_HDG, UNIT_DEGREE, 2 }, // 2 bytes Course over ground(NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. unknown max uint - { AFHDS2A_ID_GPS_STATUS, STR_SENSOR_SATELLITES, UNIT_RAW, 0 }, // 2 bytes - { AFHDS2A_ID_ACC_X, STR_SENSOR_ACCX, UNIT_METERS_PER_SECOND, 2 }, // 2 bytes m/s *100 signed - { AFHDS2A_ID_ACC_Y, STR_SENSOR_ACCY, UNIT_METERS_PER_SECOND, 2 }, // 2 bytes m/s *100 signed - { AFHDS2A_ID_ACC_Z, STR_SENSOR_ACCZ, UNIT_METERS_PER_SECOND, 2 }, // 2 bytes m/s *100 signed - { AFHDS2A_ID_ROLL, STR_SENSOR_ROLL, UNIT_DEGREE, 2 }, // 2 bytes deg *100 signed - { AFHDS2A_ID_PITCH, STR_SENSOR_PITCH, UNIT_DEGREE, 2 }, // 2 bytes deg *100 signed - { AFHDS2A_ID_YAW, STR_SENSOR_YAW, UNIT_DEGREE, 2 }, // 2 bytes deg *100 signed - { AFHDS2A_ID_VERTICAL_SPEED, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 }, // 2 bytes m/s *100 - { AFHDS2A_ID_GROUND_SPEED, STR_SENSOR_GSPD, UNIT_METERS_PER_SECOND, 2 }, // 2 bytes m/s *100 different unit than build-in sensor - { AFHDS2A_ID_GPS_DIST, STR_SENSOR_DIST, UNIT_METERS, 0 }, // 2 bytes dist from home m unsigned - { AFHDS2A_ID_ARMED, STR_SENSOR_ARM, UNIT_RAW, 0 }, // 2 bytes - { AFHDS2A_ID_FLIGHT_MODE, STR_SENSOR_FLIGHT_MODE, UNIT_RAW, 0 }, // 2 bytes index - { SENSOR_TYPE_PRES | 0x100, STR_SENSOR_TEMP2, UNIT_CELSIUS, 1 }, // 2 bytes Temperature - { AFHDS2A_ID_ODO1, STR_SENSOR_ODO1, UNIT_METERS, 2 }, // 2 bytes Odometer1 -- some magic with 330 needed - { AFHDS2A_ID_ODO2, STR_SENSOR_ODO2, UNIT_METERS, 2 }, // 2 bytes Odometer2 -- some magic with 330 needed - { AFHDS2A_ID_SPE, STR_SENSOR_ASPD, UNIT_KMH, 2 }, // 2 bytes Speed km/h -- some magic with 330 needed - { AFHDS2A_ID_GPS_LAT, STR_SENSOR_GPS, UNIT_RAW, 0 }, // 4 bytes signed WGS84 in degrees * 1E7 - { AFHDS2A_ID_GPS_LON, STR_SENSOR_GPS, UNIT_RAW, 0 }, // 4 bytes signed WGS84 in degrees * 1E7 - { AFHDS2A_ID_GPS_ALT, STR_SENSOR_GPSALT, UNIT_METERS, 2 }, // 4 bytes signed GPS alt m*100 - { AFHDS2A_ID_ALT, STR_SENSOR_ALT, UNIT_METERS, 2 }, // 4 bytes signed Alt m*100 - { AFHDS2A_ID_RX_SIG_AFHDS3, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0 }, // RX error rate - { AFHDS2A_ID_RX_SNR_AFHDS3, STR_SENSOR_RX_SNR, UNIT_DB, 1 }, // RX SNR - { AFHDS2A_ID_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_DBM, 0 }, // Pseudo sensor for TRSSI - - { 0x00, NULL, UNIT_RAW, 0 }, // sentinel + FS( AFHDS2A_ID_BAT_CURR, STR_SENSOR_CURR, UNIT_AMPS, 2 ), // battery current A * 100 + FS( AFHDS2A_ID_FUEL, STR_SENSOR_CAPACITY, UNIT_RAW, 0 ), // remaining battery percentage / mah drawn otherwise or fuel level no unit! + FS( AFHDS2A_ID_RPM, STR_SENSOR_RPM, UNIT_RAW, 0 ), // throttle value / battery capacity + FS( AFHDS2A_ID_CMP_HEAD, STR_SENSOR_HDG, UNIT_DEGREE, 0 ), // Heading 0..360 deg, 0=north 2bytes + FS( AFHDS2A_ID_CLIMB_RATE, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 + FS( AFHDS2A_ID_COG, STR_SENSOR_HDG, UNIT_DEGREE, 2 ), // 2 bytes Course over ground(NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. unknown max uint + FS( AFHDS2A_ID_GPS_STATUS, STR_SENSOR_SATELLITES, UNIT_RAW, 0 ), // 2 bytes + FS( AFHDS2A_ID_ACC_X, STR_SENSOR_ACCX, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 signed + FS( AFHDS2A_ID_ACC_Y, STR_SENSOR_ACCY, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 signed + FS( AFHDS2A_ID_ACC_Z, STR_SENSOR_ACCZ, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 signed + FS( AFHDS2A_ID_ROLL, STR_SENSOR_ROLL, UNIT_DEGREE, 2 ), // 2 bytes deg *100 signed + FS( AFHDS2A_ID_PITCH, STR_SENSOR_PITCH, UNIT_DEGREE, 2 ), // 2 bytes deg *100 signed + FS( AFHDS2A_ID_YAW, STR_SENSOR_YAW, UNIT_DEGREE, 2 ), // 2 bytes deg *100 signed + FS( AFHDS2A_ID_VERTICAL_SPEED, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 + FS( AFHDS2A_ID_GROUND_SPEED, STR_SENSOR_GSPD, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 different unit than build-in sensor + FS( AFHDS2A_ID_GPS_DIST, STR_SENSOR_DIST, UNIT_METERS, 0 ), // 2 bytes dist from home m unsigned + FS( AFHDS2A_ID_ARMED, STR_SENSOR_ARM, UNIT_RAW, 0 ), // 2 bytes + FS( AFHDS2A_ID_FLIGHT_MODE, STR_SENSOR_FLIGHT_MODE, UNIT_RAW, 0 ), // 2 bytes index + FS( SENSOR_TYPE_PRES | 0x100, STR_SENSOR_TEMP2, UNIT_CELSIUS, 1 ), // 2 bytes Temperature + FS( AFHDS2A_ID_ODO1, STR_SENSOR_ODO1, UNIT_METERS, 2 ), // 2 bytes Odometer1 -- some magic with 330 needed + FS( AFHDS2A_ID_ODO2, STR_SENSOR_ODO2, UNIT_METERS, 2 ), // 2 bytes Odometer2 -- some magic with 330 needed + FS( AFHDS2A_ID_SPE, STR_SENSOR_ASPD, UNIT_KMH, 2 ), // 2 bytes Speed km/h -- some magic with 330 needed + FS( AFHDS2A_ID_GPS_LAT, STR_SENSOR_GPS, UNIT_RAW, 0 ), // 4 bytes signed WGS84 in degrees * 1E7 + FS( AFHDS2A_ID_GPS_LON, STR_SENSOR_GPS, UNIT_RAW, 0 ), // 4 bytes signed WGS84 in degrees * 1E7 + FS( AFHDS2A_ID_GPS_ALT, STR_SENSOR_GPSALT, UNIT_METERS, 2 ), // 4 bytes signed GPS alt m*100 + FS( AFHDS2A_ID_ALT, STR_SENSOR_ALT, UNIT_METERS, 2 ), // 4 bytes signed Alt m*100 + FS( AFHDS2A_ID_RX_SIG_AFHDS3, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0 ), // RX error rate + FS( AFHDS2A_ID_RX_SNR_AFHDS3, STR_SENSOR_RX_SNR, UNIT_DB, 1 ), // RX SNR + FS( AFHDS2A_ID_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_DBM, 0 ), // Pseudo sensor for TRSSI + + FS( 0x00, NULL, UNIT_RAW, 0 ), // sentinel }; int32_t getALT(uint32_t value); diff --git a/radio/src/telemetry/frsky_d.cpp b/radio/src/telemetry/frsky_d.cpp index 35cbd5fd75a..59cf1e590bd 100644 --- a/radio/src/telemetry/frsky_d.cpp +++ b/radio/src/telemetry/frsky_d.cpp @@ -101,34 +101,36 @@ void frskyDProcessPacket(uint8_t module, const uint8_t *packet, uint8_t len) struct FrSkyDSensor { const uint8_t id; - const char * name; const TelemetryUnit unit; const uint8_t prec; + const char * name; }; +#define FS(id,name,unit,prec) {id,unit,prec,name} + const FrSkyDSensor frskyDSensors[] = { - { D_RSSI_ID, STR_SENSOR_RSSI, UNIT_RAW, 0 }, - { D_A1_ID, STR_SENSOR_A1, UNIT_VOLTS, 1 }, - { D_A2_ID, STR_SENSOR_A2, UNIT_VOLTS, 1 }, - { RPM_ID, STR_SENSOR_RPM, UNIT_RPMS, 0 }, - { FUEL_ID, STR_SENSOR_FUEL, UNIT_PERCENT, 0 }, - { TEMP1_ID, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0 }, - { TEMP2_ID, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0 }, - { CURRENT_ID, STR_SENSOR_CURR, UNIT_AMPS, 1 }, - { ACCEL_X_ID, STR_SENSOR_ACCX, UNIT_G, 3 }, - { ACCEL_Y_ID, STR_SENSOR_ACCY, UNIT_G, 3 }, - { ACCEL_Z_ID, STR_SENSOR_ACCZ, UNIT_G, 3 }, - { VARIO_ID, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 }, - { VFAS_ID, STR_SENSOR_VFAS, UNIT_VOLTS, 2 }, - { BARO_ALT_AP_ID, STR_SENSOR_ALT, UNIT_METERS, 1 }, // we map hi precision vario into PREC1! - { VOLTS_AP_ID, STR_SENSOR_VFAS, UNIT_VOLTS, 2 }, - { GPS_SPEED_BP_ID, STR_SENSOR_GSPD, UNIT_KTS, 0 }, - { GPS_COURS_BP_ID, STR_SENSOR_HDG, UNIT_DEGREE, 0 }, - { VOLTS_ID, STR_SENSOR_CELLS, UNIT_CELLS, 2 }, - { GPS_ALT_BP_ID, STR_SENSOR_GPSALT, UNIT_METERS, 0 }, - { GPS_HOUR_MIN_ID, STR_SENSOR_GPSDATETIME, UNIT_DATETIME, 0 }, - { GPS_LAT_AP_ID, STR_SENSOR_GPS, UNIT_GPS, 0 }, - { 0, NULL, UNIT_RAW, 0 } // sentinel + FS( D_RSSI_ID, STR_SENSOR_RSSI, UNIT_RAW, 0 ), + FS( D_A1_ID, STR_SENSOR_A1, UNIT_VOLTS, 1 ), + FS( D_A2_ID, STR_SENSOR_A2, UNIT_VOLTS, 1 ), + FS( RPM_ID, STR_SENSOR_RPM, UNIT_RPMS, 0 ), + FS( FUEL_ID, STR_SENSOR_FUEL, UNIT_PERCENT, 0 ), + FS( TEMP1_ID, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0 ), + FS( TEMP2_ID, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0 ), + FS( CURRENT_ID, STR_SENSOR_CURR, UNIT_AMPS, 1 ), + FS( ACCEL_X_ID, STR_SENSOR_ACCX, UNIT_G, 3 ), + FS( ACCEL_Y_ID, STR_SENSOR_ACCY, UNIT_G, 3 ), + FS( ACCEL_Z_ID, STR_SENSOR_ACCZ, UNIT_G, 3 ), + FS( VARIO_ID, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 ), + FS( VFAS_ID, STR_SENSOR_VFAS, UNIT_VOLTS, 2 ), + FS( BARO_ALT_AP_ID, STR_SENSOR_ALT, UNIT_METERS, 1 ), // we map hi precision vario into PREC1! + FS( VOLTS_AP_ID, STR_SENSOR_VFAS, UNIT_VOLTS, 2 ), + FS( GPS_SPEED_BP_ID, STR_SENSOR_GSPD, UNIT_KTS, 0 ), + FS( GPS_COURS_BP_ID, STR_SENSOR_HDG, UNIT_DEGREE, 0 ), + FS( VOLTS_ID, STR_SENSOR_CELLS, UNIT_CELLS, 2 ), + FS( GPS_ALT_BP_ID, STR_SENSOR_GPSALT, UNIT_METERS, 0 ), + FS( GPS_HOUR_MIN_ID, STR_SENSOR_GPSDATETIME, UNIT_DATETIME, 0 ), + FS( GPS_LAT_AP_ID, STR_SENSOR_GPS, UNIT_GPS, 0 ), + FS( 0, NULL, UNIT_RAW, 0 ) // sentinel }; const FrSkyDSensor * getFrSkyDSensor(uint8_t id) diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index df5ee5e61be..a5bcdb353a5 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -23,89 +23,91 @@ struct FrSkySportSensor { const uint16_t firstId; - const uint16_t lastId; - const uint8_t subId; + const uint8_t idCnt:6; + const uint8_t subId:2; + const uint8_t prec:2; + const TelemetryUnit unit:6; const char * name; - const TelemetryUnit unit; - const uint8_t prec; }; +#define FS(firstId,lastId,subId,name,unit,prec) {firstId,lastId-firstId,subId,prec,unit,name} + const FrSkySportSensor sportSensors[] = { - { VALID_FRAME_RATE_ID, VALID_FRAME_RATE_ID, 0, STR_SENSOR_VFR, UNIT_PERCENT, 0 }, - { RSSI_ID, RSSI_ID, 0, STR_SENSOR_RSSI, UNIT_DB, 0 }, + FS( VALID_FRAME_RATE_ID, VALID_FRAME_RATE_ID, 0, STR_SENSOR_VFR, UNIT_PERCENT, 0 ), + FS( RSSI_ID, RSSI_ID, 0, STR_SENSOR_RSSI, UNIT_DB, 0 ), #if defined(MULTIMODULE) - { TX_RSSI_ID, TX_RSSI_ID, 0, STR_SENSOR_TX_RSSI , UNIT_DB , 0 }, - { TX_LQI_ID , TX_LQI_ID, 0, STR_SENSOR_TX_QUALITY, UNIT_RAW, 0 }, + FS( TX_RSSI_ID, TX_RSSI_ID, 0, STR_SENSOR_TX_RSSI , UNIT_DB , 0 ), + FS( TX_LQI_ID , TX_LQI_ID, 0, STR_SENSOR_TX_QUALITY, UNIT_RAW, 0 ), #endif - { ADC1_ID, ADC1_ID, 0, STR_SENSOR_A1, UNIT_VOLTS, 1 }, - { ADC2_ID, ADC2_ID, 0, STR_SENSOR_A2, UNIT_VOLTS, 1 }, - { A3_FIRST_ID, A3_LAST_ID, 0, STR_SENSOR_A3, UNIT_VOLTS, 2 }, - { A4_FIRST_ID, A4_LAST_ID, 0, STR_SENSOR_A4, UNIT_VOLTS, 2 }, - { BATT_ID, BATT_ID, 0, STR_SENSOR_BATT, UNIT_VOLTS, 1 }, - { R9_PWR_ID, R9_PWR_ID, 0, STR_SENSOR_R9PW, UNIT_MILLIWATTS, 0 }, - { T1_FIRST_ID, T1_LAST_ID, 0, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0 }, - { T2_FIRST_ID, T2_LAST_ID, 0, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0 }, - { RPM_FIRST_ID, RPM_LAST_ID, 0, STR_SENSOR_RPM, UNIT_RPMS, 0 }, - { FUEL_FIRST_ID, FUEL_LAST_ID, 0, STR_SENSOR_FUEL, UNIT_PERCENT, 0 }, - { ALT_FIRST_ID, ALT_LAST_ID, 0, STR_SENSOR_ALT, UNIT_METERS, 2 }, - { VARIO_FIRST_ID, VARIO_LAST_ID, 0, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 }, - { ACCX_FIRST_ID, ACCX_LAST_ID, 0, STR_SENSOR_ACCX, UNIT_G, 3 }, - { ACCY_FIRST_ID, ACCY_LAST_ID, 0, STR_SENSOR_ACCY, UNIT_G, 3 }, - { ACCZ_FIRST_ID, ACCZ_LAST_ID, 0, STR_SENSOR_ACCZ, UNIT_G, 3 }, - { CURR_FIRST_ID, CURR_LAST_ID, 0, STR_SENSOR_CURR, UNIT_AMPS, 1 }, - { VFAS_FIRST_ID, VFAS_LAST_ID, 0, STR_SENSOR_VFAS, UNIT_VOLTS, 2 }, - { AIR_SPEED_FIRST_ID, AIR_SPEED_LAST_ID, 0, STR_SENSOR_ASPD, UNIT_KTS, 1 }, - { GPS_SPEED_FIRST_ID, GPS_SPEED_LAST_ID, 0, STR_SENSOR_GSPD, UNIT_KTS, 3 }, - { CELLS_FIRST_ID, CELLS_LAST_ID, 0, STR_SENSOR_CELLS, UNIT_CELLS, 2 }, - { GPS_ALT_FIRST_ID, GPS_ALT_LAST_ID, 0, STR_SENSOR_GPSALT, UNIT_METERS, 2 }, - { GPS_TIME_DATE_FIRST_ID, GPS_TIME_DATE_LAST_ID, 0, STR_SENSOR_GPSDATETIME, UNIT_DATETIME, 0 }, - { GPS_LONG_LATI_FIRST_ID, GPS_LONG_LATI_LAST_ID, 0, STR_SENSOR_GPS, UNIT_GPS, 0 }, - { FUEL_QTY_FIRST_ID, FUEL_QTY_LAST_ID, 0, STR_SENSOR_FUEL, UNIT_MILLILITERS, 2 }, - { GPS_COURS_FIRST_ID, GPS_COURS_LAST_ID, 0, STR_SENSOR_HDG, UNIT_DEGREE, 2 }, - { RBOX_BATT1_FIRST_ID, RBOX_BATT1_LAST_ID, 0, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 3 }, - { RBOX_BATT2_FIRST_ID, RBOX_BATT2_LAST_ID, 0, STR_SENSOR_BATT2_VOLTAGE, UNIT_VOLTS, 3 }, - { RBOX_BATT1_FIRST_ID, RBOX_BATT1_LAST_ID, 1, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 2 }, - { RBOX_BATT2_FIRST_ID, RBOX_BATT2_LAST_ID, 1, STR_SENSOR_BATT2_CURRENT, UNIT_AMPS, 2 }, - { RBOX_CNSP_FIRST_ID, RBOX_CNSP_LAST_ID, 0, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 0 }, - { RBOX_CNSP_FIRST_ID, RBOX_CNSP_LAST_ID, 1, STR_SENSOR_BATT2_CONSUMPTION, UNIT_MAH, 0 }, - { RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 0, STR_SENSOR_CHANS_STATE, UNIT_TEXT, 0 }, - { RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 1, STR_SENSOR_RB_STATE, UNIT_TEXT, 0 }, - { SD1_FIRST_ID, SD1_LAST_ID, 0, STR_SENSOR_SD1_CHANNEL, UNIT_RAW, 0 }, - { ESC_POWER_FIRST_ID, ESC_POWER_LAST_ID, 0, STR_SENSOR_ESC_VOLTAGE, UNIT_VOLTS, 2 }, - { ESC_POWER_FIRST_ID, ESC_POWER_LAST_ID, 1, STR_SENSOR_ESC_CURRENT, UNIT_AMPS, 2 }, - { ESC_RPM_CONS_FIRST_ID, ESC_RPM_CONS_LAST_ID, 0, STR_SENSOR_ESC_RPM, UNIT_RPMS, 0 }, - { ESC_RPM_CONS_FIRST_ID, ESC_RPM_CONS_LAST_ID, 1, STR_SENSOR_ESC_CONSUMPTION, UNIT_MAH, 0 }, - { ESC_TEMPERATURE_FIRST_ID, ESC_TEMPERATURE_LAST_ID, 0, STR_SENSOR_ESC_TEMP, UNIT_CELSIUS, 0 }, - { GASSUIT_TEMP1_FIRST_ID, GASSUIT_TEMP1_LAST_ID, 0, STR_SENSOR_GASSUIT_TEMP1, UNIT_CELSIUS, 0 }, - { GASSUIT_TEMP2_FIRST_ID, GASSUIT_TEMP2_LAST_ID, 0, STR_SENSOR_GASSUIT_TEMP2, UNIT_CELSIUS, 0 }, - { GASSUIT_SPEED_FIRST_ID, GASSUIT_SPEED_LAST_ID, 0, STR_SENSOR_GASSUIT_RPM, UNIT_RPMS, 0 }, - { GASSUIT_RES_VOL_FIRST_ID, GASSUIT_RES_VOL_LAST_ID, 0, STR_SENSOR_GASSUIT_RES_VOL, UNIT_MILLILITERS, 0 }, - { GASSUIT_RES_PERC_FIRST_ID, GASSUIT_RES_PERC_LAST_ID, 0, STR_SENSOR_GASSUIT_RES_PERC, UNIT_PERCENT, 0 }, - { GASSUIT_FLOW_FIRST_ID, GASSUIT_FLOW_LAST_ID, 0, STR_SENSOR_GASSUIT_FLOW, UNIT_MILLILITERS_PER_MINUTE, 0 }, - { GASSUIT_MAX_FLOW_FIRST_ID, GASSUIT_MAX_FLOW_LAST_ID, 0, STR_SENSOR_GASSUIT_MAX_FLOW, UNIT_MILLILITERS_PER_MINUTE, 0 }, - { GASSUIT_AVG_FLOW_FIRST_ID, GASSUIT_AVG_FLOW_LAST_ID, 0, STR_SENSOR_GASSUIT_AVG_FLOW, UNIT_MILLILITERS_PER_MINUTE, 0 }, - { SBEC_POWER_FIRST_ID, SBEC_POWER_LAST_ID, 0, STR_SENSOR_SBEC_VOLTAGE, UNIT_VOLTS, 2 }, - { SBEC_POWER_FIRST_ID, SBEC_POWER_LAST_ID, 1, STR_SENSOR_SBEC_CURRENT, UNIT_AMPS, 2 }, - { RB3040_OUTPUT_FIRST_ID, RB3040_OUTPUT_LAST_ID, 0, STR_SENSOR_RB3040_EXTRA_STATE, UNIT_TEXT, 0 }, - { RB3040_CH1_2_FIRST_ID, RB3040_CH1_2_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL1, UNIT_AMPS, 2 }, - { RB3040_CH1_2_FIRST_ID, RB3040_CH1_2_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL2, UNIT_AMPS, 2 }, - { RB3040_CH3_4_FIRST_ID, RB3040_CH3_4_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL3, UNIT_AMPS, 2 }, - { RB3040_CH3_4_FIRST_ID, RB3040_CH3_4_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL4, UNIT_AMPS, 2 }, - { RB3040_CH5_6_FIRST_ID, RB3040_CH5_6_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL5, UNIT_AMPS, 2 }, - { RB3040_CH5_6_FIRST_ID, RB3040_CH5_6_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL6, UNIT_AMPS, 2 }, - { RB3040_CH7_8_FIRST_ID, RB3040_CH7_8_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL7, UNIT_AMPS, 2 }, - { RB3040_CH7_8_FIRST_ID, RB3040_CH7_8_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL8, UNIT_AMPS, 2 }, - { SERVO_FIRST_ID, SERVO_LAST_ID, 0, STR_SENSOR_SERVO_CURRENT, UNIT_AMPS, 1 }, - { SERVO_FIRST_ID, SERVO_LAST_ID, 1, STR_SENSOR_SERVO_VOLTAGE, UNIT_VOLTS, 1 }, - { SERVO_FIRST_ID, SERVO_LAST_ID, 2, STR_SENSOR_SERVO_TEMPERATURE, UNIT_CELSIUS, 0 }, - { SERVO_FIRST_ID, SERVO_LAST_ID, 3, STR_SENSOR_SERVO_STATUS, UNIT_TEXT, 0 }, - { 0, 0, 0, nullptr, UNIT_RAW, 0 } // sentinel + FS( ADC1_ID, ADC1_ID, 0, STR_SENSOR_A1, UNIT_VOLTS, 1 ), + FS( ADC2_ID, ADC2_ID, 0, STR_SENSOR_A2, UNIT_VOLTS, 1 ), + FS( A3_FIRST_ID, A3_LAST_ID, 0, STR_SENSOR_A3, UNIT_VOLTS, 2 ), + FS( A4_FIRST_ID, A4_LAST_ID, 0, STR_SENSOR_A4, UNIT_VOLTS, 2 ), + FS( BATT_ID, BATT_ID, 0, STR_SENSOR_BATT, UNIT_VOLTS, 1 ), + FS( R9_PWR_ID, R9_PWR_ID, 0, STR_SENSOR_R9PW, UNIT_MILLIWATTS, 0 ), + FS( T1_FIRST_ID, T1_LAST_ID, 0, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0 ), + FS( T2_FIRST_ID, T2_LAST_ID, 0, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0 ), + FS( RPM_FIRST_ID, RPM_LAST_ID, 0, STR_SENSOR_RPM, UNIT_RPMS, 0 ), + FS( FUEL_FIRST_ID, FUEL_LAST_ID, 0, STR_SENSOR_FUEL, UNIT_PERCENT, 0 ), + FS( ALT_FIRST_ID, ALT_LAST_ID, 0, STR_SENSOR_ALT, UNIT_METERS, 2 ), + FS( VARIO_FIRST_ID, VARIO_LAST_ID, 0, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 ), + FS( ACCX_FIRST_ID, ACCX_LAST_ID, 0, STR_SENSOR_ACCX, UNIT_G, 3 ), + FS( ACCY_FIRST_ID, ACCY_LAST_ID, 0, STR_SENSOR_ACCY, UNIT_G, 3 ), + FS( ACCZ_FIRST_ID, ACCZ_LAST_ID, 0, STR_SENSOR_ACCZ, UNIT_G, 3 ), + FS( CURR_FIRST_ID, CURR_LAST_ID, 0, STR_SENSOR_CURR, UNIT_AMPS, 1 ), + FS( VFAS_FIRST_ID, VFAS_LAST_ID, 0, STR_SENSOR_VFAS, UNIT_VOLTS, 2 ), + FS( AIR_SPEED_FIRST_ID, AIR_SPEED_LAST_ID, 0, STR_SENSOR_ASPD, UNIT_KTS, 1 ), + FS( GPS_SPEED_FIRST_ID, GPS_SPEED_LAST_ID, 0, STR_SENSOR_GSPD, UNIT_KTS, 3 ), + FS( CELLS_FIRST_ID, CELLS_LAST_ID, 0, STR_SENSOR_CELLS, UNIT_CELLS, 2 ), + FS( GPS_ALT_FIRST_ID, GPS_ALT_LAST_ID, 0, STR_SENSOR_GPSALT, UNIT_METERS, 2 ), + FS( GPS_TIME_DATE_FIRST_ID, GPS_TIME_DATE_LAST_ID, 0, STR_SENSOR_GPSDATETIME, UNIT_DATETIME, 0 ), + FS( GPS_LONG_LATI_FIRST_ID, GPS_LONG_LATI_LAST_ID, 0, STR_SENSOR_GPS, UNIT_GPS, 0 ), + FS( FUEL_QTY_FIRST_ID, FUEL_QTY_LAST_ID, 0, STR_SENSOR_FUEL, UNIT_MILLILITERS, 2 ), + FS( GPS_COURS_FIRST_ID, GPS_COURS_LAST_ID, 0, STR_SENSOR_HDG, UNIT_DEGREE, 2 ), + FS( RBOX_BATT1_FIRST_ID, RBOX_BATT1_LAST_ID, 0, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 3 ), + FS( RBOX_BATT2_FIRST_ID, RBOX_BATT2_LAST_ID, 0, STR_SENSOR_BATT2_VOLTAGE, UNIT_VOLTS, 3 ), + FS( RBOX_BATT1_FIRST_ID, RBOX_BATT1_LAST_ID, 1, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 2 ), + FS( RBOX_BATT2_FIRST_ID, RBOX_BATT2_LAST_ID, 1, STR_SENSOR_BATT2_CURRENT, UNIT_AMPS, 2 ), + FS( RBOX_CNSP_FIRST_ID, RBOX_CNSP_LAST_ID, 0, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 0 ), + FS( RBOX_CNSP_FIRST_ID, RBOX_CNSP_LAST_ID, 1, STR_SENSOR_BATT2_CONSUMPTION, UNIT_MAH, 0 ), + FS( RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 0, STR_SENSOR_CHANS_STATE, UNIT_TEXT, 0 ), + FS( RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 1, STR_SENSOR_RB_STATE, UNIT_TEXT, 0 ), + FS( SD1_FIRST_ID, SD1_LAST_ID, 0, STR_SENSOR_SD1_CHANNEL, UNIT_RAW, 0 ), + FS( ESC_POWER_FIRST_ID, ESC_POWER_LAST_ID, 0, STR_SENSOR_ESC_VOLTAGE, UNIT_VOLTS, 2 ), + FS( ESC_POWER_FIRST_ID, ESC_POWER_LAST_ID, 1, STR_SENSOR_ESC_CURRENT, UNIT_AMPS, 2 ), + FS( ESC_RPM_CONS_FIRST_ID, ESC_RPM_CONS_LAST_ID, 0, STR_SENSOR_ESC_RPM, UNIT_RPMS, 0 ), + FS( ESC_RPM_CONS_FIRST_ID, ESC_RPM_CONS_LAST_ID, 1, STR_SENSOR_ESC_CONSUMPTION, UNIT_MAH, 0 ), + FS( ESC_TEMPERATURE_FIRST_ID, ESC_TEMPERATURE_LAST_ID, 0, STR_SENSOR_ESC_TEMP, UNIT_CELSIUS, 0 ), + FS( GASSUIT_TEMP1_FIRST_ID, GASSUIT_TEMP1_LAST_ID, 0, STR_SENSOR_GASSUIT_TEMP1, UNIT_CELSIUS, 0 ), + FS( GASSUIT_TEMP2_FIRST_ID, GASSUIT_TEMP2_LAST_ID, 0, STR_SENSOR_GASSUIT_TEMP2, UNIT_CELSIUS, 0 ), + FS( GASSUIT_SPEED_FIRST_ID, GASSUIT_SPEED_LAST_ID, 0, STR_SENSOR_GASSUIT_RPM, UNIT_RPMS, 0 ), + FS( GASSUIT_RES_VOL_FIRST_ID, GASSUIT_RES_VOL_LAST_ID, 0, STR_SENSOR_GASSUIT_RES_VOL, UNIT_MILLILITERS, 0 ), + FS( GASSUIT_RES_PERC_FIRST_ID, GASSUIT_RES_PERC_LAST_ID, 0, STR_SENSOR_GASSUIT_RES_PERC, UNIT_PERCENT, 0 ), + FS( GASSUIT_FLOW_FIRST_ID, GASSUIT_FLOW_LAST_ID, 0, STR_SENSOR_GASSUIT_FLOW, UNIT_MILLILITERS_PER_MINUTE, 0 ), + FS( GASSUIT_MAX_FLOW_FIRST_ID, GASSUIT_MAX_FLOW_LAST_ID, 0, STR_SENSOR_GASSUIT_MAX_FLOW, UNIT_MILLILITERS_PER_MINUTE, 0 ), + FS( GASSUIT_AVG_FLOW_FIRST_ID, GASSUIT_AVG_FLOW_LAST_ID, 0, STR_SENSOR_GASSUIT_AVG_FLOW, UNIT_MILLILITERS_PER_MINUTE, 0 ), + FS( SBEC_POWER_FIRST_ID, SBEC_POWER_LAST_ID, 0, STR_SENSOR_SBEC_VOLTAGE, UNIT_VOLTS, 2 ), + FS( SBEC_POWER_FIRST_ID, SBEC_POWER_LAST_ID, 1, STR_SENSOR_SBEC_CURRENT, UNIT_AMPS, 2 ), + FS( RB3040_OUTPUT_FIRST_ID, RB3040_OUTPUT_LAST_ID, 0, STR_SENSOR_RB3040_EXTRA_STATE, UNIT_TEXT, 0 ), + FS( RB3040_CH1_2_FIRST_ID, RB3040_CH1_2_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL1, UNIT_AMPS, 2 ), + FS( RB3040_CH1_2_FIRST_ID, RB3040_CH1_2_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL2, UNIT_AMPS, 2 ), + FS( RB3040_CH3_4_FIRST_ID, RB3040_CH3_4_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL3, UNIT_AMPS, 2 ), + FS( RB3040_CH3_4_FIRST_ID, RB3040_CH3_4_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL4, UNIT_AMPS, 2 ), + FS( RB3040_CH5_6_FIRST_ID, RB3040_CH5_6_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL5, UNIT_AMPS, 2 ), + FS( RB3040_CH5_6_FIRST_ID, RB3040_CH5_6_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL6, UNIT_AMPS, 2 ), + FS( RB3040_CH7_8_FIRST_ID, RB3040_CH7_8_LAST_ID, 0, STR_SENSOR_RB3040_CHANNEL7, UNIT_AMPS, 2 ), + FS( RB3040_CH7_8_FIRST_ID, RB3040_CH7_8_LAST_ID, 1, STR_SENSOR_RB3040_CHANNEL8, UNIT_AMPS, 2 ), + FS( SERVO_FIRST_ID, SERVO_LAST_ID, 0, STR_SENSOR_SERVO_CURRENT, UNIT_AMPS, 1 ), + FS( SERVO_FIRST_ID, SERVO_LAST_ID, 1, STR_SENSOR_SERVO_VOLTAGE, UNIT_VOLTS, 1 ), + FS( SERVO_FIRST_ID, SERVO_LAST_ID, 2, STR_SENSOR_SERVO_TEMPERATURE, UNIT_CELSIUS, 0 ), + FS( SERVO_FIRST_ID, SERVO_LAST_ID, 3, STR_SENSOR_SERVO_STATUS, UNIT_TEXT, 0 ), + FS( 0, 0, 0, nullptr, UNIT_RAW, 0 ) // sentinel }; const FrSkySportSensor * getFrSkySportSensor(uint16_t id, uint8_t subId=0) { for (const FrSkySportSensor * sensor = sportSensors; sensor->firstId; sensor++) { - if (id >= sensor->firstId && id <= sensor->lastId && subId == sensor->subId) { + if (id >= sensor->firstId && id <= (sensor->firstId + sensor->idCnt) && subId == sensor->subId) { return sensor; } } diff --git a/radio/src/telemetry/ghost.cpp b/radio/src/telemetry/ghost.cpp index dd09a8e96c4..f9f6c678165 100755 --- a/radio/src/telemetry/ghost.cpp +++ b/radio/src/telemetry/ghost.cpp @@ -30,11 +30,13 @@ const char *ghstVtxBandName[GHST_VTX_BAND_COUNT] = { "- - -" , "IRC", "Race", "B struct GhostSensor { const uint16_t id; - const char * name; const TelemetryUnit unit; const uint8_t precision; + const char * name; }; +#define GS(id,name,unit,precision) {id,unit,precision,name} + // telemetry sensors ID enum { @@ -63,32 +65,32 @@ enum }; const GhostSensor ghostSensors[] = { - {GHOST_ID_RX_RSSI, STR_SENSOR_RSSI, UNIT_DB, 0}, - {GHOST_ID_RX_LQ, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0}, - {GHOST_ID_RX_SNR, STR_SENSOR_RX_SNR, UNIT_DB, 0}, - - {GHOST_ID_FRAME_RATE, STR_SENSOR_FRAME_RATE, UNIT_RAW, 0}, - {GHOST_ID_TX_POWER, STR_SENSOR_TX_POWER, UNIT_MILLIWATTS, 0}, - {GHOST_ID_RF_MODE, STR_SENSOR_RF_MODE, UNIT_TEXT, 0}, - {GHOST_ID_TOTAL_LATENCY, STR_SENSOR_TOTAL_LATENCY, UNIT_RAW, 0}, - - {GHOST_ID_VTX_FREQ, STR_SENSOR_VTX_FREQ, UNIT_RAW, 0}, - {GHOST_ID_VTX_POWER, STR_SENSOR_VTX_PWR, UNIT_RAW, 0}, - {GHOST_ID_VTX_CHAN, STR_SENSOR_VTX_CHAN, UNIT_RAW, 0}, - {GHOST_ID_VTX_BAND, STR_SENSOR_VTX_BAND, UNIT_TEXT, 0}, - - {GHOST_ID_PACK_VOLTS, STR_SENSOR_BATT, UNIT_VOLTS, 2}, - {GHOST_ID_PACK_AMPS, STR_SENSOR_CURR, UNIT_AMPS, 2}, - {GHOST_ID_PACK_MAH, STR_SENSOR_CAPACITY, UNIT_MAH, 0}, - - {GHOST_ID_GPS_LAT, STR_GPS, UNIT_GPS_LATITUDE, 0}, - {GHOST_ID_GPS_LONG, STR_GPS, UNIT_GPS_LONGITUDE, 0}, - {GHOST_ID_GPS_GSPD, STR_SENSOR_GSPD, UNIT_KMH, 1}, - {GHOST_ID_GPS_HDG, STR_SENSOR_HDG, UNIT_DEGREE, 3}, - {GHOST_ID_GPS_ALT, STR_SENSOR_GPSALT, UNIT_METERS, 0}, - {GHOST_ID_GPS_SATS, STR_SENSOR_SATELLITES, UNIT_RAW, 0}, - - {0x00, NULL, UNIT_RAW, 0}, + GS(GHOST_ID_RX_RSSI, STR_SENSOR_RSSI, UNIT_DB, 0), + GS(GHOST_ID_RX_LQ, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0), + GS(GHOST_ID_RX_SNR, STR_SENSOR_RX_SNR, UNIT_DB, 0), + + GS(GHOST_ID_FRAME_RATE, STR_SENSOR_FRAME_RATE, UNIT_RAW, 0), + GS(GHOST_ID_TX_POWER, STR_SENSOR_TX_POWER, UNIT_MILLIWATTS, 0), + GS(GHOST_ID_RF_MODE, STR_SENSOR_RF_MODE, UNIT_TEXT, 0), + GS(GHOST_ID_TOTAL_LATENCY, STR_SENSOR_TOTAL_LATENCY, UNIT_RAW, 0), + + GS(GHOST_ID_VTX_FREQ, STR_SENSOR_VTX_FREQ, UNIT_RAW, 0), + GS(GHOST_ID_VTX_POWER, STR_SENSOR_VTX_PWR, UNIT_RAW, 0), + GS(GHOST_ID_VTX_CHAN, STR_SENSOR_VTX_CHAN, UNIT_RAW, 0), + GS(GHOST_ID_VTX_BAND, STR_SENSOR_VTX_BAND, UNIT_TEXT, 0), + + GS(GHOST_ID_PACK_VOLTS, STR_SENSOR_BATT, UNIT_VOLTS, 2), + GS(GHOST_ID_PACK_AMPS, STR_SENSOR_CURR, UNIT_AMPS, 2), + GS(GHOST_ID_PACK_MAH, STR_SENSOR_CAPACITY, UNIT_MAH, 0), + + GS(GHOST_ID_GPS_LAT, STR_GPS, UNIT_GPS_LATITUDE, 0), + GS(GHOST_ID_GPS_LONG, STR_GPS, UNIT_GPS_LONGITUDE, 0), + GS(GHOST_ID_GPS_GSPD, STR_SENSOR_GSPD, UNIT_KMH, 1), + GS(GHOST_ID_GPS_HDG, STR_SENSOR_HDG, UNIT_DEGREE, 3), + GS(GHOST_ID_GPS_ALT, STR_SENSOR_GPSALT, UNIT_METERS, 0), + GS(GHOST_ID_GPS_SATS, STR_SENSOR_SATELLITES, UNIT_RAW, 0), + + GS(0x00, NULL, UNIT_RAW, 0), }; const GhostSensor *getGhostSensor(uint8_t id) diff --git a/radio/src/telemetry/hitec.cpp b/radio/src/telemetry/hitec.cpp index a52522fd61c..1331da6fe50 100644 --- a/radio/src/telemetry/hitec.cpp +++ b/radio/src/telemetry/hitec.cpp @@ -104,9 +104,9 @@ data byte 3 -> Alti2L Altitude filtered struct HitecSensor { const uint16_t id; - const char * name; const TelemetryUnit unit; const uint8_t precision; + const char * name; }; // telemetry frames @@ -160,48 +160,50 @@ enum HITEC_ID_TX_LQI = 0xFF01, // Pseudo id outside 1 byte range of Hitec sensors }; +#define HS(id,name,unit,precision) {id,unit,precision,name} + const HitecSensor hitecSensors[] = { //frame 00 - {HITEC_ID_RX_VOLTAGE, STR_SENSOR_BATT, UNIT_VOLTS, 2}, // RX_Batt Voltage + HS(HITEC_ID_RX_VOLTAGE, STR_SENSOR_BATT, UNIT_VOLTS, 2), // RX_Batt Voltage //frame 11 //frame 12 - {HITEC_ID_GPS_LAT_LONG, STR_SENSOR_GPS, UNIT_GPS, 0}, // GPS position + HS(HITEC_ID_GPS_LAT_LONG, STR_SENSOR_GPS, UNIT_GPS, 0), // GPS position //frame 13 - {HITEC_ID_TEMP2, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0}, // Temperature sensor 2 + HS(HITEC_ID_TEMP2, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0), // Temperature sensor 2 //frame 14 - {HITEC_ID_GPS_SPEED, STR_SENSOR_GSPD, UNIT_KMH, 0}, // GPS speed - {HITEC_ID_GPS_ALTITUDE, STR_SENSOR_GPSALT, UNIT_METERS, 0}, // GPS altitude sea level - {HITEC_ID_TEMP1, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0}, // Temperature sensor 1 + HS(HITEC_ID_GPS_SPEED, STR_SENSOR_GSPD, UNIT_KMH, 0), // GPS speed + HS(HITEC_ID_GPS_ALTITUDE, STR_SENSOR_GPSALT, UNIT_METERS, 0), // GPS altitude sea level + HS(HITEC_ID_TEMP1, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0), // Temperature sensor 1 //frame 15 - {HITEC_ID_FUEL, STR_SENSOR_FUEL, UNIT_PERCENT, 0}, // Fuel - {HITEC_ID_RPM1, STR_SENSOR_RPM, UNIT_RPMS, 0}, // RPM1 - {HITEC_ID_RPM2, STR_SENSOR_RPM2, UNIT_RPMS, 0}, // RPM2 + HS(HITEC_ID_FUEL, STR_SENSOR_FUEL, UNIT_PERCENT, 0), // Fuel + HS(HITEC_ID_RPM1, STR_SENSOR_RPM, UNIT_RPMS, 0), // RPM1 + HS(HITEC_ID_RPM2, STR_SENSOR_RPM2, UNIT_RPMS, 0), // RPM2 //frame 16 - {HITEC_ID_GPS_DATETIME, STR_SENSOR_GPS, UNIT_DATETIME, 0}, // GPS date time + HS(HITEC_ID_GPS_DATETIME, STR_SENSOR_GPS, UNIT_DATETIME, 0), // GPS date time //frame 17 - {HITEC_ID_GPS_HEADING, STR_SENSOR_HDG, UNIT_DEGREE, 0}, // GPS Heading - {HITEC_ID_GPS_COUNT, STR_SENSOR_SATELLITES, UNIT_RAW, 0}, // GPS count - {HITEC_ID_TEMP3, STR_SENSOR_TEMP3, UNIT_CELSIUS, 0}, // Temperature sensor 3 - {HITEC_ID_TEMP4, STR_SENSOR_TEMP4, UNIT_CELSIUS, 0}, // Temperature sensor 4 + HS(HITEC_ID_GPS_HEADING, STR_SENSOR_HDG, UNIT_DEGREE, 0), // GPS Heading + HS(HITEC_ID_GPS_COUNT, STR_SENSOR_SATELLITES, UNIT_RAW, 0), // GPS count + HS(HITEC_ID_TEMP3, STR_SENSOR_TEMP3, UNIT_CELSIUS, 0), // Temperature sensor 3 + HS(HITEC_ID_TEMP4, STR_SENSOR_TEMP4, UNIT_CELSIUS, 0), // Temperature sensor 4 //frame 18 - {HITEC_ID_VOLTAGE, STR_SENSOR_A1, UNIT_VOLTS, 1}, // Voltage sensor - {HITEC_ID_AMP, STR_SENSOR_CURR, UNIT_AMPS, 0}, // Amp sensor - {HITEC_ID_C50, STR_SENSOR_C50, UNIT_AMPS, 1}, // Amp sensor C50 - {HITEC_ID_C200, STR_SENSOR_C200, UNIT_AMPS, 0}, // Amp sensor C200 + HS(HITEC_ID_VOLTAGE, STR_SENSOR_A1, UNIT_VOLTS, 1), // Voltage sensor + HS(HITEC_ID_AMP, STR_SENSOR_CURR, UNIT_AMPS, 0), // Amp sensor + HS(HITEC_ID_C50, STR_SENSOR_C50, UNIT_AMPS, 1), // Amp sensor C50 + HS(HITEC_ID_C200, STR_SENSOR_C200, UNIT_AMPS, 0), // Amp sensor C200 //frame 19 - {HITEC_ID_AMP_S1, STR_SENSOR_CURR_SERVO1, UNIT_AMPS, 1}, // Amp sensor - {HITEC_ID_AMP_S2, STR_SENSOR_CURR_SERVO2, UNIT_AMPS, 1}, // Amp sensor - {HITEC_ID_AMP_S3, STR_SENSOR_CURR_SERVO3, UNIT_AMPS, 1}, // Amp sensor - {HITEC_ID_AMP_S4, STR_SENSOR_CURR_SERVO4, UNIT_AMPS, 1}, // Amp sensor + HS(HITEC_ID_AMP_S1, STR_SENSOR_CURR_SERVO1, UNIT_AMPS, 1), // Amp sensor + HS(HITEC_ID_AMP_S2, STR_SENSOR_CURR_SERVO2, UNIT_AMPS, 1), // Amp sensor + HS(HITEC_ID_AMP_S3, STR_SENSOR_CURR_SERVO3, UNIT_AMPS, 1), // Amp sensor + HS(HITEC_ID_AMP_S4, STR_SENSOR_CURR_SERVO4, UNIT_AMPS, 1), // Amp sensor //frame 1A - {HITEC_ID_AIR_SPEED, STR_SENSOR_ASPD, UNIT_KMH, 0}, // Air speed + HS(HITEC_ID_AIR_SPEED, STR_SENSOR_ASPD, UNIT_KMH, 0), // Air speed //frame 1B - {HITEC_ID_VARIO, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 1}, // Vario - {HITEC_ID_ALT, STR_SENSOR_ALT, UNIT_METERS, 1}, // Altitude + HS(HITEC_ID_VARIO, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 1), // Vario + HS(HITEC_ID_ALT, STR_SENSOR_ALT, UNIT_METERS, 1), // Altitude - {HITEC_ID_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hitec sensors - {HITEC_ID_TX_LQI, STR_SENSOR_TX_QUALITY, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hitec sensors// Pseudo sensor for TLQI - {0x00, NULL, UNIT_RAW, 0}, // sentinel + HS(HITEC_ID_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_RAW, 0), // Pseudo id outside 1 byte range of Hitec sensors + HS(HITEC_ID_TX_LQI, STR_SENSOR_TX_QUALITY, UNIT_RAW, 0), // Pseudo id outside 1 byte range of Hitec sensors// Pseudo sensor for TLQI + HS(0x00, NULL, UNIT_RAW, 0), // sentinel }; const HitecSensor * getHitecSensor(uint16_t id) diff --git a/radio/src/telemetry/hott.cpp b/radio/src/telemetry/hott.cpp index 1c0ab878503..f37ed4fc945 100644 --- a/radio/src/telemetry/hott.cpp +++ b/radio/src/telemetry/hott.cpp @@ -212,83 +212,85 @@ enum TelemetrySensorID struct HottSensor { const uint16_t id; - const char * name; const TelemetryUnit unit; const uint8_t precision; + const char * name; }; +#define HS(id,name,unit,precision) {id,unit,precision,name} + const HottSensor hottSensors[] = { // TX - { HOTT_ID_TX_RSSI_DL, STR_SENSOR_HOTT_ID_TX_RSSI_DL, UNIT_DB, 0}, // downlink signal strength (rx --> tx as seen by tx) - { HOTT_ID_TX_LQI_DL, STR_SENSOR_HOTT_ID_TX_LQI_DL, UNIT_RAW, 0}, // downlink signal quality (rx --> tx s seen by tx) + HS( HOTT_ID_TX_RSSI_DL, STR_SENSOR_HOTT_ID_TX_RSSI_DL, UNIT_DB, 0), // downlink signal strength (rx --> tx as seen by tx) + HS( HOTT_ID_TX_LQI_DL, STR_SENSOR_HOTT_ID_TX_LQI_DL, UNIT_RAW, 0), // downlink signal quality (rx --> tx s seen by tx) // RX - { HOTT_ID_RX_RSSI_UL, STR_SENSOR_HOTT_ID_RX_RSSI_UL, UNIT_DB, 0 }, // uplink signal strength (tx --> rx as seen by rx) - { HOTT_ID_RX_LQI_UL, STR_SENSOR_HOTT_ID_RX_LQI_UL, UNIT_RAW, 0 }, // uplink signal quality (tx --> rx as seen by rx) - { HOTT_ID_RX_VLT, STR_SENSOR_HOTT_ID_RX_VLT, UNIT_VOLTS, 1 }, // RX battery voltage - { HOTT_ID_RX_TMP, STR_SENSOR_HOTT_ID_RX_TMP, UNIT_CELSIUS, 0 }, // RX temperature - { HOTT_ID_RX_BAT_MIN, STR_SENSOR_HOTT_ID_RX_BAT_MIN, UNIT_VOLTS, 1 }, // RX lowest rx voltage - { HOTT_ID_RX_VPCK, STR_SENSOR_HOTT_ID_RX_VPCK, UNIT_MS, 0 }, // RX VPack - { HOTT_ID_RX_EVENT, STR_SENSOR_HOTT_ID_RX_EVENT, UNIT_RAW, 0 }, // RX event and other devices warnings + HS( HOTT_ID_RX_RSSI_UL, STR_SENSOR_HOTT_ID_RX_RSSI_UL, UNIT_DB, 0 ), // uplink signal strength (tx --> rx as seen by rx) + HS( HOTT_ID_RX_LQI_UL, STR_SENSOR_HOTT_ID_RX_LQI_UL, UNIT_RAW, 0 ), // uplink signal quality (tx --> rx as seen by rx) + HS( HOTT_ID_RX_VLT, STR_SENSOR_HOTT_ID_RX_VLT, UNIT_VOLTS, 1 ), // RX battery voltage + HS( HOTT_ID_RX_TMP, STR_SENSOR_HOTT_ID_RX_TMP, UNIT_CELSIUS, 0 ), // RX temperature + HS( HOTT_ID_RX_BAT_MIN, STR_SENSOR_HOTT_ID_RX_BAT_MIN, UNIT_VOLTS, 1 ), // RX lowest rx voltage + HS( HOTT_ID_RX_VPCK, STR_SENSOR_HOTT_ID_RX_VPCK, UNIT_MS, 0 ), // RX VPack + HS( HOTT_ID_RX_EVENT, STR_SENSOR_HOTT_ID_RX_EVENT, UNIT_RAW, 0 ), // RX event and other devices warnings // Vario - { HOTT_ID_VARIO_ALT, STR_SENSOR_HOTT_ID_VARIO_ALT, UNIT_METERS, 0 }, // Vario altitude - { HOTT_ID_VARIO_VV, STR_SENSOR_HOTT_ID_VARIO_VV, UNIT_METERS_PER_SECOND, 2 }, // Vario vertical velocity - { HOTT_ID_VARIO_HDG, STR_SENSOR_HOTT_ID_VARIO_HDG, UNIT_DEGREE, 0 }, // Vario heading + HS( HOTT_ID_VARIO_ALT, STR_SENSOR_HOTT_ID_VARIO_ALT, UNIT_METERS, 0 ), // Vario altitude + HS( HOTT_ID_VARIO_VV, STR_SENSOR_HOTT_ID_VARIO_VV, UNIT_METERS_PER_SECOND, 2 ), // Vario vertical velocity + HS( HOTT_ID_VARIO_HDG, STR_SENSOR_HOTT_ID_VARIO_HDG, UNIT_DEGREE, 0 ), // Vario heading // GPS - { HOTT_ID_GPS_HDG, STR_SENSOR_HOTT_ID_GPS_HDG, UNIT_DEGREE, 0 }, // GPS heading - { HOTT_ID_GPS_SPEED, STR_SENSOR_HOTT_ID_GPS_SPEED, UNIT_KMH, 0 } , // GPS ground speed - { HOTT_ID_GPS_LL, STR_SENSOR_HOTT_ID_GPS_LL, UNIT_GPS, 0 }, // GPS lat/long - { HOTT_ID_GPS_DST, STR_SENSOR_HOTT_ID_GPS_DST, UNIT_METERS, 0 }, // GPS distance - { HOTT_ID_GPS_ALT, STR_SENSOR_HOTT_ID_GPS_ALT, UNIT_METERS, 0 }, // GPS altitude - { HOTT_ID_GPS_VV, STR_SENSOR_HOTT_ID_GPS_VV, UNIT_METERS_PER_SECOND, 2}, // GPS vertical velocity - { HOTT_ID_GPS_NSATS, STR_SENSOR_HOTT_ID_GPS_NSATS, UNIT_RAW, 0 }, // GPS number of satellites + HS( HOTT_ID_GPS_HDG, STR_SENSOR_HOTT_ID_GPS_HDG, UNIT_DEGREE, 0 ), // GPS heading + HS( HOTT_ID_GPS_SPEED, STR_SENSOR_HOTT_ID_GPS_SPEED, UNIT_KMH, 0 ) , // GPS ground speed + HS( HOTT_ID_GPS_LL, STR_SENSOR_HOTT_ID_GPS_LL, UNIT_GPS, 0 ), // GPS lat/long + HS( HOTT_ID_GPS_DST, STR_SENSOR_HOTT_ID_GPS_DST, UNIT_METERS, 0 ), // GPS distance + HS( HOTT_ID_GPS_ALT, STR_SENSOR_HOTT_ID_GPS_ALT, UNIT_METERS, 0 ), // GPS altitude + HS( HOTT_ID_GPS_VV, STR_SENSOR_HOTT_ID_GPS_VV, UNIT_METERS_PER_SECOND, 2), // GPS vertical velocity + HS( HOTT_ID_GPS_NSATS, STR_SENSOR_HOTT_ID_GPS_NSATS, UNIT_RAW, 0 ), // GPS number of satellites // ESC - { HOTT_ID_ESC_VLT, STR_SENSOR_HOTT_ID_ESC_VLT, UNIT_VOLTS, 1 }, // ESC battery voltage - { HOTT_ID_ESC_CAP, STR_SENSOR_HOTT_ID_ESC_CAP, UNIT_MAH, 0 }, // ESC battery capacity consumed - { HOTT_ID_ESC_TMP, STR_SENSOR_HOTT_ID_ESC_TMP, UNIT_CELSIUS, 0 }, // ESC temperature - { HOTT_ID_ESC_CUR, STR_SENSOR_HOTT_ID_ESC_CUR, UNIT_AMPS, 1 }, // ESC current - { HOTT_ID_ESC_RPM, STR_SENSOR_HOTT_ID_ESC_RPM, UNIT_RPMS, 0 }, // ESC motor rpm - { HOTT_ID_ESC_BEC_VLT, STR_SENSOR_HOTT_ID_ESC_BEC_VLT, UNIT_VOLTS, 1 }, // ESC BEC voltage - { HOTT_ID_ESC_BEC_CUR, STR_SENSOR_HOTT_ID_ESC_BEC_CUR, UNIT_AMPS, 1 }, // ESC BEC current - { HOTT_ID_ESC_BEC_TMP, STR_SENSOR_HOTT_ID_ESC_BEC_TMP, UNIT_CELSIUS, 0 }, // BEC BEC temperature - { HOTT_ID_ESC_MOT_TMP, STR_SENSOR_HOTT_ID_ESC_MOT_TMP, UNIT_CELSIUS, 0 }, // ESC motor or external temperature + HS( HOTT_ID_ESC_VLT, STR_SENSOR_HOTT_ID_ESC_VLT, UNIT_VOLTS, 1 ), // ESC battery voltage + HS( HOTT_ID_ESC_CAP, STR_SENSOR_HOTT_ID_ESC_CAP, UNIT_MAH, 0 ), // ESC battery capacity consumed + HS( HOTT_ID_ESC_TMP, STR_SENSOR_HOTT_ID_ESC_TMP, UNIT_CELSIUS, 0 ), // ESC temperature + HS( HOTT_ID_ESC_CUR, STR_SENSOR_HOTT_ID_ESC_CUR, UNIT_AMPS, 1 ), // ESC current + HS( HOTT_ID_ESC_RPM, STR_SENSOR_HOTT_ID_ESC_RPM, UNIT_RPMS, 0 ), // ESC motor rpm + HS( HOTT_ID_ESC_BEC_VLT, STR_SENSOR_HOTT_ID_ESC_BEC_VLT, UNIT_VOLTS, 1 ), // ESC BEC voltage + HS( HOTT_ID_ESC_BEC_CUR, STR_SENSOR_HOTT_ID_ESC_BEC_CUR, UNIT_AMPS, 1 ), // ESC BEC current + HS( HOTT_ID_ESC_BEC_TMP, STR_SENSOR_HOTT_ID_ESC_BEC_TMP, UNIT_CELSIUS, 0 ), // BEC BEC temperature + HS( HOTT_ID_ESC_MOT_TMP, STR_SENSOR_HOTT_ID_ESC_MOT_TMP, UNIT_CELSIUS, 0 ), // ESC motor or external temperature // GAM - { HOTT_ID_GAM_CELS, STR_SENSOR_HOTT_ID_GAM_CELS, UNIT_CELLS, 2}, // GAM Cels L - { HOTT_ID_GAM_VLT1, STR_SENSOR_HOTT_ID_GAM_VLT1, UNIT_VOLTS, 1 }, // GAM voltage battery 1 - { HOTT_ID_GAM_VLT2, STR_SENSOR_HOTT_ID_GAM_VLT2, UNIT_VOLTS, 1 }, // GAM volatge battery 2 - { HOTT_ID_GAM_TMP1, STR_SENSOR_HOTT_ID_GAM_TMP1, UNIT_CELSIUS, 0 }, // GAM temperature 1 - { HOTT_ID_GAM_TMP2, STR_SENSOR_HOTT_ID_GAM_TMP2, UNIT_CELSIUS, 0 }, // GAM temperature 2 - { HOTT_ID_GAM_FUEL, STR_SENSOR_HOTT_ID_GAM_FUEL, UNIT_PERCENT, 0}, // GAM fuel percentage - { HOTT_ID_GAM_RPM1, STR_SENSOR_HOTT_ID_GAM_RPM1, UNIT_RPMS, 0 }, // GAM rpm 1 - { HOTT_ID_GAM_ALT, STR_SENSOR_HOTT_ID_GAM_ALT, UNIT_METERS, 0 }, // GAM altitude - { HOTT_ID_GAM_VV, STR_SENSOR_HOTT_ID_GAM_VV, UNIT_METERS_PER_SECOND, 2 }, // GAM vertical velocity - { HOTT_ID_GAM_CUR, STR_SENSOR_HOTT_ID_GAM_CUR, UNIT_AMPS, 1 }, // GAM current - { HOTT_ID_GAM_VLT3, STR_SENSOR_HOTT_ID_GAM_VLT3, UNIT_VOLTS, 1 }, // GAM voltage battery 3 - { HOTT_ID_GAM_CAP, STR_SENSOR_HOTT_ID_GAM_CAP, UNIT_MAH, 0 }, // GAM battery capacity - { HOTT_ID_GAM_SPEED, STR_SENSOR_HOTT_ID_GAM_SPEED, UNIT_KMH, 0 } , // GAM speed - { HOTT_ID_GAM_RPM2, STR_SENSOR_HOTT_ID_GAM_RPM2, UNIT_RPMS, 0 }, // GAM rmp 2 + HS( HOTT_ID_GAM_CELS, STR_SENSOR_HOTT_ID_GAM_CELS, UNIT_CELLS, 2), // GAM Cels L + HS( HOTT_ID_GAM_VLT1, STR_SENSOR_HOTT_ID_GAM_VLT1, UNIT_VOLTS, 1 ), // GAM voltage battery 1 + HS( HOTT_ID_GAM_VLT2, STR_SENSOR_HOTT_ID_GAM_VLT2, UNIT_VOLTS, 1 ), // GAM volatge battery 2 + HS( HOTT_ID_GAM_TMP1, STR_SENSOR_HOTT_ID_GAM_TMP1, UNIT_CELSIUS, 0 ), // GAM temperature 1 + HS( HOTT_ID_GAM_TMP2, STR_SENSOR_HOTT_ID_GAM_TMP2, UNIT_CELSIUS, 0 ), // GAM temperature 2 + HS( HOTT_ID_GAM_FUEL, STR_SENSOR_HOTT_ID_GAM_FUEL, UNIT_PERCENT, 0), // GAM fuel percentage + HS( HOTT_ID_GAM_RPM1, STR_SENSOR_HOTT_ID_GAM_RPM1, UNIT_RPMS, 0 ), // GAM rpm 1 + HS( HOTT_ID_GAM_ALT, STR_SENSOR_HOTT_ID_GAM_ALT, UNIT_METERS, 0 ), // GAM altitude + HS( HOTT_ID_GAM_VV, STR_SENSOR_HOTT_ID_GAM_VV, UNIT_METERS_PER_SECOND, 2 ), // GAM vertical velocity + HS( HOTT_ID_GAM_CUR, STR_SENSOR_HOTT_ID_GAM_CUR, UNIT_AMPS, 1 ), // GAM current + HS( HOTT_ID_GAM_VLT3, STR_SENSOR_HOTT_ID_GAM_VLT3, UNIT_VOLTS, 1 ), // GAM voltage battery 3 + HS( HOTT_ID_GAM_CAP, STR_SENSOR_HOTT_ID_GAM_CAP, UNIT_MAH, 0 ), // GAM battery capacity + HS( HOTT_ID_GAM_SPEED, STR_SENSOR_HOTT_ID_GAM_SPEED, UNIT_KMH, 0 ) , // GAM speed + HS( HOTT_ID_GAM_RPM2, STR_SENSOR_HOTT_ID_GAM_RPM2, UNIT_RPMS, 0 ), // GAM rmp 2 //EAM - { HOTT_ID_EAM_CELS_L, STR_SENSOR_HOTT_ID_EAM_CELS_L, UNIT_CELLS, 2}, // EAM Cells L voltage - { HOTT_ID_EAM_CELS_H, STR_SENSOR_HOTT_ID_EAM_CELS_H, UNIT_CELLS, 2}, // EAM Cells H voltage - { HOTT_ID_EAM_VLT1, STR_SENSOR_HOTT_ID_EAM_VLT1, UNIT_VOLTS, 1 }, // EAM Voltage battery 1 - { HOTT_ID_EAM_VLT2, STR_SENSOR_HOTT_ID_EAM_VLT2, UNIT_VOLTS, 1 }, // EAM Voltage battery 2 - { HOTT_ID_EAM_TMP1, STR_SENSOR_HOTT_ID_EAM_TMP1, UNIT_CELSIUS, 0 }, // EAM temperature 1 - { HOTT_ID_EAM_TMP2, STR_SENSOR_HOTT_ID_EAM_TMP2, UNIT_CELSIUS, 0 }, // EAM temperature 2 - { HOTT_ID_EAM_ALT, STR_SENSOR_HOTT_ID_EAM_ALT, UNIT_METERS, 0 }, // EAM altitude - { HOTT_ID_EAM_CUR, STR_SENSOR_HOTT_ID_EAM_CUR, UNIT_AMPS, 1 }, // EAM current - { HOTT_ID_EAM_VLT3, STR_SENSOR_HOTT_ID_EAM_VLT3, UNIT_VOLTS, 1 }, // EAM battery voltage 3 - { HOTT_ID_EAM_CAP, STR_SENSOR_HOTT_ID_EAM_CAP, UNIT_MAH, 0 }, // EAM Batt capacity - { HOTT_ID_EAM_VV, STR_SENSOR_HOTT_ID_EAM_VV, UNIT_METERS_PER_SECOND, 2 }, // EAM vertical velcocity - { HOTT_ID_EAM_RPM, STR_SENSOR_HOTT_ID_EAM_RPM, UNIT_RPMS, 0 }, // EAM rpm - { HOTT_ID_EAM_SPEED, STR_SENSOR_HOTT_ID_EAM_SPEED, UNIT_KMH, 0 } , // EAM speed + HS( HOTT_ID_EAM_CELS_L, STR_SENSOR_HOTT_ID_EAM_CELS_L, UNIT_CELLS, 2), // EAM Cells L voltage + HS( HOTT_ID_EAM_CELS_H, STR_SENSOR_HOTT_ID_EAM_CELS_H, UNIT_CELLS, 2), // EAM Cells H voltage + HS( HOTT_ID_EAM_VLT1, STR_SENSOR_HOTT_ID_EAM_VLT1, UNIT_VOLTS, 1 ), // EAM Voltage battery 1 + HS( HOTT_ID_EAM_VLT2, STR_SENSOR_HOTT_ID_EAM_VLT2, UNIT_VOLTS, 1 ), // EAM Voltage battery 2 + HS( HOTT_ID_EAM_TMP1, STR_SENSOR_HOTT_ID_EAM_TMP1, UNIT_CELSIUS, 0 ), // EAM temperature 1 + HS( HOTT_ID_EAM_TMP2, STR_SENSOR_HOTT_ID_EAM_TMP2, UNIT_CELSIUS, 0 ), // EAM temperature 2 + HS( HOTT_ID_EAM_ALT, STR_SENSOR_HOTT_ID_EAM_ALT, UNIT_METERS, 0 ), // EAM altitude + HS( HOTT_ID_EAM_CUR, STR_SENSOR_HOTT_ID_EAM_CUR, UNIT_AMPS, 1 ), // EAM current + HS( HOTT_ID_EAM_VLT3, STR_SENSOR_HOTT_ID_EAM_VLT3, UNIT_VOLTS, 1 ), // EAM battery voltage 3 + HS( HOTT_ID_EAM_CAP, STR_SENSOR_HOTT_ID_EAM_CAP, UNIT_MAH, 0 ), // EAM Batt capacity + HS( HOTT_ID_EAM_VV, STR_SENSOR_HOTT_ID_EAM_VV, UNIT_METERS_PER_SECOND, 2 ), // EAM vertical velcocity + HS( HOTT_ID_EAM_RPM, STR_SENSOR_HOTT_ID_EAM_RPM, UNIT_RPMS, 0 ), // EAM rpm + HS( HOTT_ID_EAM_SPEED, STR_SENSOR_HOTT_ID_EAM_SPEED, UNIT_KMH, 0 ) , // EAM speed // sentinel - {0x00, NULL, UNIT_RAW, 0} // sentinel + HS(0x00, NULL, UNIT_RAW, 0) // sentinel }; const HottSensor * getHottSensor(uint16_t id) diff --git a/radio/src/telemetry/mlink.cpp b/radio/src/telemetry/mlink.cpp index e1ee4856029..5ffa63662d8 100644 --- a/radio/src/telemetry/mlink.cpp +++ b/radio/src/telemetry/mlink.cpp @@ -25,31 +25,33 @@ struct MLinkSensor { const uint16_t id; - const char * name; const TelemetryUnit unit; const uint8_t precision; + const char * name; }; +#define MS(id,name,unit,precision) {id,unit,precision,name} + const MLinkSensor mlinkSensors[] = { - {MLINK_SPECIAL, STR_SENSOR_SPECIAL, UNIT_RAW, 0}, - {MLINK_RX_VOLTAGE, STR_SENSOR_BATT, UNIT_VOLTS, 1}, - {MLINK_VOLTAGE, STR_SENSOR_VFAS, UNIT_VOLTS, 1}, - {MLINK_CURRENT, STR_SENSOR_CURR, UNIT_AMPS, 1}, - {MLINK_VARIO, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 1}, - {MLINK_SPEED, STR_SENSOR_SPEED, UNIT_KMH, 1}, - {MLINK_RPM, STR_SENSOR_RPM, UNIT_RPMS, 0}, - {MLINK_TEMP, STR_SENSOR_TEMP1, UNIT_CELSIUS, 1}, - {MLINK_HEADING, STR_SENSOR_HDG, UNIT_DEGREE, 1}, - {MLINK_ALT, STR_SENSOR_ALT , UNIT_METERS, 0}, - {MLINK_FUEL, STR_SENSOR_FUEL, UNIT_PERCENT, 0}, - {MLINK_CAPACITY, STR_SENSOR_CAPACITY, UNIT_MAH, 0}, - {MLINK_FLOW, STR_SENSOR_FLOW, UNIT_MILLILITERS, 0}, - {MLINK_DISTANCE, STR_SENSOR_DIST, UNIT_KM, 1}, - {MLINK_GRATE, STR_SENSOR_ACC, UNIT_G, 1}, - {MLINK_LQI, STR_SENSOR_RSSI, UNIT_RAW, 0}, - {MLINK_LOSS, STR_SENSOR_LOSS, UNIT_RAW, 0}, - {MLINK_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_RAW, 0}, - {MLINK_TX_LQI, STR_SENSOR_TX_QUALITY, UNIT_RAW, 0}, + MS(MLINK_SPECIAL, STR_SENSOR_SPECIAL, UNIT_RAW, 0), + MS(MLINK_RX_VOLTAGE, STR_SENSOR_BATT, UNIT_VOLTS, 1), + MS(MLINK_VOLTAGE, STR_SENSOR_VFAS, UNIT_VOLTS, 1), + MS(MLINK_CURRENT, STR_SENSOR_CURR, UNIT_AMPS, 1), + MS(MLINK_VARIO, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 1), + MS(MLINK_SPEED, STR_SENSOR_SPEED, UNIT_KMH, 1), + MS(MLINK_RPM, STR_SENSOR_RPM, UNIT_RPMS, 0), + MS(MLINK_TEMP, STR_SENSOR_TEMP1, UNIT_CELSIUS, 1), + MS(MLINK_HEADING, STR_SENSOR_HDG, UNIT_DEGREE, 1), + MS(MLINK_ALT, STR_SENSOR_ALT , UNIT_METERS, 0), + MS(MLINK_FUEL, STR_SENSOR_FUEL, UNIT_PERCENT, 0), + MS(MLINK_CAPACITY, STR_SENSOR_CAPACITY, UNIT_MAH, 0), + MS(MLINK_FLOW, STR_SENSOR_FLOW, UNIT_MILLILITERS, 0), + MS(MLINK_DISTANCE, STR_SENSOR_DIST, UNIT_KM, 1), + MS(MLINK_GRATE, STR_SENSOR_ACC, UNIT_G, 1), + MS(MLINK_LQI, STR_SENSOR_RSSI, UNIT_RAW, 0), + MS(MLINK_LOSS, STR_SENSOR_LOSS, UNIT_RAW, 0), + MS(MLINK_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_RAW, 0), + MS(MLINK_TX_LQI, STR_SENSOR_TX_QUALITY, UNIT_RAW, 0), }; const MLinkSensor * getMLinkSensor(uint16_t id) diff --git a/radio/src/telemetry/spektrum.cpp b/radio/src/telemetry/spektrum.cpp index fd95fc5a87d..4998ed2cfc5 100644 --- a/radio/src/telemetry/spektrum.cpp +++ b/radio/src/telemetry/spektrum.cpp @@ -133,222 +133,224 @@ enum SpektrumDataType : uint8_t { struct SpektrumSensor { const uint8_t i2caddress; - const uint8_t startByte; - const SpektrumDataType dataType; - const char *name; - const TelemetryUnit unit; + const uint8_t startByte:4; + const SpektrumDataType dataType:4; const uint8_t precision; + const TelemetryUnit unit; + const char *name; }; +#define SS(i2caddress,startByte,dataType,name,unit,precision) {i2caddress,startByte,dataType,precision,unit,name} + const SpektrumSensor spektrumSensors[] = { // 0x01 High voltage internal sensor - {I2C_VOLTAGE, 0, int16, STR_SENSOR_A1, UNIT_VOLTS, 2}, // 0.01V increments + SS(I2C_VOLTAGE, 0, int16, STR_SENSOR_A1, UNIT_VOLTS, 2), // 0.01V increments // 0x02 Temperature internal sensor - {I2C_TEMPERATURE, 0, int16, STR_SENSOR_TEMP1, UNIT_FAHRENHEIT, 1}, // Temperature in degrees Fahrenheit + SS(I2C_TEMPERATURE, 0, int16, STR_SENSOR_TEMP1, UNIT_FAHRENHEIT, 1), // Temperature in degrees Fahrenheit // 0x03 High current internal sensor (0x03), Resolution: 300A / 2048 = 0.196791 A/count - {I2C_HIGH_CURRENT, 0, int16, STR_SENSOR_CURR, UNIT_AMPS, 1}, // Range: +/- 150A + SS(I2C_HIGH_CURRENT, 0, int16, STR_SENSOR_CURR, UNIT_AMPS, 1), // Range: +/- 150A // 0x0A Powerbox (also mentioned as 0x7D but that is also transmitter frame data) - {I2C_PBOX, 0, uint16, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 2}, // Volts, 0.01v - {I2C_PBOX, 2, uint16, STR_SENSOR_BATT2_VOLTAGE, UNIT_VOLTS, 2}, - {I2C_PBOX, 4, uint16, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 0}, // mAh, 1mAh - {I2C_PBOX, 6, uint16, STR_SENSOR_BATT2_CONSUMPTION, UNIT_MAH, 0}, + SS(I2C_PBOX, 0, uint16, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 2), // Volts, 0.01v + SS(I2C_PBOX, 2, uint16, STR_SENSOR_BATT2_VOLTAGE, UNIT_VOLTS, 2), + SS(I2C_PBOX, 4, uint16, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 0), // mAh, 1mAh + SS(I2C_PBOX, 6, uint16, STR_SENSOR_BATT2_CONSUMPTION, UNIT_MAH, 0), // 0x0B Lap Timer - {I2C_LAPTIMER, 0, uint8, STR_SENSOR_LAP_NUMBER, UNIT_RAW, 0}, // Lap last finished - {I2C_LAPTIMER, 0, uint8, STR_SENSOR_GATE_NUMBER, UNIT_RAW, 0}, // Last gate passed - {I2C_LAPTIMER, 0, uint32, STR_SENSOR_LAP_TIME, UNIT_SECONDS, 3}, // Time of lap in 1ms increments - {I2C_LAPTIMER, 0, uint32, STR_SENSOR_GATE_TIME, UNIT_SECONDS, 3}, // Duration between last 2 gates + SS(I2C_LAPTIMER, 0, uint8, STR_SENSOR_LAP_NUMBER, UNIT_RAW, 0), // Lap last finished + SS(I2C_LAPTIMER, 0, uint8, STR_SENSOR_GATE_NUMBER, UNIT_RAW, 0), // Last gate passed + SS(I2C_LAPTIMER, 0, uint32, STR_SENSOR_LAP_TIME, UNIT_SECONDS, 3), // Time of lap in 1ms increments + SS(I2C_LAPTIMER, 0, uint32, STR_SENSOR_GATE_TIME, UNIT_SECONDS, 3), // Duration between last 2 gates // Text Generator -//{I2C_TEXTGEN, 0, uint32, STR_SENSOR_FLIGHT_MODE, UNIT_TEXT, 0}, +//SS(I2C_TEXTGEN, 0, uint32, STR_SENSOR_FLIGHT_MODE, UNIT_TEXT, 0), // 0x11 AirSpeed - {I2C_AIRSPEED, 0, int16, STR_SENSOR_ASPD, UNIT_KMH, 0}, // 1 km/h increments -//{I2C_AIRSPEED, 2, int16, STR_SENSOR_MAX_ASPD ?, UNIT_KMH, 0}, // 1 km/h increments + SS(I2C_AIRSPEED, 0, int16, STR_SENSOR_ASPD, UNIT_KMH, 0), // 1 km/h increments +//SS(I2C_AIRSPEED, 2, int16, STR_SENSOR_MAX_ASPD ?, UNIT_KMH, 0), // 1 km/h increments // 0x012 Altitude - {I2C_ALTITUDE, 0, int16, STR_SENSOR_ALT, UNIT_METERS, 1}, // .1m increments -//{I2C_ALTITUDE, 2, int16, STR_SENSOR_MAX_ALT ?, UNIT_METERS, 1}, // .1m increments + SS(I2C_ALTITUDE, 0, int16, STR_SENSOR_ALT, UNIT_METERS, 1), // .1m increments +//SS(I2C_ALTITUDE, 2, int16, STR_SENSOR_MAX_ALT ?, UNIT_METERS, 1), // .1m increments // 0x14 G-Force - {I2C_GMETER, 0, int16, STR_SENSOR_ACCX, UNIT_G, 2}, // force is reported as .01G increments - {I2C_GMETER, 2, int16, STR_SENSOR_ACCY, UNIT_G, 2}, // Range = +/-4000 (+/- 40G) in Pro model - {I2C_GMETER, 4, int16, STR_SENSOR_ACCZ, UNIT_G, 2}, // Range = +/-800 (+/- 8G) in Standard model -//{I2C_GMETER, 6, int16, STR_SENSOR_MAX_ACCX ?, UNIT_G, 2}, // abs(max G X-axis) FORE/AFT -//{I2C_GMETER, 8, int16, STR_SENSOR_MAX_ACCY ?, UNIT_G, 2}, // abs (max G Y-axis) LEFT/RIGHT -//{I2C_GMETER, 10, int16, STR_SENSOR_MAX_ACCZ ?, UNIT_G, 2}, // max G Z-axis WING SPAR LOAD -//{I2C_GMETER, 12, int16, STR_SENSOR_MIN_ACCZ ?, UNIT_G, 2}, // min G Z-axis WING SPAR LOAD + SS(I2C_GMETER, 0, int16, STR_SENSOR_ACCX, UNIT_G, 2), // force is reported as .01G increments + SS(I2C_GMETER, 2, int16, STR_SENSOR_ACCY, UNIT_G, 2), // Range = +/-4000 (+/- 40G) in Pro model + SS(I2C_GMETER, 4, int16, STR_SENSOR_ACCZ, UNIT_G, 2), // Range = +/-800 (+/- 8G) in Standard model +//SS(I2C_GMETER, 6, int16, STR_SENSOR_MAX_ACCX ?, UNIT_G, 2), // abs(max G X-axis) FORE/AFT +//SS(I2C_GMETER, 8, int16, STR_SENSOR_MAX_ACCY ?, UNIT_G, 2), // abs (max G Y-axis) LEFT/RIGHT +//SS(I2C_GMETER, 10, int16, STR_SENSOR_MAX_ACCZ ?, UNIT_G, 2), // max G Z-axis WING SPAR LOAD +//SS(I2C_GMETER, 12, int16, STR_SENSOR_MIN_ACCZ ?, UNIT_G, 2), // min G Z-axis WING SPAR LOAD // 0x15, JETCAT/TURBINE, BCD Encoded values // TODO: Add decoding of status information -//{I2C_JETCAT, 0, uint8, STR_SENSOR_STATUS, UNIT_BITFIELD, 0}, - {I2C_JETCAT, 1, uint8bcd, STR_SENSOR_THROTTLE, UNIT_PERCENT, 0}, - {I2C_JETCAT, 2, uint16bcd, STR_SENSOR_A1, UNIT_VOLTS, 2}, - {I2C_JETCAT, 4, uint16bcd, STR_SENSOR_A2, UNIT_VOLTS, 2}, - {I2C_JETCAT, 6, uint32bcd, STR_SENSOR_RPM, UNIT_RPMS, 0}, - {I2C_JETCAT, 10, uint16bcd, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0}, +//SS(I2C_JETCAT, 0, uint8, STR_SENSOR_STATUS, UNIT_BITFIELD, 0), + SS(I2C_JETCAT, 1, uint8bcd, STR_SENSOR_THROTTLE, UNIT_PERCENT, 0), + SS(I2C_JETCAT, 2, uint16bcd, STR_SENSOR_A1, UNIT_VOLTS, 2), + SS(I2C_JETCAT, 4, uint16bcd, STR_SENSOR_A2, UNIT_VOLTS, 2), + SS(I2C_JETCAT, 6, uint32bcd, STR_SENSOR_RPM, UNIT_RPMS, 0), + SS(I2C_JETCAT, 10, uint16bcd, STR_SENSOR_TEMP1, UNIT_CELSIUS, 0), // 0x16 GPS LOG - {I2C_GPS_LOC, 0, uint16bcd, STR_SENSOR_GPSALT, UNIT_METERS, 1}, // Atl-Low BCD 3.1 - {I2C_GPS_LOC, 2, uint32bcd, STR_SENSOR_GPS, UNIT_GPS, 0}, // LAT and LON - {I2C_GPS_LOC, 10, uint16bcd, STR_SENSOR_HDG, UNIT_DEGREE, 1}, // Course BCD 3.1 -//{I2C_GPS_LOC, 12, uint8bcd, STR_SENSOR_HDOP ?, UNIT_RAW, 1}, // HDOP BCD 1.1 + SS(I2C_GPS_LOC, 0, uint16bcd, STR_SENSOR_GPSALT, UNIT_METERS, 1), // Atl-Low BCD 3.1 + SS(I2C_GPS_LOC, 2, uint32bcd, STR_SENSOR_GPS, UNIT_GPS, 0), // LAT and LON + SS(I2C_GPS_LOC, 10, uint16bcd, STR_SENSOR_HDG, UNIT_DEGREE, 1), // Course BCD 3.1 +//SS(I2C_GPS_LOC, 12, uint8bcd, STR_SENSOR_HDOP ?, UNIT_RAW, 1), // HDOP BCD 1.1 // 0x17 GPS STAT - {I2C_GPS_STAT, 0, uint16bcd, STR_SENSOR_GSPD, UNIT_KTS, 1}, // BCD 3.1 - {I2C_GPS_STAT, 2, uint32bcd, STR_SENSOR_GPSDATETIME, UNIT_DATETIME, 1}, // BCD 6.1 HH:MM:SS.S - {I2C_GPS_STAT, 6, uint8bcd, STR_SENSOR_SATELLITES, UNIT_RAW, 0}, // BCD 2.0 + SS(I2C_GPS_STAT, 0, uint16bcd, STR_SENSOR_GSPD, UNIT_KTS, 1), // BCD 3.1 + SS(I2C_GPS_STAT, 2, uint32bcd, STR_SENSOR_GPSDATETIME, UNIT_DATETIME, 1), // BCD 6.1 HH:MM:SS.S + SS(I2C_GPS_STAT, 6, uint8bcd, STR_SENSOR_SATELLITES, UNIT_RAW, 0), // BCD 2.0 // 0x18 Dual Batt Capacity monitor - Receiver - {I2C_RX_BATT, 0, int16, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 2}, // Instantaneous current, 0.01A (0-327.66A) - {I2C_RX_BATT, 2, uint16, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 1}, // Integrated mAh used, 0.1mAh (0-3276.6mAh) - {I2C_RX_BATT, 4, uint16, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 2}, // Volts, 0.01V increments (0-16.00V) - {I2C_RX_BATT, 6, int16, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 2}, // Instantaneous current, 0.01A (0-327.66A) - {I2C_RX_BATT, 8, uint16, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 1}, // Integrated mAh used, 0.1mAh (0-3276.6mAh) - {I2C_RX_BATT, 10, uint16, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 2}, // Volts, 0.01V increments (0-16.00V) + SS(I2C_RX_BATT, 0, int16, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 2), // Instantaneous current, 0.01A (0-327.66A) + SS(I2C_RX_BATT, 2, uint16, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 1), // Integrated mAh used, 0.1mAh (0-3276.6mAh) + SS(I2C_RX_BATT, 4, uint16, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 2), // Volts, 0.01V increments (0-16.00V) + SS(I2C_RX_BATT, 6, int16, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 2), // Instantaneous current, 0.01A (0-327.66A) + SS(I2C_RX_BATT, 8, uint16, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 1), // Integrated mAh used, 0.1mAh (0-3276.6mAh) + SS(I2C_RX_BATT, 10, uint16, STR_SENSOR_BATT1_VOLTAGE, UNIT_VOLTS, 2), // Volts, 0.01V increments (0-16.00V) // 0x19 Jetcat flow rate -//{I2C_JETCAT_2, 0, uint16bcd, STR_SENSOR_FUEL_CONSUMPTION, UNIT_MILLILITERS_PER_MINUTE, 1}, missing ml/min - {I2C_JETCAT_2, 2, uint32bcd, STR_SENSOR_FUEL, UNIT_MILLILITERS, 1}, +//SS(I2C_JETCAT_2, 0, uint16bcd, STR_SENSOR_FUEL_CONSUMPTION, UNIT_MILLILITERS_PER_MINUTE, 1), missing ml/min + SS(I2C_JETCAT_2, 2, uint32bcd, STR_SENSOR_FUEL, UNIT_MILLILITERS, 1), // 0x1a Gyro - {I2C_GYRO, 0, int16, STR_SENSOR_GYROX, UNIT_DEGREE, 1}, // Units are 0.1 deg/sec - {I2C_GYRO, 2, int16, STR_SENSOR_GYROY, UNIT_DEGREE, 1}, - {I2C_GYRO, 4, int16, STR_SENSOR_GYROZ, UNIT_DEGREE, 1}, - //{I2C_GYRO, 6, int16, STR_SENSOR_MAX_GYROX ?, UNIT_DEGREE, 1}, // abs (max) - //{I2C_GYRO, 8, int16, STR_SENSOR_MAX_GYROY ?, UNIT_DEGREE, 1}, - //{I2C_GYRO, 10, int16, STR_SENSOR_MAX_GYROZ ?, UNIT_DEGREE, 1}, + SS(I2C_GYRO, 0, int16, STR_SENSOR_GYROX, UNIT_DEGREE, 1), // Units are 0.1 deg/sec + SS(I2C_GYRO, 2, int16, STR_SENSOR_GYROY, UNIT_DEGREE, 1), + SS(I2C_GYRO, 4, int16, STR_SENSOR_GYROZ, UNIT_DEGREE, 1), + //SS(I2C_GYRO, 6, int16, STR_SENSOR_MAX_GYROX ?, UNIT_DEGREE, 1), // abs (max) + //SS(I2C_GYRO, 8, int16, STR_SENSOR_MAX_GYROY ?, UNIT_DEGREE, 1), + //SS(I2C_GYRO, 10, int16, STR_SENSOR_MAX_GYROZ ?, UNIT_DEGREE, 1), // 0x1b Attitude & Mag Compass // mag Units are tbd so probably no sensor in existance, ignore them for now - {I2C_ATTMAG, 0, int16, STR_SENSOR_ROLL, UNIT_DEGREE, 1}, // Attitude, 3 axes. - {I2C_ATTMAG, 2, int16, STR_SENSOR_PITCH, UNIT_DEGREE, 1}, // Units are 0.1 deg - {I2C_ATTMAG, 4, int16, STR_SENSOR_YAW, UNIT_DEGREE, 1}, -//{I2C_ATTMAG, 6, int16, STR_SENSOR_MAGX ?, ??, 1}, // Magnetic Compass, 3 axes -//{I2C_ATTMAG, 8, int16, STR_SENSOR_MAGY ?, ??, 1}, // Units are 0.1mG -//{I2C_ATTMAG, 10, int16, STR_SENSOR_MAXZ ?, ??, 1}, -//{I2C_ATTMAG, 12, int16, STR_SENSOR_HDG ?, UNIT_DEGREE, 1}, // Heading, 0.1deg + SS(I2C_ATTMAG, 0, int16, STR_SENSOR_ROLL, UNIT_DEGREE, 1), // Attitude, 3 axes. + SS(I2C_ATTMAG, 2, int16, STR_SENSOR_PITCH, UNIT_DEGREE, 1), // Units are 0.1 deg + SS(I2C_ATTMAG, 4, int16, STR_SENSOR_YAW, UNIT_DEGREE, 1), +//SS(I2C_ATTMAG, 6, int16, STR_SENSOR_MAGX ?, ??, 1), // Magnetic Compass, 3 axes +//SS(I2C_ATTMAG, 8, int16, STR_SENSOR_MAGY ?, ??, 1), // Units are 0.1mG +//SS(I2C_ATTMAG, 10, int16, STR_SENSOR_MAXZ ?, ??, 1), +//SS(I2C_ATTMAG, 12, int16, STR_SENSOR_HDG ?, UNIT_DEGREE, 1), // Heading, 0.1deg // 0x20 Smart ESC telemetry - {I2C_ESC, 0, uint16, STR_SENSOR_ESC_RPM2, UNIT_RPMS, 0}, // Electrical RPM, 10RPM (0-655340 RPM) - {I2C_ESC, 2, uint16, STR_SENSOR_ESC_VIN, UNIT_VOLTS, 2}, // Volts, 0.01v (0-655.34V) - {I2C_ESC, 4, uint16, STR_SENSOR_ESC_TFET, UNIT_CELSIUS, 1}, // Temperature, 0.1C (0-6553.4C) - {I2C_ESC, 6, uint16, STR_SENSOR_ESC_CUR, UNIT_AMPS, 2}, // Current, 10mA (0-655.34A) - {I2C_ESC, 8, uint16, STR_SENSOR_ESC_TBEC, UNIT_CELSIUS, 1}, // Temperature, 0.1C (0-6553.4C) - {I2C_ESC, 10, uint8, STR_SENSOR_ESC_BCUR, UNIT_AMPS, 1}, // BEC Current, 100mA (0-25.4A) - {I2C_ESC, 11, uint8, STR_SENSOR_ESC_VBEC, UNIT_VOLTS, 2}, // BEC Volts, 0.05V (0-12.70V) - {I2C_ESC, 12, uint8, STR_SENSOR_ESC_THR, UNIT_PERCENT, 0}, // 0.5% (0-100%) - {I2C_ESC, 13, uint8, STR_SENSOR_ESC_POUT, UNIT_PERCENT, 0}, // Power Output, 0.5% (0-127%) + SS(I2C_ESC, 0, uint16, STR_SENSOR_ESC_RPM2, UNIT_RPMS, 0), // Electrical RPM, 10RPM (0-655340 RPM) + SS(I2C_ESC, 2, uint16, STR_SENSOR_ESC_VIN, UNIT_VOLTS, 2), // Volts, 0.01v (0-655.34V) + SS(I2C_ESC, 4, uint16, STR_SENSOR_ESC_TFET, UNIT_CELSIUS, 1), // Temperature, 0.1C (0-6553.4C) + SS(I2C_ESC, 6, uint16, STR_SENSOR_ESC_CUR, UNIT_AMPS, 2), // Current, 10mA (0-655.34A) + SS(I2C_ESC, 8, uint16, STR_SENSOR_ESC_TBEC, UNIT_CELSIUS, 1), // Temperature, 0.1C (0-6553.4C) + SS(I2C_ESC, 10, uint8, STR_SENSOR_ESC_BCUR, UNIT_AMPS, 1), // BEC Current, 100mA (0-25.4A) + SS(I2C_ESC, 11, uint8, STR_SENSOR_ESC_VBEC, UNIT_VOLTS, 2), // BEC Volts, 0.05V (0-12.70V) + SS(I2C_ESC, 12, uint8, STR_SENSOR_ESC_THR, UNIT_PERCENT, 0), // 0.5% (0-100%) + SS(I2C_ESC, 13, uint8, STR_SENSOR_ESC_POUT, UNIT_PERCENT, 0), // Power Output, 0.5% (0-127%) // 0x26 GPS Binary - {I2C_GPS_BIN, 0, uint16, STR_SENSOR_GPSALT, UNIT_METERS, 0}, // altitude m, 1000m offset - {I2C_GPS_BIN, 2, int32, STR_SENSOR_GPS, UNIT_GPS, 0}, // latitude+long degree / 10,000,000 - {I2C_GPS_BIN, 10, uint16, STR_SENSOR_HDG, UNIT_DEGREE, 1}, // heading/course degree / 10 - {I2C_GPS_BIN, 12, uint8, STR_SENSOR_GSPD, UNIT_KMH, 0}, // ground speed Km/h - {I2C_GPS_BIN, 13, uint8, STR_SENSOR_SATELLITES, UNIT_RAW, 0}, // count + SS(I2C_GPS_BIN, 0, uint16, STR_SENSOR_GPSALT, UNIT_METERS, 0), // altitude m, 1000m offset + SS(I2C_GPS_BIN, 2, int32, STR_SENSOR_GPS, UNIT_GPS, 0), // latitude+long degree / 10,000,000 + SS(I2C_GPS_BIN, 10, uint16, STR_SENSOR_HDG, UNIT_DEGREE, 1), // heading/course degree / 10 + SS(I2C_GPS_BIN, 12, uint8, STR_SENSOR_GSPD, UNIT_KMH, 0), // ground speed Km/h + SS(I2C_GPS_BIN, 13, uint8, STR_SENSOR_SATELLITES, UNIT_RAW, 0), // count // 0x34 Dual Batt Capacity monitor - Flight Pack // The difference with sensor 0x18 (RX capacity monitor) is the consumption magnitude. // RX (0x18) is up to 3.2A, and flight pack is up to 32A (x 10 or 1 decimal place) // Right now they have the same sensor name... could this sensors (0x18 and 0x34) be used at the same time? - {I2C_FP_BATT, 0, int16le, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 1}, // Instantaneous current, 0.1A (0-3276.6A) - {I2C_FP_BATT, 2, int16le, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 0}, // Integrated mAh used, 1mAh (0-32.766Ah) - {I2C_FP_BATT, 4, int16le, STR_SENSOR_BATT1_TEMP, UNIT_CELSIUS, 1}, // Temperature, 0.1C (0-150C) - {I2C_FP_BATT, 6, int16le, STR_SENSOR_BATT2_CURRENT, UNIT_AMPS, 1}, // Instantaneous current, 0.1A (0-3276.6A) - {I2C_FP_BATT, 8, int16le, STR_SENSOR_BATT2_CONSUMPTION, UNIT_MAH, 0}, // Integrated mAh used, 1mAh (0-32.766Ah) - {I2C_FP_BATT, 10, int16le, STR_SENSOR_BATT2_TEMP, UNIT_CELSIUS, 1}, // Temperature, 0.1C (0-150C) + SS(I2C_FP_BATT, 0, int16le, STR_SENSOR_BATT1_CURRENT, UNIT_AMPS, 1), // Instantaneous current, 0.1A (0-3276.6A) + SS(I2C_FP_BATT, 2, int16le, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 0), // Integrated mAh used, 1mAh (0-32.766Ah) + SS(I2C_FP_BATT, 4, int16le, STR_SENSOR_BATT1_TEMP, UNIT_CELSIUS, 1), // Temperature, 0.1C (0-150C) + SS(I2C_FP_BATT, 6, int16le, STR_SENSOR_BATT2_CURRENT, UNIT_AMPS, 1), // Instantaneous current, 0.1A (0-3276.6A) + SS(I2C_FP_BATT, 8, int16le, STR_SENSOR_BATT2_CONSUMPTION, UNIT_MAH, 0), // Integrated mAh used, 1mAh (0-32.766Ah) + SS(I2C_FP_BATT, 10, int16le, STR_SENSOR_BATT2_TEMP, UNIT_CELSIUS, 1), // Temperature, 0.1C (0-150C) // Tank pressure + custom input bits (ignore for now) -//{0x38, 0, uint16, STR_SENSOR_STATUS_BITS, UNIT_BITFIELD, 0}, -//{0x38, 0, uint16, STR_SENSOR_PRESSSURE, UNIT_PSI, 1}, +//SS(0x38, 0, uint16, STR_SENSOR_STATUS_BITS, UNIT_BITFIELD, 0), +//SS(0x38, 0, uint16, STR_SENSOR_PRESSSURE, UNIT_PSI, 1), // 0x3A Lipo 6s Monitor Cells - {I2C_CELLS, 0, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2}, // Voltage across cell 1, .01V steps - {I2C_CELLS, 2, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2}, - {I2C_CELLS, 4, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2}, - {I2C_CELLS, 6, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2}, - {I2C_CELLS, 8, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2}, - {I2C_CELLS, 10, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2}, - {I2C_CELLS, 12, uint16, STR_SENSOR_TEMP2, UNIT_CELSIUS, 2}, // Temperature, 0.1C (0-655.34C) + SS(I2C_CELLS, 0, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2), // Voltage across cell 1, .01V steps + SS(I2C_CELLS, 2, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2), + SS(I2C_CELLS, 4, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2), + SS(I2C_CELLS, 6, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2), + SS(I2C_CELLS, 8, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2), + SS(I2C_CELLS, 10, uint16, STR_SENSOR_CELLS, UNIT_VOLTS, 2), + SS(I2C_CELLS, 12, uint16, STR_SENSOR_TEMP2, UNIT_CELSIUS, 2), // Temperature, 0.1C (0-655.34C) // 0x40 Vario-S - {I2C_VARIO, 0, int16, STR_SENSOR_ALT, UNIT_METERS, 1}, - {I2C_VARIO, 2, int16, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 1}, + SS(I2C_VARIO, 0, int16, STR_SENSOR_ALT, UNIT_METERS, 1), + SS(I2C_VARIO, 2, int16, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 1), // 0x42 Smartbat -//{I2C_SMART_BAT_REALTIME, 1, int8, STR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, // disabled because sensor is a duplicate of cells sensors ones - {I2C_SMART_BAT_REALTIME, 2, uint32le, STR_SENSOR_SMART_BAT_BCUR, UNIT_MAH, 0}, - {I2C_SMART_BAT_REALTIME, 6, uint16le, STR_SENSOR_SMART_BAT_BCAP, UNIT_MAH, 0}, - {I2C_SMART_BAT_REALTIME, 8, uint16le, STR_SENSOR_SMART_BAT_MIN_CEL, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_REALTIME, 10, uint16le, STR_SENSOR_SMART_BAT_MAX_CEL, UNIT_VOLTS, 2}, -//{I2C_SMART_BAT_REALTIME, 12, uint16le, "RFU[2]", UNIT_RAW, 0}, // disabled to save sensors slots - - {I2C_SMART_BAT_CELLS_1_6, 1, int8, STR_SENSOR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, - {I2C_SMART_BAT_CELLS_1_6, 2, uint16le, STR_SENSOR_CL01, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_1_6, 4, uint16le, STR_SENSOR_CL02, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_1_6, 6, uint16le, STR_SENSOR_CL03, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_1_6, 8, uint16le, STR_SENSOR_CL04, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_1_6, 10, uint16le, STR_SENSOR_CL05, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_1_6, 12, uint16le, STR_SENSOR_CL06, UNIT_VOLTS, 2}, - - {I2C_SMART_BAT_CELLS_7_12, 1, int8, STR_SENSOR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, - {I2C_SMART_BAT_CELLS_7_12, 2, uint16le, STR_SENSOR_CL07, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_7_12, 4, uint16le, STR_SENSOR_CL08, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_7_12, 6, uint16le, STR_SENSOR_CL09, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_7_12, 8, uint16le, STR_SENSOR_CL10, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_7_12, 10, uint16le, STR_SENSOR_CL11, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_7_12, 12, uint16le, STR_SENSOR_CL12, UNIT_VOLTS, 2}, - - {I2C_SMART_BAT_CELLS_13_18, 1, int8, STR_SENSOR_SMART_BAT_BTMP, UNIT_CELSIUS, 0}, - {I2C_SMART_BAT_CELLS_13_18, 2, uint16le, STR_SENSOR_CL13, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_13_18, 4, uint16le, STR_SENSOR_CL14, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_13_18, 6, uint16le, STR_SENSOR_CL15, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_13_18, 8, uint16le, STR_SENSOR_CL16, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_13_18, 10, uint16le, STR_SENSOR_CL17, UNIT_VOLTS, 2}, - {I2C_SMART_BAT_CELLS_13_18, 12, uint16le, STR_SENSOR_CL18, UNIT_VOLTS, 2}, - - //{I2C_SMART_BAT_ID, 1, uint8, "chemistery", UNIT_RAW, 0}, // disabled to save sensors slots - //{I2C_SMART_BAT_ID, 2, uint8, "number of cells", UNIT_RAW, 0}, // disabled to save sensors slots - //{I2C_SMART_BAT_ID, 3, uint8, "manufacturer code", UNIT_RAW, 0}, // disabled to save sensors slots - {I2C_SMART_BAT_ID, 4, uint16le, STR_SENSOR_SMART_BAT_CYCLES, UNIT_RAW, 0}, - //{I2C_SMART_BAT_ID, 6, uint8, "uniqueID[8]", UNIT_RAW, 0}, // disabled to save sensors slots - - //{I2C_SMART_BAT_LIMITS, 1, uint8, "rfu", UNIT_RAW, 0}, // disabled to save sensors slots - {I2C_SMART_BAT_LIMITS, 2, uint16le, STR_SENSOR_SMART_BAT_CAPACITY,UNIT_MAH, 0}, - //{I2C_SMART_BAT_LIMITS, 4, uint16le, "dischargeCurrentRating", UNIT_RAW, 0}, // disabled to save sensors slots - //{I2C_SMART_BAT_LIMITS, 6, uint16le, "overDischarge_mV", UNIT_RAW, 0}, // disabled to save sensors slots - //{I2C_SMART_BAT_LIMITS, 8, uint16le, "zeroCapacity_mV", UNIT_RAW, 0}, // disabled to save sensors slots - //{I2C_SMART_BAT_LIMITS, 10, uint16le, "fullyCharged_mV", UNIT_RAW, 0}, // disabled to save sensors slots - //{I2C_SMART_BAT_LIMITS, 12, uint8, "minWorkingTemp", UNIT_RAW, 0}, // disabled to save sensors slots - //{I2C_SMART_BAT_LIMITS, 13, uint8, "maxWorkingTemp", UNIT_RAW, 0}, // disabled to save sensors slots +//SS(I2C_SMART_BAT_REALTIME, 1, int8, STR_SMART_BAT_BTMP, UNIT_CELSIUS, 0), // disabled because sensor is a duplicate of cells sensors ones + SS(I2C_SMART_BAT_REALTIME, 2, uint32le, STR_SENSOR_SMART_BAT_BCUR, UNIT_MAH, 0), + SS(I2C_SMART_BAT_REALTIME, 6, uint16le, STR_SENSOR_SMART_BAT_BCAP, UNIT_MAH, 0), + SS(I2C_SMART_BAT_REALTIME, 8, uint16le, STR_SENSOR_SMART_BAT_MIN_CEL, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_REALTIME, 10, uint16le, STR_SENSOR_SMART_BAT_MAX_CEL, UNIT_VOLTS, 2), +//SS(I2C_SMART_BAT_REALTIME, 12, uint16le, "RFU[2]", UNIT_RAW, 0), // disabled to save sensors slots + + SS(I2C_SMART_BAT_CELLS_1_6, 1, int8, STR_SENSOR_SMART_BAT_BTMP, UNIT_CELSIUS, 0), + SS(I2C_SMART_BAT_CELLS_1_6, 2, uint16le, STR_SENSOR_CL01, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_1_6, 4, uint16le, STR_SENSOR_CL02, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_1_6, 6, uint16le, STR_SENSOR_CL03, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_1_6, 8, uint16le, STR_SENSOR_CL04, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_1_6, 10, uint16le, STR_SENSOR_CL05, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_1_6, 12, uint16le, STR_SENSOR_CL06, UNIT_VOLTS, 2), + + SS(I2C_SMART_BAT_CELLS_7_12, 1, int8, STR_SENSOR_SMART_BAT_BTMP, UNIT_CELSIUS, 0), + SS(I2C_SMART_BAT_CELLS_7_12, 2, uint16le, STR_SENSOR_CL07, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_7_12, 4, uint16le, STR_SENSOR_CL08, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_7_12, 6, uint16le, STR_SENSOR_CL09, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_7_12, 8, uint16le, STR_SENSOR_CL10, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_7_12, 10, uint16le, STR_SENSOR_CL11, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_7_12, 12, uint16le, STR_SENSOR_CL12, UNIT_VOLTS, 2), + + SS(I2C_SMART_BAT_CELLS_13_18, 1, int8, STR_SENSOR_SMART_BAT_BTMP, UNIT_CELSIUS, 0), + SS(I2C_SMART_BAT_CELLS_13_18, 2, uint16le, STR_SENSOR_CL13, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_13_18, 4, uint16le, STR_SENSOR_CL14, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_13_18, 6, uint16le, STR_SENSOR_CL15, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_13_18, 8, uint16le, STR_SENSOR_CL16, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_13_18, 10, uint16le, STR_SENSOR_CL17, UNIT_VOLTS, 2), + SS(I2C_SMART_BAT_CELLS_13_18, 12, uint16le, STR_SENSOR_CL18, UNIT_VOLTS, 2), + + //SS(I2C_SMART_BAT_ID, 1, uint8, "chemistery", UNIT_RAW, 0), // disabled to save sensors slots + //SS(I2C_SMART_BAT_ID, 2, uint8, "number of cells", UNIT_RAW, 0), // disabled to save sensors slots + //SS(I2C_SMART_BAT_ID, 3, uint8, "manufacturer code", UNIT_RAW, 0), // disabled to save sensors slots + SS(I2C_SMART_BAT_ID, 4, uint16le, STR_SENSOR_SMART_BAT_CYCLES, UNIT_RAW, 0), + //SS(I2C_SMART_BAT_ID, 6, uint8, "uniqueID[8]", UNIT_RAW, 0), // disabled to save sensors slots + + //SS(I2C_SMART_BAT_LIMITS, 1, uint8, "rfu", UNIT_RAW, 0), // disabled to save sensors slots + SS(I2C_SMART_BAT_LIMITS, 2, uint16le, STR_SENSOR_SMART_BAT_CAPACITY,UNIT_MAH, 0), + //SS(I2C_SMART_BAT_LIMITS, 4, uint16le, "dischargeCurrentRating", UNIT_RAW, 0), // disabled to save sensors slots + //SS(I2C_SMART_BAT_LIMITS, 6, uint16le, "overDischarge_mV", UNIT_RAW, 0), // disabled to save sensors slots + //SS(I2C_SMART_BAT_LIMITS, 8, uint16le, "zeroCapacity_mV", UNIT_RAW, 0), // disabled to save sensors slots + //SS(I2C_SMART_BAT_LIMITS, 10, uint16le, "fullyCharged_mV", UNIT_RAW, 0), // disabled to save sensors slots + //SS(I2C_SMART_BAT_LIMITS, 12, uint8, "minWorkingTemp", UNIT_RAW, 0), // disabled to save sensors slots + //SS(I2C_SMART_BAT_LIMITS, 13, uint8, "maxWorkingTemp", UNIT_RAW, 0), // disabled to save sensors slots // 0x50-0x56 custom 3rd party sensors - //{0x50, 0, int16, STR_SENSOR_} + //SS(0x50, 0, int16, STR_SENSOR_) // 0x7d are transmitter channels frame data [7], probably only available on the Spektrum // telemetry bus on the model itself // 0x7E RPM/Volts/Temperature - {I2C_RPM, 0, uint16, STR_SENSOR_RPM, UNIT_RPMS, 0}, // microseconds between pulse leading edges - {I2C_RPM, 2, uint16, STR_SENSOR_A3, UNIT_VOLTS, 2}, // 0.01V increments (typically flight pack voltage) - {I2C_RPM, 4, int16, STR_SENSOR_TEMP2, UNIT_FAHRENHEIT, 0}, // Temperature in degrees F. + SS(I2C_RPM, 0, uint16, STR_SENSOR_RPM, UNIT_RPMS, 0), // microseconds between pulse leading edges + SS(I2C_RPM, 2, uint16, STR_SENSOR_A3, UNIT_VOLTS, 2), // 0.01V increments (typically flight pack voltage) + SS(I2C_RPM, 4, int16, STR_SENSOR_TEMP2, UNIT_FAHRENHEIT, 0), // Temperature in degrees F. // 0x7f, QoS DATA, also called Flight Log - {I2C_QOS, 0, uint16, STR_SENSOR_QOS_A, UNIT_RAW, 0}, // A - Antenna Fades on Receiver A - {I2C_QOS, 2, uint16, STR_SENSOR_QOS_B, UNIT_RAW, 0}, // B - Antenna Fades on Receiver B - {I2C_QOS, 4, uint16, STR_SENSOR_QOS_L, UNIT_RAW, 0}, // L - Antenna Fades on left Receiver - {I2C_QOS, 6, uint16, STR_SENSOR_QOS_R, UNIT_RAW, 0}, // R - Antenna Fades on right Receiver - {I2C_QOS, 8, uint16, STR_SENSOR_QOS_F, UNIT_RAW, 0}, // F - Frame losses. - {I2C_QOS, 10, uint16, STR_SENSOR_QOS_H, UNIT_RAW, 0}, // H - Holds - {I2C_QOS, 12, uint16, STR_SENSOR_A2, UNIT_VOLTS, 2}, // Volts, .01V increment. - - {I2C_PSEUDO_TX, 0, uint8, STR_SENSOR_TX_RSSI, UNIT_RAW, 0}, - {I2C_PSEUDO_TX, 4, uint32, STR_SENSOR_BIND, UNIT_RAW, 0}, - {I2C_PSEUDO_TX, 8, uint32, STR_SENSOR_FLIGHT_MODE, UNIT_TEXT, 0}, - {0, 0, int16, NULL, UNIT_RAW, 0} //sentinel + SS(I2C_QOS, 0, uint16, STR_SENSOR_QOS_A, UNIT_RAW, 0), // A - Antenna Fades on Receiver A + SS(I2C_QOS, 2, uint16, STR_SENSOR_QOS_B, UNIT_RAW, 0), // B - Antenna Fades on Receiver B + SS(I2C_QOS, 4, uint16, STR_SENSOR_QOS_L, UNIT_RAW, 0), // L - Antenna Fades on left Receiver + SS(I2C_QOS, 6, uint16, STR_SENSOR_QOS_R, UNIT_RAW, 0), // R - Antenna Fades on right Receiver + SS(I2C_QOS, 8, uint16, STR_SENSOR_QOS_F, UNIT_RAW, 0), // F - Frame losses. + SS(I2C_QOS, 10, uint16, STR_SENSOR_QOS_H, UNIT_RAW, 0), // H - Holds + SS(I2C_QOS, 12, uint16, STR_SENSOR_A2, UNIT_VOLTS, 2), // Volts, .01V increment. + + SS(I2C_PSEUDO_TX, 0, uint8, STR_SENSOR_TX_RSSI, UNIT_RAW, 0), + SS(I2C_PSEUDO_TX, 4, uint32, STR_SENSOR_BIND, UNIT_RAW, 0), + SS(I2C_PSEUDO_TX, 8, uint32, STR_SENSOR_FLIGHT_MODE, UNIT_TEXT, 0), + SS(0, 0, int16, NULL, UNIT_RAW, 0) //sentinel }; // Alt Low and High needs to be combined (in 2 diff packets) From 47ff7284fd562e09cebc5c90ba120990b69027ad Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sun, 24 Sep 2023 07:51:18 +0200 Subject: [PATCH 24/29] fix(radio): Better iteration through mixers on display, sanitize invalid sources (#3999) * fix: mixer lines with empty source Fixes #3367 * Fix color mixes display. --------- Co-authored-by: Phil Mitchell --- radio/src/CMakeLists.txt | 1 + radio/src/gui/128x64/gui.h | 3 - radio/src/gui/128x64/model_mix_edit.cpp | 1 + radio/src/gui/212x64/gui.h | 4 - radio/src/gui/212x64/model_mix_edit.cpp | 1 + radio/src/gui/colorlcd/menus.h | 5 - radio/src/gui/colorlcd/mixer_edit.cpp | 1 + radio/src/gui/colorlcd/mixer_edit_adv.cpp | 1 + radio/src/gui/colorlcd/model_mixes.cpp | 126 +--------------- radio/src/gui/common/stdlcd/model_mixes.cpp | 124 ++------------- radio/src/gui/gui_common.cpp | 1 + radio/src/lua/api_model.cpp | 6 +- radio/src/mixer.cpp | 1 + radio/src/mixes.cpp | 159 ++++++++++++++++++++ radio/src/mixes.h | 48 ++++++ radio/src/model_init.cpp | 1 + radio/src/opentx.cpp | 5 - radio/src/opentx.h | 1 - radio/src/storage/storage_common.cpp | 18 ++- 19 files changed, 248 insertions(+), 259 deletions(-) create mode 100644 radio/src/mixes.cpp create mode 100644 radio/src/mixes.h diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index a5ce3292344..5f6741d3b28 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -388,6 +388,7 @@ set(SRC strhelpers.cpp switches.cpp analogs.cpp + mixes.cpp mixer.cpp mixer_scheduler.cpp stamp.cpp diff --git a/radio/src/gui/128x64/gui.h b/radio/src/gui/128x64/gui.h index 477155f70a3..c767ab8a892 100644 --- a/radio/src/gui/128x64/gui.h +++ b/radio/src/gui/128x64/gui.h @@ -158,9 +158,6 @@ extern uint8_t editNameCursorPos; uint8_t getExposCount(); void insertExpo(uint8_t idx); void deleteExpo(uint8_t idx); -uint8_t getMixesCount(); -void insertMix(uint8_t idx); -void deleteMix(uint8_t idx); void onSwitchLongEnterPress(const char *result); void onSourceLongEnterPress(const char *result); diff --git a/radio/src/gui/128x64/model_mix_edit.cpp b/radio/src/gui/128x64/model_mix_edit.cpp index 735157111c6..bb01ad2c8bc 100644 --- a/radio/src/gui/128x64/model_mix_edit.cpp +++ b/radio/src/gui/128x64/model_mix_edit.cpp @@ -20,6 +20,7 @@ */ #include "opentx.h" +#include "mixes.h" enum MixFields { MIX_FIELD_NAME, diff --git a/radio/src/gui/212x64/gui.h b/radio/src/gui/212x64/gui.h index 0bee01de875..f7ff0490490 100644 --- a/radio/src/gui/212x64/gui.h +++ b/radio/src/gui/212x64/gui.h @@ -157,10 +157,6 @@ uint8_t getExposCount(); void deleteExpo(uint8_t idx); void insertExpo(uint8_t idx); -uint8_t getMixesCount(); -void deleteMix(uint8_t idx); -void insertMix(uint8_t idx); - #define STATUS_LINE_LENGTH 32 extern char statusLineMsg[STATUS_LINE_LENGTH]; void showStatusLine(); diff --git a/radio/src/gui/212x64/model_mix_edit.cpp b/radio/src/gui/212x64/model_mix_edit.cpp index 3bca95c5785..6fc15a43ad0 100644 --- a/radio/src/gui/212x64/model_mix_edit.cpp +++ b/radio/src/gui/212x64/model_mix_edit.cpp @@ -20,6 +20,7 @@ */ #include "opentx.h" +#include "mixes.h" enum MixFields { MIX_FIELD_NAME, diff --git a/radio/src/gui/colorlcd/menus.h b/radio/src/gui/colorlcd/menus.h index 7c338d949f8..2c6740ddc0a 100644 --- a/radio/src/gui/colorlcd/menus.h +++ b/radio/src/gui/colorlcd/menus.h @@ -101,11 +101,6 @@ uint8_t getExposCount(); void deleteExpo(uint8_t idx); void insertExpo(uint8_t idx, uint8_t input); -uint8_t getMixesCount(); -void deleteMix(uint8_t idx); -void insertMix(uint8_t idx); -void copyMix(uint8_t source, uint8_t dest, int8_t ch); - typedef int (*FnFuncP) (int x); void drawFunction(FnFuncP fn, int x, int y, int width); diff --git a/radio/src/gui/colorlcd/mixer_edit.cpp b/radio/src/gui/colorlcd/mixer_edit.cpp index 2ff64b9aed2..08ded25f2ec 100644 --- a/radio/src/gui/colorlcd/mixer_edit.cpp +++ b/radio/src/gui/colorlcd/mixer_edit.cpp @@ -24,6 +24,7 @@ #include "channel_bar.h" #include "gvar_numberedit.h" #include "curve_param.h" +#include "mixes.h" #include "opentx.h" diff --git a/radio/src/gui/colorlcd/mixer_edit_adv.cpp b/radio/src/gui/colorlcd/mixer_edit_adv.cpp index c753b5d979a..faf8661fa42 100644 --- a/radio/src/gui/colorlcd/mixer_edit_adv.cpp +++ b/radio/src/gui/colorlcd/mixer_edit_adv.cpp @@ -22,6 +22,7 @@ #include "mixer_edit_adv.h" #include "numberedit.h" #include "fm_matrix.h" +#include "mixes.h" #include "opentx.h" diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index 8385fcb4e3f..0ab6eb2b535 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -31,6 +31,7 @@ #include "input_mix_button.h" #include "mixer_edit.h" #include "input_mapping.h" +#include "mixes.h" #include "tasks/mixer_task.h" #include "hal/adc_driver.h" @@ -54,119 +55,6 @@ static const uint8_t _mask_mplex_replace[] = { }; STATIC_LZ4_BITMAP(mask_mplex_replace); -uint8_t getMixesCount() -{ - uint8_t count = 0; - uint8_t ch; - - for (int i = MAX_MIXERS - 1; i >= 0; i--) { - ch = mixAddress(i)->srcRaw; - if (ch != 0) { - count++; - } - } - return count; -} - -void insertMix(uint8_t idx, uint8_t channel) -{ - mixerTaskStop(); - MixData *mix = mixAddress(idx); - memmove(mix + 1, mix, (MAX_MIXERS - (idx + 1)) * sizeof(MixData)); - memclear(mix, sizeof(MixData)); - mix->destCh = channel; - mix->srcRaw = channel + 1; - if (!isSourceAvailable(mix->srcRaw)) { - if (channel >= adcGetMaxInputs(ADC_INPUT_MAIN)) { - mix->srcRaw = MIXSRC_FIRST_STICK + channel; - } else { - mix->srcRaw = MIXSRC_FIRST_STICK + inputMappingChannelOrder(channel); - } - while (!isSourceAvailable(mix->srcRaw)) { - mix->srcRaw += 1; - } - } - mix->weight = 100; - mixerTaskStart(); - storageDirty(EE_MODEL); -} - -void deleteMix(uint8_t idx) -{ - mixerTaskStop(); - MixData * mix = mixAddress(idx); - memmove(mix, mix + 1, (MAX_MIXERS - (idx + 1)) * sizeof(MixData)); - memclear(&g_model.mixData[MAX_MIXERS - 1], sizeof(MixData)); - mixerTaskStart(); - storageDirty(EE_MODEL); -} - -#if defined(LUA) -// This is necessary as the LUA API uses th old interface -// where insertMix() has only one param. The channel is -// passed through s_currCh -void insertMix(uint8_t idx) -{ - insertMix(idx, s_currCh - 1); -} -#endif - -void copyMix(uint8_t source, uint8_t dest, int8_t ch) -{ - mixerTaskStop(); - MixData sourceMix; - memcpy(&sourceMix, mixAddress(source), sizeof(MixData)); - MixData *mix = mixAddress(dest); - size_t trailingMixes = MAX_MIXERS - (dest + 1); - memmove(mix + 1, mix, trailingMixes * sizeof(MixData)); - memcpy(mix, &sourceMix, sizeof(MixData)); - mix->destCh = ch; - mixerTaskStart(); - storageDirty(EE_MODEL); -} - -bool swapMixes(uint8_t &idx, uint8_t up) -{ - MixData * x, * y; - int8_t tgt_idx = (up ? idx - 1 : idx + 1); - - x = mixAddress(idx); - - if (tgt_idx < 0) { - if (x->destCh == 0) - return false; - x->destCh--; - return true; - } - - if (tgt_idx == MAX_MIXERS) { - if (x->destCh == MAX_OUTPUT_CHANNELS - 1) - return false; - x->destCh++; - return true; - } - - y = mixAddress(tgt_idx); - uint8_t destCh = x->destCh; - if (!y->srcRaw || destCh != y->destCh) { - if (up) { - if (destCh > 0) x->destCh--; - else return false; - } - else { - if (destCh < MAX_OUTPUT_CHANNELS - 1) x->destCh++; - else return false; - } - return true; - } - - mixerTaskStop(); - memswap(x, y, sizeof(MixData)); - mixerTaskStart(); - - idx = tgt_idx; - return true; -} class MixLineButton : public InputMixButton { @@ -312,7 +200,7 @@ ModelMixesPage::ModelMixesPage() : bool ModelMixesPage::reachMixesLimit() { - if (getMixesCount() >= MAX_MIXERS) { + if (getMixCount() >= MAX_MIXERS) { new MessageDialog(form, STR_WARNING, STR_NOFREEMIXER); return true; } @@ -550,17 +438,14 @@ void ModelMixesPage::build(FormWindow * window) bool focusSet = false; uint8_t index = 0; MixData* line = g_model.mixData; - for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { + for (uint8_t ch = 0; (ch < MAX_OUTPUT_CHANNELS) && (index < MAX_MIXERS); ch++) { - if (index >= MAX_MIXERS) break; - - bool skip_mix = (ch == 0 && is_memclear(line, sizeof(MixData))); - if (line->destCh == ch && !skip_mix) { + if (line->destCh == ch) { // one group for the complete mixer channel auto group = createGroup(form, MIXSRC_FIRST_CH + ch); groups.emplace_back(group); - while (index < MAX_MIXERS && (line->destCh == ch) && !skip_mix) { + while (index < MAX_MIXERS && (line->destCh == ch)) { // one button per input line auto btn = createLineButton(group, index); if (!focusSet) { @@ -569,7 +454,6 @@ void ModelMixesPage::build(FormWindow * window) } ++index; ++line; - skip_mix = (ch == 0 && is_memclear(line, sizeof(MixData))); } } } diff --git a/radio/src/gui/common/stdlcd/model_mixes.cpp b/radio/src/gui/common/stdlcd/model_mixes.cpp index 3cf4bb0a774..681a174ed4e 100644 --- a/radio/src/gui/common/stdlcd/model_mixes.cpp +++ b/radio/src/gui/common/stdlcd/model_mixes.cpp @@ -23,118 +23,20 @@ #include "tasks/mixer_task.h" #include "hal/adc_driver.h" #include "input_mapping.h" +#include "mixes.h" #define _STR_MAX(x) "/" #x #define STR_MAX(x) _STR_MAX(x) -uint8_t getMixesCount() -{ - uint8_t count = 0; - uint8_t ch; - - for (int i=MAX_MIXERS-1; i>=0; i--) { - ch = mixAddress(i)->srcRaw; - if (ch != 0) { - count++; - } - } - return count; -} - bool reachMixesLimit() { - if (getMixesCount() >= MAX_MIXERS) { + if (getMixCount() >= MAX_MIXERS) { POPUP_WARNING(STR_NOFREEMIXER); return true; } return false; } -void deleteMix(uint8_t idx) -{ - mixerTaskStop(); - MixData * mix = mixAddress(idx); - memmove(mix, mix+1, (MAX_MIXERS-(idx+1))*sizeof(MixData)); - memclear(&g_model.mixData[MAX_MIXERS-1], sizeof(MixData)); - mixerTaskStart(); - storageDirty(EE_MODEL); -} - -void insertMix(uint8_t idx) -{ - mixerTaskStop(); - MixData * mix = mixAddress(idx); - memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData)); - memclear(mix, sizeof(MixData)); - mix->destCh = s_currCh-1; - mix->srcRaw = s_currCh; - if (!isSourceAvailable(mix->srcRaw)) { - if (s_currCh > adcGetMaxInputs(ADC_INPUT_MAIN)) { - mix->srcRaw = MIXSRC_FIRST_STICK - 1 + s_currCh; - } else { - mix->srcRaw = MIXSRC_FIRST_STICK + inputMappingChannelOrder(s_currCh - 1); - } - while (!isSourceAvailable(mix->srcRaw)) { - mix->srcRaw += 1; - } - } - mix->weight = 100; - mixerTaskStart(); - storageDirty(EE_MODEL); -} - -void copyMix(uint8_t idx) -{ - mixerTaskStop(); - MixData * mix = mixAddress(idx); - memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData)); - mixerTaskStart(); - storageDirty(EE_MODEL); -} - -bool swapMixes(uint8_t & idx, uint8_t up) -{ - MixData * x, * y; - int8_t tgt_idx = (up ? idx-1 : idx+1); - - x = mixAddress(idx); - - if (tgt_idx < 0) { - if (x->destCh == 0) - return false; - x->destCh--; - return true; - } - - if (tgt_idx == MAX_MIXERS) { - if (x->destCh == MAX_OUTPUT_CHANNELS-1) - return false; - x->destCh++; - return true; - } - - y = mixAddress(tgt_idx); - uint8_t destCh = x->destCh; - if(!y->srcRaw || destCh != y->destCh) { - if (up) { - if (destCh>0) x->destCh--; - else return false; - } - else { - if (destChdestCh++; - else return false; - } - return true; - } - - mixerTaskStop(); - memswap(x, y, sizeof(MixData)); - mixerTaskStart(); - - idx = tgt_idx; - return true; -} - void onMixesMenu(const char * result) { uint8_t chn = mixAddress(s_currIdx)->destCh + 1; @@ -146,7 +48,7 @@ void onMixesMenu(const char * result) if (!reachMixesLimit()) { s_currCh = chn; if (result == STR_INSERT_AFTER) { s_currIdx++; menuVerticalPosition++; } - insertMix(s_currIdx); + insertMix(s_currIdx, s_currCh - 1); pushMenu(menuModelMixOne); } } @@ -289,7 +191,7 @@ void menuModelMixAll(event_t event) } else { do { - swapMixes(s_currIdx, s_copyTgtOfs > 0); + s_currIdx = moveMix(s_currIdx, s_copyTgtOfs > 0); s_copyTgtOfs += (s_copyTgtOfs < 0 ? +1 : -1); } while (s_copyTgtOfs != 0); storageDirty(EE_MODEL); @@ -327,7 +229,7 @@ void menuModelMixAll(event_t event) if (s_copyMode) s_currCh = 0; if (s_currCh) { if (reachMixesLimit()) break; - insertMix(s_currIdx); + insertMix(s_currIdx, s_currCh - 1); pushMenu(menuModelMixOne); s_copyMode = 0; } @@ -353,7 +255,7 @@ void menuModelMixAll(event_t event) // if (reachMixesLimit()) break; // s_currCh = chn; // if (event == EVT_KEY_LONG(KEY_RIGHT)) { s_currIdx++; menuVerticalPosition++; } - // insertMix(s_currIdx); + // insertMix(s_currIdx, s_currCh - 1); // pushMenu(menuModelMixOne); // s_copyMode = 0; // killEvents(event); @@ -369,7 +271,7 @@ void menuModelMixAll(event_t event) if (s_copyTgtOfs==0 && s_copyMode==COPY_MODE) { // insert a mix on the same channel (just above / just below) if (!reachMixesLimit()) { - copyMix(s_currIdx); + copyMix(s_currIdx, s_currIdx, mixAddress(s_currIdx)->destCh); if (IS_NEXT_EVENT(event)) s_currIdx++; else if (sub - menuVerticalOffset >= 6) @@ -384,15 +286,13 @@ void menuModelMixAll(event_t event) } else { // only swap the mix with its neighbor - if (swapMixes(s_currIdx, IS_PREVIOUS_EVENT(event))) { - storageDirty(EE_MODEL); - } + moveMix(s_currIdx, IS_PREVIOUS_EVENT(event)); } s_copyTgtOfs = next_ofs; } - lcdDrawNumber(FW*sizeof(TR_MIXES)+FW/2, 0, getMixesCount(), 0); + lcdDrawNumber(FW*sizeof(TR_MIXES)+FW/2, 0, getMixCount(), 0); lcdDrawText(lcdNextPos, 0, STR_MAX(MAX_MIXERS)); // Value @@ -419,9 +319,9 @@ void menuModelMixAll(event_t event) int i = 0; for (uint8_t ch=1; ch<=MAX_OUTPUT_CHANNELS; ch++) { - MixData * md; coord_t y = MENU_HEADER_HEIGHT+1+(cur-menuVerticalOffset)*FH; - if (isrcRaw && md->destCh+1 == ch) { + MixData * md = mixAddress(i); + if (i < getMixCount() && (md->destCh + 1 == ch)) { if (cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES) { putsChn(0, y, ch, 0); // show CHx } @@ -473,7 +373,7 @@ void menuModelMixAll(event_t event) } } cur++; y+=FH; mixCnt++; i++; md++; - } while (isrcRaw && md->destCh+1 == ch); + } while (i < getMixCount() && (md->destCh + 1 == ch)); if (s_copyMode == MOVE_MODE && cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) { lcdDrawRect(22, y-1, LCD_W-22, 9, DOTTED); cur++; diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 8bd79b0eed0..91cd53d2431 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -25,6 +25,7 @@ #include "hal/adc_driver.h" #include "hal/switch_driver.h" #include "switches.h" +#include "mixes.h" #undef CPN #include "MultiSubtypeDefs.h" diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp index b5aee1f298a..2e59feefd2e 100644 --- a/radio/src/lua/api_model.cpp +++ b/radio/src/lua/api_model.cpp @@ -28,6 +28,7 @@ #include "../timers.h" #include "model_init.h" #include "gvars.h" +#include "mixes.h" #if defined(SDCARD_YAML) #include @@ -887,10 +888,9 @@ static int luaModelInsertMix(lua_State *L) unsigned int first = getFirstMix(chn); unsigned int count = getMixesCountFromFirst(chn, first); - if (chndestCh = channel; + mix->srcRaw = channel + 1; + if (!isSourceAvailable(mix->srcRaw)) { + if (s_currCh > adcGetMaxInputs(ADC_INPUT_MAIN)) { + mix->srcRaw = MIXSRC_FIRST_STICK + channel; + } else { + mix->srcRaw = MIXSRC_FIRST_STICK + inputMappingChannelOrder(channel); + } + while (!isSourceAvailable(mix->srcRaw)) { + mix->srcRaw += 1; + } + } + mix->weight = 100; + mixerTaskStart(); + + _nb_mix_lines += 1; + storageDirty(EE_MODEL); +} + +void deleteMix(uint8_t idx) +{ + mixerTaskStop(); + MixData * mix = mixAddress(idx); + memmove(mix, mix + 1, (MAX_MIXERS - (idx + 1)) * sizeof(MixData)); + memclear(&g_model.mixData[MAX_MIXERS - 1], sizeof(MixData)); + mixerTaskStart(); + + _nb_mix_lines -= 1; + storageDirty(EE_MODEL); +} + +void copyMix(uint8_t src, uint8_t dst, uint8_t channel) +{ + mixerTaskStop(); + MixData sourceMix; + memcpy(&sourceMix, mixAddress(src), sizeof(MixData)); + MixData* mix = mixAddress(dst); + size_t trailingMixes = MAX_MIXERS - (dst + 1); + memmove(mix + 1, mix, trailingMixes * sizeof(MixData)); + memcpy(mix, &sourceMix, sizeof(MixData)); + mix->destCh = channel; + mixerTaskStart(); + + _nb_mix_lines += 1; + storageDirty(EE_MODEL); +} + +// Move the mixer line at 'idx' up or down +// by one position and return the new index. +uint8_t moveMix(uint8_t idx, bool up) +{ + MixData * x, * y; + int8_t tgt_idx = (up ? idx-1 : idx+1); + + x = mixAddress(idx); + + if (tgt_idx < 0) { + if (x->destCh > 0) { + x->destCh--; + storageDirty(EE_MODEL); + } + return idx; + } + + if (tgt_idx == MAX_MIXERS) { + if (x->destCh < MAX_OUTPUT_CHANNELS - 1) { + x->destCh++; + storageDirty(EE_MODEL); + } + return idx; + } + + y = mixAddress(tgt_idx); + uint8_t destCh = x->destCh; + + // If current target is empty or + // assigned to a different channel: + // + // TODO: check what happens with the mixer + // when channel is changed on-the-fly + // + if(!y->srcRaw || destCh != y->destCh) { + if (up) { + if (destCh > 0) { + x->destCh--; + storageDirty(EE_MODEL); + } + } + else { + if (destCh < MAX_OUTPUT_CHANNELS - 1) { + x->destCh++; + storageDirty(EE_MODEL); + } + } + return idx; + } + + mixerTaskStop(); + memswap(x, y, sizeof(MixData)); + mixerTaskStart(); + + storageDirty(EE_MODEL); + return tgt_idx; +} + +static uint8_t _countMixLines() +{ + // search for first blank + uint8_t i = 0; + do { + if (is_memclear(mixAddress(i), sizeof(MixData))) break; + } while (++i < MAX_MIXERS); + + return i; +} + +void updateMixCount() +{ + _nb_mix_lines = _countMixLines(); +} diff --git a/radio/src/mixes.h b/radio/src/mixes.h new file mode 100644 index 00000000000..de3805482d5 --- /dev/null +++ b/radio/src/mixes.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * 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. + */ + +#pragma once + +#include + +struct MixData; + +// Get a pointer to a mixer line +MixData* mixAddress(uint8_t idx); + +// Insert a new mixer line at 'idx' +void insertMix(uint8_t idx, uint8_t channel); + +// Delete mixer line at 'idx' +void deleteMix(uint8_t idx); + +// Duplicate mixer line at 'idx' in place +void copyMix(uint8_t idx, uint8_t dst, uint8_t channel); + +// Move the mixer line at 'idx' up or down +// by one position and return the new index. +uint8_t moveMix(uint8_t idx, bool up); + +uint8_t getMixCount(); + +// Should only be called from storage +// right after a model has been loaded +void updateMixCount(); diff --git a/radio/src/model_init.cpp b/radio/src/model_init.cpp index 4eebb733009..c122a5f4142 100644 --- a/radio/src/model_init.cpp +++ b/radio/src/model_init.cpp @@ -22,6 +22,7 @@ #include "opentx.h" #include "hal/adc_driver.h" #include "input_mapping.h" +#include "mixes.h" void clearInputs() { diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 245c2fe8bc7..7c2224e7fe5 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -215,11 +215,6 @@ ExpoData *expoAddress(uint8_t idx ) return &g_model.expoData[idx]; } -MixData *mixAddress(uint8_t idx) -{ - return &g_model.mixData[idx]; -} - LimitData *limitAddress(uint8_t idx) { return &g_model.limitData[idx]; diff --git a/radio/src/opentx.h b/radio/src/opentx.h index e5e51eb6572..3dd6fcbd6d2 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -627,7 +627,6 @@ uint16_t anaIn(uint8_t chan); FlightModeData * flightModeAddress(uint8_t idx); ExpoData * expoAddress(uint8_t idx); -MixData * mixAddress(uint8_t idx); LimitData * limitAddress(uint8_t idx); LogicalSwitchData * lswAddress(uint8_t idx); USBJoystickChData * usbJChAddress(uint8_t idx); diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp index d10c244db10..45940a54240 100644 --- a/radio/src/storage/storage_common.cpp +++ b/radio/src/storage/storage_common.cpp @@ -22,6 +22,7 @@ #include "opentx.h" #include "timers_driver.h" #include "tasks/mixer_task.h" +#include "mixes.h" #if defined(USBJ_EX) #include "usb_joystick.h" @@ -106,7 +107,7 @@ void postRadioSettingsLoad() #endif } -static void sortMixerLines() +static bool sortMixerLines() { // simple bubble sort unsigned passes = 0; @@ -132,9 +133,16 @@ static void sortMixerLines() ++passes; } while(swaps > 0); - if (passes > 1) { - storageDirty(EE_MODEL); - } + // anything above 1 means that + // we changed something + return passes > 1; +} + +static void sanitizeMixerLines() +{ + bool dirty = sortMixerLines(); + updateMixCount(); + if (dirty) storageDirty(EE_MODEL); } void postModelLoad(bool alarms) @@ -226,7 +234,7 @@ if(g_model.rssiSource) { } loadCurves(); - sortMixerLines(); + sanitizeMixerLines(); #if defined(GUI) if (alarms) { From bd9440daa3ca4321acfcace4c5fe8a04e6d10b29 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 24 Sep 2023 10:43:01 +0200 Subject: [PATCH 25/29] fix: Deactivate logs and close log file if USB is connected (#4024) --- radio/src/logs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/logs.cpp b/radio/src/logs.cpp index fd1bbd240b9..7d8c67d6cfd 100644 --- a/radio/src/logs.cpp +++ b/radio/src/logs.cpp @@ -271,7 +271,7 @@ void logsWrite() return; } - if (isFunctionActive(FUNCTION_LOGS) && logDelay100ms > 0) { + if (isFunctionActive(FUNCTION_LOGS) && logDelay100ms > 0 && !usbPlugged()) { #if defined(SIMU) || !defined(RTCLOCK) tmr10ms_t tmr10ms = get_tmr10ms(); // tmr10ms works in 10ms increments if (lastLogTime == 0 || (tmr10ms_t)(tmr10ms - lastLogTime) >= (tmr10ms_t)(logDelay100ms*10)-1) { From 66b9bdd3e400c29ec40343ca7eb271edfcdb9b5a Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sun, 24 Sep 2023 19:27:06 +0200 Subject: [PATCH 26/29] fix: ADC DMA clock enable and inhibit mask for internal channels (#4103) --- radio/src/targets/common/arm/stm32/stm32_adc.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/radio/src/targets/common/arm/stm32/stm32_adc.cpp b/radio/src/targets/common/arm/stm32/stm32_adc.cpp index 95c6f599829..4244a5d96a9 100644 --- a/radio/src/targets/common/arm/stm32/stm32_adc.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_adc.cpp @@ -20,7 +20,10 @@ */ #include "stm32_adc.h" +#include "stm32_dma.h" #include "stm32_gpio_driver.h" +#include "timers_driver.h" + #include "opentx.h" #define ADC_COMMON ((ADC_Common_TypeDef *) ADC_BASE) @@ -235,7 +238,7 @@ static uint8_t adc_init_channels(const stm32_adc_t* adc, } } else { // Internal channels are inhibited until explicitely enabled - _adc_inhibit_mask |= mask; + _adc_inhibit_mask |= (1 << input_idx); } // channel is already used, probably a secondary input @@ -270,6 +273,8 @@ static bool adc_init_dma_stream(ADC_TypeDef* adc, DMA_TypeDef* DMAx, uint32_t stream, uint32_t channel, uint16_t* dest, uint8_t nconv) { + stm32_dma_enable_clock(DMAx); + // Disable DMA before continuing (see ref. manual "Stream configuration procedure") if (!adc_disable_dma(DMAx, stream)) return false; From 5bc06959a1b37a1cbaeda0fdd092286ce8bfb723 Mon Sep 17 00:00:00 2001 From: Risto Date: Mon, 25 Sep 2023 03:55:54 +0200 Subject: [PATCH 27/29] feat(color): Add alignment option for text widget (#3574) --- radio/src/gui/colorlcd/widgets/text.cpp | 25 +++++++++++++++++++++++-- radio/src/translations.cpp | 1 + radio/src/translations.h | 1 + radio/src/translations/cn.h | 1 + radio/src/translations/cz.h | 1 + radio/src/translations/da.h | 1 + radio/src/translations/de.h | 1 + radio/src/translations/en.h | 1 + radio/src/translations/es.h | 1 + radio/src/translations/fi.h | 1 + radio/src/translations/fr.h | 1 + radio/src/translations/he.h | 1 + radio/src/translations/it.h | 1 + radio/src/translations/jp.h | 1 + radio/src/translations/nl.h | 1 + radio/src/translations/pl.h | 1 + radio/src/translations/pt.h | 1 + radio/src/translations/tw.h | 1 + 18 files changed, 40 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/colorlcd/widgets/text.cpp b/radio/src/gui/colorlcd/widgets/text.cpp index 68cf6b0ef58..903de9c7165 100644 --- a/radio/src/gui/colorlcd/widgets/text.cpp +++ b/radio/src/gui/colorlcd/widgets/text.cpp @@ -40,13 +40,33 @@ class TextWidget: public Widget // get font size from options[2] LcdFlags fontsize = persistentData->options[2].value.unsignedValue << 8u; + // get alignment from options[4] + LcdFlags alignment = persistentData->options[4].value.unsignedValue; + + coord_t x; + LcdFlags attributes = fontsize; + + switch (alignment) { + case ALIGN_RIGHT: + x = width(); + attributes |= RIGHT; + break; + case ALIGN_CENTER: + x = width()/2; + attributes |= CENTERED; + break; + default: // ALIGN_LEFT: + x = 0; + attributes |= LEFT; + } + // draw shadow if (persistentData->options[3].value.boolValue) { - dc->drawText(1, 1, persistentData->options[0].value.stringValue, fontsize | BLACK); + dc->drawText(x+1, 1, persistentData->options[0].value.stringValue, attributes | BLACK); } // draw text - dc->drawText(0, 0, persistentData->options[0].value.stringValue, fontsize | CUSTOM_COLOR); + dc->drawText(x, 0, persistentData->options[0].value.stringValue, attributes | CUSTOM_COLOR); } static const ZoneOption options[]; @@ -57,6 +77,7 @@ const ZoneOption TextWidget::options[] = { { STR_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(COLOR_THEME_SECONDARY1>>16) }, { STR_SIZE, ZoneOption::TextSize, OPTION_VALUE_UNSIGNED(0) }, { STR_SHADOW, ZoneOption::Bool, OPTION_VALUE_BOOL(false) }, + { STR_ALIGNMENT, ZoneOption::Align, OPTION_VALUE_UNSIGNED(ALIGN_LEFT) }, { nullptr, ZoneOption::Bool } }; diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 06b469e6613..de49864a284 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -761,6 +761,7 @@ const char STR_INVALID_FILE[] = TR_INVALID_FILE; const char STR_TIMER_SOURCE[] = TR_TIMER_SOURCE; const char STR_SIZE[] = TR_SIZE; const char STR_SHADOW[] = TR_SHADOW; +const char STR_ALIGNMENT[] = TR_ALIGNMENT; const char STR_ALIGN_LABEL[] = TR_ALIGN_LABEL; const char STR_ALIGN_VALUE[] = TR_ALIGN_VALUE; const char* const STR_ALIGN_OPTS[] = TR_ALIGN_OPTS; diff --git a/radio/src/translations.h b/radio/src/translations.h index 98770941ea1..6e53a96ea9a 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -768,6 +768,7 @@ extern const char* const STR_TEXT_SIZE[]; extern const char* const STR_SUBTRIMMODES[]; extern const char STR_SIZE[]; extern const char STR_SHADOW[]; +extern const char STR_ALIGNMENT[]; extern const char STR_ALIGN_LABEL[]; extern const char STR_ALIGN_VALUE[]; extern const char* const STR_ALIGN_OPTS[]; diff --git a/radio/src/translations/cn.h b/radio/src/translations/cn.h index 1e3b459655f..1afd25ee97e 100644 --- a/radio/src/translations/cn.h +++ b/radio/src/translations/cn.h @@ -960,6 +960,7 @@ #define TR_TIMER_SOURCE "计时器选择" #define TR_SIZE "尺寸" #define TR_SHADOW "阴影" + #define TR_ALIGNMENT "对齐" #define TR_ALIGN_LABEL "对齐名称" #define TR_ALIGN_VALUE "对齐值" #define TR_ALIGN_OPTS { "左", "中", "右" } diff --git a/radio/src/translations/cz.h b/radio/src/translations/cz.h index be8dd26e9fc..8b5c75c097c 100644 --- a/radio/src/translations/cz.h +++ b/radio/src/translations/cz.h @@ -980,6 +980,7 @@ #define TR_TIMER_SOURCE "Časovač zdroj" #define TR_SIZE "Velikost" #define TR_SHADOW "Stíny" + #define TR_ALIGNMENT "Zarovnání" #define TR_ALIGN_LABEL "Zarovnat název" #define TR_ALIGN_VALUE "Zarovnat hodnotu" #define TR_ALIGN_OPTS { "Vlevo", "Uprostřed", "Vpravo" } diff --git a/radio/src/translations/da.h b/radio/src/translations/da.h index cf03d8abe92..d8334740153 100644 --- a/radio/src/translations/da.h +++ b/radio/src/translations/da.h @@ -974,6 +974,7 @@ #define TR_TIMER_SOURCE "Tidtagning kilde" #define TR_SIZE "Størrelse" #define TR_SHADOW "Skygge" + #define TR_ALIGNMENT "Justering" #define TR_ALIGN_LABEL "Justere navn" #define TR_ALIGN_VALUE "Justere værdi" #define TR_ALIGN_OPTS { "Venstre", "Center", "Højre" } diff --git a/radio/src/translations/de.h b/radio/src/translations/de.h index 9a1036b369e..8d404550d72 100644 --- a/radio/src/translations/de.h +++ b/radio/src/translations/de.h @@ -955,6 +955,7 @@ #define TR_TIMER_SOURCE "Timer Quelle" #define TR_SIZE "Größe" #define TR_SHADOW "Schatten" + #define TR_ALIGNMENT "Ausrichtung" #define TR_ALIGN_LABEL "Name ausrichten" #define TR_ALIGN_VALUE "Wert ausrichten" #define TR_ALIGN_OPTS { "Links", "Mitte", "Rechts" } diff --git a/radio/src/translations/en.h b/radio/src/translations/en.h index 54802bedc73..47ecc4593db 100644 --- a/radio/src/translations/en.h +++ b/radio/src/translations/en.h @@ -969,6 +969,7 @@ #define TR_TIMER_SOURCE "Timer source" #define TR_SIZE "Size" #define TR_SHADOW "Shadow" + #define TR_ALIGNMENT "Alignment" #define TR_ALIGN_LABEL "Align label" #define TR_ALIGN_VALUE "Align value" #define TR_ALIGN_OPTS { "Left", "Center", "Right" } diff --git a/radio/src/translations/es.h b/radio/src/translations/es.h index 37880660327..126cc4fad10 100644 --- a/radio/src/translations/es.h +++ b/radio/src/translations/es.h @@ -972,6 +972,7 @@ #define TR_TIMER_SOURCE "Entrada timer" #define TR_SIZE "Tamaño" #define TR_SHADOW "Sombra" + #define TR_ALIGNMENT "Alinear" #define TR_ALIGN_LABEL "Alinear marbete" #define TR_ALIGN_VALUE "Alinear valor" #define TR_ALIGN_OPTS { "Lzquierdo", "Centro", "Derecho" } diff --git a/radio/src/translations/fi.h b/radio/src/translations/fi.h index cdc8b4e6f1b..74b9e6e4fbe 100644 --- a/radio/src/translations/fi.h +++ b/radio/src/translations/fi.h @@ -984,6 +984,7 @@ #define TR_TIMER_SOURCE "Timer source" #define TR_SIZE "Size" #define TR_SHADOW "Shadow" + #define TR_ALIGNMENT "Kohdistus" #define TR_ALIGN_LABEL "Kohdista merkki" #define TR_ALIGN_VALUE "Kohdista arvo" #define TR_ALIGN_OPTS { "Vasen", "Keski", "Oikea" } diff --git a/radio/src/translations/fr.h b/radio/src/translations/fr.h index dca3dc2c468..3c95daad491 100644 --- a/radio/src/translations/fr.h +++ b/radio/src/translations/fr.h @@ -988,6 +988,7 @@ #define TR_TIMER_SOURCE "Source Chrono" #define TR_SIZE "Taille" #define TR_SHADOW "Ombre" + #define TR_ALIGNMENT "Alignement" #define TR_ALIGN_LABEL "Aligner Catégorie" #define TR_ALIGN_VALUE "Aligner Valeur" #define TR_ALIGN_OPTS { "Gauche", "Centre", "Droite" } diff --git a/radio/src/translations/he.h b/radio/src/translations/he.h index aede57bc175..8260fe73fd8 100644 --- a/radio/src/translations/he.h +++ b/radio/src/translations/he.h @@ -1050,6 +1050,7 @@ #define TR_TIMER_SOURCE "מקור השעון" #define TR_SIZE "גודל" #define TR_SHADOW "הצללה" + #define TR_ALIGNMENT "יישור" #define TR_ALIGN_LABEL "Align label" #define TR_ALIGN_VALUE "Align value" #define TR_ALIGN_OPTS { "שמאל", "מרכז", "ימין" } diff --git a/radio/src/translations/it.h b/radio/src/translations/it.h index f92955bf4ab..205be259fc9 100644 --- a/radio/src/translations/it.h +++ b/radio/src/translations/it.h @@ -968,6 +968,7 @@ #define TR_TIMER_SOURCE "Sorgente timer" #define TR_SIZE "Dimensione" #define TR_SHADOW "Ombra" + #define TR_ALIGNMENT "Allineamento" #define TR_ALIGN_LABEL "Allineare il cartellino" #define TR_ALIGN_VALUE "Allineare il valore" #define TR_ALIGN_OPTS { "Sinistra", "Mezzo", "Destra" } diff --git a/radio/src/translations/jp.h b/radio/src/translations/jp.h index bd29d439612..ea8659c90fc 100644 --- a/radio/src/translations/jp.h +++ b/radio/src/translations/jp.h @@ -965,6 +965,7 @@ #define TR_TIMER_SOURCE "タイマーソース" #define TR_SIZE "サイズ" #define TR_SHADOW "影" + #define TR_ALIGNMENT "アライメント" #define TR_ALIGN_LABEL "ラベルを揃える" #define TR_ALIGN_VALUE "値を揃える" #define TR_ALIGN_OPTS { "左", "中央", "右" } diff --git a/radio/src/translations/nl.h b/radio/src/translations/nl.h index 08befd3ca44..4dc3201503c 100644 --- a/radio/src/translations/nl.h +++ b/radio/src/translations/nl.h @@ -977,6 +977,7 @@ #define TR_TIMER_SOURCE "Timer source" #define TR_SIZE "Size" #define TR_SHADOW "Shadow" + #define TR_ALIGNMENT "Uitlijnen" #define TR_ALIGN_LABEL "Label uitlijnen" #define TR_ALIGN_VALUE "Waarde uitlijnen" #define TR_ALIGN_OPTS { "Links", "Midden", "Rechts" } diff --git a/radio/src/translations/pl.h b/radio/src/translations/pl.h index 35ad2c8a9fc..98df101f224 100644 --- a/radio/src/translations/pl.h +++ b/radio/src/translations/pl.h @@ -966,6 +966,7 @@ #define TR_TIMER_SOURCE "Timer source" #define TR_SIZE "Rozmiar" #define TR_SHADOW "Cień" + #define TR_ALIGNMENT "Wyrównaj" #define TR_ALIGN_LABEL "Wyrównaj przywieszka" #define TR_ALIGN_VALUE "Wyrównać wartość" #define TR_ALIGN_OPTS { "Lewy", "Centrum", "Prawe" } diff --git a/radio/src/translations/pt.h b/radio/src/translations/pt.h index 0dc13fc23b1..59c8ee4205b 100644 --- a/radio/src/translations/pt.h +++ b/radio/src/translations/pt.h @@ -972,6 +972,7 @@ #define TR_TIMER_SOURCE "Timer source" #define TR_SIZE "Size" #define TR_SHADOW "Shadow" + #define TR_ALIGNMENT "Alinhar" #define TR_ALIGN_LABEL "Alinhar etiqueta" #define TR_ALIGN_VALUE "Alinhar valor" #define TR_ALIGN_OPTS { "Esquerda", "Centro", "Direita" } diff --git a/radio/src/translations/tw.h b/radio/src/translations/tw.h index 36122897e9e..2428cd22d95 100644 --- a/radio/src/translations/tw.h +++ b/radio/src/translations/tw.h @@ -964,6 +964,7 @@ #define TR_TIMER_SOURCE "計時器選擇" #define TR_SIZE "尺寸" #define TR_SHADOW "陰影" + #define TR_ALIGNMENT "對齊" #define TR_ALIGN_LABEL "对齐名称" #define TR_ALIGN_VALUE "对齐值" #define TR_ALIGN_OPTS { "左", "中", "右" } From 1d5c7e2cc21ac1b708f8e06b42a0cef4e0846b42 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Mon, 25 Sep 2023 16:09:42 +1000 Subject: [PATCH 28/29] ci: Disable unnecessary tlitef4 builds --- .github/workflows/actions.yml | 2 +- .github/workflows/nightly.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 16546872fe2..a140d22c8d6 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -98,7 +98,7 @@ jobs: - t16 - t18 - t8;zorro;pocket;commando8 - - tlite;tlitef4;tpro;tprov2;lr3pro + - tlite;tpro;tprov2;lr3pro - t20 - tx12;tx12mk2;boxer - tx16s diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e9c70748345..7efd556501e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -23,7 +23,7 @@ jobs: - t16 - t18 - t8;zorro;pocket;commando8 - - tlite;tlitef4;tpro;tprov2;lr3pro + - tlite;tpro;tprov2;lr3pro - t20 - tx12;tx12mk2;boxer - tx16s From 1cc1810afc52d9eee6dffb8f79413b7a24a5f2dd Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Mon, 25 Sep 2023 09:47:15 +0200 Subject: [PATCH 29/29] fix: VS1053b initialisation on NV14/EL18 (#4108) --- radio/src/targets/common/arm/stm32/vs1053b.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/vs1053b.cpp b/radio/src/targets/common/arm/stm32/vs1053b.cpp index 6da8164fec7..cad7948bee6 100644 --- a/radio/src/targets/common/arm/stm32/vs1053b.cpp +++ b/radio/src/targets/common/arm/stm32/vs1053b.cpp @@ -234,7 +234,7 @@ uint8_t audioHardReset(void) delay_ms(100); // 100ms RST_HIGH(); - if (!audioWaitDreq(100)) + if (!audioWaitDreq(5000)) return 0; delay_ms(20); // 20ms @@ -249,12 +249,15 @@ uint8_t audioSoftReset(void) audioSpiReadWriteByte(0x00); // start the transfer - audioSpiWriteCmd(SPI_MODE, 0x0816); // SOFT RESET, new model - if (!audioWaitDreq(100)) - return 0; + uint8_t retry = 0; + uint16_t mode = SM_SDINEW | SM_EARSPEAKER_LO; + while (audioSpiReadReg(SPI_MODE) != mode && retry < 100) { + retry++; + audioSpiWriteCmd(SPI_MODE, mode | SM_RESET); + } // wait for set up successful - uint8_t retry = 0; + retry = 0; while (audioSpiReadReg(SPI_CLOCKF) != 0x9800 && retry < 100) { retry++; audioSpiWriteCmd(SPI_CLOCKF, 0x9800);