2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
23 #if defined(USE_SPEKTRUM_REAL_RSSI) || defined(USE_SPEKTRUM_FAKE_RSSI)
25 #include "config/feature.h"
26 #include "common/utils.h"
27 #include "common/maths.h"
29 #include "drivers/system.h"
30 #include "drivers/time.h"
35 #include "rx/spektrum.h"
36 #include "io/spektrum_rssi.h"
38 // Number of fade outs counted as a link loss when using USE_SPEKTRUM_REAL_RSSI
39 #define SPEKTRUM_RSSI_LINK_LOSS_FADES 5
41 #ifdef USE_SPEKTRUM_FAKE_RSSI
42 // Spektrum Rx type. Determined by bind method.
43 static bool spektrumSatInternal
= true; // Assume internal,bound by BF.
45 // Variables used for calculating a signal strength from satellite fade.
46 // This is time-variant and computed every second based on the fade
47 // count over the last second.
48 static uint32_t spek_fade_last_sec
= 0; // Stores the timestamp of the last second.
49 static uint16_t spek_fade_last_sec_count
= 0; // Stores the fade count at the last second.
52 // Linear mapping and interpolation function
53 int32_t map(int32_t x
, int32_t in_min
, int32_t in_max
, int32_t out_min
, int32_t out_max
) {
54 return (x
- in_min
) * (out_max
- out_min
) / (in_max
- in_min
) + out_min
;
57 #ifdef USE_SPEKTRUM_RSSI_PERCENT_CONVERSION
59 // Conversion table from dBm to a percentage scale aproximating a more linear RSSI vs Distance curve.
61 static const dbm_table_t dbmTable
[] = {
62 {SPEKTRUM_RSSI_MAX
, 101},
75 {-78, 56}, // Linear part of the table, can be interpolated
84 {-87, 20}, // Beta Flight default RSSI % alatm point
87 {-90, 8}, // Failsafe usually hits here
88 {-91, 4}, // Linear part of the table end
90 {SPEKTRUM_RSSI_MIN
, 0}};
92 // Convert dBm to Range %
93 static int8_t dBm2range (int8_t dBm
) {
94 int8_t retval
= dbmTable
[0].reportAs
;
96 dBm
= constrain(dBm
, SPEKTRUM_RSSI_MIN
, SPEKTRUM_RSSI_MAX
);
97 for ( uint8_t i
= 1; i
< ARRAYLEN(dbmTable
); i
++ ) {
98 if (dBm
>= dbmTable
[i
].dBm
) {
99 // Linear interpolation between table points.
100 retval
= map(dBm
, dbmTable
[i
-1].dBm
, dbmTable
[i
].dBm
, dbmTable
[i
-1].reportAs
, dbmTable
[i
].reportAs
);
105 retval
= constrain(retval
, 0, 100);
110 void spektrumHandleRSSI(volatile uint8_t spekFrame
[]) {
111 #ifdef USE_SPEKTRUM_REAL_RSSI
112 static int8_t spek_last_rssi
= SPEKTRUM_RSSI_MAX
;
113 static uint8_t spek_fade_count
= 0;
117 // Real RSSI reported only by SRXL Telemetry Rx, in dBm.
118 int8_t rssi
= spekFrame
[0];
120 if (rssi
<= SPEKTRUM_RSSI_FADE_LIMIT
) {
121 // If Rx reports -100 dBm or less, it is a fade out and frame
123 // If it is a temporary fade, real RSSI will come back in the
124 // next frame, in that case
125 // we should not report 0% back as OSD keeps a "minimum RSSI"
126 // value. Instead keep last good report.
127 // If it is a total link loss, failsafe will kick in.
128 // The number of fades are counted and if it is equal or above
129 // SPEKTRUM_RSSI_LINK_LOSS_FADES a link loss is assumed and
130 // RSSI is set to Spektrums minimum RSSI value.
133 if (spek_fade_count
< SPEKTRUM_RSSI_LINK_LOSS_FADES
) {
134 // Ignore report and keep last known good value
135 rssi
= spek_last_rssi
;
137 // Link loss assumed, set RSSI to minimum value
138 rssi
= SPEKTRUM_RSSI_MIN
;
144 if(rssi_channel
!= 0) {
145 #ifdef USE_SPEKTRUM_RSSI_PERCENT_CONVERSION
146 // Do an dBm to percent conversion with an approxatelly linear distance
147 // and map the percentage to RSSI RC channel range
148 spekChannelData
[rssi_channel
] = (uint16_t)(map(dBm2range (rssi
),
152 // Do a direkt dBm to percent mapping, keeping the non-linear dBm logarithmic curve.
153 spekChannelData
[rssi_channel
] = (uint16_t)(map(rssi
),
154 SPEKTRUM_RSSI_MIN
, SPEKTRUM_RSSI_MAX
,
158 spek_last_rssi
= rssi
;
161 #ifdef USE_SPEKTRUM_FAKE_RSSI
164 #endif // USE_SPEKTRUM_REAL_RSSI
166 #ifdef USE_SPEKTRUM_FAKE_RSSI
168 // Fake RSSI value computed from fades
170 const uint32_t current_secs
= micros() / 1000 / (1000 / SPEKTRUM_FADE_REPORTS_PER_SEC
);
174 // Get fade count, different format depending on Rx rype and how Rx is bound. Initially assumed Internal
175 if (spektrumSatInternal
) {
176 // Internal Rx, bind values 3, 5, 7, 9
177 fade
= (uint16_t) spekFrame
[0];
178 system
= spekFrame
[1];
180 // Try to detect system type by assuming Internal until we find ANY frame telling otherwise.
181 if ( !( (system
== SPEKTRUM_DSM2_22
) |
182 (system
== SPEKTRUM_DSM2_11
) |
183 (system
== SPEKTRUM_DSMX_22
) |
184 (system
== SPEKTRUM_DSMX_11
) ) ){
185 spektrumSatInternal
=false; // Nope, this is an externally bound Sat Rx
188 // External Rx, bind values 4, 6, 8, 10
189 fade
= ((spekFrame
[0] << 8) + spekFrame
[1]);
192 if (spek_fade_last_sec
== 0) {
193 // This is the first frame status received.
194 spek_fade_last_sec_count
= fade
;
195 spek_fade_last_sec
= current_secs
;
196 } else if (spek_fade_last_sec
!= current_secs
) {
197 // If the difference is > 1, then we missed several seconds worth of frames and
198 // should just throw out the fade calc (as it's likely a full signal loss).
199 if ((current_secs
- spek_fade_last_sec
) == 1) {
200 if (rssi_channel
!= 0) {
201 spekChannelData
[rssi_channel
] = (uint16_t)(map(fade
- spek_fade_last_sec_count
,
202 SPEKTRUM_MAX_FADE_PER_SEC
/ SPEKTRUM_FADE_REPORTS_PER_SEC
, 0,
206 spek_fade_last_sec_count
= fade
;
207 spek_fade_last_sec
= current_secs
;
210 #endif // USE_SPEKTRUM_FAKE_RSSI
212 #endif // USE_SPEKTRUM_REAL_RSSI || USE_SPEKTRUM_FAKE_RSSI
213 #endif // USE_SERIAL_RX