Skip to content

Commit cb5c9c8

Browse files
Make MAVLink WiFi mode also emit ESPNOW CRSF GPS frames (which should be enough to make antenna trackers work)
1 parent 409435c commit cb5c9c8

File tree

9 files changed

+163
-66
lines changed

9 files changed

+163
-66
lines changed

include/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ typedef enum
1111

1212
extern connectionState_e connectionState;
1313
extern unsigned long bindingStart;
14+
static const uint8_t bindingAddress[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

lib/CRSF/CRSF.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "CRSF.h"
2+
#include <crc.h>
3+
4+
GENERIC_CRC8 crsf_crc(CRSF_CRC_POLY);
5+
6+
void CRSF::SetHeaderAndCrc(uint8_t *frame, crsf_frame_type_e frameType, uint8_t frameSize, crsf_addr_e destAddr)
7+
{
8+
auto *header = (crsf_header_t *)frame;
9+
header->sync_byte = destAddr;
10+
header->frame_size = frameSize;
11+
header->type = frameType;
12+
13+
uint8_t crc = crsf_crc.calc(&frame[CRSF_FRAME_NOT_COUNTED_BYTES], frameSize - 1, 0);
14+
frame[frameSize + CRSF_FRAME_NOT_COUNTED_BYTES - 1] = crc;
15+
}

lib/CRSF/CRSF.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <stdint.h>
2+
#include "crsf_protocol.h"
3+
4+
class CRSF {
5+
public:
6+
static void SetHeaderAndCrc(uint8_t *frame, crsf_frame_type_e frameType, uint8_t frameSize, crsf_addr_e destAddr);
7+
};
8+

lib/CrsfProtocol/crsf_protocol.h

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22

33
#define CRSF_CRC_POLY 0xd5
44
#define CRSF_SYNC_BYTE 0xc8
5-
6-
#define CRSF_FRAMETYPE_GPS 0x02
7-
#define CRSF_FRAMETYPE_LINK_STATISTICS 0x14
8-
#define CRSF_FRAMETYPE_BATTERY_SENSOR 0x08
5+
#define CRSF_FRAME_NOT_COUNTED_BYTES 2
96

107
#define PACKED __attribute__((packed))
118

@@ -19,6 +16,57 @@ typedef struct crsf_header_s
1916
uint8_t type; // from crsf_frame_type_e
2017
} PACKED crsf_header_t;
2118

19+
typedef enum : uint8_t
20+
{
21+
CRSF_FRAMETYPE_GPS = 0x02,
22+
CRSF_FRAMETYPE_VARIO = 0x07,
23+
CRSF_FRAMETYPE_BATTERY_SENSOR = 0x08,
24+
CRSF_FRAMETYPE_BARO_ALTITUDE = 0x09,
25+
CRSF_FRAMETYPE_LINK_STATISTICS = 0x14,
26+
CRSF_FRAMETYPE_OPENTX_SYNC = 0x10,
27+
CRSF_FRAMETYPE_RADIO_ID = 0x3A,
28+
CRSF_FRAMETYPE_RC_CHANNELS_PACKED = 0x16,
29+
CRSF_FRAMETYPE_ATTITUDE = 0x1E,
30+
CRSF_FRAMETYPE_FLIGHT_MODE = 0x21,
31+
// Extended Header Frames, range: 0x28 to 0x96
32+
CRSF_FRAMETYPE_DEVICE_PING = 0x28,
33+
CRSF_FRAMETYPE_DEVICE_INFO = 0x29,
34+
CRSF_FRAMETYPE_PARAMETER_SETTINGS_ENTRY = 0x2B,
35+
CRSF_FRAMETYPE_PARAMETER_READ = 0x2C,
36+
CRSF_FRAMETYPE_PARAMETER_WRITE = 0x2D,
37+
38+
//CRSF_FRAMETYPE_ELRS_STATUS = 0x2E, ELRS good/bad packet count and status flags
39+
40+
CRSF_FRAMETYPE_COMMAND = 0x32,
41+
// KISS frames
42+
CRSF_FRAMETYPE_KISS_REQ = 0x78,
43+
CRSF_FRAMETYPE_KISS_RESP = 0x79,
44+
// MSP commands
45+
CRSF_FRAMETYPE_MSP_REQ = 0x7A, // response request using msp sequence as command
46+
CRSF_FRAMETYPE_MSP_RESP = 0x7B, // reply with 58 byte chunked binary
47+
CRSF_FRAMETYPE_MSP_WRITE = 0x7C, // write with 8 byte chunked binary (OpenTX outbound telemetry buffer limit)
48+
// Ardupilot frames
49+
CRSF_FRAMETYPE_ARDUPILOT_RESP = 0x80,
50+
} crsf_frame_type_e;
51+
52+
typedef enum : uint8_t
53+
{
54+
CRSF_ADDRESS_BROADCAST = 0x00,
55+
CRSF_ADDRESS_USB = 0x10,
56+
CRSF_ADDRESS_TBS_CORE_PNP_PRO = 0x80,
57+
CRSF_ADDRESS_RESERVED1 = 0x8A,
58+
CRSF_ADDRESS_CURRENT_SENSOR = 0xC0,
59+
CRSF_ADDRESS_GPS = 0xC2,
60+
CRSF_ADDRESS_TBS_BLACKBOX = 0xC4,
61+
CRSF_ADDRESS_FLIGHT_CONTROLLER = 0xC8,
62+
CRSF_ADDRESS_RESERVED2 = 0xCA,
63+
CRSF_ADDRESS_RACE_TAG = 0xCC,
64+
CRSF_ADDRESS_RADIO_TRANSMITTER = 0xEA,
65+
CRSF_ADDRESS_CRSF_RECEIVER = 0xEC,
66+
CRSF_ADDRESS_CRSF_TRANSMITTER = 0xEE,
67+
CRSF_ADDRESS_ELRS_LUA = 0xEF
68+
} crsf_addr_e;
69+
2270
#define CRSF_MK_FRAME_T(payload) struct payload##_frame_s { crsf_header_t h; payload p; uint8_t crc; } PACKED
2371

2472
typedef struct crsf_sensor_gps_s {

lib/ESPNOW/ESPNOW_Helpers.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "ESPNOW_Helpers.h"
2+
#include "espnow.h"
3+
#include <options.h>
4+
#include <common.h>
5+
#include "devLED.h"
6+
7+
extern MSP msp;
8+
extern connectionState_e connectionState; // from Vrx_main.cpp
9+
10+
void ESPNOW::sendMSPViaEspnow(mspPacket_t *packet)
11+
{
12+
// Do not send while in binding mode. The currently used firmwareOptions.uid may be garbage.
13+
if (connectionState == binding)
14+
return;
15+
16+
uint8_t packetSize = msp.getTotalPacketSize(packet);
17+
uint8_t nowDataOutput[packetSize];
18+
19+
uint8_t result = msp.convertToByteArray(packet, nowDataOutput);
20+
21+
if (!result)
22+
{
23+
// packet could not be converted to array, bail out
24+
return;
25+
}
26+
if (packet->function == MSP_ELRS_BIND)
27+
{
28+
esp_now_send((uint8_t*)bindingAddress, (uint8_t *) &nowDataOutput, packetSize); // Send Bind packet with the broadcast address
29+
}
30+
else
31+
{
32+
esp_now_send(firmwareOptions.uid, (uint8_t *) &nowDataOutput, packetSize);
33+
}
34+
blinkLED();
35+
}

lib/ESPNOW/ESPNOW_Helpers.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include "msp.h"
2+
#include "msptypes.h"
3+
4+
class ESPNOW {
5+
public:
6+
static void sendMSPViaEspnow(mspPacket_t *packet);
7+
};

lib/MAVLink/MAVLink.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#include <Arduino.h>
33
#include "MAVLink.h"
44
#include <config.h>
5+
#include <crsf_protocol.h>
6+
#include <msp.h>
7+
#include <msptypes.h>
8+
#include <CRSF.h>
9+
#include <ESPNOW_Helpers.h>
510

611
void
712
MAVLink::ProcessMAVLinkFromTX(uint8_t c)
@@ -40,6 +45,35 @@ MAVLink::ProcessMAVLinkFromTX(uint8_t c)
4045
mavlink_to_gcs_buf[mavlink_to_gcs_buf_count] = msg;
4146
mavlink_to_gcs_buf_count++;
4247
mavlink_stats.packets_downlink++;
48+
49+
// Look for GPS packets - convert them to CRSF
50+
if (msg.msgid == MAVLINK_MSG_ID_GPS_RAW_INT)
51+
{
52+
mavlink_gps_raw_int_t gps_int;
53+
mavlink_msg_gps_raw_int_decode(&msg, &gps_int);
54+
CRSF_MK_FRAME_T(crsf_sensor_gps_t) crsfgps = {0};
55+
56+
crsfgps.p.speed = htobe16(gps_int.vel * 36 / 100);
57+
crsfgps.p.lat = htobe32(gps_int.lat);
58+
crsfgps.p.lon = htobe32(gps_int.lon);
59+
crsfgps.p.heading = htobe16(gps_int.cog);
60+
crsfgps.p.satcnt = gps_int.satellites_visible;
61+
crsfgps.p.altitude = htobe16(gps_int.alt / 1000 + 1000);
62+
63+
CRSF::SetHeaderAndCrc((uint8_t *)&crsfgps, CRSF_FRAMETYPE_GPS, sizeof(crsf_sensor_gps_t), CRSF_ADDRESS_CRSF_TRANSMITTER);
64+
65+
// Wrap in MSP
66+
mspPacket_t packet;
67+
packet.reset();
68+
packet.makeCommand();
69+
packet.function = MSP_ELRS_BACKPACK_CRSF_TLM;
70+
for (size_t i = 0; i < sizeof(crsfgps); i++)
71+
{
72+
packet.addByte(((uint8_t *)&crsfgps)[i]);
73+
}
74+
// Send it out ESPNOW
75+
ESPNOW::sendMSPViaEspnow(&packet);
76+
}
4377
}
4478
}
4579

src/Tx_main.cpp

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "msp.h"
1313
#include "msptypes.h"
14+
#include "ESPNOW_Helpers.h"
1415
#include "logging.h"
1516
#include "config.h"
1617
#include "common.h"
@@ -28,8 +29,6 @@
2829

2930
/////////// GLOBALS ///////////
3031

31-
uint8_t bindingAddress[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
32-
3332
const uint8_t version[] = {LATEST_VERSION};
3433

3534
connectionState_e connectionState = starting;
@@ -61,11 +60,6 @@ mspPacket_t cachedHTPacket;
6160
MAVLink mavlink;
6261
#endif
6362

64-
/////////// FUNCTION DEFS ///////////
65-
66-
void sendMSPViaEspnow(mspPacket_t *packet);
67-
68-
/////////////////////////////////////
6963

7064
#if defined(PLATFORM_ESP32)
7165
// This seems to need to be global, as per this page,
@@ -200,7 +194,7 @@ void ProcessMSPPacketFromTX(mspPacket_t *packet)
200194
DBG(""); // Extra line for serial output readability
201195
config.Commit();
202196
// delay(500); // delay may not be required
203-
sendMSPViaEspnow(packet);
197+
ESPNOW::sendMSPViaEspnow(packet);
204198
// delay(500); // delay may not be required
205199
rebootTime = millis(); // restart to set SetSoftMACAddress
206200
}
@@ -212,11 +206,11 @@ void ProcessMSPPacketFromTX(mspPacket_t *packet)
212206
cachedVTXPacket = *packet;
213207
cacheFull = true;
214208
// transparently forward MSP packets via espnow to any subscribers
215-
sendMSPViaEspnow(packet);
209+
ESPNOW::sendMSPViaEspnow(packet);
216210
break;
217211
case MSP_ELRS_SET_VRX_BACKPACK_WIFI_MODE:
218212
DBGLN("Processing MSP_ELRS_SET_VRX_BACKPACK_WIFI_MODE...");
219-
sendMSPViaEspnow(packet);
213+
ESPNOW::sendMSPViaEspnow(packet);
220214
break;
221215
case MSP_ELRS_SET_TX_BACKPACK_WIFI_MODE:
222216
DBGLN("Processing MSP_ELRS_SET_TX_BACKPACK_WIFI_MODE...");
@@ -230,13 +224,13 @@ void ProcessMSPPacketFromTX(mspPacket_t *packet)
230224
DBGLN("Processing MSP_ELRS_BACKPACK_SET_HEAD_TRACKING...");
231225
cachedHTPacket = *packet;
232226
cacheFull = true;
233-
sendMSPViaEspnow(packet);
227+
ESPNOW::sendMSPViaEspnow(packet);
234228
break;
235229
case MSP_ELRS_BACKPACK_CRSF_TLM:
236230
DBGLN("Processing MSP_ELRS_BACKPACK_CRSF_TLM...");
237231
if (config.GetTelemMode() != BACKPACK_TELEM_MODE_OFF)
238232
{
239-
sendMSPViaEspnow(packet);
233+
ESPNOW::sendMSPViaEspnow(packet);
240234
}
241235
break;
242236
case MSP_ELRS_BACKPACK_CONFIG:
@@ -245,36 +239,11 @@ void ProcessMSPPacketFromTX(mspPacket_t *packet)
245239
break;
246240
default:
247241
// transparently forward MSP packets via espnow to any subscribers
248-
sendMSPViaEspnow(packet);
242+
ESPNOW::sendMSPViaEspnow(packet);
249243
break;
250244
}
251245
}
252246

253-
void sendMSPViaEspnow(mspPacket_t *packet)
254-
{
255-
uint8_t packetSize = msp.getTotalPacketSize(packet);
256-
uint8_t nowDataOutput[packetSize];
257-
258-
uint8_t result = msp.convertToByteArray(packet, nowDataOutput);
259-
260-
if (!result)
261-
{
262-
// packet could not be converted to array, bail out
263-
return;
264-
}
265-
266-
if (packet->function == MSP_ELRS_BIND)
267-
{
268-
esp_now_send(bindingAddress, (uint8_t *) &nowDataOutput, packetSize); // Send Bind packet with the broadcast address
269-
}
270-
else
271-
{
272-
esp_now_send(firmwareOptions.uid, (uint8_t *) &nowDataOutput, packetSize);
273-
}
274-
275-
blinkLED();
276-
}
277-
278247
void SendCachedMSP()
279248
{
280249
if (!cacheFull)
@@ -285,11 +254,11 @@ void SendCachedMSP()
285254

286255
if (cachedVTXPacket.type != MSP_PACKET_UNKNOWN)
287256
{
288-
sendMSPViaEspnow(&cachedVTXPacket);
257+
ESPNOW::sendMSPViaEspnow(&cachedVTXPacket);
289258
}
290259
if (cachedHTPacket.type != MSP_PACKET_UNKNOWN)
291260
{
292-
sendMSPViaEspnow(&cachedHTPacket);
261+
ESPNOW::sendMSPViaEspnow(&cachedHTPacket);
293262
}
294263
}
295264

src/Vrx_main.cpp

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "msp.h"
1414
#include "msptypes.h"
15+
#include "ESPNOW_Helpers.h"
1516
#include "logging.h"
1617
#include "helpers.h"
1718
#include "common.h"
@@ -125,7 +126,6 @@ VrxBackpackConfig config;
125126
/////////// FUNCTION DEFS ///////////
126127

127128
void ProcessMSPPacket(mspPacket_t *packet);
128-
void sendMSPViaEspnow(mspPacket_t *packet);
129129
void resetBootCounter();
130130
void SetupEspNow();
131131

@@ -340,30 +340,10 @@ void RequestVTXPacket()
340340
packet.addByte(0); // empty byte
341341

342342
blinkLED();
343-
sendMSPViaEspnow(&packet);
343+
ESPNOW::sendMSPViaEspnow(&packet);
344344
#endif
345345
}
346346

347-
void sendMSPViaEspnow(mspPacket_t *packet)
348-
{
349-
// Do not send while in binding mode. The currently used firmwareOptions.uid may be garbage.
350-
if (connectionState == binding)
351-
return;
352-
353-
uint8_t packetSize = msp.getTotalPacketSize(packet);
354-
uint8_t nowDataOutput[packetSize];
355-
356-
uint8_t result = msp.convertToByteArray(packet, nowDataOutput);
357-
358-
if (!result)
359-
{
360-
// packet could not be converted to array, bail out
361-
return;
362-
}
363-
364-
esp_now_send(firmwareOptions.uid, (uint8_t *) &nowDataOutput, packetSize);
365-
}
366-
367347
void resetBootCounter()
368348
{
369349
config.SetBootCount(0);

0 commit comments

Comments
 (0)