Contiki-NG
ble-mac.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Nordic Semiconductor
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 /**
31  * \addtogroup nrf52832-ble
32  * @{
33  *
34  * \file
35  * A MAC protocol implementation that uses nRF52 IPSP implementation
36  * as a link layer.
37  * \author
38  * Wojciech Bober <wojciech.bober@nordicsemi.no>
39  */
40 #include <stdint.h>
41 #include <ble-core.h>
42 #include "app_error.h"
43 #include "ble_ipsp.h"
44 #include "nrf_soc.h"
45 #include "iot_defines.h"
46 
48 #include "net/netstack.h"
49 #include "net/ipv6/uip.h"
50 #include "net/ipv6/tcpip.h"
51 #include "net/packetbuf.h"
52 #include "net/netstack.h"
53 #include "net/linkaddr.h"
54 
55 #include "dev/watchdog.h"
56 
57 #define DEBUG 0
58 #if DEBUG
59 #include <stdio.h>
60 #define PRINTF(...) printf(__VA_ARGS__)
61 #else
62 #define PRINTF(...)
63 #endif
64 
65 #ifndef BLE_MAC_MAX_INTERFACE_NUM
66 #define BLE_MAC_MAX_INTERFACE_NUM 1 /**< Maximum number of interfaces, i.e., connection to master devices */
67 #endif
68 
69 /*---------------------------------------------------------------------------*/
70 process_event_t ble_event_interface_added; /**< This event is broadcast when BLE connection is established */
71 process_event_t ble_event_interface_deleted; /**< This event is broadcast when BLE connection is destroyed */
72 
73 /*---------------------------------------------------------------------------*/
74 PROCESS(ble_ipsp_process, "BLE IPSP process");
75 
76 /*---------------------------------------------------------------------------*/
77 /**
78  * \brief A structure that binds IPSP connection with a peer address.
79  */
80 typedef struct {
81  eui64_t peer_addr;
82  ble_ipsp_handle_t handle;
83 } ble_mac_interface_t;
84 
85 static ble_mac_interface_t interfaces[BLE_MAC_MAX_INTERFACE_NUM];
86 
87 static volatile int busy_tx; /**< Flag is set to 1 when the driver is busy transmitting a packet. */
88 static volatile int busy_rx; /**< Flag is set to 1 when there is a received packet pending. */
89 
90 struct {
91  eui64_t src;
92  uint8_t payload[PACKETBUF_SIZE];
93  uint16_t len;
94  int8_t rssi;
95 } input_packet;
96 
97 static mac_callback_t mac_sent_cb;
98 static void *mac_sent_ptr;
99 
100 /*---------------------------------------------------------------------------*/
101 /**
102  * \brief Lookup interface by IPSP connection.
103  *
104  * \param handle a pointer to IPSP handle.
105  * \retval a pointer to interface structure
106  * \retval NULL if no interface has been found for a given handle
107  */
108 static ble_mac_interface_t *
109 ble_mac_interface_lookup(ble_ipsp_handle_t *handle)
110 {
111  int i;
112  for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
113  if(interfaces[i].handle.conn_handle == handle->conn_handle &&
114  interfaces[i].handle.cid == handle->cid) {
115  return &interfaces[i];
116  }
117  }
118  return NULL;
119 }
120 /*---------------------------------------------------------------------------*/
121 /**
122  * \brief Add IPSP connection to the interface table.
123  *
124  * This function binds IPSP connection with peer address.
125  *
126  * \param peer a pointer to eui64 address
127  * \param handle a pointer to IPSP handle
128  *
129  * \retval a pointer to an interface structure on success
130  * \retval NULL if interface table is full
131  */
132 static ble_mac_interface_t *
133 ble_mac_interface_add(eui64_t *peer, ble_ipsp_handle_t *handle)
134 {
135  int i;
136  for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
137  if(interfaces[i].handle.conn_handle == 0 && interfaces[i].handle.cid == 0) {
138  memcpy(&interfaces[i].handle, handle, sizeof(ble_ipsp_handle_t));
139  memcpy(&interfaces[i].peer_addr, peer, sizeof(eui64_t));
140  process_post(PROCESS_BROADCAST, ble_event_interface_added, NULL);
141  return &interfaces[i];
142  }
143  }
144  return NULL;
145 }
146 /*---------------------------------------------------------------------------*/
147 /**
148  * \brief Remove interface from the interface table.
149  * \param interface a pointer to interface
150  */
151 static void
152 ble_mac_interface_delete(ble_mac_interface_t *interface)
153 {
154  memset(interface, 0, sizeof(ble_mac_interface_t));
155  process_post(PROCESS_BROADCAST, ble_event_interface_deleted, NULL);
156 }
157 
158 /*---------------------------------------------------------------------------*/
159 /**
160  * \brief Callback registered with IPSP to receive asynchronous events from the module.
161  * \note This function is called from SoftDevice interrupt context.
162  *
163  * \param[in] p_handle Pointer to IPSP handle.
164  * \param[in] p_evt Pointer to specific event, generated by IPSP module.
165  *
166  * \return NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
167  */
168 static uint32_t
169 ble_mac_ipsp_evt_handler_irq(ble_ipsp_handle_t *p_handle, ble_ipsp_evt_t *p_evt)
170 {
171  uint32_t retval = NRF_SUCCESS;
172 
173  ble_mac_interface_t *p_instance = NULL;
174  p_instance = ble_mac_interface_lookup(p_handle);
175 
176  if(p_handle) {
177  PRINTF("ble-mac: IPSP event [handle:%d CID 0x%04X]\n", p_handle->conn_handle, p_handle->cid);
178  }
179 
180  switch(p_evt->evt_id) {
181  case BLE_IPSP_EVT_CHANNEL_CONNECTED: {
182  eui64_t peer_addr;
183 
184  PRINTF("ble-mac: channel connected\n");
185 
186  IPV6_EUI64_CREATE_FROM_EUI48(
187  peer_addr.identifier,
188  p_evt->evt_param->params.ch_conn_request.peer_addr.addr,
189  p_evt->evt_param->params.ch_conn_request.peer_addr.addr_type);
190 
191  p_instance = ble_mac_interface_add(&peer_addr, p_handle);
192 
193  if(p_instance != NULL) {
194  PRINTF("ble-mac: added new IPSP interface\n");
195  } else {
196  PRINTF("ble-mac: cannot add new interface. Table is full\n");
197  ble_ipsp_disconnect(p_handle);
198  }
199  break;
200  }
201 
202  case BLE_IPSP_EVT_CHANNEL_DISCONNECTED: {
203  PRINTF("ble-mac: channel disconnected\n");
204  if(p_instance != NULL) {
205  PRINTF("ble-mac: removed IPSP interface\n");
206  ble_mac_interface_delete(p_instance);
207  }
208  break;
209  }
210 
211  case BLE_IPSP_EVT_CHANNEL_DATA_RX: {
212  PRINTF("ble-mac: data received\n");
213  if(p_instance != NULL) {
214  if(busy_rx) {
215  PRINTF("ble-mac: packet dropped as input buffer is busy\n");
216  break;
217  }
218 
219  if(p_evt->evt_param->params.ch_rx.len > PACKETBUF_SIZE) {
220  PRINTF("ble-mac: packet buffer is too small!\n");
221  break;
222  }
223 
224  busy_rx = 1;
225 
226  input_packet.len = p_evt->evt_param->params.ch_rx.len;
227  memcpy(input_packet.payload, p_evt->evt_param->params.ch_rx.p_data, input_packet.len);
228  memcpy(input_packet.src.identifier, p_instance->peer_addr.identifier, sizeof(eui64_t));
229  sd_ble_gap_rssi_get(p_handle->conn_handle, &input_packet.rssi);
230 
231  process_poll(&ble_ipsp_process);
232  } else {
233  PRINTF("ble-mac: got data to unknown interface!\n");
234  }
235  break;
236  }
237 
238  case BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE: {
239  PRINTF("ble-mac: data transmitted\n");
240  busy_tx = 0;
241  break;
242  }
243  }
244 
245  return retval;
246 }
247 /*---------------------------------------------------------------------------*/
248 PROCESS_THREAD(ble_ipsp_process, ev, data)
249 {
250  PROCESS_BEGIN();
251 
252  while(1) {
254  if(ev == PROCESS_EVENT_POLL) {
256  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, input_packet.rssi);
257  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (const linkaddr_t *)input_packet.src.identifier);
258  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &linkaddr_node_addr);
259  busy_rx = 0;
260  NETSTACK_NETWORK.input();
261  }
262  }
263 
264  PROCESS_END();
265 }
266 
267 /*---------------------------------------------------------------------------*/
268 /**
269  * \brief Lookup IPSP handle by peer address.
270  *
271  * \param addr a pointer to eui64 address.
272  * \retval a pointer to IPSP handle on success
273  * \retval NULL if an IPSP handle for given address haven't been found
274  */
275 static ble_ipsp_handle_t *
276 find_handle(const linkaddr_t *addr)
277 {
278  int i;
279  for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
280  if(linkaddr_cmp((const linkaddr_t *)&interfaces[i].peer_addr, addr)) {
281  return &interfaces[i].handle;
282  }
283  }
284  return NULL;
285 }
286 /*---------------------------------------------------------------------------*/
287 /**
288  * \brief Send packet on a given IPSP handle.
289  *
290  * \param handle a pointer to IPSP handle.
291  * \return 1 on success, 0 otherwise
292  */
293 static int
294 send_to_peer(ble_ipsp_handle_t *handle)
295 {
296  PRINTF("ble-mac: sending packet[GAP handle:%d CID:0x%04X]\n", handle->conn_handle, handle->cid);
297  return (ble_ipsp_send(handle, packetbuf_dataptr(), packetbuf_datalen()) == NRF_SUCCESS);
298 }
299 /*---------------------------------------------------------------------------*/
300 static void
301 send_packet(mac_callback_t sent, void *ptr)
302 {
303  int i;
304  const linkaddr_t *dest;
305  ble_ipsp_handle_t *handle;
306  int ret = 0;
307 
308  mac_sent_cb = sent;
309  mac_sent_ptr = ptr;
310 
311  dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
312 
313  if(linkaddr_cmp(dest, &linkaddr_null)) {
314  for(i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) {
315  if(interfaces[i].handle.cid != 0 && interfaces[i].handle.conn_handle != 0) {
316  ret = send_to_peer(&interfaces[i].handle);
317  }
318  }
319  } else if((handle = find_handle(dest)) != NULL) {
320  ret = send_to_peer(handle);
321  } else {
322  PRINTF("ble-mac: no connection found for peer");
323  }
324 
325  if(ret) {
326  busy_tx = 1;
327  while(busy_tx) {
328  sd_app_evt_wait();
329  }
330  mac_call_sent_callback(sent, ptr, MAC_TX_OK, 1);
331  } else {
332  mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1);
333  }
334 }
335 /*---------------------------------------------------------------------------*/
336 static int
337 on(void)
338 {
339  return 1;
340 }
341 /*---------------------------------------------------------------------------*/
342 static int
343 off(void)
344 {
345  return 1;
346 }
347 /*---------------------------------------------------------------------------*/
348 static int
349 max_payload(void)
350 {
351  return PACKETBUF_SIZE;
352 }
353 /*---------------------------------------------------------------------------*/
354 static void
355 init(void)
356 {
357 // Initialize IPSP service
358  uint32_t err_code;
359  ble_ipsp_init_t ipsp_init_params;
360 
361  memset(&ipsp_init_params, 0, sizeof(ipsp_init_params));
362  ipsp_init_params.evt_handler = ble_mac_ipsp_evt_handler_irq;
363  err_code = ble_ipsp_init(&ipsp_init_params);
364  APP_ERROR_CHECK(err_code);
365 
368 
369  process_start(&ble_ipsp_process, NULL);
370 }
371 /*---------------------------------------------------------------------------*/
373  "nRF52 IPSP driver",
374  init,
375  send_packet,
376  NULL,
377  on,
378  off,
380 };
381 /*---------------------------------------------------------------------------*/
382 /**
383  * @}
384  */
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
Header for the Contiki/uIP interface.
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
static int send_to_peer(ble_ipsp_handle_t *handle)
Send packet on a given IPSP handle.
Definition: ble-mac.c:294
int(* on)(void)
Turn the MAC layer on.
Definition: mac.h:75
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:62
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
static ble_mac_interface_t * ble_mac_interface_lookup(ble_ipsp_handle_t *handle)
Lookup interface by IPSP connection.
Definition: ble-mac.c:109
Header file for the link-layer address representation
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
static void send_packet(linkaddr_t *dest)
This function is called by the 6lowpan code to send out a packet.
Definition: sicslowpan.c:1491
process_event_t ble_event_interface_added
This event is broadcast when BLE connection is established.
Definition: ble-mac.c:70
#define BLE_MAC_MAX_INTERFACE_NUM
Maximum number of interfaces, i.e., connection to master devices.
Definition: ble-mac.c:66
const linkaddr_t linkaddr_null
The null link-layer address.
The MAC layer transmission was OK.
Definition: mac.h:87
int(* off)(void)
Turn the MAC layer off.
Definition: mac.h:78
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
static volatile int busy_rx
Flag is set to 1 when there is a received packet pending.
Definition: ble-mac.c:88
A MAC protocol implementation that does not do anything.
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
process_event_t ble_event_interface_deleted
This event is broadcast when BLE connection is destroyed.
Definition: ble-mac.c:71
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
static volatile int busy_tx
Flag is set to 1 when the driver is busy transmitting a packet.
Definition: ble-mac.c:87
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
Definition: packetbuf.c:84
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:101
void(* init)(void)
Initialize the network driver.
Definition: netstack.h:121
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
static void ble_mac_interface_delete(ble_mac_interface_t *interface)
Remove interface from the interface table.
Definition: ble-mac.c:152
Header file for the uIP TCP/IP stack.
const struct mac_driver ble_ipsp_mac_driver
BLE over IPSP MAC driver structure.
Definition: ble-mac.c:372
static ble_ipsp_handle_t * find_handle(const linkaddr_t *addr)
Lookup IPSP handle by peer address.
Definition: ble-mac.c:276
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
Header file for the Packet buffer (packetbuf) management
static uint32_t ble_mac_ipsp_evt_handler_irq(ble_ipsp_handle_t *p_handle, ble_ipsp_evt_t *p_evt)
Callback registered with IPSP to receive asynchronous events from the module.
Definition: ble-mac.c:169
Include file for the Contiki low-layer network stack (NETSTACK)
int(* max_payload)(void)
Read out estimated max payload size based on payload in packetbuf.
Definition: mac.h:81
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1107
Stores data about an incoming packet.
Definition: tsch-types.h:152
static ble_mac_interface_t * ble_mac_interface_add(eui64_t *peer, ble_ipsp_handle_t *handle)
Add IPSP connection to the interface table.
Definition: ble-mac.c:133
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
Basic BLE functions.