diff --git a/mLRS/Common/bind.h b/mLRS/Common/bind.h deleted file mode 100644 index 295cca0a8..000000000 --- a/mLRS/Common/bind.h +++ /dev/null @@ -1,365 +0,0 @@ -//******************************************************* -// Copyright (c) MLRS project -// GPL3 -// https://www.gnu.org/licenses/gpl-3.0.de.html -// OlliW @ www.olliw.eu -//******************************************************* -// Bind -//******************************************************* -#ifndef BIND_H -#define BIND_H -#pragma once - - -#include -#include "common_conf.h" -#include "hal/device_conf.h" -#include "setup_types.h" - - -extern volatile uint32_t millis32(void); -extern bool connected(void); -#ifdef DEVICE_IS_RECEIVER -extern void clock_reset(void); -#endif - -extern SX_DRIVER sx; -extern SX2_DRIVER sx2; - -void sxReadFrame(uint8_t antenna, void* const data, void* const data2, uint8_t len); -void sxSendFrame(uint8_t antenna, void* const data, uint8_t len, uint16_t tmo_ms); -void sxGetPacketStatus(uint8_t antenna, tStats* const stats); - -extern tSetup Setup; -extern tGlobalConfig Config; -extern tStats stats; - - -//------------------------------------------------------- -// Bind Class -//------------------------------------------------------- - -#define BIND_SIGNATURE_TX_STR "mLRS\x01\x02\x03\x04" -#define BIND_SIGNATURE_RX_STR "mLRS\x04\x03\x02\x01" -#define BIND_BUTTON_DEBOUNCE_MS 50 -#define BIND_BUTTON_TMO_MS 4000 - - -typedef enum { - BIND_TASK_NONE = 0, - BIND_TASK_CHANGED_TO_BIND, - BIND_TASK_RX_STORE_PARAMS, - BIND_TASK_TX_RESTART_CONTROLLER, -} BIND_TASK_ENUM; - - -class tBindBase -{ - public: - void Init(void); - bool IsInBind(void) { return is_in_binding; } - void StartBind(void) { if (!is_in_binding) binding_requested = true; } - void StopBind(void) { if (is_in_binding) binding_stop_requested = true; } - void ConfigForBind(void); - void HopToNextBind(uint16_t frequency_band); // SETUP_FREQUENCY_BAND_ENUM - void Tick_ms(void); - void Do(void); - uint8_t Task(void); - - void AutoBind(void); // only for receiver, call every ms - uint32_t auto_bind_tmo_ms; - - bool is_in_binding; // is in sync with link loop - bool binding_requested; - bool binding_stop_requested; - uint32_t button_tlast_ms; - uint8_t task; - bool is_connected; - - uint64_t TxSignature; // 8 bytes, signature of Tx module - uint64_t RxSignature; // 8 bytes, signature of Rx module - - void handle_receive(uint8_t antenna, uint8_t rx_status); - void do_transmit(uint8_t antenna); - uint8_t do_receive(uint8_t antenna, bool do_clock_reset); - void config_rf(void); - - bool is_pressed; - int8_t pressed_cnt; - - private: - tSxGlobalConfig* gconfig; - uint16_t mode_mask; // mask to handle toggling between 19 Hz and 19 Hz7x mode -}; - - -void tBindBase::Init(void) -{ - is_in_binding = false; - binding_requested = false; - binding_stop_requested = false; - task = BIND_TASK_NONE; - is_connected = false; - - button_tlast_ms = millis32(); - is_pressed = false; - pressed_cnt = 0; - - memcpy(&TxSignature, BIND_SIGNATURE_TX_STR, 8); - memcpy(&RxSignature, BIND_SIGNATURE_RX_STR, 8); - - auto_bind_tmo_ms = 1000 * RX_BIND_MODE_AFTER_POWERUP_TIME_SEC; - - mode_mask = 0; -} - - -void tBindBase::ConfigForBind(void) -{ - // used by both the Tx and Rx, switch to 19Hz or 19Hz7x mode, select lowest possible power - // we have to distinguish between MODE_19HZ or MODE_19HZ_7X - // configure_mode() however does currently do the same for both cases - // for devices which can do both modes we need to toggle - if (Config.Mode == MODE_19HZ_7X) { - mode_mask = 0xFFFF; - configure_mode(MODE_19HZ_7X, Config.FrequencyBand); - mode_mask &=~ (1 << Config.FrequencyBand); // clear bit for current frequency band - } else { - mode_mask = 0; - configure_mode(MODE_19HZ, Config.FrequencyBand); - mode_mask |= (1 << Config.FrequencyBand); // set bit for current frequency band - } - - config_rf(); -} - - -// used only by Rx -// is called in rx main when fhss.HopToNextBind() returns true -// the frequency band is obtained with fhss.GetCurrBindSetupFrequencyBand() -void tBindBase::HopToNextBind(uint16_t frequency_band) // SETUP_FREQUENCY_BAND_ENUM -{ - // not nice - // we would need SetupMetaData.Mode_allowed_mask before it is adjusted for the selected frequency band - // could keep a copy of the un-adjusted SetupMetaData.Mode_allowed_mask - // for the moment reconstruct the info by explicit defines -#if defined DEVICE_HAS_LR11xx - uint16_t mode_allowed_mask = 0b110111; // 50 Hz, 31 Hz, 19 Hz, 19 Hz 7x, FSK // only important that both 19Hz and 19Hz7x are set -#elif defined DEVICE_HAS_SX127x - uint16_t mode_allowed_mask = 0b100000; // 19 Hz 7x, not editable // only important that only 19Hz7x is set -#else - uint16_t mode_allowed_mask = 0b000111; // 50 Hz, 31 Hz, 19 Hz // only important that only 19Hz is set -#endif - - // if both 19Hz and 19Hz7X are set, we need to cycle with toggles - if ((mode_allowed_mask & (1 << MODE_19HZ)) && (mode_allowed_mask & (1 << MODE_19HZ_7X))) { - if (frequency_band == SETUP_FREQUENCY_BAND_2P4_GHZ) { - configure_mode(MODE_19HZ, frequency_band); - } else { - if (mode_mask & (1 << frequency_band)) { - configure_mode(MODE_19HZ_7X, frequency_band); - mode_mask &=~ (1 << frequency_band); // clear bit - } else { - configure_mode(MODE_19HZ, frequency_band); - mode_mask |= (1 << frequency_band); // set bit - } - } - config_rf(); - } -} - - -void tBindBase::config_rf(void) -{ - sx.SetToIdle(); - sx2.SetToIdle(); - sx.SetRfPower_dbm(rfpower_list[0].dbm); - sx2.SetRfPower_dbm(rfpower_list[0].dbm); - IF_SX(sx.ResetToLoraConfiguration()); - IF_SX2(sx2.ResetToLoraConfiguration()); - sx.SetToIdle(); - sx2.SetToIdle(); -} - - -// called each ms -void tBindBase::Tick_ms(void) -{ - // a not so efficient but simple debounce - if (!is_pressed) { - if (button_pressed()) { pressed_cnt++; } else { pressed_cnt = 0; } - if (pressed_cnt >= BIND_BUTTON_DEBOUNCE_MS) is_pressed = true; - } else { - if (!button_pressed()) { pressed_cnt--; } else { pressed_cnt = BIND_BUTTON_DEBOUNCE_MS; } - if (pressed_cnt <= 0) is_pressed = false; - } -} - - -// called in each doPreTransmit or doPostReceive cycle -void tBindBase::Do(void) -{ - uint32_t tnow = millis32(); - - if (is_pressed) { - if (tnow - button_tlast_ms > BIND_BUTTON_TMO_MS) { - binding_requested = true; - } - } else { - button_tlast_ms = tnow; - } - -#ifdef DEVICE_IS_TRANSMITTER - if (is_in_binding) { - if (is_connected && !connected()) { // we just lost connection - task = BIND_TASK_TX_RESTART_CONTROLLER; - } - is_connected = connected(); - - if (binding_stop_requested) { - task = BIND_TASK_TX_RESTART_CONTROLLER; - } - } -#endif - - if (!is_in_binding && binding_requested) { - is_in_binding = true; - task = BIND_TASK_CHANGED_TO_BIND; - } -} - - -// called directly after bind.Do() -uint8_t tBindBase::Task(void) -{ - switch (task) { - case BIND_TASK_TX_RESTART_CONTROLLER: - case BIND_TASK_RX_STORE_PARAMS: - // postpone until button is released, prevents jumping to RESTART while button is till pressed by user - if (is_pressed) return BIND_TASK_NONE; - break; - } - - uint8_t ret = task; - task = BIND_TASK_NONE; - return ret; -} - - -void tBindBase::AutoBind(void) // only for receiver, call every ms -{ -#if defined DEVICE_IS_RECEIVER && defined RX_BIND_MODE_AFTER_POWERUP - if (!auto_bind_tmo_ms) return; - - auto_bind_tmo_ms--; - - if (auto_bind_tmo_ms == 0) { - binding_requested = true; - } -#endif -} - - -tTxBindFrame txBindFrame; -tRxBindFrame rxBindFrame; - - -#ifdef DEVICE_IS_TRANSMITTER - -void tBindBase::handle_receive(uint8_t antenna, uint8_t rx_status) -{ - if (rx_status == RX_STATUS_INVALID) return; - - // do stuff -} - - -void tBindBase::do_transmit(uint8_t antenna) -{ - memset((uint8_t*)&txBindFrame, 0, sizeof(txBindFrame)); - txBindFrame.bind_signature = TxSignature; - - txBindFrame.connected = connected(); - - strbufstrcpy(txBindFrame.BindPhrase_6, Setup.Common[Config.ConfigId].BindPhrase, 6); - txBindFrame.FrequencyBand = Setup.Common[Config.ConfigId].FrequencyBand; - txBindFrame.Mode = Setup.Common[Config.ConfigId].Mode; - txBindFrame.Ortho = Setup.Common[Config.ConfigId].Ortho; - - txBindFrame.crc = fmav_crc_calculate((uint8_t*)&txBindFrame, FRAME_TX_RX_LEN - 2); -} - - -uint8_t tBindBase::do_receive(uint8_t antenna, bool do_clock_reset) -{ - sxReadFrame(antenna, &rxBindFrame, &rxBindFrame, FRAME_TX_RX_LEN); - - bool ok = (rxBindFrame.bind_signature == RxSignature); - if (ok) { - uint16_t crc = fmav_crc_calculate((uint8_t*)&rxBindFrame, FRAME_TX_RX_LEN - 2); - ok = (crc == rxBindFrame.crc); - } - - sxGetPacketStatus(antenna, &stats); - - if (ok) return RX_STATUS_VALID; - - return RX_STATUS_INVALID; -} - -#endif -#ifdef DEVICE_IS_RECEIVER - -void tBindBase::handle_receive(uint8_t antenna, uint8_t rx_status) -{ - if (rx_status == RX_STATUS_INVALID) return; - - strstrbufcpy(Setup.Common[0].BindPhrase, txBindFrame.BindPhrase_6, 6); - Setup.Common[0].FrequencyBand = (SETUP_FREQUENCY_BAND_ENUM)txBindFrame.FrequencyBand; - Setup.Common[0].Mode = txBindFrame.Mode; - Setup.Common[0].Ortho = txBindFrame.Ortho; - - if (txBindFrame.connected) { - task = BIND_TASK_RX_STORE_PARAMS; - } -} - - -void tBindBase::do_transmit(uint8_t antenna) -{ - memset((uint8_t*)&rxBindFrame, 0, sizeof(rxBindFrame)); - rxBindFrame.bind_signature = RxSignature; - - rxBindFrame.connected = connected(); - - rxBindFrame.firmware_version = VERSION; - strbufstrcpy(rxBindFrame.device_name_20, DEVICE_NAME, 20); - - rxBindFrame.crc = fmav_crc_calculate((uint8_t*)&rxBindFrame, FRAME_TX_RX_LEN - 2); - sxSendFrame(antenna, &rxBindFrame, FRAME_TX_RX_LEN, SEND_FRAME_TMO_MS); -} - - -uint8_t tBindBase::do_receive(uint8_t antenna, bool do_clock_reset) -{ - sxReadFrame(antenna, &txBindFrame, &txBindFrame, FRAME_TX_RX_LEN); - - bool ok = (txBindFrame.bind_signature == TxSignature); - if (ok) { - uint16_t crc = fmav_crc_calculate((uint8_t*)&txBindFrame, FRAME_TX_RX_LEN - 2); - ok = (crc == txBindFrame.crc); - } - - if (ok && do_clock_reset) clock_reset(); - - sxGetPacketStatus(antenna, &stats); - - if (ok) return RX_STATUS_VALID; - - return RX_STATUS_INVALID; -} - -#endif - - -#endif // BIND_H diff --git a/mLRS/Common/common.h b/mLRS/Common/common.h index 0f4c41d6b..3e5032a3e 100644 --- a/mLRS/Common/common.h +++ b/mLRS/Common/common.h @@ -19,7 +19,6 @@ #include "frame_types.h" #include "link_types.h" #include "common_stats.h" -#include "bind.h" #include "fail.h" #include "buzzer.h" #include "fan.h" @@ -218,8 +217,6 @@ tStats stats; tFhss fhss; -tBindBase bind; - #ifdef DEVICE_IS_TRANSMITTER tBuzzer buzzer; #endif @@ -357,9 +354,6 @@ STATIC_ASSERT(sizeof(tRxFrameStatus) == FRAME_TX_RX_HEADER_LEN - 2, "tRxFrameSta STATIC_ASSERT(sizeof(tTxFrame) == FRAME_TX_RX_LEN, "tTxFrame len missmatch") STATIC_ASSERT(sizeof(tRxFrame) == FRAME_TX_RX_LEN, "tRxFrame len missmatch") -STATIC_ASSERT(sizeof(tTxBindFrame) == FRAME_TX_RX_LEN, "tTxBindFrame len missmatch") -STATIC_ASSERT(sizeof(tRxBindFrame) == FRAME_TX_RX_LEN, "tRxBindFrame len missmatch") - STATIC_ASSERT(sizeof(tTxCmdFrameRxParams) == FRAME_TX_PAYLOAD_LEN, "tTxCmdFrameRxParams len missmatch") STATIC_ASSERT(sizeof(tRxCmdFrameRxSetupData) == FRAME_RX_PAYLOAD_LEN, "tRxCmdFrameRxSetupData len missmatch") @@ -368,6 +362,11 @@ STATIC_ASSERT(sizeof(tTxSetup) == 20, "tTxSetup len missmatch") STATIC_ASSERT(sizeof(tCommonSetup) == 16, "tCommonSetup len missmatch") STATIC_ASSERT(sizeof(tSetup) == 22+16+36+(20+16)*SETUP_CONFIG_NUM+8+2, "tSetup len missmatch") +// FanMode was taken from tTxSetup.spare[0], so it must sit at that very offset, else the EEPROM +// layout would silently shift and SETUPLAYOUT would have to be bumped +STATIC_ASSERT(offsetof(tTxSetup, FanMode) == 16, "tTxSetup.FanMode offset missmatch") +STATIC_ASSERT(SETUP_TX_FAN < FAN_MODE_NUM, "SETUP_TX_FAN out of range") + STATIC_ASSERT(sizeof(fhss_config) == sizeof(tFhssConfig) * SX_FHSS_FREQUENCY_BAND_NUM, "fhss_config size missmatch") #endif // COMMON_H diff --git a/mLRS/Common/common_conf.h b/mLRS/Common/common_conf.h index 31c3f3640..909fdfe40 100644 --- a/mLRS/Common/common_conf.h +++ b/mLRS/Common/common_conf.h @@ -24,6 +24,15 @@ // un-comment to enable Rx module to go into bind mode after power up //#define RX_BIND_MODE_AFTER_POWERUP +// un-comment to hard-force the cooling fan to always run, independent of the rf power setting and of +// the temperature. The "Tx Fan" setup parameter is then locked to "always on". +// Only needed for devices which have no way to change the setup, e.g. an Rx with a fan. +//#define FAN_ALWAYS_ON + +// the fan setting used for "always on", POWER_MAX selects the highest setting the device offers +// only relevant for devices with DEVICE_HAS_FAN_ONOFF, on/off fans are simply switched on +//#define FAN_ALWAYS_ON_DBM POWER_MAX + // Development features. Note: They are offered for testing, but they are not for production //currently none @@ -47,7 +56,7 @@ #define SETUP_TX_SERIAL_DESTINATION 0 // 0: serial port, 1: serial2 (BT/ESP) port, 2: mBridge -#define SETUP_TX_CHANNELS_SOURCE 1 // 0: none, 1: Crsf (pin5), 2: In (In or pin1), 3: mBridge (pin5) +#define SETUP_TX_CHANNELS_SOURCE 0 // 0: none, 1: Crsf (pin5), 2: In (In or pin1), 3: mBridge (pin5) #define SETUP_TX_CHANNEL_ORDER CHANNEL_ORDER_AETR @@ -59,15 +68,17 @@ #define SETUP_TX_DIVERSITY DIVERSITY // 0: default, 1: ANTENNA 1 if diversity available, 2: ANTENNA 2 if diversity available -#define SETUP_TX_SEND_RADIO_STATUS 1 // 0: off, 1: 1 Hz -#define SETUP_TX_MAV_COMPONENT 1 // 0: off, 1: enabled +#define SETUP_TX_SEND_RADIO_STATUS 0 // 0: off, 1: 1 Hz +#define SETUP_TX_MAV_COMPONENT 0 // 0: off, 1: enabled #define SETUP_TX_BUZZER 0 // 0: off, 1: LP, 2: rxLQ +#define SETUP_TX_FAN 1 // 0: auto, 1: always on + #define SETUP_RX_CHANNEL_ORDER CHANNEL_ORDER_AETR -#define SETUP_RX_OUT_MODE 1 // 0: OUT_CONFIG_SBUS, 1: OUT_CONFIG_CRSF, 2: OUT_CONFIG_SBUS_INVERTED +#define SETUP_RX_OUT_MODE 0 // 0: OUT_CONFIG_SBUS, 1: OUT_CONFIG_CRSF, 2: OUT_CONFIG_SBUS_INVERTED #define SETUP_RX_FAILSAFE_MODE 0 // 0: no signal 1: low throttle, 4: CH1-CH4 center signal @@ -79,27 +90,31 @@ #define SETUP_RX_DIVERSITY DIVERSITY // 0: default, 1: ANTENNA 1 if diversity available, 2: ANTENNA 2 if diversity available -#define SETUP_RX_SERIAL_LINK_MODE 2 // 0: transparent, 1: mavlink, 2: mavlinkX, 3: mspX +#define SETUP_RX_SERIAL_LINK_MODE 0 // 0: transparent, 1: mavlink, 2: mavlinkX, 3: mspX +#define SETUP_RX_SEND_RADIO_STATUS 0 // 0: off, 1: ardu_1, 2: px4 aka "brad" #define SETUP_RX_MAVLINK_SYSTEM_ID 0 // 0: 51, 1: 52, 2: 53, 3: 54, 4: 55 // SiK uses 51, 68 -#define SETUP_RX_SEND_RADIO_STATUS 1 // 0: off, 1: ardu_1, 2: px4 aka "brad" + #define SETUP_RX_SEND_RC_CHANNELS 0 // 0: off, 1: RC_CHANNEL_OVERRIDE, 2: RC_CHANNELS #define SETUP_RX_OUT_RSSI_CHANNEL 0 // 0: off, 5: CH5, 16: CH16 #define SETUP_RX_OUT_LQ_CHANNEL 0 // 0: off, 5: CH5, 16: CH16 -#define BIND_PHRASE "mlrs.0" // string of 6 characters, allowed are 'a'-'z','0'-'9','_','-','#','.' +#define BIND_PHRASE "bind.5" // string of 6 characters, allowed are 'a'-'z','0'-'9','_','-','#','.' #define SETUP_MODE MODE_50HZ +//#define SETUP_MODE MODE_50HZ //#define SETUP_MODE MODE_31HZ //#define SETUP_MODE MODE_19HZ +//#define SETUP_MODE MODE_19HZ -//#define SETUP_RF_BAND SETUP_FREQUENCY_BAND_915_MHZ_FCC -#define SETUP_RF_BAND SETUP_FREQUENCY_BAND_868_MHZ // that's my privilege :) - +//#define SETUP_RF_BAND SETUP_FREQUENCY_BAND_915_MHZ_FCC +//#define SETUP_RF_BAND SETUP_FREQUENCY_BAND_868_MHZ // that's my privilege :) +//#define SETUP_RF_BAND SETUP_FREQUENCY_BAND_868_MHZ // that's my privilege :) +#define SETUP_RF_BAND SETUP_FREQUENCY_BAND_2P4_GHZ #define SETUP_RF_ORTHO 0 // 0: off, 1: 1/3, 2: 2/3, 3: 3/3 @@ -132,15 +147,15 @@ #define FHSS_NUM_868_MHZ 6 // it's a very narrow band #define FHSS_NUM_915_MHZ_FCC 25 // https://www.ecfr.gov/current/title-47/chapter-I/subchapter-A/part-15/subpart-C/subject-group-ECFR2f2e5828339709e/section-15.247#p-15.247(a)(1)(i) #define FHSS_NUM_866_MHZ_IN 3 // 3 since 1 is needed for bind -#define FHSS_NUM_2P4_GHZ 24 +#define FHSS_NUM_2P4_GHZ 12 #define FHSS_NUM_2P4_GHZ_31HZ 18 #define FHSS_NUM_2P4_GHZ_19HZ 12 // was 24, but a cycle takes then 1.3 sec! would need long disconnect -#define FRAME_TX_RX_LEN 91 // we currently only support equal len +#define FRAME_TX_RX_LEN 73 // we currently only support equal len -#define CONNECT_TMO_MS 1250 // time to disconnect, was 500, then 750 to better handle 19 Hz mode, now 1250 +#define CONNECT_TMO_MS 1250 // 1250 time to disconnect, was 500, then 750 to better handle 19 Hz mode, now 1250 -#define CONNECT_SYNC_CNT 5 // number of packets to connect +#define CONNECT_SYNC_CNT 1 // 5 number of packets to connect #define LQ_AVERAGING_MS 1000 diff --git a/mLRS/Common/common_stats.h b/mLRS/Common/common_stats.h index d3ba6ca3b..7ee7c09bb 100644 --- a/mLRS/Common/common_stats.h +++ b/mLRS/Common/common_stats.h @@ -82,6 +82,10 @@ class tStats uint8_t last_antenna; uint8_t last_transmit_antenna; + uint8_t sys_id; + uint8_t show_group; + uint8_t broadcast; + // statistics received from the other end int8_t received_rssi; diff --git a/mLRS/Common/fan.h b/mLRS/Common/fan.h index 926e7bbf4..9ec182cfe 100644 --- a/mLRS/Common/fan.h +++ b/mLRS/Common/fan.h @@ -14,47 +14,81 @@ #include #include #include "hal/hal.h" +#include "setup_types.h" #ifndef USE_FAN +#ifdef FAN_ALWAYS_ON + #warning FAN_ALWAYS_ON is defined, but the device has no fan! +#endif + class tFan { public: void Init(void) {} + void SetMode(uint8_t fan_mode) {} void SetPower(int8_t power_dbm) {} void Tick_ms(void) {} }; #else +#ifndef FAN_ALWAYS_ON_DBM + #define FAN_ALWAYS_ON_DBM POWER_MAX // POWER_MAX selects the highest fan setting the device offers +#endif + + class tFan { public: void Init(void); + void SetMode(uint8_t fan_mode); // FAN_MODE_AUTO or FAN_MODE_ALWAYS_ON, see Setup.Tx[].FanMode void SetPower(int8_t power_dbm); void Tick_ms(void); private: + bool always_on(void); + bool initialized; int8_t power_dbm_curr; + uint8_t mode; }; +bool tFan::always_on(void) +{ +#ifdef FAN_ALWAYS_ON + return true; // hard forced, the setup parameter is locked to always on +#else + return (mode == FAN_MODE_ALWAYS_ON); +#endif +} + + void tFan::Init(void) { fan_init(); initialized = false; power_dbm_curr = POWER_MIN; + mode = FAN_MODE_AUTO; // the Tx overwrites this with the setup value before the first SetPower() +} + + +void tFan::SetMode(uint8_t fan_mode) +{ + mode = fan_mode; } void tFan::SetPower(int8_t power_dbm) { + if (always_on()) power_dbm = FAN_ALWAYS_ON_DBM; // ignore the rf power + #ifdef DEVICE_HAS_FAN_ONOFF - if (power_dbm_curr != power_dbm || !initialized) { + if (power_dbm_curr != power_dbm || !initialized) { // a mode change also changes power_dbm, so is caught here initialized = true; fan_set_power(power_dbm); power_dbm_curr = power_dbm; @@ -66,6 +100,8 @@ void tFan::SetPower(int8_t power_dbm) void tFan::Tick_ms(void) { #ifdef DEVICE_HAS_FAN_TEMPCONTROLLED_ONOFF + if (always_on()) { fan_on(); return; } + int16_t temp_dC = fan_tempsensor_read_dC(); if (temp_dC > 500) { // 50.0 C diff --git a/mLRS/Common/frame_types.h b/mLRS/Common/frame_types.h index 0454017aa..5ba114175 100644 --- a/mLRS/Common/frame_types.h +++ b/mLRS/Common/frame_types.h @@ -37,99 +37,52 @@ typedef enum { typedef struct { uint8_t seq_no; - uint8_t ack; - int8_t rssi; - uint8_t LQ_rc; // that's the LQ we want to report to the world - uint8_t LQ_serial; - uint8_t antenna; - uint8_t transmit_antenna; + uint8_t broadcast; + uint8_t sys_id; + uint8_t show_group; // not stats but needed uint8_t tx_fhss_index_band; uint8_t tx_fhss_index; } tFrameStats; - #define FRAME_TX_RX_HEADER_LEN 7 -#define FRAME_TX_RCDATA1_LEN 6 -#define FRAME_TX_RCDATA2_LEN 10 #define FRAME_TX_PAYLOAD_LEN 64 // 82 - 10-6(rcdata) - 2(crc) = 64 -#define FRAME_RX_PAYLOAD_LEN 82 - +#define FRAME_RX_PAYLOAD_LEN 64 PACKED( typedef struct { uint32_t seq_no : 3; - uint32_t ack : 1; uint32_t frame_type : 4; - uint32_t antenna : 1; - uint32_t rssi_u7 : 7; + uint32_t broadcast : 1; + uint32_t sys_id:8; + uint32_t show_group:8; uint32_t fhss_index_band : 1; // fhss index is for band 0 or 1 uint32_t fhss_index : 6; // older versions have set that field to 63 - uint32_t LQ_serial : 7; - uint32_t transmit_antenna : 1; uint32_t spare : 2; uint32_t payload_len : 7; }) tTxFrameStatus; // 5 bytes - PACKED( typedef struct { uint32_t seq_no : 3; - uint32_t ack : 1; uint32_t frame_type : 4; - uint32_t antenna : 1; - uint32_t rssi_u7 : 7; - uint32_t LQ_rc : 7; // available only for Rx->Tx frame, not for Tx->Rx - uint32_t LQ_serial : 7; - uint32_t transmit_antenna : 1; - uint32_t spare : 2; + uint32_t broadcast : 1; + uint32_t sys_id:8; + uint32_t show_group:8; + uint32_t spare : 9; uint32_t payload_len : 7; }) tRxFrameStatus; // 5 bytes - -//-- Tx Frame ---------- - -PACKED( -typedef struct -{ - uint16_t ch0 : 11; // 0 .. 1024 .. 2047, 11 bits - uint16_t ch1 : 11; - uint16_t ch2 : 11; - uint16_t ch3 : 11; - uint16_t ch12 : 2; // 0 .. 1 .. 2, 2 bits, 3-way - uint16_t ch13 : 2; -}) tFrameRcData1; // 6 bytes - - -PACKED( -typedef struct -{ - uint16_t ch4 : 11; // 0 .. 1024 .. 2047, 11 bits - uint16_t ch5 : 11; - uint16_t ch6 : 11; - uint16_t ch7 : 11; - uint16_t ch14 : 2; // 0 .. 1 .. 2, 2 bits, 3-way - uint16_t ch15 : 2; - uint8_t ch8; // 0 .. 128 .. 255, 8 bits - uint8_t ch9; // 0 .. 128 .. 255, 8 bits - uint8_t ch10; // 0 .. 128 .. 255, 8 bits - uint8_t ch11; // 0 .. 128 .. 255, 8 bits -}) tFrameRcData2; // 10 bytes - - PACKED( typedef struct { uint16_t sync_word; // 2 bytes tTxFrameStatus status; // 5 bytes - tFrameRcData1 rc1; // 6 bytes - uint16_t crc1; - tFrameRcData2 rc2; // 10 bytes - uint8_t payload[64]; // = FRAME_TX_PAYLOAD_LEN + uint8_t payload[FRAME_TX_PAYLOAD_LEN]; // = FRAME_TX_PAYLOAD_LEN uint16_t crc; -}) tTxFrame; // 91 bytes +}) tTxFrame; // 73 bytes //-- Rx Frame ---------- @@ -139,58 +92,9 @@ typedef struct { uint16_t sync_word; // 2 bytes tRxFrameStatus status; // 5 bytes - uint8_t payload[82]; // = FRAME_RX_PAYLOAD_LEN + uint8_t payload[FRAME_RX_PAYLOAD_LEN]; // = FRAME_RX_PAYLOAD_LEN uint16_t crc; -}) tRxFrame; // 91 bytes - - -//------------------------------------------------------- -// Bind frames -// are send on bind frequency in 19 Hz mode -//------------------------------------------------------- - -PACKED( -typedef struct -{ - uint64_t bind_signature; // 8 bytes // different for Tx and Rx - uint8_t seq_no : 3; - uint8_t ack : 1; - uint8_t frame_type : 4; // 1 byte // not used currently - - uint8_t connected : 1; - uint8_t spare : 7; - - char BindPhrase_6[6]; - uint8_t FrequencyBand: 4; // required for bind to know - uint8_t Mode : 4; - uint8_t Ortho : 4; - - uint8_t spare1 : 4; - uint8_t spare2[71]; - - uint16_t crc; // 2 bytes -}) tTxBindFrame; // 91 bytes - - -PACKED( -typedef struct -{ - uint64_t bind_signature; // 8 bytes // different for Tx and Rx - uint8_t seq_no : 3; - uint8_t ack : 1; - uint8_t frame_type : 4; // 1 byte // not used currently - - uint8_t connected : 1; - uint8_t spare : 7; - - uint32_t firmware_version; - char device_name_20[20]; - - uint8_t spare2[55]; - - uint16_t crc; // 2 bytes -}) tRxBindFrame; // 91 bytes - +}) tRxFrame; // 73 bytes //------------------------------------------------------- // Cmd & SetupData frames @@ -249,31 +153,16 @@ typedef struct { uint8_t cmd; uint8_t spare; - // rx setup meta data 1 - uint16_t firmware_version_u16; // 16.64.64 - uint16_t setup_layout_u16; // 16.64.64 char device_name_20[20]; int8_t actual_power_dbm; - uint8_t actual_diversity; - + uint8_t spare1; // rx parameter values // BindPhrase, FrequencyBand, Mode must be equal to Tx, otherwise Rx wouldn't connect, so don't have to be send tCmdFrameRxParameters RxParams; // 24 bytes - // rx setup meta data 2, parameter metadata - uint16_t FrequencyBand_allowed_mask_XXX; // TODO - uint8_t Mode_allowed_mask_XXX; // TODO - uint8_t Ortho_allowed_mask_XXX; // TODO - uint8_t spare2[2]; - int16_t Power_list[8]; - uint8_t Diversity_allowed_mask; - uint8_t OutMode_allowed_mask; - uint8_t SerialPort_allowed_mask; // was uint8_t __Buzzer_allowed_mask; // deprecated - - uint8_t spare3[5]; -}) tRxCmdFrameRxSetupData; // 82 bytes +}) tRxCmdFrameRxSetupData; // 64 bytes // send from Tx to do SET_RX_PARAMS diff --git a/mLRS/Common/frames.h b/mLRS/Common/frames.h index d242985fa..c1f95d840 100644 --- a/mLRS/Common/frames.h +++ b/mLRS/Common/frames.h @@ -41,7 +41,7 @@ void _pack_txframe_w_type( uint8_t* const payload, uint8_t payload_len) { -uint16_t crc; + uint16_t crc; if (payload_len > FRAME_TX_PAYLOAD_LEN) payload_len = FRAME_TX_PAYLOAD_LEN; // should never occur, but play it safe @@ -50,38 +50,22 @@ uint16_t crc; // generate header frame->sync_word = Config.FrameSyncWord; frame->status.seq_no = frame_stats->seq_no; - frame->status.ack = frame_stats->ack; frame->status.frame_type = type; // FRAME_TYPE_TX, FRAME_TYPE_TX_RX_CMD - frame->status.antenna = frame_stats->antenna; - frame->status.transmit_antenna = frame_stats->transmit_antenna; - frame->status.rssi_u7 = rssi_u7_from_i8(frame_stats->rssi); + frame->status.broadcast = frame_stats->broadcast; frame->status.fhss_index_band = frame_stats->tx_fhss_index_band; frame->status.fhss_index = frame_stats->tx_fhss_index; - frame->status.LQ_serial = frame_stats->LQ_serial; + if (frame->status.broadcast) + { + frame->status.sys_id = 0x00; + frame->status.show_group = 0xFF; + } + else + { + frame->status.sys_id = frame_stats->sys_id; + frame->status.show_group = frame_stats->show_group; + } frame->status.payload_len = payload_len; - // pack rc data - // rcData: 0 .. 1024 .. 2047, 11 bits - frame->rc1.ch0 = rc->ch[0]; // 0 .. 1024 .. 2047, 11 bits - frame->rc1.ch1 = rc->ch[1]; - frame->rc1.ch2 = rc->ch[2]; - frame->rc1.ch3 = rc->ch[3]; - - frame->rc2.ch4 = rc->ch[4]; // 0 .. 1024 .. 2047, 11 bits - frame->rc2.ch5 = rc->ch[5]; - frame->rc2.ch6 = rc->ch[6]; - frame->rc2.ch7 = rc->ch[7]; - - frame->rc2.ch8 = rc->ch[8] / 8; // 0 .. 128 .. 255, 8 bits - frame->rc2.ch9 = rc->ch[9] / 8; - frame->rc2.ch10 = rc->ch[10] / 8; - frame->rc2.ch11 = rc->ch[11] / 8; - - frame->rc1.ch12 = (rc->ch[12] >= 1536) ? 2 : ((rc->ch[12] <= 512) ? 0 : 1); // 0 .. 1 .. 2, bits, 3-way - frame->rc1.ch13 = (rc->ch[13] >= 1536) ? 2 : ((rc->ch[13] <= 512) ? 0 : 1); - frame->rc2.ch14 = (rc->ch[14] >= 1536) ? 2 : ((rc->ch[14] <= 512) ? 0 : 1); - frame->rc2.ch15 = (rc->ch[15] >= 1536) ? 2 : ((rc->ch[15] <= 512) ? 0 : 1); - // pack the payload for (uint8_t i = 0; i < payload_len; i++) { frame->payload[i] = payload[i]; @@ -89,10 +73,7 @@ uint16_t crc; // finalize, crc fmav_crc_init(&crc); - fmav_crc_accumulate_buf(&crc, (uint8_t*)frame, FRAME_TX_RX_HEADER_LEN + FRAME_TX_RCDATA1_LEN); - frame->crc1 = crc; - - fmav_crc_accumulate_buf(&crc, (uint8_t*)frame + FRAME_TX_RX_HEADER_LEN + FRAME_TX_RCDATA1_LEN, FRAME_TX_RX_LEN - FRAME_TX_RX_HEADER_LEN - FRAME_TX_RCDATA1_LEN - 2); + fmav_crc_accumulate_buf(&crc, (uint8_t*)frame, FRAME_TX_RX_HEADER_LEN - 2); frame->crc = crc; } @@ -107,7 +88,6 @@ void pack_txframe( _pack_txframe_w_type(frame, FRAME_TYPE_TX, frame_stats, rc, payload, payload_len); } - // returns 0 if OK !! uint8_t check_txframe(tTxFrame* const frame) { @@ -122,70 +102,18 @@ uint16_t crc; if (frame->status.payload_len > FRAME_TX_PAYLOAD_LEN) return CHECK_ERROR_HEADER; fmav_crc_init(&crc); - fmav_crc_accumulate_buf(&crc, (uint8_t*)frame, FRAME_TX_RX_HEADER_LEN + FRAME_TX_RCDATA1_LEN); - if (crc != frame->crc1) return CHECK_ERROR_CRC1; - - fmav_crc_accumulate_buf(&crc, (uint8_t*)frame + FRAME_TX_RX_HEADER_LEN + FRAME_TX_RCDATA1_LEN, FRAME_TX_RX_LEN - FRAME_TX_RX_HEADER_LEN - FRAME_TX_RCDATA1_LEN - 2); + fmav_crc_accumulate_buf(&crc, (uint8_t*)frame, FRAME_TX_RX_HEADER_LEN - 2); if (crc != frame->crc) return CHECK_ERROR_CRC; return CHECK_OK; } - -void rcdata_rc1_from_txframe(tRcData* const rc, tTxFrame* const frame) -{ - rc->ch[0] = frame->rc1.ch0; - rc->ch[1] = frame->rc1.ch1; - rc->ch[2] = frame->rc1.ch2; - rc->ch[3] = frame->rc1.ch3; - - rc->ch[12] = (frame->rc1.ch12 > 1) ? 2047 : ((frame->rc1.ch12 < 1) ? 0 : 1024); - rc->ch[13] = (frame->rc1.ch13 > 1) ? 2047 : ((frame->rc1.ch13 < 1) ? 0 : 1024); -} - - -void rcdata_from_txframe(tRcData* const rc, tTxFrame* const frame) -{ - rc->ch[0] = frame->rc1.ch0; - rc->ch[1] = frame->rc1.ch1; - rc->ch[2] = frame->rc1.ch2; - rc->ch[3] = frame->rc1.ch3; - - rc->ch[4] = frame->rc2.ch4; - rc->ch[5] = frame->rc2.ch5; - rc->ch[6] = frame->rc2.ch6; - rc->ch[7] = frame->rc2.ch7; - - rc->ch[8] = frame->rc2.ch8 * 8; - rc->ch[9] = frame->rc2.ch9 * 8; - rc->ch[10] = frame->rc2.ch10 * 8; - rc->ch[11] = frame->rc2.ch11 * 8; - - rc->ch[12] = (frame->rc1.ch12 > 1) ? 2047 : ((frame->rc1.ch12 < 1) ? 0 : 1024); - rc->ch[13] = (frame->rc1.ch13 > 1) ? 2047 : ((frame->rc1.ch13 < 1) ? 0 : 1024); - rc->ch[14] = (frame->rc2.ch14 > 1) ? 2047 : ((frame->rc2.ch14 < 1) ? 0 : 1024); - rc->ch[15] = (frame->rc2.ch15 > 1) ? 2047 : ((frame->rc2.ch15 < 1) ? 0 : 1024); - - rc->ch[16] = 1024; - rc->ch[17] = 1024; -} - - // update header info with new data, keep payload void update_rxframe_stats(tRxFrame* const frame, tFrameStats* const frame_stats) { uint16_t crc; frame->sync_word = Config.FrameSyncWord; - // keep !! frame->status.seq_no = frame_stats->seq_no; - frame->status.ack = frame_stats->ack; - // keep !! frame->status.frame_type = type; // FRAME_TYPE_RX, FRAME_TYPE_TX_RX_CMD - frame->status.antenna = frame_stats->antenna; - frame->status.transmit_antenna = frame_stats->transmit_antenna; - frame->status.rssi_u7 = rssi_u7_from_i8(frame_stats->rssi); - frame->status.LQ_rc = frame_stats->LQ_rc; - frame->status.LQ_serial = frame_stats->LQ_serial; - // keep !! frame->status.payload_len = payload_len; fmav_crc_init(&crc); fmav_crc_accumulate_buf(&crc, (uint8_t*)frame, FRAME_TX_RX_LEN - 2); @@ -200,7 +128,7 @@ void _pack_rxframe_w_type( uint8_t* const payload, uint8_t payload_len) { -uint16_t crc; + uint16_t crc; if (payload_len > FRAME_RX_PAYLOAD_LEN) payload_len = FRAME_RX_PAYLOAD_LEN; // should never occur, but play it safe @@ -208,13 +136,7 @@ uint16_t crc; frame->sync_word = Config.FrameSyncWord; frame->status.seq_no = frame_stats->seq_no; - frame->status.ack = frame_stats->ack; frame->status.frame_type = type; // FRAME_TYPE_RX, FRAME_TYPE_TX_RX_CMD - frame->status.antenna = frame_stats->antenna; - frame->status.transmit_antenna = frame_stats->transmit_antenna; - frame->status.rssi_u7 = rssi_u7_from_i8(frame_stats->rssi); - frame->status.LQ_rc = frame_stats->LQ_rc; - frame->status.LQ_serial = frame_stats->LQ_serial; frame->status.payload_len = payload_len; for (uint8_t i = 0; i < payload_len; i++) { @@ -240,7 +162,7 @@ void pack_rxframe( // returns 0 if OK !! uint8_t check_rxframe(tRxFrame* const frame) { -uint16_t crc; + uint16_t crc; if (frame->sync_word != Config.FrameSyncWord) return CHECK_ERROR_SYNCWORD; @@ -336,15 +258,12 @@ uint8_t payload[1]; // Tx: handle FRAME_CMD_RX_SETUPDATA from Rx void unpack_rxcmdframe_rxsetupdata(tRxFrame* const frame) { -tRxCmdFrameRxSetupData* rx_setupdata = (tRxCmdFrameRxSetupData*)frame->payload; + tRxCmdFrameRxSetupData* rx_setupdata = (tRxCmdFrameRxSetupData*)frame->payload; SetupMetaData.rx_available = true; - SetupMetaData.rx_firmware_version = version_from_u16(rx_setupdata->firmware_version_u16); - SetupMetaData.rx_setup_layout = version_from_u16(rx_setupdata->setup_layout_u16); strstrbufcpy(SetupMetaData.rx_device_name, rx_setupdata->device_name_20, 20); SetupMetaData.rx_actual_power_dbm = rx_setupdata->actual_power_dbm; - SetupMetaData.rx_actual_diversity = rx_setupdata->actual_diversity; cmdframerxparameters_rxparams_to_rxsetup(&(rx_setupdata->RxParams)); @@ -357,9 +276,6 @@ tRxCmdFrameRxSetupData* rx_setupdata = (tRxCmdFrameRxSetupData*)frame->payload; int16_t power_list[8]; for (uint8_t i = 0; i < 8; i++) power_list[i] = rx_setupdata->Power_list[i]; // to avoid unaligned warning power_optstr_from_power_list(SetupMetaData.Rx_Power_optstr, power_list, 8, 67); - SetupMetaData.Rx_Diversity_allowed_mask = rx_setupdata->Diversity_allowed_mask; - SetupMetaData.Rx_OutMode_allowed_mask = rx_setupdata->OutMode_allowed_mask; - SetupMetaData.Rx_SerialPort_allowed_mask = rx_setupdata->SerialPort_allowed_mask; } @@ -367,7 +283,7 @@ tRxCmdFrameRxSetupData* rx_setupdata = (tRxCmdFrameRxSetupData*)frame->payload; // we take the values from Tx' Setup.Rx structure void pack_txcmdframe_setrxparams(tTxFrame* const frame, tFrameStats* const frame_stats, tRcData* const rc) { -tTxCmdFrameRxParams rx_params = {}; + tTxCmdFrameRxParams rx_params = {}; rx_params.cmd = FRAME_CMD_SET_RX_PARAMS; @@ -387,15 +303,12 @@ tTxCmdFrameRxParams rx_params = {}; // Rx: send FRAME_CMD_RX_SETUPDATA to Tx void pack_rxcmdframe_rxsetupdata(tRxFrame* const frame, tFrameStats* const frame_stats) { -tRxCmdFrameRxSetupData rx_setupdata = {}; + tRxCmdFrameRxSetupData rx_setupdata = {}; rx_setupdata.cmd = FRAME_CMD_RX_SETUPDATA; - rx_setupdata.firmware_version_u16 = version_to_u16(VERSION); - rx_setupdata.setup_layout_u16 = version_to_u16(SETUPLAYOUT); strbufstrcpy(rx_setupdata.device_name_20, DEVICE_NAME, 20); rx_setupdata.actual_power_dbm = sx.RfPower_dbm(); - rx_setupdata.actual_diversity = Config.Diversity; cmdframerxparameters_rxparams_from_rxsetup(&(rx_setupdata.RxParams)); @@ -408,9 +321,6 @@ tRxCmdFrameRxSetupData rx_setupdata = {}; for (uint8_t i = 0; i < 8; i++) { rx_setupdata.Power_list[i] = (i < RFPOWER_LIST_NUM) ? rfpower_list[i].mW : INT16_MAX; } - rx_setupdata.Diversity_allowed_mask = SetupMetaData.Rx_Diversity_allowed_mask; - rx_setupdata.OutMode_allowed_mask = SetupMetaData.Rx_OutMode_allowed_mask; - rx_setupdata.SerialPort_allowed_mask = SetupMetaData.Rx_SerialPort_allowed_mask; _pack_rxframe_w_type(frame, FRAME_TYPE_TX_RX_CMD, frame_stats, (uint8_t*)&rx_setupdata, sizeof(rx_setupdata)); } @@ -420,7 +330,7 @@ tRxCmdFrameRxSetupData rx_setupdata = {}; // new parameter values are stored in Rx' Setup.Rx fields void unpack_txcmdframe_setrxparams(tTxFrame* const frame) { -tTxCmdFrameRxParams* rx_params = (tTxCmdFrameRxParams*)frame->payload; + tTxCmdFrameRxParams* rx_params = (tTxCmdFrameRxParams*)frame->payload; strstrbufcpy(Setup.Common[0].BindPhrase, rx_params->BindPhrase_6, 6); Setup.Common[0].FrequencyBand = (SETUP_FREQUENCY_BAND_ENUM)rx_params->FrequencyBand; diff --git a/mLRS/Common/hal/esp-hal-led-rgb.h b/mLRS/Common/hal/esp-hal-led-rgb.h index 8c2ef49c2..678d7454e 100644 --- a/mLRS/Common/hal/esp-hal-led-rgb.h +++ b/mLRS/Common/hal/esp-hal-led-rgb.h @@ -14,6 +14,7 @@ #define LED_RGB_GREEN 2 #define LED_RGB_BLUE 3 #define LED_RGB_PURPLE 4 +#define LED_RGB_AMBER 5 uint8_t ledCurrentColorState;; @@ -53,3 +54,7 @@ IRAM_ATTR void led_blue_toggle(void) { (ledCurrentColorState == LED_RGB_BLUE) ? IRAM_ATTR void led_purple_off(void) { set_led_color_and_state(LED_RGB_OFF, RgbColor(0)); } IRAM_ATTR void led_purple_on(void) { set_led_color_and_state(LED_RGB_PURPLE, RgbColor(255, 0, 255)); } IRAM_ATTR void led_purple_toggle(void) { (ledCurrentColorState == LED_RGB_PURPLE) ? led_purple_off() : led_purple_on(); } + +IRAM_ATTR void led_amber_off(void) { set_led_color_and_state(LED_RGB_OFF, RgbColor(0)); } +IRAM_ATTR void led_amber_on(void) { set_led_color_and_state(LED_RGB_AMBER, RgbColor(255, 120, 0)); } +IRAM_ATTR void led_amber_toggle(void) { (ledCurrentColorState == LED_RGB_AMBER) ? led_amber_off() : led_amber_on(); } diff --git a/mLRS/Common/hal/stm32/rx-hal-diy-e28dual-board02-f103cb.h b/mLRS/Common/hal/stm32/rx-hal-diy-e28dual-board02-f103cb.h index 5f6a98ac3..1e3237412 100644 --- a/mLRS/Common/hal/stm32/rx-hal-diy-e28dual-board02-f103cb.h +++ b/mLRS/Common/hal/stm32/rx-hal-diy-e28dual-board02-f103cb.h @@ -14,8 +14,8 @@ // RX DIY DUAL-E28 BOARD02 v010 STM32F103CB //------------------------------------------------------- -#define DEVICE_HAS_DIVERSITY -#define DEVICE_HAS_OUT +//#define DEVICE_HAS_DIVERSITY +//#define DEVICE_HAS_OUT #ifdef MLRS_FEATURE_DIVERSITY diff --git a/mLRS/Common/hal/stm32/tx-hal-diy-e28dual-board02-f103cb.h b/mLRS/Common/hal/stm32/tx-hal-diy-e28dual-board02-f103cb.h index 3a50ea8b0..5a517146b 100644 --- a/mLRS/Common/hal/stm32/tx-hal-diy-e28dual-board02-f103cb.h +++ b/mLRS/Common/hal/stm32/tx-hal-diy-e28dual-board02-f103cb.h @@ -16,8 +16,8 @@ // TX DIY DUAL-E28 BOARD02 v010 STM32F103CB //------------------------------------------------------- -#define DEVICE_HAS_DIVERSITY -#define DEVICE_HAS_JRPIN5 // requires diode from Tx to Rx soldered on the board +//#define DEVICE_HAS_DIVERSITY +//#define DEVICE_HAS_JRPIN5 // requires diode from Tx to Rx soldered on the board //#define DEVICE_HAS_IN #define DEVICE_HAS_DEBUG_SWUART diff --git a/mLRS/Common/leds.h b/mLRS/Common/leds.h index fdbcc562a..83c1d43ea 100644 --- a/mLRS/Common/leds.h +++ b/mLRS/Common/leds.h @@ -23,6 +23,7 @@ class tLEDs void Tick_ms(bool connected) {} void SetToBind(void) {} void SetToParamStore(void) {} + void SetWarning(bool flag) {} void InitPassthrough(void) {} void TickPassthrough_ms(void) {} }; @@ -37,6 +38,7 @@ class tLEDs { blink = 0; is_in_bind = false; + is_warning = false; led_red_off(); for (uint8_t i = 0; i < 7; i++) { led_red_toggle(); delay_ms(50); } @@ -44,6 +46,18 @@ class tLEDs void Tick_ms(bool connected) { + if (is_warning) { // fast blink, overrides the connection indication + DECc(blink, SYSTICK_DELAY_MS(150)); + if (!blink) { +#ifdef DEVICE_HAS_SINGLE_LED_RGB + led_amber_toggle(); +#else + led_red_toggle(); // no color available, so the blink rate is all we have +#endif + } + return; + } + #ifdef DEVICE_HAS_SINGLE_LED if (!is_in_bind) { DECc(blink, SYSTICK_DELAY_MS(500)); @@ -108,6 +122,14 @@ class tLEDs #endif } + // used to warn the user, e.g. while a destructive action is waiting for confirmation + void SetWarning(bool flag) + { + if (is_warning == flag) return; + is_warning = flag; + blink = 0; // so the warning starts immediately, and the normal indication resumes immediately + } + void InitPassthrough(void) { led_red_off(); @@ -132,6 +154,7 @@ class tLEDs private: uint16_t blink; bool is_in_bind; + bool is_warning; }; diff --git a/mLRS/Common/setup.h b/mLRS/Common/setup.h index 965ca3f0b..724c376cd 100644 --- a/mLRS/Common/setup.h +++ b/mLRS/Common/setup.h @@ -186,6 +186,15 @@ void setup_configure_metadata(void) SetupMetaData.Tx_Buzzer_allowed_mask = 0; // not available, do not display #endif + // Tx Fan: "auto,always on" +#if defined USE_FAN && !defined FAN_ALWAYS_ON + SetupMetaData.Tx_FanMode_allowed_mask = UINT16_MAX; // all +#elif defined USE_FAN + SetupMetaData.Tx_FanMode_allowed_mask = 0b10; // always on, not editable, it is forced by FAN_ALWAYS_ON +#else + SetupMetaData.Tx_FanMode_allowed_mask = 0; // not available, do not display +#endif + // Tx Bridge WiFi Protocol : "TCP,UDP,BT,UDPSTA,BLE" #if defined DEVICE_HAS_ESP_WIFI_BRIDGE_ESP8266 SetupMetaData.Tx_WiFiProt_allowed_mask = 0b01011; // TCP, UDP, UDPSTA (no BT, no BLE) @@ -311,6 +320,7 @@ void setup_default(uint8_t config_id) Setup.Tx[config_id].SerialBaudrate = SETUP_TX_SERIAL_BAUDRATE; Setup.Tx[config_id].SendRadioStatus = SETUP_TX_SEND_RADIO_STATUS; Setup.Tx[config_id].Buzzer = SETUP_TX_BUZZER; + Setup.Tx[config_id].FanMode = SETUP_TX_FAN; Setup.Tx[config_id].MavlinkComponent = SETUP_TX_MAV_COMPONENT; Setup.Tx[config_id].PowerSwitchChannel = POWER_SWITCH_CHANNEL_OFF; @@ -426,6 +436,9 @@ void setup_sanitize_config(uint8_t config_id) SANITIZE(Tx[config_id].Buzzer, BUZZER_NUM, SETUP_TX_BUZZER, BUZZER_OFF); TST_NOTALLOWED(Tx_Buzzer_allowed_mask, Tx[config_id].Buzzer, BUZZER_OFF); + SANITIZE(Tx[config_id].FanMode, FAN_MODE_NUM, SETUP_TX_FAN, FAN_MODE_AUTO); + TST_NOTALLOWED(Tx_FanMode_allowed_mask, Tx[config_id].FanMode, FAN_MODE_AUTO); + SANITIZE(Tx[config_id].PowerSwitchChannel, POWER_SWITCH_CHANNEL_NUM, POWER_SWITCH_CHANNEL_OFF, POWER_SWITCH_CHANNEL_OFF); // device cannot use mBridge (pin5) and CRSF (pin5) at the same time ! diff --git a/mLRS/Common/setup_list.h b/mLRS/Common/setup_list.h index 318952744..5e19c3160 100644 --- a/mLRS/Common/setup_list.h +++ b/mLRS/Common/setup_list.h @@ -38,6 +38,7 @@ #define SETUP_MSK_TX_CH_SOURCE &SetupMetaData.Tx_ChannelsSource_allowed_mask // this we generate from the hal #define SETUP_MSK_TX_IN_MODE &SetupMetaData.Tx_InMode_allowed_mask // this we generate from the hal #define SETUP_MSK_TX_BUZZER &SetupMetaData.Tx_Buzzer_allowed_mask // this we generate from the hal +#define SETUP_MSK_TX_FAN &SetupMetaData.Tx_FanMode_allowed_mask // this we generate from the hal #define SETUP_MSK_TX_WIFIPROT &SetupMetaData.Tx_WiFiProt_allowed_mask // this we generate from the hal // Rx only @@ -106,15 +107,24 @@ X( Setup.Tx[0].PowerSwitchChannel,LIST, "Tx Power Sw Ch", "TX_POWER_SW_CH", 0,0,0,"", "off,5,6,7,8,9,10,11,12,13,14,15,16", MSK_ALL )\ X( Setup.Tx[0].Buzzer, LIST, "Tx Buzzer", "TX_BUZZER", 0,0,0,"", "off,LP,rxLQ", SETUP_MSK_TX_BUZZER ) +#define SETUP_PARAMETER_LIST_TX_FAN \ + X( Setup.Tx[0].FanMode, LIST, "Tx Fan", "TX_FAN", 0,0,0,"", "auto,on", SETUP_MSK_TX_FAN ) + #define SETUP_PARAMETER_LIST_TX_ESP \ X( Setup.Tx[0].WifiProtocol, LIST, "Tx Wifi Protocol", "TX_WIFI_PROT", 0,0,0,"", "TCP,UDP,BT,UDP STA,BLE", SETUP_MSK_TX_WIFIPROT )\ X( Setup.Tx[0].WifiChannel, LIST, "Tx Wifi Channel", "TX_WIFI_CHANNEL", 0,0,0,"", "1,6,11,13", MSK_ALL )\ X( Setup.Tx[0].WifiPower, LIST, "Tx Wifi Power", "TX_WIFI_POWER", 0,0,0,"", "low,med,max", MSK_ALL ) +#if defined USE_FAN +#define SETUP_PARAMETER_LIST_TX_MAIN_ SETUP_PARAMETER_LIST_TX_MAIN SETUP_PARAMETER_LIST_TX_FAN +#else +#define SETUP_PARAMETER_LIST_TX_MAIN_ SETUP_PARAMETER_LIST_TX_MAIN +#endif + #if defined USE_ESP_WIFI_BRIDGE_CONFIGURE -#define SETUP_PARAMETER_LIST_TX SETUP_PARAMETER_LIST_TX_MAIN SETUP_PARAMETER_LIST_TX_ESP +#define SETUP_PARAMETER_LIST_TX SETUP_PARAMETER_LIST_TX_MAIN_ SETUP_PARAMETER_LIST_TX_ESP #else -#define SETUP_PARAMETER_LIST_TX SETUP_PARAMETER_LIST_TX_MAIN +#define SETUP_PARAMETER_LIST_TX SETUP_PARAMETER_LIST_TX_MAIN_ #endif #define SETUP_PARAMETER_LIST_RX \ diff --git a/mLRS/Common/setup_types.h b/mLRS/Common/setup_types.h index 59c304fa8..6008ae0ea 100644 --- a/mLRS/Common/setup_types.h +++ b/mLRS/Common/setup_types.h @@ -219,6 +219,13 @@ typedef enum { } TX_BUZZER_END_ENUM; +typedef enum { + FAN_MODE_AUTO = 0, // fan follows the rf power setting, resp. the temperature + FAN_MODE_ALWAYS_ON, // fan runs always, whatever the rf power setting is + FAN_MODE_NUM, +} TX_FAN_MODE_ENUM; + + typedef enum { WIFI_PROTOCOL_TCP = 0, WIFI_PROTOCOL_UDP, @@ -369,8 +376,9 @@ typedef struct uint8_t WifiProtocol; uint8_t WifiChannel; uint8_t WifiPower; + uint8_t FanMode; // taken from spare, so layout is unchanged, 0xFF from an older EEPROM is caught by the sanitizer - uint8_t spare[4]; + uint8_t spare[3]; } tTxSetup; // 20 bytes @@ -457,6 +465,7 @@ typedef struct uint16_t Tx_InMode_allowed_mask; uint16_t Tx_SerialDestination_allowed_mask; uint16_t Tx_Buzzer_allowed_mask; + uint16_t Tx_FanMode_allowed_mask; uint16_t Tx_WiFiProt_allowed_mask; char Rx_Power_optstr[67+1]; diff --git a/mLRS/Common/tasks.h b/mLRS/Common/tasks.h index 0a40f3363..db258a09a 100644 --- a/mLRS/Common/tasks.h +++ b/mLRS/Common/tasks.h @@ -26,6 +26,9 @@ typedef enum { TX_TASK_RX_PARAM_SET, TX_TASK_PARAM_STORE, TX_TASK_PARAM_RELOAD, + TX_TASK_PARAM_DEFAULTS, // restores the defaults into RAM only, TX_TASK_PARAM_STORE writes them to EEPROM + // note: mavlink's task_pending_mask is a uint16_t and holds bits for RX_PARAM_SET and PARAM_STORE, + // so new tasks must be added behind them TX_TASK_FLASH_ESP, TX_TASK_ESP_PASSTHROUGH, diff --git a/mLRS/Common/thirdparty/mavlinkx.h b/mLRS/Common/thirdparty/mavlinkx.h index dc69be540..d131a31eb 100644 --- a/mLRS/Common/thirdparty/mavlinkx.h +++ b/mLRS/Common/thirdparty/mavlinkx.h @@ -764,7 +764,7 @@ CHECKRANGEBUF(result->frame_len); // returns 0, or 1 FASTMAVLINK_FUNCTION_DECORATOR uint8_t fmavX_parse_and_checkX_to_frame_buf(fmav_result_t* const result, uint8_t* const buf, fmav_status_t* const status, uint8_t c) { -uint8_t res; + uint8_t res; res = fmavX_parseX_to_frame_buf(result, buf, status, c); // result can be NONE, HAS_HEADER, or OK diff --git a/mLRS/CommonRx/mavlink_interface_rx.h b/mLRS/CommonRx/mavlink_interface_rx.h index 4e7ccb6c6..78de5ddca 100644 --- a/mLRS/CommonRx/mavlink_interface_rx.h +++ b/mLRS/CommonRx/mavlink_interface_rx.h @@ -24,6 +24,9 @@ extern bool connected(void); extern tStats stats; extern tSetup Setup; +#define REBOOT_SHUTDOWN_ACTION_REBOOT_TO_BOOTLOADER 3 /* we added this definition to avoid compilation error, */ + /* as we do not have proper mavlink code generated, */ + /* as we prefer to not use it at the moment, google AI told that it should be 3*/ //------------------------------------------------------- // RxMavlink class @@ -265,7 +268,7 @@ void tRxMavlink::Do(void) if (!SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) return; // parse serial in -> link out - parse_serial_in_link_out(); + // parse_serial_in_link_out(); DO NOT if (Setup.Rx.SendRadioStatus && connected()) { // we currently know that if we determine inject_radio_status here it will be executed immediately @@ -328,7 +331,6 @@ void tRxMavlink::Do(void) BootLoaderInit(); // jump to system bootloader break; case MAV_CMD_START_RX_PAIR: - bind.StartBind(); // start binding break; } cmd_ack.command = 0; @@ -379,7 +381,7 @@ void tRxMavlink::parse_serial_in_link_out(void) len = fmav_msg_to_frame_buf(_buf, &msg_link_out); } - fifo_link_out.PutBuf(_buf, len); + fifo_link_out.PutBuf(_buf, len); //Do not but anything for sending bytes_parser_in = 0; handle_msg(&msg_link_out); @@ -1092,7 +1094,7 @@ void tRxMavlink::handle_msg(fmav_message_t* const msg) void tRxMavlink::handle_cmd(fmav_message_t* const msg) { #ifdef USE_FEATURE_MAVLINKX -fmav_command_long_t payload; + fmav_command_long_t payload; fmav_msg_command_long_decode(&payload, msg); diff --git a/mLRS/CommonRx/mlrs-rx.cpp b/mLRS/CommonRx/mlrs-rx.cpp index 272a1ee83..903ed8e9e 100644 --- a/mLRS/CommonRx/mlrs-rx.cpp +++ b/mLRS/CommonRx/mlrs-rx.cpp @@ -178,15 +178,9 @@ void SX_DIO_EXTI_IRQHandler(void) sx_dio_exti_isr_clearflag(); irq_status = sx.GetAndClearIrqStatus(SX_IRQ_ALL); if (irq_status & SX_IRQ_RX_DONE) { - if (bind.IsInBind()) { - uint64_t bind_signature; - sx.ReadBuffer(0, (uint8_t*)&bind_signature, 8); - if (bind_signature != bind.TxSignature) irq_status = 0; // not binding frame, so ignore it - } else { - uint16_t sync_word; - sx.ReadBuffer(0, (uint8_t*)&sync_word, 2); // rxStartBufferPointer is always 0, so no need for sx.GetRxBufferStatus() - if (sync_word != Config.FrameSyncWord) irq_status = 0; // not for us, so ignore it - } + uint16_t sync_word; + sx.ReadBuffer(0, (uint8_t*)&sync_word, 2); // rxStartBufferPointer is always 0, so no need for sx.GetRxBufferStatus() + if (sync_word != Config.FrameSyncWord) irq_status = 0; // not for us, so ignore it } }) #ifdef USE_SX2 @@ -297,8 +291,8 @@ void pack_rxcmdframe(tRxFrame* const frame, tFrameStats* const frame_stats) void prepare_transmit_frame(uint8_t antenna) { -uint8_t payload[FRAME_RX_PAYLOAD_LEN]; -uint8_t payload_len = 0; + uint8_t payload[FRAME_RX_PAYLOAD_LEN]; + uint8_t payload_len = 0; bool get_fresh_payload = tarq.GetFreshPayload(); @@ -324,12 +318,6 @@ uint8_t payload_len = 0; tFrameStats frame_stats; frame_stats.seq_no = tarq.SeqNo(); - frame_stats.ack = 1; // TODO - frame_stats.antenna = stats.last_antenna; - frame_stats.transmit_antenna = antenna; - frame_stats.rssi = stats.GetLastRssi(); - frame_stats.LQ_rc = stats.GetLQ_rc(); - frame_stats.LQ_serial = stats.GetLQ_serial(); static bool rxFrame_valid = false; // just for now if (get_fresh_payload) { @@ -358,24 +346,8 @@ uint8_t payload_len = 0; void process_received_frame(bool do_payload, tTxFrame* const frame) { - stats.received_antenna = frame->status.antenna; - stats.received_transmit_antenna = frame->status.transmit_antenna; - stats.received_rssi = rssi_i8_from_u7(frame->status.rssi_u7); - stats.received_fhss_index_band = frame->status.fhss_index_band; stats.received_fhss_index = frame->status.fhss_index; - - stats.received_LQ_serial = frame->status.LQ_serial; - - // copy rc1 data - if (!do_payload) { - // copy only channels 1-4,12,13 and jump out - rcdata_rc1_from_txframe(&rcData, frame); - return; - } - - rcdata_from_txframe(&rcData, frame); - // handle cmd frame if (frame->status.frame_type == FRAME_TYPE_TX_RX_CMD) { process_received_txcmdframe(frame); @@ -385,11 +357,13 @@ void process_received_frame(bool do_payload, tTxFrame* const frame) link_task_reset(); // clear it if non-cmd frame is received // output data on serial, but only if connected - if (!connected()) return; - sx_serial.putbuf(frame->payload, frame->status.payload_len); - - stats.bytes_received.Add(frame->status.payload_len); - stats.serial_data_received.Inc(); + //if (!connected()) return; + if (frame->status.payload_len > 0) + { + sx_serial.putbuf(frame->payload, frame->status.payload_len); + stats.bytes_received.Add(frame->status.payload_len); + stats.serial_data_received.Inc(); + } } @@ -408,22 +382,10 @@ tTxFrame* frame; frame = &txFrame2; } - if (bind.IsInBind()) { - bind.handle_receive(antenna, rx_status); - return; - } - if (rx_status < RX_STATUS_INVALID) { // must not happen FAIL_WSTATE(BLINK_4, "rx_status failure", 0,0, link_rx1_status, link_rx2_status); } - // handle transmit ARQ - if (rx_status > RX_STATUS_INVALID) { // RX_STATUS_CRC1_VALID, RX_STATUS_VALID: we have valid information on ack - tarq.AckReceived(frame->status.ack); - } else { - tarq.FrameMissed(); - } - if (rx_status > RX_STATUS_INVALID) { // RX_STATUS_CRC1_VALID, RX_STATUS_VALID bool do_payload = (rx_status == RX_STATUS_VALID); @@ -452,11 +414,6 @@ void handle_receive_none(void) // RX_STATUS_NONE void do_transmit(uint8_t antenna) // we send a frame to transmitter { - if (bind.IsInBind()) { - bind.do_transmit(antenna); - return; - } - prepare_transmit_frame(antenna); // to test asymmetric connection, fake rxFrame, to no send doesn't work as it blocks the sx @@ -466,12 +423,8 @@ void do_transmit(uint8_t antenna) // we send a frame to transmitter uint8_t do_receive(uint8_t antenna, bool do_clock_reset) // we receive a frame from receiver { -uint8_t res; -uint8_t rx_status = RX_STATUS_INVALID; // this also signals that a frame was received - - if (bind.IsInBind()) { - return bind.do_receive(antenna, do_clock_reset); - } + uint8_t res; + uint8_t rx_status = RX_STATUS_INVALID; // this also signals that a frame was received // we don't need to read sx.GetRxBufferStatus(), but hey // we could save 2 byte's time by not reading sync_word again, but hey @@ -551,7 +504,6 @@ RESTARTCONTROLLER irq_status = irq2_status = 0; IF_SX(sx.StartUp(&Config.Sx)); IF_SX2(sx2.StartUp(&Config.Sx2)); - bind.Init(); fhss.Init(&Config.Fhss, &Config.Fhss2); fhss.Start(); rfpower.Init(); @@ -602,31 +554,9 @@ INITCONTROLLER_END DECc(tick_1hz, SYSTICK_DELAY_MS(1000)); - if (!connect_occured_once) bind.AutoBind(); - bind.Tick_ms(); fan.SetPower(sx.RfPower_dbm()); fan.Tick_ms(); dronecan.Tick_ms(); - - if (!tick_1hz) { - dbg.puts("."); -/* dbg.puts("\nRX: "); - dbg.puts(u8toBCD_s(stats.GetLQ_rc())); dbg.putc(','); - dbg.puts(u8toBCD_s(stats.GetLQ_serial())); - dbg.puts(" ("); - dbg.puts(u8toBCD_s(stats.frames_received.GetLQ())); dbg.putc(','); - dbg.puts(u8toBCD_s(stats.valid_crc1_received.GetLQ())); dbg.putc(','); - dbg.puts(u8toBCD_s(stats.valid_frames_received.GetLQ())); - dbg.puts("),"); - dbg.puts(u8toBCD_s(stats.received_LQ_serial)); dbg.puts(", "); - - dbg.puts(s8toBCD_s(stats.last_rssi1)); dbg.putc(','); - dbg.puts(s8toBCD_s(stats.received_rssi)); dbg.puts(", "); - dbg.puts(s8toBCD_s(stats.last_snr1)); dbg.puts("; "); - - dbg.puts(u16toBCD_s(stats.bytes_transmitted.GetBytesPerSec())); dbg.puts(", "); - dbg.puts(u16toBCD_s(stats.bytes_received.GetBytesPerSec())); dbg.puts("; "); */ - } } //-- SX handling @@ -829,7 +759,7 @@ dbg.puts(s8toBCD_s(stats.last_rssi2));*/ } connect_tmo_cnt = CONNECT_TMO_SYSTICKS; - link_state = LINK_STATE_TRANSMIT; // switch to TX + link_state = LINK_STATE_RECEIVE;// LINK_STATE_TRANSMIT // switch to TX } // when in listen: we received something, but something wrong, so we need go back to RX @@ -846,7 +776,7 @@ dbg.puts(s8toBCD_s(stats.last_rssi2));*/ link_state = LINK_STATE_RECEIVE; // switch back to RX } if (fhss.HopToNextBind()) { - bind.HopToNextBind(fhss.GetCurrBindSetupFrequencyBand()); + //bind.HopToNextBind(fhss.GetCurrBindSetupFrequencyBand()); link_state = LINK_STATE_RECEIVE; // switch back to RX } } @@ -869,7 +799,7 @@ dbg.puts(s8toBCD_s(stats.last_rssi2));*/ // switch to transmit state // only do it if receiving, else keep it in RX mode, otherwise chances to connect are dim // we are on the correct frequency, so no need to hop - link_state = LINK_STATE_TRANSMIT; + //link_state = LINK_STATE_TRANSMIT; } if ((connect_state >= CONNECT_STATE_SYNC) || @@ -889,29 +819,10 @@ dbg.puts(s8toBCD_s(stats.last_rssi2));*/ if (connect_state == CONNECT_STATE_LISTEN) { link_task_reset(); - link_task_set(LINK_TASK_RX_SEND_RX_SETUPDATA); + // link_task_set(LINK_TASK_RX_SEND_RX_SETUPDATA); } powerup.Do(); - if (powerup.Task() == POWERUPCNT_TASK_BIND) bind.StartBind(); - - bind.Do(); - switch (bind.Task()) { - case BIND_TASK_CHANGED_TO_BIND: - bind.ConfigForBind(); // may change Config - rxclock.SetPeriod(Config.frame_rate_ms); - rxclock.Reset(); - fhss.SetToBind(Config.frame_rate_ms); // needs to come after fhss - leds.SetToBind(); - connect_state = CONNECT_STATE_LISTEN; - link_state = LINK_STATE_RECEIVE; - break; - case BIND_TASK_RX_STORE_PARAMS: - // is already set in tBindBase::handle_receive() - //Setup.Common[0].FrequencyBand = fhss.GetCurrBindSetupFrequencyBand(); - doParamsStore = true; - break; - } doPostReceive2_cnt = 5; // postpone this few loops, to allow link_state changes to be handled diff --git a/mLRS/CommonRx/msp_interface_rx.h b/mLRS/CommonRx/msp_interface_rx.h index 685e77ca8..a75958357 100644 --- a/mLRS/CommonRx/msp_interface_rx.h +++ b/mLRS/CommonRx/msp_interface_rx.h @@ -301,7 +301,7 @@ void tRxMsp::parse_serial_in_link_out(void) // handle MSP2_RX_BIND, only if MSP V2 // this is a really a request from the FC but sent as a response // payload is ignored - bind.StartBind(); + //bind.StartBind(); send = false; // don't forward to ground } } diff --git a/mLRS/CommonRx/sx_serial_interface_rx.h b/mLRS/CommonRx/sx_serial_interface_rx.h index 75e158f66..ea8480d21 100644 --- a/mLRS/CommonRx/sx_serial_interface_rx.h +++ b/mLRS/CommonRx/sx_serial_interface_rx.h @@ -21,36 +21,36 @@ class tRxSxSerial : public tSerialBase bool available(void) override { - if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { - return mavlink.available(); // get from serial via MAVLink parser - } - if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { - return msp.available(); // get from serial via MSP parser - } +// if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { +// return mavlink.available(); // get from serial via MAVLink parser +// } +// if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { +// return msp.available(); // get from serial via MSP parser +// } return serial.available(); // get from serial } char getc(void) override { - if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { - return mavlink.getc(); // get from serial via MAVLink parser - } - if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { - return msp.getc(); // get from serial via MSP parser - } +// if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { +// return mavlink.getc(); // get from serial via MAVLink parser +// } +// if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { +// return msp.getc(); // get from serial via MSP parser +// } return serial.getc(); // get from serial } void putbuf(uint8_t* const buf, uint16_t len) override { - if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { - for (uint16_t i = 0; i < len; i++) mavlink.putc(buf[i]); // send to serial via MAVLink parser - return; - } - if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { - for (uint16_t i = 0; i < len; i++) msp.putc(buf[i]); // send to serial via MSP parser - return; - } +// if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { +// for (uint16_t i = 0; i < len; i++) mavlink.putc(buf[i]); // send to serial via MAVLink parser +// return; +// } +// if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { +// for (uint16_t i = 0; i < len; i++) msp.putc(buf[i]); // send to serial via MSP parser +// return; +// } serial.putbuf(buf, len); // send to serial } diff --git a/mLRS/CommonTx/disp.h b/mLRS/CommonTx/disp.h index e637453d2..39fff026e 100644 --- a/mLRS/CommonTx/disp.h +++ b/mLRS/CommonTx/disp.h @@ -62,6 +62,8 @@ typedef enum { PAGE_STARTUP = 0, PAGE_NOTIFY_BIND, PAGE_NOTIFY_STORE, + PAGE_NOTIFY_DEFAULTS, + PAGE_CONFIRM_DEFAULTS, // asks before the defaults are loaded, since that cannot be undone // left-right navigation menu PAGE_MAIN, @@ -90,7 +92,7 @@ typedef enum { typedef enum { DISP_ACTION_STORE = 0, - DISP_ACTION_BIND, + DISP_ACTION_DEFAULTS, DISP_ACTION_BOOT, DISP_ACTION_FLASH_ESP, } DISP_ACTION_ENUM; @@ -98,7 +100,7 @@ typedef enum { const uint8_t disp_actions[] = { DISP_ACTION_STORE, - DISP_ACTION_BIND, + DISP_ACTION_DEFAULTS, #if !(defined ESP8266 || defined ESP32) // ESP cannot be put into boot DISP_ACTION_BOOT, #endif @@ -141,6 +143,7 @@ class tTxDisp void draw_page_tx(void); void draw_page_rx(void); void draw_page_actions(void); + void draw_page_confirm_defaults(void); void draw_page_main_sub0(void); void draw_page_main_sub1(void); @@ -164,6 +167,7 @@ class tTxDisp uint8_t page; uint16_t page_startup_tmo; + bool confirm_yes; // selection on the confirm page, starts on NO bool page_modified; // requires complete redraw of page bool page_update; // only update some elements of page @@ -218,6 +222,7 @@ void tTxDisp::Init(void) page = PAGE_STARTUP; // start with startup page page_startup_tmo = DISP_START_PAGE_TMO_MS; + confirm_yes = false; page_modified = true; page_update = false; @@ -329,6 +334,33 @@ uint16_t keys, i, keys_new; return; } + // defaults are being loaded and stored, the controller restart takes it from here + if (page == PAGE_NOTIFY_DEFAULTS) { + return; + } + + // ask before the defaults are loaded, NO is preselected + if (page == PAGE_CONFIRM_DEFAULTS) { + leds.SetWarning(true); // blinking amber, to underline that this cannot be undone + if (key_has_been_pressed(KEY_LEFT) || key_has_been_pressed(KEY_UP)) { + if (confirm_yes) { confirm_yes = false; page_modified = true; } + } else + if (key_has_been_pressed(KEY_RIGHT) || key_has_been_pressed(KEY_DOWN)) { + if (!confirm_yes) { confirm_yes = true; page_modified = true; } + } else + if (key_has_been_pressed(KEY_CENTER)) { + leds.SetWarning(false); + if (confirm_yes) { + page = PAGE_NOTIFY_DEFAULTS; + tasks.SetDisplayTask(TX_TASK_PARAM_DEFAULTS); + } else { + page = PAGE_ACTIONS; // idx_focused is left untouched, so the cursor stays on DEFAULT + } + page_modified = true; + } + return; + } + // handle connection & receiver if (connected_last != connected()) { // connection state has changed page_modified = true; // redraws, and avoids calling gdisp_update() multiple time @@ -458,8 +490,11 @@ void tTxDisp::run_action(void) page_modified = true; tasks.SetDisplayTask(TX_TASK_PARAM_STORE); break; - case DISP_ACTION_BIND: - tasks.SetDisplayTask(MAIN_TASK_BIND_START); + case DISP_ACTION_DEFAULTS: + // loads, stores and restarts, so ask first + page = PAGE_CONFIRM_DEFAULTS; + confirm_yes = false; // NO preselected + page_modified = true; break; case DISP_ACTION_BOOT: tasks.SetDisplayTask(MAIN_TASK_SYSTEM_BOOT); @@ -523,6 +558,8 @@ void tTxDisp::Draw(void) case PAGE_ACTIONS: draw_page_actions(); break; case PAGE_NOTIFY_BIND: draw_page_notify("BINDING"); break; case PAGE_NOTIFY_STORE: draw_page_notify("STORE"); break; + case PAGE_NOTIFY_DEFAULTS: draw_page_notify("DEFAULT"); break; + case PAGE_CONFIRM_DEFAULTS: draw_page_confirm_defaults(); break; } //uint32_t t2 = micros16(); //HAL_GetTick(); @@ -994,7 +1031,7 @@ void tTxDisp::draw_page_actions(void) gdisp_setcurXY(5, idx * 16 + DISP_CONTENT_Y_BASE + 5); if (idx == idx_focused) gdisp_setinverted(); - gdisp_puts("BIND"); + gdisp_puts("DEFAULT"); // 7 chars * 11 px + x offset 5 = 82 px, so it fits gdisp_unsetinverted(); idx++; @@ -1018,6 +1055,33 @@ void tTxDisp::draw_page_actions(void) } +void tTxDisp::draw_page_confirm_defaults(void) +{ + if (!page_modified) return; + + draw_header("Defaults"); + + // default font is 6 px wide, so up to 21 chars fit on a 128 px line + gdisp_setcurY(DISP_CONTENT_Y_BASE + 2); gdisp_puts_XCentered("Load defaults and"); + gdisp_setcurY(DISP_CONTENT_Y_BASE + 12); gdisp_puts_XCentered("restart? Settings"); + gdisp_setcurY(DISP_CONTENT_Y_BASE + 22); gdisp_puts_XCentered("+ bind phrase lost!"); + + gdisp_setfont(&FreeMono9pt7b); + + gdisp_setcurXY(25, DISP_CONTENT_Y_BASE + 40); + if (!confirm_yes) gdisp_setinverted(); + gdisp_puts("NO"); + gdisp_unsetinverted(); + + gdisp_setcurXY(70, DISP_CONTENT_Y_BASE + 40); + if (confirm_yes) gdisp_setinverted(); + gdisp_puts("YES"); + gdisp_unsetinverted(); + + gdisp_unsetfont(); +} + + //------------------------------------------------------- // Edit Parameter //------------------------------------------------------- diff --git a/mLRS/CommonTx/mbridge_interface.h b/mLRS/CommonTx/mbridge_interface.h index a5942e107..8e2cbb2e0 100644 --- a/mLRS/CommonTx/mbridge_interface.h +++ b/mLRS/CommonTx/mbridge_interface.h @@ -574,7 +574,7 @@ tMBridgeLinkStats lstats = {}; lstats.vehicle_state = mavlink_vehicle_state(); // 3 = invalid lstats.link_state_connected = connected(); - lstats.link_state_binding = bind.IsInBind(); + // lstats.link_state_binding = bind.IsInBind(); mbridge.SendCommand(MBRIDGE_CMD_TX_LINK_STATS, (uint8_t*)&lstats); } @@ -608,7 +608,7 @@ tMBridgeInfo info = {}; } info.has_status = 1; // to indicate it has these flags - info.binding = (bind.IsInBind()) ? 1 : 0; + // info.binding = (bind.IsInBind()) ? 1 : 0; info._connected = (connected()) ? 1 : 0; info._rx_LQ_low = 0; info._tx_LQ_low = 0; diff --git a/mLRS/CommonTx/mlrs-tx.cpp b/mLRS/CommonTx/mlrs-tx.cpp index d429b9fd4..c6a980279 100644 --- a/mLRS/CommonTx/mlrs-tx.cpp +++ b/mLRS/CommonTx/mlrs-tx.cpp @@ -13,6 +13,21 @@ #define DEBUG_ENABLED #define FAIL_ENABLED +/* LAS identity handshake — sent once by Python over UART at connect time. + * Wire format: [LORA_MAGIC_LEN bytes magic][sys_id][show_group] + */ +#define LORA_MAGIC ".LAS!LoRa:Identity:Handshake:v1!" +#define LORA_MAGIC_LEN 32U +#define LORA_HANDSHAKE_ACK ((uint16_t)0xACAC) /* 2-byte ACK */ + +typedef enum +{ + HS_IDLE, /*!< no match in progress, bytes route directly to payload */ + HS_MATCHING, /*!< partial magic match — accumulating position hs_pos */ + HS_SYS_ID, /*!< full magic matched, next byte is sys_id */ + HS_SHOW_GROUP, /*!< sys_id received, next byte is show_group */ +} tHsState; + // we set the priorities here to have an overview, SysTick is at 15, I2C is at 15, USB is at 0 #define UART_IRQ_PRIORITY 10 // jrpin5 bridge, this needs to be high, when lower than DIO1, the module could stop sending via the bridge @@ -217,7 +232,7 @@ void tWhileTransmit::handle_once(void) disp.UpdateMain(); } - if (bind.IsInBind()) disp.SetBind(); + // if (bind.IsInBind()) disp.SetBind(); // postpone to next cycle if just updated and it's a short time slot bool allow_draw = (dtmax_us() > 2000) || (main_tlast_ms != tnow_ms); @@ -274,8 +289,8 @@ void init_hw(void) buzzer.Init(); fan.Init(); - dbg.Init(); - + + setup_init(); esp_enable(Setup.Tx[Config.ConfigId].SerialDestination); @@ -285,8 +300,6 @@ void init_hw(void) mbridge.Init(Config.UseMbridge, Config.UseCrsf); // these affect peripherals, hence do here crsf.Init(Config.UseCrsf); - in.Init(Config.UseIn); - __enable_irq(); } @@ -304,15 +317,15 @@ void SX_DIO_EXTI_IRQHandler(void) sx_dio_exti_isr_clearflag(); irq_status = sx.GetAndClearIrqStatus(SX_IRQ_ALL); if (irq_status & SX_IRQ_RX_DONE) { - if (bind.IsInBind()) { - uint64_t bind_signature; - sx.ReadBuffer(0, (uint8_t*)&bind_signature, 8); - if (bind_signature != bind.RxSignature) irq_status = 0; // not binding frame, so ignore it - } else { - uint16_t sync_word; - sx.ReadBuffer(0, (uint8_t*)&sync_word, 2); // rxStartBufferPointer is always 0, so no need for sx.GetRxBufferStatus() - if (sync_word != Config.FrameSyncWord) irq_status = 0; // not for us, so ignore it - } + //if (bind.IsInBind()) { + // uint64_t bind_signature; + // sx.ReadBuffer(0, (uint8_t*)&bind_signature, 8); + // if (bind_signature != bind.RxSignature) irq_status = 0; // not binding frame, so ignore it + //} else { + uint16_t sync_word; + sx.ReadBuffer(0, (uint8_t*)&sync_word, 2); // rxStartBufferPointer is always 0, so no need for sx.GetRxBufferStatus() + if (sync_word != Config.FrameSyncWord) irq_status = 0; // not for us, so ignore it + //} } }) #ifdef USE_SX2 @@ -437,16 +450,16 @@ void pack_txcmdframe(tTxFrame* const frame, tFrameStats* const frame_stats, tRcD { switch (link_task) { case LINK_TASK_TX_GET_RX_SETUPDATA: - pack_txcmdframe_cmd(frame, frame_stats, rc, FRAME_CMD_GET_RX_SETUPDATA); + //pack_txcmdframe_cmd(frame, frame_stats, rc, FRAME_CMD_GET_RX_SETUPDATA); break; case LINK_TASK_TX_GET_RX_SETUPDATA_WRELOAD: - pack_txcmdframe_cmd(frame, frame_stats, rc, FRAME_CMD_GET_RX_SETUPDATA_WRELOAD); + //pack_txcmdframe_cmd(frame, frame_stats, rc, FRAME_CMD_GET_RX_SETUPDATA_WRELOAD); break; case LINK_TASK_TX_SET_RX_PARAMS: - pack_txcmdframe_setrxparams(frame, frame_stats, rc); + //pack_txcmdframe_setrxparams(frame, frame_stats, rc); break; case LINK_TASK_TX_STORE_RX_PARAMS: - pack_txcmdframe_cmd(frame, frame_stats, rc, FRAME_CMD_STORE_RX_PARAMS); + //pack_txcmdframe_cmd(frame, frame_stats, rc, FRAME_CMD_STORE_RX_PARAMS); transmit_frame_type = TRANSMIT_FRAME_TYPE_NORMAL; break; } @@ -466,21 +479,113 @@ void pack_txcmdframe(tTxFrame* const frame, tFrameStats* const frame_stats, tRcD void prepare_transmit_frame(uint8_t antenna, uint8_t fhss1_curr_i, uint8_t fhss2_curr_i) { -uint8_t payload[FRAME_TX_PAYLOAD_LEN]; -uint8_t payload_len = 0; + uint8_t payload[FRAME_TX_PAYLOAD_LEN]; + uint8_t payload_len = 0; - if (transmit_frame_type == TRANSMIT_FRAME_TYPE_NORMAL) { - // read data from serial port - if (connected()) { - for (uint8_t i = 0; i < FRAME_TX_PAYLOAD_LEN; i++) { - if (!sx_serial.available()) break; - uint8_t c = sx_serial.getc(); - payload[payload_len++] = c; - } + if (transmit_frame_type == TRANSMIT_FRAME_TYPE_NORMAL) + { + static tHsState hs_state = HS_IDLE; + static uint8_t hs_pos = 0U; + static uint8_t hs_sys_id = 0U; - stats.bytes_transmitted.Add(payload_len); - stats.serial_data_transmitted.Inc(); - } else { + uint16_t to_read = sx_serial.bytes_available(); + + if (to_read > FRAME_TX_PAYLOAD_LEN) + { + to_read = FRAME_TX_PAYLOAD_LEN; + } + + for (uint16_t i = 0U; i < to_read; i++) + { + uint8_t byte = (uint8_t)sx_serial.getc(); + + /* handhshake FSM */ + switch (hs_state) + { + case HS_IDLE: + if (byte == (uint8_t)LORA_MAGIC[0]) + { + hs_pos = 1U; + hs_state = HS_MATCHING; + } + else if (connected() && payload_len < FRAME_TX_PAYLOAD_LEN) + { + payload[payload_len++] = byte; + } + break; + + case HS_MATCHING: + if (byte == (uint8_t)LORA_MAGIC[hs_pos]) + { + /* transition straight to HS_SYS_ID*/ + if (++hs_pos == LORA_MAGIC_LEN) + { + hs_state = HS_SYS_ID; + } + } + else + { + /* mismatch: forward the matched magic prefix directly to payload */ + for (uint8_t j = 0U; j < hs_pos; j++) + { + if (connected() && payload_len < FRAME_TX_PAYLOAD_LEN) + { + payload[payload_len++] = (uint8_t)LORA_MAGIC[j]; + } + } + /* re-evaluate current byte — may itself start a new match */ + if (byte == (uint8_t)LORA_MAGIC[0]) + { + hs_pos = 1U; + hs_state = HS_MATCHING; + } + else + { + if (connected() && payload_len < FRAME_TX_PAYLOAD_LEN) + { + payload[payload_len++] = byte; + } + + /* back to IDLE */ + hs_pos = 0U; + hs_state = HS_IDLE; + } + } + break; + + case HS_SYS_ID: + hs_sys_id = byte; + hs_state = HS_SHOW_GROUP; + break; + + case HS_SHOW_GROUP: + stats.sys_id = hs_sys_id; + stats.show_group = byte; + stats.broadcast = (stats.sys_id == 0x00 && stats.show_group == 0xFF) ? 1U : 0U; + + /* two-byte ACK */ + serial.putc((uint8_t)(LORA_HANDSHAKE_ACK >> 8)); /* MSB */ + serial.putc((uint8_t)(LORA_HANDSHAKE_ACK & 0xFF)); /* LSB */ + + /* back to IDLE */ + hs_pos = 0U; + hs_state = HS_IDLE; + break; + } + } + + if (connected()) + { + if (payload_len > 0U) + { + stats.bytes_transmitted.Add(payload_len); + stats.serial_data_transmitted.Inc(); + } + } + else + { + hs_state = HS_IDLE; + hs_pos = 0U; sx_serial.flush(); } } @@ -489,19 +594,16 @@ uint8_t payload_len = 0; tFrameStats frame_stats; frame_stats.seq_no = stats.transmit_seq_no; - frame_stats.ack = rarq.AckSeqNo(); - frame_stats.antenna = stats.last_antenna; - frame_stats.transmit_antenna = antenna; - frame_stats.rssi = stats.GetLastRssi(); - + frame_stats.broadcast = stats.broadcast; + frame_stats.sys_id = stats.sys_id; + frame_stats.show_group = stats.show_group; // Note: the receiver wants to see both bands, also single band receivers. // It is then important however that fhss1_curr_i and fhss2_curr_i are identical, as otherwise // the receiver would jump to wrong frequencies uint8_t fhss_band = fhss_band_next(); // this randomly toggles between 0 and 1, but never has more than two symbols in a row frame_stats.tx_fhss_index_band = fhss_band; frame_stats.tx_fhss_index = ((fhss_band & 0x01) == 0) ? fhss1_curr_i : fhss2_curr_i; - - frame_stats.LQ_serial = stats.GetLQ_serial(); + //TODO: This setup is always preparing the packet, even if it is 0 length (check if it is ok) if (transmit_frame_type == TRANSMIT_FRAME_TYPE_NORMAL) { pack_txframe(&txFrame, &frame_stats, &rcData, payload, payload_len); @@ -515,12 +617,6 @@ void process_received_frame(bool do_payload, tRxFrame* const frame) { bool accept_payload = rarq.AcceptPayload(); - stats.received_antenna = frame->status.antenna; - stats.received_transmit_antenna = frame->status.transmit_antenna; - stats.received_rssi = rssi_i8_from_u7(frame->status.rssi_u7); - stats.received_LQ_rc = frame->status.LQ_rc; - stats.received_LQ_serial = frame->status.LQ_serial; - if (!do_payload) { return; } @@ -529,7 +625,7 @@ void process_received_frame(bool do_payload, tRxFrame* const frame) // handle cmd frame if (frame->status.frame_type == FRAME_TYPE_TX_RX_CMD) { - process_received_rxcmdframe(frame); + //process_received_rxcmdframe(frame); return; } @@ -556,10 +652,10 @@ tRxFrame* frame; frame = &rxFrame2; } - if (bind.IsInBind()) { - bind.handle_receive(antenna, rx_status); - return; - } + //if (bind.IsInBind()) { + // bind.handle_receive(antenna, rx_status); + // return; + //} if (rx_status < RX_STATUS_INVALID) { // must not happen FAIL_WSTATE(BLINK_4, "rx_status failure", 0,0, link_rx1_status, link_rx2_status); @@ -604,11 +700,6 @@ void handle_receive_none(void) // RX_STATUS_NONE void do_transmit_prepare(uint8_t antenna, uint8_t fhss1_curr_i, uint8_t fhss2_curr_i) // we prepare a TX frame to be send to receiver { - if (bind.IsInBind()) { - bind.do_transmit(antenna); - return; - } - stats.transmit_seq_no++; prepare_transmit_frame(antenna, fhss1_curr_i, fhss2_curr_i); @@ -617,11 +708,6 @@ void do_transmit_prepare(uint8_t antenna, uint8_t fhss1_curr_i, uint8_t fhss2_cu void do_transmit_send(uint8_t antenna) // we send a TX frame to receiver { - if (bind.IsInBind()) { - sxSendFrame(antenna, &txBindFrame, FRAME_TX_RX_LEN, SEND_FRAME_TMO_MS); - return; - } - sxSendFrame(antenna, &txFrame, FRAME_TX_RX_LEN, SEND_FRAME_TMO_MS); // 10 ms tmo } @@ -631,9 +717,9 @@ uint8_t do_receive(uint8_t antenna) // we receive a RX frame from receiver uint8_t res; uint8_t rx_status = RX_STATUS_INVALID; // this also signals that a frame was received - if (bind.IsInBind()) { - return bind.do_receive(antenna, false); - } + //if (bind.IsInBind()) { + // return bind.do_receive(antenna, false); + //} // we don't need to read sx.GetRxBufferStatus(), but hey // we could save 2 byte's time by not reading sync_word again, but hey @@ -712,6 +798,10 @@ RESTARTCONTROLLER serial.SetBaudRate(Config.SerialBaudrate); serial2.SetBaudRate(Config.SerialBaudrate); + stats.broadcast = 1; + stats.sys_id = 0x00; + stats.show_group = 0xFF; + // startup sign of life leds.Init(); @@ -721,7 +811,6 @@ RESTARTCONTROLLER irq_status = irq2_status = 0; IF_SX(sx.StartUp(&Config.Sx)); IF_SX2(sx2.StartUp(&Config.Sx2)); - bind.Init(); fhss.Init(&Config.Fhss, &Config.Fhss2); fhss.Start(); rfpower.Init(); @@ -734,14 +823,15 @@ RESTARTCONTROLLER doPreTransmit = false; pretransmit_tstamp_us = 0; link_state = LINK_STATE_IDLE; - connect_state = CONNECT_STATE_LISTEN; + connect_state = CONNECT_STATE_CONNECTED; //CONNECT_STATE_LISTEN; connect_tmo_cnt = 0; connect_sync_cnt = 0; - connect_occured_once = false; + connect_occured_once = true; link_rx1_status = link_rx2_status = RX_STATUS_NONE; link_tx_status = TX_STATUS_NONE; link_task_init(); - link_task_set(LINK_TASK_TX_GET_RX_SETUPDATA); // we start with wanting to get rx setup data + //link_task_set(LINK_TASK_TX_GET_RX_SETUPDATA); // we do not want to receive setup data at all + SetupMetaData.rx_available = true; stats.Init(Config.LQAveragingPeriod, Config.frame_rate_hz, Config.frame_rate_ms); rdiversity.Init(); @@ -765,6 +855,7 @@ RESTARTCONTROLLER #else hc04.Init(&comport, &serial, Config.SerialBaudrate); #endif + fan.SetMode(Setup.Tx[Config.ConfigId].FanMode); fan.SetPower(sx.RfPower_dbm()); whileTransmit.Init(); disp.Init(); @@ -806,76 +897,50 @@ INITCONTROLLER_END DECc(tick_1hz, SYSTICK_DELAY_MS(1000)); - if (!tick_1hz) { - if (Setup.Tx[Config.ConfigId].Buzzer == BUZZER_RX_LQ && connect_occured_once) { - buzzer.BeepLQ(stats.GetReceivedLQ_rc()); - } - } - - bind.Tick_ms(); disp.Tick_ms(); // can take long + fan.SetMode(Setup.Tx[Config.ConfigId].FanMode); // picked up here, so a change is effective immediately fan.SetPower(sx.RfPower_dbm()); fan.Tick_ms(); esp.Tick_ms(); - - if (!tick_1hz) { - dbg.puts("."); -/* dbg.puts("\nTX: "); - dbg.puts(u8toBCD_s(stats.GetLQ_serial())); - dbg.puts("("); - dbg.puts(u8toBCD_s(stats.frames_received.GetLQ())); dbg.putc(','); - dbg.puts(u8toBCD_s(stats.valid_frames_received.GetLQ())); - dbg.puts("),"); - dbg.puts(u8toBCD_s(stats.received_LQ_rc)); dbg.puts(", "); - - dbg.puts(s8toBCD_s(stats.last_rssi1)); dbg.putc(','); - dbg.puts(s8toBCD_s(stats.received_rssi)); dbg.puts(", "); - dbg.puts(s8toBCD_s(stats.last_snr1)); dbg.puts("; "); - - dbg.puts(u16toBCD_s(stats.bytes_transmitted.GetBytesPerSec())); dbg.puts(", "); - dbg.puts(u16toBCD_s(stats.bytes_received.GetBytesPerSec())); dbg.puts("; "); */ - } } // end of if (!doPreTransmit) } //-- SX handling switch (link_state) { - case LINK_STATE_IDLE: - break; - - case LINK_STATE_TRANSMIT: - fhss.HopToNext(); - do_transmit_prepare(tdiversity.Antenna(), fhss.GetCurrI(), fhss.GetCurrI2()); - link_state = LINK_STATE_TRANSMIT_SEND; - DBG_MAIN_SLIM(dbg.puts("\nt");) - break; - - case LINK_STATE_TRANSMIT_SEND: { - uint16_t dt = micros16() - pretransmit_tstamp_us; - if (dt < 750) break; - isInTimeGuard = false; - rfpower.Update(); - sx.SetRfFrequency(fhss.GetCurrFreq()); - sx2.SetRfFrequency(fhss.GetCurrFreq2()); - do_transmit_send(tdiversity.Antenna()); - link_state = LINK_STATE_TRANSMIT_WAIT; - link_tx_status = TX_STATUS_NONE; - irq_status = irq2_status = 0; - DBG_MAIN_SLIM(dbg.puts(">");) - // auxiliaries - crsf.TelemetryStart(); - whileTransmit.Trigger(); - break; } - - case LINK_STATE_RECEIVE: - IF_ANTENNA1(sx.SetToRx()); - IF_ANTENNA2(sx2.SetToRx()); - link_state = LINK_STATE_RECEIVE_WAIT; - link_rx1_status = link_rx2_status = RX_STATUS_NONE; - irq_status = irq2_status = 0; - DBG_MAIN_SLIM(dbg.puts("r");) - break; + case LINK_STATE_IDLE: + break; + + case LINK_STATE_TRANSMIT: + fhss.HopToNext(); + do_transmit_prepare(tdiversity.Antenna(), fhss.GetCurrI(), fhss.GetCurrI2()); + link_state = LINK_STATE_TRANSMIT_SEND; + //DBG_MAIN_SLIM(dbg.puts("\nt");) + break; + + case LINK_STATE_TRANSMIT_SEND: { + uint16_t dt = micros16() - pretransmit_tstamp_us; + if (dt < 750) break; + isInTimeGuard = false; + rfpower.Update(); + sx.SetRfFrequency(fhss.GetCurrFreq()); + sx2.SetRfFrequency(fhss.GetCurrFreq2()); + do_transmit_send(tdiversity.Antenna()); + link_state = LINK_STATE_TRANSMIT_WAIT; + link_tx_status = TX_STATUS_NONE; + irq_status = irq2_status = 0; + // auxiliaries + crsf.TelemetryStart(); + whileTransmit.Trigger(); + break; } + + case LINK_STATE_RECEIVE: + IF_ANTENNA1(sx.SetToRx()); + IF_ANTENNA2(sx2.SetToRx()); + link_state = LINK_STATE_RECEIVE_WAIT; + link_rx1_status = link_rx2_status = RX_STATUS_NONE; + irq_status = irq2_status = 0; + break; }//end of switch(link_state) IF_SX( @@ -885,14 +950,13 @@ IF_SX( irq_status = 0; link_tx_status |= TX_STATUS_TX1_DONE; if (!Config.IsDualBand || (link_tx_status & TX_STATUS_TX2_DONE)) { link_state = LINK_STATE_RECEIVE; } - DBG_MAIN_SLIM(dbg.puts("1!");) + //DBG_MAIN_SLIM(dbg.puts("1!");) } } else if (link_state == LINK_STATE_RECEIVE_WAIT) { if (irq_status & SX_IRQ_RX_DONE) { irq_status = 0; link_rx1_status = do_receive(ANTENNA_1); - DBG_MAIN_SLIM(dbg.puts("1<");) } } @@ -908,7 +972,6 @@ IF_SX( irq_status = 0; link_state = LINK_STATE_IDLE; link_rx1_status = link_rx2_status = RX_STATUS_NONE; - DBG_MAIN_SLIM(dbg.puts("1?");) } }//end of if(irq_status) ); @@ -919,14 +982,13 @@ IF_SX2( irq2_status = 0; link_tx_status |= TX_STATUS_TX2_DONE; if (!Config.IsDualBand || (link_tx_status & TX_STATUS_TX1_DONE)) { link_state = LINK_STATE_RECEIVE; } - DBG_MAIN_SLIM(dbg.puts("2!");) + //DBG_MAIN_SLIM(dbg.puts("2!");) } } else if (link_state == LINK_STATE_RECEIVE_WAIT) { if (irq2_status & SX2_IRQ_RX_DONE) { irq2_status = 0; link_rx2_status = do_receive(ANTENNA_2); - DBG_MAIN_SLIM(dbg.puts("2<");) } } @@ -942,7 +1004,6 @@ IF_SX2( irq2_status = 0; link_state = LINK_STATE_IDLE; link_rx1_status = link_rx2_status = RX_STATUS_NONE; - DBG_MAIN_SLIM(dbg.puts("2?");) } }//end of if(irq2_status) ); @@ -1013,11 +1074,11 @@ IF_SX2( connect_sync_cnt_max = Config.connect_sync_cnt_max; } if (connect_sync_cnt >= connect_sync_cnt_max) { - if (!SetupMetaData.rx_available && !bind.IsInBind()) { - // should not happen, but does very occasionally happen, so let's cope with it - // We must have gotten it at least once, on first connect, since we need it. - // Later on we can accept to be gentle and be ok with not getting it again. - // Bottom line: the receiver must not change after first connection. + if (!SetupMetaData.rx_available) { + // should not have happen, but does very occasionally happen, so let's cope with + // we must have gotten it at least once, on first connect, since we need it + // later on we can accept to be gentle and be ok with not getting it again + // bottom line: the receiver must not change after first connection if (connect_occured_once) { link_task_reset(); SetupMetaData.rx_available = true; @@ -1037,29 +1098,16 @@ IF_SX2( connect_tmo_cnt = CONNECT_TMO_SYSTICKS; } - // we are connected but tmo ran out - if (connected() && !connect_tmo_cnt) { - // so disconnect - connect_state = CONNECT_STATE_LISTEN; - // link_state will be set to LINK_STATE_TRANSMIT below - } - - // we are connected but didn't receive a valid frame - if (connected() && !valid_frame_received) { - // reset sync counter, relevant if in sync - //connect_sync_cnt = 0; //isn't needed, right? since when connected we can't be in sync - } - link_state = LINK_STATE_TRANSMIT; link_rx1_status = RX_STATUS_NONE; link_rx2_status = RX_STATUS_NONE; if (!connected()) rarq.Disconnected(); - if (connect_state == CONNECT_STATE_LISTEN) { - link_task_reset(); // to ensure that the following set is enforced - link_task_set(LINK_TASK_TX_GET_RX_SETUPDATA); - } + //if (connect_state == CONNECT_STATE_LISTEN) { + // link_task_reset(); // to ensure that the following set is enforced + // link_task_set(LINK_TASK_TX_GET_RX_SETUPDATA); + //} DECc(tick_1hz_commensurate, Config.frame_rate_hz); if (!tick_1hz_commensurate) { @@ -1068,31 +1116,12 @@ IF_SX2( stats.Next(); if (!connected()) stats.Clear(); - if (Setup.Tx[Config.ConfigId].Buzzer == BUZZER_LOST_PACKETS && connect_occured_once && !bind.IsInBind()) { - if (!valid_frame_received) buzzer.BeepLP(); - } - - // store parameters + // store parameters if (doParamsStore) { leds.SetToParamStore(); setup_store_to_EEPROM(); GOTO_RESTARTCONTROLLER; } - - bind.Do(); - switch (bind.Task()) { - case BIND_TASK_CHANGED_TO_BIND: - bind.ConfigForBind(); - fhss.SetToBind(); - leds.SetToBind(); - connect_state = CONNECT_STATE_LISTEN; - // link_state was set to LINK_STATE_TRANSMIT already - break; - case BIND_TASK_TX_RESTART_CONTROLLER: GOTO_RESTARTCONTROLLER; break; - } - -//dbg.puts((valid_frame_received) ? "\nvalid" : "\ninval"); - return; // link state might have changed, process immediately }//end of if(doPreTransmit) @@ -1128,30 +1157,19 @@ IF_MBRIDGE_OR_CRSF( // to allow CRSF mBridge emulation switch (mbcmd) { case MBRIDGE_CMD_REQUEST_INFO: setup_reload(); - if (connected()) { - link_task_set(LINK_TASK_TX_GET_RX_SETUPDATA_WRELOAD); - mbridge.Lock(MBRIDGE_CMD_REQUEST_INFO); // lock mBridge - } else { - mbridge.HandleCmd(MBRIDGE_CMD_REQUEST_INFO); - } + // answer right away, no LINK_TASK_TX_GET_RX_SETUPDATA_WRELOAD, see the note at the tx_task + // switch below. Waiting for the Rx setup data would wedge link_task and keep mBridge locked. + mbridge.HandleCmd(MBRIDGE_CMD_REQUEST_INFO); break; case MBRIDGE_CMD_PARAM_REQUEST_LIST: mbridge.HandleCmd(MBRIDGE_CMD_PARAM_REQUEST_LIST); break; case MBRIDGE_CMD_REQUEST_CMD: mbridge.HandleRequestCmd(mbridge.GetPayloadPtr()); break; case MBRIDGE_CMD_PARAM_SET: { bool rx_param_changed; - bool param_changed = mbridge_do_ParamSet(mbridge.GetPayloadPtr(), &rx_param_changed); - if (param_changed && rx_param_changed && connected()) { - link_task_set(LINK_TASK_TX_SET_RX_PARAMS); // set parameter on Rx side - mbridge.Lock(MBRIDGE_CMD_PARAM_SET); // lock mBridge - } + mbridge_do_ParamSet(mbridge.GetPayloadPtr(), &rx_param_changed); + // no LINK_TASK_TX_SET_RX_PARAMS, see the note at the tx_task switch below }break; case MBRIDGE_CMD_PARAM_STORE: - if (connected()) { - link_task_set(LINK_TASK_TX_STORE_RX_PARAMS); - mbridge.Lock(MBRIDGE_CMD_PARAM_STORE); // lock mBridge - } else { - doParamsStore = true; - } + doParamsStore = true; // store locally, we cannot wait for an Rx confirmation break; case MBRIDGE_CMD_BIND_START: tasks.SetMBridgeTask(MAIN_TASK_BIND_START); break; case MBRIDGE_CMD_BIND_STOP: tasks.SetMBridgeTask(MAIN_TASK_BIND_STOP); break; @@ -1235,29 +1253,37 @@ IF_IN( if (tx_task == MAIN_TASK_NONE) tx_task = mavlink.Task(); switch (tx_task) { + // Note on the Rx link tasks: we broadcast, the receivers never talk back, and pack_txcmdframe() has all + // its cmd frames commented out. LINK_TASK_TX_SET_RX_PARAMS and LINK_TASK_TX_GET_RX_SETUPDATA* are only + // cleared in process_received_rxcmdframe(), i.e. by a reply we can never get, and connect_state is + // hardwired to CONNECT_STATE_CONNECTED. Entering one wedges link_task forever, which pins + // transmit_frame_type to CMD so no normal frame goes out any more, and makes every later + // link_task_set() fail, e.g. the store below would then never happen. So we do not enter them at all. case TX_TASK_RX_PARAM_SET: - if (connected()) { - link_task_set(LINK_TASK_TX_SET_RX_PARAMS); - mbridge.Lock(); // lock mBridge - } + // nothing to do, there is no receiver we could hand the parameter to break; case TX_TASK_PARAM_STORE: - if (connected()) { - link_task_set(LINK_TASK_TX_STORE_RX_PARAMS); - mbridge.Lock(); // lock mBridge - } else { - doParamsStore = true; - } + doParamsStore = true; // store locally, instead of via the Rx round trip break; case TX_TASK_PARAM_RELOAD: setup_reload(); - if (connected()) { - link_task_set(LINK_TASK_TX_GET_RX_SETUPDATA_WRELOAD); - mbridge.Lock(); // lock mBridge - } break; - case MAIN_TASK_BIND_START: bind.StartBind(); break; - case MAIN_TASK_BIND_STOP: bind.StopBind(); break; + case TX_TASK_PARAM_DEFAULTS: + // load the defaults, store them, and restart. The restart re-runs setup_init(), and hence also + // setup_configure_config(), so we never run with Setup and Config out of sync. + // setup_default() covers Common[ConfigId], Tx[ConfigId] and Rx, note that Rx is not per config id. + // The bind phrase is defaulted along on purpose, this is meant to be a full reset. Setting it is a + // manual step here, to be done once the receivers are on the wanted phrase. So do not "fix" this by + // preserving the old phrase, the user is warned on the confirm page instead. + // We also do not push the defaulted Rx params via LINK_TASK_TX_SET_RX_PARAMS: we broadcast and the + // receivers never talk back, and that link task is only cleared by an Rx reply, so it would pin + // transmit_frame_type to CMD and normal frames would stop + setup_default(Config.ConfigId); + setup_sanitize_config(Config.ConfigId); // so we do not store what the hardware cannot do + doParamsStore = true; // stores to EEPROM and restarts the controller + break; + case MAIN_TASK_BIND_START: /*bind.StartBind();*/ break; + case MAIN_TASK_BIND_STOP: /*bind.StopBind();*/ break; case MAIN_TASK_SYSTEM_BOOT: enter_system_bootloader(); break; case TX_TASK_CLI_CHANGE_CONFIG_ID: config_id.Change(tasks.GetCliTaskValue()); break; case TX_TASK_FLASH_ESP: esp.EnterFlash(); break; @@ -1274,7 +1300,6 @@ IF_IN( //-- Handle ESP wifi bridge - esp.Do(); //-- more diff --git a/mLRS/CommonTx/sx_serial_interface_tx.h b/mLRS/CommonTx/sx_serial_interface_tx.h index 439a3ee7e..4265b77f5 100644 --- a/mLRS/CommonTx/sx_serial_interface_tx.h +++ b/mLRS/CommonTx/sx_serial_interface_tx.h @@ -20,6 +20,7 @@ class tTxSxSerial : public tSerialBase void Init(tSerialBase* const _serialport, tSerialBase* const _mbridge, tSerialBase* const _serial2port); bool available(void) override; + uint16_t bytes_available(void) override; char getc(void) override; void putbuf(uint8_t* const buf, uint16_t len) override; void flush(void) override; @@ -54,26 +55,35 @@ bool tTxSxSerial::available(void) { if (!connected_and_rx_setup_available()) return 0; - if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { - return mavlink.available(); // get from serial via MAVLink parser - } - if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { - return msp.available(); // get from serial via MSP parser - } +// if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { +// return mavlink.available(); // get from serial via MAVLink parser +// } +// if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { +// return msp.available(); // get from serial via MSP parser +// } return ser->available(); // get from serial } +uint16_t tTxSxSerial::bytes_available(void) +{ + if (!connected_and_rx_setup_available()) + { + return 0U; + } + + return ser ? ser->bytes_available() : 0U; +} char tTxSxSerial::getc(void) { if (!connected_and_rx_setup_available()) return 0; // not needed as done already by available() - if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { - return mavlink.getc(); // get from serial via MAVLink parser - } - if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { - return msp.getc(); // get from serial via MSP parser - } +// if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { +// return mavlink.getc(); // get from serial via MAVLink parser +// } +// if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { +// return msp.getc(); // get from serial via MSP parser +// } return ser->getc(); // get from serial } @@ -82,14 +92,14 @@ void tTxSxSerial::putbuf(uint8_t* const buf, uint16_t len) { if (!connected_and_rx_setup_available()) return; - if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { // this has to go via the parser - for (uint16_t i = 0; i < len; i++) mavlink.putc(buf[i]); - return; - } - if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { // this has to go via the parser - for (uint16_t i = 0; i < len; i++) msp.putc(buf[i]); - return; - } +// if (SERIAL_LINK_MODE_IS_MAVLINK(Setup.Rx.SerialLinkMode)) { // this has to go via the parser +// for (uint16_t i = 0; i < len; i++) mavlink.putc(buf[i]); +// return; +// } +// if (SERIAL_LINK_MODE_IS_MSP(Setup.Rx.SerialLinkMode)) { // this has to go via the parser +// for (uint16_t i = 0; i < len; i++) msp.putc(buf[i]); +// return; +// } ser->putbuf(buf, len); } diff --git a/mLRS/modules/dronecan/DSDL b/mLRS/modules/dronecan/DSDL index b4653c7ab..30d02e17c 160000 --- a/mLRS/modules/dronecan/DSDL +++ b/mLRS/modules/dronecan/DSDL @@ -1 +1 @@ -Subproject commit b4653c7abc3c47cb31b16efa24ea755232774756 +Subproject commit 30d02e17c52920b4f4c5a93857c1bb9b5fa3f325 diff --git a/mLRS/modules/dronecan/dronecan_dsdlc b/mLRS/modules/dronecan/dronecan_dsdlc index de47a8972..d71b61083 160000 --- a/mLRS/modules/dronecan/dronecan_dsdlc +++ b/mLRS/modules/dronecan/dronecan_dsdlc @@ -1 +1 @@ -Subproject commit de47a8972b7d8c59e50c3acfab5754db29798caa +Subproject commit d71b61083d5c8844a8bf97b7fd2e47803e1b6958 diff --git a/mLRS/modules/fastmavlink b/mLRS/modules/fastmavlink index 72343be71..cfcc83af9 160000 --- a/mLRS/modules/fastmavlink +++ b/mLRS/modules/fastmavlink @@ -1 +1 @@ -Subproject commit 72343be7178c5585d5ad23d6f79c433f7c0ffd4c +Subproject commit cfcc83af91ca2bf84accf7e7f02c0ba26f75bc6f diff --git a/mLRS/modules/mavlink b/mLRS/modules/mavlink index 1ba67b3c9..b4add5292 160000 --- a/mLRS/modules/mavlink +++ b/mLRS/modules/mavlink @@ -1 +1 @@ -Subproject commit 1ba67b3c9c46f56a644e6f4e8a4c359172ed14bc +Subproject commit b4add5292992cc43bd471b431b425338787982be diff --git a/mLRS/modules/stm32ll-lib b/mLRS/modules/stm32ll-lib index bac5b477a..185a7ee18 160000 --- a/mLRS/modules/stm32ll-lib +++ b/mLRS/modules/stm32ll-lib @@ -1 +1 @@ -Subproject commit bac5b477a18a16d8530f8ac8b98720bd0d0b8ea1 +Subproject commit 185a7ee186da696527dd260c7c860926d7943772 diff --git a/mLRS/modules/sx12xx-lib b/mLRS/modules/sx12xx-lib index b28b4e128..807c16041 160000 --- a/mLRS/modules/sx12xx-lib +++ b/mLRS/modules/sx12xx-lib @@ -1 +1 @@ -Subproject commit b28b4e1287f0c22cb1c25b199611c8eb22055cf8 +Subproject commit 807c160411d04ef6dd50565386d1972adb800ef5 diff --git a/mLRS/rx-diy-e28dual-board02-f103cb/.cproject b/mLRS/rx-diy-e28dual-board02-f103cb/.cproject index 2132dd673..e83740fdc 100644 --- a/mLRS/rx-diy-e28dual-board02-f103cb/.cproject +++ b/mLRS/rx-diy-e28dual-board02-f103cb/.cproject @@ -99,30 +99,31 @@ - - + + - + - + + + + + + + + + + + + + + + + + @@ -206,5 +336,12 @@ - + + + + + + + + \ No newline at end of file diff --git a/mLRS/tx-diy-e28dual-board02-f103cb/.cproject b/mLRS/tx-diy-e28dual-board02-f103cb/.cproject index fe453ef91..761ada6e5 100644 --- a/mLRS/tx-diy-e28dual-board02-f103cb/.cproject +++ b/mLRS/tx-diy-e28dual-board02-f103cb/.cproject @@ -117,12 +117,12 @@ - - -