| @@ -0,0 +1,258 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup examples | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Helper tool for measuring BLE connection events | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * | ||
| * @} | ||
| */ | ||
|
|
||
| #include <stdio.h> | ||
| #include <string.h> | ||
| #include <stdint.h> | ||
|
|
||
| #include "board.h" | ||
| #include "sched.h" | ||
| #include "thread_flags.h" | ||
|
|
||
| #include "net/gorm/ll.h" | ||
| #include "nrfble_rxtim.h" | ||
| #include "net/netdev/ble.h" | ||
|
|
||
|
|
||
| #define ADV_AA (0x8e89bed6) | ||
| #define ADV_CRC (0x00555555) | ||
| #define ADV_CHAN (39U) | ||
|
|
||
| #define SYNC_ADV (0x0001) | ||
| #define SYNC_DAT (0x0002) | ||
|
|
||
| #define HOP_MASK(x) (x & 0x1f) | ||
|
|
||
| typedef struct __attribute__((packed)) { | ||
| uint8_t inita[GORM_LL_ADDR_LEN]; | ||
| uint8_t adva[GORM_LL_ADDR_LEN]; | ||
| uint8_t aa[4]; | ||
| uint8_t crc[GORM_LL_CRC_LEN]; | ||
| uint8_t win_size; | ||
| uint8_t win_offset[2]; | ||
| uint8_t interval[2]; | ||
| uint8_t latency[2]; | ||
| uint8_t timeout[2]; | ||
| uint8_t chan_map[GORM_LL_CHANMAP_LEN]; | ||
| uint8_t hop_sca; | ||
| } connect_ind_mtu_t; | ||
|
|
||
| /* state config */ | ||
| static netdev_ble_pkt_t pkt; | ||
| static netdev_t *dev; | ||
| static thread_t *thread; | ||
| static thread_flags_t flag = SYNC_ADV; | ||
|
|
||
| static gorm_ll_connection_t con; | ||
|
|
||
| /* timings */ | ||
| static uint16_t evt_cnt = 0xffff; | ||
| static uint32_t last = 0; | ||
| static uint32_t rxtim = 0; | ||
|
|
||
|
|
||
| static int _chan_used(uint8_t *map, uint8_t num) | ||
| { | ||
| return (map[num >> 3] & (1 << (num & 0x07))); | ||
| } | ||
|
|
||
| uint8_t gorm_ll_chan_count(uint8_t *map) | ||
| { | ||
| uint8_t cnt = 0; | ||
| for (uint8_t i = 0; i < GORM_LL_CHAN_NUMOF; i++) { | ||
| if (_chan_used(map, i)) { | ||
| ++cnt; | ||
| } | ||
| } | ||
| return cnt; | ||
| } | ||
|
|
||
| void gorm_ll_chan_algo1(gorm_ll_connection_t *con) | ||
| { | ||
| con->chan_unmapped = (con->chan_unmapped + con->chan_hop) % | ||
| GORM_LL_CHAN_DATA_NUMOF; | ||
| if (_chan_used(con->chan_map, con->chan_unmapped)) { | ||
| con->ctx.chan = con->chan_unmapped; | ||
| } | ||
| else { | ||
| unsigned remap_index = (con->chan_unmapped % con->chan_cnt) + 1; | ||
| int pos = -1; | ||
| while (remap_index > 0) { | ||
| /* advance to the next used channel */ | ||
| while (_chan_used(con->chan_map, ++pos) == 0) {} | ||
| --remap_index; | ||
| } | ||
| con->ctx.chan = pos; | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| static inline uint16_t _letohs(uint8_t *buf) | ||
| { | ||
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||
| return (uint16_t)((buf[1] << 8) | buf[0]); | ||
| #else | ||
| return (uint16_t)((buf[0] << 8) | buf[1]); | ||
| #endif | ||
| } | ||
|
|
||
|
|
||
| static void _on_radio(netdev_t *netdev, netdev_event_t event) | ||
| { | ||
| (void)event; | ||
| (void)netdev; | ||
|
|
||
| LED0_OFF; | ||
|
|
||
| rxtim = xtimer_now_usec(); | ||
| thread_flags_set(thread, flag); | ||
| } | ||
|
|
||
| static void _prep_next_pkt(void) | ||
| { | ||
| evt_cnt++; | ||
|
|
||
| if ((con.chan_update.cnt != 0) && | ||
| (evt_cnt == con.chan_update.instant)) { | ||
| memcpy(con.chan_map, con.chan_update.map, 5); | ||
| con.chan_cnt = con.chan_update.cnt; | ||
| con.chan_update.cnt = 0; | ||
| printf("--- chan update applied ---\n"); | ||
| } | ||
| gorm_ll_chan_algo1(&con); | ||
| } | ||
|
|
||
| static void _check_for_tim_update(void) | ||
| { | ||
| if (((pkt.flags & GORM_LL_LLID_MASK) == GORM_LL_LLID_CTRL) | ||
| && (pkt.pdu[0] == GORM_LL_CONN_UPDATE_IND)) { | ||
| uint8_t *d = &pkt.pdu[1]; | ||
| printf("--- connection update ---\n"); | ||
| uint16_t win_size = d[0]; | ||
| uint16_t win_offset = _letohs(&d[1]); | ||
| uint16_t interval = _letohs(&d[3]); | ||
| uint16_t timeout = _letohs(&d[7]); | ||
| uint16_t instant = _letohs(&d[9]); | ||
| printf("win_size: %u\n", (unsigned)win_size); | ||
| printf("win_offset: %u\n", (unsigned)win_offset); | ||
| printf("interval: %u\n", (unsigned)interval); | ||
| printf("timeout: %u\n", (unsigned)timeout); | ||
| printf("instant: %u\n", (unsigned)instant); | ||
| } | ||
| } | ||
|
|
||
| static void _check_for_chan_update(void) | ||
| { | ||
| if (((pkt.flags & GORM_LL_LLID_MASK) == GORM_LL_LLID_CTRL) | ||
| && (pkt.pdu[0] == GORM_LL_CHANNEL_MAP_IND)) { | ||
| uint8_t *d = &pkt.pdu[1]; | ||
|
|
||
| printf("--- channel map update ---\n"); | ||
| printf("map: %02x %02x %02x %02x %02x\n", | ||
| (int)d[0], (int)d[1], (int)d[2], (int)d[3], (int)d[4]); | ||
| uint16_t instant = _letohs(&d[5]); | ||
| printf("instant: %i\n", (int)instant); | ||
|
|
||
| memcpy(con.chan_update.map, d, 5); | ||
| con.chan_update.instant = instant; | ||
| con.chan_update.cnt = gorm_ll_chan_count(d); | ||
| printf("count: %i\n", (int)con.chan_update.cnt); | ||
| } | ||
| } | ||
|
|
||
| static void _check_for_con(void) | ||
| { | ||
| if ((pkt.flags & GORM_LL_PDU_MASK) == GORM_LL_CONNECT_IND) { | ||
| connect_ind_mtu_t *pdu = (connect_ind_mtu_t *)pkt.pdu; | ||
|
|
||
| con.chan_hop = HOP_MASK(pdu->hop_sca); | ||
| memcpy(con.chan_map, pdu->chan_map, GORM_LL_CHANMAP_LEN); | ||
| con.chan_cnt = gorm_ll_chan_count(con.chan_map); | ||
| con.chan_unmapped = 0; | ||
|
|
||
| memcpy(con.ctx.aa.raw, pdu->aa, 4); | ||
| memcpy(&con.ctx.crc, pdu->crc, GORM_LL_CRC_LEN); | ||
| _prep_next_pkt(); | ||
|
|
||
| flag = SYNC_DAT; | ||
|
|
||
| printf("New Connection\n"); | ||
| // printf("hop_inc: %i\n", (int)con.chan_hop); | ||
| // printf("aa: 0x%04x\n", (int)con.ctx.aa.u32); | ||
| // printf("crc: 0x%03x\n", (int)con.ctx.crc); | ||
| // printf("--- timings ---\n"); | ||
| // uint16_t win_size = pdu->win_size; | ||
| // uint16_t win_offset = _letohs(pdu->win_offset); | ||
| // uint16_t interval = _letohs(pdu->interval); | ||
| // uint16_t timeout = _letohs(pdu->timeout); | ||
| // printf("win_size: %u\n", (unsigned)win_size); | ||
| // printf("win_offset: %u\n", (unsigned)win_offset); | ||
| // printf("interval: %u\n", (unsigned)interval); | ||
| // printf("timeout: %u\n", (unsigned)timeout); | ||
| } | ||
| } | ||
|
|
||
| int main(void) | ||
| { | ||
| puts("BLE RX timer"); | ||
|
|
||
| /* setup environment */ | ||
| thread = (thread_t *)sched_active_thread; | ||
|
|
||
| last = xtimer_now_usec(); | ||
|
|
||
| /* init radio */ | ||
| dev = nrfble_setup(); | ||
| dev->event_callback = _on_radio; | ||
| dev->driver->init(dev); | ||
|
|
||
| /* prepare packet */ | ||
| con.ctx.crc = ADV_CRC; | ||
| con.ctx.aa.u32 = ADV_AA; | ||
| con.ctx.chan = ADV_CHAN; | ||
|
|
||
| while (1) { | ||
| LED0_ON; | ||
| netdev_ble_recv(dev, &pkt, &con.ctx); | ||
| thread_flags_t reason = thread_flags_wait_any(SYNC_ADV | SYNC_DAT); | ||
|
|
||
| if (reason & SYNC_ADV) { | ||
| // printf("adv: %u [%u us] | ", (unsigned)rxtim, (unsigned)(last - rxtim)); | ||
| // _adv_info(); | ||
| _check_for_con(); | ||
| } | ||
| if (reason & SYNC_DAT) { | ||
| LED1_OFF; | ||
| printf("evt %i: %u [%u us] - ch %i\n", | ||
| (int)evt_cnt, (unsigned)rxtim, | ||
| (unsigned)(rxtim - last), | ||
| (int)con.ctx.chan); | ||
| _check_for_tim_update(); | ||
| _check_for_chan_update(); | ||
| _prep_next_pkt(); | ||
| LED1_ON; | ||
| } | ||
|
|
||
| last = rxtim; | ||
| } | ||
|
|
||
| return 0; | ||
| } |
| @@ -0,0 +1,354 @@ | ||
| /* | ||
| * Copyright (C) 2017 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup drivers_nrf5x_nrfble | ||
| * | ||
| * @note This driver is not thread safe and should only be used by a | ||
| * single thread at once! | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Bluetooth low energy radio driver for nRF5x SoCs | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * | ||
| * @} | ||
| */ | ||
|
|
||
| #include <errno.h> | ||
|
|
||
| #include "cpu.h" | ||
| #include "assert.h" | ||
|
|
||
| #include "nrfble.h" | ||
| #include "net/netdev/ble.h" | ||
|
|
||
| #define ENABLE_DEBUG (0) | ||
| #include "debug.h" | ||
|
|
||
| /** | ||
| * @brief Driver specific device configuration | ||
| * @{ | ||
| */ | ||
| #define CONF_MODE RADIO_MODE_MODE_Ble_1Mbit | ||
| #define CONF_LEN (8U) | ||
| #define CONF_S0 (1U) | ||
| #define CONF_S1 (0U) | ||
| #define CONF_STATLEN (0U) | ||
| #define CONF_BASE_ADDR_LEN (3U) | ||
| #define CONF_ENDIAN RADIO_PCNF1_ENDIAN_Little | ||
| #define CONF_WHITENING RADIO_PCNF1_WHITEEN_Enabled | ||
| #define CONF_CRC_LEN (0X3 | RADIO_CRCCNF_SKIPADDR_Msk) | ||
| #define CONF_CRC_POLY (0x00065b) | ||
| #define CONF_CRC_INIT (0x555555) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @brief Allocate the netdev device descriptor | ||
| */ | ||
| netdev_t nrfble_dev; | ||
|
|
||
| /** | ||
| * @brief Remember the radio context when receiving things | ||
| */ | ||
| netdev_ble_ctx_t *rx_ctx; | ||
|
|
||
| /** | ||
| * @brief Map logical BLE channel values to actual radio frequencies | ||
| */ | ||
| static const uint8_t ble_chan_map[40] = { | ||
| [ 0] = 4, | ||
| [ 1] = 6, | ||
| [ 2] = 8, | ||
| [ 3] = 10, | ||
| [ 4] = 12, | ||
| [ 5] = 14, | ||
| [ 6] = 16, | ||
| [ 7] = 18, | ||
| [ 8] = 20, | ||
| [ 9] = 22, | ||
| [10] = 24, | ||
| [11] = 28, | ||
| [12] = 30, | ||
| [13] = 32, | ||
| [14] = 34, | ||
| [15] = 36, | ||
| [16] = 38, | ||
| [17] = 40, | ||
| [18] = 42, | ||
| [19] = 44, | ||
| [20] = 46, | ||
| [21] = 48, | ||
| [22] = 50, | ||
| [23] = 52, | ||
| [24] = 54, | ||
| [25] = 56, | ||
| [26] = 58, | ||
| [27] = 60, | ||
| [28] = 62, | ||
| [29] = 64, | ||
| [30] = 66, | ||
| [31] = 68, | ||
| [32] = 70, | ||
| [33] = 72, | ||
| [34] = 74, | ||
| [35] = 76, | ||
| [36] = 78, | ||
| [37] = 2, | ||
| [38] = 26, | ||
| [39] = 80, | ||
| }; | ||
|
|
||
| /** | ||
| * @brief Set radio into idle (DISABLED) state | ||
| */ | ||
| static void go_idle(void) | ||
| { | ||
| /* only do anything in case RX is active */ | ||
| if (NRF_RADIO->INTENSET & RADIO_INTENSET_DISABLED_Msk) { | ||
| NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; | ||
| /* set device into basic disabled state */ | ||
| NRF_RADIO->EVENTS_DISABLED = 0; | ||
| NRF_RADIO->TASKS_DISABLE = 1; | ||
| while (NRF_RADIO->EVENTS_DISABLED == 0) { | ||
| /* TODO: enable sleep here */ | ||
| // cortexm_sleep_until_event(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| static void set_context(netdev_ble_ctx_t *ctx) | ||
| { | ||
| assert(ctx->chan <= NRFBLE_CHAN_MAX); | ||
|
|
||
| NRF_RADIO->FREQUENCY = ble_chan_map[ctx->chan]; | ||
| NRF_RADIO->PREFIX0 = ctx->aa.raw[3]; | ||
| NRF_RADIO->BASE0 = (uint32_t)((ctx->aa.raw[0] << 8) | | ||
| (ctx->aa.raw[1] << 16) | | ||
| (ctx->aa.raw[2] << 24)); | ||
| NRF_RADIO->DATAWHITEIV = ctx->chan; | ||
| NRF_RADIO->CRCINIT = ctx->crc; | ||
| } | ||
|
|
||
| static int16_t nrfble_get_txpower(void) | ||
| { | ||
| int8_t p = (int8_t)NRF_RADIO->TXPOWER; | ||
| if (p < 0) { | ||
| return (int16_t)(0xff00 | p); | ||
| } | ||
| return (int16_t)p; | ||
| } | ||
|
|
||
| static void nrfble_set_txpower(int16_t power) | ||
| { | ||
| if (power > 2) { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Pos4dBm; | ||
| } | ||
| else if (power > -2) { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_0dBm; | ||
| } | ||
| else if (power > -6) { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg4dBm; | ||
| } | ||
| else if (power > -10) { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg8dBm; | ||
| } | ||
| else if (power > -14) { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg12dBm; | ||
| } | ||
| else if (power > -18) { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg16dBm; | ||
| } | ||
| else if (power > -25) { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg20dBm; | ||
| } | ||
| else { | ||
| NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg30dBm; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @brief Radio interrupt routine | ||
| */ | ||
| void isr_radio(void) | ||
| { | ||
| if (NRF_RADIO->EVENTS_DISABLED == 1) { | ||
| NRF_RADIO->EVENTS_DISABLED = 0; | ||
|
|
||
| rx_ctx->crc = NRF_RADIO->CRCSTATUS; | ||
| nrfble_dev.event_callback(&nrfble_dev, NETDEV_EVENT_RX_COMPLETE); | ||
| } | ||
| cortexm_isr_end(); | ||
| } | ||
|
|
||
|
|
||
| netdev_t *nrfble_setup(void) | ||
| { | ||
| nrfble_dev.driver = &nrfble_netdev; | ||
| nrfble_dev.event_callback = NULL; | ||
| nrfble_dev.context = NULL; | ||
| #ifdef MODULE_NETSTATS_L2 | ||
| memset(&nrfble_dev.stats, 0, sizeof(netstats_t));; | ||
| #endif | ||
| return &nrfble_dev; | ||
| } | ||
|
|
||
| static int nrfble_init(netdev_t *dev) | ||
| { | ||
| (void)dev; | ||
| assert(nrfble_dev.driver && nrfble_dev.event_callback); | ||
|
|
||
| /* power on the NRFs radio */ | ||
| NRF_RADIO->POWER = 1; | ||
| /* configure variable parameters to default values */ | ||
| NRF_RADIO->TXPOWER = NRFBLE_TXPOWER_DEFAULT; | ||
| /* always send from and listen to logical address 0 */ | ||
| NRF_RADIO->TXADDRESS = 0x00UL; | ||
| NRF_RADIO->RXADDRESSES = 0x01UL; | ||
| /* load driver specific configuration */ | ||
| NRF_RADIO->MODE = CONF_MODE; | ||
| /* configure data fields and packet length whitening and endianess */ | ||
| NRF_RADIO->PCNF0 = ((CONF_S1 << RADIO_PCNF0_S1LEN_Pos) | | ||
| (CONF_S0 << RADIO_PCNF0_S0LEN_Pos) | | ||
| (CONF_LEN << RADIO_PCNF0_LFLEN_Pos)); | ||
| NRF_RADIO->PCNF1 = ((CONF_WHITENING << RADIO_PCNF1_WHITEEN_Pos) | | ||
| (CONF_ENDIAN << RADIO_PCNF1_ENDIAN_Pos) | | ||
| (CONF_BASE_ADDR_LEN << RADIO_PCNF1_BALEN_Pos) | | ||
| (CONF_STATLEN << RADIO_PCNF1_STATLEN_Pos) | | ||
| (NETDEV_BLE_PDU_MAXLEN << RADIO_PCNF1_MAXLEN_Pos)); | ||
| /* configure the CRC unit, we skip the address field as this seems to lead | ||
| * to wrong checksum calculation on nRF52 devices in some cases */ | ||
| NRF_RADIO->CRCCNF = CONF_CRC_LEN; | ||
| NRF_RADIO->CRCPOLY = CONF_CRC_POLY; | ||
| NRF_RADIO->CRCINIT = CONF_CRC_INIT; | ||
| /* set shortcuts for more efficient transfer */ | ||
| NRF_RADIO->SHORTS = (RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk); | ||
| /* enable global radio interrupts, but leave local interrupts masked */ | ||
| NRF_RADIO->INTENCLR = 0xffffffff; | ||
| NVIC_EnableIRQ(RADIO_IRQn); | ||
|
|
||
| DEBUG("[nrfble] initialization successful\n"); | ||
| return 0; | ||
| } | ||
|
|
||
| static int nrfble_send(netdev_t *dev, const struct iovec *data, unsigned count) | ||
| { | ||
| (void)dev; | ||
| (void)count; | ||
|
|
||
| assert(count == 2); | ||
| assert((data != NULL) && | ||
| (data[0].iov_len == sizeof(netdev_ble_ctx_t)) && | ||
| (data[1].iov_len == sizeof(netdev_ble_pkt_t))); | ||
|
|
||
| /* cancel any RX operation (if ongoing) */ | ||
| go_idle(); | ||
|
|
||
| /* get the BLE pkt data */ | ||
| netdev_ble_ctx_t *ctx = data[0].iov_base; | ||
| netdev_ble_pkt_t *pkt = data[1].iov_base; | ||
|
|
||
| DEBUG("[nrfble] send: sending %i bytes on chan %i\n", | ||
| (int)pkt->len, (int)ctx->chan); | ||
|
|
||
| /* setup radio */ | ||
| set_context(ctx); | ||
| NRF_RADIO->PACKETPTR = (uint32_t)(pkt); | ||
|
|
||
| NRF_RADIO->EVENTS_DISABLED = 0; | ||
| NRF_RADIO->TASKS_TXEN = 1; | ||
| while (NRF_RADIO->EVENTS_DISABLED == 0) { | ||
| /* TODO: enable (and verify) sleep below */ | ||
| // cortexm_sleep_until_event(); | ||
| } | ||
|
|
||
| return (int)pkt->len; | ||
| } | ||
|
|
||
| static int nrfble_recv(netdev_t *dev, void *buf, size_t len, void *info) | ||
| { | ||
| (void)dev; | ||
| (void)len; | ||
|
|
||
| /* cancel any ongoing operation */ | ||
| go_idle(); | ||
|
|
||
| if (buf) { | ||
| assert(info); | ||
| assert(len == sizeof(netdev_ble_pkt_t)); | ||
|
|
||
| rx_ctx = (netdev_ble_ctx_t *)info; | ||
|
|
||
| /* setup radio */ | ||
| set_context(rx_ctx); | ||
| NRF_RADIO->PACKETPTR = (uint32_t)(buf); | ||
| NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; | ||
|
|
||
| /* put radio into RX mode */ | ||
| NRF_RADIO->EVENTS_DISABLED = 0; | ||
| NRF_RADIO->TASKS_RXEN = 1; | ||
| DEBUG("[nrfble] recv: now in RX mode (chan %i)\n", (int)rx_ctx->chan); | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static void nrfble_isr(netdev_t *dev) | ||
| { | ||
| if (nrfble_dev.event_callback) { | ||
| nrfble_dev.event_callback(dev, NETDEV_EVENT_RX_COMPLETE); | ||
| } | ||
| } | ||
|
|
||
| static int nrfble_get(netdev_t *dev, netopt_t opt, void *val, size_t max_len) | ||
| { | ||
| (void)dev; | ||
| (void)max_len; | ||
|
|
||
| switch (opt) { | ||
| case NETOPT_TX_POWER: | ||
| assert(max_len >= sizeof(int16_t)); | ||
| *((int16_t *)val) = nrfble_get_txpower(); | ||
| return sizeof(int16_t); | ||
| case NETOPT_DEVICE_TYPE: | ||
| assert(max_len >= sizeof(uint16_t)); | ||
| *((uint16_t *)val) = NETDEV_TYPE_BLE; | ||
| return sizeof(uint16_t); | ||
| default: | ||
| return -ENOTSUP; | ||
| } | ||
| } | ||
|
|
||
| static int nrfble_set(netdev_t *dev, netopt_t opt, const void *val, size_t len) | ||
| { | ||
| (void)dev; | ||
| (void)len; | ||
|
|
||
| switch (opt) { | ||
| case NETOPT_TX_POWER: | ||
| assert(len == sizeof(int16_t)); | ||
| nrfble_set_txpower(*((const int16_t *)val)); | ||
| return sizeof(int16_t); | ||
| default: | ||
| return -ENOTSUP; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @brief Export of the netdev interface | ||
| */ | ||
| const netdev_driver_t nrfble_netdev = { | ||
| .send = nrfble_send, | ||
| .recv = nrfble_recv, | ||
| .init = nrfble_init, | ||
| .isr = nrfble_isr, | ||
| .get = nrfble_get, | ||
| .set = nrfble_set | ||
| }; |
| @@ -0,0 +1,73 @@ | ||
| /* | ||
| * Copyright (C) 2017 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup drivers_nrf5x_nrfble nRF BLE radio driver | ||
| * @ingroup drivers_netdev | ||
| * @brief Radio driver for nRF5x SoCs for using the radio in BLE mode | ||
| * | ||
| * @note This driver is not thread safe (as of now) | ||
| * | ||
| * @todo add support for netdev_ble_pkt_ext_t | ||
| * @todo figure out how to synchronize send and receive and how to make | ||
| * them thread safe | ||
| * | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Interface definition for the nrfble radio driver | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef NRFBLE_H | ||
| #define NRFBLE_H | ||
|
|
||
| #include "net/netdev.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief nrfble channel configuration | ||
| * @{ | ||
| */ | ||
| #define NRFBLE_CHAN_MIN (0U) | ||
| #define NRFBLE_CHAN_MAX (39U) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @brief Default transmission power used | ||
| */ | ||
| #define NRFBLE_TXPOWER_DEFAULT (0) /* 0dBm */ | ||
|
|
||
| /** | ||
| * @brief Export the netdev device descriptor | ||
| */ | ||
| extern netdev_t nrfble_dev; | ||
|
|
||
| /** | ||
| * @brief Reference to the netdev driver interface | ||
| */ | ||
| extern const netdev_driver_t nrfble_netdev; | ||
|
|
||
| /** | ||
| * @brief Setup the device driver's data structures | ||
| * | ||
| * @return pointer to the device's netdev struct | ||
| */ | ||
| netdev_t *nrfble_setup(void); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* NRFBLE_H */ | ||
| /** @} */ |
| @@ -0,0 +1,3 @@ | ||
| MODULE = auto_init_gorm | ||
|
|
||
| include $(RIOTBASE)/Makefile.base |
| @@ -0,0 +1,124 @@ | ||
| /* | ||
| * Copyright (C) 2017 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's link layer implementation | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * @} | ||
| */ | ||
|
|
||
| #include "log.h" | ||
| #include "assert.h" | ||
| #include "thread.h" | ||
|
|
||
| #include "net/gorm.h" | ||
| #include "net/gorm/pdupool.h" | ||
|
|
||
| /* we do some ugly device specific multiplexing here for now */ | ||
| #if defined(MODULE_NRFBLE) | ||
| #include "nrfble.h" | ||
| #elif defined(MODULE_SOME_BLE_RADIO_DRIVER) | ||
| #include "somedrv.h" | ||
| #include "somedrv_params.h" | ||
| static somedrv_t somedrv_dev; | ||
| #else | ||
| #error "[auto_init_gorm] error: now compatible radio driver found" | ||
| #endif | ||
|
|
||
| /* set CREATE_STACKTEST flag depending on log level */ | ||
| #if (LOG_LEVEL >= LOG_DEBUG) | ||
| #define TFLAGS THREAD_CREATE_STACKTEST | ||
| #else | ||
| #define TFLAGS (0) | ||
| #endif | ||
|
|
||
| /* allocate stack(s) */ | ||
| static char stack_ctrl[GORM_CFG_THREAD_STACKSIZE_CONTROLLER]; | ||
| #ifdef MODULE_GORM_STANDALONE | ||
| static char stack_host[GORM_CFG_THREAD_STACKSIZE_HOST] | ||
| #endif | ||
|
|
||
| /* TODO: move together with the pool mem allocation below */ | ||
| static char pool[GORM_CFG_POOLSIZE * sizeof(gorm_buf_t)]; | ||
|
|
||
| static netdev_t *radio_setup(void) | ||
| { | ||
| netdev_t *dev = NULL; | ||
|
|
||
| #if defined(MODULE_NRFBLE) | ||
| LOG_DEBUG("[auto_init_gorm] initializing nrfble #0\n"); | ||
| dev = nrfble_setup(); | ||
| #elif defined(MODULE_SOME_BLE_RADIO_DRIVER) | ||
| LOG_DEBUG("[auto_init_gorm] initializing somedrv #0\n"); | ||
| somedrv_setup(&somedrv_dev, &somedrv_params[0]); | ||
| dev = (netdev_t *)(&somedrv_dev); | ||
| #endif | ||
|
|
||
| return dev; | ||
| } | ||
|
|
||
| static void *ctrl_thread(void *arg) | ||
| { | ||
| netdev_t *dev = (netdev_t *)arg; | ||
| gorm_run_controller(dev); | ||
| return NULL; | ||
| } | ||
|
|
||
| #ifdef MODULE_GORM_STANDALONE | ||
| static void *host_thread(void *arg) | ||
| { | ||
| (void)arg; | ||
| gorm_host_run(); | ||
| return NULL; | ||
| } | ||
| #endif | ||
|
|
||
| void auto_init_gorm(void) | ||
| { | ||
| netdev_t *dev = radio_setup(); | ||
|
|
||
| /* make sure we got a device handle */ | ||
| if (!dev) { | ||
| LOG_ERROR("[auto_init_gorm] unable to setup radio for Gorm\n"); | ||
| return; | ||
| } | ||
|
|
||
| /* allocate the PDU pool */ | ||
| /* TODO: move somewhere better suited */ | ||
| gorm_pdupool_addmem(pool, sizeof(pool)); | ||
|
|
||
| /* initialize the host */ | ||
| gorm_host_init(); | ||
|
|
||
| /* run Gorm's link layer */ | ||
| LOG_DEBUG("[auto_init_gorm] setting up Gorm's link layer thread now\n"); | ||
| thread_create(stack_ctrl, | ||
| sizeof(stack_ctrl), | ||
| GORM_CFG_THREAD_PRIO_CONTROLLER, | ||
| TFLAGS, | ||
| ctrl_thread, | ||
| dev, | ||
| GORM_CFG_THREAD_NAME_CONTROLLER); | ||
|
|
||
| /* if standalone mode is activated, we also spawn Gorm's host thread now */ | ||
| #ifdef MODULE_GORM_STANDALONE | ||
| LOG_DEBUG("[auto_init_gorm] setting up Gorm's host thread now\n"); | ||
| thread_create(stack_host, | ||
| sizeof(stack_host), | ||
| GORM_CFG_THREAD_PRIO_HOST, | ||
| TFLAGS, | ||
| host_thread, | ||
| NULL, | ||
| GORM_CFG_THREAD_NAME_HOST); | ||
| #endif | ||
| } |
| @@ -0,0 +1,4 @@ | ||
| SRC = ggs.c | ||
| SRC += $(patsubst ggs_%,%.c,$(filter ggs_%,$(USEMODULE))) | ||
|
|
||
| include $(RIOTBASE)/Makefile.base |
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_ggs | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Bootstrapping of included GATT services for GORM | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * @} | ||
| */ | ||
|
|
||
| #include "net/gorm/gatt.h" | ||
| #include "net/gorm/gatt/tab.h" | ||
|
|
||
| #include "net/ggs.h" | ||
| #include "net/ggs/riot.h" | ||
| #include "net/ggs/sig.h" | ||
|
|
||
| /* TDODO: move SIG services into the Gorm stack at some point? */ | ||
| #ifdef MODULE_GGS_IPS | ||
| static gorm_gatt_entry_t ips_entry; | ||
| extern gorm_gatt_service_t ggs_ips_service; | ||
| #endif | ||
|
|
||
| #ifdef MODULE_GGS_RIOT_LED | ||
| static gorm_gatt_entry_t led_entry; | ||
| extern gorm_gatt_service_t ggs_riot_led_service; | ||
| #endif | ||
|
|
||
| void ggs_init(void) | ||
| { | ||
| #ifdef MODULE_GGS_IPS | ||
| gorm_gatt_tab_reg_service(&ips_entry, &ggs_ips_service); | ||
| #endif | ||
|
|
||
| #ifdef MODULE_GGS_RIOT_LED | ||
| gorm_gatt_tab_reg_service(&led_entry, &ggs_riot_led_service); | ||
| #endif | ||
| /* TODO: add SAUL etc ... */ | ||
| } |
| @@ -0,0 +1,28 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_ggs_sig | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Implementation of the BT SIG Internet Protocol Support Service | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * @} | ||
| */ | ||
|
|
||
| #include "net/gorm/uuid.h" | ||
|
|
||
| #include "net/ggs/sig.h" | ||
|
|
||
| const gorm_gatt_service_t ggs_ips_service = { | ||
| .uuid = GORM_UUID(GGS_UUID_IPS, NULL), | ||
| .char_cnt = 0, /* this service has no characteristics */ | ||
| .chars = NULL, | ||
| }; |
| @@ -0,0 +1,194 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_ggs_riot | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief RIOT specific LED GATT service for Gorm | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * @} | ||
| */ | ||
|
|
||
| #include "net/ggs/riot.h" | ||
| #include "net/gorm/gatt/desc.h" | ||
|
|
||
| #define ENABLE_DEBUG (0) | ||
| #include "debug.h" | ||
|
|
||
| /* we assume them all initially turned off */ | ||
| static uint8_t _led_state = 0; | ||
|
|
||
| #if defined(LED7_ON) | ||
| #define NUMOF_LED (8U) | ||
| #elif defined(LED6_ON) | ||
| #define NUMOF_LED (7U) | ||
| #elif defined(LED5_ON) | ||
| #define NUMOF_LED (6U) | ||
| #elif defined(LED4_ON) | ||
| #define NUMOF_LED (5U) | ||
| #elif defined(LED3_ON) | ||
| #define NUMOF_LED (4U) | ||
| #elif defined(LED2_ON) | ||
| #define NUMOF_LED (3U) | ||
| #elif defined(LED1_ON) | ||
| #define NUMOF_LED (2U) | ||
| #elif defined(LED0_ON) | ||
| #define NUMOF_LED (1U) | ||
| #else | ||
| #error "Gorm GATT service 'LED': unable to build - no LEDs available" | ||
| #endif | ||
|
|
||
| static inline void _write(unsigned led, uint8_t state) | ||
| { | ||
| if (state) { | ||
| _led_state |= (1 << led); | ||
| switch (led) { | ||
| case 0: LED0_ON; break; | ||
| case 1: LED1_ON; break; | ||
| case 2: LED2_ON; break; | ||
| case 3: LED3_ON; break; | ||
| case 4: LED4_ON; break; | ||
| case 5: LED5_ON; break; | ||
| case 6: LED6_ON; break; | ||
| case 7: LED7_ON; break; | ||
| default: break; /* do nothing */ | ||
| } | ||
| } | ||
| else { | ||
| _led_state &= ~(1 << led); | ||
| switch (led) { | ||
| case 0: LED0_OFF; break; | ||
| case 1: LED1_OFF; break; | ||
| case 2: LED2_OFF; break; | ||
| case 3: LED3_OFF; break; | ||
| case 4: LED4_OFF; break; | ||
| case 5: LED5_OFF; break; | ||
| case 6: LED6_OFF; break; | ||
| case 7: LED7_OFF; break; | ||
| default: break; /* do nothing */ | ||
| } | ||
| } | ||
| } | ||
|
|
||
| static size_t _led_cb(const gorm_gatt_char_t *c, uint8_t method, | ||
| uint8_t *buf, size_t buf_len) | ||
| { | ||
| if (buf_len < 1) { | ||
| return 0; | ||
| } | ||
|
|
||
| unsigned led = (unsigned)c->arg; | ||
|
|
||
|
|
||
| switch (method) { | ||
| case GORM_GATT_READ: | ||
| buf[0] = ((_led_state >> led) & 0x1); | ||
| return 1; | ||
| case GORM_GATT_WRITE: | ||
| _write(led, buf[0]); | ||
| return 1; | ||
| default: | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| static const gorm_gatt_desc_t _led_desc[] = { | ||
| GORM_GATT_DESC_FMT(BLE_UNIT_BLE_FMT_BOOL, 0, BLE_UNIT_NONE), | ||
| }; | ||
|
|
||
| static const gorm_gatt_char_t _led_chars[] = { | ||
| #ifdef LED0_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)0, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| #ifdef LED1_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)1, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| #ifdef LED2_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)2, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| #ifdef LED3_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)3, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| #ifdef LED4_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)4, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| #ifdef LED5_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)5, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| #ifdef LED6_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)6, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| #ifdef LED7_ON | ||
| { | ||
| .cb = _led_cb, | ||
| .arg = (void *)7, | ||
| .type = GORM_UUID(GORM_UUID_RIOT_LED_CHAR, &ggs_uuid_riot_base), | ||
| .perm = (BLE_ATT_READ | BLE_ATT_WRITE), | ||
| .desc_cnt = 1, | ||
| .desc = _led_desc, | ||
| }, | ||
| #endif | ||
| }; | ||
|
|
||
| const gorm_gatt_service_t ggs_riot_led_service = { | ||
| .uuid = GORM_UUID(GORM_UUID_RIOT_LED_SERVICE, &ggs_uuid_riot_base), | ||
| .char_cnt = NUMOF_LED, | ||
| .chars = _led_chars, | ||
| }; |
| @@ -0,0 +1,39 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_ggs GATT Services for Gorm | ||
| * @ingroup net | ||
| * @brief Collection of pre-defined GATT services to be used with Gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Bootstrapping interface for the built-in Gorm GATT services | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_SERVICE_RIOT_H | ||
| #define GORM_SERVICE_RIOT_H | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Initialize all configured built-in services and register them with | ||
| * the GATT table | ||
| */ | ||
| void ggs_init(void); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_SERVICE_RIOT_H */ | ||
| /** @} */ |
| @@ -0,0 +1,50 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_ggs_riot RIOT GATT services for Gorm | ||
| * @ingroup net_ggs | ||
| * @brief RIOT specific GATT services to be used with Gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Definition of RIOT specific GATT defines for Gorm | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_SERVICE_RIOT_H | ||
| #define GORM_SERVICE_RIOT_H | ||
|
|
||
| #include "net/gorm/gatt.h" | ||
| #include "net/gorm/uuid.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #define GORM_UUID_RIOT_LED_SERVICE (0x0001) | ||
| #define GORM_UUID_RIOT_LED_CHAR (0x0002) | ||
|
|
||
| static const gorm_uuid_base_t ggs_uuid_riot_base = {{ | ||
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 0x0a, 0x0f, 0x0f, 0x0e, | ||
| 0x00, 0x00, 0x52, 0x49, 0x4f, 0x54 | ||
| }}; | ||
|
|
||
| /** | ||
| * @brief Export the RIOT LED service | ||
| */ | ||
| extern const gorm_gatt_service_t ggs_riot_led_service; | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_SERVICE_RIOT_H */ | ||
| /** @} */ |
| @@ -0,0 +1,49 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_ggs_sig BT SIG defined GATT services | ||
| * @ingroup net_ggs | ||
| * @brief BT SIG specific GATT services | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Definition of BT SIG specific GATT | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_SERVICE_RIOT_H | ||
| #define GORM_SERVICE_RIOT_H | ||
|
|
||
| #include "net/gorm/gatt.h" | ||
|
|
||
| #define GGS_UUID_IPS (0x1820) | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /* TODO: not sure we ever need this */ | ||
| // static const gorm_uuid_base_t gorm_uuid_sig_base = {{ | ||
| // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| // 0x10, 0x00, 0x80, 0x00, | ||
| // 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb | ||
| // }}; | ||
|
|
||
| /** | ||
| * @brief Export the `Internet Protocol Support Service` | ||
| */ | ||
| extern const gorm_gatt_service_t ggs_ips_service; | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_SERVICE_RIOT_H */ | ||
| /** @} */ |
| @@ -0,0 +1,85 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_gorm Gorm, the daddy of Bluetooth | ||
| * @ingroup net | ||
| * @brief Gorm, the BLE stack for RIOT | ||
| * | ||
| * TODO more high-level doc | ||
| * | ||
| * @todo Unify concept of static vs dynamic configuaration values, e.g. | ||
| * - advertisement intervals (conn vs nonconn) | ||
| * @todo Address handling: generation of public addresses etc | ||
| * @todo Use netdev correctly (do proper switching to thread context) | ||
| * @todo Implement and use `event_post_first()` and use in link layer for | ||
| * received packets | ||
| * @todo check for consistent naming of static functions (_x vs x) | ||
| * | ||
| * @{ | ||
| * @file | ||
| * @brief High level interface for telling Gorm how to behave | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_H | ||
| #define GORM_H | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #include "clist.h" | ||
|
|
||
| #include "net/netdev/ble.h" | ||
| #include "net/gorm/config.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Maximum link layer PDU length (excluding 2 byte header) [0:255] bytes | ||
| */ | ||
| #define GORM_PDU_MAXLEN (255U) | ||
|
|
||
| typedef struct gorm_pdu { | ||
| struct gorm_pdu *next; | ||
| netdev_ble_pkt_t pkt; | ||
| } gorm_buf_t; | ||
|
|
||
| /** | ||
| * @brief Gorm's error codes | ||
| */ | ||
| /* TODO: Move to dedicated header?! */ | ||
| enum { | ||
| GORM_OK = 0, | ||
| GORM_ERR_TIMINGS = -1, | ||
| }; | ||
|
|
||
|
|
||
| /** | ||
| * @brief Run Gorm's link layer | ||
| */ | ||
| void gorm_run_controller(netdev_t *radio); | ||
|
|
||
| /** | ||
| * @brief Initialize Gorm's host implementation | ||
| */ | ||
| void gorm_host_init(void); | ||
|
|
||
| /** | ||
| * @brief Run Gorm's host layers | ||
| */ | ||
| void gorm_host_run(void); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_H */ | ||
| /** @} */ |
| @@ -0,0 +1,5 @@ | ||
|
|
||
|
|
||
| typedef event_t gorm_arch_event_t; | ||
|
|
||
| gorm_arch_event_post_first(gorm_arch_event_t ) |
| @@ -0,0 +1,46 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm_arch | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Mapping of the platform dependent (pseudo-)random number | ||
| * generator | ||
| * | ||
| * @todo Think about inlining... | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_ARCH_RAND_H | ||
| #define GORM_ARCH_RAND_H | ||
|
|
||
| #include <stdio.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Generate a random number that lies within the [min,max)-interval | ||
| * | ||
| * @param[in] min lower bound of output values (including this value) | ||
| * @param[in] max upper bound of output values (excluding this value) | ||
| * | ||
| * @return (pseudo-)random value from the [min,max)-interval | ||
| */ | ||
| uint32_t gorm_arch_rand(uint32_t min, uint32_t max); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* RANDOM_H */ | ||
| /** @} */ |
| @@ -0,0 +1,57 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm_arch | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's timer abstraction | ||
| * | ||
| * @note All timer callbacks are supposed to be run in interrupt context | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_ARCH_TIMER_H | ||
| #define GORM_ARCH_TIMER_H | ||
|
|
||
| #include "xtimer.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /* TODO: let architecture specific implementation define this somehow */ | ||
| typedef struct { | ||
| xtimer_t base; | ||
| uint32_t last; | ||
| } gorm_arch_timer_t; | ||
|
|
||
| typedef void (*gorm_arch_timer_cb_t)(void *); | ||
|
|
||
| /* does set last value to now() */ | ||
| void gorm_arch_timer_anchor(gorm_arch_timer_t *timer, uint32_t compensation); | ||
|
|
||
| /* will change last value to last + timeout */ | ||
| void gorm_arch_timer_set_from_last(gorm_arch_timer_t *timer, uint32_t timeout, | ||
| gorm_arch_timer_cb_t cb, void *arg); | ||
|
|
||
| /* does not touch last value */ | ||
| void gorm_arch_timer_set_from_now(gorm_arch_timer_t *timer, uint32_t timeout, | ||
| gorm_arch_timer_cb_t cb, void *arg); | ||
|
|
||
| /* cancel the timer */ | ||
| void gorm_arch_timer_cancel(gorm_arch_timer_t *timer); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_ARCH_TIMER_H */ | ||
| /** @} */ |
| @@ -0,0 +1,65 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's ATT (Attribute Protocol) implementation | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_ATT_H | ||
| #define GORM_ATT_H | ||
|
|
||
| #include "net/gorm.h" | ||
| #include "net/gorm/uuid.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @name ATT error codes | ||
| * @{ | ||
| */ | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Attribute opcodes | ||
| * @{ | ||
| */ | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Attribute properties | ||
| * @{ | ||
| */ | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Permission flags | ||
| * | ||
| * TODO: probably need re-definition... | ||
| * @{ | ||
| */ | ||
| #define GORM_ATT_READABLE (0x01) | ||
| #define GORM_ATT_WRITABLE (0x02) | ||
| #define GORM_ATT_ENC_REQ (0x04) | ||
| #define GORM_ATT_AUTHEN_REQ (0x08) | ||
| #define GORM_ATT_AUTHOR_REQ (0x10) | ||
| /** @} */ | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_PDUQ_H */ | ||
| /** @} */ |
| @@ -0,0 +1,119 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup sys_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's global configuration | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_CONFIG_H | ||
| #define GORM_CONFIG_H | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #ifndef GORM_CFG_LL_PERIPH_CONNECTIONS_LIMIT | ||
| #define GORM_CFG_LL_PERIPH_CONNECTIONS_LIMIT (1U) | ||
| #endif | ||
|
|
||
| #ifndef GORM_CFG_LL_PERIPH_ADV_INTERVAL | ||
| #define GORM_CFG_LL_PERIPH_ADV_INTERVAL (1U * US_PER_SEC) | ||
| #endif | ||
|
|
||
| #ifndef GORM_CFG_LL_PERIPH_ADV_EVENT_DURATION | ||
| #define GORM_CFG_LL_PERIPH_ADV_EVENT_DURATION (10U * US_PER_MS) | ||
| #endif | ||
|
|
||
| #ifndef GORM_CFG_LL_PERIPH_ADV_CHANNELS | ||
| #define GORM_CFG_LL_PERIPH_ADV_CHANNELS { 37, 38, 39 } | ||
| // #define GORM_CFG_LL_PERIPH_ADV_CHANNELS { 39 } | ||
| #endif | ||
|
|
||
| /* ADVANCED */ | ||
| /** | ||
| * @brief Compensate for the time passed between the start of the first packet | ||
| * received in a connection and the time when the actual callback is | ||
| * triggered, in [us] | ||
| */ | ||
| #ifndef GORM_CFG_LL_ANCHOR_OFFSET | ||
| #define GORM_CFG_LL_ANCHOR_OFFSET (350U) | ||
| #endif | ||
|
|
||
| /* ADVANCED */ | ||
| /** | ||
| * @brief Static window widening value, roughly estimated... | ||
| */ | ||
| #ifndef GORM_CFG_LL_WIN_WIDENING | ||
| #define GORM_CFG_LL_WIN_WIDENING (50U) | ||
| #endif | ||
|
|
||
| /* ADVANCED */ | ||
| /** | ||
| * @brief Time to listen for incoming data while in a connection | ||
| * | ||
| * Default time is 300us (2 times T_IFS) | ||
| */ | ||
| #ifndef GORM_CFG_LL_RX_TIMEOUT | ||
| #define GORM_CFG_LL_RX_TIMEOUT (300U + GORM_CFG_LL_RX_RAMPUP_DELAY) | ||
| #endif | ||
|
|
||
|
|
||
| /* TODO: nRF52 specific timing, move to CPU/radio specific config section */ | ||
| #ifndef GORM_CFG_LL_RX_RAMPUP_DELAY | ||
| #define GORM_CFG_LL_RX_RAMPUP_DELAY (165U) | ||
| #endif | ||
|
|
||
|
|
||
| #ifndef GORM_CFG_VENDOR_ID | ||
| #define GORM_CFG_VENDOR_ID (0xffff) | ||
| #endif | ||
|
|
||
| #ifndef GORM_CFG_SUB_VERS_NR | ||
| #define GORM_CFG_SUB_VERS_NR (0xabcd) | ||
| #endif | ||
|
|
||
| #ifndef GORM_CFG_POOLSIZE | ||
| #define GORM_CFG_POOLSIZE (10U) | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Thread priority assigned to the Gorm thread in standalone mode | ||
| * | ||
| * @todo Move to RIOT specific configuration! | ||
| */ | ||
| #ifndef GORM_CFG_THREAD_STACKSIZE_HOST | ||
| #define GORM_CFG_THREAD_STACKSIZE_HOST (THREAD_STACKSIZE_DEFAULT) | ||
| #endif | ||
| #ifndef GORM_CFG_THREAD_PRIO_HOST | ||
| #define GORM_CFG_THREAD_PRIO_HOST (THREAD_PRIORITY_MAIN - 1) | ||
| #endif | ||
| #ifndef GORM_CFG_THREAD_NAME_HOST | ||
| #define GORM_CFG_THREAD_NAME_HOST "gorm_host" | ||
| #endif | ||
|
|
||
| #ifndef GORM_CFG_THREAD_STACKSIZE_CONTROLLER | ||
| #define GORM_CFG_THREAD_STACKSIZE_CONTROLLER (THREAD_STACKSIZE_DEFAULT) | ||
| #endif | ||
| #ifndef GORM_CFG_THREAD_PRIO_CONTROLLER | ||
| #define GORM_CFG_THREAD_PRIO_CONTROLLER (0) | ||
| #endif | ||
| #ifndef GORM_CFG_THREAD_NAME_CONTROLLER | ||
| #define GORM_CFG_THREAD_NAME_CONTROLLER "gorm_ctrl" | ||
| #endif | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_CONFIG_H */ |
| @@ -0,0 +1,156 @@ | ||
| /* | ||
| * Copyright (C) 2017 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_gorm_gap GAP for Gorm | ||
| * @ingroup net_gorm | ||
| * @brief Gorm's GAP implementation | ||
| * | ||
| * # Design Decisions and Limitations | ||
| * - no support for sending additional information in a SCAN_RESP packet | ||
| * | ||
| * # Implementation State | ||
| * | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's GAP mapping | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_GAP_H | ||
| #define GORM_GAP_H | ||
|
|
||
| #include <stddef.h> | ||
| #include <stdint.h> | ||
|
|
||
| #include "net/ble.h" | ||
| #include "net/gorm/ll.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Maximum AD data length allowed [in bytes] | ||
| */ | ||
| #define GORM_GAP_AD_MAXLEN (31U) | ||
|
|
||
| /* TODO: move to ble.h */ | ||
| /** | ||
| * @name GAP advertisement data type values | ||
| * | ||
| * @see https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile | ||
| * | ||
| * @{ | ||
| */ | ||
| #define GORM_GAP_FLAGS (0x01) | ||
| #define GORM_GAP_UUID16_INCOMP (0x02) | ||
| #define GORM_GAP_UUID16_COMP (0x03) | ||
| #define GORM_GAP_UUID32_INCOMP (0x04) | ||
| #define GORM_GAP_UUID32_COMP (0x05) | ||
| #define GORM_GAP_UUID128_INCOMP (0x06) | ||
| #define GORM_GAP_UUID128_COMP (0x07) | ||
| #define GORM_GAP_NAME_SHORT (0x08) | ||
| #define GORM_GAP_NAME (0x09) | ||
| // #define GORM_GAP Tx Power Level (0x0A) | ||
| // #define GORM_GAP Class of Device (0x0D) | ||
| // #define GORM_GAP Simple Pairing Hash C (0x0E) | ||
| // #define GORM_GAP Simple Pairing Hash C-192 (0x0E) | ||
| // #define GORM_GAP Simple Pairing Randomizer R (0x0F) | ||
| // #define GORM_GAP Simple Pairing Randomizer R-192 (0x0F) | ||
| // #define GORM_GAP Device ID (0x10) | ||
| // #define GORM_GAP Security Manager TK Value (0x10) | ||
| // #define GORM_GAP Security Manager Out of Band Flags (0x11) | ||
| // #define GORM_GAP Slave Connection Interval Range (0x12) | ||
| // #define GORM_GAP List of 16-bit Service Solicitation UUIDs (0x14) | ||
| // #define GORM_GAP List of 128-bit Service Solicitation UUIDs (0x15) | ||
| #define GORM_GAP_SERVICE_DATA (0x16) | ||
| #define GORM_GAP_SERVICE_DATA_UUID16 (0x16) | ||
| #define GORM_GAP_ADDR_PUBLIC (0x17) | ||
| #define GORM_GAP_ADDR_RANDOM (0x18) | ||
| #define GORM_GAP_APPEARANCE (0x19) | ||
| // #define GORM_GAP Advertising Interval (0x1A) | ||
| // #define GORM_GAP LE Bluetooth Device Address (0x1B) | ||
| // #define GORM_GAP LE Role (0x1C) | ||
| // #define GORM_GAP Simple Pairing Hash C-256 (0x1D) | ||
| // #define GORM_GAP Simple Pairing Randomizer R-256 (0x1E) | ||
| // #define GORM_GAP List of 32-bit Service Solicitation UUIDs (0x1F) | ||
| // #define GORM_GAP Service Data - 32-bit UUID (0x20) | ||
| // #define GORM_GAP Service Data - 128-bit UUID (0x21) | ||
| // #define GORM_GAP LE Secure Connections Confirmation Value (0x22) | ||
| // #define GORM_GAP LE Secure Connections Random Value (0x23) | ||
| // #define GORM_GAP URI (0x24) | ||
| // #define GORM_GAP Indoor Positioning (0x25) | ||
| // #define GORM_GAP Transport Discovery Data (0x26) | ||
| // #define GORM_GAP LE Supported Features (0x27) | ||
| // #define GORM_GAP Channel Map Update Indication (0x28) | ||
| // #define GORM_GAP 3D Information Data (0x3D) | ||
| #define GORM_GAP_VENDOR (0xFF) | ||
| /** @} */ | ||
|
|
||
| /* TODO: move to ble.h */ | ||
| /** | ||
| * @name Available flags in the GORM_GAP_FLAGS field | ||
| * @{ | ||
| */ | ||
| #define GORM_GAP_DISCOVER_LIM (0x01) | ||
| #define GORM_GAP_DISCOVERABLE (0x02) | ||
| #define GORM_GAP_FLAG_BREDR_NOTSUP (0x04) | ||
| /** @} */ | ||
|
|
||
|
|
||
| #define GORM_GAP_FLAGS_DEFAULT (GORM_GAP_DISCOVERABLE | \ | ||
| GORM_GAP_FLAG_BREDR_NOTSUP) | ||
|
|
||
|
|
||
| void gorm_gap_init(const char *name, uint16_t appearance); | ||
|
|
||
| size_t gorm_gap_copy_name(uint8_t *buf, size_t max_len); | ||
|
|
||
| void gorm_gap_copy_appearance(uint8_t *buf); | ||
|
|
||
|
|
||
| /** | ||
| * @brief Add advertising data field to the given buffer | ||
| * | ||
| * @param[out] buf [description] | ||
| * @param[in] pos | ||
| * @param[in] type [description] | ||
| * @param[in] data [description] | ||
| * @param[in] len [description] | ||
| * | ||
| * @return overall length of AD data in the buffer | ||
| */ | ||
| size_t gorm_gap_ad_add(uint8_t *buf, size_t pos, | ||
| uint8_t type, const void *data, size_t len); | ||
|
|
||
|
|
||
| /** | ||
| * @brief Convenience function for writing flags to given AD data | ||
| * | ||
| * @param[out] buf AD data buffer | ||
| * @param[in] flags flags to use, typically GORM_GAP_FLAGS_DEFAULT | ||
| * | ||
| * @return always returns 3 (as the flag field is 3 bytes long) | ||
| */ | ||
| static inline size_t gorm_gap_ad_add_flags(uint8_t *buf, size_t pos, | ||
| uint8_t flags) | ||
| { | ||
| return gorm_gap_ad_add(buf, pos, GORM_GAP_FLAGS, &flags, 1); | ||
| } | ||
|
|
||
| /* @todo add functions for reading AD data when running a scanner */ | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_LL_H */ | ||
| /** @} */ |
| @@ -0,0 +1,160 @@ | ||
| /* | ||
| * Copyright (C) 2017-2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_gorm_gatt | ||
| * @ingroup net_gorm | ||
| * @brief Gorm's GATT implementation | ||
| * | ||
| * | ||
| * # Implementation status | ||
| * | ||
| * ## Descriptors | ||
| * So far the implementation supports only descriptors of type | ||
| * - extended properties (0x2900) | ||
| * - presentation format (0x2904) | ||
| * - user description (0x2901) | ||
| * | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's GATT interface | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_GATT_H | ||
| #define GORM_GATT_H | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #include "net/ble.h" | ||
| #include "net/gorm/ll.h" | ||
| #include "net/gorm/att.h" | ||
| #include "net/gorm/uuid.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @name GATT MTU size | ||
| * | ||
| * TODO: make this non-static an negotiate this from the con object | ||
| */ | ||
| #define GORM_GATT_MAX_MTU (NETDEV_BLE_PDU_MAXLEN - 4) | ||
| #define GORM_GATT_DEFAULT_MTU (23U) | ||
|
|
||
| enum { | ||
| GORM_GATT_READ, | ||
| GORM_GATT_WRITE, | ||
| }; | ||
|
|
||
| enum { | ||
| GORM_GATT_OP_NOT_SUPPORTED = 0, | ||
| GORM_GATT_OP_OK = 1, | ||
| }; | ||
|
|
||
| typedef struct gorm_gatt_char gorm_gatt_char_t; | ||
| typedef struct gorm_gatt_desc gorm_gatt_desc_t; | ||
|
|
||
| typedef size_t (*gorm_gatt_char_cb_t)(const gorm_gatt_char_t *characteristic, | ||
| uint8_t method, | ||
| uint8_t *buf, size_t buf_len); | ||
|
|
||
| /* as of now, Gorm's descriptors are read-only */ | ||
| typedef size_t (*gorm_gatt_desc_cb_t)(const gorm_gatt_desc_t *descriptor, | ||
| uint8_t *buf, size_t buf_len); | ||
|
|
||
| struct gorm_gatt_desc { | ||
| gorm_gatt_desc_cb_t cb; | ||
| uint32_t arg; | ||
| uint16_t type; /**< 16-bit UUIDs only */ | ||
| }; | ||
|
|
||
| struct gorm_gatt_char { | ||
| gorm_gatt_char_cb_t cb; | ||
| void *arg; | ||
| gorm_uuid_t type; | ||
| uint8_t perm; | ||
| uint16_t desc_cnt; | ||
| const gorm_gatt_desc_t *desc; | ||
| }; | ||
|
|
||
| typedef struct { | ||
| gorm_uuid_t uuid; | ||
| /* TODO: how to handle includes? | ||
| * -> maybe simply: GORM does not support includes?! */ | ||
| uint16_t char_cnt; | ||
| const gorm_gatt_char_t *chars; | ||
| } gorm_gatt_service_t; | ||
|
|
||
| /** | ||
| * @brief Entry in the GATT table containing a service | ||
| */ | ||
| typedef struct gorm_gatt_entry { | ||
| struct gorm_gatt_entry *next; | ||
| const gorm_gatt_service_t *service; | ||
| uint16_t handle; | ||
| } gorm_gatt_entry_t; | ||
|
|
||
|
|
||
|
|
||
| void gorm_gatt_server_init(void); | ||
|
|
||
| void gorm_gatt_on_data(gorm_ll_connection_t *con, gorm_buf_t *buf, | ||
| uint8_t *data, size_t len); | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| gorm_gatt_entry_t *gorm_gatt_tab_find_service(uint16_t start_from); | ||
|
|
||
| /** | ||
| * @brief Get the service identified by the service part of the given handle | ||
| * | ||
| * @param[in] handle handle with valid service part | ||
| * | ||
| * @return the service entry for the given handle | ||
| * @return NULL if service could not be found | ||
| */ | ||
| gorm_gatt_entry_t *gorm_gatt_tab_get_service(uint16_t handle); | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| int gorm_gatt_tab_find_char(gorm_gatt_entry_t *entry, uint16_t start_handle); | ||
|
|
||
| gorm_gatt_desc_t *gorm_gatt_tab_get_desc(uint16_t handle); | ||
|
|
||
| uint16_t gorm_gatt_tab_get_end_handle(gorm_gatt_entry_t *entry); | ||
| uint16_t gorm_gatt_tab_get_char_handle(gorm_gatt_entry_t *entry, uint16_t num); | ||
| uint16_t gorm_gatt_tab_get_val_handle(gorm_gatt_entry_t *entry, uint16_t num); | ||
|
|
||
| /* TDOO: just for debugging -> remove or move ... */ | ||
| void gorm_gatt_tab_print(void); | ||
|
|
||
|
|
||
|
|
||
|
|
||
| /** | ||
| * GATT Table interface: | ||
| * | ||
| * - get base x: ignore lower bits and match only higher ones | ||
| * - get exact x: use all bits and check lower ones to be 0 | ||
| */ | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_GATT_H */ | ||
| /** @} */ |
| @@ -0,0 +1,76 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm_gatt | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief GATT characteristic description formats | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_GATT_DESC_H | ||
| #define GORM_GATT_DESC_H | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #include "net/gorm/gatt.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #define GORM_GATT_DESC_FMT(f, e, u) \ | ||
| { \ | ||
| .type = BLE_DESC_PRES_FMT, \ | ||
| .cb = gorm_gatt_desc_pres_fmt_cb, \ | ||
| .arg = (uint32_t)((f << 24) | (e << 16) | u), \ | ||
| } | ||
|
|
||
| #define GORM_GATT_DESC_EXT_PROP(rwe, wae) \ | ||
| { \ | ||
| .type = BLE_DESC_EXT_PROP, \ | ||
| .cb = gorm_gatt_desc_ext_prop_cb, \ | ||
| .arg = (uint32_t)((rwe & 0x1) | ((wae & 0x01) << 1)), \ | ||
| } | ||
|
|
||
| #define GORM_GATT_DESC_USER_DESC(str_ptr) \ | ||
| { \ | ||
| .type = BLE_DESC_USER_DESC, \ | ||
| .cb = gorm_gatt_desc_user_desc_cb, \ | ||
| .arg = (uint32_t)str_ptr, \ | ||
| } | ||
|
|
||
| #define GORM_GATT_DESC_CLIENT_CONF(noe, ine) \ | ||
| { \ | ||
| .type = BLE_DESC_CLIENT_CONFIG, \ | ||
| .cb = gorm_gatt_desc_client_conf_cb, \ | ||
| .arg = (uint32_t)((noe & 0x01) | ((ine & 0x01) << 1)), \ | ||
| } | ||
|
|
||
| size_t gorm_gatt_desc_pres_fmt_cb(const gorm_gatt_desc_t *desc, | ||
| uint8_t *buf, size_t buf_len); | ||
|
|
||
| size_t gorm_gatt_desc_ext_prop_cb(const gorm_gatt_desc_t *desc, | ||
| uint8_t *buf, size_t buf_len); | ||
|
|
||
| size_t gorm_gatt_desc_user_desc_cb(const gorm_gatt_desc_t *desc, | ||
| uint8_t *buf, size_t buf_len); | ||
|
|
||
| size_t gorm_gatt_desc_client_conf_cb(const gorm_gatt_desc_t *desc, | ||
| uint8_t *buf, size_t buf_len); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_GATT_DESC_H */ | ||
| /** @} */ | ||
|
|
| @@ -0,0 +1,90 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_gorm_gatt_tab Gorm's GATT Table | ||
| * @ingroup net_gorm_gatt | ||
| * @brief Gorm's GATT table implementation | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's GATT table interface | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_GATT_TAB_H | ||
| #define GORM_GATT_TAB_H | ||
|
|
||
| #include "net/gorm/gatt.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #define GORM_GATT_CHAR_VAL_MASK (0x0008) | ||
|
|
||
| /** | ||
| * @brief GATT table iterator | ||
| */ | ||
| typedef struct { | ||
| const gorm_gatt_entry_t *e; /**< base entry (points to a single service) */ | ||
| const gorm_gatt_char_t *c; /**< pointer to a characteristic */ | ||
| const gorm_gatt_desc_t *d; /**< pointer to a descriptor */ | ||
| uint16_t handle; /**< corresponding/current handle */ | ||
| } gorm_gatt_tab_iter_t; | ||
|
|
||
|
|
||
| /** | ||
| * @brief Initialize Gorm's GATT table | ||
| */ | ||
| void gorm_gatt_tab_init(void); | ||
|
|
||
|
|
||
| void gorm_gatt_tab_reg_service(gorm_gatt_entry_t *entry, | ||
| const gorm_gatt_service_t *service); | ||
|
|
||
| /** | ||
| * @brief Read the given handle | ||
| */ | ||
| /* good */ | ||
| void gorm_gatt_tab_get_by_handle(gorm_gatt_tab_iter_t *iter); | ||
|
|
||
| /* good */ | ||
| void gorm_gatt_tab_get_next(gorm_gatt_tab_iter_t *iter); | ||
|
|
||
|
|
||
| static inline int gorm_gatt_tab_is_service(const gorm_gatt_tab_iter_t *iter) | ||
| { | ||
| return ((iter->e != NULL) && (iter->c == NULL)); | ||
| } | ||
|
|
||
| static inline int gorm_gatt_tab_is_char_decl(const gorm_gatt_tab_iter_t *iter) | ||
| { | ||
| return ((iter->c != NULL) && (iter->d == NULL) && | ||
| !(iter->handle & GORM_GATT_CHAR_VAL_MASK)); | ||
| } | ||
|
|
||
| static inline int gorm_gatt_tab_is_char_val(const gorm_gatt_tab_iter_t *iter) | ||
| { | ||
| return ((iter->c != NULL) && (iter->d == NULL) && | ||
| (iter->handle & GORM_GATT_CHAR_VAL_MASK)); | ||
| } | ||
|
|
||
| static inline int gorm_gatt_tab_is_decl(const gorm_gatt_tab_iter_t *iter) | ||
| { | ||
| return (iter->d != NULL); | ||
| } | ||
|
|
||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_GATT_TAB_H */ | ||
| /** @} */ |
| @@ -0,0 +1,38 @@ | ||
| /* | ||
| * Copyright (C) 2017 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup net_gorm_ibeacon Gorm's iBeacon interface | ||
| * @ingroup net_gorm | ||
| * @brief Gorm's dedicated iBeacon handling submodule | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's iBeacon specific interface | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_IBEACON_H | ||
| #define GORM_IBEACON_H | ||
|
|
||
| #include "net/gorm.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| void gorm_ibeacon_setup(gorm_uuid_t *uuid, uint16_t major, uint16_t minor, | ||
| uint8_t txpower, uint32_t adv_interval); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_IBEACON_H */ | ||
| /** @} */ |
| @@ -0,0 +1,59 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's L2CAP layer interface | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_L2CAP_H | ||
| #define GORM_L2CAP_H | ||
|
|
||
| #include "net/gorm/ll.h" | ||
| #include "net/gorm/pduq.h" | ||
| #include "net/gorm/util.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @name Channel identifiers used by L2CAP for LE-U link layers | ||
| * @{ | ||
| */ | ||
| #define GORM_L2CAP_CID_ATT (0x0004) | ||
| #define GORM_L2CAP_CID_LE_SIGNAL (0x0005) | ||
| #define GORM_L2CAP_CID_SM (0x0006) | ||
| #define GORM_L2CAP_CID_CB_MIN (0x0040) | ||
| #define GORM_L2CAP_CID_CB_MAX (0x007f) | ||
| /** @} */ | ||
|
|
||
| #define GORM_L2CAP_HDR_LEN (4U) | ||
|
|
||
| /* higher layer interface functions */ | ||
| int gorm_l2cap_send(gorm_ll_connection_t *con, void *data, size_t len); | ||
|
|
||
|
|
||
|
|
||
| void gorm_l2cap_reply(gorm_ll_connection_t *con, | ||
| gorm_buf_t *buf, uint16_t data_len); | ||
|
|
||
| void gorm_l2cap_on_data(gorm_ll_connection_t *con, uint8_t llid, | ||
| gorm_buf_t *data); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_L2CAP_H */ | ||
| /** @} */ |
| @@ -0,0 +1,231 @@ | ||
| /* | ||
| * Copyright (C) 2017,2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's BLE link layer | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * | ||
| * @todo Split this header for periph/bcaster/host/... | ||
| */ | ||
|
|
||
| #ifndef GORM_LL_H | ||
| #define GORM_LL_H | ||
|
|
||
| #include "mutex.h" | ||
| #include "assert.h" | ||
| #include "event/timeout.h" | ||
| #include "event/callback.h" | ||
|
|
||
| #include "net/netdev/ble.h" | ||
| #include "net/gorm.h" | ||
| #include "net/gorm/pduq.h" | ||
| #include "net/gorm/arch/timer.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @name Constant value of advertising CRC and access address | ||
| * @{ | ||
| */ | ||
| #define GORM_LL_ADV_AA (0x8e89bed6) | ||
| #define GORM_LL_ADV_CRC (0x00555555) | ||
| /** @} */ | ||
|
|
||
| /* TODO: moved to ble.h */ | ||
| /** | ||
| * @name BLE advertising data packet types | ||
| * @{ | ||
| */ | ||
| #define GORM_LL_PDU_MASK (0x0f) | ||
| #define GORM_LL_ADV_IND (0x00) | ||
| #define GORM_LL_DIRECT_IND (0x01) | ||
| #define GORM_LL_ADV_NONCON_IND (0x02) | ||
| #define GORM_LL_SCAN_REQ (0x03) | ||
| #define GORM_LL_AUX_SCAN_REQ (0x03) | ||
| #define GORM_LL_SCAN_RESP (0x04) | ||
| #define GORM_LL_CONNECT_IND (0x05) | ||
| #define GORM_LL_AUX_CONNECT_REQ (0x05) | ||
| #define GORM_LL_ADV_SCAN_IND (0x06) | ||
| #define GORM_LL_ADV_EXT_IND (0x07) | ||
| #define GORM_LL_AUX_ADV_IND (0x07) | ||
| #define GORM_LL_AUX_SCAN_RSP (0x07) | ||
| #define GORM_LL_AUX_SYNC_IND (0x07) | ||
| #define GORM_LL_AUX_CHAIN_IND (0x07) | ||
| #define GORM_LL_CONNECT_RESP (0x08) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Advertising data PDU flags | ||
| */ | ||
| #define GORM_LL_FLAG_CHSEL (0x20) | ||
| #define GORM_LL_FLAG_TXADD (0x40) | ||
| #define GORM_LL_FLAG_RXADD (0x80) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Link layer data PDU flags | ||
| * @{ | ||
| */ | ||
| #define GORM_LL_LLID_MASK (0x03) | ||
| #define GORM_LL_LLID_DATA_CONT (0x01) /**< continued or empty packet */ | ||
| #define GORM_LL_LLID_DATA_START (0x02) | ||
| #define GORM_LL_LLID_CTRL (0x03) | ||
| #define GORM_LL_NESN (0x04) /**< next expected sequence number */ | ||
| #define GORM_LL_SN (0x08) /**< sequence number */ | ||
| #define GORM_LL_MD (0x10) /**< more data */ | ||
| #define GORM_LL_SEQ_MASK (0x0c) /**< mask SN and NESN */ | ||
| #define GORM_LL_FLOW_MASK (0x1c) /**< mask SN, NESN, and MD */ | ||
| /** @} */ | ||
|
|
||
|
|
||
| /* TODO: re-order fields to optimize memory usage... */ | ||
| typedef struct gorm_ll_connection_struct { | ||
| /* connection state: holds ll state, flow control, and anchor state */ | ||
| uint8_t state; | ||
|
|
||
| /* context data when in connection state */ | ||
| uint16_t event_counter; | ||
| netdev_ble_ctx_t ctx; | ||
|
|
||
| /* channel configuration */ | ||
| uint8_t chan_hop; /**< hop increment value */ | ||
| uint8_t chan_map[5]; /**< active channel map */ | ||
| uint8_t chan_cnt; /**< number of active channels */ | ||
| uint8_t chan_unmapped; /**< next unmapped channel */ | ||
| /* TODO: add channel selection algorithm as function pointer? */ /**< remapped next channel */ | ||
|
|
||
| /* used timers */ | ||
| gorm_arch_timer_t timer_spv; | ||
| gorm_arch_timer_t timer_con; | ||
|
|
||
| /* timing parameters */ | ||
| uint32_t timeout_spv; /**< supervision timeout */ | ||
| uint32_t timeout_rx; /**< receive timeout */ | ||
| uint32_t interval; /**< connection event interval */ | ||
| uint16_t slave_latency; /**< count number of connection events, reset on new connection */ | ||
| // uint32_t adv_interval; /**< -> we use a static define for this (for now) */ | ||
|
|
||
| /* buffered timing parameter update values */ | ||
| struct { | ||
| uint16_t instant; /**< apply the update when event_counter hits this value */ | ||
| uint8_t raw[9]; | ||
| } timings_update; | ||
|
|
||
| /* buffered channel map update values */ | ||
| struct { | ||
| uint16_t instant; | ||
| uint8_t map[5]; | ||
| uint8_t cnt; | ||
| } chan_update; | ||
|
|
||
| /* shadow fields for updating channel config and timings */ | ||
| /* TODO */ | ||
|
|
||
| /* pkt queues for passing data to and receiving data from l2cap layer */ | ||
| gorm_pduq_t rxq; | ||
| gorm_pduq_t txq; | ||
| gorm_buf_t *in_tx; | ||
| gorm_buf_t *in_rx; | ||
|
|
||
| /* TODO: additional information needed for triggering events on higher layer? */ | ||
|
|
||
| /* GATT specific values */ | ||
| /* TODO: split these into separate struct(s) and join structs on higher layer */ | ||
| // uint16_t gatt_max_mtu; | ||
| } gorm_ll_connection_t; | ||
|
|
||
| typedef struct { | ||
| gorm_arch_timer_t timer; | ||
| uint32_t interval; | ||
| netdev_ble_pkt_t *pkt; | ||
| } gorm_ll_adv_nonconn_t; | ||
|
|
||
| extern event_queue_t gorm_ll_runqueue; | ||
| extern event_queue_t gorm_ll_waitqueue; | ||
|
|
||
| /* TODO: only include in peripheral, scanner, and central roles */ | ||
| extern event_callback_t gorm_ll_rx_action; | ||
|
|
||
|
|
||
| void gorm_ll_run(netdev_t *dev); | ||
|
|
||
| uint8_t *gorm_ll_addr_rand(void); | ||
|
|
||
|
|
||
| /* TODO: only include in peripheral, scanner, and central roles */ | ||
| static inline int gorm_ll_busy(void) | ||
| { | ||
| return (gorm_ll_rx_action.callback != NULL); | ||
| } | ||
|
|
||
|
|
||
| static inline int gorm_ll_get_type(netdev_ble_pkt_t *pkt) | ||
| { | ||
| return (int)(pkt->flags & GORM_LL_PDU_MASK); | ||
| } | ||
|
|
||
|
|
||
| /* TODO: merge broadcaster code with `ll_perihp`, use gorm_ll_connection_t for | ||
| * this also. */ | ||
| #if 0 | ||
| #ifdef MODULE_GORM_BROADCASTER | ||
| void gorm_ll_adv_nonconn_setup(gorm_ll_adv_nonconn_t *adv, | ||
| netdev_ble_pkt_t *pkt, uint32_t interval); | ||
|
|
||
| static inline void gorm_ll_adv_nonconn_start(gorm_ll_adv_nonconn_t *adv) | ||
| { | ||
| assert(adv); | ||
| gorm_arch_evtim_set_from_now(&adv->timer, adv->interval); | ||
| } | ||
|
|
||
| static inline void gorm_ll_adv_nonconn_stop(gorm_ll_adv_nonconn_t *adv) | ||
| { | ||
| assert(adv); | ||
| gorm_arch_evtim_cancel(&adv->timer); | ||
| } | ||
| #endif | ||
| #endif | ||
|
|
||
|
|
||
| #ifdef MODULE_GORM_PERIPHERAL | ||
| void gorm_ll_periph_init(void); | ||
| void gorm_ll_periph_adv_start(void); | ||
| void gorm_ll_periph_adv_setup(void *ad_adv, size_t adv_len, | ||
| void *ad_scan, size_t scan_len); | ||
|
|
||
| /** | ||
| * @brief Close the given connection, independent of its state | ||
| * | ||
| * If the connection is currently in advertising or connected state, it will | ||
| * be put into STANDBY state. If the connection is already STANDBY, nothing | ||
| * will happen. | ||
| * | ||
| * @param[in,out] con connection to close | ||
| */ | ||
| void gorm_ll_periph_terminate(gorm_ll_connection_t *con); | ||
|
|
||
| /* TODO: find a better way to pass connections form LL to l2cap, probably turn | ||
| * the buffer handling around, so that the upper layer passes connection | ||
| * structs to the LL?! */ | ||
| gorm_ll_connection_t *gorm_ll_periph_getcon(void); | ||
| #endif | ||
|
|
||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_LL_H */ | ||
| /** @} */ |
| @@ -0,0 +1,45 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's channel selection algorithms | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #include "net/gorm/ll.h" | ||
|
|
||
| /** | ||
| * @brief Count the allowed channels in the given channel map | ||
| * | ||
| * @param[in] map map masking the allowed channels | ||
| * | ||
| * @return number of allowed channels | ||
| */ | ||
| uint8_t gorm_ll_chan_count(const uint8_t *map); | ||
|
|
||
| /** | ||
| * @brief Compute the next used channel using channel selection algorithm #1 | ||
| * | ||
| * @param[in,out] con connection context | ||
| */ | ||
| void gorm_ll_chan_algo1(gorm_ll_connection_t *con); | ||
|
|
||
| /** | ||
| * @brief Compute the next used channel using channel selection algorithm #2 | ||
| * | ||
| * @param[in,out] con connection context | ||
| */ | ||
| /* TODO: implement */ | ||
| //void gorm_ll_chan_algo2(gorm_ll_connection_t *con); |
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @brief | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's interface for handling link layer control messages | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_LL_CTRL_H | ||
| #define GORM_LL_CTRL_H | ||
|
|
||
| #include "net/gorm/ll.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Build a response to a FEATURE_REQ packet | ||
| * | ||
| * @param[out] pkt response is written to this packet | ||
| */ | ||
| void gorm_ll_ctrl_feature_resp(gorm_buf_t *buf); | ||
|
|
||
| void gorm_ll_ctrl_version(gorm_buf_t *buf); | ||
|
|
||
| void gorm_ll_ctrl_1b(gorm_buf_t *buf, uint8_t opcode, uint8_t data); | ||
|
|
||
|
|
||
| void gorm_ll_ctrl_on_data(gorm_ll_connection_t *con, gorm_buf_t *buf); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_LL_CTRL_H */ | ||
| /** @} */ |
| @@ -0,0 +1,38 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @brief | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's link layer part that runs in the host thread | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_LL_HOST_H | ||
| #define GORM_LL_HOST_H | ||
|
|
||
| #include "net/gorm/ll.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| void gorm_ll_host_run(void); | ||
|
|
||
| void gorm_ll_host_notify(gorm_ll_connection_t *con); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_LL_HOST_H */ | ||
| /** @} */ |
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| #include "net/gorm.h" | ||
| #include "net/netdev/ble.h" | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's radio wrapper | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| typedef int(*gorm_ll_trx_cb_t)(gorm_buf_t *buf, void *arg); | ||
|
|
||
| /** | ||
| * @brief Initialize Gorm's radio wrapper | ||
| * | ||
| * @param[in] dev network device to use | ||
| * | ||
| * @return GORM_OK on success | ||
| * @return GORM_ERR_RADIO on failed radio initialization | ||
| */ | ||
| int gorm_ll_trx_init(netdev_t *dev); | ||
|
|
||
| /** | ||
| * @brief Cancel any ongoing operation and put the radio into idle mode | ||
| */ | ||
| void gorm_ll_trx_stop(void); | ||
|
|
||
|
|
||
| void gorm_ll_trx_send(gorm_buf_t *buf, netdev_ble_ctx_t *ctx, | ||
| gorm_ll_trx_cb_t cb, void *arg); | ||
|
|
||
| void gorm_ll_trx_recv(gorm_buf_t *buf, netdev_ble_ctx_t *ctx, | ||
| gorm_ll_trx_cb_t cb, void *arg); | ||
|
|
||
| void gorm_ll_trx_send_next(gorm_buf_t *buf, gorm_ll_trx_cb_t cb); | ||
|
|
||
| void gorm_ll_trx_recv_next(gorm_buf_t *buf, gorm_ll_trx_cb_t cb); |
| @@ -0,0 +1,57 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's PDU (packet) pool | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_PDUPOOL_H | ||
| #define GORM_PDUPOOL_H | ||
|
|
||
| #include "net/gorm.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
|
|
||
| /** | ||
| * @brief Initialize the PDU pool | ||
| * | ||
| * @param mem [description] | ||
| * @param len [description] | ||
| */ | ||
| void gorm_pdupool_addmem(void *mem, size_t len); | ||
|
|
||
| /** | ||
| * @brief Get a number of packets from the pool | ||
| * | ||
| * @param[in] num | ||
| * @return [description] | ||
| */ | ||
| gorm_buf_t *gorm_pdupool_get(unsigned num); | ||
|
|
||
| /** | ||
| * @brief Free the given packet by putting it back into the pool | ||
| * | ||
| * @param[in,out] pdu packet to return to pool | ||
| */ | ||
| void gorm_pdupool_return(gorm_buf_t *buf); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_PDUPOOL_H */ | ||
| /** @} */ |
| @@ -0,0 +1,49 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's PDU (packet) pool | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_PDUQ_H | ||
| #define GORM_PDUQ_H | ||
|
|
||
| #include "net/gorm.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #define GORM_PDUQ_INIT { NULL, NULL } | ||
|
|
||
| typedef struct gorm_pduq { | ||
| gorm_buf_t *head; | ||
| gorm_buf_t *tail; | ||
| } gorm_pduq_t; | ||
|
|
||
| void gorm_pduq_enq(gorm_pduq_t *queue, gorm_buf_t *pkt); | ||
|
|
||
| gorm_buf_t *gorm_pduq_deq(gorm_pduq_t *queue); | ||
|
|
||
| static inline gorm_buf_t *gorm_pduq_peek(gorm_pduq_t *queue) | ||
| { | ||
| return queue->head; | ||
| } | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_PDUQ_H */ | ||
| /** @} */ |
| @@ -0,0 +1,73 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's little helpers | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_UTIL_H | ||
| #define GORM_UTIL_H | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| static inline uint16_t gorm_util_letohs(uint8_t *buf) | ||
| { | ||
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||
| return (uint16_t)((buf[1] << 8) | buf[0]); | ||
| #else | ||
| return (uint16_t)((buf[0] << 8) | buf[1]); | ||
| #endif | ||
| } | ||
|
|
||
| static inline uint16_t gorm_util_betohs(uint8_t *buf) | ||
| { | ||
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||
| return (uint16_t)((buf[0] << 8) | buf[1]); | ||
| #else | ||
| return (uint16_t)((buf[1] << 8) | buf[0]); | ||
| #endif | ||
| } | ||
|
|
||
| static inline void gorm_util_htoles(uint8_t *buf, uint16_t val) | ||
| { | ||
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||
| buf[0] = (uint8_t)(val & 0xff); | ||
| buf[1] = (uint8_t)(val >> 8); | ||
| #else | ||
| buf[0] = (uint8_t)(val >> 8); | ||
| buf[1] = (uint8_t)(val & 0xff); | ||
| #endif | ||
| } | ||
|
|
||
| static inline void gorm_util_htobes(uint8_t *buf, uint16_t val) | ||
| { | ||
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||
| buf[0] = (uint8_t)(val >> 8); | ||
| buf[1] = (uint8_t)(val & 0xff); | ||
| #else | ||
| buf[0] = (uint8_t)(val & 0xff); | ||
| buf[1] = (uint8_t)(val >> 8); | ||
| #endif | ||
| } | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* GORM_LL_H */ | ||
| /** @} */ |
| @@ -0,0 +1,95 @@ | ||
| /* | ||
| * Copyright (C) 2018 Freie Universität Berlin | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup net_gorm | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Gorm's UUID handling | ||
| * | ||
| * Implementation restrictions: | ||
| * - only support for 128-bit and 16-bit UUIDs (is that true?) | ||
| * - handle allocation: | ||
| * - 0b0xxxxxxxNNNNNNNN -> 16-bit UUIDed services | ||
| * - 0b1xxxxxxxNNNNNNNN -> 128-bit UUIDed services | ||
| * - 0bxxxxxxxxCCCC0000 -> 4 MSB of lower byte: characteristics | ||
| * - 0bxxxxxxxxCCCCDDDD -> 4 LSB of lower byte: char descriptions | ||
| * | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| */ | ||
|
|
||
| #ifndef GORM_UUID_H | ||
| #define GORM_UUID_H | ||
|
|
||
| #include <stdint.h> | ||
| #include <stddef.h> | ||
|
|
||
| #define GORM_UUID(u16, b) { .uuid16 = u16, .base = b } | ||
|
|
||
| /* TODO: move to ble.h */ | ||
| #define GORM_UUID_GAP (0x1800) | ||
| #define GORM_UUID_ATT (0x1801) | ||
|
|
||
| /* TODO: move to ble.h */ | ||
| #define GORM_UUID_DEVICE_NAME (0x2a00) | ||
| #define GORM_UUID_APPEARANCE (0x2a01) | ||
| #define GORM_UUID_PREF_CON_PARAM (0x2a04) | ||
|
|
||
| typedef union { | ||
| uint8_t raw[16]; | ||
| uint16_t u16[8]; | ||
| uint32_t u32[4]; | ||
| } gorm_uuid_base_t; | ||
|
|
||
| typedef struct { | ||
| const gorm_uuid_base_t *base; /**< base UUID, NULL refers to Bluetooth UUID */ | ||
| uint16_t uuid16; | ||
| } gorm_uuid_t; | ||
|
|
||
|
|
||
| void gorm_uuid_from_buf(gorm_uuid_t *uuid, uint8_t *buf, size_t len); | ||
| size_t gorm_uuid_to_buf(uint8_t *buf, const gorm_uuid_t *uuid); | ||
|
|
||
| /** | ||
| * @brief Compare two given UUIDs | ||
| * | ||
| * @param[in] a first UUID to compare | ||
| * @param[in] b second UUID to compare | ||
| * | ||
| * @return 0 if UUIDs are different | ||
| * @return != 0 if UUIDs are equal | ||
| */ | ||
| int gorm_uuid_cmp(const gorm_uuid_t *a, const gorm_uuid_t *b); | ||
|
|
||
|
|
||
| static inline int gorm_uuid_sig(const gorm_uuid_t *uuid) | ||
| { | ||
| return (uuid->base == NULL); | ||
| } | ||
|
|
||
| static inline int gorm_uuid_eq16(const gorm_uuid_t *uuid, uint16_t uuid16) | ||
| { | ||
| return (gorm_uuid_sig(uuid) && (uuid->uuid16 == uuid16)); | ||
| } | ||
|
|
||
| static inline size_t gorm_uuid_len(const gorm_uuid_t *uuid) | ||
| { | ||
| return (gorm_uuid_sig(uuid)) ? 2 : 16; | ||
| } | ||
|
|
||
| static inline void gorm_uuid_init(gorm_uuid_t *uuid, gorm_uuid_base_t *base, | ||
| uint16_t uuid16) { | ||
| uuid->base = base; | ||
| uuid->uuid16 = uuid16; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| #endif /* GORM_UUID_H */ |
| @@ -0,0 +1,27 @@ | ||
| MODULE = gorm | ||
|
|
||
| SRC = ll.c ll_trx.c util.c gorm.c | ||
|
|
||
| ifneq (,$(filter gorm_peripheral,$(USEMODULE))) | ||
| SRC += ll_periph.c ll_chan.c ll_ctrl.c ll_host.c l2cap.c pdupool.c pduq.c | ||
| endif | ||
|
|
||
| ifneq (,$(filter gorm_gatt,$(USEMODULE))) | ||
| SRC += uuid.c | ||
| DIRS += $(RIOTBASE)/sys/net/gorm/gatt | ||
| endif | ||
|
|
||
| ifneq (,$(filter gorm_gap,$(USEMODULE))) | ||
| DIRS += $(RIOTBASE)/sys/net/gorm/gap | ||
| endif | ||
|
|
||
| ifneq (,$(filter gorm_arch_riot,$(USEMODULE))) | ||
| DIRS += $(RIOTBASE)/sys/net/gorm/arch/riot | ||
| endif | ||
|
|
||
| # include select build-in services | ||
| ifneq (,$(filter gorm_service_%,$(USEMODULE))) | ||
| DIRS += $(RIOTBASE)/sys/net/gorm/service | ||
| endif | ||
|
|
||
| include $(RIOTBASE)/Makefile.base |
| @@ -0,0 +1,2 @@ | ||
| MODULE = gorm_arch_riot | ||
| include $(RIOTBASE)/Makefile.base |