Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
bluegiga.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Kirk Scheper <kirkscheper@gmail.com>
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22 
28 #include "mcu_periph/sys_time.h"
30 #include "mcu_periph/gpio.h"
31 #include "mcu_periph/spi.h"
32 
33 #ifdef MODEM_LED
34 #include "led.h"
35 #endif
36 
37 #include "modules/core/abi.h"
38 
39 // for memset
40 #include <string.h>
41 
42 #ifndef BLUEGIGA_SPI_DEV
43 #error "bluegiga: must define a BLUEGIGA_SPI_DEV"
44 #endif
45 
46 // Bluegiga: DRDY defaults to SuperbitRf DRDY
47 #ifndef BLUEGIGA_DRDY_GPIO
48 #define BLUEGIGA_DRDY_GPIO SUPERBITRF_DRDY_PORT
49 #endif
50 
51 #ifndef BLUEGIGA_DRDY_GPIO_PIN
52 #define BLUEGIGA_DRDY_GPIO_PIN SUPERBITRF_DRDY_PIN
53 #endif
54 
55 #define TxStrengthOfSender(x) (x[1])
56 #define RssiOfSender(x) (x[2])
57 #define Pprz_StxOfMsg(x) (x[3])
58 #define SenderIdOfBGMsg(x) (x[5])
59 
63 
65 
66 void bluegiga_load_tx(struct bluegiga_periph *p);
67 void bluegiga_transmit(struct bluegiga_periph *p, uint8_t data);
68 void bluegiga_receive(struct spi_transaction *trans);
69 
70 // Functions for the generic link device device API
71 static int dev_check_free_space(struct bluegiga_periph *p, long *fd __attribute__((unused)), uint16_t len)
72 {
73  // check if there is enough space for message
74  // NB if BLUEGIGA_BUFFER_SIZE is smaller than 256 then an additional check is needed that len < BLUEGIGA_BUFFER_SIZE
75  if (len - 1 <= ((p->tx_extract_idx - p->tx_insert_idx - 1 + BLUEGIGA_BUFFER_SIZE) % BLUEGIGA_BUFFER_SIZE)) {
76  return true;
77  }
78 
79  return false;
80 }
81 static void dev_put_buffer(struct bluegiga_periph *p, long fd __attribute__((unused)), uint8_t *data, uint16_t len)
82 {
83  int i;
84  for (i = 0; i < len; i++) {
85  bluegiga_transmit(p, data[i]);
86  }
87 }
88 static void dev_put_byte(struct bluegiga_periph *p, long fd __attribute__((unused)), uint8_t byte)
89 {
90  bluegiga_transmit(p, byte);
91 }
92 static void dev_send_message(struct bluegiga_periph *p, long fd __attribute__((unused)))
93 {
94  p->end_of_msg = p->tx_insert_idx;
95 }
97 {
98  return bluegiga_ch_available(p);
99 }
100 
101 // note, need to run dev_char_available first
103 {
104  uint8_t ret = p->rx_buf[p->rx_extract_idx];
105  bluegiga_increment_buf(&p->rx_extract_idx, 1);
106  return ret;
107 }
108 
109 // Functions for the generic spi device API
110 static void trans_cb(struct spi_transaction *trans)
111 {
112  bluegiga_receive(trans);
113 }
114 
115 /* check if character available in receive buffer */
117 {
118  return (p->rx_extract_idx != p->rx_insert_idx);
119 }
120 
121 /* safe increment of circular buffer */
123 {
124  *buf_idx = (*buf_idx + len) % BLUEGIGA_BUFFER_SIZE;
125 }
126 
128 #if PERIODIC_TELEMETRY
130 
132 static void send_bluegiga(struct transport_tx *trans, struct link_device *dev)
133 {
134  uint32_t now_ts = get_sys_time_msec();
135 
136  if (now_ts > last_ts) {
137  uint32_t rate = 1000 * bluegiga_p.bytes_recvd_since_last / (now_ts - last_ts);
138  uint32_t a2a_rate = 1000 * a2a_msgs / (now_ts - last_ts);
139  pprz_msg_send_BLUEGIGA(trans, dev, AC_ID, &rate, &a2a_rate);
140 
141  a2a_msgs = 0;
143  last_ts = now_ts;
144  }
145 }
146 #endif
147 
149 {
150 #ifdef MODEM_LED
151  LED_INIT(MODEM_LED);
152 #endif
153 
154  // configure the SPI bus
155  bluegiga_spi.input_buf = p->work_rx;
156  bluegiga_spi.output_buf = p->work_tx;
159  bluegiga_spi.slave_idx = 0; // Not used for SPI-Slave: always NSS pin
167 
168  // Configure generic link device
169  p->device.periph = (void *)(p);
170  p->device.check_free_space = (check_free_space_t) dev_check_free_space;
171  p->device.put_byte = (put_byte_t) dev_put_byte;
172  p->device.put_buffer = (put_buffer_t) dev_put_buffer;
173  p->device.send_message = (send_message_t) dev_send_message;
174  p->device.char_available = (char_available_t) dev_char_available;
175  p->device.get_byte = (get_byte_t) dev_get_byte;
176 
177  // initialize peripheral variables
178  p->rx_insert_idx = 0;
179  p->rx_extract_idx = 0;
180  p->tx_insert_idx = 0;
181  p->tx_extract_idx = 0;
182 
183  memset(p->work_rx, 0, bluegiga_spi.input_length);
184  memset(p->work_tx, 0, bluegiga_spi.output_length);
185 
186  memset(broadcast_msg, 0, 19);
187 
188  p->bytes_recvd_since_last = 0;
189  p->end_of_msg = p->tx_insert_idx;
190  p->connected = 0;
191 
192  // set DRDY interrupt pin for spi master triggered on falling edge
195 
197 
198 #if PERIODIC_TELEMETRY
200 #endif
201 
202  // register spi slave read for transaction
203  spi_slave_register(&(BLUEGIGA_SPI_DEV), &bluegiga_spi);
204 }
205 
206 /* Add one byte to the end of tx circular buffer */
208 {
209  long fd = 0;
211  p->tx_buf[p->tx_insert_idx] = data;
212  bluegiga_increment_buf(&p->tx_insert_idx, 1);
213  }
214 }
215 
216 /* Load waiting data into tx peripheral buffer */
218 {
219  uint8_t packet_len;
220  // check data available in buffer to send
221  packet_len = ((p->end_of_msg - p->tx_extract_idx + BLUEGIGA_BUFFER_SIZE) % BLUEGIGA_BUFFER_SIZE);
222  if (packet_len > 19) {
223  packet_len = 19;
224  }
225 
226  if (packet_len && coms_status == BLUEGIGA_IDLE) {
227  uint8_t i;
228  // attach header with data length of real data in 20 char data string
229  p->work_tx[0] = packet_len;
230 
231  // copy data from working buffer to spi output buffer
232  for (i = 0; i < packet_len; i++) {
233  p->work_tx[i + 1] = p->tx_buf[(p->tx_extract_idx + i) % BLUEGIGA_BUFFER_SIZE];
234  }
235  bluegiga_increment_buf(&p->tx_extract_idx, packet_len);
236 
237  // clear unused bytes
238  for (i = packet_len + 1; i < BLUEGIGA_SPI_BUF_SIZE; i++) {
239  p->work_tx[i] = 0;
240  }
241 
243  }
244 }
245 
246 /* read data from dma if available, set as call back of successful spi exchange
247  *
248  * TODO Remove use of bluegiga_p global in following function
249  */
251 {
252  if (trans->status == SPITransSuccess) {
253  // handle successful msg send
254  if (coms_status == BLUEGIGA_SENDING) {
255  // empty transfer buffer
256  for (uint8_t i = 0; i < trans->output_length; i++) {
257  trans->output_buf[i] = 0;
258  }
259  } else if (coms_status == BLUEGIGA_SENDING_BROADCAST) {
260  // sending second half of broadcast message
261  for (uint8_t i = 0; i < broadcast_msg[0]; i++) {
262  trans->output_buf[i] = broadcast_msg[i];
263  }
265  return;
266  }
267 
268  /*
269  * >235 data package from broadcast mode
270  * 0x50 communication lost with ground station
271  * 0x51 interrupt handled
272  * <20 data package from connection
273  */
274 
275  uint8_t packet_len = 0;
276  uint8_t read_offset = 0;
277  switch (trans->input_buf[0]) {
278  case 0x50: // communication status changed
279  bluegiga_p.connected = trans->input_buf[1];
280  if (bluegiga_p.connected) {
281  //telemetry_mode_Main = TELEMETRY_PROCESS_Main;
282  } else {
283  //telemetry_mode_Main = NB_TELEMETRY_MODES; // send no periodic telemetry
284  }
286  break;
287  case 0x51: // Interrupt handled
288  gpio_set(BLUEGIGA_DRDY_GPIO, BLUEGIGA_DRDY_GPIO_PIN); // Reset interrupt pin
289  break;
290  default:
292  // compute length of transmitted message
293  if (trans->input_buf[0] < trans->input_length) { // normal connection mode
294  packet_len = trans->input_buf[0];
295  read_offset = 1;
296  } else if (trans->input_buf[0] > 0xff - trans->input_length) { // broadcast mode
297  packet_len = 0xff - trans->input_buf[0];
298 
299  if (packet_len > 3)
300  {
301 #ifdef MODEM_LED
302  LED_TOGGLE(MODEM_LED);
303 #endif
304 
305  int8_t tx_strength = TxStrengthOfSender(trans->input_buf);
306  int8_t rssi = RssiOfSender(trans->input_buf);
307  uint8_t ac_id = SenderIdOfBGMsg(trans->input_buf);
308 
309  if (Pprz_StxOfMsg(trans->input_buf) == PPRZ_STX) {
310  AbiSendMsgRSSI(RSSI_BLUEGIGA_ID, ac_id, tx_strength, rssi);
311  }
312  a2a_msgs++;
313  }
314 
315  read_offset = 3;
316  }
317  }
318 
319  // handle incoming datalink message
320  if (packet_len > 0 && packet_len <= trans->input_length - read_offset) {
321 //#ifdef MODEM_LED
322 // LED_TOGGLE(MODEM_LED);
323 //#endif
324  // Handle received message
325  for (uint8_t i = 0; i < packet_len; i++) {
326  bluegiga_p.rx_buf[(bluegiga_p.rx_insert_idx + i) % BLUEGIGA_BUFFER_SIZE] = trans->input_buf[i + read_offset];
327  }
329  bluegiga_p.bytes_recvd_since_last += packet_len;
330  }
331 
332  // load next message to be sent into work buffer, needs to be loaded before calling spi_slave_register
334 
335  // register spi slave read for next transaction
336  spi_slave_register(&(BLUEGIGA_SPI_DEV), trans);
337  }
338 }
339 
340 /* Send data for broadcast message to the bluegiga module
341  * maximum size of message is 22 bytes
342  */
343 void bluegiga_broadcast_msg(struct bluegiga_periph *p, char *msg, uint8_t msg_len)
344 {
345  if (msg_len == 0 || msg_len > 22) {
346  return;
347  }
348 
349  uint8_t max_length = 20;
350  p->work_tx[0] = msg_len;
351 
352  if (msg_len < max_length) {
353  for (uint8_t i = 0; i < msg_len; i++) {
354  p->work_tx[i + 1] = msg[i];
355  }
357  } else {
358  for (uint8_t i = 0; i < max_length - 1; i++) {
359  p->work_tx[i + 1] = msg[i];
360  }
361 
362  memcpy(broadcast_msg, msg + max_length - 1, msg_len - (max_length - 1));
364  }
365 
366  // trigger bluegiga to read direct command
368 }
Main include for ABI (AirBorneInterface).
#define RSSI_BLUEGIGA_ID
#define BLUEGIGA_DRDY_GPIO_PIN
Definition: bluegiga.c:52
uint32_t last_ts
Definition: bluegiga.c:131
#define TxStrengthOfSender(x)
Definition: bluegiga.c:55
static void dev_put_byte(struct bluegiga_periph *p, long fd, uint8_t byte)
Definition: bluegiga.c:88
static void send_bluegiga(struct transport_tx *trans, struct link_device *dev)
Definition: bluegiga.c:132
static uint8_t dev_get_byte(struct bluegiga_periph *p)
Definition: bluegiga.c:102
void bluegiga_broadcast_msg(struct bluegiga_periph *p, char *msg, uint8_t msg_len)
Definition: bluegiga.c:343
static void dev_send_message(struct bluegiga_periph *p, long fd)
Definition: bluegiga.c:92
#define SenderIdOfBGMsg(x)
Definition: bluegiga.c:58
static void dev_put_buffer(struct bluegiga_periph *p, long fd, uint8_t *data, uint16_t len)
Definition: bluegiga.c:81
void bluegiga_receive(struct spi_transaction *trans)
Definition: bluegiga.c:250
#define Pprz_StxOfMsg(x)
Definition: bluegiga.c:57
enum BlueGigaStatus coms_status
Definition: bluegiga.c:60
#define BLUEGIGA_DRDY_GPIO
Definition: bluegiga.c:48
bool bluegiga_ch_available(struct bluegiga_periph *p)
Definition: bluegiga.c:116
static int dev_check_free_space(struct bluegiga_periph *p, long *fd, uint16_t len)
Definition: bluegiga.c:71
struct spi_transaction bluegiga_spi
Definition: bluegiga.c:62
static void trans_cb(struct spi_transaction *trans)
Definition: bluegiga.c:110
uint8_t broadcast_msg[20]
Definition: bluegiga.c:64
void bluegiga_load_tx(struct bluegiga_periph *p)
Definition: bluegiga.c:217
static int dev_char_available(struct bluegiga_periph *p)
Definition: bluegiga.c:96
uint32_t a2a_msgs
Definition: bluegiga.c:127
void bluegiga_transmit(struct bluegiga_periph *p, uint8_t data)
Definition: bluegiga.c:207
struct bluegiga_periph bluegiga_p
Definition: bluegiga.c:61
void bluegiga_init(struct bluegiga_periph *p)
Definition: bluegiga.c:148
#define RssiOfSender(x)
Definition: bluegiga.c:56
void bluegiga_increment_buf(uint8_t *buf_idx, uint8_t len)
Definition: bluegiga.c:122
Bluegiga Bluetooth chip I/O.
BlueGigaStatus
Definition: bluegiga.h:35
@ BLUEGIGA_SENDING_BROADCAST
The com is switched from data link to rssi scanning.
Definition: bluegiga.h:39
@ BLUEGIGA_IDLE
The com is in idle.
Definition: bluegiga.h:37
@ BLUEGIGA_UNINIT
The com isn't initialized.
Definition: bluegiga.h:36
@ BLUEGIGA_SENDING
The com is sending.
Definition: bluegiga.h:38
#define BLUEGIGA_SPI_BUF_SIZE
Definition: bluegiga.h:50
uint8_t connected
Definition: bluegiga.h:70
uint8_t rx_buf[BLUEGIGA_BUFFER_SIZE]
Definition: bluegiga.h:54
uint8_t rx_insert_idx
Definition: bluegiga.h:55
uint32_t bytes_recvd_since_last
Definition: bluegiga.h:68
#define BLUEGIGA_BUFFER_SIZE
Definition: bluegiga.h:43
static uint16_t rssi
Definition: cc2500_rx.c:85
#define LED_INIT(i)
Definition: led_hw.h:50
#define LED_TOGGLE(i)
Definition: led_hw.h:53
void gpio_setup_output(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as outputs.
Definition: gpio_arch.c:33
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition: gpio_arch.h:98
static void gpio_clear(ioportid_t port, uint16_t pin)
Clear a gpio output to low level.
Definition: gpio_arch.h:108
uint32_t get_sys_time_msec(void)
Get the time in milliseconds since startup.
Definition: sys_time_arch.c:98
Some architecture independent helper functions for GPIOs.
enum SPIClockPolarity cpol
clock polarity control
Definition: spi.h:155
enum SPIClockPhase cpha
clock phase control
Definition: spi.h:156
enum SPISlaveSelect select
slave selection behavior
Definition: spi.h:154
SPICallback after_cb
NULL or function called after the transaction.
Definition: spi.h:161
enum SPIDataSizeSelect dss
data transfer word size
Definition: spi.h:157
volatile uint8_t * output_buf
pointer to transmit buffer for DMA
Definition: spi.h:150
uint16_t input_length
number of data words to read
Definition: spi.h:151
enum SPIClockDiv cdiv
prescaler of main clock to use as SPI clock
Definition: spi.h:159
volatile uint8_t * input_buf
pointer to receive buffer for DMA
Definition: spi.h:149
uint8_t slave_idx
slave id: SPI_SLAVE0 to SPI_SLAVE4
Definition: spi.h:153
enum SPIBitOrder bitorder
MSB/LSB order.
Definition: spi.h:158
uint16_t output_length
number of data words to write
Definition: spi.h:152
enum SPITransactionStatus status
Definition: spi.h:162
void(* SPICallback)(struct spi_transaction *trans)
SPI Callback function.
Definition: spi.h:136
bool spi_slave_register(struct spi_periph *periph, struct spi_transaction *trans)
Register a spi transaction in slave mode (only one transaction can be registered).
Definition: spi_arch.c:1624
@ SPICphaEdge2
CPHA = 1.
Definition: spi.h:75
@ SPITransSuccess
Definition: spi.h:99
@ SPICpolIdleHigh
CPOL = 1.
Definition: spi.h:84
@ SPISelectUnselect
slave is selected before transaction and unselected after
Definition: spi.h:63
@ SPIMSBFirst
Definition: spi.h:112
@ SPIDiv256
Definition: spi.h:127
@ SPIDss8bit
Definition: spi.h:90
SPI transaction structure.
Definition: spi.h:148
uint8_t msg[10]
Buffer used for general comunication over SPI (out buffer)
static float p[2][2]
arch independent LED (Light Emitting Diodes) API
int fd
Definition: serial.c:26
Architecture independent SPI (Serial Peripheral Interface) API.
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
Architecture independent timing functions.
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
signed char int8_t
Typedef defining 8 bit char type.
Definition: vl53l1_types.h:103