From 7a7c4e0015cba254841ead6b86193e83adf4053b Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 6 Dec 2017 16:10:58 +0100 Subject: [PATCH 1/9] added support for IPv6 over BLE communication --- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 4 +- arch/cpu/cc26xx-cc13xx/ble-addr.c | 67 ++ arch/cpu/cc26xx-cc13xx/ble-addr.h | 61 + arch/cpu/cc26xx-cc13xx/dev/ble-hal.h | 395 +++++++ arch/cpu/cc26xx-cc13xx/rf-core/README.md | 84 ++ arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c | 278 +++++ .../rf-core/ble-hal/ble-hal-cc26xx.c | 1016 +++++++++++++++++ .../rf-core/ble-hal/ble-hal-cc26xx.h | 47 + .../rf-core/ble-hal/rf-ble-cmd.c | 249 ++++ .../rf-core/ble-hal/rf-ble-cmd.h | 75 ++ arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c | 666 +++++++++++ arch/platform/srf06-cc26xx/contiki-conf.h | 6 +- arch/platform/srf06-cc26xx/platform.c | 9 +- .../cc26xx/cc26xx-ble-client-demo/Makefile | 9 + .../cc26xx/cc26xx-ble-client-demo/README.md | 28 + .../cc26xx/cc26xx-ble-client-demo/client.c | 134 +++ .../cc26xx-ble-client-demo/project-conf.h | 79 ++ os/contiki-main.c | 4 +- 18 files changed, 3205 insertions(+), 6 deletions(-) create mode 100644 arch/cpu/cc26xx-cc13xx/ble-addr.c create mode 100644 arch/cpu/cc26xx-cc13xx/ble-addr.h create mode 100644 arch/cpu/cc26xx-cc13xx/dev/ble-hal.h create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/README.md create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h create mode 100644 arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c create mode 100644 examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile create mode 100644 examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md create mode 100644 examples/platform-specific/cc26xx/cc26xx-ble-client-demo/client.c create mode 100644 examples/platform-specific/cc26xx/cc26xx-ble-client-demo/project-conf.h diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index 48c08235d..6ccd6e160 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -25,7 +25,7 @@ ifdef NODEID endif ### CPU-dependent directories -CONTIKI_CPU_DIRS += . dev rf-core rf-core/api $(TI_XXWARE_STARTUP_DIR) +CONTIKI_CPU_DIRS += . dev rf-core rf-core/api rf-core/ble-hal $(TI_XXWARE_STARTUP_DIR) ### CPU-dependent source files CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c soc-rtc.c uart.c @@ -34,6 +34,8 @@ CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c adc-sensor.c CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c oscillators.c CONTIKI_CPU_SOURCEFILES += rf-core.c rf-ble.c ieee-mode.c +CONTIKI_CPU_SOURCEFILES += ble-cc2650.c ble-hal-cc26xx.c ble-addr.c rf-ble-cmd.c +CONTIKI_CPU_SOURCEFILES += ble-l2cap.c CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c diff --git a/arch/cpu/cc26xx-cc13xx/ble-addr.c b/arch/cpu/cc26xx-cc13xx/ble-addr.c new file mode 100644 index 000000000..91f665b01 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/ble-addr.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, Michael Spoerk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michael Spoerk + * + */ +/*---------------------------------------------------------------------------*/ +#include "../ble-addr.h" + +#include "contiki-conf.h" +#include "net/linkaddr.h" +#include + +/*---------------------------------------------------------------------------*/ +void +ble_addr_cpy_to(uint8_t *dst) +{ + int i; + uint8_t *location = (uint8_t *)BLE_ADDR_LOCATION; + + for(i = 0; i < BLE_ADDR_SIZE; i++) { + dst[i] = location[BLE_ADDR_SIZE - 1 - i]; + } +} +/*---------------------------------------------------------------------------*/ +void +ble_addr_to_eui64(uint8_t *dst, uint8_t *src) +{ + memcpy(dst, src, 3); + dst[3] = 0xFF; + dst[4] = 0xFE; + memcpy(&dst[5], &src[3], 3); +} +/*---------------------------------------------------------------------------*/ +void +ble_eui64_addr_cpy_to(uint8_t *dst) +{ + uint8_t ble_addr[BLE_ADDR_SIZE]; + ble_addr_cpy_to(ble_addr); + ble_addr_to_eui64(dst, ble_addr); +} diff --git a/arch/cpu/cc26xx-cc13xx/ble-addr.h b/arch/cpu/cc26xx-cc13xx/ble-addr.h new file mode 100644 index 000000000..b5b7c4ed5 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/ble-addr.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Michael Spoerk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michael Spoerk + * + */ +/*---------------------------------------------------------------------------*/ +#ifndef BLE_ADDR_H_ +#define BLE_ADDR_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" +#include +/*---------------------------------------------------------------------------*/ +/* primary BLE address location */ +#define BLE_ADDR_LOCATION 0x500012E8 + +/* BLE device address size */ +#define BLE_ADDR_SIZE 6 + +/*---------------------------------------------------------------------------*/ +/* Type of BLE device address */ +typedef enum { + BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_RANDOM +} ble_addr_type_t; + +/*---------------------------------------------------------------------------*/ +void ble_addr_cpy_to(uint8_t *dst); + +void ble_addr_to_eui64(uint8_t *dst, uint8_t *src); + +void ble_eui64_addr_cpy_to(uint8_t *dst); +/*---------------------------------------------------------------------------*/ + +#endif /* BLE_ADDR_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/dev/ble-hal.h b/arch/cpu/cc26xx-cc13xx/dev/ble-hal.h new file mode 100644 index 000000000..74aef1585 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/dev/ble-hal.h @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * hardware abstraction for a BLE controller + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ + +#ifndef BLE_HAL_H_ +#define BLE_HAL_H_ + +#include +#include "ble-addr.h" + +/*---------------------------------------------------------------------------*/ +/* Advertisement channel definitions */ +#define BLE_ADV_DATA_LEN 31 +#define BLE_SCAN_RESP_DATA_LEN 31 +#define BLE_ADV_CHANNEL_1 37 +#define BLE_ADV_CHANNEL_1_MASK 0b001 +#define BLE_ADV_CHANNEL_2 38 +#define BLE_ADV_CHANNEL_2_MASK 0b010 +#define BLE_ADV_CHANNEL_3 39 +#define BLE_ADV_CHANNEL_3_MASK 0b100 +#define BLE_ADV_INTERVAL_MIN 20 +#define BLE_ADV_INTERVAL_MAX 0x4000 +#define BLE_SCAN_INTERVAL_MIN 0x0004 +#define BLE_SCAN_INTERVAL_MAX 0x4000 +/*---------------------------------------------------------------------------*/ +/* Data channel definitions */ +#define BLE_DATA_CHANNEL_MIN 0 +#define BLE_DATA_CHANNEL_MAX 36 +/* Types of data PDU frames */ +#define BLE_DATA_PDU_LLID_DATA_FRAGMENT 0b01 +#define BLE_DATA_PDU_LLID_DATA_MESSAGE 0b10 +#define BLE_DATA_PDU_LLID_CONTROL 0b11 +/*---------------------------------------------------------------------------*/ +/* Types of LL control PDUs */ +#define BLE_LL_CONN_UPDATE_REQ 0x00 +#define BLE_LL_CHANNEL_MAP_REQ 0x01 +#define BLE_LL_TERMINATE_IND 0x02 +#define BLE_LL_ENC_REQ 0x03 +#define BLE_LL_ENC_RSP 0x04 +#define BLE_LL_START_ENC_REQ 0x05 +#define BLE_LL_START_ENC_RSP 0x06 +#define BLE_LL_UNKNOWN_RSP 0x07 +#define BLE_LL_FEATURE_REQ 0x08 +#define BLE_LL_FEATURE_RSP 0x09 +#define BLE_LL_PAUSE_ENC_REQ 0x0A +#define BLE_LL_PAUSE_ENC_RSP 0x0B +#define BLE_LL_VERSION_IND 0x0C +#define BLE_LL_REJECT_IND 0x0D +#define BLE_LL_SLAVE_FEATURE_REQ 0x0E +#define BLE_LL_CONN_PARAM_REQ 0x0F +#define BLE_LL_CONN_PARAM_RSP 0x10 +#define BLE_LL_REJECT_IND_EXT 0x11 +#define BLE_LL_PING_REQ 0x12 +#define BLE_LL_PING_RSP 0x13 +/*---------------------------------------------------------------------------*/ +#define FRAME_BLE_RX_EVENT 0x00 /* signaling that data was received (standard) */ +#define FRAME_BLE_TX_EVENT 0x10 /* signaling that data was successfully sent */ +#define FRAME_BLE_CONNECTION_EVENT 0x20 /* signaling that a new BLE connection was established */ +#define FRAME_BLE_CONNECTION_UPDATED 0x30 /* signaling that the BLE connection parameter were successfully updated */ +/*---------------------------------------------------------------------------*/ +/* Return values for functions of ble_controller_driver implementations */ +typedef enum { + BLE_RESULT_OK, + BLE_RESULT_NOT_SUPPORTED, + BLE_RESULT_INVALID_PARAM, + BLE_RESULT_ERROR +} ble_result_t; + +/*---------------------------------------------------------------------------*/ +/* Advertising modes of BLE */ +typedef enum { + /* connectable undirected advertising */ + BLE_ADV_IND, + + /* connectable directed advertising (high duty cycle) */ + BLE_ADV_DIR_IND_HDC, + + /* scannable undirected advertising */ + BLE_ADV_SCAN_IND, + + /* non connectable undirected advertising */ + BLE_ADV_NONCONN_IND, + + /* connectable directed advertising (low duty cycle) */ + BLE_ADV_DIR_IND_LDC +} ble_adv_type_t; + +/*---------------------------------------------------------------------------*/ +/* Scanning modes of BLE */ +typedef enum { + /* no SCAN REQUESTS are sent */ + BLE_SCAN_PASSIVE, + /* SCAN REQUESTS may be sent */ + BLE_SCAN_ACTIVE +} ble_scan_type_t; + +/*---------------------------------------------------------------------------*/ +/* Scanning filter policy */ +typedef enum { + /* accept all advertisement packets */ + BLE_SCAN_FILTER_POLICY_ACCEPT, + /* ignore all advertisement packets from devices not on the white list */ + BLE_SCAN_FILTER_POLICY_IGNORE +} ble_scan_filter_policy_t; +/*---------------------------------------------------------------------------*/ +/* List of packets to be sent by RDC layer */ +struct ble_buf_list { + struct ble_buf_list *next; + struct queuebuf *buf; + void *ptr; +}; + +/*---------------------------------------------------------------------------*/ +/* Extension of the RADIO_PARAM fields for the BLE radios */ +enum { + /* start with 100 to be sure to not interfere with the standard values*/ + /*-----------------------------------------------------------------------*/ + /* BLE controller general */ + /* The bluetooth device address */ + RADIO_CONST_BLE_BD_ADDR = 100, + + /* the size of a single BLE command buffer */ + RADIO_CONST_BLE_BUFFER_SIZE, + + /* the amount of single BLE command buffers */ + RADIO_CONST_BLE_BUFFER_AMOUNT, + + /*-----------------------------------------------------------------------*/ + /* BLE advertisement */ + + /* advertisement interval */ + RADIO_PARAM_BLE_ADV_INTERVAL, + + /* BLE advertisement type (directed/undirected, ...) */ + RADIO_PARAM_BLE_ADV_TYPE, + + /* type of own address during advertisement */ + RADIO_PARAM_BLE_ADV_OWN_ADDR_TYPE, + + /* advertisement channel map */ + RADIO_PARAM_BLE_ADV_CHANNEL_MAP, + + /* advertisement payload */ + RADIO_PARAM_BLE_ADV_PAYLOAD, + + /* scan response payload */ + RADIO_PARAM_BLE_ADV_SCAN_RESPONSE, + + /* 1: enable advertisement / 0: disable advertisement */ + RADIO_PARAM_BLE_ADV_ENABLE, + + /*-----------------------------------------------------------------------*/ + /* BLE scanning */ + + /* scanning interval */ + RADIO_PARAM_BLE_SCAN_INTERVAL, + + /* scanning window */ + RADIO_PARAM_BLE_SCAN_WINDOW, + + /* BLE scanning type (active/passive) */ + RADIO_PARAM_BLE_SCAN_TYPE, + + /* type of own address during scanning */ + RADIO_PARAM_BLE_SCAN_OWN_ADDR_TYPE, + + /* scanning channel */ + RADIO_PARAM_BLE_SCAN_CHANNEL, + + /* 1: enable scanning / 0: disable scanning */ + RADIO_PARAM_BLE_SCAN_ENABLE, + + /*-----------------------------------------------------------------------*/ + /* BLE initiating */ + /* The initiating command uses some parameters from scanning */ + /* (scan interval, window, address type) */ + + /* address type of the advertising device */ + RADIO_PARAM_BLE_PEER_ADDR_TYPE, + + /* address of the advertising device */ + RADIO_PARAM_BLE_PEER_ADDR, + + /* connection interval */ + RADIO_PARAM_BLE_CONN_INTERVAL, + + /* slave latency */ + RADIO_PARAM_BLE_CONN_LATENCY, + + /* supervision timeout */ + RADIO_PARAM_BLE_CONN_SUPERVISION_TIMEOUT, + + /* 1: start connection / 0: cancel connection creation */ + RADIO_PARAM_BLE_INITIATOR_ENABLE, + + RADIO_PARAM_BLE_CONN_UPDATE +}; + +/*---------------------------------------------------------------------------*/ +/** + * The structure of a ble radio controller driver in Contiki. + */ +struct ble_hal_driver { + + /*------------------------------------------------------------------------*/ + /* GENERAL COMMANDS */ + /** + * Resets the BLE controller + */ + ble_result_t (*reset)(void); + + /** + * Reads the static BLE device address. + * + * \param addr the static device address + */ + ble_result_t (*read_bd_addr)(uint8_t *addr); + + /** + * Reads the size of the data buffers. + * + * \param buf_len the length of a single data buffer + * \param num_buf the number of data buffers + */ + ble_result_t (*read_buffer_size) (unsigned int *buf_len, + unsigned int *num_buf); + + /*------------------------------------------------------------------------*/ + /* ADVERTISING COMMANDS */ + /** + * Sets the parameter for advertising. + * + * \param adv_interval advertising interval + * (interval = adv_interval * 0.625 ms) + * \param type type of advertising + * \param own_addr_type indicator if own address is public/random + * \param adv_channel_map map of advertising channels to use + */ + ble_result_t (*set_adv_param) (unsigned int adv_interval, + ble_adv_type_t type, + ble_addr_type_t own_addr_type, + unsigned short adv_channel_map); + + /** + * Reads the used power on the advertisement channels. + * + * \param power the used power in dBm + */ + ble_result_t (*read_adv_channel_tx_power) (short *power); + + /** + * Sets the advertising data. + * + * \param data_len the length of the advertising data + * \param data the data to advertise + */ + ble_result_t (*set_adv_data) (unsigned short data_len, + char *data); + + /** + * Sets the scan response data. + * + * \param data_len the length of the scan response data + * \param data the data of a scan response + */ + ble_result_t (*set_scan_resp_data) (unsigned short data_len, + char *data); + + /** + * Enables/disables advertising. + * + * \param enable if 1 then enable advertising, otherwise disable + */ + ble_result_t (*set_adv_enable) (unsigned short enable); + + /*------------------------------------------------------------------------*/ + /* SCANNING COMMANDS */ + /** + * Sets the parameter for scanning. + * + * \param type scan mode + * \param scan_interval scan interval (interval = scan_interval * 0.625 ms) + * \param scan_window scan window (window = scan_window * 0.625 ms) + * \param own_addr_type indicator if own address is public/random + */ + ble_result_t (*set_scan_param) (ble_scan_type_t type, + unsigned int scan_interval, + unsigned int scan_window, + ble_addr_type_t own_addr_type); + + /** + * Enables/disables scanning. + * + * \param enable 1: enable scanning, otherwise disable + * \param filter_duplicates: 1: filter duplicates, otherwise no filtering + */ + ble_result_t (*set_scan_enable) (unsigned short enable, + unsigned short filter_duplicates); + + /*------------------------------------------------------------------------*/ + /* INITIATING COMMANDS */ + /** + * Initiates the creation of a BLE connection. + * + * \param scan_interval scan interval (interval = scan_interval * 0.625 ms) + * \param scan_window scan window (window = scan_window * 0.625 ms) + * \param peer_addr_type indicator if peer address is public/random + * \param peer_addr ble address of the device to connect to + * \param own_addr_type indicator if own address is public/random + * \param conn_interval connection interval + * (interval = conn_interval * 1.25 ms) + * \param conn_latency slave latency + * \param supervision_timeout (timeout = supervision_timeout * 10 ms) + */ + ble_result_t (*create_connection) (unsigned int scan_interval, + unsigned int scan_window, + ble_addr_type_t peer_addr_type, + uint8_t *peer_addr, + ble_addr_type_t own_addr_type, + unsigned int conn_interval, + unsigned int conn_latency, + unsigned int supervision_timeout); + + /** + * Cancels the initiation of a BLE connection. + */ + ble_result_t (*create_connection_cancel) (void); + + /*------------------------------------------------------------------------*/ + /* CONNECTION COMMANDS */ + /** + * Updates the connection parameters. + * \param conn_interval connection interval + * (interval = conn_interval * 1.25 ms) + * \param conn_latency slave latency + * \param supervision_timeout (timeout = supervision_timeout * 10 ms) + */ + ble_result_t (*connection_update) (unsigned int connection_handle, + unsigned int conn_interval, + unsigned int conn_latency, + unsigned int supervision_timeout); + + /** + * Disconnects the connection. + * + * \param connection_handle + * \param reason see error codes of Bluetooth specification + */ + ble_result_t (*disconnect) (unsigned int connection_handle, + unsigned short reason); + + ble_result_t (*send) (void *buf, unsigned short buf_len); + + ble_result_t (*send_list) (struct ble_buf_list *list); + + ble_result_t (*read_connection_interval) (unsigned int conn_handle, + unsigned int *conn_interval_ms); +}; + +#endif /* BLE_HAL_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/README.md b/arch/cpu/cc26xx-cc13xx/rf-core/README.md new file mode 100644 index 000000000..6d263c118 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/README.md @@ -0,0 +1,84 @@ +# BLEach: a fully open-source IPv6-over-BLE stack for Constrained Embedded IoT Devices + +## Overview +In 2015, the IETF released the [RFC 7668][rfc7668] that specifies how IPv6 packets +can be exchanged using BLE connections (IPv6 over BLE). +This Contiki extenstion implements [BLEach][bleachWeb], a fully open-source IPv6-over-BLE stack for Contiki. +BLEach in Contiki-NG can be used for node (BLE slave) devices. + +It was developed by +* [Michael Spoerk](www.michaelspoerk.com), Graz University of Technology, michael.spoerk@tugraz.at, github user: [spoerk](https://github.com/spoerk) + +This IPv6-over-BLE stack is presented and evaluated in the paper: +[BLEach: Exploiting the Full Potential of IPv6 over BLE in Constrained Embedded IoT Devices](http://sensys.acm.org/2017/), ACM SenSys'17. + +## Features +This implementation includes: + * IPv6-over-BLE node implementation compliant to [RFC 7668][rfc7668] + * connect to a single IPv6-over-BLE border router + * maximum IPv6 packet length of 1280 bytes + * BLE L2CAP channels in LE credit-based flow control mode + * BLE link layer support for version [4.1][bleSpec]: + * BLE advertisement + * BLE connection slave + +It has been tested on the TI CC2650 SensorTag and the TI CC2650 LaunchPad hardware. + +## Modules +The IPv6-over-BLE stack comes with the following modules: + +### BLE radio +The implementation of the BLE radio for the TI CC26xx platform is implemented in `arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c` +and `arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/*.[ch]`. +These files contain all the hardware specific code for supporting BLE as a link layer. + +### BLE L2CAP layer +The L2CAP LE credit-based flow control support is implemented in `arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c`. +Besides implementing rudimentary L2CAP support, this module handles fragmentation of large IPv6 packets. + +## Using BLEach +A simple IPv6-over-BLE UDP-client is included under `examples/platform-specific/cc26xx/cc26xx-ble-client-demo`. + +Currently, BLEach is only available for the Texas Instruments CC2650 hardware platform. + +The following sections describe how to configure BLEach for IPv6-over-BLE nodes and border routers. + +### IPv6-over-BLE node (BLE slave) +To enable IPv6 over BLE, the project conf needs to contain: +``` +#define PACKETBUF_CONF_SIZE 1280 +#define QUEUEBUF_CONF_NUM 1 +#define UIP_CONF_BUFFER_SIZE 1280 + +#define CC26XX_CONF_RADIO_MODE CC26XX_RADIO_MODE_BLE +#define NETSTACK_CONF_RADIO ble_cc2650_driver +#define NETSTACK_CONF_MAC ble_l2cap_driver + +#define RTIMER_CONF_MULTIPLE_ACCESS 1 + +/* 6LoWPAN settings */ +#define SICSLOWPAN_CONF_MAC_MAX_PAYLOAD 1280 +#define SICSLOWPAN_CONF_COMPRESSION SICSLOWPAN_COMPRESSION_HC06 +#define SICSLOWPAN_CONF_COMPRESSION_THRESHOLD 0 /* always use compression */ +#define SICSLOWPAN_CONF_FRAG 0 +#define SICSLOWPAN_FRAMER_HDRLEN 0 + +/* network stack settings */ +#define UIP_CONF_ROUTER 0 +#define UIP_CONF_ND6_SEND_NA 1 + +``` + +The following optional parameter can be used to configure that BLE advertisement behaviour: +``` +#define BLE_CONF_DEVICE_NAME "TI CC26xx device" +#define BLE_CONF_ADV_INTERVAL 25 +``` +`BLE_CONF_DEVICE_NAME` holds the device name that is used for advertisement, `BLE_CONF_ADV_INTERVAL` +specifies the used advertisement interval in milliseconds. + + +[rfc7668]: https://tools.ietf.org/html/rfc7668 +[bleSpec]: https://www.bluetooth.com/specifications/bluetooth-core-specification/legacy-specifications +[bleachWeb]: http://www.iti.tugraz.at/BLEach + diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c new file mode 100644 index 000000000..1cc9ed7d9 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * BLE radio for the TI CC26xx platform + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ + +#include +#include +#include "contiki.h" +#include "dev/radio.h" +/*---------------------------------------------------------------------------*/ +#include "sys/log.h" +#define LOG_MODULE "RADIO" +#define LOG_LEVEL LOG_LEVEL_MAIN +/*---------------------------------------------------------------------------*/ +static uint16_t adv_interval; +static ble_adv_type_t adv_type; +static ble_addr_type_t adv_own_addr_type; +static uint8_t adv_channel_map; +static uint16_t buffer_size = 0; +/*---------------------------------------------------------------------------*/ +static uint16_t scan_interval; +static uint16_t scan_window; +static ble_scan_type_t scan_type; +static ble_addr_type_t scan_own_addr_type; +/*---------------------------------------------------------------------------*/ +static ble_addr_type_t initiator_peer_addr_type; +static uint8_t initiator_peer_addr[BLE_ADDR_SIZE]; +/*---------------------------------------------------------------------------*/ +static uint16_t connection_interval; +static uint16_t connection_latency; +static uint16_t connection_timeout; +/*---------------------------------------------------------------------------*/ +static int +init(void) +{ + int result = ble_hal.reset(); + return result == BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static int +send(const void *payload, unsigned short payload_len) +{ + uint8_t res; + res = ble_hal.send((void *)payload, payload_len); + LOG_DBG("ble-mode send() %d bytes\n", payload_len); + if(res == BLE_RESULT_OK) { + return RADIO_TX_OK; + } else { + LOG_ERR("ble-mode send() error: %d\n", res); + return RADIO_TX_ERR; + } +} +/*---------------------------------------------------------------------------*/ +static int +on(void) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +off(void) +{ + ble_hal.disconnect(0, 0); + return 1; +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +get_value(radio_param_t param, radio_value_t *value) +{ + unsigned int temp; + + if(!value) { + return RADIO_RESULT_INVALID_VALUE; + } + + switch(param) { + case RADIO_CONST_CHANNEL_MIN: + *value = BLE_DATA_CHANNEL_MIN; + return RADIO_RESULT_OK; + case RADIO_CONST_CHANNEL_MAX: + *value = BLE_DATA_CHANNEL_MAX; + return RADIO_RESULT_OK; + case RADIO_CONST_BLE_BUFFER_SIZE: + if(buffer_size == 0) { + ble_hal.read_buffer_size((unsigned int *)&buffer_size, &temp); + } + memcpy(value, &buffer_size, 2); + return RADIO_RESULT_OK; + case RADIO_CONST_BLE_BUFFER_AMOUNT: + ble_hal.read_buffer_size(&temp, (unsigned int *)value); + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_CONN_INTERVAL: + ble_hal.read_connection_interval(0, (unsigned int *)value); + return RADIO_RESULT_OK; + default: + return RADIO_RESULT_NOT_SUPPORTED; + } +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +set_value(radio_param_t param, radio_value_t value) +{ + switch(param) { + case RADIO_PARAM_BLE_ADV_INTERVAL: + if((value > BLE_ADV_INTERVAL_MAX) || (value < BLE_ADV_INTERVAL_MIN)) { + return RADIO_RESULT_INVALID_VALUE; + } + adv_interval = (uint16_t)value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_ADV_TYPE: + adv_type = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_ADV_OWN_ADDR_TYPE: + adv_own_addr_type = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_ADV_CHANNEL_MAP: + adv_channel_map = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_ADV_ENABLE: + if(value) { + /* set the advertisement parameter before enabling */ + ble_hal.set_adv_param(adv_interval, adv_type, + adv_own_addr_type, adv_channel_map); + } + ble_hal.set_adv_enable(value); + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_SCAN_INTERVAL: + if((value > BLE_SCAN_INTERVAL_MAX) || (value < BLE_SCAN_INTERVAL_MIN)) { + return RADIO_RESULT_INVALID_VALUE; + } + scan_interval = (uint16_t)value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_SCAN_WINDOW: + if((value > BLE_SCAN_INTERVAL_MAX) || (value < BLE_SCAN_INTERVAL_MIN)) { + return RADIO_RESULT_INVALID_VALUE; + } + scan_window = (uint16_t)value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_SCAN_TYPE: + scan_type = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_SCAN_OWN_ADDR_TYPE: + scan_own_addr_type = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_SCAN_ENABLE: + if(value) { + ble_hal.set_scan_param(scan_type, scan_interval, + scan_window, scan_own_addr_type); + } + ble_hal.set_scan_enable(value, 0); + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_PEER_ADDR_TYPE: + initiator_peer_addr_type = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_CONN_INTERVAL: + connection_interval = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_CONN_LATENCY: + connection_latency = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_CONN_SUPERVISION_TIMEOUT: + connection_timeout = value; + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_INITIATOR_ENABLE: + if(value) { + ble_hal.create_connection(scan_interval, scan_window, + initiator_peer_addr_type, + initiator_peer_addr, + scan_own_addr_type, + connection_interval, + connection_latency, + connection_timeout); + } else { + ble_hal.create_connection_cancel(); + } + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_CONN_UPDATE: + if(value) { + return ble_hal.connection_update(0, connection_interval, connection_latency, connection_timeout); + } else { + return RADIO_RESULT_INVALID_VALUE; + } + default: + return RADIO_RESULT_NOT_SUPPORTED; + } +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +get_object(radio_param_t param, void *dest, size_t size) +{ + switch(param) { + case RADIO_CONST_BLE_BD_ADDR: + if(size != BLE_ADDR_SIZE || !dest) { + return RADIO_RESULT_INVALID_VALUE; + } + ble_hal.read_bd_addr(dest); + return RADIO_RESULT_OK; + } + return RADIO_RESULT_NOT_SUPPORTED; +} +/*---------------------------------------------------------------------------*/ +static radio_result_t +set_object(radio_param_t param, const void *src, size_t size) +{ + switch(param) { + case RADIO_PARAM_BLE_ADV_PAYLOAD: + if(size <= 0 || size >= BLE_ADV_DATA_LEN || !src) { + return RADIO_RESULT_INVALID_VALUE; + } + ble_hal.set_adv_data((unsigned short)size, (char *)src); + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_ADV_SCAN_RESPONSE: + if(size <= 0 || size >= BLE_SCAN_RESP_DATA_LEN || !src) { + return RADIO_RESULT_INVALID_VALUE; + } + ble_hal.set_scan_resp_data((unsigned short)size, (char *)src); + return RADIO_RESULT_OK; + case RADIO_PARAM_BLE_PEER_ADDR: + if(size <= 0 || size > BLE_ADDR_SIZE || !src) { + return RADIO_RESULT_INVALID_VALUE; + } + memcpy(initiator_peer_addr, src, size); + return RADIO_RESULT_OK; + } + return RADIO_RESULT_NOT_SUPPORTED; +} +/*---------------------------------------------------------------------------*/ +const struct radio_driver ble_cc2650_driver = { + init, + NULL, + NULL, + send, + NULL, + NULL, + NULL, + NULL, + on, + off, + get_value, + set_value, + get_object, + set_object, +}; +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c new file mode 100644 index 000000000..086ebb8a7 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c @@ -0,0 +1,1016 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * hardware abstraction implementation for the TI CC2650 controller + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ +#include "ble-hal.h" +#include "rf-core/ble-hal/rf-ble-cmd.h" +#include "lpm.h" + +#include "sys/rtimer.h" +#include "sys/process.h" + +#include "dev/oscillators.h" + +#include "ble-addr.h" + +#include "net/netstack.h" +#include "net/packetbuf.h" + +#include "rf_data_entry.h" +#include "rf-core/rf-core.h" +#include "rf_ble_cmd.h" +#include "lib/random.h" + +#include "ioc.h" +#include "ti-lib.h" +#include "inc/hw_types.h" +#include "inc/hw_rfc_dbell.h" + +#include + +/*---------------------------------------------------------------------------*/ +#include "sys/log.h" +#define LOG_MODULE "BLE-RADIO" +#define LOG_LEVEL LOG_LEVEL_MAIN +/*---------------------------------------------------------------------------*/ +#define CMD_GET_STATUS(X) (((rfc_radioOp_t *)X)->status) +#define RX_ENTRY_STATUS(X) (((rfc_dataEntry_t *)X)->status) +#define RX_ENTRY_LENGTH(X) (((rfc_dataEntry_t *)X)->length) +#define RX_ENTRY_TYPE(X) (((rfc_dataEntry_t *)X)->config.type) +#define RX_ENTRY_NEXT_ENTRY(X) (((rfc_dataEntry_t *)X)->pNextEntry) +#define RX_ENTRY_DATA_LENGTH(X) ((X)[8]) +#define RX_ENTRY_DATA_PTR(X) (&(X)[9]) +#define TX_ENTRY_STATUS(X) RX_ENTRY_STATUS(X) +#define TX_ENTRY_LENGTH(X) RX_ENTRY_LENGTH(X) +#define TX_ENTRY_TYPE(X) RX_ENTRY_TYPE(X) +#define TX_ENTRY_NEXT_ENTRY(X) RX_ENTRY_NEXT_ENTRY(X) +#define TX_ENTRY_FRAME_TYPE(X) ((X)[8]) +#define TX_ENTRY_DATA_PTR(X) (&(X)[9]) +/*---------------------------------------------------------------------------*/ +/* LPM */ +/*---------------------------------------------------------------------------*/ +static uint8_t +request(void) +{ + if(rf_core_is_accessible()) { + return LPM_MODE_SLEEP; + } + + return LPM_MODE_MAX_SUPPORTED; +} +/*---------------------------------------------------------------------------*/ +LPM_MODULE(cc26xx_ble_lpm_module, request, NULL, NULL, LPM_DOMAIN_NONE); +/*---------------------------------------------------------------------------*/ +/* timing utilities */ +#define TIME_UNIT_MS 1000 /* 1000 times per second */ +#define TIME_UNIT_0_625_MS 1600 /* 1600 times per second */ +#define TIME_UNIT_1_25_MS 800 /* 800 times per second */ +#define TIME_UNIT_10_MS 100 /* 100 times per second */ +#define TIME_UNIT_RF_CORE 4000000 /* runs at 4 MHz */ +#define TIME_UNIT_RTIMER RTIMER_SECOND + +rtimer_clock_t +ticks_from_unit(uint32_t value, uint32_t unit) +{ + double temp = (((double)value) / unit) * RTIMER_SECOND; + return (rtimer_clock_t)temp; +} +uint32_t +ticks_to_unit(rtimer_clock_t value, uint32_t unit) +{ + double temp = (((double)value) / RTIMER_SECOND) * unit; + return (uint32_t)temp; +} +/*---------------------------------------------------------------------------*/ +#define CMD_BUFFER_SIZE 24 +#define PARAM_BUFFER_SIZE 36 +#define OUTPUT_BUFFER_SIZE 24 +/*---------------------------------------------------------------------------*/ +/* ADVERTISING data structures */ +#define ADV_RX_BUFFERS_OVERHEAD 8 +#define ADV_RX_BUFFERS_DATA_LEN 60 +#define ADV_RX_BUFFERS_LEN (ADV_RX_BUFFERS_OVERHEAD + ADV_RX_BUFFERS_DATA_LEN) +#define ADV_RX_BUFFERS_NUM 2 + +#define ADV_PREPROCESSING_TIME_TICKS 65 + +typedef struct { + /* PARAMETER */ + uint16_t adv_interval; + ble_adv_type_t adv_type; + ble_addr_type_t own_addr_type; + uint8_t channel_map; + uint8_t adv_data_len; + uint8_t adv_data[BLE_ADV_DATA_LEN]; + uint8_t scan_rsp_data_len; + uint8_t scan_rsp_data[BLE_ADV_DATA_LEN]; + /* STATE information */ + uint8_t active; + rtimer_clock_t start_rt; + struct rtimer timer; + /* utility */ + uint8_t cmd_buf[CMD_BUFFER_SIZE]; + uint8_t param_buf[PARAM_BUFFER_SIZE]; + uint8_t output_buf[OUTPUT_BUFFER_SIZE]; + dataQueue_t rx_queue; + uint8_t rx_buffers[ADV_RX_BUFFERS_NUM][ADV_RX_BUFFERS_LEN]; + uint8_t *rx_queue_current; +} ble_adv_param_t; + +static ble_adv_param_t adv_param; +static void advertising_event(struct rtimer *t, void *ptr); +/*---------------------------------------------------------------------------*/ +/* CONNECTION data structures */ +#define BLE_MODE_MAX_CONNECTIONS 1 + +/* maximum packet length that is transmitted during a single connection event*/ +#ifdef BLE_MODE_CONF_CONN_MAX_PACKET_SIZE +#define BLE_MODE_CONN_MAX_PACKET_SIZE BLE_MODE_CONF_CONN_MAX_PACKET_SIZE +#else +#define BLE_MODE_CONN_MAX_PACKET_SIZE 256 +#endif + +#define CONN_BLE_BUFFER_SIZE 27 /* maximum size of the data buffer */ + +#define CONN_RX_BUFFERS_OVERHEAD 8 +#define CONN_RX_BUFFERS_DATA_LEN 60 +#define CONN_RX_BUFFERS_LEN (CONN_RX_BUFFERS_OVERHEAD + CONN_RX_BUFFERS_DATA_LEN) +#define CONN_RX_BUFFERS_NUM 12 + +/* custom status used for tx buffers */ +#define DATA_ENTRY_FREE 5 +#define DATA_ENTRY_QUEUED 6 + +#define CONN_TX_BUFFERS_OVERHEAD 9 +#define CONN_TX_BUFFERS_DATA_LEN 27 +#define CONN_TX_BUFFERS_LEN (CONN_TX_BUFFERS_OVERHEAD + CONN_TX_BUFFERS_DATA_LEN) +#define CONN_TX_BUFFERS_NUM 12 + +#define CONN_WIN_SIZE 1 +#define CONN_WIN_OFFSET 20 + +#define CONN_EVENT_LATENCY_THRESHOLD 10 +#define CONN_WINDOW_WIDENING_TICKS 30 /* appr. 0.46 ms */ +#define CONN_PREPROCESSING_TIME_TICKS 100 /* 1.5 ms */ + +#define CONN_UPDATE_DELAY 6 + +typedef struct { + /* PARAMETER */ + uint8_t peer_address[BLE_ADDR_SIZE]; + uint32_t access_address; + uint8_t crc_init_0; + uint8_t crc_init_1; + uint8_t crc_init_2; + uint8_t win_size; + uint16_t win_offset; + uint16_t interval; + uint16_t latency; + uint16_t timeout; + uint64_t channel_map; + uint8_t num_used_channels; + uint8_t hop; + uint8_t sca; + rtimer_clock_t timestamp_rt; + /* STATE information */ + uint8_t active; + uint16_t counter; + uint8_t unmapped_channel; + uint8_t mapped_channel; + rtimer_clock_t start_rt; + uint16_t conn_handle; + struct rtimer timer; + /* utility */ + uint8_t cmd_buf[CMD_BUFFER_SIZE]; + uint8_t param_buf[PARAM_BUFFER_SIZE]; + uint8_t output_buf[OUTPUT_BUFFER_SIZE]; + dataQueue_t rx_queue; + uint8_t rx_buffers[CONN_RX_BUFFERS_NUM][CONN_RX_BUFFERS_LEN]; + uint8_t *rx_queue_current; + dataQueue_t tx_queue; + uint8_t tx_buffers[CONN_TX_BUFFERS_NUM][CONN_TX_BUFFERS_LEN]; + uint8_t tx_buffers_sent; + uint16_t skipped_events; + /* channel map update */ + uint64_t channel_update_channel_map; + uint16_t channel_update_counter; + uint8_t channel_update_num_used_channels; + /* connection parameter update */ + uint8_t conn_update_win_size; + uint16_t conn_update_win_offset; + uint16_t conn_update_interval; + uint16_t conn_update_latency; + uint16_t conn_update_timeout; + uint16_t conn_update_counter; +} ble_conn_param_t; + +static ble_conn_param_t conn_param[BLE_MODE_MAX_CONNECTIONS]; + +static uint16_t conn_counter = 0; + +static void connection_event_slave(struct rtimer *t, void *ptr); +/*---------------------------------------------------------------------------*/ +PROCESS(ble_hal_conn_rx_process, "BLE/CC26xx connection RX process"); +process_event_t rx_data_event; +/*---------------------------------------------------------------------------*/ +static void +setup_buffers(void) +{ + uint8_t conn_count; + ble_conn_param_t *conn; + uint8_t i; + rfc_dataEntry_t *entry; + + /* setup advertisement RX buffer (circular buffer) */ + memset(&adv_param, 0x00, sizeof(ble_adv_param_t)); + memset(&adv_param.rx_queue, 0x00, sizeof(adv_param.rx_queue)); + adv_param.rx_queue.pCurrEntry = adv_param.rx_buffers[0]; + adv_param.rx_queue.pLastEntry = NULL; + adv_param.rx_queue_current = adv_param.rx_buffers[0]; + for(i = 0; i < ADV_RX_BUFFERS_NUM; i++) { + memset(&adv_param.rx_buffers[i], 0x00, ADV_RX_BUFFERS_LEN); + entry = (rfc_dataEntry_t *)adv_param.rx_buffers[i]; + entry->pNextEntry = adv_param.rx_buffers[(i + 1) % ADV_RX_BUFFERS_NUM]; + entry->config.lenSz = 1; + entry->length = ADV_RX_BUFFERS_DATA_LEN; + } + + memset(conn_param, 0x00, sizeof(ble_conn_param_t) * BLE_MODE_MAX_CONNECTIONS); + for(conn_count = 0; conn_count < BLE_MODE_MAX_CONNECTIONS; conn_count++) { + /* setup connection RX buffer (circular buffer) */ + conn = &conn_param[conn_count]; + memset(&conn->rx_queue, 0x00, sizeof(conn->rx_queue)); + conn->rx_queue.pCurrEntry = conn->rx_buffers[0]; + conn->rx_queue.pLastEntry = NULL; + conn->rx_queue_current = conn->rx_buffers[0]; + + for(i = 0; i < CONN_RX_BUFFERS_NUM; i++) { + memset(&conn->rx_buffers[i], 0x00, CONN_RX_BUFFERS_LEN); + entry = (rfc_dataEntry_t *)conn->rx_buffers[i]; + entry->pNextEntry = conn->rx_buffers[(i + 1) % CONN_RX_BUFFERS_NUM]; + entry->config.lenSz = 1; + entry->length = CONN_RX_BUFFERS_DATA_LEN; + } + + /* setup connection TX buffer (buffers are added on demand to the queue) */ + memset(&conn->tx_queue, 0x00, sizeof(conn->tx_queue)); + conn->tx_queue.pCurrEntry = NULL; + conn->tx_queue.pLastEntry = NULL; + + for(i = 0; i < CONN_TX_BUFFERS_NUM; i++) { + memset(&conn->tx_buffers[i], 0x00, CONN_TX_BUFFERS_LEN); + entry = (rfc_dataEntry_t *)conn->tx_buffers[i]; + entry->config.lenSz = 1; + entry->status = DATA_ENTRY_FREE; + } + } +} +/*---------------------------------------------------------------------------*/ +static ble_conn_param_t * +get_connection_for_handle(uint8_t conn_handle) +{ + uint8_t i; + for(i = 0; i < BLE_MODE_MAX_CONNECTIONS; i++) { + if(conn_param[i].conn_handle == conn_handle) { + return &conn_param[i]; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static uint8_t * +tx_queue_get_buffer(ble_conn_param_t *param) +{ + uint8_t i; + rfc_dataEntry_t *entry; + for(i = 0; i < CONN_TX_BUFFERS_NUM; i++) { + entry = (rfc_dataEntry_t *)param->tx_buffers[i]; + if(entry->status == DATA_ENTRY_FREE) { + return (uint8_t *)entry; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static uint16_t +tx_queue_count_free_buffers(ble_conn_param_t *param) +{ + uint16_t i; + uint16_t free_bufs = 0; + for(i = 0; i < CONN_TX_BUFFERS_NUM; i++) { + if(TX_ENTRY_STATUS(param->tx_buffers[i]) == DATA_ENTRY_FREE) { + free_bufs++; + } + } + return free_bufs; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +tx_queue_data_to_transmit(ble_conn_param_t *param) +{ + uint16_t i; + for(i = 0; i < CONN_TX_BUFFERS_NUM; i++) { + if(TX_ENTRY_STATUS(param->tx_buffers[i]) == DATA_ENTRY_QUEUED) { + return 1; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +ble_result_t +on(void) +{ + oscillators_request_hf_xosc(); + if(!rf_core_is_accessible()) { + /* boot the rf core */ + if(rf_core_boot() != RF_CORE_CMD_OK) { + LOG_ERR("ble_controller_reset() could not boot rf-core\n"); + return BLE_RESULT_ERROR; + } + + rf_core_setup_interrupts(0); + oscillators_switch_to_hf_xosc(); + + if(rf_ble_cmd_setup_ble_mode() != RF_BLE_CMD_OK) { + LOG_ERR("could not setup rf-core to BLE mode\n"); + return BLE_RESULT_ERROR; + } + } + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +void +off(void) +{ + rf_core_power_down(); + oscillators_switch_to_hf_rc(); +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +reset(void) +{ + LOG_INFO("maximum connections: %4d\n", BLE_MODE_MAX_CONNECTIONS); + LOG_INFO("max. packet length: %4d\n", BLE_MODE_CONN_MAX_PACKET_SIZE); + lpm_register_module(&cc26xx_ble_lpm_module); + rf_core_set_modesel(); + setup_buffers(); + if(on() != BLE_RESULT_OK) { + return BLE_RESULT_ERROR; + } + off(); + if(!process_is_running(&ble_hal_conn_rx_process)) { + rx_data_event = process_alloc_event(); + process_start(&ble_hal_conn_rx_process, NULL); + } + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +read_bd_addr(uint8_t *addr) +{ + ble_addr_cpy_to(addr); + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +read_buffer_size(unsigned int *buf_len, unsigned int *num_buf) +{ + uint16_t i; + uint16_t ll_buffers = CONN_TX_BUFFERS_NUM; + uint16_t packet_buffers; + uint16_t buffer_size; + for(i = 0; i < conn_counter; i++) { + ll_buffers = MIN(ll_buffers, tx_queue_count_free_buffers(&conn_param[i])); + } + packet_buffers = ll_buffers / (BLE_MODE_CONN_MAX_PACKET_SIZE / CONN_BLE_BUFFER_SIZE); + buffer_size = BLE_MODE_CONN_MAX_PACKET_SIZE; + memcpy(buf_len, &buffer_size, 2); + memcpy(num_buf, &packet_buffers, 2); + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +set_adv_param(unsigned int adv_int, ble_adv_type_t type, + ble_addr_type_t own_type, unsigned short adv_map) +{ + adv_param.adv_interval = adv_int; + adv_param.adv_type = type; + adv_param.own_addr_type = own_type; + adv_param.channel_map = adv_map; + + LOG_INFO("advertising parameter: interval: %4d, channels: %2d\n", + adv_param.adv_interval, adv_param.channel_map); + + LOG_DBG("interval: %16u (ms)\n", adv_param.adv_interval); + LOG_DBG("type: %16u\n", adv_param.adv_type); + LOG_DBG("addr_type:%16u\n", adv_param.own_addr_type); + LOG_DBG("channels: %16u\n", adv_param.channel_map); + + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +read_adv_channel_tx_power(short *power) +{ + return BLE_RESULT_NOT_SUPPORTED; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +set_adv_data(unsigned short data_len, char *data) +{ + if(data_len > BLE_ADV_DATA_LEN) { + LOG_WARN("BLE-HAL: adv_data too long\n"); + return BLE_RESULT_INVALID_PARAM; + } + adv_param.adv_data_len = data_len; + memcpy(adv_param.adv_data, data, data_len); + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +set_scan_resp_data(unsigned short data_len, char *data) +{ + if(data_len > BLE_SCAN_RESP_DATA_LEN) { + LOG_WARN("BLE-HAL: scan_resp_data too long\n"); + return BLE_RESULT_INVALID_PARAM; + } + adv_param.scan_rsp_data_len = data_len; + memcpy(adv_param.scan_rsp_data, data, data_len); + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +set_adv_enable(unsigned short enable) +{ + uint32_t now = RTIMER_NOW(); + if((enable) && (!adv_param.active)) { + adv_param.start_rt = now + ticks_from_unit(adv_param.adv_interval, + TIME_UNIT_1_25_MS); + rtimer_set(&adv_param.timer, adv_param.start_rt, + 0, advertising_event, (void *)&adv_param); + } + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +send_frame(ble_conn_param_t *conn, uint8_t *data, uint8_t data_len, uint8_t frame_type) +{ + uint8_t *tx_buffer = tx_queue_get_buffer(conn); + if(tx_buffer == NULL) { + LOG_WARN("BLE-HAL: send_frame: no TX buffer available (conn_handle: 0x%04X)\n", conn->conn_handle); + return BLE_RESULT_ERROR; + } + if(data_len > CONN_BLE_BUFFER_SIZE) { + LOG_WARN("BLE-HAL: send_frame: data too long (%d bytes)\n", data_len); + return BLE_RESULT_ERROR; + } + + memcpy(TX_ENTRY_DATA_PTR(tx_buffer), data, data_len); + TX_ENTRY_LENGTH(tx_buffer) = data_len + 1; + TX_ENTRY_STATUS(tx_buffer) = DATA_ENTRY_QUEUED; + TX_ENTRY_FRAME_TYPE(tx_buffer) = frame_type; + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +connection_update(unsigned int connection_handle, unsigned int conn_interval, + unsigned int conn_latency, unsigned int supervision_timeout) +{ + uint8_t len = 0; + uint8_t data[24]; + ble_conn_param_t *conn = get_connection_for_handle(connection_handle); + + if(conn == NULL) { + return BLE_RESULT_ERROR; + } + + LOG_INFO("connection_update: handle: 0x%04X, interval: %4d, latency: %2d, timeout: %4d\n", + connection_handle, conn_interval, conn_latency, supervision_timeout); +#if UIP_CONF_ROUTER + uint16_t instant = conn->counter + CONN_UPDATE_DELAY; + /* prepare connection update packet */ + data[0] = BLE_LL_CONN_UPDATE_REQ; + data[1] = conn->win_size; + data[2] = 0; + data[3] = 0; + memcpy(&data[4], &conn_interval, 2); + memcpy(&data[6], &conn_latency, 2); + memcpy(&data[8], &supervision_timeout, 2); + memcpy(&data[10], &instant, 2); + len = 12; + /* set new connection */ + conn->conn_update_win_size = conn->win_size; + conn->conn_update_interval = conn_interval; + conn->conn_update_latency = conn_latency; + conn->conn_update_timeout = supervision_timeout; + conn->conn_update_counter = instant; + + if(send_frame(conn, data, len, BLE_DATA_PDU_LLID_CONTROL) != BLE_RESULT_OK) { + LOG_ERR("connection_update: send frame was NOT successful\n"); + return BLE_RESULT_ERROR; + } +#else + data[0] = BLE_LL_CONN_PARAM_REQ; + memcpy(&data[1], &conn_interval, 2); /* interval min */ + memcpy(&data[3], &conn_interval, 2); /* interval max */ + memcpy(&data[5], &conn_latency, 2); /* latency */ + memcpy(&data[7], &supervision_timeout, 2); /* supervision timeout */ + memcpy(&data[9], &conn_interval, 1); /* preferred periodicity */ + memcpy(&data[10], &conn->counter, 2); /* referenc conn event count */ + memset(&data[12], 0xFF, 12); /* offset 0 to 5 */ + len = 24; + + if(send_frame(conn, data, len, BLE_DATA_PDU_LLID_CONTROL) != BLE_RESULT_OK) { + LOG_ERR("connection_update: send frame was NOT successful\n"); + return BLE_RESULT_ERROR; + } +#endif + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +send(void *buf, unsigned short buf_len) +{ + uint16_t loop_data; + uint16_t loop_conn; + ble_conn_param_t *conn; + uint8_t *data; + uint16_t data_len; + linkaddr_t dest_addr; + linkaddr_t conn_addr; + uint8_t result; + + linkaddr_copy(&dest_addr, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + + LOG_DBG("ble-hal: sending %d bytes\n", buf_len); + + for(loop_conn = 0; loop_conn < conn_counter; loop_conn++) { + conn = &conn_param[loop_conn]; + ble_addr_to_eui64(conn_addr.u8, conn->peer_address); + if((linkaddr_cmp(&dest_addr, &linkaddr_null) != 0) || (linkaddr_cmp(&dest_addr, &conn_addr) != 0)) { + for(loop_data = 0; loop_data < buf_len; loop_data += CONN_BLE_BUFFER_SIZE) { + data = &((uint8_t *)buf)[loop_data]; + data_len = MIN((buf_len - loop_data), CONN_BLE_BUFFER_SIZE); + if(loop_data == 0) { + result = send_frame(conn, data, data_len, BLE_DATA_PDU_LLID_DATA_MESSAGE); + } else { + result = send_frame(conn, data, data_len, BLE_DATA_PDU_LLID_DATA_FRAGMENT); + } + if(result != BLE_RESULT_OK) { + LOG_WARN("ble-hal: send was unsuccessful\n"); + return result; + } + } + } + } + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static ble_result_t +read_connection_interval(unsigned int conn_handle, unsigned int *conn_interval) +{ + ble_conn_param_t *conn = get_connection_for_handle(conn_handle); + if(conn == NULL) { + memset(conn_interval, 0x00, sizeof(uint16_t)); + return BLE_RESULT_ERROR; + } + memcpy(conn_interval, &conn->interval, sizeof(uint16_t)); + return BLE_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +const struct ble_hal_driver ble_hal = +{ + reset, + read_bd_addr, + read_buffer_size, + set_adv_param, + read_adv_channel_tx_power, + set_adv_data, + set_scan_resp_data, + set_adv_enable, + NULL, + NULL, + NULL, + NULL, + connection_update, + NULL, + send, + NULL, + read_connection_interval +}; +/*---------------------------------------------------------------------------*/ +static void +advertising_rx(ble_adv_param_t *param) +{ + uint8_t i; + uint8_t offset = 14; + uint8_t *rx_data; + ble_conn_param_t *c_param = &conn_param[0]; + rtimer_clock_t wakeup; + + while(RX_ENTRY_STATUS(param->rx_queue_current) == DATA_ENTRY_FINISHED) { + rx_data = RX_ENTRY_DATA_PTR(param->rx_queue_current); + + if(CMD_GET_STATUS(param->cmd_buf) == RF_CORE_RADIO_OP_STATUS_BLE_DONE_CONNECT) { + /* parsing connection parameter */ + for(i = 0; i < BLE_ADDR_SIZE; i++) { + c_param->peer_address[i] = rx_data[BLE_ADDR_SIZE + 1 - i]; + } + memcpy(&c_param->access_address, &rx_data[offset], 4); + memcpy(&c_param->crc_init_0, &rx_data[offset + 4], 1); + memcpy(&c_param->crc_init_1, &rx_data[offset + 5], 1); + memcpy(&c_param->crc_init_2, &rx_data[offset + 6], 1); + memcpy(&c_param->win_size, &rx_data[offset + 7], 1); + memcpy(&c_param->win_offset, &rx_data[offset + 8], 2); + memcpy(&c_param->interval, &rx_data[offset + 10], 2); + memcpy(&c_param->latency, &rx_data[offset + 12], 2); + memcpy(&c_param->timeout, &rx_data[offset + 14], 2); + memcpy(&c_param->channel_map, &rx_data[offset + 16], 5); + memcpy(&c_param->hop, &rx_data[offset + 21], 1); + memcpy(&c_param->sca, &rx_data[offset + 21], 1); + memcpy(&c_param->timestamp_rt, &rx_data[offset + 24], 4); + + /* convert all received timing values to rtimer ticks */ + + c_param->timestamp_rt = ticks_from_unit(c_param->timestamp_rt, TIME_UNIT_RF_CORE); + c_param->hop = c_param->hop & 0x1F; + c_param->sca = (c_param->sca >> 5) & 0x07; + + LOG_INFO("connection created: conn_int: %4u, latency: %3u, channel_map: %8llX\n", + c_param->interval, c_param->latency, c_param->channel_map); + + LOG_DBG("access address: 0x%08lX\n", c_param->access_address); + LOG_DBG("crc0: 0x%02X\n", c_param->crc_init_0); + LOG_DBG("crc1: 0x%02X\n", c_param->crc_init_1); + LOG_DBG("crc2: 0x%02X\n", c_param->crc_init_2); + LOG_DBG("win_size: %4u\n", c_param->win_size); + LOG_DBG("win_offset: %4u\n", c_param->win_offset); + LOG_DBG("interval: %4u\n", c_param->interval); + LOG_DBG("latency: %4u\n", c_param->latency); + LOG_DBG("timeout: %4u\n", c_param->timeout); + LOG_DBG("channel_map: %llX\n", c_param->channel_map); + + /* calculate the first anchor point + * (add an interval, because we skip the first connection event ) */ + wakeup = c_param->timestamp_rt + ticks_from_unit(c_param->win_offset, TIME_UNIT_1_25_MS) - CONN_WINDOW_WIDENING_TICKS; + wakeup += ticks_from_unit(c_param->interval, TIME_UNIT_1_25_MS) - CONN_PREPROCESSING_TIME_TICKS; + rtimer_set(&c_param->timer, wakeup, 0, connection_event_slave, (void *)c_param); + + /* initialization for the connection */ + c_param->counter = 0; + c_param->unmapped_channel = 0; + c_param->conn_handle = conn_counter; + c_param->active = 1; + conn_counter++; + LOG_INFO("BLE-HAL: connection (0x%04X) created\n", c_param->conn_handle); + } + + /* free current entry (clear BLE data length & reset status) */ + RX_ENTRY_DATA_LENGTH(param->rx_queue_current) = 0; + RX_ENTRY_STATUS(param->rx_queue_current) = DATA_ENTRY_PENDING; + param->rx_queue_current = RX_ENTRY_NEXT_ENTRY(param->rx_queue_current); + } +} +/*---------------------------------------------------------------------------*/ +static void +advertising_event(struct rtimer *t, void *ptr) +{ + ble_adv_param_t *param = (ble_adv_param_t *)ptr; + uint32_t wakeup; + + if(on() != BLE_RESULT_OK) { + LOG_ERR("BLE-HAL: advertising event: could not enable rf core\n"); + return; + } + + rf_ble_cmd_create_adv_params(param->param_buf, ¶m->rx_queue, + param->adv_data_len, param->adv_data, + param->scan_rsp_data_len, param->scan_rsp_data, + param->own_addr_type, (uint8_t *)BLE_ADDR_LOCATION); + + /* advertising on advertisement channel 1*/ + if(param->channel_map & BLE_ADV_CHANNEL_1_MASK) { + rf_ble_cmd_create_adv_cmd(param->cmd_buf, BLE_ADV_CHANNEL_1, + param->param_buf, param->output_buf); + rf_ble_cmd_send(param->cmd_buf); + rf_ble_cmd_wait(param->cmd_buf); + } + + off(); + advertising_rx(param); + + if(conn_param[0].active == 1) { + LOG_INFO("stop advertising\n"); + return; + } + + param->start_rt = param->start_rt + ticks_from_unit(param->adv_interval, TIME_UNIT_MS); + wakeup = adv_param.start_rt - ADV_PREPROCESSING_TIME_TICKS; + rtimer_set(¶m->timer, wakeup, 0, advertising_event, (void *)param); +} +/*---------------------------------------------------------------------------*/ +static void +update_data_channel(ble_conn_param_t *param) +{ + uint8_t i; + uint8_t j; + uint8_t remap_index; + /* perform the data channel selection according to BLE standard */ + + /* calculate unmapped channel*/ + param->unmapped_channel = (param->unmapped_channel + param->hop) % (BLE_DATA_CHANNEL_MAX + 1); + + /* map the calculated channel */ + if(param->channel_map & (1ULL << param->unmapped_channel)) { + /* channel is marked as used */ + param->mapped_channel = param->unmapped_channel; + } else { + remap_index = param->unmapped_channel % param->num_used_channels; + j = 0; + for(i = 0; i < (BLE_DATA_CHANNEL_MAX + 1); i++) { + if(param->channel_map & (1ULL << i)) { + if(j == remap_index) { + param->mapped_channel = i; + } + j++; + } + } + } +} +/*---------------------------------------------------------------------------*/ +static void +process_ll_ctrl_msg(ble_conn_param_t *conn, uint8_t input_len, uint8_t *input, uint8_t *output_len, uint8_t *output) +{ + uint8_t op_code = input[0]; + uint16_t interval; + uint16_t latency; + uint16_t timeout; + uint64_t channel_map = 0; + uint16_t instant = 0; + uint8_t i; + + if(op_code == BLE_LL_CONN_UPDATE_REQ) { + LOG_INFO("BLE-HAL: connection update request received\n"); + memcpy(&conn->conn_update_win_size, &input[1], 1); + memcpy(&conn->conn_update_win_offset, &input[2], 2); + memcpy(&conn->conn_update_interval, &input[4], 2); + memcpy(&conn->conn_update_latency, &input[6], 2); + memcpy(&conn->conn_update_timeout, &input[8], 2); + memcpy(&conn->conn_update_counter, &input[10], 2); + } else if(op_code == BLE_LL_CHANNEL_MAP_REQ) { + LOG_INFO("BLE-HAL: channel map update received\n"); + memcpy(&channel_map, &input[1], 5); + memcpy(&instant, &input[6], 2); + + conn->channel_update_channel_map = channel_map; + conn->channel_update_counter = instant; + conn->channel_update_num_used_channels = 0; + for(i = 0; i <= BLE_DATA_CHANNEL_MAX; i++) { + if(channel_map & (1ULL << i)) { + conn->channel_update_num_used_channels++; + } + } + } else if(op_code == BLE_LL_FEATURE_REQ) { + LOG_INFO("BLE-HAL: feature request received\n"); + output[0] = BLE_LL_FEATURE_RSP; + memset(&output[1], 0x00, 8); + *output_len = 9; + } else if(op_code == BLE_LL_VERSION_IND) { + LOG_INFO("BLE-HAL: version request received\n"); + output[0] = BLE_LL_VERSION_IND; + output[1] = 7; + memset(&output[2], 0xAA, 4); + *output_len = 6; + } else if(op_code == BLE_LL_CONN_PARAM_REQ) { + LOG_INFO("BLE-HAL: connection parameter request received\n"); + memcpy(&interval, &input[1], 2); /* use interval min */ + memcpy(&latency, &input[5], 2); + memcpy(&timeout, &input[7], 2); + connection_update(conn->conn_handle, interval, latency, timeout); + } else { + LOG_WARN("BLE-HAL: unknown LL control code: %02X\n", op_code); + } +} +/*---------------------------------------------------------------------------*/ +static void +connection_rx(ble_conn_param_t *param) +{ + uint8_t header_offset = 2; + uint8_t *rx_data; + uint16_t len; + uint8_t channel; + uint8_t frame_type; + uint8_t more_data; + uint8_t rssi; + linkaddr_t sender_addr; + rfc_bleMasterSlaveOutput_t *out_buf = (rfc_bleMasterSlaveOutput_t *)param->output_buf; + + uint8_t output_len = 0; + uint8_t output[26]; + + while(RX_ENTRY_STATUS(param->rx_queue_current) == DATA_ENTRY_FINISHED) { + rx_data = RX_ENTRY_DATA_PTR(param->rx_queue_current); + len = RX_ENTRY_DATA_LENGTH(param->rx_queue_current) - 6 - 2; /* last 8 bytes are status, timestamp, ... */ + channel = (rx_data[len + 3] & 0x3F); + frame_type = rx_data[0] & 0x03; + more_data = (rx_data[0] & 0x10) >> 4; + + if(frame_type == BLE_DATA_PDU_LLID_CONTROL) { + process_ll_ctrl_msg(param, (len - header_offset), &rx_data[header_offset], &output_len, output); + if(output_len > 0) { + send_frame(param, output, output_len, BLE_DATA_PDU_LLID_CONTROL); + } + } else if(frame_type == BLE_DATA_PDU_LLID_DATA_MESSAGE) { + packetbuf_clear(); + memcpy(packetbuf_dataptr(), &rx_data[header_offset], len); + packetbuf_set_datalen(len); + rssi = out_buf->lastRssi; + ble_addr_to_eui64(sender_addr.u8, param->peer_address); + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); + packetbuf_set_attr(PACKETBUF_ATTR_CHANNEL, channel); + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &linkaddr_node_addr); + packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &sender_addr); + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME_BLE_RX_EVENT); + if((!more_data) || (len < CONN_BLE_BUFFER_SIZE)) { + NETSTACK_MAC.input(); + } + } else if(frame_type == BLE_DATA_PDU_LLID_DATA_FRAGMENT) { + memcpy((packetbuf_dataptr() + packetbuf_datalen()), &rx_data[header_offset], len); + packetbuf_set_datalen(packetbuf_datalen() + len); + if((!more_data) || (len < CONN_BLE_BUFFER_SIZE)) { + NETSTACK_MAC.input(); + } + } + + /* free current entry (clear BLE data length & reset status) */ + RX_ENTRY_DATA_LENGTH(param->rx_queue_current) = 0; + RX_ENTRY_STATUS(param->rx_queue_current) = DATA_ENTRY_PENDING; + param->rx_queue_current = RX_ENTRY_NEXT_ENTRY(param->rx_queue_current); + } +} +/*---------------------------------------------------------------------------*/ +static void +connection_event_slave(struct rtimer *t, void *ptr) +{ + + ble_conn_param_t *conn = (ble_conn_param_t *)ptr; + rfc_bleMasterSlaveOutput_t *output = (rfc_bleMasterSlaveOutput_t *)conn->output_buf; + uint8_t first_packet = 0; + rtimer_clock_t wakeup; + uint8_t i; + uint8_t tx_data = tx_queue_data_to_transmit(conn); + + if(conn->counter == 0) { + /* the slave skips connection event 0, because it is usually too early */ + conn->start_rt = conn->timestamp_rt + ticks_from_unit(conn->win_offset, TIME_UNIT_1_25_MS) - CONN_WINDOW_WIDENING_TICKS; + update_data_channel(conn); + first_packet = 1; + } + conn->counter++; + + /* connection timing */ + if(conn->counter == conn->conn_update_counter) { + conn->start_rt += ticks_from_unit(conn->interval + conn->conn_update_win_offset, TIME_UNIT_1_25_MS); + + conn->win_size = conn->conn_update_win_size; + conn->win_offset = conn->conn_update_win_offset; + conn->interval = conn->conn_update_interval; + conn->latency = conn->conn_update_latency; + conn->timeout = conn->conn_update_timeout; + conn->conn_update_win_size = 0; + conn->conn_update_win_offset = 0; + conn->conn_update_interval = 0; + conn->conn_update_latency = 0; + conn->conn_update_timeout = 0; + } else if(output->pktStatus.bTimeStampValid) { + conn->start_rt = ticks_from_unit(output->timeStamp, TIME_UNIT_RF_CORE) + + ticks_from_unit(conn->interval, TIME_UNIT_1_25_MS) - CONN_WINDOW_WIDENING_TICKS; + } else { + conn->start_rt += ticks_from_unit(conn->interval, TIME_UNIT_1_25_MS); + } + + /* connection channel */ + if(conn->channel_update_counter == conn->counter) { + conn->channel_map = conn->channel_update_channel_map; + conn->num_used_channels = conn->channel_update_num_used_channels; + conn->channel_update_counter = 0; + conn->channel_update_channel_map = 0; + conn->channel_update_num_used_channels = 0; + } + update_data_channel(conn); + + if(tx_data || (conn->skipped_events >= conn->latency) || (conn->counter < CONN_EVENT_LATENCY_THRESHOLD)) { + /* participating in the connection event */ + conn->skipped_events = 0; + rf_ble_cmd_create_slave_params(conn->param_buf, &conn->rx_queue, &conn->tx_queue, conn->access_address, + conn->crc_init_0, conn->crc_init_1, conn->crc_init_2, + ticks_to_unit(ticks_from_unit(conn->win_size, TIME_UNIT_1_25_MS), TIME_UNIT_RF_CORE), + ticks_to_unit(CONN_WINDOW_WIDENING_TICKS, TIME_UNIT_RF_CORE), first_packet); + + rf_ble_cmd_create_slave_cmd(conn->cmd_buf, conn->mapped_channel, conn->param_buf, conn->output_buf, + ticks_to_unit(conn->start_rt, TIME_UNIT_RF_CORE)); + + if(on() != BLE_RESULT_OK) { + LOG_ERR("connection_event: could not enable radio core\n"); + return; + } + + /* append TX buffers */ + for(i = 0; i < CONN_TX_BUFFERS_NUM; i++) { + if(TX_ENTRY_STATUS(conn->tx_buffers[i]) == DATA_ENTRY_QUEUED) { + TX_ENTRY_STATUS(conn->tx_buffers[i]) = DATA_ENTRY_PENDING; + rf_ble_cmd_add_data_queue_entry(&conn->tx_queue, conn->tx_buffers[i]); + } + } + rf_ble_cmd_send(conn->cmd_buf); + rf_ble_cmd_wait(conn->cmd_buf); + off(); + + if(CMD_GET_STATUS(conn->cmd_buf) != RF_CORE_RADIO_OP_STATUS_BLE_DONE_OK) { + LOG_DBG("command status: 0x%04X; connection event counter: %d, channel: %d\n", + CMD_GET_STATUS(conn->cmd_buf), conn->counter, conn->mapped_channel); + } + + /* free finished TX buffers */ + for(i = 0; i < CONN_TX_BUFFERS_NUM; i++) { + if(TX_ENTRY_STATUS(conn->tx_buffers[i]) == DATA_ENTRY_FINISHED) { + TX_ENTRY_STATUS(conn->tx_buffers[i]) = DATA_ENTRY_FREE; + TX_ENTRY_LENGTH(conn->tx_buffers[i]) = 0; + TX_ENTRY_NEXT_ENTRY(conn->tx_buffers[i]) = NULL; + } + } + } else { + /* skipping connection event */ + conn->skipped_events++; + output->pktStatus.bTimeStampValid = 0; + } + wakeup = conn->start_rt + ticks_from_unit(conn->interval, TIME_UNIT_1_25_MS) - CONN_PREPROCESSING_TIME_TICKS; + rtimer_set(&conn->timer, wakeup, 0, connection_event_slave, ptr); + process_post(&ble_hal_conn_rx_process, rx_data_event, ptr); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(ble_hal_conn_rx_process, ev, data) { + ble_conn_param_t *conn = (ble_conn_param_t *)data; + rfc_bleMasterSlaveOutput_t *output = (rfc_bleMasterSlaveOutput_t *)conn->output_buf; + uint8_t tx_buffers_sent; + PROCESS_BEGIN(); + LOG_DBG("BLE-HAL: conn rx process start\n"); + + while(1) { + PROCESS_WAIT_EVENT_UNTIL(ev == rx_data_event); + /* notify upper layers (L2CAP) when TX buffers were successfully transmitted */ + tx_buffers_sent = output->nTxEntryDone - conn->tx_buffers_sent; + if(tx_buffers_sent != 0) { + conn->tx_buffers_sent = output->nTxEntryDone; + packetbuf_set_datalen(0); + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME_BLE_TX_EVENT); + NETSTACK_MAC.input(); + } + + /* handle RX buffers */ + connection_rx(conn); + + /* generate an event if the connection parameter were updated */ + if(conn->counter == conn->conn_update_counter) { + packetbuf_set_datalen(0); + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME_BLE_CONNECTION_UPDATED); + NETSTACK_MAC.input(); + } + } + + PROCESS_END(); +} diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h new file mode 100644 index 000000000..7f231e4be --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * hardware abstraction for the TI CC2650 controller + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ + +#ifndef BLE_HAL_CC26XX_H_ +#define BLE_HAL_CC26XX_H_ + +#include "ble-hal.h" + +extern const struct ble_hal_driver ble_hal; + +#endif /* BLE_HAL_CC26XX_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c new file mode 100644 index 000000000..051442e91 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * BLE commands for the TI CC26xx BLE radio + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" + +#include "rf_ble_cmd.h" +#include "rf-core/rf-core.h" +#include "rf-core/ble-hal/rf-ble-cmd.h" + +/*---------------------------------------------------------------------------*/ +#include "sys/log.h" +#define LOG_MODULE "BLE-RADIO" +#define LOG_LEVEL LOG_LEVEL_MAIN +/*---------------------------------------------------------------------------*/ +#define CMD_GET_STATUS(X) (((rfc_radioOp_t *)X)->status) +/*---------------------------------------------------------------------------*/ +/* values for a selection of available TX powers (values from SmartRF Studio) */ +/*static uint16_t tx_power = 0x9330; / * +5 dBm * / */ +static uint16_t tx_power = 0x3161; /* 0 dBm */ +/*static uint16_t tx_power = 0x0CCB; / * -15 dBm * / */ +/*---------------------------------------------------------------------------*/ +/* BLE overrides */ +static uint32_t ble_overrides[] = { + 0x00364038, /* Synth: Set RTRIM (POTAILRESTRIM) to 6 */ + 0x000784A3, /* Synth: Set FREF = 3.43 MHz (24 MHz / 7) */ + 0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz (K2) */ + 0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, LSB) */ + 0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, MSB) */ + 0x00456088, /* Adjust AGC reference level */ + 0x008F88B3, /* GPIO mode: https://e2e.ti.com/support/wireless_connectivity/proprietary_sub_1_ghz_simpliciti/f/156/t/488244?*/ + 0xFFFFFFFF, /* End of override list */ +}; +/*---------------------------------------------------------------------------*/ +unsigned short +rf_ble_cmd_send(uint8_t *command) +{ + uint32_t cmdsta; + rfc_radioOp_t *cmd = (rfc_radioOp_t *)command; + + if(rf_core_send_cmd((uint32_t)cmd, &cmdsta) != RF_CORE_CMD_OK) { + LOG_ERR("rf_ble_cmd_send() could not send cmd. status: 0x%04X\n", + CMD_GET_STATUS(cmd)); + return RF_BLE_CMD_ERROR; + } + return RF_BLE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ +unsigned short +rf_ble_cmd_wait(uint8_t *command) +{ + rfc_radioOp_t *cmd = (rfc_radioOp_t *)command; + if(rf_core_wait_cmd_done((void *)cmd) != RF_CORE_CMD_OK) { + LOG_ERR("rf_ble_cmd_wait() could not wait. status: 0x%04X\n", + CMD_GET_STATUS(cmd)); + return RF_BLE_CMD_ERROR; + } + return RF_BLE_CMD_OK; +} +/*---------------------------------------------------------------------------*/ +unsigned short +rf_ble_cmd_setup_ble_mode(void) +{ + rfc_CMD_RADIO_SETUP_t cmd; + + /* Create radio setup command */ + rf_core_init_radio_op((rfc_radioOp_t *)&cmd, sizeof(cmd), CMD_RADIO_SETUP); + + cmd.txPower = tx_power; + cmd.pRegOverride = ble_overrides; + cmd.mode = 0; + + /* Send Radio setup to RF Core */ + if(rf_ble_cmd_send((uint8_t *)&cmd) != RF_BLE_CMD_OK) { + return RF_BLE_CMD_ERROR; + } + + /* Wait until radio setup is done */ + return rf_ble_cmd_wait((uint8_t *)&cmd); +} +/*---------------------------------------------------------------------------*/ +/* ADVERTISING functions */ +void +rf_ble_cmd_create_adv_cmd(uint8_t *command, uint8_t channel, + uint8_t *param, uint8_t *output) +{ + rfc_CMD_BLE_ADV_t *c = (rfc_CMD_BLE_ADV_t *)command; + + memset(c, 0x00, sizeof(rfc_CMD_BLE_ADV_t)); + c->commandNo = CMD_BLE_ADV; + c->condition.rule = COND_NEVER; + c->whitening.bOverride = 0; + c->channel = channel; + c->pParams = (rfc_bleAdvPar_t *)param; + c->startTrigger.triggerType = TRIG_NOW; + c->pOutput = (rfc_bleAdvOutput_t *)output; +} +/*---------------------------------------------------------------------------*/ +void +rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, + uint8_t adv_data_len, uint8_t *adv_data, + uint8_t scan_resp_data_len, uint8_t *scan_resp_data, + ble_addr_type_t own_addr_type, uint8_t *own_addr) +{ + rfc_bleAdvPar_t *p = (rfc_bleAdvPar_t *)param; + + memset(p, 0x00, sizeof(rfc_bleAdvPar_t)); + + p->pRxQ = rx_queue; + p->rxConfig.bAutoFlushIgnored = 1; + p->rxConfig.bAutoFlushCrcErr = 0; + p->rxConfig.bAutoFlushEmpty = 1; + p->rxConfig.bIncludeLenByte = 1; + p->rxConfig.bIncludeCrc = 0; + p->rxConfig.bAppendRssi = 1; + p->rxConfig.bAppendStatus = 1; + p->rxConfig.bAppendTimestamp = 1; + p->advConfig.advFilterPolicy = 0; + p->advConfig.bStrictLenFilter = 0; + p->advConfig.deviceAddrType = own_addr_type; + p->pDeviceAddress = (uint16_t *)own_addr; + p->advLen = adv_data_len; + p->scanRspLen = scan_resp_data_len; + p->pAdvData = adv_data; + p->pScanRspData = scan_resp_data; + p->endTrigger.triggerType = TRIG_NEVER; +} +/*---------------------------------------------------------------------------*/ +/* CONNECTION slave functions */ +/*---------------------------------------------------------------------------*/ +void +rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, + uint8_t *output, uint32_t start_time) +{ + rfc_CMD_BLE_SLAVE_t *c = (rfc_CMD_BLE_SLAVE_t *)cmd; + + memset(c, 0x00, sizeof(rfc_CMD_BLE_SLAVE_t)); + + c->commandNo = CMD_BLE_SLAVE; + c->condition.rule = COND_NEVER; + c->whitening.bOverride = 0; + c->channel = channel; + c->pParams = (rfc_bleSlavePar_t *)params; + c->startTrigger.triggerType = TRIG_ABSTIME; + c->startTrigger.pastTrig = 0; + c->startTime = start_time; + c->pOutput = (rfc_bleMasterSlaveOutput_t *)output; +} +/*---------------------------------------------------------------------------*/ +void +rf_ble_cmd_create_slave_params(uint8_t *params, dataQueue_t *rx_queue, + dataQueue_t *tx_queue, uint32_t access_address, + uint8_t crc_init_0, uint8_t crc_init_1, + uint8_t crc_init_2, uint32_t win_size, + uint32_t window_widening, uint8_t first_packet) +{ + rfc_bleSlavePar_t *p = (rfc_bleSlavePar_t *)params; + + p->pRxQ = rx_queue; + p->pTxQ = tx_queue; + p->rxConfig.bAutoFlushIgnored = 1; + p->rxConfig.bAutoFlushCrcErr = 1; + p->rxConfig.bAutoFlushEmpty = 1; + p->rxConfig.bIncludeLenByte = 1; + p->rxConfig.bIncludeCrc = 0; + p->rxConfig.bAppendRssi = 1; + p->rxConfig.bAppendStatus = 1; + p->rxConfig.bAppendTimestamp = 1; + + if(first_packet) { + /* set parameters for first packet according to TI Technical Reference Manual */ + p->seqStat.lastRxSn = 1; + p->seqStat.lastTxSn = 1; + p->seqStat.nextTxSn = 0; + p->seqStat.bFirstPkt = 1; + p->seqStat.bAutoEmpty = 0; + p->seqStat.bLlCtrlTx = 0; + p->seqStat.bLlCtrlAckRx = 0; + p->seqStat.bLlCtrlAckPending = 0; + } + + p->maxNack = 0; + p->maxPkt = 0; + p->accessAddress = access_address; + p->crcInit0 = crc_init_0; + p->crcInit1 = crc_init_1; + p->crcInit2 = crc_init_2; + p->timeoutTrigger.triggerType = TRIG_REL_START; + if(first_packet) { + p->timeoutTime = (uint32_t)(10 * win_size); + } else { + p->timeoutTime = (uint32_t)(win_size + 2 * window_widening); + } + p->endTrigger.triggerType = TRIG_NEVER; +} +/*---------------------------------------------------------------------------*/ +/* DATA queue functions */ +/*---------------------------------------------------------------------------*/ +unsigned short +rf_ble_cmd_add_data_queue_entry(dataQueue_t *q, uint8_t *e) +{ + uint32_t cmdsta; + + rfc_CMD_ADD_DATA_ENTRY_t cmd; + cmd.commandNo = CMD_ADD_DATA_ENTRY; + cmd.pQueue = q; + cmd.pEntry = e; + + if(rf_core_send_cmd((uint32_t)&cmd, &cmdsta) != RF_CORE_CMD_OK) { + LOG_ERR("could not add entry to data queue. status: 0x%04X\n", + CMD_GET_STATUS(&cmd)); + return RF_BLE_CMD_ERROR; + } + return RF_BLE_CMD_OK; +} diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h new file mode 100644 index 000000000..526166cda --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * BLE commands for the TI CC26xx BLE radio + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ + +#ifndef RF_BLE_CMD_H_ +#define RF_BLE_CMD_H_ + +#include "../../ble-addr.h" +#include "ble-hal.h" +#include "rf_common_cmd.h" + +#define RF_BLE_CMD_OK 1 +#define RF_BLE_CMD_ERROR 0 + +unsigned short rf_ble_cmd_send(uint8_t *cmd); + +unsigned short rf_ble_cmd_wait(uint8_t *cmd); + +unsigned short rf_ble_cmd_setup_ble_mode(void); + +void rf_ble_cmd_create_adv_cmd(uint8_t *command, uint8_t channel, + uint8_t *param, uint8_t *output); + +void rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, + uint8_t adv_data_len, uint8_t *adv_data, + uint8_t scan_resp_data_len, uint8_t *scan_resp_data, + ble_addr_type_t own_addr_type, uint8_t *own_addr); + +void rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, + uint8_t *output, uint32_t start_time); + +void rf_ble_cmd_create_slave_params(uint8_t *params, dataQueue_t *rx_queue, + dataQueue_t *tx_queue, uint32_t access_address, + uint8_t crc_init_0, uint8_t crc_init_1, + uint8_t crc_init_2, uint32_t win_size, + uint32_t window_widening, uint8_t first_packet); + +unsigned short rf_ble_cmd_add_data_queue_entry(dataQueue_t *q, uint8_t *e); + +#endif /* RF_BLE_CMD_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c new file mode 100644 index 000000000..d3f2a0217 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * MAC layer that implements BLE L2CAP credit-based flow control + * channels to support IPv6 over BLE (RFC 7668) + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ + +#include "ble-hal.h" +#include "net/packetbuf.h" +#include "net/netstack.h" + +#include "lib/memb.h" +#include "lib/list.h" + +#include +/*---------------------------------------------------------------------------*/ +#include "sys/log.h" +#define LOG_MODULE "L2CAP" +#define LOG_LEVEL LOG_LEVEL_MAC +/*---------------------------------------------------------------------------*/ +/* device name used for BLE advertisement */ +#ifdef BLE_CONF_DEVICE_NAME +#define BLE_DEVICE_NAME BLE_CONF_DEVICE_NAME +#else +#define BLE_DEVICE_NAME "BLE device name" +#endif + +/* BLE advertisement in milliseconds */ +#ifdef BLE_CONF_ADV_INTERVAL +#define BLE_ADV_INTERVAL BLE_CONF_ADV_INTERVAL +#else +#define BLE_ADV_INTERVAL 50 +#endif + +#define BLE_SLAVE_CONN_INTERVAL_MIN 0x0150 +#define BLE_SLAVE_CONN_INTERVAL_MAX 0x01F0 +#define L2CAP_SIGNAL_CHANNEL 0x0005 +#define L2CAP_FLOW_CHANNEL 0x0041 +#define L2CAP_CODE_CONN_UPDATE_REQ 0x12 +#define L2CAP_CODE_CONN_UPDATE_RSP 0x13 +#define L2CAP_CODE_CONN_REQ 0x14 +#define L2CAP_CODE_CONN_RSP 0x15 +#define L2CAP_CODE_CREDIT 0x16 +#define L2CAP_IPSP_PSM 0x0023 + +/* the maximum MTU size of the L2CAP channel */ +#ifdef BLE_L2CAP_CONF_NODE_MTU +#define BLE_L2CAP_NODE_MTU BLE_L2CAP_CONF_NODE_MTU +#else +#define BLE_L2CAP_NODE_MTU 1280 +#endif + +/* the max. supported L2CAP fragment length */ +#ifdef BLE_L2CAP_CONF_NODE_FRAG_LEN +#define BLE_L2CAP_NODE_FRAG_LEN BLE_L2CAP_CONF_NODE_FRAG_LEN +#else +#ifdef BLE_MODE_CONF_CONN_MAX_PACKET_SIZE +#define BLE_L2CAP_NODE_FRAG_LEN BLE_MODE_CONF_CONN_MAX_PACKET_SIZE +#else +#define BLE_L2CAP_NODE_FRAG_LEN 256 +#endif +#endif + +#define L2CAP_CREDIT_NEW (BLE_L2CAP_NODE_MTU / BLE_L2CAP_NODE_FRAG_LEN) +#define L2CAP_CREDIT_THRESHOLD 2 + +#define L2CAP_INIT_INTERVAL (2 * CLOCK_SECOND) + +/* BLE connection interval in milliseconds */ +#ifdef BLE_CONF_CONNECTION_INTERVAL +#define CONNECTION_INTERVAL_MS BLE_CONF_CONNECTION_INTERVAL +#else +#define CONNECTION_INTERVAL_MS 125 +#endif + +/* BLE slave latency */ +#ifdef BLE_CONF_CONNECTION_SLAVE_LATENCY +#define CONNECTION_SLAVE_LATENCY BLE_CONF_CONNECTION_SLAVE_LATENCY +#else +#define CONNECTION_SLAVE_LATENCY 0 +#endif + +/* BLE supervision timeout */ +#define CONNECTION_TIMEOUT 42 + +#define MS_TO_CLOCK_SECONDS(X) ((int)(((double)((X)*CLOCK_SECOND)) / 1000.0)) + +#define L2CAP_FIRST_HEADER_SIZE 6 +#define L2CAP_SUBSEQ_HEADER_SIZE 4 +/*---------------------------------------------------------------------------*/ +/* BLE controller */ +/* public device address of BLE controller */ +static uint8_t ble_addr[BLE_ADDR_SIZE]; +/*---------------------------------------------------------------------------*/ +#if UIP_CONF_ROUTER +#ifdef BLE_MODE_CONF_MAX_CONNECTIONS +#define L2CAP_CHANNELS BLE_MODE_CONF_MAX_CONNECTIONS +#else +#define L2CAP_CHANNELS 1 +#endif +#else +#define L2CAP_CHANNELS 1 +#endif +/*---------------------------------------------------------------------------*/ +/* L2CAP fragmentation buffers and utilities */ +typedef struct { + /* L2CAP Service Data Unit (SDU) (= packet data)*/ + uint8_t sdu[BLE_L2CAP_NODE_MTU]; + /* length of the L2CAP SDU */ + uint16_t sdu_length; + /* index of the first byte not sent yet */ + uint16_t current_index; +} l2cap_buffer_t; +/*---------------------------------------------------------------------------*/ +typedef struct { + uint16_t cid; + uint16_t mtu; + uint16_t mps; + uint16_t credits; +} ble_mac_l2cap_channel_t; +/*---------------------------------------------------------------------------*/ +typedef struct { + ble_mac_l2cap_channel_t channel_own; + ble_mac_l2cap_channel_t channel_peer; + l2cap_buffer_t tx_buffer; + l2cap_buffer_t rx_buffer; + linkaddr_t peer_addr; +} l2cap_channel_t; + +static uint8_t l2cap_channel_count; +static l2cap_channel_t l2cap_channels[L2CAP_CHANNELS]; +static process_event_t l2cap_tx_event; +/*---------------------------------------------------------------------------*/ +static l2cap_channel_t * +get_channel_for_addr(const linkaddr_t *peer_addr) +{ + uint8_t i; + l2cap_channel_t *channel; + for(i = 0; i < l2cap_channel_count; i++) { + channel = &l2cap_channels[i]; + if(linkaddr_cmp(peer_addr, &channel->peer_addr) != 0) { + return channel; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static l2cap_channel_t * +get_channel_for_cid(uint16_t own_cid) +{ + uint8_t i = own_cid - L2CAP_FLOW_CHANNEL; + if(i >= 0 && i < l2cap_channel_count) { + return &l2cap_channels[own_cid - L2CAP_FLOW_CHANNEL]; + } else { + return NULL; + } +} +/*---------------------------------------------------------------------------*/ +PROCESS(ble_l2cap_tx_process, "BLE L2CAP TX process"); +/*---------------------------------------------------------------------------*/ +static uint8_t +init_adv_data(char *adv_data) +{ + uint8_t adv_data_len = 0; + memset(adv_data, 0x00, BLE_ADV_DATA_LEN); + /* BLE flags */ + adv_data[adv_data_len++] = 2; + adv_data[adv_data_len++] = 0x01; + adv_data[adv_data_len++] = 0x05; /* LE limited (no BR/EDR support) */ + /* TX power level */ + adv_data[adv_data_len++] = 2; + adv_data[adv_data_len++] = 0x0A; + adv_data[adv_data_len++] = 0; /* 0 dBm */ + /* service UUIDs (16-bit identifiers) */ + adv_data[adv_data_len++] = 3; + adv_data[adv_data_len++] = 0x03; + adv_data[adv_data_len++] = 0x20; + adv_data[adv_data_len++] = 0x18; /* only IP support service exposed */ + /* service UUIDs (32-bit identifiers) */ + adv_data[adv_data_len++] = 1; + adv_data[adv_data_len++] = 0x05; /* empty list */ + /* service UUIDs (128-bit identifiers) */ + adv_data[adv_data_len++] = 1; + adv_data[adv_data_len++] = 0x07; /* empty list */ + return adv_data_len; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +init_scan_resp_data(char *scan_resp_data) +{ + uint8_t scan_resp_data_len = 0; + memset(scan_resp_data, 0x00, BLE_SCAN_RESP_DATA_LEN); + /* complete device name */ + scan_resp_data[scan_resp_data_len++] = 1 + strlen(BLE_DEVICE_NAME); + scan_resp_data[scan_resp_data_len++] = 0x09; + memcpy(&scan_resp_data[scan_resp_data_len], + BLE_DEVICE_NAME, strlen(BLE_DEVICE_NAME)); + scan_resp_data_len += strlen(BLE_DEVICE_NAME); + /* slave connection interval range */ + scan_resp_data[scan_resp_data_len++] = 5; + scan_resp_data[scan_resp_data_len++] = 0x12; + scan_resp_data[scan_resp_data_len++] = (BLE_SLAVE_CONN_INTERVAL_MIN & 0xFF); + scan_resp_data[scan_resp_data_len++] = ((BLE_SLAVE_CONN_INTERVAL_MIN >> 8) & 0xFF); + scan_resp_data[scan_resp_data_len++] = (BLE_SLAVE_CONN_INTERVAL_MAX & 0xFF); + scan_resp_data[scan_resp_data_len++] = ((BLE_SLAVE_CONN_INTERVAL_MAX >> 8) & 0xFF); + + return scan_resp_data_len; +} +/*---------------------------------------------------------------------------*/ +void +input_l2cap_conn_req(uint8_t *data) +{ + uint8_t identifier = data[0]; + uint16_t len; + uint16_t le_psm; + uint8_t resp_data[18]; + l2cap_channel_t *channel; + + memcpy(&len, &data[1], 2); + + if(len != 10) { + LOG_WARN("l2cap_conn_req: invalid len: %d\n", len); + return; + } + + /* create a new L2CAP connection because of this request */ + if(l2cap_channel_count >= L2CAP_CHANNELS) { + LOG_WARN("l2cap_conn_req: maximum supported L2CAP channels reached\n"); + return; + } + + channel = &l2cap_channels[l2cap_channel_count]; + /* parse L2CAP connection data */ + memcpy(&le_psm, &data[3], 2); + memset(&channel->channel_peer, 0x00, sizeof(ble_mac_l2cap_channel_t)); + memcpy(&channel->channel_peer.cid, &data[5], 2); + memcpy(&channel->channel_peer.mtu, &data[7], 2); + memcpy(&channel->channel_peer.mps, &data[9], 2); + memcpy(&channel->channel_peer.credits, &data[11], 2); + linkaddr_copy(&channel->peer_addr, packetbuf_addr(PACKETBUF_ADDR_SENDER)); + + LOG_INFO("recv CONN_REQ (MTU: %4d, MPS: %4d, credits: %4d)\n", + channel->channel_peer.mtu, channel->channel_peer.mps, channel->channel_peer.credits); + + l2cap_channel_count++; + + /* create L2CAP connection response */ + /* length */ + resp_data[0] = 0x0E; + resp_data[1] = 0x00; + /* channel ID */ + resp_data[2] = 0x05; + resp_data[3] = 0x00; + /* code */ + resp_data[4] = L2CAP_CODE_CONN_RSP; + /* identifier */ + resp_data[5] = identifier; + /* cmd length */ + resp_data[6] = 0x0A; + resp_data[7] = 0x00; + /* node channel information */ + memcpy(&resp_data[8], &channel->channel_own.cid, 2); + memcpy(&resp_data[10], &channel->channel_own.mtu, 2); + memcpy(&resp_data[12], &channel->channel_own.mps, 2); + memcpy(&resp_data[14], &channel->channel_own.credits, 2); + /* result */ + memset(&resp_data[16], 0x00, 2); + + packetbuf_copyfrom((void *)resp_data, 18); + packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &channel->peer_addr); + NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); +} +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + uint8_t i; + l2cap_tx_event = process_alloc_event(); + LOG_DBG("init()\n"); + /* initialize the L2CAP connection parameter */ + for(i = 0; i < L2CAP_CHANNELS; i++) { + l2cap_channels[i].channel_own.cid = L2CAP_FLOW_CHANNEL + i; + l2cap_channels[i].channel_own.credits = L2CAP_CREDIT_NEW; + l2cap_channels[i].channel_own.mps = (BLE_L2CAP_NODE_FRAG_LEN - L2CAP_SUBSEQ_HEADER_SIZE); + l2cap_channels[i].channel_own.mtu = BLE_L2CAP_NODE_MTU; + } + + /* Initialize the BLE controller */ + NETSTACK_RADIO.init(); + NETSTACK_RADIO.get_object(RADIO_CONST_BLE_BD_ADDR, &ble_addr, BLE_ADDR_SIZE); + + uint8_t adv_data_len, scan_resp_data_len; + char adv_data[BLE_ADV_DATA_LEN]; + char scan_resp_data[BLE_SCAN_RESP_DATA_LEN]; + /* set the advertisement parameter */ + NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_INTERVAL, BLE_ADV_INTERVAL); + NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_TYPE, BLE_ADV_DIR_IND_LDC); + NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_OWN_ADDR_TYPE, BLE_ADDR_TYPE_PUBLIC); + NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_CHANNEL_MAP, 0x01); + + adv_data_len = init_adv_data(adv_data); + scan_resp_data_len = init_scan_resp_data(scan_resp_data); + + /* set advertisement payload & scan response */ + NETSTACK_RADIO.set_object(RADIO_PARAM_BLE_ADV_PAYLOAD, adv_data, adv_data_len); + NETSTACK_RADIO.set_object(RADIO_PARAM_BLE_ADV_SCAN_RESPONSE, scan_resp_data, scan_resp_data_len); + + /* enable advertisement */ + NETSTACK_RADIO.set_value(RADIO_PARAM_BLE_ADV_ENABLE, 1); + + NETSTACK_MAC.on(); +} +/*---------------------------------------------------------------------------*/ +static uint16_t +check_own_l2cap_credits(l2cap_channel_t *channel) +{ + uint16_t credits_new = 0; + uint16_t credits_current; + + credits_current = channel->channel_own.credits; + if(credits_current < L2CAP_CREDIT_THRESHOLD) { + credits_new = L2CAP_CREDIT_NEW; + } + LOG_DBG("check for new credits: current credits: %2d, new credits: %2d\n", credits_current, credits_new); + return credits_new; +} +/*---------------------------------------------------------------------------*/ +static void +send_l2cap_credit(l2cap_channel_t *channel, uint16_t credits) +{ + uint8_t len = 4; + uint8_t data[12]; + /* create L2CAP credit */ + /* length */ + data[0] = len + 4; + data[1] = 0x00; + /* channel ID */ + data[2] = 0x05; + data[3] = 0x00; + /* code */ + data[4] = L2CAP_CODE_CREDIT; + /* identifier */ + data[5] = 0xFF; + /* cmd length */ + data[6] = len; + data[7] = 0x00; + + memcpy(&data[8], &channel->channel_own.cid, 2); + data[10] = credits & 0xFF; + data[11] = credits >> 8; + + channel->channel_own.credits += credits; + + packetbuf_copyfrom((void *)data, len + 8); + packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &channel->peer_addr); + NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); +} +/*---------------------------------------------------------------------------*/ +static void +send(mac_callback_t sent_callback, void *ptr) +{ + uint8_t i; + l2cap_channel_t *channel; + uint16_t data_len = packetbuf_datalen(); + LOG_DBG("send %d\n", data_len); + + /* packet is too long */ + if(data_len > BLE_L2CAP_NODE_MTU) { + LOG_WARN("send message is too long\n"); + mac_call_sent_callback(sent_callback, ptr, MAC_TX_ERR, 0); + return; + } + + for(i = 0; i < l2cap_channel_count; i++) { + channel = &l2cap_channels[i]; + if((linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null) != 0) + || (linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &channel->peer_addr) != 0)) { + if(channel->tx_buffer.sdu_length > 0) { + LOG_WARN("send() another L2CAP message active (trying to send %4d bytes)\n", data_len); + mac_call_sent_callback(sent_callback, ptr, MAC_TX_COLLISION, 0); + return; + } + LOG_DBG("send() adding to L2CAP CID: %2d\n", channel->channel_own.cid); + channel->tx_buffer.sdu_length = data_len; + if(channel->tx_buffer.sdu_length > 0) { + memcpy(&channel->tx_buffer.sdu, packetbuf_dataptr(), data_len); + mac_call_sent_callback(sent_callback, ptr, MAC_TX_DEFERRED, 1); + process_post(&ble_l2cap_tx_process, l2cap_tx_event, (void *)channel); + } + } + } +} +/*---------------------------------------------------------------------------*/ +void +input_l2cap_connection_udate_resp(uint8_t *data) +{ + uint16_t len; + uint16_t result; + + memcpy(&len, &data[1], 2); + + if(len != 2) { + LOG_WARN("input_l2cap_connection_update_resp: invalid len: %d\n", len); + return; + } + + memcpy(&result, &data[3], 2); + if(result != 0x0000) { + LOG_WARN("input_l2cap_connection_update_resp: result: 0x%04X\n", result); + return; + } +} +/*---------------------------------------------------------------------------*/ +void +input_l2cap_credit(uint8_t *data) +{ + uint16_t len; + uint16_t cid; + uint16_t credits; + l2cap_channel_t *channel = get_channel_for_addr(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + +/* uint8_t identifier = data[0]; */ + memcpy(&len, &data[1], 2); + + if(len != 4) { + LOG_WARN("process_l2cap_credit: invalid len: %d\n", len); + return; + } + + /* parse L2CAP credit data */ + memcpy(&cid, &data[3], 2); + memcpy(&credits, &data[5], 2); + + channel->channel_peer.credits += credits; +} +/*---------------------------------------------------------------------------*/ +static void +input_l2cap_frame_signal_channel(uint8_t *data, uint8_t data_len) +{ + if(data[4] == L2CAP_CODE_CREDIT) { + input_l2cap_credit(&data[5]); + } else if(data[4] == L2CAP_CODE_CONN_REQ) { + input_l2cap_conn_req(&data[5]); + } else if(data[4] == L2CAP_CODE_CONN_UPDATE_RSP) { + input_l2cap_connection_udate_resp(&data[5]); + } else { + LOG_WARN("l2cap_frame_signal_channel: unknown signal channel code: %d\n", data[4]); + } +} +/*---------------------------------------------------------------------------*/ +static void +input_l2cap_frame_flow_channel(l2cap_channel_t *channel, uint8_t *data, uint16_t data_len) +{ + uint16_t frame_len; + uint16_t payload_len; + + if(data_len < 4) { + LOG_WARN("l2cap_frame: illegal L2CAP frame data_len: %d\n", data_len); + /* a L2CAP frame has a minimum length of 4 */ + return; + } + + if(channel->rx_buffer.sdu_length == 0) { + /* handle first fragment */ + memcpy(&frame_len, &data[0], 2); + memcpy(&channel->rx_buffer.sdu_length, &data[4], 2); + payload_len = frame_len - 2; + + memcpy(channel->rx_buffer.sdu, &data[6], payload_len); + channel->rx_buffer.current_index = payload_len; + } else { + /* subsequent fragment */ + memcpy(&frame_len, &data[0], 2); + payload_len = frame_len; + + memcpy(&channel->rx_buffer.sdu[channel->rx_buffer.current_index], &data[4], payload_len); + channel->rx_buffer.current_index += payload_len; + } + + if((channel->rx_buffer.sdu_length > 0) && + (channel->rx_buffer.sdu_length == channel->rx_buffer.current_index)) { + /* do not use packetbuf_copyfrom here because the packetbuf_attr + * must not be cleared */ + memcpy(packetbuf_dataptr(), channel->rx_buffer.sdu, channel->rx_buffer.sdu_length); + packetbuf_set_datalen(channel->rx_buffer.sdu_length); + NETSTACK_NETWORK.input(); + + /* reset counters */ + channel->rx_buffer.sdu_length = 0; + channel->rx_buffer.current_index = 0; + } +} +/*---------------------------------------------------------------------------*/ +static void +input(void) +{ + uint8_t *data = (uint8_t *)packetbuf_dataptr(); + uint16_t len = packetbuf_datalen(); + uint8_t frame_type = packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE); + uint16_t channel_id; + l2cap_channel_t *channel; + uint16_t credits; + + if(frame_type == FRAME_BLE_RX_EVENT) { + memcpy(&channel_id, &data[2], 2); + channel = get_channel_for_cid(channel_id); + LOG_DBG("input %d bytes\n", len); + if(channel_id == L2CAP_SIGNAL_CHANNEL) { + input_l2cap_frame_signal_channel(data, len); + } else if(channel == NULL) { + LOG_WARN("input (RX_EVENT): no channel found for CID: %d\n", channel_id); + return; + } else { + input_l2cap_frame_flow_channel(channel, data, len); + channel->channel_own.credits--; + credits = check_own_l2cap_credits(channel); + if(credits > 0) { + send_l2cap_credit(channel, credits); + } + } + } + /* check if there are still fragments left to be transmitted */ + if(frame_type == FRAME_BLE_TX_EVENT) { + channel = get_channel_for_addr(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + if(channel == NULL) { + LOG_WARN("input (TX_EVENT): no channel found for CID: %d\n", channel_id); + } else if(channel->tx_buffer.sdu_length > 0) { + process_post(&ble_l2cap_tx_process, l2cap_tx_event, (void *)channel); + } + } +} +/*---------------------------------------------------------------------------*/ +static int +on(void) +{ + LOG_DBG("on()\n"); + process_start(&ble_l2cap_tx_process, NULL); + return 0; +} +/*---------------------------------------------------------------------------*/ +static int +off(void) +{ + LOG_DBG("off()\n"); + process_exit(&ble_l2cap_tx_process); + return 0; +} +/*---------------------------------------------------------------------------*/ +const struct mac_driver ble_l2cap_driver = { + "ble-l2cap", + init, + send, + input, + on, + off, + NULL, +}; +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(ble_l2cap_tx_process, ev, data) +{ + uint16_t data_len; + uint16_t frame_len; + uint16_t num_buffer; + l2cap_channel_t *channel = (l2cap_channel_t *)data; + uint8_t first_fragment; + uint16_t used_mps; + uint16_t credits; + + PROCESS_BEGIN(); + LOG_DBG("starting ble_mac_tx_process\n"); + + while(1) { + PROCESS_YIELD_UNTIL(ev == l2cap_tx_event); + if(channel != NULL) { + NETSTACK_RADIO.get_value(RADIO_CONST_BLE_BUFFER_AMOUNT, (radio_value_t *)&num_buffer); + first_fragment = (channel->tx_buffer.current_index == 0); + used_mps = MIN(channel->channel_own.mps, channel->channel_peer.mps); + credits = channel->channel_peer.credits; + + LOG_DBG("process: sending - first: %d, used_mps: %3d, num_buffers: %2d, credits: %2d\n", + first_fragment, used_mps, num_buffer, credits); + if((channel->tx_buffer.sdu_length > 0) && (num_buffer > 0) && (credits > 0)) { + packetbuf_clear(); + if(first_fragment) { + packetbuf_hdralloc(L2CAP_FIRST_HEADER_SIZE); + used_mps -= L2CAP_FIRST_HEADER_SIZE; + data_len = MIN(channel->tx_buffer.sdu_length, used_mps); + frame_len = data_len + 2; + + /* set L2CAP header fields */ + memcpy(packetbuf_hdrptr(), &frame_len, 2); /* fragment size */ + memcpy(packetbuf_hdrptr() + 2, &channel->channel_peer.cid, 2); /* L2CAP channel id*/ + memcpy(packetbuf_hdrptr() + 4, &channel->tx_buffer.sdu_length, 2); /* overall packet size */ + } else { + packetbuf_hdralloc(L2CAP_SUBSEQ_HEADER_SIZE); + used_mps -= L2CAP_SUBSEQ_HEADER_SIZE; + data_len = MIN((channel->tx_buffer.sdu_length - channel->tx_buffer.current_index), used_mps); + frame_len = data_len; + + /* set L2CAP header fields */ + memcpy(packetbuf_hdrptr(), &frame_len, 2); /* fragment size */ + memcpy(packetbuf_hdrptr() + 2, &channel->channel_peer.cid, 2); /* L2CAP channel id*/ + } + + /* copy payload */ + memcpy(packetbuf_dataptr(), + &channel->tx_buffer.sdu[channel->tx_buffer.current_index], + data_len); + packetbuf_set_datalen(data_len); + channel->tx_buffer.current_index += data_len; + + /* send the fragment */ + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &channel->peer_addr); + packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); + NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen()); + channel->channel_peer.credits--; + + /* reset the L2CAP TX buffer if packet is finished */ + if(channel->tx_buffer.current_index == channel->tx_buffer.sdu_length) { + channel->tx_buffer.current_index = 0; + channel->tx_buffer.sdu_length = 0; + } + } + } else { + LOG_WARN("process. channel is NULL\n"); + } + } + + PROCESS_END(); + LOG_DBG("stopped ble_mac_tx_process\n"); +} diff --git a/arch/platform/srf06-cc26xx/contiki-conf.h b/arch/platform/srf06-cc26xx/contiki-conf.h index fbe9c5059..63c6ac712 100644 --- a/arch/platform/srf06-cc26xx/contiki-conf.h +++ b/arch/platform/srf06-cc26xx/contiki-conf.h @@ -94,7 +94,9 @@ #define CSMA_CONF_SEND_SOFT_ACK 1 #else /* CC13XX_CONF_PROP_MODE */ +#ifndef NETSTACK_CONF_RADIO #define NETSTACK_CONF_RADIO ieee_mode_driver +#endif #define CSMA_CONF_SEND_SOFT_ACK 0 #endif /* CC13XX_CONF_PROP_MODE */ @@ -269,7 +271,7 @@ typedef uint32_t rtimer_clock_t; #if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256) #error RADIO_TO_RTIMER macro must be fixed! #endif -#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) +#define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X)*(RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) #define USEC_TO_RADIO(X) ((X) * 4) /* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ @@ -279,7 +281,7 @@ typedef uint32_t rtimer_clock_t; #define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 /* Disable TSCH frame filtering */ -#define TSCH_CONF_HW_FRAME_FILTERING 0 +#define TSCH_CONF_HW_FRAME_FILTERING 0 /* Use hardware timestamps */ #ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS diff --git a/arch/platform/srf06-cc26xx/platform.c b/arch/platform/srf06-cc26xx/platform.c index 7b8a8c477..c2868af13 100644 --- a/arch/platform/srf06-cc26xx/platform.c +++ b/arch/platform/srf06-cc26xx/platform.c @@ -52,6 +52,7 @@ #include "gpio-interrupt.h" #include "dev/oscillators.h" #include "ieee-addr.h" +#include "ble-addr.h" #include "vims.h" #include "dev/cc26xx-uart.h" #include "dev/soc-rtc.h" @@ -104,9 +105,14 @@ fade(unsigned char l) static void set_rf_params(void) { - uint16_t short_addr; uint8_t ext_addr[8]; +#if MAKE_MAC == MAKE_MAC_OTHER + ble_eui64_addr_cpy_to((uint8_t *)&ext_addr); + memcpy(&linkaddr_node_addr, &ext_addr[8 - LINKADDR_SIZE], LINKADDR_SIZE); + NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); +#else + uint16_t short_addr; ieee_addr_cpy_to(ext_addr, 8); short_addr = ext_addr[7]; @@ -119,6 +125,7 @@ set_rf_params(void) /* also set the global node id */ node_id = short_addr; +#endif } /*---------------------------------------------------------------------------*/ void diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile new file mode 100644 index 000000000..7000fd8c7 --- /dev/null +++ b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile @@ -0,0 +1,9 @@ +DEFINES+=PROJECT_CONF_H=\"project-conf.h\" +CONTIKI_PROJECT=client + +all: $(CONTIKI_PROJECT) + + + +CONTIKI = ../../../.. +include $(CONTIKI)/Makefile.include \ No newline at end of file diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md new file mode 100644 index 000000000..380075bdc --- /dev/null +++ b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md @@ -0,0 +1,28 @@ +# CC26xx IPv6-over-BLE client demo + +This example provides a simple implementation of a UDP client that connects +to a UDP server via IPv6-over-BLE [RFC 7668](https://tools.ietf.org/html/rfc7668). + +After booting, the node sends an ICMPv6 echo request (ping) to the configured server address +and waits for an ICMPv6 echo response. +When a response is received, the client start to send a UDP packet with content +`Hello server !` to the server, where is a packet counter that is incremented every time a UDP packet is sent. +If the server respondes with a UDP packet, the content of the packet is printed in the console. + +## Requirements +To run this example, you will need a [RFC 7668](https://tools.ietf.org/html/rfc7668)-compliant border router. +One possible border router is the Raspberry Pi 3 with the Raspbian OS +(for detailed instructions see the [Nordic Semiconductor guide](http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00092.html)). + +## Configuration +In addition to the configuration described in [BLEach README](../../../../arch/cpu/cc26xx-cc13xx/net/README.md) the following configuration is needed. + +To successfully communicate with a UDP server, the `SERVER_IP` define in `client.c` needs to be configured +to the IPv6 address of the UDP server. +For example: +``` +#define SERVER_IP "fe80::1" +``` +## Running the example +Deploy your border router and create the IPv6-over-BLE connection to the node device. +After node and router perform IPv6 neighbor discovery, the node will start to send UDP packets to the server. diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/client.c b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/client.c new file mode 100644 index 000000000..538933346 --- /dev/null +++ b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/client.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * A simple IPv6-over-BLE UDP-client. + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" + +#include "net/ipv6/uip-icmp6.h" + +#include "ble-hal.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#define SERVER_IP "::" +#define CLIENT_PORT 61617 +#define SERVER_PORT 61616 + +#define PING_TIMEOUT (CLOCK_SECOND / 4) +#define CLIENT_SEND_INTERVAL (CLOCK_SECOND * 1) + +#define UDP_LEN_MAX 255 +/*---------------------------------------------------------------------------*/ +static uip_ipaddr_t server_addr; +static struct uip_icmp6_echo_reply_notification icmp_notification; +static uint8_t echo_received; +static struct uip_udp_conn *conn; + +static struct etimer timer; +static char buf[UDP_LEN_MAX]; +static uint16_t packet_counter; +/*---------------------------------------------------------------------------*/ +PROCESS(ipv6_ble_client_process, "IPv6 over BLE - client process"); +AUTOSTART_PROCESSES(&ipv6_ble_client_process); +/*---------------------------------------------------------------------------*/ +void +icmp_reply_handler(uip_ipaddr_t *source, uint8_t ttl, + uint8_t *data, uint16_t datalen) +{ + if(uip_ip6addr_cmp(source, &server_addr)) { + printf("echo response received\n"); + echo_received = 1; + } +} +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + char data[UDP_LEN_MAX]; + if(uip_newdata()) { + strncpy(data, uip_appdata, uip_datalen()); + data[uip_datalen()] = '\0'; + printf("rec. message: <%s>\n", data); + } +} +/*---------------------------------------------------------------------------*/ +static void +timeout_handler(void) +{ + sprintf(buf, "Hello server %04u!", packet_counter); + printf("send message: <%s>\n", buf); + uip_udp_packet_send(conn, buf, strlen(buf)); + packet_counter++; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(ipv6_ble_client_process, ev, data) +{ + PROCESS_BEGIN(); + printf("CC26XX-IPv6-over-BLE client started\n"); + + uiplib_ipaddrconv(SERVER_IP, &server_addr); + uip_icmp6_echo_reply_callback_add(&icmp_notification, icmp_reply_handler); + + printf("pinging the IPv6-over-BLE server\n"); + + do { + etimer_set(&timer, PING_TIMEOUT); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); + uip_icmp6_send(&server_addr, ICMP6_ECHO_REQUEST, 0, 20); + } while(!echo_received); + + conn = udp_new(&server_addr, UIP_HTONS(SERVER_PORT), NULL); + udp_bind(conn, UIP_HTONS(CLIENT_PORT)); + + etimer_set(&timer, CLIENT_SEND_INTERVAL); + + while(1) { + PROCESS_YIELD(); + if((ev == PROCESS_EVENT_TIMER) && (data == &timer)) { + timeout_handler(); + etimer_set(&timer, CLIENT_SEND_INTERVAL); + } else if(ev == tcpip_event) { + tcpip_handler(); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/project-conf.h b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/project-conf.h new file mode 100644 index 000000000..76f174f2f --- /dev/null +++ b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/project-conf.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ + +/*---------------------------------------------------------------------------*/ +/* Disable button shutdown functionality */ +#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 0 +/*---------------------------------------------------------------------------*/ +/* Change to match your configuration */ +#define BOARD_CONF_DEBUGGER_DEVPACK 1 +/*---------------------------------------------------------------------------*/ +#define PACKETBUF_CONF_SIZE 1280 +#define QUEUEBUF_CONF_NUM 1 +#define UIP_CONF_BUFFER_SIZE 1280 + +#define CC26XX_CONF_RADIO_MODE RADIO_MODE_BLE +#define NETSTACK_CONF_RADIO ble_cc2650_driver +#define MAKE_MAC MAKE_MAC_OTHER +#define NETSTACK_CONF_MAC ble_l2cap_driver + +#define LOG_CONF_LEVEL_MAC LOG_LEVEL_INFO +#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN + +/* BLE L2CAP settings */ +#define BLE_CONF_DEVICE_NAME "TI CC26xx device" +#define BLE_CONF_ADV_INTERVAL 25 + +#define MAKE_NET MAKE_NET_IPV6 +#define MAKE_ROUTING MAKE_ROUTING_NONE + +/*/ * 6LoWPAN settings * / */ +#define SICSLOWPAN_CONF_MAC_MAX_PAYLOAD 1280 +#define SICSLOWPAN_CONF_COMPRESSION SICSLOWPAN_COMPRESSION_6LORH +#define SICSLOWPAN_CONF_COMPRESSION_THRESHOLD 0 /* always use compression */ +#define SICSLOWPAN_CONF_FRAG 0 +#define SICSLOWPAN_FRAMER_HDRLEN 0 +/* */ +/*/ * network stack settings * / */ +#define UIP_CONF_ROUTER 0 +#define UIP_CONF_ND6_SEND_NA 1 +/*---------------------------------------------------------------------------*/ +#endif /* PROJECT_CONF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/os/contiki-main.c b/os/contiki-main.c index 88bea0a10..489bc8da8 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -92,6 +92,8 @@ main(void) LOG_INFO_LLADDR(&linkaddr_node_addr); LOG_INFO_("\n"); + platform_init_stage_three(); + #if NETSTACK_CONF_WITH_IPV6 { uip_ds6_addr_t *lladdr; @@ -105,8 +107,6 @@ main(void) } #endif /* NETSTACK_CONF_WITH_IPV6 */ - platform_init_stage_three(); - #if BUILD_WITH_ORCHESTRA orchestra_init(); LOG_DBG("With Orchestra\n"); From 5a281334522b42ac1093236b0849c50c46623434 Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 3 Jan 2018 13:28:11 +0100 Subject: [PATCH 2/9] IPv6-over-BLE client example moved --- examples/ble/ipv6-client/Makefile | 10 +++++++ .../ipv6-client}/client.c | 5 ++-- .../ipv6-client}/project-conf.h | 0 .../cc26xx/cc26xx-ble-client-demo/Makefile | 9 ------ .../cc26xx/cc26xx-ble-client-demo/README.md | 28 ------------------- 5 files changed, 13 insertions(+), 39 deletions(-) create mode 100644 examples/ble/ipv6-client/Makefile rename examples/{platform-specific/cc26xx/cc26xx-ble-client-demo => ble/ipv6-client}/client.c (97%) rename examples/{platform-specific/cc26xx/cc26xx-ble-client-demo => ble/ipv6-client}/project-conf.h (100%) delete mode 100644 examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile delete mode 100644 examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md diff --git a/examples/ble/ipv6-client/Makefile b/examples/ble/ipv6-client/Makefile new file mode 100644 index 000000000..589743721 --- /dev/null +++ b/examples/ble/ipv6-client/Makefile @@ -0,0 +1,10 @@ +DEFINES+=PROJECT_CONF_H=\"project-conf.h\" +CONTIKI_PROJECT=client + +all: $(CONTIKI_PROJECT) + +upload: + srfprog -t 'soc(XDS-L1000130)' -e all -p 'epfw(0)' -v rb -f $(CONTIKI_PROJECT).hex -a 0x0 + +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include \ No newline at end of file diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/client.c b/examples/ble/ipv6-client/client.c similarity index 97% rename from examples/platform-specific/cc26xx/cc26xx-ble-client-demo/client.c rename to examples/ble/ipv6-client/client.c index 538933346..04281a0a5 100644 --- a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/client.c +++ b/examples/ble/ipv6-client/client.c @@ -47,7 +47,8 @@ #include #include /*---------------------------------------------------------------------------*/ -#define SERVER_IP "::" +//#define SERVER_IP "::" +#define SERVER_IP "fe80::ba27:ebff:fe40:9b06" #define CLIENT_PORT 61617 #define SERVER_PORT 61616 @@ -101,7 +102,7 @@ timeout_handler(void) PROCESS_THREAD(ipv6_ble_client_process, ev, data) { PROCESS_BEGIN(); - printf("CC26XX-IPv6-over-BLE client started\n"); + printf("IPv6-over-BLE client started\n"); uiplib_ipaddrconv(SERVER_IP, &server_addr); uip_icmp6_echo_reply_callback_add(&icmp_notification, icmp_reply_handler); diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/project-conf.h b/examples/ble/ipv6-client/project-conf.h similarity index 100% rename from examples/platform-specific/cc26xx/cc26xx-ble-client-demo/project-conf.h rename to examples/ble/ipv6-client/project-conf.h diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile deleted file mode 100644 index 7000fd8c7..000000000 --- a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -DEFINES+=PROJECT_CONF_H=\"project-conf.h\" -CONTIKI_PROJECT=client - -all: $(CONTIKI_PROJECT) - - - -CONTIKI = ../../../.. -include $(CONTIKI)/Makefile.include \ No newline at end of file diff --git a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md deleted file mode 100644 index 4af712517..000000000 --- a/examples/platform-specific/cc26xx/cc26xx-ble-client-demo/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# CC26xx IPv6-over-BLE client demo - -This example provides a simple implementation of a UDP client that connects -to a UDP server via IPv6-over-BLE [RFC 7668](https://tools.ietf.org/html/rfc7668). - -After booting, the node sends an ICMPv6 echo request (ping) to the configured server address -and waits for an ICMPv6 echo response. -When a response is received, the client start to send a UDP packet with content -`Hello server !` to the server, where is a packet counter that is incremented every time a UDP packet is sent. -If the server respondes with a UDP packet, the content of the packet is printed in the console. - -## Requirements -To run this example, you will need a [RFC 7668](https://tools.ietf.org/html/rfc7668)-compliant border router. -One possible border router is the Raspberry Pi 3 with the Raspbian OS -(for detailed instructions see the [Nordic Semiconductor guide](http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00092.html)). - -## Configuration -In addition to the configuration described in [BLEach README](../../../../arch/cpu/cc26xx-cc13xx/rf-core/README.md) the following configuration is needed. - -To successfully communicate with a UDP server, the `SERVER_IP` define in `client.c` needs to be configured -to the IPv6 address of the UDP server. -For example: -``` -#define SERVER_IP "fe80::1" -``` -## Running the example -Deploy your border router and create the IPv6-over-BLE connection to the node device. -After node and router perform IPv6 neighbor discovery, the node will start to send UDP packets to the server. From 35c08597e6c19af6d29e2d233c0a2f3b1c234df6 Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 3 Jan 2018 14:36:14 +0100 Subject: [PATCH 3/9] BLE L2CAP moved to the other MAC implementations --- Makefile.include | 8 +- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 1 - arch/cpu/cc26xx-cc13xx/ble-addr.c | 11 +- arch/cpu/cc26xx-cc13xx/ble-addr.h | 41 ++++-- arch/cpu/cc26xx-cc13xx/rf-core/README.md | 1 - arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c | 5 +- .../rf-core/ble-hal/ble-hal-cc26xx.c | 5 +- .../rf-core/ble-hal/ble-hal-cc26xx.h | 2 +- .../rf-core/ble-hal/rf-ble-cmd.h | 2 +- examples/ble/ipv6-client/Makefile | 2 + examples/ble/ipv6-client/client.c | 4 +- examples/ble/ipv6-client/project-conf.h | 6 - {arch/cpu/cc26xx-cc13xx => os}/dev/ble-hal.h | 11 +- .../rf-core => os/net/mac/ble}/ble-l2cap.c | 84 +----------- os/net/mac/ble/ble-l2cap.h | 127 ++++++++++++++++++ os/net/netstack.h | 2 + 16 files changed, 199 insertions(+), 113 deletions(-) rename {arch/cpu/cc26xx-cc13xx => os}/dev/ble-hal.h (97%) rename {arch/cpu/cc26xx-cc13xx/rf-core => os/net/mac/ble}/ble-l2cap.c (90%) create mode 100644 os/net/mac/ble/ble-l2cap.h diff --git a/Makefile.include b/Makefile.include index 3b8c41605..bcddedca8 100644 --- a/Makefile.include +++ b/Makefile.include @@ -86,7 +86,8 @@ endif MAKE_MAC_NULLMAC = 0 MAKE_MAC_CSMA = 1 MAKE_MAC_TSCH = 2 -MAKE_MAC_OTHER = 3 +MAKE_MAC_BLE = 3 +MAKE_MAC_OTHER = 4 # Make CSMA the default MAC MAKE_MAC ?= MAKE_MAC_CSMA @@ -106,6 +107,11 @@ ifeq ($(MAKE_MAC),MAKE_MAC_TSCH) CFLAGS += -DMAC_CONF_WITH_TSCH=1 endif +ifeq ($(MAKE_MAC),MAKE_MAC_BLE) + MODULES += os/net/mac/ble + CFLAGS += -DMAC_CONF_WITH_BLE=1 +endif + ifeq ($(MAKE_MAC),MAKE_MAC_OTHER) CFLAGS += -DMAC_CONF_WITH_OTHER=1 endif diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index 534151e42..7c6ab55b3 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -35,7 +35,6 @@ CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c oscillators.c CONTIKI_CPU_SOURCEFILES += rf-core.c rf-ble.c ieee-mode.c CONTIKI_CPU_SOURCEFILES += ble-cc2650.c ble-hal-cc26xx.c ble-addr.c rf-ble-cmd.c -CONTIKI_CPU_SOURCEFILES += ble-l2cap.c CONTIKI_CPU_SOURCEFILES += random.c soc-trng.c int-master.c DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c diff --git a/arch/cpu/cc26xx-cc13xx/ble-addr.c b/arch/cpu/cc26xx-cc13xx/ble-addr.c index 91f665b01..7617133cc 100644 --- a/arch/cpu/cc26xx-cc13xx/ble-addr.c +++ b/arch/cpu/cc26xx-cc13xx/ble-addr.c @@ -27,16 +27,21 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Michael Spoerk + */ +/** + * \file + * Driver for the retrieval of an BLE address from flash * + * \author + * Michael Spoerk */ /*---------------------------------------------------------------------------*/ -#include "../ble-addr.h" - #include "contiki-conf.h" #include "net/linkaddr.h" #include +#include "ble-addr.h" +#include "os/dev/ble-hal.h" /*---------------------------------------------------------------------------*/ void ble_addr_cpy_to(uint8_t *dst) diff --git a/arch/cpu/cc26xx-cc13xx/ble-addr.h b/arch/cpu/cc26xx-cc13xx/ble-addr.h index b5b7c4ed5..9069ff9a7 100644 --- a/arch/cpu/cc26xx-cc13xx/ble-addr.h +++ b/arch/cpu/cc26xx-cc13xx/ble-addr.h @@ -27,8 +27,13 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Michael Spoerk + */ +/** + * \file + * Driver for the retrieval of an BLE address from flash * + * \author + * Michael Spoerk */ /*---------------------------------------------------------------------------*/ #ifndef BLE_ADDR_H_ @@ -40,21 +45,35 @@ /* primary BLE address location */ #define BLE_ADDR_LOCATION 0x500012E8 -/* BLE device address size */ -#define BLE_ADDR_SIZE 6 - -/*---------------------------------------------------------------------------*/ -/* Type of BLE device address */ -typedef enum { - BLE_ADDR_TYPE_PUBLIC, - BLE_ADDR_TYPE_RANDOM -} ble_addr_type_t; - /*---------------------------------------------------------------------------*/ +/** + * \brief Copy the node's factory BLE address to a destination memory area + * \param dst A pointer to the destination area where the BLE address is to be + * written + * + * This function will copy 6 bytes and it will invert byte order in + * the process. The factory address on devices is normally little-endian, + * therefore you should expect dst to store the address in a big-endian order. + */ void ble_addr_cpy_to(uint8_t *dst); +/*---------------------------------------------------------------------------*/ +/** + * \brief Copy the node's BLE address to a destination memory area and converts + * it into a EUI64 address in the process + * \param dst A pointer to the destination area where the EUI64 address is to be + * written + * \param src A pointer to the BLE address that is to be copied + */ void ble_addr_to_eui64(uint8_t *dst, uint8_t *src); +/*---------------------------------------------------------------------------*/ +/** + * \brief Copy the node's EUI64 address that is based on its factory BLE address + * to a destination memory area + * \param dst A pointer to the destination area where the EUI64 address is to be + * written + */ void ble_eui64_addr_cpy_to(uint8_t *dst); /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/README.md b/arch/cpu/cc26xx-cc13xx/rf-core/README.md index ebc565b69..247626e2d 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/README.md +++ b/arch/cpu/cc26xx-cc13xx/rf-core/README.md @@ -50,7 +50,6 @@ To enable IPv6 over BLE, the project conf needs to contain: #define QUEUEBUF_CONF_NUM 1 #define UIP_CONF_BUFFER_SIZE 1280 -#define CC26XX_CONF_RADIO_MODE CC26XX_RADIO_MODE_BLE #define NETSTACK_CONF_RADIO ble_cc2650_driver #define NETSTACK_CONF_MAC ble_l2cap_driver diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c index 1cc9ed7d9..6c4d82f8a 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-cc2650.c @@ -36,11 +36,10 @@ * Michael Spoerk */ /*---------------------------------------------------------------------------*/ - -#include -#include #include "contiki.h" #include "dev/radio.h" +#include "os/dev/ble-hal.h" +#include "rf-core/ble-hal/ble-hal-cc26xx.h" /*---------------------------------------------------------------------------*/ #include "sys/log.h" #define LOG_MODULE "RADIO" diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c index 086ebb8a7..fe9d6e0c0 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c @@ -36,13 +36,13 @@ * Michael Spoerk */ /*---------------------------------------------------------------------------*/ -#include "ble-hal.h" -#include "rf-core/ble-hal/rf-ble-cmd.h" + #include "lpm.h" #include "sys/rtimer.h" #include "sys/process.h" +#include "os/dev/ble-hal.h" #include "dev/oscillators.h" #include "ble-addr.h" @@ -62,6 +62,7 @@ #include +#include "rf-core/ble-hal/rf-ble-cmd.h" /*---------------------------------------------------------------------------*/ #include "sys/log.h" #define LOG_MODULE "BLE-RADIO" diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h index 7f231e4be..48ca4fd8e 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h @@ -40,7 +40,7 @@ #ifndef BLE_HAL_CC26XX_H_ #define BLE_HAL_CC26XX_H_ -#include "ble-hal.h" +#include "os/dev/ble-hal.h" extern const struct ble_hal_driver ble_hal; diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h index 526166cda..42944eaab 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h @@ -40,8 +40,8 @@ #ifndef RF_BLE_CMD_H_ #define RF_BLE_CMD_H_ +#include "os/dev/ble-hal.h" #include "../../ble-addr.h" -#include "ble-hal.h" #include "rf_common_cmd.h" #define RF_BLE_CMD_OK 1 diff --git a/examples/ble/ipv6-client/Makefile b/examples/ble/ipv6-client/Makefile index 589743721..015e2a9bf 100644 --- a/examples/ble/ipv6-client/Makefile +++ b/examples/ble/ipv6-client/Makefile @@ -6,5 +6,7 @@ all: $(CONTIKI_PROJECT) upload: srfprog -t 'soc(XDS-L1000130)' -e all -p 'epfw(0)' -v rb -f $(CONTIKI_PROJECT).hex -a 0x0 +MAKE_MAC = MAKE_MAC_BLE +MAKE_NET = MAKE_NET_IPV6 CONTIKI = ../../.. include $(CONTIKI)/Makefile.include \ No newline at end of file diff --git a/examples/ble/ipv6-client/client.c b/examples/ble/ipv6-client/client.c index 04281a0a5..e41e698df 100644 --- a/examples/ble/ipv6-client/client.c +++ b/examples/ble/ipv6-client/client.c @@ -42,10 +42,10 @@ #include "net/ipv6/uip-icmp6.h" -#include "ble-hal.h" - #include #include + +#include "os/dev/ble-hal.h" /*---------------------------------------------------------------------------*/ //#define SERVER_IP "::" #define SERVER_IP "fe80::ba27:ebff:fe40:9b06" diff --git a/examples/ble/ipv6-client/project-conf.h b/examples/ble/ipv6-client/project-conf.h index 76f174f2f..114565066 100644 --- a/examples/ble/ipv6-client/project-conf.h +++ b/examples/ble/ipv6-client/project-conf.h @@ -47,10 +47,7 @@ #define QUEUEBUF_CONF_NUM 1 #define UIP_CONF_BUFFER_SIZE 1280 -#define CC26XX_CONF_RADIO_MODE RADIO_MODE_BLE #define NETSTACK_CONF_RADIO ble_cc2650_driver -#define MAKE_MAC MAKE_MAC_OTHER -#define NETSTACK_CONF_MAC ble_l2cap_driver #define LOG_CONF_LEVEL_MAC LOG_LEVEL_INFO #define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN @@ -61,9 +58,6 @@ #define BLE_CONF_DEVICE_NAME "TI CC26xx device" #define BLE_CONF_ADV_INTERVAL 25 -#define MAKE_NET MAKE_NET_IPV6 -#define MAKE_ROUTING MAKE_ROUTING_NONE - /*/ * 6LoWPAN settings * / */ #define SICSLOWPAN_CONF_MAC_MAX_PAYLOAD 1280 #define SICSLOWPAN_CONF_COMPRESSION SICSLOWPAN_COMPRESSION_6LORH diff --git a/arch/cpu/cc26xx-cc13xx/dev/ble-hal.h b/os/dev/ble-hal.h similarity index 97% rename from arch/cpu/cc26xx-cc13xx/dev/ble-hal.h rename to os/dev/ble-hal.h index 74aef1585..ce5f5e8b1 100644 --- a/arch/cpu/cc26xx-cc13xx/dev/ble-hal.h +++ b/os/dev/ble-hal.h @@ -41,8 +41,10 @@ #define BLE_HAL_H_ #include -#include "ble-addr.h" +/*---------------------------------------------------------------------------*/ +/* BLE device address size */ +#define BLE_ADDR_SIZE 6 /*---------------------------------------------------------------------------*/ /* Advertisement channel definitions */ #define BLE_ADV_DATA_LEN 31 @@ -101,6 +103,13 @@ typedef enum { BLE_RESULT_ERROR } ble_result_t; +/*---------------------------------------------------------------------------*/ +/* Type of BLE device address */ +typedef enum { + BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_RANDOM +} ble_addr_type_t; + /*---------------------------------------------------------------------------*/ /* Advertising modes of BLE */ typedef enum { diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c b/os/net/mac/ble/ble-l2cap.c similarity index 90% rename from arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c rename to os/net/mac/ble/ble-l2cap.c index d3f2a0217..f12fbb369 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-l2cap.c +++ b/os/net/mac/ble/ble-l2cap.c @@ -38,103 +38,27 @@ */ /*---------------------------------------------------------------------------*/ -#include "ble-hal.h" +#include "net/mac/ble/ble-l2cap.h" + #include "net/packetbuf.h" #include "net/netstack.h" - #include "lib/memb.h" #include "lib/list.h" #include + +#include "../../../dev/ble-hal.h" /*---------------------------------------------------------------------------*/ #include "sys/log.h" #define LOG_MODULE "L2CAP" #define LOG_LEVEL LOG_LEVEL_MAC /*---------------------------------------------------------------------------*/ -/* device name used for BLE advertisement */ -#ifdef BLE_CONF_DEVICE_NAME -#define BLE_DEVICE_NAME BLE_CONF_DEVICE_NAME -#else -#define BLE_DEVICE_NAME "BLE device name" -#endif - -/* BLE advertisement in milliseconds */ -#ifdef BLE_CONF_ADV_INTERVAL -#define BLE_ADV_INTERVAL BLE_CONF_ADV_INTERVAL -#else -#define BLE_ADV_INTERVAL 50 -#endif - -#define BLE_SLAVE_CONN_INTERVAL_MIN 0x0150 -#define BLE_SLAVE_CONN_INTERVAL_MAX 0x01F0 -#define L2CAP_SIGNAL_CHANNEL 0x0005 -#define L2CAP_FLOW_CHANNEL 0x0041 -#define L2CAP_CODE_CONN_UPDATE_REQ 0x12 -#define L2CAP_CODE_CONN_UPDATE_RSP 0x13 -#define L2CAP_CODE_CONN_REQ 0x14 -#define L2CAP_CODE_CONN_RSP 0x15 -#define L2CAP_CODE_CREDIT 0x16 -#define L2CAP_IPSP_PSM 0x0023 - -/* the maximum MTU size of the L2CAP channel */ -#ifdef BLE_L2CAP_CONF_NODE_MTU -#define BLE_L2CAP_NODE_MTU BLE_L2CAP_CONF_NODE_MTU -#else -#define BLE_L2CAP_NODE_MTU 1280 -#endif - -/* the max. supported L2CAP fragment length */ -#ifdef BLE_L2CAP_CONF_NODE_FRAG_LEN -#define BLE_L2CAP_NODE_FRAG_LEN BLE_L2CAP_CONF_NODE_FRAG_LEN -#else -#ifdef BLE_MODE_CONF_CONN_MAX_PACKET_SIZE -#define BLE_L2CAP_NODE_FRAG_LEN BLE_MODE_CONF_CONN_MAX_PACKET_SIZE -#else -#define BLE_L2CAP_NODE_FRAG_LEN 256 -#endif -#endif - -#define L2CAP_CREDIT_NEW (BLE_L2CAP_NODE_MTU / BLE_L2CAP_NODE_FRAG_LEN) -#define L2CAP_CREDIT_THRESHOLD 2 - -#define L2CAP_INIT_INTERVAL (2 * CLOCK_SECOND) - -/* BLE connection interval in milliseconds */ -#ifdef BLE_CONF_CONNECTION_INTERVAL -#define CONNECTION_INTERVAL_MS BLE_CONF_CONNECTION_INTERVAL -#else -#define CONNECTION_INTERVAL_MS 125 -#endif - -/* BLE slave latency */ -#ifdef BLE_CONF_CONNECTION_SLAVE_LATENCY -#define CONNECTION_SLAVE_LATENCY BLE_CONF_CONNECTION_SLAVE_LATENCY -#else -#define CONNECTION_SLAVE_LATENCY 0 -#endif - -/* BLE supervision timeout */ -#define CONNECTION_TIMEOUT 42 - #define MS_TO_CLOCK_SECONDS(X) ((int)(((double)((X)*CLOCK_SECOND)) / 1000.0)) - -#define L2CAP_FIRST_HEADER_SIZE 6 -#define L2CAP_SUBSEQ_HEADER_SIZE 4 /*---------------------------------------------------------------------------*/ /* BLE controller */ /* public device address of BLE controller */ static uint8_t ble_addr[BLE_ADDR_SIZE]; /*---------------------------------------------------------------------------*/ -#if UIP_CONF_ROUTER -#ifdef BLE_MODE_CONF_MAX_CONNECTIONS -#define L2CAP_CHANNELS BLE_MODE_CONF_MAX_CONNECTIONS -#else -#define L2CAP_CHANNELS 1 -#endif -#else -#define L2CAP_CHANNELS 1 -#endif -/*---------------------------------------------------------------------------*/ /* L2CAP fragmentation buffers and utilities */ typedef struct { /* L2CAP Service Data Unit (SDU) (= packet data)*/ diff --git a/os/net/mac/ble/ble-l2cap.h b/os/net/mac/ble/ble-l2cap.h new file mode 100644 index 000000000..73dfa18a5 --- /dev/null +++ b/os/net/mac/ble/ble-l2cap.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017, Graz University of Technology + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * MAC layer that implements BLE L2CAP credit-based flow control + * channels to support IPv6 over BLE (RFC 7668) + * + * \author + * Michael Spoerk + */ +/*---------------------------------------------------------------------------*/ +#ifndef BLE_L2CAP_H_ +#define BLE_L2CAP_H_ + +#include "contiki.h" +#include "net/mac/mac.h" +#include "dev/radio.h" +/*---------------------------------------------------------------------------*/ +/* device name used for BLE advertisement */ +#ifdef BLE_CONF_DEVICE_NAME +#define BLE_DEVICE_NAME BLE_CONF_DEVICE_NAME +#else +#define BLE_DEVICE_NAME "BLE device name" +#endif + +/* BLE advertisement in milliseconds */ +#ifdef BLE_CONF_ADV_INTERVAL +#define BLE_ADV_INTERVAL BLE_CONF_ADV_INTERVAL +#else +#define BLE_ADV_INTERVAL 50 +#endif + +#define BLE_SLAVE_CONN_INTERVAL_MIN 0x0150 +#define BLE_SLAVE_CONN_INTERVAL_MAX 0x01F0 +#define L2CAP_SIGNAL_CHANNEL 0x0005 +#define L2CAP_FLOW_CHANNEL 0x0041 +#define L2CAP_CODE_CONN_UPDATE_REQ 0x12 +#define L2CAP_CODE_CONN_UPDATE_RSP 0x13 +#define L2CAP_CODE_CONN_REQ 0x14 +#define L2CAP_CODE_CONN_RSP 0x15 +#define L2CAP_CODE_CREDIT 0x16 +#define L2CAP_IPSP_PSM 0x0023 + +/* the maximum MTU size of the L2CAP channel */ +#ifdef BLE_L2CAP_CONF_NODE_MTU +#define BLE_L2CAP_NODE_MTU BLE_L2CAP_CONF_NODE_MTU +#else +#define BLE_L2CAP_NODE_MTU 1280 +#endif + +/* the max. supported L2CAP fragment length */ +#ifdef BLE_L2CAP_CONF_NODE_FRAG_LEN +#define BLE_L2CAP_NODE_FRAG_LEN BLE_L2CAP_CONF_NODE_FRAG_LEN +#else +#ifdef BLE_MODE_CONF_CONN_MAX_PACKET_SIZE +#define BLE_L2CAP_NODE_FRAG_LEN BLE_MODE_CONF_CONN_MAX_PACKET_SIZE +#else +#define BLE_L2CAP_NODE_FRAG_LEN 256 +#endif +#endif + +#define L2CAP_CREDIT_NEW (BLE_L2CAP_NODE_MTU / BLE_L2CAP_NODE_FRAG_LEN) +#define L2CAP_CREDIT_THRESHOLD 2 + +#define L2CAP_INIT_INTERVAL (2 * CLOCK_SECOND) + +/* BLE connection interval in milliseconds */ +#ifdef BLE_CONF_CONNECTION_INTERVAL +#define CONNECTION_INTERVAL_MS BLE_CONF_CONNECTION_INTERVAL +#else +#define CONNECTION_INTERVAL_MS 125 +#endif + +/* BLE slave latency */ +#ifdef BLE_CONF_CONNECTION_SLAVE_LATENCY +#define CONNECTION_SLAVE_LATENCY BLE_CONF_CONNECTION_SLAVE_LATENCY +#else +#define CONNECTION_SLAVE_LATENCY 0 +#endif + +/* BLE supervision timeout */ +#define CONNECTION_TIMEOUT 42 + +#define L2CAP_FIRST_HEADER_SIZE 6 +#define L2CAP_SUBSEQ_HEADER_SIZE 4 + +#if UIP_CONF_ROUTER +#ifdef BLE_MODE_CONF_MAX_CONNECTIONS +#define L2CAP_CHANNELS BLE_MODE_CONF_MAX_CONNECTIONS +#else +#define L2CAP_CHANNELS 1 +#endif +#else +#define L2CAP_CHANNELS 1 +#endif + +extern const struct mac_driver ble_l2cap_driver; + +#endif /* BLE_L2CAP_H_ */ diff --git a/os/net/netstack.h b/os/net/netstack.h index 4251ef5e9..1e4921b61 100644 --- a/os/net/netstack.h +++ b/os/net/netstack.h @@ -68,6 +68,8 @@ #define NETSTACK_MAC csma_driver #elif MAC_CONF_WITH_TSCH #define NETSTACK_MAC tschmac_driver +#elif MAC_CONF_WITH_BLE +#define NETSTACK_MAC ble_l2cap_driver #else #error Unknown MAC configuration #endif From 2a49608af643acd0ccec7456ced5ec1b49c5aad8 Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 3 Jan 2018 14:51:23 +0100 Subject: [PATCH 4/9] link layer problem fixed --- arch/platform/srf06-cc26xx/platform.c | 10 +++++++--- examples/ble/ipv6-client/project-conf.h | 6 +++--- os/contiki-main.c | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/platform/srf06-cc26xx/platform.c b/arch/platform/srf06-cc26xx/platform.c index c2868af13..0d24e6f2c 100644 --- a/arch/platform/srf06-cc26xx/platform.c +++ b/arch/platform/srf06-cc26xx/platform.c @@ -107,9 +107,8 @@ set_rf_params(void) { uint8_t ext_addr[8]; -#if MAKE_MAC == MAKE_MAC_OTHER +#if MAKE_MAC == MAKE_MAC_BLE ble_eui64_addr_cpy_to((uint8_t *)&ext_addr); - memcpy(&linkaddr_node_addr, &ext_addr[8 - LINKADDR_SIZE], LINKADDR_SIZE); NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); #else uint16_t short_addr; @@ -176,8 +175,13 @@ platform_init_stage_two() serial_line_init(); /* Populate linkaddr_node_addr */ +#if MAKE_MAC == MAKE_MAC_BLE + uint8_t ext_addr[8]; + ble_eui64_addr_cpy_to((uint8_t *)&ext_addr); + memcpy(&linkaddr_node_addr, &ext_addr[8 - LINKADDR_SIZE], LINKADDR_SIZE); +#else ieee_addr_cpy_to(linkaddr_node_addr.u8, LINKADDR_SIZE); - +#endif fade(LEDS_GREEN); } /*---------------------------------------------------------------------------*/ diff --git a/examples/ble/ipv6-client/project-conf.h b/examples/ble/ipv6-client/project-conf.h index 114565066..14b6e8d05 100644 --- a/examples/ble/ipv6-client/project-conf.h +++ b/examples/ble/ipv6-client/project-conf.h @@ -50,9 +50,9 @@ #define NETSTACK_CONF_RADIO ble_cc2650_driver #define LOG_CONF_LEVEL_MAC LOG_LEVEL_INFO -#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN -#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN -#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN +//#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN +//#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN +//#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN /* BLE L2CAP settings */ #define BLE_CONF_DEVICE_NAME "TI CC26xx device" diff --git a/os/contiki-main.c b/os/contiki-main.c index deb9413f3..62638c8a7 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -95,8 +95,6 @@ main(void) LOG_INFO_LLADDR(&linkaddr_node_addr); LOG_INFO_("\n"); - platform_init_stage_three(); - #if NETSTACK_CONF_WITH_IPV6 { uip_ds6_addr_t *lladdr; @@ -110,6 +108,8 @@ main(void) } #endif /* NETSTACK_CONF_WITH_IPV6 */ + platform_init_stage_three(); + #if BUILD_WITH_ORCHESTRA orchestra_init(); LOG_DBG("With Orchestra\n"); From 03ec1ea4019a8f8c5729621dbebdc289c9328c4f Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 3 Jan 2018 15:18:01 +0100 Subject: [PATCH 5/9] Some documentation added --- .../rf-core/ble-hal/ble-hal-cc26xx.c | 2 +- .../rf-core/ble-hal/ble-hal-cc26xx.h | 2 +- .../rf-core/ble-hal/rf-ble-cmd.c | 4 +- .../rf-core/ble-hal/rf-ble-cmd.h | 87 ++++++++++++++++++- 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c index fe9d6e0c0..d4c761dcd 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c @@ -30,7 +30,7 @@ /** * \file - * hardware abstraction implementation for the TI CC2650 controller + * BLE radio hardware abstraction implementation for the TI CC26XX controller * * \author * Michael Spoerk diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h index 48ca4fd8e..41e71c684 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.h @@ -30,7 +30,7 @@ /** * \file - * hardware abstraction for the TI CC2650 controller + * BLE radio hardware abstraction for the TI CC26XX controller * * \author * Michael Spoerk diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c index 051442e91..cde42f99b 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.c @@ -30,7 +30,9 @@ /** * \file - * BLE commands for the TI CC26xx BLE radio + * BLE commands for the TI CC26xx BLE radio. + * These functions are specific to the TI CC26xx and cannot be + * reused by other BLE radios. * * \author * Michael Spoerk diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h index 42944eaab..585366342 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h @@ -30,7 +30,9 @@ /** * \file - * BLE commands for the TI CC26xx BLE radio + * BLE commands for the TI CC26xx BLE radio. + * These functions are specific to the TI CC26xx and cannot be + * reused by other BLE radios. * * \author * Michael Spoerk @@ -47,29 +49,112 @@ #define RF_BLE_CMD_OK 1 #define RF_BLE_CMD_ERROR 0 +/*---------------------------------------------------------------------------*/ +/** + * \brief Sends a BLE radio command to the radio + * \param cmd A pointer to the command to be send + * \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR + */ unsigned short rf_ble_cmd_send(uint8_t *cmd); +/*---------------------------------------------------------------------------*/ +/** + * \brief Waits for a running BLE radio command to be finished + * \param cmd A pointer to the running command + * \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR + */ unsigned short rf_ble_cmd_wait(uint8_t *cmd); +/*---------------------------------------------------------------------------*/ +/** + * \brief Initializes the radio core to be used as a BLE radio + * \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR + */ unsigned short rf_ble_cmd_setup_ble_mode(void); +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates a BLE radio command structure that enables + * BLE advertisement when sent to the radio core + * \param command A pointer to command that is created + * \param channel The BLE advertisement channel used for advertisement + * \param param A pointer to the radio command parameters + * \param output A pointer to the radio command output + */ void rf_ble_cmd_create_adv_cmd(uint8_t *command, uint8_t channel, uint8_t *param, uint8_t *output); +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates BLE radio command parameters that are used to enable + * BLE advertisement on the radio core + * \param param A pointer to parameter structure that is created + * \param rx_queue A pointer to the RX queue that is used + * \param adv_data_len + * The length of the advertisement data + * \param adv_data A pointer to the advertisement data that is advertised + * \param scan_resp_data_len + * The length of the scan response data + * \param scan_resp_data + * A pointer to the scan response data + * \param own_addr_type + * Either BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM + * \param own_addr A pointer to the device address that is used as own address + */ void rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, uint8_t adv_data_len, uint8_t *adv_data, uint8_t scan_resp_data_len, uint8_t *scan_resp_data, ble_addr_type_t own_addr_type, uint8_t *own_addr); +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates a BLE radio command structure that sets up a single + * BLE connection event when sent to the radio core + * \param cmd A pointer to command that is created + * \param channel The BLE data channel used for the connection event + * \param param A pointer to the radio command parameters + * \param output A pointer to the radio command output + * \param start_time + * The time in rf_core_ticks when the connection event will start + */ void rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, uint8_t *output, uint32_t start_time); +/*---------------------------------------------------------------------------*/ +/** + * \brief Creates BLE radio command parameters that are used to setup a single + * BLE connection event on the radio core + * \param param A pointer to parameter structure that is created + * \param rx_queue A pointer to the RX queue that is used + * \param tx_queue A pointer to the TX queue that is used + * \param access_address + * The access address of the used BLE connection + * \param crc_init_0 + * Part of the initialization of the CRC checksum + * \param crc_init_1 + * Part of the initialization of the CRC checksum + * \param crc_init_2 + * Part of the initialization of the CRC checksum + * \param win_size The window size parameter of the BLE connection event + * \param window_widening + * The window widening parameter used for this connection event + * \param first_packet + * 1 for the first packet of the BLE connection so that the + * connection is properly initialized + */ void rf_ble_cmd_create_slave_params(uint8_t *params, dataQueue_t *rx_queue, dataQueue_t *tx_queue, uint32_t access_address, uint8_t crc_init_0, uint8_t crc_init_1, uint8_t crc_init_2, uint32_t win_size, uint32_t window_widening, uint8_t first_packet); +/*---------------------------------------------------------------------------*/ +/** + * \brief Adds a data buffer to a BLE transmission queue + * \param q A pointer to BLE transmission queue where the buffer + * should be added + * \param e A pointer to the data buffer that is added + */ unsigned short rf_ble_cmd_add_data_queue_entry(dataQueue_t *q, uint8_t *e); #endif /* RF_BLE_CMD_H_ */ From 40a9822225397ae3740cd861dc57f3a11e1fffad Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 3 Jan 2018 15:22:50 +0100 Subject: [PATCH 6/9] Cleanup of the hardware specific values --- examples/ble/ipv6-client/Makefile | 2 -- examples/ble/ipv6-client/client.c | 3 +-- examples/ble/ipv6-client/project-conf.h | 3 --- tests/02-compile-arm-ports-01/Makefile | 1 + 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/ble/ipv6-client/Makefile b/examples/ble/ipv6-client/Makefile index 015e2a9bf..c8f4f2a41 100644 --- a/examples/ble/ipv6-client/Makefile +++ b/examples/ble/ipv6-client/Makefile @@ -3,8 +3,6 @@ CONTIKI_PROJECT=client all: $(CONTIKI_PROJECT) -upload: - srfprog -t 'soc(XDS-L1000130)' -e all -p 'epfw(0)' -v rb -f $(CONTIKI_PROJECT).hex -a 0x0 MAKE_MAC = MAKE_MAC_BLE MAKE_NET = MAKE_NET_IPV6 diff --git a/examples/ble/ipv6-client/client.c b/examples/ble/ipv6-client/client.c index e41e698df..79878cf31 100644 --- a/examples/ble/ipv6-client/client.c +++ b/examples/ble/ipv6-client/client.c @@ -47,8 +47,7 @@ #include "os/dev/ble-hal.h" /*---------------------------------------------------------------------------*/ -//#define SERVER_IP "::" -#define SERVER_IP "fe80::ba27:ebff:fe40:9b06" +#define SERVER_IP "::" #define CLIENT_PORT 61617 #define SERVER_PORT 61616 diff --git a/examples/ble/ipv6-client/project-conf.h b/examples/ble/ipv6-client/project-conf.h index 14b6e8d05..815cfb90a 100644 --- a/examples/ble/ipv6-client/project-conf.h +++ b/examples/ble/ipv6-client/project-conf.h @@ -50,9 +50,6 @@ #define NETSTACK_CONF_RADIO ble_cc2650_driver #define LOG_CONF_LEVEL_MAC LOG_LEVEL_INFO -//#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN -//#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN -//#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN /* BLE L2CAP settings */ #define BLE_CONF_DEVICE_NAME "TI CC26xx device" diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index b54acc303..1505fd831 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -15,6 +15,7 @@ rpl-border-router/srf06-cc26xx:BOARD=launchpad/cc2650 \ sensniff/srf06-cc26xx \ sensniff/srf06-cc26xx:BOARD=launchpad/cc1310 \ 6tisch/etsi-plugtest-2017/srf06-cc26xx:BOARD=launchpad/cc2650 \ +ble/ipv6-client/srf06-cc26xx:BOARD=launchpad/cc2650 \ storage/cfs-coffee/cc2538dk \ sensniff/cc2538dk \ rpl-udp/cc2538dk \ From f8d2c3fa483384712be2cdbeac4fa59f92e0370d Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 3 Jan 2018 15:52:36 +0100 Subject: [PATCH 7/9] code style fixes --- arch/cpu/cc26xx-cc13xx/ble-addr.h | 4 +- .../rf-core/ble-hal/rf-ble-cmd.h | 44 +++++++++---------- os/net/netstack.h | 28 +++++------- 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/ble-addr.h b/arch/cpu/cc26xx-cc13xx/ble-addr.h index 9069ff9a7..4f61b0dd6 100644 --- a/arch/cpu/cc26xx-cc13xx/ble-addr.h +++ b/arch/cpu/cc26xx-cc13xx/ble-addr.h @@ -60,7 +60,7 @@ void ble_addr_cpy_to(uint8_t *dst); /*---------------------------------------------------------------------------*/ /** * \brief Copy the node's BLE address to a destination memory area and converts - * it into a EUI64 address in the process + * it into a EUI64 address in the process * \param dst A pointer to the destination area where the EUI64 address is to be * written * \param src A pointer to the BLE address that is to be copied @@ -70,7 +70,7 @@ void ble_addr_to_eui64(uint8_t *dst, uint8_t *src); /*---------------------------------------------------------------------------*/ /** * \brief Copy the node's EUI64 address that is based on its factory BLE address - * to a destination memory area + * to a destination memory area * \param dst A pointer to the destination area where the EUI64 address is to be * written */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h index 585366342..e4eb12579 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h @@ -75,7 +75,7 @@ unsigned short rf_ble_cmd_setup_ble_mode(void); /*---------------------------------------------------------------------------*/ /** * \brief Creates a BLE radio command structure that enables - * BLE advertisement when sent to the radio core + * BLE advertisement when sent to the radio core * \param command A pointer to command that is created * \param channel The BLE advertisement channel used for advertisement * \param param A pointer to the radio command parameters @@ -87,18 +87,18 @@ void rf_ble_cmd_create_adv_cmd(uint8_t *command, uint8_t channel, /*---------------------------------------------------------------------------*/ /** * \brief Creates BLE radio command parameters that are used to enable - * BLE advertisement on the radio core - * \param param A pointer to parameter structure that is created + * BLE advertisement on the radio core + * \param param A pointer to parameter structure that is created * \param rx_queue A pointer to the RX queue that is used * \param adv_data_len - * The length of the advertisement data + * The length of the advertisement data * \param adv_data A pointer to the advertisement data that is advertised * \param scan_resp_data_len - * The length of the scan response data + * The length of the scan response data * \param scan_resp_data - * A pointer to the scan response data + * A pointer to the scan response data * \param own_addr_type - * Either BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM + * Either BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM * \param own_addr A pointer to the device address that is used as own address */ void rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, @@ -109,13 +109,13 @@ void rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, /*---------------------------------------------------------------------------*/ /** * \brief Creates a BLE radio command structure that sets up a single - * BLE connection event when sent to the radio core - * \param cmd A pointer to command that is created + * BLE connection event when sent to the radio core + * \param cmd A pointer to command that is created * \param channel The BLE data channel used for the connection event * \param param A pointer to the radio command parameters * \param output A pointer to the radio command output * \param start_time - * The time in rf_core_ticks when the connection event will start + * The time in rf_core_ticks when the connection event will start */ void rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, uint8_t *output, uint32_t start_time); @@ -123,26 +123,26 @@ void rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, /*---------------------------------------------------------------------------*/ /** * \brief Creates BLE radio command parameters that are used to setup a single - * BLE connection event on the radio core - * \param param A pointer to parameter structure that is created + * BLE connection event on the radio core + * \param param A pointer to parameter structure that is created * \param rx_queue A pointer to the RX queue that is used * \param tx_queue A pointer to the TX queue that is used * \param access_address - * The access address of the used BLE connection + * The access address of the used BLE connection * \param crc_init_0 - * Part of the initialization of the CRC checksum + * Part of the initialization of the CRC checksum * \param crc_init_1 - * Part of the initialization of the CRC checksum + * Part of the initialization of the CRC checksum * \param crc_init_2 - * Part of the initialization of the CRC checksum + * Part of the initialization of the CRC checksum * \param win_size The window size parameter of the BLE connection event * \param window_widening - * The window widening parameter used for this connection event + * The window widening parameter used for this connection event * \param first_packet - * 1 for the first packet of the BLE connection so that the - * connection is properly initialized + * 1 for the first packet of the BLE connection so that the + * connection is properly initialized */ -void rf_ble_cmd_create_slave_params(uint8_t *params, dataQueue_t *rx_queue, +void rf_ble_cmd_create_slave_params(uint8_t *param, dataQueue_t *rx_queue, dataQueue_t *tx_queue, uint32_t access_address, uint8_t crc_init_0, uint8_t crc_init_1, uint8_t crc_init_2, uint32_t win_size, @@ -151,8 +151,8 @@ void rf_ble_cmd_create_slave_params(uint8_t *params, dataQueue_t *rx_queue, /*---------------------------------------------------------------------------*/ /** * \brief Adds a data buffer to a BLE transmission queue - * \param q A pointer to BLE transmission queue where the buffer - * should be added + * \param q A pointer to BLE transmission queue where the buffer + * should be added * \param e A pointer to the data buffer that is added */ unsigned short rf_ble_cmd_add_data_queue_entry(dataQueue_t *q, uint8_t *e); diff --git a/os/net/netstack.h b/os/net/netstack.h index 1e4921b61..b7a439940 100644 --- a/os/net/netstack.h +++ b/os/net/netstack.h @@ -69,7 +69,7 @@ #elif MAC_CONF_WITH_TSCH #define NETSTACK_MAC tschmac_driver #elif MAC_CONF_WITH_BLE -#define NETSTACK_MAC ble_l2cap_driver +#define NETSTACK_MAC ble_l2cap_driver #else #error Unknown MAC configuration #endif @@ -102,24 +102,22 @@ struct network_driver { char *name; /** Initialize the network driver */ - void (* init)(void); + void (*init)(void); /** Callback for getting notified of incoming packet in packetbuf. */ - void (* input)(void); + void (*input)(void); /** Output funtion, sends from uipbuf. */ - uint8_t (* output)(const linkaddr_t *localdest); - + uint8_t (*output)(const linkaddr_t *localdest); }; extern const struct network_driver NETSTACK_NETWORK; -extern const struct mac_driver NETSTACK_MAC; -extern const struct radio_driver NETSTACK_RADIO; -extern const struct framer NETSTACK_FRAMER; +extern const struct mac_driver NETSTACK_MAC; +extern const struct radio_driver NETSTACK_RADIO; +extern const struct framer NETSTACK_FRAMER; void netstack_init(void); - /* Netstack ip_packet_processor - for implementing packet filters, firewalls, debuggin info, etc */ @@ -135,8 +133,8 @@ enum netstack_ip_callback_type { struct netstack_ip_packet_processor { struct netstack_ip_packet_processor *next; - enum netstack_ip_action (* process_input)(void); - enum netstack_ip_action (* process_output)(const linkaddr_t *localdest); + enum netstack_ip_action (*process_input)(void); + enum netstack_ip_action (*process_output)(const linkaddr_t * localdest); }; /* This function is intended for the IP stack to call whenever input/output @@ -146,18 +144,16 @@ enum netstack_ip_action netstack_process_ip_callback(uint8_t type, const linkadd void netstack_ip_packet_processor_add(struct netstack_ip_packet_processor *p); void netstack_ip_packet_processor_remove(struct netstack_ip_packet_processor *p); - - /* Netstack sniffer - this will soon be deprecated... */ struct netstack_sniffer { struct netstack_sniffer *next; - void (* input_callback)(void); - void (* output_callback)(int mac_status); + void (*input_callback)(void); + void (*output_callback)(int mac_status); }; #define NETSTACK_SNIFFER(name, input_callback, output_callback) \ -static struct netstack_sniffer name = { NULL, input_callback, output_callback } + static struct netstack_sniffer name = { NULL, input_callback, output_callback } void netstack_sniffer_add(struct netstack_sniffer *s); void netstack_sniffer_remove(struct netstack_sniffer *s); From 1defa2646aa70b4945ccdb6a55d378cb76ca49cd Mon Sep 17 00:00:00 2001 From: spoerk Date: Wed, 3 Jan 2018 16:18:21 +0100 Subject: [PATCH 8/9] Fixed Doxygen problem --- arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h index e4eb12579..d8a86f798 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/rf-ble-cmd.h @@ -117,7 +117,7 @@ void rf_ble_cmd_create_adv_params(uint8_t *param, dataQueue_t *rx_queue, * \param start_time * The time in rf_core_ticks when the connection event will start */ -void rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *params, +void rf_ble_cmd_create_slave_cmd(uint8_t *cmd, uint8_t channel, uint8_t *param, uint8_t *output, uint32_t start_time); /*---------------------------------------------------------------------------*/ From 4b173ce01f821d4f860422b701cb73bc6690ce71 Mon Sep 17 00:00:00 2001 From: dongdongbh <18310682633@163.com> Date: Sun, 11 Mar 2018 02:07:46 +0800 Subject: [PATCH 9/9] add cfs support for srf06-cc26xx --- arch/platform/srf06-cc26xx/cfs-coffee-arch.h | 88 +++++++++ arch/platform/srf06-cc26xx/common/xmem.c | 168 ++++++++++++++++++ .../srf06-cc26xx/launchpad/Makefile.launchpad | 2 +- .../srf06-cc26xx/sensortag/Makefile.sensortag | 2 +- examples/storage/cfs-coffee/Makefile | 1 + examples/storage/cfs-coffee/README.md | 3 + 6 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 arch/platform/srf06-cc26xx/cfs-coffee-arch.h create mode 100644 arch/platform/srf06-cc26xx/common/xmem.c diff --git a/arch/platform/srf06-cc26xx/cfs-coffee-arch.h b/arch/platform/srf06-cc26xx/cfs-coffee-arch.h new file mode 100644 index 000000000..33cc5123b --- /dev/null +++ b/arch/platform/srf06-cc26xx/cfs-coffee-arch.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Coffee architecture-dependent header for the srf06-cc2650 sensortag platform. + * \author + * Dongda Lee + */ + +#ifndef CFS_COFFEE_ARCH_H +#define CFS_COFFEE_ARCH_H + +#include "contiki-conf.h" +#include "dev/xmem.h" + +/*** MX25R8035F Memory Organization +The memory is organized as: +8Mbit = 1048576 bytes (8 bits each) +256 sectors (32 Kbits, 4096 bytes each) +4096 pages (256 bytes each). +Each page can be individually programmed (bits are programmed from 1 to 0). The device is +sector or bulk erasable (bits are erased from 0 to 1) but not page erasable +*/ +#define COFFEE_XMEM_TOTAL_SIZE_KB 1024UL //Total size of the External Flash Memory in the Z1 + +/* Coffee configuration parameters. */ +#define COFFEE_SECTOR_SIZE 4096UL +#define COFFEE_PAGE_SIZE 256UL +#define COFFEE_START 0UL //COFFEE_SECTOR_SIZE +#define COFFEE_SIZE (COFFEE_XMEM_TOTAL_SIZE_KB * 1024UL - COFFEE_START) +#define COFFEE_NAME_LENGTH 16 +#define COFFEE_MAX_OPEN_FILES 6 +#define COFFEE_FD_SET_SIZE 8 +#define COFFEE_LOG_TABLE_LIMIT 256 +#define COFFEE_DYN_SIZE 2*1024 +#define COFFEE_LOG_SIZE 1024 + +#define COFFEE_MICRO_LOGS 1 + + + + + + +/* Flash operations. */ +#define COFFEE_WRITE(buf, size, offset) \ + xmem_pwrite((char *)(buf), (size), COFFEE_START + (offset)) + +#define COFFEE_READ(buf, size, offset) \ + xmem_pread((char *)(buf), (size), COFFEE_START + (offset)) + +#define COFFEE_ERASE(sector) \ + xmem_erase(COFFEE_SECTOR_SIZE, COFFEE_START + (sector) * COFFEE_SECTOR_SIZE) + +/* Coffee types. */ +typedef int16_t coffee_page_t; + +#endif /* !COFFEE_ARCH_H */ diff --git a/arch/platform/srf06-cc26xx/common/xmem.c b/arch/platform/srf06-cc26xx/common/xmem.c new file mode 100644 index 000000000..5a79be6c1 --- /dev/null +++ b/arch/platform/srf06-cc26xx/common/xmem.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/** + * \file + * Device driver for the MX25R8035F 1Mbyte external memory. + * \author + * Dongda Lee + * + * Data is written bit inverted (~-operator) to flash so that + * unwritten data will read as zeros (UNIX style). + */ + +#include "contiki.h" +#include "ext-flash.h" +#include "dev/xmem.h" +#include "dev/watchdog.h" +#include "cfs-coffee-arch.h" +#include /* For PRINTF() */ + +#define EXT_ERASE_UNIT_SIZE 4096UL + +#define XMEM_BUFF_LENGHT 128 + + +#if 0 +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) do {} while (0) +#endif + + +void +xmem_init(void) +{ + ext_flash_open(); +} + + +int +xmem_pread(void *_p, int size, unsigned long addr) +{ + int rv; + uint8_t x; + int i; + + rv = ext_flash_open(); + + if(!rv) { + PRINTF("Could not open flash to save config\n"); + ext_flash_close(); + return -1; + } + + rv = ext_flash_read(addr, size, _p); + for (i = 0; i < size; i++){ + x = ~*((uint8_t *)_p + i); + *((uint8_t *)_p+i) = x; + } + + ext_flash_close(); + + if(rv) + return size; + + PRINTF("Could not read flash memory!\n"); + return -1; +} + + +int +xmem_pwrite(const void *_buf, int size, unsigned long addr) +{ + int rv; + int i, j; + int remain; + + uint8_t tmp_buf[XMEM_BUFF_LENGHT]; + + rv = ext_flash_open(); + + if(!rv) { + PRINTF("Could not open flash to save config!\n"); + ext_flash_close(); + return -1; + } + + for (remain = size, j = 0; remain > 0; remain -= XMEM_BUFF_LENGHT, j += XMEM_BUFF_LENGHT) { + int to_write = MIN(XMEM_BUFF_LENGHT, remain); + for (i = 0; i < to_write; i++) { + tmp_buf[i] = ~*((uint8_t *)_buf + j + i); + } + rv = ext_flash_write(addr + j, to_write, tmp_buf); + if (!rv) { + PRINTF("Could not write flash memory!\n"); + return size - remain; + } + } + + ext_flash_close(); + + return size; +} + + +int +xmem_erase(long size, unsigned long addr) +{ + int rv; + + rv = ext_flash_open(); + + + if(!rv) { + PRINTF("Could not open flash to save config\n"); + ext_flash_close(); + return -1; + } + + if(size % EXT_ERASE_UNIT_SIZE != 0) { + PRINTF("xmem_erase: bad size\n"); + return -1; + } + + if(addr % EXT_ERASE_UNIT_SIZE != 0) { + PRINTF("xmem_erase: bad offset\n"); + return -1; + } + + rv = ext_flash_erase(addr, size); + + ext_flash_close(); + + watchdog_periodic(); + + if(rv) + return size; + + PRINTF("Could not erase flash memory\n"); + return -1; +} diff --git a/arch/platform/srf06-cc26xx/launchpad/Makefile.launchpad b/arch/platform/srf06-cc26xx/launchpad/Makefile.launchpad index 8676c4171..224f0c2c5 100644 --- a/arch/platform/srf06-cc26xx/launchpad/Makefile.launchpad +++ b/arch/platform/srf06-cc26xx/launchpad/Makefile.launchpad @@ -2,7 +2,7 @@ CFLAGS += -DBOARD_LAUNCHPAD=1 CONTIKI_TARGET_DIRS += launchpad common -BOARD_SOURCEFILES += board.c launchpad-sensors.c button-sensor.c +BOARD_SOURCEFILES += board.c launchpad-sensors.c button-sensor.c xmem.c BOARD_SOURCEFILES += ext-flash.c board-spi.c ### Signal that we can be programmed with cc2538-bsl diff --git a/arch/platform/srf06-cc26xx/sensortag/Makefile.sensortag b/arch/platform/srf06-cc26xx/sensortag/Makefile.sensortag index 68e4b007f..1862f59fa 100644 --- a/arch/platform/srf06-cc26xx/sensortag/Makefile.sensortag +++ b/arch/platform/srf06-cc26xx/sensortag/Makefile.sensortag @@ -5,6 +5,6 @@ CONTIKI_TARGET_DIRS += sensortag common BOARD_SOURCEFILES += sensortag-sensors.c sensor-common.c BOARD_SOURCEFILES += bmp-280-sensor.c tmp-007-sensor.c opt-3001-sensor.c -BOARD_SOURCEFILES += hdc-1000-sensor.c mpu-9250-sensor.c button-sensor.c +BOARD_SOURCEFILES += hdc-1000-sensor.c mpu-9250-sensor.c button-sensor.c xmem.c BOARD_SOURCEFILES += reed-relay.c ext-flash.c buzzer.c BOARD_SOURCEFILES += board.c board-spi.c board-i2c.c diff --git a/examples/storage/cfs-coffee/Makefile b/examples/storage/cfs-coffee/Makefile index 4d27d6f8f..31a1aea59 100644 --- a/examples/storage/cfs-coffee/Makefile +++ b/examples/storage/cfs-coffee/Makefile @@ -1,6 +1,7 @@ CONTIKI = ../../.. MODULES += os/services/unit-test +MODULES += os/storage/cfs all: test-cfs test-coffee example-coffee diff --git a/examples/storage/cfs-coffee/README.md b/examples/storage/cfs-coffee/README.md index 991e9583b..028f518f8 100644 --- a/examples/storage/cfs-coffee/README.md +++ b/examples/storage/cfs-coffee/README.md @@ -23,6 +23,9 @@ Supported Hardware (tested or known to work) * cc2538dk * openmote-cc2538 * zoul +* TI srf06-cc26xx + - sensortag + - launchpad The examples are known to build for the 'avr-raven' platform. However, some of them currently fail at runtime due to file system overflow.