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/*---------------------------------------------------------------------------*/
70process_event_t ble_event_interface_added; /**< This event is broadcast when BLE connection is established */
71process_event_t ble_event_interface_deleted; /**< This event is broadcast when BLE connection is destroyed */
72
73/*---------------------------------------------------------------------------*/
74PROCESS(ble_ipsp_process, "BLE IPSP process");
75
76/*---------------------------------------------------------------------------*/
77/**
78 * \brief A structure that binds IPSP connection with a peer address.
79 */
80typedef struct {
81 eui64_t peer_addr;
82 ble_ipsp_handle_t handle;
83} ble_mac_interface_t;
84
85static ble_mac_interface_t interfaces[BLE_MAC_MAX_INTERFACE_NUM];
86
87static volatile int busy_tx; /**< Flag is set to 1 when the driver is busy transmitting a packet. */
88static volatile int busy_rx; /**< Flag is set to 1 when there is a received packet pending. */
89
90struct {
91 eui64_t src;
92 uint8_t payload[PACKETBUF_SIZE];
93 uint16_t len;
94 int8_t rssi;
96
97static mac_callback_t mac_sent_cb;
98static 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 */
108static ble_mac_interface_t *
109ble_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 */
132static ble_mac_interface_t *
133ble_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 */
151static void
152ble_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 */
168static uint32_t
169ble_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/*---------------------------------------------------------------------------*/
248PROCESS_THREAD(ble_ipsp_process, ev, data)
249{
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 */
275static ble_ipsp_handle_t *
276find_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 */
293static int
294send_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/*---------------------------------------------------------------------------*/
300static void
301send_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/*---------------------------------------------------------------------------*/
336static int
337on(void)
338{
339 return 1;
340}
341/*---------------------------------------------------------------------------*/
342static int
343off(void)
344{
345 return 1;
346}
347/*---------------------------------------------------------------------------*/
348static int
349max_payload(void)
350{
351 return PACKETBUF_SIZE;
352}
353/*---------------------------------------------------------------------------*/
354static void
355init(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,
376 NULL,
377 on,
378 off,
380};
381/*---------------------------------------------------------------------------*/
382/**
383 * @}
384 */
Basic BLE functions.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
const linkaddr_t linkaddr_null
The null link-layer address.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
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
process_event_t ble_event_interface_deleted
This event is broadcast when BLE connection is destroyed.
Definition: ble-mac.c:71
static ble_ipsp_handle_t * find_handle(const linkaddr_t *addr)
Lookup IPSP handle by peer address.
Definition: ble-mac.c:276
#define BLE_MAC_MAX_INTERFACE_NUM
Maximum number of interfaces, i.e., connection to master devices.
Definition: ble-mac.c:66
static volatile int busy_rx
Flag is set to 1 when there is a received packet pending.
Definition: ble-mac.c:88
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
static int send_to_peer(ble_ipsp_handle_t *handle)
Send packet on a given IPSP handle.
Definition: ble-mac.c:294
static ble_mac_interface_t * ble_mac_interface_lookup(ble_ipsp_handle_t *handle)
Lookup interface by IPSP connection.
Definition: ble-mac.c:109
static volatile int busy_tx
Flag is set to 1 when the driver is busy transmitting a packet.
Definition: ble-mac.c:87
static void ble_mac_interface_delete(ble_mac_interface_t *interface)
Remove interface from the interface table.
Definition: ble-mac.c:152
process_event_t ble_event_interface_added
This event is broadcast when BLE connection is established.
Definition: ble-mac.c:70
const struct mac_driver ble_ipsp_mac_driver
BLE over IPSP MAC driver structure.
Definition: ble-mac.c:372
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
Definition: packetbuf.c:84
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
static void send_packet(linkaddr_t *dest)
This function is called by the 6lowpan code to send out a packet.
Definition: sicslowpan.c:1548
Header file for the link-layer address representation.
@ MAC_TX_OK
The MAC layer transmission was OK.
Definition: mac.h:87
@ MAC_TX_ERR
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:101
Include file for the Contiki low-layer network stack (NETSTACK)
A MAC protocol implementation that does not do anything.
Header file for the Packet buffer (packetbuf) management.
Stores data about an incoming packet.
Definition: tsch-types.h:149
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:62
int(* on)(void)
Turn the MAC layer on.
Definition: mac.h:75
int(* max_payload)(void)
Read out estimated max payload size based on payload in packetbuf.
Definition: mac.h:81
int(* off)(void)
Turn the MAC layer off.
Definition: mac.h:78
void(* init)(void)
Initialize the MAC driver.
Definition: mac.h:66
Header for the Contiki/uIP interface.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
Header file for the uIP TCP/IP stack.