dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_srxl.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 
26 #include "pios.h"
27 
28 #if defined(PIOS_INCLUDE_SRXL)
29 
30 #if !defined(PIOS_INCLUDE_RTC)
31 #error PIOS_INCLUDE_RTC must be used to use SRXL
32 #endif
33 
34 #include "openpilot.h"
35 #include "misc_math.h"
36 #include "pios_srxl.h"
37 
38 /* Private Types */
39 enum pios_srxl_magic {
40  PIOS_SRXL_MAGIC = 0xda8e23be
41 };
42 
43 enum pios_srxl_sync {
44  PIOS_SRXL_SYNC_MULTIPLEX12 = 0xA1,
45  PIOS_SRXL_SYNC_MULTIPLEX16 = 0xA2,
46  PIOS_SRXL_SYNC_WEATRONIC16 = 0xA6,
47 };
48 
49 struct pios_srxl_frame_multiplex12 {
50  uint8_t sync;
51  uint16_t chan[12];
52  uint16_t crc;
53 } __attribute__((packed));
54 
55 struct pios_srxl_frame_multiplex16 {
56  uint8_t sync;
57  uint16_t chan[16];
58  uint16_t crc;
59 } __attribute__((packed));
60 
61 struct pios_srxl_frame_weatronic16 {
62  uint8_t sync;
63  uint8_t junk0[3]; // unknown at this stage
64  uint8_t status; // bit 4 seems to be failsafe flag
65  uint8_t junk1; // unknown
66  int16_t chan[16];
67  uint16_t crc;
68 } __attribute__((packed));
69 
70 /* weatronic 16 is currently the largest */
71 #define PIOS_SRXL_RXBUF_LEN (40)
72 
73 struct pios_srxl_dev {
74  enum pios_srxl_magic magic;
75  uint16_t channels[PIOS_SRXL_MAX_CHANNELS];
76  uint8_t rx_buffer[PIOS_SRXL_RXBUF_LEN];
77  uint8_t rx_buffer_pos;
78  uint32_t rx_timer;
79  uint32_t failsafe_timer;
80  uint8_t frame_length;
81  uint16_t crc;
82 };
83 
84 /* Private Functions */
89 static struct pios_srxl_dev *PIOS_SRXL_AllocDev(void);
95 static bool PIOS_SRXL_ValidateDev(struct pios_srxl_dev *dev);
101 static void PIOS_SRXL_UpdateCRC(struct pios_srxl_dev *dev, uint8_t value);
111 static uint16_t PIOS_SRXL_RxCallback(uintptr_t context, uint8_t *buf,
112  uint16_t buf_len, uint16_t *headroom, bool *task_woken);
117 static void PIOS_SRXL_ParseFrame(struct pios_srxl_dev *dev);
123 static void PIOS_SRXL_ResetChannels(struct pios_srxl_dev *dev, uint16_t val);
129 static int32_t PIOS_SRXL_Read(uintptr_t id, uint8_t channel);
134 void PIOS_SRXL_Supervisor(uintptr_t id);
135 
136 /* Private Variables */
137 
138 /* Public Variables */
140  .read = PIOS_SRXL_Read
141 };
142 
143 /* Implementation */
144 
145 int32_t PIOS_SRXL_Init(uintptr_t *srxl_id,
146  const struct pios_com_driver *driver, uintptr_t lower_id)
147 {
148  if (!driver || !lower_id)
149  return -1;
150  struct pios_srxl_dev *dev = PIOS_SRXL_AllocDev();
151  if (dev == NULL)
152  return -2;
153 
154  *srxl_id = (uintptr_t)dev;
155 
156  (driver->bind_rx_cb)(lower_id, PIOS_SRXL_RxCallback, *srxl_id);
157 
158  if (!PIOS_RTC_RegisterTickCallback(PIOS_SRXL_Supervisor, *srxl_id)) {
160  }
161 
162  return 0;
163 }
164 
165 static struct pios_srxl_dev *PIOS_SRXL_AllocDev(void)
166 {
167  struct pios_srxl_dev *dev = PIOS_malloc(sizeof(*dev));
168  if (dev == NULL)
169  return NULL;
170 
171  dev->magic = PIOS_SRXL_MAGIC;
172 
173  return dev;
174 }
175 
176 static bool PIOS_SRXL_ValidateDev(struct pios_srxl_dev *dev)
177 {
178  if (dev != NULL && dev->magic == PIOS_SRXL_MAGIC)
179  return true;
180  return false;
181 }
182 
183 static void PIOS_SRXL_UpdateCRC(struct pios_srxl_dev *dev, uint8_t value)
184 {
185  if (!PIOS_SRXL_ValidateDev(dev))
186  return;
187 
188  uint8_t i;
189  dev->crc = dev->crc ^ (int16_t)value << 8;
190  for(i = 0; i < 8; i++)
191  {
192  if(dev->crc & 0x8000)
193  dev->crc = dev->crc << 1^0x1021;
194  else
195  dev->crc = dev->crc << 1;
196  }
197 }
198 
199 static uint16_t PIOS_SRXL_RxCallback(uintptr_t context, uint8_t *buf,
200  uint16_t buf_len, uint16_t *headroom, bool *task_woken)
201 {
202  struct pios_srxl_dev *dev = (struct pios_srxl_dev *)context;
203  if (!PIOS_SRXL_ValidateDev(dev))
204  return PIOS_RCVR_INVALID;
205 
206  dev->rx_timer = 0;
207  uint16_t consumed = 0;
208 
209  for (int i = 0; i < buf_len; i++) {
210  if (dev->rx_buffer_pos == 0) {
211  dev->crc = 0;
212  if (buf[i] == PIOS_SRXL_SYNC_MULTIPLEX12) {
213  dev->frame_length = sizeof(struct pios_srxl_frame_multiplex12);
214  } else if (buf[i] == PIOS_SRXL_SYNC_MULTIPLEX16) {
215  dev->frame_length = sizeof(struct pios_srxl_frame_multiplex16);
216  } else if (buf[i] == PIOS_SRXL_SYNC_WEATRONIC16) {
217  dev->frame_length = sizeof(struct pios_srxl_frame_weatronic16);
218  } else {
219  continue;
220  }
221  }
222  dev->rx_buffer[dev->rx_buffer_pos++] = buf[i];
223  PIOS_SRXL_UpdateCRC(dev, buf[i]);
224  if (dev->rx_buffer_pos == dev->frame_length)
225  PIOS_SRXL_ParseFrame(dev);
226  consumed++;
227  }
228 
229  if (headroom)
230  *headroom = PIOS_SRXL_RXBUF_LEN - dev->rx_buffer_pos;
231  *task_woken = false;
232 
233  return consumed;
234 }
235 
236 static void PIOS_SRXL_ParseFrame(struct pios_srxl_dev *dev)
237 {
238  if (!PIOS_SRXL_ValidateDev(dev))
239  return;
240 
241  if (dev->crc == 0) {
242  bool failsafe = false; // only used by variants with failsafe flag
243 
244  switch (dev->rx_buffer[0]) {
245  case PIOS_SRXL_SYNC_MULTIPLEX16:
246  {
247  struct pios_srxl_frame_multiplex16 *frame =
248  (struct pios_srxl_frame_multiplex16 *)dev->rx_buffer;
249  for (int i = 0; i < 16; i++)
250  dev->channels[i] = BE16_TO_CPU(frame->chan[i]);
251  }
252  break;
253  case PIOS_SRXL_SYNC_MULTIPLEX12:
254  {
255  struct pios_srxl_frame_multiplex12 *frame =
256  (struct pios_srxl_frame_multiplex12 *)dev->rx_buffer;
257  for (int i = 0; i < 12; i++)
258  dev->channels[i] = BE16_TO_CPU(frame->chan[i]);
259  }
260  break;
261  case PIOS_SRXL_SYNC_WEATRONIC16:
262  {
263  struct pios_srxl_frame_weatronic16 *frame =
264  (struct pios_srxl_frame_weatronic16 *)dev->rx_buffer;
265  for (int i = 0; i < 16; i++) {
266  int16_t value = 2000 + BE16_TO_CPU(frame->chan[i]); // centre values around 2000
267  if (value < 0 || value > 4000)
268  dev->channels[i] = PIOS_RCVR_INVALID;
269  else
270  dev->channels[i] = (uint16_t)value;
271  }
272  failsafe = (frame->status & 0x10) > 0;
273  }
274  break;
275  }
276 
277  if (failsafe)
278  PIOS_SRXL_ResetChannels(dev, PIOS_RCVR_TIMEOUT);
279  else
280  dev->failsafe_timer = 0;
281 
283  }
284 
285  dev->rx_buffer_pos = 0;
286 }
287 
288 static int32_t PIOS_SRXL_Read(uintptr_t id, uint8_t channel)
289 {
290  struct pios_srxl_dev *dev = (struct pios_srxl_dev *)id;
291  if (!PIOS_SRXL_ValidateDev(dev))
292  return PIOS_RCVR_INVALID;
293  return dev->channels[channel];
294 }
295 
296 static void PIOS_SRXL_ResetChannels(struct pios_srxl_dev *dev, uint16_t val)
297 {
298  if (!PIOS_SRXL_ValidateDev(dev))
299  return;
300 
301  for (int i = 0; i < NELEMENTS(dev->channels); i++)
302  dev->channels[i] = val;
303 }
304 
305 void PIOS_SRXL_Supervisor(uintptr_t id)
306 {
307  struct pios_srxl_dev *dev = (struct pios_srxl_dev *)id;
308  if (!PIOS_SRXL_ValidateDev(dev))
309  return;
310  /*
311  * RTC runs this callback at 625 Hz (T=1.6 ms)
312  * Frame period is either 14 ms or 21 ms
313  * We will reset the rx buffer if nothing is received for 8 ms (5 ticks)
314  * We will failsafe if 12 frames (low rate) are lost
315  * (12 * 21) / 1.6 ~ 158 ticks
316  */
317  if (++dev->rx_timer >= 5)
318  dev->rx_buffer_pos = 0;
319  if (++dev->failsafe_timer >= 158)
320  PIOS_SRXL_ResetChannels(dev, PIOS_RCVR_TIMEOUT);
321 }
322 
323 DONT_BUILD_IF(sizeof(struct pios_srxl_frame_multiplex12) > PIOS_SRXL_RXBUF_LEN, SRXLBufferSize);
324 DONT_BUILD_IF(sizeof(struct pios_srxl_frame_multiplex16) > PIOS_SRXL_RXBUF_LEN, SRXLBufferSize);
325 DONT_BUILD_IF(sizeof(struct pios_srxl_frame_weatronic16) > PIOS_SRXL_RXBUF_LEN, SRXLBufferSize);
326 
327 #endif /* defined(PIOS_INCLUDE_SRXL) */
328 
union @12 crc
int32_t(* read)(uintptr_t id, uint8_t channel)
Definition: pios_rcvr.h:35
Main PiOS header to include all the compiled in PiOS options.
#define NELEMENTS(x)
Definition: pios.h:192
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
bool PIOS_RTC_RegisterTickCallback(void(*fn)(uintptr_t id), uintptr_t data)
Definition: pios_delay.c:185
int32_t PIOS_SRXL_Init(uintptr_t *serial_id, const struct pios_com_driver *driver, uintptr_t lower_id)
Initialize a new SRXL device.
#define BE16_TO_CPU(x)
Definition: pios.h:221
void PIOS_RCVR_ActiveFromISR()
int16_t status
Definition: main.c:61
#define PIOS_SRXL_MAX_CHANNELS
Definition: pios_srxl.h:33
uint8_t i
Definition: msp_messages.h:97
uint16_t value
Definition: storm32bgc.c:155
uint32_t magic
#define DONT_BUILD_IF(COND, MSG)
Definition: morsel.c:206
Includes PiOS and core architecture components.
void(* bind_rx_cb)(uintptr_t id, pios_com_callback rx_in_cb, uintptr_t context)
Definition: pios_com.h:47
const struct pios_rcvr_driver pios_srxl_rcvr_driver
typedef __attribute__
Definition: serial_4way.h:43