Skip to content

Commit e7553ce

Browse files
committed
Add Spektrum satellite serial protocol
1 parent 435f5c9 commit e7553ce

File tree

11 files changed

+239
-16
lines changed

11 files changed

+239
-16
lines changed

src/html/index.html

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,24 +205,39 @@ <h2>Serial Protocol</h2>
205205
<option value='4'>SUMD</option>
206206
<option value='5'>DJI RS Pro</option>
207207
<option value='6'>HoTT Telemetry</option>
208+
<option value='7'>Spektrum Satellite</option>
208209
</select>
209210
<label>Serial Protocol</label>
210211
</div>
211212
</div>
212-
<div id="sbus-config" style="display: none;">
213-
<h2>SBUS Failsafe</h2>
214-
Set the failsafe behaviour when using the SBUS protocol:<br/>
213+
<div id="satellite-config" style="display: none;">
214+
<h2>Satellite System</h2>
215+
Set the satellite system when using the Spektrum satellite protocol.<br/>
216+
<br/>
217+
<div class="mui-select">
218+
<select id='satellite-system' name='satellite-system'>
219+
<option value='0'>DSMX 11MS</option>
220+
<option value='1'>DSMX 22MS</option>
221+
<option value='2'>DSM2 11MS</option>
222+
<option value='3'>DSM2 22MS</option>
223+
</select>
224+
<label>Satellite System</label>
225+
</div>
226+
</div>
227+
<div id="failsafe-config" style="display: none;">
228+
<h2>Failsafe</h2>
229+
Set the failsafe behaviour when using the SBUS or Spektrum satellite protocol:<br/>
215230
<ul>
216-
<li>"No Pulses" stops sending SBUS data when a connection to the transmitter is lost</li>
231+
<li>"No Pulses" stops sending data when a connection to the transmitter is lost</li>
217232
<li>"Last Position" continues to send the last received channel data along with the FAILSAFE bit set</li>
218233
</ul>
219234
<br/>
220235
<div class="mui-select">
221-
<select id='sbus-failsafe' name='serial-failsafe'>
236+
<select id='serial-failsafe' name='serial-failsafe'>
222237
<option value='0'>No Pulses</option>
223238
<option value='1'>Last Position</option>
224239
</select>
225-
<label>SBUS Failsafe</label>
240+
<label>Failsafe</label>
226241
</div>
227242
</div>
228243

src/html/scan.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,21 @@ function updateConfig(data, options) {
272272
else if (_('serial-protocol').value == 2 || _('serial-protocol').value == 3) {
273273
_('rcvr-uart-baud').disabled = true;
274274
_('rcvr-uart-baud').value = '100000';
275-
_('sbus-config').style.display = 'block';
276-
_('sbus-failsafe').value = data['sbus-failsafe'];
275+
_('failsafe-config').style.display = 'block';
276+
_('serial-failsafe').value = data['serial-failsafe'];
277277
}
278278
else if (_('serial-protocol').value == 4) {
279279
_('rcvr-uart-baud').disabled = true;
280280
_('rcvr-uart-baud').value = '115200';
281281
}
282+
else if (_('serial-protocol').value == 7) {
283+
_('rcvr-uart-baud').disabled = true;
284+
_('rcvr-uart-baud').value = '115200';
285+
_('satellite-config').style.display = 'block';
286+
_('failsafe-config').style.display = 'block';
287+
_('satellite-system').value = data['satellite-system'];
288+
_('serial-failsafe').value = data['serial-failsafe'];
289+
}
282290
}
283291
updatePwmSettings(data.pwm);
284292
_('serial-protocol').value = data['serial-protocol'];
@@ -562,7 +570,8 @@ if (_('config') != undefined) {
562570
return JSON.stringify({
563571
"pwm": getPwmFormData(),
564572
"serial-protocol": +_('serial-protocol').value,
565-
"sbus-failsafe": +_('sbus-failsafe').value,
573+
"satellite-system": +_('satellite-system').value,
574+
"serial-failsafe": +_('serial-failsafe').value,
566575
"modelid": +_('modelid').value,
567576
"force-tlm": +_('force-tlm').checked
568577
});

src/include/common.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ enum eSerialProtocol : uint8_t
187187
PROTOCOL_INVERTED_SBUS,
188188
PROTOCOL_SUMD,
189189
PROTOCOL_DJI_RS_PRO,
190-
PROTOCOL_HOTT_TLM
190+
PROTOCOL_HOTT_TLM,
191+
PROTOCOL_SPEKTRUM_SATELLITE,
191192
};
192193

193194
enum eFailsafeMode : uint8_t
@@ -197,6 +198,14 @@ enum eFailsafeMode : uint8_t
197198
FAILSAFE_SET_POSITION
198199
};
199200

201+
enum eSatelliteSystem : uint8_t
202+
{
203+
DSMX_11MS,
204+
DSMX_22MS,
205+
DSM2_11MS,
206+
DSM2_22MS,
207+
};
208+
200209
#ifndef UNIT_TEST
201210
#if defined(RADIO_SX127X)
202211
#define RATE_MAX 6

src/lib/CONFIG/config.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,4 +1038,13 @@ void RxConfig::SetFailsafeMode(eFailsafeMode failsafeMode)
10381038
m_modified = true;
10391039
}
10401040
}
1041+
1042+
void RxConfig::SetSatelliteSystem(eSatelliteSystem satelliteSystem)
1043+
{
1044+
if (m_config.satelliteSystem != satelliteSystem)
1045+
{
1046+
m_config.satelliteSystem = satelliteSystem;
1047+
m_modified = true;
1048+
}
1049+
}
10411050
#endif

src/lib/CONFIG/config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ typedef struct {
207207
uint8_t modelId;
208208
uint8_t serialProtocol:4,
209209
failsafeMode:2,
210-
unused:2;
210+
satelliteSystem:2;
211211
rx_config_pwm_t pwmChannels[PWM_MAX_CHANNELS];
212212
} rx_config_t;
213213

@@ -236,6 +236,7 @@ class RxConfig
236236
uint8_t GetRateInitialIdx() const { return m_config.rateInitialIdx; }
237237
eSerialProtocol GetSerialProtocol() const { return (eSerialProtocol)m_config.serialProtocol; }
238238
eFailsafeMode GetFailsafeMode() const { return (eFailsafeMode)m_config.failsafeMode; }
239+
eSatelliteSystem GetSatelliteSystem() const {return (eSatelliteSystem)m_config.satelliteSystem; }
239240

240241
// Setters
241242
void SetIsBound(bool isBound);
@@ -256,6 +257,7 @@ class RxConfig
256257
void SetRateInitialIdx(uint8_t rateInitialIdx);
257258
void SetSerialProtocol(eSerialProtocol serialProtocol);
258259
void SetFailsafeMode(eFailsafeMode failsafeMode);
260+
void SetSatelliteSystem(eSatelliteSystem satelliteSystem);
259261

260262
private:
261263
void UpgradeEepromV4();

src/lib/LUA/rx_devLUA.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ static const char *rxModes = "50Hz;60Hz;100Hz;160Hz;333Hz;400Hz;10kHzDuty;On/Off
1818
static struct luaItem_selection luaSerialProtocol = {
1919
{"Protocol", CRSF_TEXT_SELECTION},
2020
0, // value
21-
"CRSF;Inverted CRSF;SBUS;Inverted SBUS;SUMD;DJI RS Pro;HoTT Telemetry",
21+
"CRSF;Inverted CRSF;SBUS;Inverted SBUS;SUMD;DJI RS Pro;HoTT Telemetry;Spektrum Satellite",
22+
STR_EMPTYSPACE
23+
};
24+
25+
static struct luaItem_selection luaSatelliteSystem = {
26+
{"Satellite System", CRSF_TEXT_SELECTION},
27+
0, // value
28+
"DSMX 11MS;DSMX 22MS;DSM2 11MS;DSM2 22MS",
2229
STR_EMPTYSPACE
2330
};
2431

@@ -312,7 +319,17 @@ static void registerLuaParameters()
312319
}
313320
});
314321

315-
if (config.GetSerialProtocol() == PROTOCOL_SBUS || config.GetSerialProtocol() == PROTOCOL_INVERTED_SBUS || config.GetSerialProtocol() == PROTOCOL_DJI_RS_PRO)
322+
if (config.GetSerialProtocol() == PROTOCOL_SPEKTRUM_SATELLITE)
323+
{
324+
registerLUAParameter(&luaSatelliteSystem, [](struct luaPropertiesCommon* item, uint8_t arg){
325+
config.SetSatelliteSystem((eSatelliteSystem)arg);
326+
});
327+
}
328+
329+
if (config.GetSerialProtocol() == PROTOCOL_SBUS ||
330+
config.GetSerialProtocol() == PROTOCOL_INVERTED_SBUS ||
331+
config.GetSerialProtocol() == PROTOCOL_DJI_RS_PRO ||
332+
config.GetSerialProtocol() == PROTOCOL_SPEKTRUM_SATELLITE)
316333
{
317334
registerLUAParameter(&luaFailsafeMode, [](struct luaPropertiesCommon* item, uint8_t arg){
318335
config.SetFailsafeMode((eFailsafeMode)arg);
@@ -376,6 +393,7 @@ static void registerLuaParameters()
376393
static int event()
377394
{
378395
setLuaTextSelectionValue(&luaSerialProtocol, config.GetSerialProtocol());
396+
setLuaTextSelectionValue(&luaSatelliteSystem, config.GetSatelliteSystem());
379397
setLuaTextSelectionValue(&luaFailsafeMode, config.GetFailsafeMode());
380398

381399
if (GPIO_PIN_ANT_CTRL != UNDEF_PIN)

src/lib/WIFI/devWIFI.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,8 @@ static void GetConfiguration(AsyncWebServerRequest *request)
326326
json["config"]["mode"] = wifiMode == WIFI_STA ? "STA" : "AP";
327327
#if defined(TARGET_RX)
328328
json["config"]["serial-protocol"] = config.GetSerialProtocol();
329-
json["config"]["sbus-failsafe"] = config.GetFailsafeMode();
329+
json["config"]["satellite-system"] = config.GetSatelliteSystem();
330+
json["config"]["serial-failsafe"] = config.GetFailsafeMode();
330331
json["config"]["modelid"] = config.GetModelId();
331332
json["config"]["force-tlm"] = config.GetForceTlmOff();
332333
#if defined(GPIO_PIN_PWM_OUTPUTS)
@@ -450,7 +451,11 @@ static void UpdateConfiguration(AsyncWebServerRequest *request, JsonVariant &jso
450451
DBGLN("Setting serial protocol %u", protocol);
451452
config.SetSerialProtocol((eSerialProtocol)protocol);
452453

453-
uint8_t failsafe = json["sbus-failsafe"] | 0;
454+
uint8_t satelliteSystem = json["satellite-system"] | 0;
455+
DBGLN("Setting satellite system %u", satelliteSystem);
456+
config.SetSatelliteSystem((eSatelliteSystem)satelliteSystem);
457+
458+
uint8_t failsafe = json["serial-failsafe"] | 0;
454459
DBGLN("Setting SBUS failsafe mode %u", failsafe);
455460
config.SetFailsafeMode((eFailsafeMode)failsafe);
456461

src/python/serve_html.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@
6464
}
6565
],
6666
"serial-protocol": 3,
67-
"sbus-failsafe": 0,
67+
"satellite-config": 0,
68+
"serial-failsafe": 0,
6869
"product_name": "Generic ESP8285 + 5xPWM 2.4Ghz RX",
6970
"lua_name": "ELRS+PWM 2400RX",
7071
"reg_domain": "ISM2G4",

src/src/rx-serial/SerialSatellite.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#include "SerialSatellite.h"
2+
#include "CRSF.h"
3+
#include "config.h"
4+
#include "device.h"
5+
6+
#if defined(TARGET_RX)
7+
8+
extern RxConfig config;
9+
10+
static constexpr uint8_t CRSF_TO_SATELLITE_CH_MAP[12] = {
11+
// clang-format off
12+
// CRSF // Satellite
13+
/*Channel 0*/ 1,
14+
/*Channel 1*/ 2,
15+
/*Channel 2*/ 0,
16+
/*Channel 3*/ 3,
17+
/*Channel 4*/ 11,
18+
/*Channel 5*/ 4,
19+
/*Channel 6*/ 5,
20+
/*Channel 7*/ 6,
21+
/*Channel 8*/ 7,
22+
/*Channel 9*/ 8,
23+
/*Channel 10*/ 9,
24+
/*Channel 11*/ 10,
25+
// clang-format on
26+
};
27+
28+
static uint16_t crsfToSatellite(uint16_t crsfValue, uint8_t satelliteChannel, eSatelliteSystem protocol)
29+
{
30+
static constexpr uint16_t SATELLITE_MIN_US = 903;
31+
static constexpr uint16_t SATELLITE_MAX_US = 2097;
32+
33+
// Map the channel data
34+
const uint16_t us = constrain(CRSF_to_US(crsfValue), SATELLITE_MIN_US, SATELLITE_MAX_US);
35+
const float divisor = (protocol == DSM2_22MS) ? 1.166f
36+
: 0.583f;
37+
38+
uint16_t channelValue = roundf((us - SATELLITE_MIN_US) / divisor);
39+
40+
// Encode the channel information
41+
channelValue |= satelliteChannel << ((protocol == DSM2_22MS) ? 10 : 11);
42+
43+
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
44+
return __builtin_bswap16(channelValue);
45+
#else
46+
return channelValue;
47+
#endif // __BYTE_ORDER__
48+
}
49+
50+
uint32_t SerialSatellite::sendRCFrame(bool frameAvailable, uint32_t *channelData)
51+
{
52+
const eSatelliteSystem satelliteSystem = config.GetSatelliteSystem();
53+
const uint32_t callbackIntervalMs =
54+
((satelliteSystem == DSMX_11MS) || (satelliteSystem == DSM2_11MS)) ? 11 : 22;
55+
56+
if ((failsafe && config.GetFailsafeMode() == FAILSAFE_NO_PULSES) || (!sendPackets && connectionState != connected))
57+
{
58+
// Fade count does not overflow
59+
if (sendPackets && (fadeCount < UINT8_MAX))
60+
{
61+
++fadeCount;
62+
}
63+
return callbackIntervalMs;
64+
}
65+
sendPackets = true;
66+
67+
uint16_t outgoingPacket[SATELLITE_CHANNEL_DATA_LENGTH];
68+
for (uint8_t ii = 0; ii < SATELLITE_CHANNEL_DATA_LENGTH; ++ii)
69+
{
70+
// These channels are sent in every packet
71+
if (ii < SATELLITE_FIRST_RR_CHANNEL)
72+
{
73+
outgoingPacket[ii] = crsfToSatellite(channelData[ii],
74+
CRSF_TO_SATELLITE_CH_MAP[ii],
75+
satelliteSystem);
76+
}
77+
// Round-robin channels
78+
else
79+
{
80+
outgoingPacket[ii] = crsfToSatellite(channelData[rr],
81+
CRSF_TO_SATELLITE_CH_MAP[rr],
82+
satelliteSystem);
83+
84+
// Update the round-robin index
85+
++rr;
86+
if (rr >= SATELLITE_NUM_CHANNELS)
87+
{
88+
rr = SATELLITE_FIRST_RR_CHANNEL;
89+
}
90+
}
91+
}
92+
93+
uint8_t satelliteSystemValue{};
94+
switch (satelliteSystem)
95+
{
96+
case DSMX_11MS:
97+
satelliteSystemValue = 0xB2;
98+
break;
99+
case DSMX_22MS:
100+
satelliteSystemValue = 0xA2;
101+
break;
102+
case DSM2_11MS:
103+
satelliteSystemValue = 0x12;
104+
break;
105+
default:
106+
satelliteSystemValue = 0x01;
107+
}
108+
109+
// Transmit the fade count
110+
_outputPort->write(fadeCount);
111+
// Transmit the protocol in use
112+
_outputPort->write(satelliteSystemValue);
113+
// Transmit the channel data
114+
_outputPort->write(reinterpret_cast<uint8_t *>(outgoingPacket), sizeof(outgoingPacket)); // Channel data
115+
116+
return callbackIntervalMs;
117+
}
118+
119+
#endif // defined(TARGET_RX)

src/src/rx-serial/SerialSatellite.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "SerialIO.h"
2+
3+
class SerialSatellite : public SerialIO
4+
{
5+
public:
6+
SerialSatellite(Stream &out, Stream &in)
7+
: SerialIO(&out, &in) {}
8+
9+
virtual ~SerialSatellite() = default;
10+
11+
void queueLinkStatisticsPacket() override {}
12+
void queueMSPFrameTransmission(uint8_t *data) override {}
13+
uint32_t sendRCFrame(bool frameAvailable, uint32_t *channelData) override;
14+
15+
private:
16+
static constexpr uint16_t SATELLITE_NUM_CHANNELS = 12;
17+
static constexpr uint8_t SATELLITE_FIRST_RR_CHANNEL = 4;
18+
static constexpr uint8_t SATELLITE_CHANNEL_DATA_LENGTH = 7;
19+
20+
void processBytes(uint8_t *bytes, uint16_t size) override{};
21+
22+
uint8_t fadeCount{0};
23+
uint8_t rr{SATELLITE_FIRST_RR_CHANNEL};
24+
bool sendPackets{false};
25+
};

0 commit comments

Comments
 (0)