dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_crossfire.c
Go to the documentation of this file.
1 
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, see <http://www.gnu.org/licenses/>
24  *
25  * Additional note on redistribution: The copyright and license notices above
26  * must be maintained in each individual source file that is a derivative work
27  * of this source file; otherwise redistribution is prohibited.
28  */
29 
30 #include "pios_crossfire.h"
31 #include "pios_crc.h"
32 
33 #ifdef PIOS_INCLUDE_CROSSFIRE
34 
35 // Addresses with one-based index, because they're used after a pointer
36 // increase only.
37 #define CRSF_LEN_IDX 2
38 #define CRSF_HEADER_IDX 3
39 
40 #include "pios_crc.h"
41 #include "pios_com.h"
42 #include "pios_com_priv.h"
43 
44 #define CRSF_CRCFIELD(frame) (frame.payload[frame.length - CRSF_CRC_LEN - CRSF_TYPE_LEN])
45 
46 // Internal use. Random number.
47 #define PIOS_CROSSFIRE_MAGIC 0xcdf19cf5
48 
52 struct pios_crossfire_dev {
53  uint32_t magic;
54  uint8_t buf_pos;
55  uint16_t rx_timer;
56  uint16_t failsafe_timer;
57  uint8_t bytes_expected;
58 
59  uint16_t channel_data[PIOS_CROSSFIRE_CHANNELS];
60 
61  union {
62  struct crsf_frame_t frame;
63  uint8_t rx_buf[sizeof(struct crsf_frame_t)];
64  } u;
65 
66  // Need a copy of the USART/driver ref to initialize a COM device
67  // when necessary.
68  uintptr_t usart_id;
69  const struct pios_com_driver *usart_driver;
70 
71  // COM device ID for sending telemetry. Might be this USART
72  // or a separate one.
73  uintptr_t telem_com_id;
74 
75  // To track frame starts to track whether telemetry is OK to send.
76  uint32_t time_frame_start;
77 };
78 
83 static struct pios_crossfire_dev *PIOS_Crossfire_Alloc(void);
89 static bool PIOS_Crossfire_Validate(const struct pios_crossfire_dev *dev);
96 static int32_t PIOS_Crossfire_Read(uintptr_t id, uint8_t channel);
102 static void PIOS_Crossfire_SetAllChannels(struct pios_crossfire_dev *dev, uint16_t value);
112 static uint16_t PIOS_Crossfire_Receive(uintptr_t context, uint8_t *buf, uint16_t buf_len,
113  uint16_t *headroom, bool *task_woken);
118 static void PIOS_Crossfire_ResetBuffer(struct pios_crossfire_dev *dev);
123 static bool PIOS_Crossfire_UnpackFrame(struct pios_crossfire_dev *dev);
128 static void PIOS_Crossfire_Supervisor(uintptr_t context);
129 
130 // public
132  .read = PIOS_Crossfire_Read,
133 };
134 
135 
136 static struct pios_crossfire_dev *PIOS_Crossfire_Alloc(void)
137 {
138  struct pios_crossfire_dev *dev = PIOS_malloc_no_dma(sizeof(struct pios_crossfire_dev));
139  if (!dev)
140  return NULL;
141 
142  memset(dev, 0, sizeof(*dev));
143  dev->magic = PIOS_CROSSFIRE_MAGIC;
144 
145  return dev;
146 }
147 
148 static bool PIOS_Crossfire_Validate(const struct pios_crossfire_dev *dev)
149 {
150  return dev && dev->magic == PIOS_CROSSFIRE_MAGIC;
151 }
152 
153 int PIOS_Crossfire_Init(uintptr_t *crsf_id, const struct pios_com_driver *driver,
154  uintptr_t usart_id)
155 {
156  struct pios_crossfire_dev *dev = PIOS_Crossfire_Alloc();
157 
158  if (!dev)
159  return -1;
160 
161  *crsf_id = (uintptr_t)dev;
162  dev->usart_id = usart_id;
163  dev->usart_driver = driver;
164 
165  PIOS_Crossfire_ResetBuffer(dev);
166  PIOS_Crossfire_SetAllChannels(dev, PIOS_RCVR_INVALID);
167 
168  // Get COM device for telemetry.
169  if(PIOS_COM_Init(&dev->telem_com_id, dev->usart_driver, dev->usart_id, 0, CRSF_MAX_FRAMELEN))
170  return -1;
171 
172  if (!PIOS_RTC_RegisterTickCallback(PIOS_Crossfire_Supervisor, *crsf_id))
173  PIOS_Assert(0);
174 
175  (driver->bind_rx_cb)(usart_id, PIOS_Crossfire_Receive, *crsf_id);
176 
177  return 0;
178 }
179 
180 int PIOS_Crossfire_InitTelemetry(uintptr_t crsf_id)
181 {
182  struct pios_crossfire_dev *dev = (struct pios_crossfire_dev*)crsf_id;
183 
184  // What the hell? Return error code and don't assert, telemetry ain't vital.
185  if(!PIOS_Crossfire_Validate(dev))
186  return -1;
187  else
188  return 0;
189 }
190 
191 static int32_t PIOS_Crossfire_Read(uintptr_t context, uint8_t channel)
192 {
193  if (channel > PIOS_CROSSFIRE_CHANNELS)
194  return PIOS_RCVR_INVALID;
195 
196  struct pios_crossfire_dev *dev = (struct pios_crossfire_dev *)context;
197  if (!PIOS_Crossfire_Validate(dev))
198  return PIOS_RCVR_NODRIVER;
199 
200  return dev->channel_data[channel];
201 }
202 
203 static void PIOS_Crossfire_SetAllChannels(struct pios_crossfire_dev *dev, uint16_t value)
204 {
205  for (int i = 0; i < PIOS_CROSSFIRE_CHANNELS; i++)
206  dev->channel_data[i] = value;
207 }
208 
209 static uint16_t PIOS_Crossfire_Receive(uintptr_t context, uint8_t *buf, uint16_t buf_len,
210  uint16_t *headroom, bool *task_woken)
211 {
212  struct pios_crossfire_dev *dev = (struct pios_crossfire_dev *)context;
213 
214  if (!PIOS_Crossfire_Validate(dev))
215  goto out_fail;
216 
217  if(dev->buf_pos == 0) {
218  dev->time_frame_start = PIOS_DELAY_GetRaw();
219  }
220 
221  for (int i = 0; i < buf_len; i++) {
222  // Ignore any stuff beyond what's expected.
223  if(dev->buf_pos >= dev->bytes_expected)
224  break;
225 
226  dev->u.rx_buf[dev->buf_pos++] = buf[i];
227 
228  if(dev->buf_pos == CRSF_LEN_IDX) {
229  // Read length field and adjust. Denotes payload, plus type field, plus CRC field.
230  dev->bytes_expected = CRSF_ADDRESS_LEN + CRSF_LENGTH_LEN + dev->u.frame.length;
231 
232  // If length field isn't plausible, ignore rest of the data.
233  if(dev->bytes_expected >= CRSF_MAX_FRAMELEN) {
234  dev->bytes_expected = 0;
235  break;
236  }
237  }
238 
239  if (dev->buf_pos == dev->bytes_expected) {
240  // Frame complete, decode.
241  if(PIOS_Crossfire_UnpackFrame(dev)) {
242  // Frame is valid, trigger semaphore.
244  // Ignore any stuff that might be left in the buffer.
245  // There shouldn't be anything.
246  break;
247  }
248  }
249  }
250 
251  dev->rx_timer = 0;
252 
253  // Keep pumping data.
254  if(headroom) *headroom = CRSF_MAX_FRAMELEN;
255  if(task_woken) *task_woken = false;
256  return buf_len;
257 
258 out_fail:
259  if(headroom) *headroom = 0;
260  if(task_woken) *task_woken = false;
261  return 0;
262 }
263 
264 static void PIOS_Crossfire_ResetBuffer(struct pios_crossfire_dev *dev)
265 {
266  dev->buf_pos = 0;
267  dev->bytes_expected = CRSF_MAX_FRAMELEN;
268 }
269 
270 static bool PIOS_Crossfire_UnpackFrame(struct pios_crossfire_dev *dev)
271 {
272  // Currently there appears to be only RC channel messages.
273  // We also only care about those for now.
274 
275  if(dev->u.frame.type == CRSF_FRAME_RCCHANNELS &&
276  dev->u.frame.length == (CRSF_TYPE_LEN + CRSF_PAYLOAD_RCCHANNELS + CRSF_CRC_LEN)) {
277 
278  // If there's a valid type and it matches its payload length,
279  // then proceed doing the heavy lifting.
280  uint8_t crc = PIOS_CRC_updateCRC_TBS(0, &dev->u.frame.type, dev->u.frame.length - CRSF_CRC_LEN);
281 
282  if(crc == CRSF_CRCFIELD(dev->u.frame)) {
283  // From pios_sbus.c
284  uint8_t *s = dev->u.frame.payload;
285  uint16_t *d = dev->channel_data;
286 
287  #define F(v,s) (((v) >> (s)) & 0x7ff)
288 
289  /* unroll channels 1-8 */
290  d[0] = F(s[0] | s[1] << 8, 0);
291  d[1] = F(s[1] | s[2] << 8, 3);
292  d[2] = F(s[2] | s[3] << 8 | s[4] << 16, 6);
293  d[3] = F(s[4] | s[5] << 8, 1);
294  d[4] = F(s[5] | s[6] << 8, 4);
295  d[5] = F(s[6] | s[7] << 8 | s[8] << 16, 7);
296  d[6] = F(s[8] | s[9] << 8, 2);
297  d[7] = F(s[9] | s[10] << 8, 5);
298 
299  /* unroll channels 9-16 */
300  d[8] = F(s[11] | s[12] << 8, 0);
301  d[9] = F(s[12] | s[13] << 8, 3);
302  d[10] = F(s[13] | s[14] << 8 | s[15] << 16, 6);
303  d[11] = F(s[15] | s[16] << 8, 1);
304  d[12] = F(s[16] | s[17] << 8, 4);
305  d[13] = F(s[17] | s[18] << 8 | s[19] << 16, 7);
306  d[14] = F(s[19] | s[20] << 8, 2);
307  d[15] = F(s[20] | s[21] << 8, 5);
308 
309  // RC control is still happening.
310  dev->failsafe_timer = 0;
311 
312  PIOS_Crossfire_ResetBuffer(dev);
313 
314  return true;
315  }
316  }
317 
318  PIOS_Crossfire_ResetBuffer(dev);
319  return false;
320 }
321 
322 static void PIOS_Crossfire_Supervisor(uintptr_t context)
323 {
324  struct pios_crossfire_dev *dev = (struct pios_crossfire_dev *)context;
325  PIOS_Assert(PIOS_Crossfire_Validate(dev));
326 
327  // An RC channel type packet is 26 bytes, at 420kbit with stop bit, that's 557us.
328  // Maximum packet size is 36 bytes, that's 772us.
329  // Minimum frame timing is supposed to be 4ms, typical is however 6.67ms (150hz).
330  // So if more than 1.6ms passed without communication, safe to say that a new
331  // packet is inbound.
332  if (++dev->rx_timer > 1)
333  PIOS_Crossfire_ResetBuffer(dev);
334 
335  // Failsafe after 250ms.
336  if (++dev->failsafe_timer > 156)
337  PIOS_Crossfire_SetAllChannels(dev, PIOS_RCVR_TIMEOUT);
338 }
339 
340 int PIOS_Crossfire_SendTelemetry(uintptr_t crsf_id, uint8_t *buf, uint8_t bytes)
341 {
342  struct pios_crossfire_dev *dev = (struct pios_crossfire_dev*)crsf_id;
343 
344  // While telemetry ain't vital, if something's giving a wrong device handle,
345  // assert anyway.
346  if(!PIOS_Crossfire_Validate(dev))
347  PIOS_Assert(0);
348 
349  // There should be a telemetry channel regardless. And sending NULL buffers
350  // ain't nice.
351  if(!dev->telem_com_id || !buf)
352  PIOS_Assert(0);
353 
354  // Nothing to send? Fine!
355  if(!bytes)
356  return 0;
357 
358  uint32_t delay = PIOS_DELAY_DiffuS(dev->time_frame_start);
360 
361  // We're still within the send window.
362  PIOS_COM_SendBuffer(dev->telem_com_id, buf, (uint16_t)bytes);
363  return 0;
364 
365  } else {
366  return -1;
367  }
368 }
369 
370 bool PIOS_Crossfire_IsFailsafed(uintptr_t crsf_id)
371 {
372  struct pios_crossfire_dev *dev = (struct pios_crossfire_dev*)crsf_id;
373 
374  if(!PIOS_Crossfire_Validate(dev))
375  PIOS_Assert(0);
376 
377  /* ~250ms to failsafe. */
378  return dev->failsafe_timer > 156;
379 }
380 
381 #endif // PIOS_INCLUDE_CROSSFIRE
382 
CRC functions header.
int PIOS_Crossfire_SendTelemetry(uintptr_t crsf_id, uint8_t *buf, uint8_t bytes)
union @12 crc
float F[NUMX][NUMX]
Definition: insgps14state.c:63
uint32_t PIOS_DELAY_DiffuS(uint32_t raw)
Subtract raw time from now and convert to us.
Definition: pios_delay.c:159
int32_t(* read)(uintptr_t id, uint8_t channel)
Definition: pios_rcvr.h:35
#define CRSF_FRAME_RCCHANNELS
COM layer functions header.
COM private definitions.
bool PIOS_RTC_RegisterTickCallback(void(*fn)(uintptr_t id), uintptr_t data)
Definition: pios_delay.c:185
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
#define CRSF_MAX_FRAMELEN
#define CRSF_CRC_LEN
uint8_t bytes[2]
Definition: storm32bgc.c:156
void PIOS_RCVR_ActiveFromISR()
#define CRSF_LENGTH_LEN
int PIOS_Crossfire_InitTelemetry(uintptr_t crsf_id)
#define CRSF_TIMING_MAXFRAME
uint8_t PIOS_CRC_updateCRC_TBS(uint8_t crc, const uint8_t *data, int32_t length)
Definition: pios_crc.c:185
#define CRSF_TYPE_LEN
#define CRSF_ADDRESS_LEN
uint8_t i
Definition: msp_messages.h:97
uint8_t d
Definition: msp_messages.h:98
uint16_t value
Definition: storm32bgc.c:155
#define CRSF_TIMING_FRAMEDISTANCE
uint32_t magic
PIOS_COM_SendBuffer(shub_global->frsky_port, shub_global->serial_buf, msg_length)
#define CRSF_PAYLOAD_RCCHANNELS
int PIOS_Crossfire_Init(uintptr_t *crsf_id, const struct pios_com_driver *driver, uintptr_t uart_id)
Initialises the TBS Crossfire Rx driver with a serial port.
const struct pios_rcvr_driver pios_crossfire_rcvr_driver
int32_t PIOS_COM_Init(uintptr_t *com_id, const struct pios_com_driver *driver, uintptr_t lower_id, uint16_t rx_buffer_len, uint16_t tx_buffer_len)
void(* bind_rx_cb)(uintptr_t id, pios_com_callback rx_in_cb, uintptr_t context)
Definition: pios_com.h:47
bool PIOS_Crossfire_IsFailsafed()
#define PIOS_Assert(test)
Definition: pios_debug.h:52
#define PIOS_CROSSFIRE_CHANNELS
uint32_t PIOS_DELAY_GetRaw()
Get the raw delay timer, useful for timing.
Definition: pios_delay.c:153