Skip to content

Commit ae47974

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

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

src/src/rx-serial/SerialSatellite.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
static constexpr uint8_t crsfToSatelliteChannelMap[12] = {
23+
// clang-format off
24+
// CRSF // Satellite
25+
/*Channel 0*/ 1,
26+
/*Channel 1*/ 2,
27+
/*Channel 2*/ 0,
28+
/*Channel 3*/ 3,
29+
/*Channel 4*/ 11,
30+
/*Channel 5*/ 4,
31+
/*Channel 6*/ 5,
32+
/*Channel 7*/ 6,
33+
/*Channel 8*/ 7,
34+
/*Channel 9*/ 8,
35+
/*Channel 10*/ 9,
36+
/*Channel 11*/ 10,
37+
// clang-format on
38+
};
39+
40+
uint8_t fadeCount{0};
41+
uint8_t rr{SATELLITE_FIRST_RR_CHANNEL};
42+
bool sendPackets{false};
43+
};

0 commit comments

Comments
 (0)