dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_flyingpio.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 "openpilot.h"
31 #include "pios.h"
32 
33 #if defined(PIOS_INCLUDE_FLYINGPIO)
34 
35 #include "pios_thread.h"
36 #include "pios_queue.h"
37 #include "taskmonitor.h"
38 
39 #include "pios_flyingpio_priv.h"
40 #include "flyingpio_messages.h"
41 
42 #include "actuatorcommand.h"
43 #include "hwshared.h"
44 
49 enum pios_flyingpio_dev_magic {
50  PIOS_FLYINGPIO_DEV_MAGIC = 0x4f497046
51 };
52 
55 };
56 
57 static int32_t PIOS_FLYINGPIO_ADC_PinGet(uintptr_t dev_int, uint32_t pin);
58 static uint8_t PIOS_FLYINGPIO_ADC_NumberOfChannels(uintptr_t dev_int);
59 static float PIOS_FLYINGPIO_ADC_LSB_Voltage(uintptr_t dev_int);
60 
62  .get_pin = PIOS_FLYINGPIO_ADC_PinGet,
63  .number_of_channels = PIOS_FLYINGPIO_ADC_NumberOfChannels,
64  .lsb_voltage = PIOS_FLYINGPIO_ADC_LSB_Voltage,
65 };
66 
67 #define MIN_QUIET_TIME 300 /* Microseconds */
68 
72 struct pios_flyingpio_dev {
73  enum pios_flyingpio_dev_magic magic;
74  pios_spi_t spi_id;
75  uint32_t spi_slave;
77  uint32_t last_msg_time;
79  uint16_t msg_num;
80  uint16_t err_cnt;
83  volatile uint16_t rcvr_value[FPPROTO_MAX_RCCHANS];
86  volatile uint16_t adc_value[FPPROTO_MAX_ADCCHANS];
89  uint8_t protocol;
90 };
91 
92 #define MAX_CONSEC_ERRS 5
93 
95 static struct pios_flyingpio_dev *fpio_dev;
96 
97 static struct flyingpi_msg actuator_cfg;
98 static float channel_values[FPPROTO_MAX_SERVOS];
99 
101 
104 static struct pios_flyingpio_dev *PIOS_FLYINGPIO_Alloc();
105 
110 static int32_t PIOS_FLYINGPIO_Validate(struct pios_flyingpio_dev *dev);
111 
112 static void PIOS_FLYINGPIO_ActuatorUpdate();
113 static int PIOS_FLYINGPIO_ActuatorSetMode(const uint16_t *out_rate,
114  const int banks, const uint16_t *channel_max,
115  const uint16_t *channel_min);
116 static void PIOS_FLYINGPIO_ActuatorSet(uint8_t servo, float position);
117 
118 const struct pios_servo_callbacks flyingpio_callbacks = {
119  .update = PIOS_FLYINGPIO_ActuatorUpdate,
120  .set_mode = PIOS_FLYINGPIO_ActuatorSetMode,
121  .set = PIOS_FLYINGPIO_ActuatorSet
122 };
123 
124 static struct pios_flyingpio_dev *PIOS_FLYINGPIO_Alloc()
125 {
126  struct pios_flyingpio_dev *dev;
127 
128  dev = (struct pios_flyingpio_dev *)PIOS_malloc(sizeof(*fpio_dev));
129  if (!dev)
130  return NULL;
131 
132  dev->magic = PIOS_FLYINGPIO_DEV_MAGIC;
133 
134  PIOS_Servo_SetCallbacks(&flyingpio_callbacks);
135 
136  return dev;
137 }
138 
139 static int32_t PIOS_FLYINGPIO_Validate(struct pios_flyingpio_dev *dev)
140 {
141  if (dev == NULL)
142  return -1;
143  if (dev->magic != PIOS_FLYINGPIO_DEV_MAGIC)
144  return -2;
145  if (dev->spi_id == 0)
146  return -3;
147  return 0;
148 }
149 
151  uint32_t slave_idx, uint8_t protocol)
152 {
153  fpio_dev = PIOS_FLYINGPIO_Alloc();
154  if (fpio_dev == NULL)
155  return -1;
156  *dev = fpio_dev;
157 
158  fpio_dev->spi_id = spi_id;
159  fpio_dev->spi_slave = slave_idx;
160 
161  fpio_dev->protocol = protocol;
162 
163  for (int i = 0; i < FPPROTO_MAX_RCCHANS; i++) {
164  // Just for a very short time; remote end will take this over
165  fpio_dev->rcvr_value[i] = PIOS_RCVR_TIMEOUT;
166  }
167 
168  return 0;
169 }
170 
171 static int PIOS_FLYINGPIO_SendCmd(struct flyingpi_msg *msg) {
172  int len = 0;
173 
174  int ret = 0;
175 
176  uint32_t span = PIOS_DELAY_DiffuS(fpio_dev->last_msg_time);
177 
178  if (span < MIN_QUIET_TIME) {
179  /* Busy wait. No sense in other stuff stacking up.
180  * This has happened because we missed timing last time
181  * around on the actuator side. Ensure we get this actuator
182  * message out ASAP and queues don't fill in the meantime.
183  */
184  PIOS_DELAY_WaituS(MIN_QUIET_TIME - span + 20);
185  }
186 
187  flyingpi_calc_crc(msg, true, &len);
188 
189  if (PIOS_SPI_ClaimBus(fpio_dev->spi_id) != 0) {
190  return -1; /* No bueno. */
191  }
192 
193  PIOS_SPI_SetClockSpeed(fpio_dev->spi_id, 15000000);
194 
195  PIOS_SPI_RC_PinSet(fpio_dev->spi_id, fpio_dev->spi_slave,
196  false);
197 
198  struct flyingpi_msg resp;
199  if (PIOS_SPI_TransferBlock(fpio_dev->spi_id, (uint8_t *)msg,
200  (uint8_t *)&resp, len)) {
201  ret = -1;
202  }
203 
204  PIOS_SPI_RC_PinSet(fpio_dev->spi_id, fpio_dev->spi_slave,
205  true);
206  PIOS_SPI_ReleaseBus(fpio_dev->spi_id);
207 
208  fpio_dev->last_msg_time = PIOS_DELAY_GetRaw();
209 
210  /* Handle response data-- after releasing SPI */
211  if (!ret) {
212  if (!flyingpi_calc_crc(&resp, false, NULL)) {
213  printf("fpio: VERYBAD: Bad CRC on response data %d\n\t",
214  fpio_dev->msg_num);
215 
216  uint8_t *msg_data = (void *) &resp;
217 
218  for (int i = 0; i < 16; i++) {
219  printf("%02x ", msg_data[i]);
220  }
221 
222  printf("\n");
223 
224  ret = -1;
225 
226  } else if (resp.id != FLYINGPIRESP_IO) {
227  printf("fpio: VERYBAD: Unexpected response message type\n");
228  ret = -1;
229  } else {
230  struct flyingpiresp_io_10 *data = &resp.body.io_10;
231  if (data->valid_messages_recvd != fpio_dev->msg_num) {
232  printf("fpio: BAD: sequence number mismatch %d vs %d\n", data->valid_messages_recvd, fpio_dev->msg_num);
233 
234  // Signal that caller should reconfig.
235  ret = -1;
236 
237  fpio_dev->msg_num = data->valid_messages_recvd;
238  } else {
239  for (int i = 0; i < FPPROTO_MAX_RCCHANS; i++) {
240  fpio_dev->rcvr_value[i] = data->chan_data[i];
241  }
242 
243  for (int i = 0; i < FPPROTO_MAX_ADCCHANS; i++) {
244  fpio_dev->adc_value[i] = data->adc_data[i];
245 #if 0
246  if (!(fpio_dev->msg_num & 1023)) {
247  printf("%d : %d\n", i, data->adc_data[i]);
248  }
249 #endif
250  }
251  }
252  }
253  fpio_dev->msg_num++;
254 
255  }
256 
257  if (!ret) {
258  fpio_dev->err_cnt = 0;
259  } else {
260  fpio_dev->err_cnt++;
261 
262  PIOS_Assert(fpio_dev->err_cnt < MAX_CONSEC_ERRS);
263  }
264 
265  return ret;
266 
267 }
268 
269 static void PIOS_FLYINGPIO_ActuatorUpdate()
270 {
271  /* Make sure we've already been configured */
272  PIOS_Assert(actuator_cfg.id == FLYINGPICMD_CFG);
273 
274  static int upd_num = 0;
275 
276  upd_num++;
277 
278  PIOS_Assert(!PIOS_FLYINGPIO_Validate(fpio_dev));
279 
280  struct flyingpi_msg tx_buf;
281 
282  tx_buf.id = FLYINGPICMD_ACTUATOR;
283 
284  struct flyingpicmd_actuator_fc *cmd = &tx_buf.body.actuator_fc;
285  struct flyingpicmd_cfg_fa *cfg = &actuator_cfg.body.cfg_fa;
286 
287  for (int i = 0; i < FPPROTO_MAX_SERVOS; i++) {
288  uint16_t span = cfg->actuators[i].max - cfg->actuators[i].min;
289  if (span == 0) {
290  // Prevent div by 0, this is a simple case.
291  cmd->values[i] = cfg->actuators[i].max;
292  } else {
293  float fraction = channel_values[i] -
294  cfg->actuators[i].min;
295 
296  fraction /= span;
297  fraction *= 65535.0f;
298  fraction += 0.5f;
299 
300  if (fraction > 65535) {
301  fraction = 65535;
302  } else if (fraction < 0) {
303  fraction = 0;
304  }
305 
306  cmd->values[i] = fraction;
307 
308 #if 0
309  if (!(upd_num & 1023)) {
310  printf("fpio: actuator: %d %f\n", i, fraction);
311  }
312 #endif
313  }
314  }
315 
316  cmd->led_status = PIOS_ANNUNC_GetStatus(PIOS_LED_HEARTBEAT);
317 
318  if (PIOS_FLYINGPIO_SendCmd(&tx_buf)) {
319  // If there's a sequence mismatch, reconfig.
320  PIOS_FLYINGPIO_SendCmd(&actuator_cfg);
321  PIOS_DELAY_WaituS(3 * MIN_QUIET_TIME);
322  }
323 }
324 
325 static int PIOS_FLYINGPIO_ActuatorSetMode(const uint16_t *out_rate,
326  const int banks, const uint16_t *channel_max,
327  const uint16_t *channel_min) {
328  actuator_cfg.id = FLYINGPICMD_CFG;
329 
330  struct flyingpicmd_cfg_fa *cmd = &actuator_cfg.body.cfg_fa;
331 
332  PIOS_Assert(banks >= FPPROTO_MAX_BANKS);
333 
334  for (int i = 0; i < FPPROTO_MAX_BANKS; i++) {
335  cmd->rate[i] = out_rate[i];
336  }
337 
338  for (int i = 0; i < ACTUATORCOMMAND_CHANNEL_NUMELEM; i++) {
339  uint16_t true_min, true_max;
340 
341  if (channel_min[i] > channel_max[i]) {
342  true_min = channel_max[i];
343  true_max = channel_min[i];
344  } else {
345  true_min = channel_min[i];
346  true_max = channel_max[i];
347  }
348 
349  cmd->actuators[i].min = true_min;
350  cmd->actuators[i].max = true_max;
351  }
352 
353  cmd->receiver_protocol = fpio_dev->protocol;
354 
355  while (PIOS_FLYINGPIO_SendCmd(&actuator_cfg)) { // retry until OK
357  }
358 
360 
361  return 0;
362 }
363 
364 static void PIOS_FLYINGPIO_ActuatorSet(uint8_t servo, float position) {
365  PIOS_Assert(servo < FPPROTO_MAX_SERVOS);
366 
367  channel_values[servo] = position;
368 }
369 
370 int32_t PIOS_FLYINGPIO_Receiver_Get(uintptr_t dev_int, uint8_t channel)
371 {
373 
374  if (channel >= FPPROTO_MAX_RCCHANS) {
375  return PIOS_RCVR_INVALID;
376  }
377 
378  return dev->rcvr_value[channel];
379 }
380 
381 static int32_t PIOS_FLYINGPIO_ADC_PinGet(uintptr_t dev_int, uint32_t pin) {
383 
384  if (pin >= FPPROTO_MAX_ADCCHANS) {
385  return -1;
386  }
387 
388  return dev->adc_value[pin];
389 }
390 
391 static uint8_t PIOS_FLYINGPIO_ADC_NumberOfChannels(uintptr_t dev_int) {
392  return FPPROTO_MAX_ADCCHANS;
393 }
394 
395 #define VREF_PLUS 3.3f
396 static float PIOS_FLYINGPIO_ADC_LSB_Voltage(uintptr_t dev_int) {
397  // Value is expected to be a fraction of 3V3
398  return VREF_PLUS / (((uint32_t)1 << 16) - 1);
399 }
400 
401 #endif // PIOS_INCLUDE_FLYINGPIO
402 
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
Main PiOS header to include all the compiled in PiOS options.
int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
uint16_t adc_data[FPPROTO_MAX_ADCCHANS]
int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
uint16_t values[FPPROTO_MAX_SERVOS]
int32_t PIOS_FLYINGPIO_Receiver_Get(uintptr_t dev_int, uint8_t channel)
Returns receiver data returned by flyingpio.
Task monitoring library.
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
#define FPPROTO_MAX_ADCCHANS
#define FLYINGPICMD_ACTUATOR
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
const struct pios_adc_driver pios_flyingpio_adc_driver
#define VREF_PLUS
Definition: pios_board.h:222
int32_t PIOS_SPI_SetClockSpeed(pios_spi_t spi_dev, uint32_t speed)
uint16_t rate[FPPROTO_MAX_BANKS]
int32_t PIOS_SPI_TransferBlock(pios_spi_t spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
int32_t PIOS_FLYINGPIO_SPI_Init(pios_flyingpio_dev_t *dev, pios_spi_t spi_id, uint32_t slave_idx, uint8_t protocol)
Initialize the FlyingPIO programmed-IO expander.
struct pios_flyingpio_dev * pios_flyingpio_dev_t
uint8_t i
Definition: msp_messages.h:97
void PIOS_Servo_SetCallbacks(const struct pios_servo_callbacks *cb)
#define FLYINGPIRESP_IO
#define FPPROTO_MAX_BANKS
#define FPPROTO_MAX_SERVOS
uint32_t magic
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
uint16_t servo[8]
Definition: msp_messages.h:96
Includes PiOS and core architecture components.
int printf(const char *format,...)
int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
static ManualControlCommandData cmd
const struct pios_rcvr_driver pios_flyingpio_rcvr_driver
#define PIOS_Assert(test)
Definition: pios_debug.h:52
#define FPPROTO_MAX_RCCHANS
static uint16_t msg_num
Definition: main.c:52
int32_t(* get_pin)(uintptr_t id, uint32_t pin)
Definition: pios_adc.h:41
uint16_t chan_data[FPPROTO_MAX_RCCHANS]
static bool flyingpi_calc_crc(struct flyingpi_msg *msg, bool fill_in, int *total_len)
int32_t PIOS_DELAY_WaituS(uint32_t uS)
Definition: pios_delay.c:116
struct flyingpicmd_cfg_fa::@15 actuators[FPPROTO_MAX_SERVOS]
#define PIOS_LED_HEARTBEAT
Definition: pios_board.h:85
uint32_t PIOS_DELAY_GetRaw()
Get the raw delay timer, useful for timing.
Definition: pios_delay.c:153
#define FLYINGPICMD_CFG