1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/pkg/nimble/netif/nimble_netif_conn.c
2021-09-24 17:28:09 +02:00

276 lines
6.7 KiB
C

/*
* Copyright (C) 2018-2019 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 pkg_nimble_netif_conn
* @{
*
* @file
* @brief Connection context handling for NimBLE netif
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <assert.h>
#include "nimble_netif_conn.h"
#include "random.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define CONN_CNT (NIMBLE_NETIF_MAX_CONN)
static mutex_t _lock = MUTEX_INIT;
static nimble_netif_conn_t _conn[CONN_CNT];
static int _find_by_state(uint16_t filter)
{
for (unsigned i = 0; i < CONN_CNT; i++) {
if (_conn[i].state & filter) {
return (int)i;
}
}
return NIMBLE_NETIF_CONN_INVALID;
}
void nimble_netif_conn_init(void)
{
DEBUG("conn_init\n");
memset(_conn, 0, sizeof(_conn));
for (unsigned i = 0; i < CONN_CNT; i++) {
_conn[i].state = NIMBLE_NETIF_UNUSED;
}
}
nimble_netif_conn_t *nimble_netif_conn_get(int handle)
{
if ((handle < 0) || (handle >= CONN_CNT)) {
return NULL;
}
return &_conn[handle];
}
int nimble_netif_conn_get_adv(void)
{
int handle;
DEBUG("nimble_netif_conn_get_adv\n");
mutex_lock(&_lock);
handle = _find_by_state(NIMBLE_NETIF_ADV);
mutex_unlock(&_lock);
return handle;
}
int nimble_netif_conn_get_connecting(void)
{
int handle;
DEBUG("nimble_netif_conn_get_connecting\n");
mutex_lock(&_lock);
handle = _find_by_state(NIMBLE_NETIF_CONNECTING);
mutex_unlock(&_lock);
DEBUG("nimble_netif_conn_get_connecting - handle %i\n", handle);
return handle;
}
int nimble_netif_conn_get_by_addr(const uint8_t *addr)
{
assert(addr);
int handle = NIMBLE_NETIF_CONN_INVALID;
DEBUG("nimble_netif_conn_get_by_addr %02x\n", (int)addr[0]);
mutex_lock(&_lock);
for (unsigned i = 0; i < CONN_CNT; i++) {
if ((_conn[i].state & NIMBLE_NETIF_L2CAP_CONNECTED) &&
memcmp(_conn[i].addr, addr, BLE_ADDR_LEN) == 0) {
handle = (int)i;
break;
}
}
mutex_unlock(&_lock);
DEBUG("nimble_netif_conn_get_by_addr - found handle: %i\n", handle);
return handle;
}
int nimble_netif_conn_get_by_gaphandle(uint16_t gaphandle)
{
int handle = NIMBLE_NETIF_CONN_INVALID;
DEBUG("nimble_netif_conn_get_by_gaphandle %i\n", (int)gaphandle);
mutex_lock(&_lock);
for (unsigned i = 0; i < CONN_CNT; i++) {
if (_conn[i].gaphandle == gaphandle) {
handle = (int)i;
break;
}
}
mutex_unlock(&_lock);
DEBUG("nimble_netif_conn_get_by_gaphandle - found %i\n", handle);
return handle;
}
int nimble_netif_conn_start_connection(const uint8_t *addr)
{
int handle;
DEBUG("nimble_netif_conn_start_connection, addr %02x\n", (int)addr[0]);
mutex_lock(&_lock);
handle = _find_by_state(NIMBLE_NETIF_UNUSED);
if (handle != NIMBLE_NETIF_CONN_INVALID) {
_conn[handle].state = NIMBLE_NETIF_CONNECTING;
memcpy(_conn[handle].addr, addr, BLE_ADDR_LEN);
}
mutex_unlock(&_lock);
return handle;
}
int nimble_netif_conn_start_adv(void)
{
int handle;
DEBUG("nimble_netif_conn_start_adv\n");
mutex_lock(&_lock);
handle = _find_by_state(NIMBLE_NETIF_ADV);
if (handle != NIMBLE_NETIF_CONN_INVALID) {
handle = -EALREADY;
}
else {
handle = _find_by_state(NIMBLE_NETIF_UNUSED);
if (handle != NIMBLE_NETIF_CONN_INVALID) {
_conn[handle].state = NIMBLE_NETIF_ADV;
}
else {
handle = -ENOMEM;
}
}
mutex_unlock(&_lock);
return handle;
}
void nimble_netif_conn_free(int handle, uint8_t *addr)
{
assert((handle >= 0) && (handle < CONN_CNT));
DEBUG("nimble_netif_conn_free, handle %i\n", handle);
mutex_lock(&_lock);
if (addr) {
memcpy(addr, _conn[handle].addr, BLE_ADDR_LEN);
}
memset(&_conn[handle], 0, sizeof(nimble_netif_conn_t));
_conn[handle].state = NIMBLE_NETIF_UNUSED;
mutex_unlock(&_lock);
}
void nimble_netif_conn_foreach(uint16_t filter,
nimble_netif_conn_iter_t cb, void *arg)
{
assert(cb);
DEBUG("nimble_netif_conn_foreach 0x%04x\n", (int)filter);
mutex_lock(&_lock);
for (unsigned i = 0; i < CONN_CNT; i++) {
if (_conn[i].state & filter) {
int res = cb(&_conn[i], (int)i, arg);
if (res != 0) {
break;
}
}
}
mutex_unlock(&_lock);
}
int nimble_netif_conn_get_next(int handle, uint16_t filter)
{
/* if handle is undefined, start from the beginning */
if (handle < 0) {
handle = -1;
}
for (int i = (handle + 1); i < (int)CONN_CNT; i++) {
if (_conn[i].state & filter) {
return i;
}
}
return NIMBLE_NETIF_CONN_INVALID;
}
unsigned nimble_netif_conn_count(uint16_t filter)
{
unsigned cnt = 0;
DEBUG("nimble_netif_conn_count, filter 0x%04x\n", (int)filter);
mutex_lock(&_lock);
for (unsigned i = 0; i < CONN_CNT; i++) {
if (_conn[i].state & filter) {
++cnt;
}
}
mutex_unlock(&_lock);
return cnt;
}
uint16_t nimble_netif_conn_get_itvl_ms(int handle)
{
if ((handle < 0) || (handle >= CONN_CNT)) {
return 0;
}
return ((_conn[handle].itvl * BLE_HCI_CONN_ITVL) / 1000);
}
bool nimble_netif_conn_itvl_used(uint16_t itvl, int skip_handle)
{
for (int handle = 0; handle < CONN_CNT; handle++) {
if ((handle != skip_handle) && (_conn[handle].itvl != 0)) {
uint16_t diff = (_conn[handle].itvl < itvl)
? itvl - _conn[handle].itvl
: _conn[handle].itvl - itvl;
if (diff < NIMBLE_NETIF_CONN_ITVL_SPACING) {
return true;
}
}
}
return false;
}
uint16_t nimble_netif_conn_gen_itvl(uint16_t min, uint16_t max)
{
assert(min <= max);
uint16_t start = random_uint32_range(min, max);
if (NIMBLE_NETIF_CONN_ITVL_SPACING == 0) {
return start;
}
for (uint16_t itvl = start;
itvl <= max;
itvl += NIMBLE_NETIF_CONN_ITVL_SPACING) {
if (!nimble_netif_conn_itvl_used(itvl, NIMBLE_NETIF_CONN_INVALID)) {
return itvl;
}
}
for (uint16_t itvl = start - NIMBLE_NETIF_CONN_ITVL_SPACING;
itvl >= min;
itvl -= NIMBLE_NETIF_CONN_ITVL_SPACING) {
if (!nimble_netif_conn_itvl_used(itvl, NIMBLE_NETIF_CONN_INVALID)) {
return itvl;
}
}
return 0;
}