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/>.
22 * Driver for IBUS (Flysky) receiver
23 * - initial implementation for MultiWii by Cesco/Pl¸schi
24 * - implementation for BaseFlight by Andreas (fiendie) Tacke
25 * - ported to CleanFlight by Konstantin (digitalentity) Sharlaimov
34 #ifdef USE_SERIALRX_IBUS
38 #include "common/utils.h"
40 #include "drivers/serial.h"
41 #include "drivers/serial_uart.h"
42 #include "drivers/time.h"
44 #include "io/serial.h"
47 #include "telemetry/telemetry.h"
52 #include "telemetry/ibus.h"
53 #include "telemetry/ibus_shared.h"
55 #define IBUS_MAX_CHANNEL 18
56 //In AFHDS there is 18 channels encoded in 14 slots (each slot is 2 byte long)
57 #define IBUS_MAX_SLOTS 14
58 #define IBUS_BUFFSIZE 32
59 #define IBUS_MODEL_IA6B 0
60 #define IBUS_MODEL_IA6 1
61 #define IBUS_FRAME_GAP 500
63 #define IBUS_BAUDRATE 115200
64 #define IBUS_TELEMETRY_PACKET_LENGTH (4)
65 #define IBUS_SERIAL_RX_PACKET_LENGTH (32)
67 static uint8_t ibusModel
;
68 static uint8_t ibusSyncByte
;
69 static uint8_t ibusFrameSize
;
70 static uint8_t ibusChannelOffset
;
71 static uint8_t rxBytesToIgnore
;
72 static uint16_t ibusChecksum
;
74 static bool ibusFrameDone
= false;
75 static uint32_t ibusChannelData
[IBUS_MAX_CHANNEL
];
77 static uint8_t ibus
[IBUS_BUFFSIZE
] = { 0, };
78 static timeDelta_t lastFrameDelta
= 0;
80 static bool isValidIa6bIbusPacketLength(uint8_t length
)
82 return (length
== IBUS_TELEMETRY_PACKET_LENGTH
) || (length
== IBUS_SERIAL_RX_PACKET_LENGTH
);
86 // Receive ISR callback
87 static void ibusDataReceive(uint16_t c
, void *data
)
91 static timeUs_t ibusTimeLast
;
92 static uint8_t ibusFramePosition
;
93 static timeUs_t lastFrameCompleteTimeUs
= 0;
95 const timeUs_t ibusTime
= microsISR();
97 if (cmpTimeUs(ibusTime
, ibusTimeLast
) > IBUS_FRAME_GAP
) {
98 ibusFramePosition
= 0;
100 } else if (rxBytesToIgnore
) {
105 ibusTimeLast
= ibusTime
;
107 if (ibusFramePosition
== 0) {
108 if (isValidIa6bIbusPacketLength(c
)) {
109 ibusModel
= IBUS_MODEL_IA6B
;
112 ibusChannelOffset
= 2;
113 ibusChecksum
= 0xFFFF;
114 } else if ((ibusSyncByte
== 0) && (c
== 0x55)) {
115 ibusModel
= IBUS_MODEL_IA6
;
118 ibusChecksum
= 0x0000;
119 ibusChannelOffset
= 1;
120 } else if (ibusSyncByte
!= c
) {
125 ibus
[ibusFramePosition
] = (uint8_t)c
;
127 if (ibusFramePosition
== ibusFrameSize
- 1) {
128 lastFrameDelta
= cmpTimeUs(ibusTime
, lastFrameCompleteTimeUs
);
129 lastFrameCompleteTimeUs
= ibusTime
;
130 ibusFrameDone
= true;
137 static bool isChecksumOkIa6(void)
141 uint16_t chksum
, rxsum
;
142 chksum
= ibusChecksum
;
143 rxsum
= ibus
[ibusFrameSize
- 2] + (ibus
[ibusFrameSize
- 1] << 8);
144 for (i
= 0, offset
= ibusChannelOffset
; i
< IBUS_MAX_SLOTS
; i
++, offset
+= 2) {
145 chksum
+= ibus
[offset
] + (ibus
[offset
+ 1] << 8);
147 return chksum
== rxsum
;
151 static bool checksumIsOk(void) {
152 if (ibusModel
== IBUS_MODEL_IA6
) {
153 return isChecksumOkIa6();
155 return isChecksumOkIa6b(ibus
, ibusFrameSize
);
160 static void updateChannelData(void) {
163 for (i
= 0, offset
= ibusChannelOffset
; i
< IBUS_MAX_SLOTS
; i
++, offset
+= 2) {
164 ibusChannelData
[i
] = ibus
[offset
] + ((ibus
[offset
+ 1] & 0x0F) << 8);
166 //latest IBUS recievers are using prviously not used 4 bits on every channel to incresse total channel count
167 for (i
= IBUS_MAX_SLOTS
, offset
= ibusChannelOffset
+ 1; i
< IBUS_MAX_CHANNEL
; i
++, offset
+= 6) {
168 ibusChannelData
[i
] = ((ibus
[offset
] & 0xF0) >> 4) | (ibus
[offset
+ 2] & 0xF0) | ((ibus
[offset
+ 4] & 0xF0) << 4);
172 static uint8_t ibusFrameStatus(rxRuntimeState_t
*rxRuntimeState
)
174 UNUSED(rxRuntimeState
);
176 uint8_t frameStatus
= RX_FRAME_PENDING
;
178 if (!ibusFrameDone
) {
182 ibusFrameDone
= false;
184 if (checksumIsOk()) {
185 if (ibusModel
== IBUS_MODEL_IA6
|| ibusSyncByte
== IBUS_SERIAL_RX_PACKET_LENGTH
) {
187 frameStatus
= RX_FRAME_COMPLETE
;
191 #if defined(USE_TELEMETRY) && defined(USE_TELEMETRY_IBUS)
192 rxBytesToIgnore
= respondToIbusRequest(ibus
);
201 static uint16_t ibusReadRawRC(const rxRuntimeState_t
*rxRuntimeState
, uint8_t chan
)
203 UNUSED(rxRuntimeState
);
204 return ibusChannelData
[chan
];
207 static timeDelta_t
ibusFrameDelta(void)
209 return lastFrameDelta
;
212 bool ibusInit(const rxConfig_t
*rxConfig
, rxRuntimeState_t
*rxRuntimeState
)
217 rxRuntimeState
->channelCount
= IBUS_MAX_CHANNEL
;
218 rxRuntimeState
->rxRefreshRate
= 20000; // TODO - Verify speed
220 rxRuntimeState
->rcReadRawFn
= ibusReadRawRC
;
221 rxRuntimeState
->rcFrameStatusFn
= ibusFrameStatus
;
222 rxRuntimeState
->rcFrameDeltaFn
= ibusFrameDelta
;
224 const serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_RX_SERIAL
);
230 bool portShared
= isSerialPortShared(portConfig
, FUNCTION_RX_SERIAL
, FUNCTION_TELEMETRY_IBUS
);
232 bool portShared
= false;
237 serialPort_t
*ibusPort
= openSerialPort(portConfig
->identifier
,
242 portShared
? MODE_RXTX
: MODE_RX
,
243 (rxConfig
->serialrx_inverted
? SERIAL_INVERTED
: 0) | (rxConfig
->halfDuplex
|| portShared
? SERIAL_BIDIR
: 0)
246 #if defined(USE_TELEMETRY) && defined(USE_TELEMETRY_IBUS)
248 initSharedIbusTelemetry(ibusPort
);
252 return ibusPort
!= NULL
;