From 778e1f6dd30553aba0ae336ffed1bc84ed1d7298 Mon Sep 17 00:00:00 2001 From: wvarty Date: Sun, 21 Aug 2022 12:16:29 +1000 Subject: [PATCH] Add support for custom OSD message, and ESP32 TX backpack target --- lib/MSP/msp.h | 6 +- lib/MSP/msptypes.h | 1 + platformio.ini | 3 +- src/Tx_main.cpp | 44 ++++++++++++-- src/Vrx_main.cpp | 10 +++- src/fusion.cpp | 2 +- src/fusion.h | 3 +- src/hdzero.cpp | 2 +- src/hdzero.h | 3 +- src/module_base.cpp | 27 +++++++++ src/module_base.h | 16 ++++++ src/rapidfire.cpp | 2 +- src/rapidfire.h | 3 +- src/rx5808.cpp | 2 + src/rx5808.h | 3 +- src/skyzone_msp.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++ src/skyzone_msp.h | 37 ++++++++++++ src/steadyview.cpp | 2 + src/steadyview.h | 3 +- targets/common.ini | 20 +++++-- targets/debug.ini | 12 ++++ targets/skyzone.ini | 15 +++++ 22 files changed, 327 insertions(+), 25 deletions(-) create mode 100644 src/module_base.cpp create mode 100644 src/module_base.h create mode 100644 src/skyzone_msp.cpp create mode 100644 src/skyzone_msp.h create mode 100644 targets/skyzone.ini diff --git a/lib/MSP/msp.h b/lib/MSP/msp.h index db51b06..e465041 100644 --- a/lib/MSP/msp.h +++ b/lib/MSP/msp.h @@ -4,9 +4,9 @@ // TODO: MSP_PORT_INBUF_SIZE should be changed to // dynamically allocate array length based on the payload size -// Hardcoding payload size to 8 bytes for now, since MSP is -// limited to a 4 byte payload on the BF side -#define MSP_PORT_INBUF_SIZE 8 +// Hardcoding payload size to 64 bytes for now, to allow enough space +// for custom OSD text. +#define MSP_PORT_INBUF_SIZE 64 #define CHECK_PACKET_PARSING() \ if (packet->readError) {\ diff --git a/lib/MSP/msptypes.h b/lib/MSP/msptypes.h index 5a59156..aae18c1 100644 --- a/lib/MSP/msptypes.h +++ b/lib/MSP/msptypes.h @@ -16,6 +16,7 @@ #define MSP_ELRS_REQU_VTX_PKT 0x0B #define MSP_ELRS_SET_TX_BACKPACK_WIFI_MODE 0x0C #define MSP_ELRS_SET_VRX_BACKPACK_WIFI_MODE 0x0D +#define MSP_ELRS_SET_OSD 0x00B6 // CRSF encapsulated msp defines #define ENCAPSULATED_MSP_PAYLOAD_SIZE 4 diff --git a/platformio.ini b/platformio.ini index 7eb278b..c721e99 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,4 +17,5 @@ extra_configs = targets/betafpv_tx.ini targets/dupletx_tx.ini targets/radiomaster_tx.ini - targets/hdzero.ini \ No newline at end of file + targets/hdzero.ini + targets/skyzone.ini \ No newline at end of file diff --git a/src/Tx_main.cpp b/src/Tx_main.cpp index 9f69b0d..9d7c265 100644 --- a/src/Tx_main.cpp +++ b/src/Tx_main.cpp @@ -1,6 +1,13 @@ #include -#include -#include + +#if defined(PLATFORM_ESP8266) + #include + #include +#elif defined(PLATFORM_ESP32) + #include + #include + #include +#endif #include "msp.h" #include "msptypes.h" @@ -52,6 +59,13 @@ void sendMSPViaEspnow(mspPacket_t *packet); ///////////////////////////////////// +#if defined(PLATFORM_ESP32) +// This seems to need to be global, as per this page, +// otherwise we get errors about invalid peer: +// https://rntlab.com/question/espnow-peer-interface-is-invalid/ +esp_now_peer_info_t peerInfo; +#endif + void RebootIntoWifi() { DBGLN("Rebooting into wifi update mode..."); @@ -74,7 +88,11 @@ void ProcessMSPPacketFromPeer(mspPacket_t *packet) } // espnow on-receive callback +#if defined(PLATFORM_ESP8266) void OnDataRecv(uint8_t * mac_addr, uint8_t *data, uint8_t data_len) +#elif defined(PLATFORM_ESP32) +void OnDataRecv(const uint8_t * mac_addr, const uint8_t *data, int data_len) +#endif { DBGLN("ESP NOW DATA:"); for(int i = 0; i < data_len; i++) @@ -198,7 +216,11 @@ void SetSoftMACAddress() WiFi.disconnect(); // Soft-set the MAC address to the passphrase UID for binding - wifi_set_macaddr(STATION_IF, broadcastAddress); + #if defined(PLATFORM_ESP8266) + wifi_set_macaddr(STATION_IF, broadcastAddress); + #elif defined(PLATFORM_ESP32) + esp_wifi_set_mac(WIFI_IF_STA, broadcastAddress); + #endif } #if defined(PLATFORM_ESP8266) @@ -257,8 +279,20 @@ void setup() rebootTime = millis(); } - esp_now_set_self_role(ESP_NOW_ROLE_COMBO); - esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0); + #if defined(PLATFORM_ESP8266) + esp_now_set_self_role(ESP_NOW_ROLE_COMBO); + esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0); + #elif defined(PLATFORM_ESP32) + memcpy(peerInfo.peer_addr, broadcastAddress, 6); + peerInfo.channel = 0; + peerInfo.encrypt = false; + if (esp_now_add_peer(&peerInfo) != ESP_OK) + { + DBGLN("ESP-NOW failed to add peer"); + return; + } + #endif + esp_now_register_recv_cb(OnDataRecv); } diff --git a/src/Vrx_main.cpp b/src/Vrx_main.cpp index 3e3e43d..ab80286 100644 --- a/src/Vrx_main.cpp +++ b/src/Vrx_main.cpp @@ -32,6 +32,8 @@ #include "fusion.h" #elif defined(HDZERO_BACKPACK) #include "hdzero.h" +#elif defined(SKYZONE_MSP_BACKPACK) + #include "skyzone_msp.h" #endif /////////// DEFINES /////////// @@ -98,6 +100,8 @@ VrxBackpackConfig config; Fusion vrxModule; #elif defined(HDZERO_BACKPACK) HDZero vrxModule(&Serial); +#elif defined(SKYZONE_MSP_BACKPACK) + SkyzoneMSP vrxModule(&Serial); #endif /////////// FUNCTION DEFS /////////// @@ -202,7 +206,6 @@ void ProcessMSPPacket(mspPacket_t *packet) break; case MSP_ELRS_BACKPACK_SET_RECORDING_STATE: DBGLN("Processing MSP_ELRS_BACKPACK_SET_RECORDING_STATE..."); - #if defined(HDZERO_BACKPACK) { uint8_t state = packet->readByte(); uint8_t lowByte = packet->readByte(); @@ -210,7 +213,9 @@ void ProcessMSPPacket(mspPacket_t *packet) uint16_t delay = lowByte | highByte << 8; vrxModule.SetRecordingState(state, delay); } - #endif + break; + case MSP_ELRS_SET_OSD: + vrxModule.SetOSD(packet); break; default: DBGLN("Unknown command from ESPNOW"); @@ -405,6 +410,7 @@ void loop() uint32_t now = millis(); devicesUpdate(now); + vrxModule.Loop(now); #if defined(PLATFORM_ESP8266) || defined(PLATFORM_ESP32) // If the reboot time is set and the current time is past the reboot time then reboot. diff --git a/src/fusion.cpp b/src/fusion.cpp index cc3d251..48f8a78 100644 --- a/src/fusion.cpp +++ b/src/fusion.cpp @@ -9,7 +9,7 @@ GENERIC_CRC8 crsf_crc(CRSF_CRC_POLY); void Fusion::Init() { - delay(VRX_BOOT_DELAY); + ModuleBase::Init(); DBGLN("Fusion backpack init complete"); } diff --git a/src/fusion.h b/src/fusion.h index 1ab9927..4d6aebd 100644 --- a/src/fusion.h +++ b/src/fusion.h @@ -1,5 +1,6 @@ #pragma once +#include "module_base.h" #include #define VRX_BOOT_DELAY 1000 @@ -14,7 +15,7 @@ const uint16_t frequencyTable[48] = { 5333, 5373, 5413, 5453, 5493, 5533, 5573, 5613 // L }; -class Fusion +class Fusion : public ModuleBase { public: void Init(); diff --git a/src/hdzero.cpp b/src/hdzero.cpp index 44510db..d18a70b 100644 --- a/src/hdzero.cpp +++ b/src/hdzero.cpp @@ -10,7 +10,7 @@ HDZero::HDZero(Stream *port) void HDZero::Init() { - delay(VRX_BOOT_DELAY); + ModuleBase::Init(); } void diff --git a/src/hdzero.h b/src/hdzero.h index 2fc8a8b..e8d7075 100644 --- a/src/hdzero.h +++ b/src/hdzero.h @@ -2,6 +2,7 @@ #include "msp.h" #include "msptypes.h" +#include "module_base.h" #include #define VRX_BOOT_DELAY 7000 @@ -13,7 +14,7 @@ #define VRX_DVR_RECORDING_INACTIVE 0 #define VRX_DVR_RECORDING_UNKNOWN 255 -class HDZero +class HDZero : public ModuleBase { public: HDZero(Stream *port); diff --git a/src/module_base.cpp b/src/module_base.cpp new file mode 100644 index 0000000..38d6fcc --- /dev/null +++ b/src/module_base.cpp @@ -0,0 +1,27 @@ +#include "module_base.h" + +void +ModuleBase::Init() +{ + delay(VRX_BOOT_DELAY); +} + +void +ModuleBase::SendIndexCmd(uint8_t index) +{ +} + +void +ModuleBase::SetRecordingState(uint8_t recordingState, uint16_t delay) +{ +} + +void +ModuleBase::SetOSD(mspPacket_t *packet) +{ +} + +void +ModuleBase::Loop(uint32_t now) +{ +} \ No newline at end of file diff --git a/src/module_base.h b/src/module_base.h new file mode 100644 index 0000000..9886fb2 --- /dev/null +++ b/src/module_base.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "msp.h" + +#define VRX_BOOT_DELAY 0 + +class ModuleBase +{ +public: + void Init(); + void SendIndexCmd(uint8_t index); + void SetRecordingState(uint8_t recordingState, uint16_t delay); + void SetOSD(mspPacket_t *packet); + void Loop(uint32_t now); +}; \ No newline at end of file diff --git a/src/rapidfire.cpp b/src/rapidfire.cpp index f95c7af..d36fbd3 100644 --- a/src/rapidfire.cpp +++ b/src/rapidfire.cpp @@ -5,7 +5,7 @@ void Rapidfire::Init() { - delay(VRX_BOOT_DELAY); + ModuleBase::Init(); EnableSPIMode(); // https://github.com/ExpressLRS/ExpressLRS/pull/1489 & https://github.com/ExpressLRS/Backpack/pull/65 diff --git a/src/rapidfire.h b/src/rapidfire.h index 40c9079..b70b3ca 100644 --- a/src/rapidfire.h +++ b/src/rapidfire.h @@ -1,5 +1,6 @@ #pragma once +#include "module_base.h" #include #define VRX_BOOT_DELAY 2000 @@ -13,7 +14,7 @@ #define RF_API_CHANNEL_CMD 0x43 // 'C' #define RF_API_BAND_CMD 0x42 // 'B' -class Rapidfire +class Rapidfire : public ModuleBase { public: void Init(); diff --git a/src/rx5808.cpp b/src/rx5808.cpp index 19fed0d..00f4d40 100644 --- a/src/rx5808.cpp +++ b/src/rx5808.cpp @@ -5,6 +5,8 @@ void RX5808::Init() { + ModuleBase::Init(); + pinMode(PIN_MOSI, INPUT); pinMode(PIN_CLK, INPUT); pinMode(PIN_CS, INPUT); diff --git a/src/rx5808.h b/src/rx5808.h index 3946d66..6fd0cda 100644 --- a/src/rx5808.h +++ b/src/rx5808.h @@ -1,5 +1,6 @@ #pragma once +#include "module_base.h" #include #define BIT_BANG_FREQ 10000 @@ -32,7 +33,7 @@ const uint16_t frequencyTable[48] = { 5333, 5373, 5413, 5453, 5493, 5533, 5573, 5613 // L }; -class RX5808 +class RX5808 : public ModuleBase { public: void Init(); diff --git a/src/skyzone_msp.cpp b/src/skyzone_msp.cpp new file mode 100644 index 0000000..c666592 --- /dev/null +++ b/src/skyzone_msp.cpp @@ -0,0 +1,136 @@ +#include "skyzone_msp.h" +#include "logging.h" +#include + +SkyzoneMSP::SkyzoneMSP(Stream *port) +{ + m_port = port; +} + +void +SkyzoneMSP::Init() +{ + ModuleBase::Init(); + m_delay = 0; +} + +void +SkyzoneMSP::SendIndexCmd(uint8_t index) +{ + uint8_t retries = 3; + while (GetChannelIndex() != index && retries > 0) + { + SetChannelIndex(index); + retries--; + } +} + +uint8_t +SkyzoneMSP::GetChannelIndex() +{ + MSP msp; + mspPacket_t* packet = new mspPacket_t; + packet->reset(); + packet->makeCommand(); + packet->function = MSP_ELRS_BACKPACK_GET_CHANNEL_INDEX; + + // Send request, then wait for a response back from the VRX + bool receivedResponse = msp.awaitPacket(packet, m_port, VRX_RESPONSE_TIMEOUT); + + if (receivedResponse) + { + packet = msp.getReceivedPacket(); + return packet->readByte(); + } + + DBGLN("Skyzone module: Exceeded timeout while waiting for channel index response"); + return CHANNEL_INDEX_UNKNOWN; +} + +void +SkyzoneMSP::SetChannelIndex(uint8_t index) +{ + MSP msp; + mspPacket_t packet; + packet.reset(); + packet.makeCommand(); + packet.function = MSP_ELRS_BACKPACK_SET_CHANNEL_INDEX; + packet.addByte(index); // payload + + msp.sendPacket(&packet, m_port); +} + +uint8_t +SkyzoneMSP::GetRecordingState() +{ + MSP msp; + mspPacket_t* packet = new mspPacket_t; + packet->reset(); + packet->makeCommand(); + packet->function = MSP_ELRS_BACKPACK_GET_RECORDING_STATE; + + // Send request, then wait for a response back from the VRX + bool receivedResponse = msp.awaitPacket(packet, m_port, VRX_RESPONSE_TIMEOUT); + + if (receivedResponse) + { + packet = msp.getReceivedPacket(); + return packet->readByte() ? VRX_DVR_RECORDING_ACTIVE : VRX_DVR_RECORDING_INACTIVE; + } + + DBGLN("Skyzone module: Exceeded timeout while waiting for recording state response"); + return VRX_DVR_RECORDING_UNKNOWN; +} + +void +SkyzoneMSP::SetRecordingState(uint8_t recordingState, uint16_t delay) +{ + DBGLN("SetRecordingState = %d delay = %d", recordingState, delay); + + m_recordingState = recordingState; + m_delay = delay * 1000; // delay is in seconds, convert to milliseconds + m_delayStartMillis = millis(); + + if (m_delay == 0) + { + SendRecordingState(); + } +} + +void +SkyzoneMSP::SendRecordingState() +{ + DBGLN("SendRecordingState = %d delay = %d", m_recordingState, m_delay); + + MSP msp; + mspPacket_t packet; + packet.reset(); + packet.makeCommand(); + packet.function = MSP_ELRS_BACKPACK_SET_RECORDING_STATE; + packet.addByte(m_recordingState); + packet.addByte(m_delay & 0xFF); // delay byte 1 + packet.addByte(m_delay >> 8); // delay byte 2 + + msp.sendPacket(&packet, m_port); +} + +void +SkyzoneMSP::SetOSD(mspPacket_t *packet) +{ + MSP msp; + msp.sendPacket(packet, m_port); +} + +void +SkyzoneMSP::Loop(uint32_t now) +{ + // Handle delay timer for SendRecordingState() + if (m_delay != 0) + { + if (now - m_delayStartMillis >= m_delay) + { + SendRecordingState(); + m_delay = 0; + } + } +} diff --git a/src/skyzone_msp.h b/src/skyzone_msp.h new file mode 100644 index 0000000..cb29f4d --- /dev/null +++ b/src/skyzone_msp.h @@ -0,0 +1,37 @@ +#pragma once + +#include "msp.h" +#include "msptypes.h" +#include "module_base.h" +#include + +#define VRX_BOOT_DELAY 2000 +#define VRX_RESPONSE_TIMEOUT 500 +#define VRX_UART_BAUD 115200 // skyzone uses 115k baud between the ESP32-PICO and their MCU + +#define CHANNEL_INDEX_UNKNOWN 255 +#define VRX_DVR_RECORDING_ACTIVE 1 +#define VRX_DVR_RECORDING_INACTIVE 0 +#define VRX_DVR_RECORDING_UNKNOWN 255 + +class SkyzoneMSP : public ModuleBase +{ +public: + SkyzoneMSP(Stream *port); + void Init(); + void SendIndexCmd(uint8_t index); + uint8_t GetChannelIndex(); + void SetChannelIndex(uint8_t index); + uint8_t GetRecordingState(); + void SetRecordingState(uint8_t recordingState, uint16_t delay); + void SetOSD(mspPacket_t *packet); + void Loop(uint32_t now); + +private: + void SendRecordingState(); + + Stream *m_port; + uint8_t m_recordingState; + uint16_t m_delay; + uint32_t m_delayStartMillis; +}; diff --git a/src/steadyview.cpp b/src/steadyview.cpp index 5849deb..eaf9cde 100644 --- a/src/steadyview.cpp +++ b/src/steadyview.cpp @@ -5,6 +5,8 @@ void SteadyView::Init() { + ModuleBase::Init(); + pinMode(PIN_MOSI, OUTPUT); pinMode(PIN_CLK, OUTPUT); pinMode(PIN_CS, OUTPUT); diff --git a/src/steadyview.h b/src/steadyview.h index 088df4c..39cf934 100644 --- a/src/steadyview.h +++ b/src/steadyview.h @@ -1,5 +1,6 @@ #pragma once +#include "module_base.h" #include #define BIT_BANG_FREQ 10000 @@ -37,7 +38,7 @@ typedef enum { ModeDiversity } videoMode_t; -class SteadyView +class SteadyView : public ModuleBase { public: void Init(); diff --git a/targets/common.ini b/targets/common.ini index c86d36a..72a302b 100644 --- a/targets/common.ini +++ b/targets/common.ini @@ -50,7 +50,7 @@ build_flags = build_flags = ${common_env_data.build_flags} -D TARGET_TX_BACKPACK -build_src_filter = ${common_env_data.build_src_filter} - - - - - - +build_src_filter = ${common_env_data.build_src_filter} - - - - - - - # ------------------------- COMMON RAPIDFIRE-BACKPACK DEFINITIONS ----------------- [rapidfire_vrx_backpack_common] @@ -58,7 +58,7 @@ build_flags = ${common_env_data.build_flags} -D TARGET_VRX_BACKPACK -D RAPIDFIRE_BACKPACK -build_src_filter = ${common_env_data.build_src_filter} - - - - - +build_src_filter = ${common_env_data.build_src_filter} - - - - - - # ------------------------- COMMON RX5808-BACKPACK DEFINITIONS ----------------- [rx5808_vrx_backpack_common] @@ -66,7 +66,7 @@ build_flags = ${common_env_data.build_flags} -D TARGET_VRX_BACKPACK -D RX5808_BACKPACK -build_src_filter = ${common_env_data.build_src_filter} - - - - - +build_src_filter = ${common_env_data.build_src_filter} - - - - - - # ------------------------- COMMON STEADYVIEW-BACKPACK DEFINITIONS ----------------- [steadyview_vrx_backpack_common] @@ -74,7 +74,7 @@ build_flags = ${common_env_data.build_flags} -D TARGET_VRX_BACKPACK -D STEADYVIEW_BACKPACK -build_src_filter = ${common_env_data.build_src_filter} - - - - - +build_src_filter = ${common_env_data.build_src_filter} - - - - - - # ------------------------- COMMON FUSION-BACKPACK DEFINITIONS ----------------- [fusion_vrx_backpack_common] @@ -82,7 +82,7 @@ build_flags = ${common_env_data.build_flags} -D TARGET_VRX_BACKPACK -D FUSION_BACKPACK -build_src_filter = ${common_env_data.build_src_filter} - - - - - +build_src_filter = ${common_env_data.build_src_filter} - - - - - - # ------------------------- COMMON HDZERO-BACKPACK DEFINITIONS ----------------- [hdzero_vrx_backpack_common] @@ -90,4 +90,12 @@ build_flags = ${common_env_data.build_flags} -D TARGET_VRX_BACKPACK -D HDZERO_BACKPACK -build_src_filter = ${common_env_data.build_src_filter} - - - - - - +build_src_filter = ${common_env_data.build_src_filter} - - - - - - - + +# ------------------------- COMMON SKYZONE-MSP-BACKPACK DEFINITIONS ----------------- +[skyzone_msp_vrx_backpack_common] +build_flags = + ${common_env_data.build_flags} + -D TARGET_VRX_BACKPACK + -D SKYZONE_MSP_BACKPACK +build_src_filter = ${common_env_data.build_src_filter} - - - - - - - \ No newline at end of file diff --git a/targets/debug.ini b/targets/debug.ini index b646ffa..55b8a17 100644 --- a/targets/debug.ini +++ b/targets/debug.ini @@ -35,3 +35,15 @@ build_flags = [env:DEBUG_TX_Backpack_via_WIFI] extends = env:DEBUG_TX_Backpack_via_UART + +[env:DEBUG_ESP32_TX_Backpack_via_UART] +extends = env_common_esp32, tx_backpack_common +build_flags = + ${env_common_esp32.build_flags} + ${tx_backpack_common.build_flags} + -D PIN_BUTTON=0 + -D PIN_LED=4 +lib_ignore = STM32UPDATE + +[env:DEBUG_ESP32_TX_Backpack_via_WIFI] +extends = env:DEBUG_ESP32_TX_Backpack_via_UART diff --git a/targets/skyzone.ini b/targets/skyzone.ini new file mode 100644 index 0000000..5a78479 --- /dev/null +++ b/targets/skyzone.ini @@ -0,0 +1,15 @@ +# ******************************** +# VRX backpack targets +# ******************************** + +[env:Skyzone_Onboard_ESP32_Backpack_via_UART] +extends = env_common_esp32, skyzone_msp_vrx_backpack_common +monitor_speed = 115200 +build_flags = + ${env_common_esp32.build_flags} + ${skyzone_msp_vrx_backpack_common.build_flags} + -D PIN_LED=4 +lib_ignore = STM32UPDATE + +[env:Skyzone_Onboard_ESP32_Backpack_via_WIFI] +extends = env:Skyzone_Onboard_ESP32_Backpack_via_UART