commit
6259b81628
@ -0,0 +1,54 @@
|
||||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
|
||||
# Sample applications
|
||||
|
||||
## advertiser
|
||||
|
||||
This is the simplest example of advertising. Application sets NRPA, configures
|
||||
advertisement parameters: general discoverable and not connectable and fills
|
||||
advertisement fields. Transmited data contains only flags, tx power level and
|
||||
device name, which fits in 31B limit of single package. With this data set,
|
||||
device advertises for 10 seconds, terminates advertisement and repeats process
|
||||
again infinitely.
|
||||
|
||||
## scanner
|
||||
|
||||
This application shows how to perform simple scan. Device performs discovery
|
||||
procedure, during which receives advertising reports (if any devices are
|
||||
advertising nearby). These reports are being parsed and results are printed to
|
||||
serial port. Applicaton starts new discovery every second.
|
||||
|
||||
## peripheral
|
||||
|
||||
Peripheral application is based on advertiser, but has added capability of
|
||||
connecting with other devices. As peripheral, device doesn't initiate any
|
||||
connection by itself; instead, advertises infinitely and accepts any connection
|
||||
request it receives. Because we cannot use any 16 or 32 bit UUIDs, as these are
|
||||
reserved by Bluetooth SIG, we are forced to use 128-bit one. Including such
|
||||
long UUID in advertising data consumes large part of available payload, so this
|
||||
data is split in advertising data and response data.
|
||||
|
||||
## central
|
||||
|
||||
This application works in pair with peripheral. It's based on scanner
|
||||
application - the difference is, that if there was detected device with UUID
|
||||
fitting to the one predefined in central application, connection is initiated.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
pkg.name: "apps/central"
|
||||
pkg.type: app
|
||||
pkg.description: "Basic central application"
|
||||
pkg.author: "Krzysztof Kopyściński <krzysztof.kopyscinski@codecoup.pl>"
|
||||
|
||||
pkg.deps:
|
||||
- "@apache-mynewt-core/kernel/os"
|
||||
- "@apache-mynewt-core/sys/console/full"
|
||||
- "@apache-mynewt-core/sys/log/full"
|
||||
- "@apache-mynewt-core/sys/stats/full"
|
||||
- "@apache-mynewt-core/sys/log/modlog"
|
||||
- "@apache-mynewt-nimble/nimble/host"
|
||||
- "@apache-mynewt-nimble/nimble/host/util/"
|
||||
- "@apache-mynewt-nimble/nimble/host/store/config"
|
||||
- "@apache-mynewt-nimble/nimble/transport"
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "os/os.h"
|
||||
#include "console/console.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#include "log/log.h"
|
||||
|
||||
static uint8_t g_own_addr_type;
|
||||
|
||||
static void
|
||||
ble_app_set_addr(void)
|
||||
{
|
||||
ble_addr_t addr;
|
||||
int rc;
|
||||
|
||||
/* generate new non-resolvable private address */
|
||||
rc = ble_hs_id_gen_rnd(0, &addr);
|
||||
assert(rc == 0);
|
||||
|
||||
/* set generated address */
|
||||
rc = ble_hs_id_set_rnd(addr.val);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
/* scan_event() calls scan(), so forward declaration is required */
|
||||
static void scan(void);
|
||||
|
||||
/* connection has separate event handler from scan */
|
||||
static int
|
||||
conn_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
if (event->connect.status == 0) {
|
||||
MODLOG_DFLT(INFO,"Connection was established\n");
|
||||
ble_gap_terminate(event->connect.conn_handle, 0x13);
|
||||
} else {
|
||||
MODLOG_DFLT(INFO,"Connection failed, error code: %i\n",
|
||||
event->connect.status);
|
||||
}
|
||||
break;
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO,"Disconnected, reason code: %i\n",
|
||||
event->disconnect.reason);
|
||||
scan();
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE_REQ:
|
||||
MODLOG_DFLT(INFO,"Connection update request received\n");
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
if (event->conn_update.status == 0) {
|
||||
MODLOG_DFLT(INFO,"Connection update successful\n");
|
||||
} else {
|
||||
MODLOG_DFLT(INFO,"Connection update failed; reson: %d\n",
|
||||
event->conn_update.status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MODLOG_DFLT(INFO,"Connection event type not supported, %d\n",
|
||||
event->type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
scan_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
/* predef_uuid stores information about UUID of device,
|
||||
that we connect to */
|
||||
const ble_uuid128_t predef_uuid =
|
||||
BLE_UUID128_INIT(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff);
|
||||
struct ble_hs_adv_fields parsed_fields;
|
||||
int uuid_cmp_result;
|
||||
|
||||
memset(&parsed_fields, 0, sizeof(parsed_fields));
|
||||
|
||||
switch (event->type) {
|
||||
/* advertising report has been received during discovery procedure */
|
||||
case BLE_GAP_EVENT_DISC:
|
||||
MODLOG_DFLT(INFO, "Advertising report received! Checking UUID...\n");
|
||||
ble_hs_adv_parse_fields(&parsed_fields, event->disc.data,
|
||||
event->disc.length_data);
|
||||
/* Predefined UUID is compared to recieved one;
|
||||
if doesn't fit - end procedure and go back to scanning,
|
||||
else - connect. */
|
||||
uuid_cmp_result = ble_uuid_cmp(&predef_uuid.u, &parsed_fields.uuids128->u);
|
||||
if (uuid_cmp_result) {
|
||||
MODLOG_DFLT(INFO, "UUID doesn't fit\n");
|
||||
} else {
|
||||
MODLOG_DFLT(INFO, "UUID fits, connecting...\n");
|
||||
ble_gap_disc_cancel();
|
||||
ble_gap_connect(g_own_addr_type, &(event->disc.addr), 10000,
|
||||
NULL, conn_event, NULL);
|
||||
}
|
||||
break;
|
||||
case BLE_GAP_EVENT_DISC_COMPLETE:
|
||||
MODLOG_DFLT(INFO,"Discovery completed, reason: %d\n",
|
||||
event->disc_complete.reason);
|
||||
scan();
|
||||
break;
|
||||
default:
|
||||
MODLOG_DFLT(ERROR, "Discovery event not handled\n");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
scan(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* set scan parameters:
|
||||
- scan interval in 0.625ms units
|
||||
- scan window in 0.625ms units
|
||||
- filter policy - 0 if whitelisting not used
|
||||
- limited - should limited discovery be used
|
||||
- passive - should passive scan be used
|
||||
- filter duplicates - 1 enables filtering duplicated advertisements */
|
||||
const struct ble_gap_disc_params scan_params = {10000, 200, 0, 0, 0, 1};
|
||||
|
||||
/* performs discovery procedure */
|
||||
rc = ble_gap_disc(g_own_addr_type, 10000, &scan_params,scan_event, NULL);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
/* Generate a non-resolvable private address. */
|
||||
ble_app_set_addr();
|
||||
|
||||
/* g_own_addr_type will store type of addres our BSP uses */
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
rc = ble_hs_id_infer_auto(0, &g_own_addr_type);
|
||||
assert(rc == 0);
|
||||
/* begin scanning */
|
||||
scan();
|
||||
}
|
||||
|
||||
static void
|
||||
on_reset(int reason)
|
||||
{
|
||||
console_printf("Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
/* Initialize all packages. */
|
||||
sysinit();
|
||||
|
||||
ble_hs_cfg.sync_cb = on_sync;
|
||||
ble_hs_cfg.reset_cb = on_reset;
|
||||
|
||||
/* As the last thing, process events from default event queue. */
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
### Mesh Badge
|
||||
|
||||
|
||||
##### Overview
|
||||
********
|
||||
|
||||
This sample app for the reel board showcases Bluetooth Mesh
|
||||
|
||||
The app starts off as a regular Bluetooth GATT peripheral application.
|
||||
Install the the "nRF Connect" app on your phone (available both for
|
||||
Android and iOS) to access the service that the app exposes. The service
|
||||
can also be accessed with any Bluetooth LE GATT client from your PC,
|
||||
however these instructions focus on the necessary steps for phones.
|
||||
|
||||
##### Steps to set up
|
||||
***************
|
||||
|
||||
* On your phone, use the nRF Connect app to Scan for devices and look
|
||||
for "reel board"
|
||||
* Connect to the device. You'll see a single service - select it
|
||||
* Request to write to the characteristic by pressing on the upward pointing
|
||||
arrow symbol
|
||||
* Select "Text" to enter text instead of hex
|
||||
* Enter your name (or any other arbitrary text). Multiple words
|
||||
separated by spaces are possible. The font used on the reel display
|
||||
allows three rows of up to 12 characters
|
||||
wide text. You can force line breaks with a comma.
|
||||
* Press "Send" - this will trigger pairing since this is a protected
|
||||
characteristic. The passkey for the pairing will be shown on the board's
|
||||
display. Enter the passkey in your phone.
|
||||
* Once pairing is complete the board will show the text you sent. If
|
||||
you're not happy with it you can try writing something else.
|
||||
* When you're happy with the text, disconnect from the board (exit the app or
|
||||
go back to the device scan page)
|
||||
* Once disconnected the board switches over to Bluetooth Mesh mode, and you
|
||||
can't connect to it anymore over GATT.
|
||||
|
||||
If you configure multiple boards like this they can communicate with
|
||||
each other over mesh: by pressing the user button on the board the first
|
||||
word (name) of the stored text will be sent to all other boards in
|
||||
the network and cause the other boards to display "<name> says hi!".
|
||||
|
||||
To reset a board to its initial state (disable mesh, erase the stored
|
||||
text, and make it connectable over GATT):
|
||||
|
||||
* Keep the user button pressed when powering on (or press the reset button
|
||||
when powered)
|
||||
* Wait until "Reseting Device" is shown
|
@ -0,0 +1,39 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
pkg.name: apps/mesh_badge
|
||||
pkg.type: app
|
||||
pkg.description: Sample app for the reel board that showcases Bluetooth Mesh
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@apache-mynewt-core/hw/drivers/display/cfb"
|
||||
- "@apache-mynewt-core/hw/drivers/display/ssd1673"
|
||||
- "@apache-mynewt-core/kernel/os"
|
||||
- "@apache-mynewt-core/sys/console/full"
|
||||
- "@apache-mynewt-core/sys/log/full"
|
||||
- "@apache-mynewt-core/sys/log/modlog"
|
||||
- "@apache-mynewt-core/sys/stats/full"
|
||||
- "@apache-mynewt-core/sys/shell"
|
||||
- nimble/controller
|
||||
- nimble/host
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/host/store/config
|
||||
- nimble/transport/ram
|
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Phytec Messtechnik GmbH
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
void board_refresh_display(void);
|
||||
void board_show_text(const char *text, bool center, int32_t duration);
|
||||
void board_blink_leds(void);
|
||||
void board_add_hello(uint16_t addr, const char *name);
|
||||
void board_add_heartbeat(uint16_t addr, uint8_t hops);
|
||||
int board_init(void);
|
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
|
||||
#include "mesh.h"
|
||||
#include "board.h"
|
||||
#include "mesh_badge.h"
|
||||
|
||||
static const ble_uuid16_t gatt_cud_uuid = BLE_UUID16_INIT(0x2901);
|
||||
static const ble_uuid16_t gatt_cpf_uuid = BLE_UUID16_INIT(0x2904);
|
||||
|
||||
/** @brief GATT Characteristic Presentation Format Attribute Value. */
|
||||
struct bt_gatt_cpf {
|
||||
/** Format of the value of the characteristic */
|
||||
uint8_t format;
|
||||
/** Exponent field to determine how the value of this characteristic is further formatted */
|
||||
int8_t exponent;
|
||||
/** Unit of the characteristic */
|
||||
uint16_t unit;
|
||||
/** Name space of the description */
|
||||
uint8_t name_space;
|
||||
/** Description of the characteristic as defined in a higher layer profile */
|
||||
uint16_t description;
|
||||
} __packed;
|
||||
|
||||
#define CPF_FORMAT_UTF8 0x19
|
||||
|
||||
static const struct bt_gatt_cpf name_cpf = {
|
||||
.format = CPF_FORMAT_UTF8,
|
||||
};
|
||||
|
||||
static const ble_uuid128_t name_uuid = BLE_UUID128_INIT(
|
||||
0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
|
||||
0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
|
||||
|
||||
static const ble_uuid128_t name_enc_uuid = BLE_UUID128_INIT(
|
||||
0xf1, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
|
||||
0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &name_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
.uuid = &name_enc_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access,
|
||||
.flags = BLE_GATT_CHR_F_READ |
|
||||
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
|
||||
.descriptors = (struct ble_gatt_dsc_def[]) { {
|
||||
.uuid = &gatt_cud_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
}, {
|
||||
.uuid = &gatt_cpf_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
}, {
|
||||
0, /* No more descriptors in this characteristic. */
|
||||
} }
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
} },
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
static int read_name(struct os_mbuf *om)
|
||||
{
|
||||
const char *value = bt_get_name();
|
||||
int rc;
|
||||
|
||||
rc = os_mbuf_append(om, value, (uint16_t) strlen(value));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
static int write_name(struct os_mbuf *om)
|
||||
{
|
||||
char name[MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH)];
|
||||
uint16_t len;
|
||||
uint16_t om_len;
|
||||
int rc;
|
||||
|
||||
om_len = OS_MBUF_PKTLEN(om);
|
||||
if (om_len >= sizeof(name)) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
rc = ble_hs_mbuf_to_flat(om, name, sizeof(name) - 1, &len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
name[len] = '\0';
|
||||
|
||||
rc = bt_set_name(name);
|
||||
if (rc) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
board_refresh_display();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
|
||||
uuid = ctxt->chr->uuid;
|
||||
|
||||
if (ble_uuid_cmp(uuid, &name_enc_uuid.u) == 0) {
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
rc = read_name(ctxt->om);
|
||||
return rc;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
rc = write_name(ctxt->om);
|
||||
return rc;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
} else if (ble_uuid_cmp(uuid, &gatt_cud_uuid.u) == 0) {
|
||||
rc = os_mbuf_append(ctxt->om, "Badge Name",
|
||||
(uint16_t) strlen("Badge Name"));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
} else if (ble_uuid_cmp(uuid, &gatt_cpf_uuid.u) == 0) {
|
||||
rc = os_mbuf_append(ctxt->om, &name_cpf,
|
||||
(uint16_t) sizeof(name_cpf));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
/* Unknown characteristic; the nimble stack should not have called this
|
||||
* function.
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
void
|
||||
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "console/console.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "mesh/glue.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "base64/base64.h"
|
||||
|
||||
#include "mesh_badge.h"
|
||||
#include "mesh.h"
|
||||
#include "board.h"
|
||||
|
||||
static char badge_name[MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH)];
|
||||
|
||||
#define MESH_BADGE_NAME_ENCODE_SIZE \
|
||||
BASE64_ENCODE_SIZE(sizeof(badge_name))
|
||||
|
||||
static bool reset_mesh;
|
||||
|
||||
void print_addr(const void *addr)
|
||||
{
|
||||
const uint8_t *u8p;
|
||||
|
||||
u8p = addr;
|
||||
MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
print_conn_desc(struct ble_gap_conn_desc *desc)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
|
||||
desc->conn_handle, desc->our_ota_addr.type);
|
||||
print_addr(desc->our_ota_addr.val);
|
||||
MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
|
||||
desc->our_id_addr.type);
|
||||
print_addr(desc->our_id_addr.val);
|
||||
MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
|
||||
desc->peer_ota_addr.type);
|
||||
print_addr(desc->peer_ota_addr.val);
|
||||
MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
|
||||
desc->peer_id_addr.type);
|
||||
print_addr(desc->peer_id_addr.val);
|
||||
MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
|
||||
"encrypted=%d authenticated=%d bonded=%d\n",
|
||||
desc->conn_itvl, desc->conn_latency,
|
||||
desc->supervision_timeout,
|
||||
desc->sec_state.encrypted,
|
||||
desc->sec_state.authenticated,
|
||||
desc->sec_state.bonded);
|
||||
}
|
||||
|
||||
static int gap_event(struct ble_gap_event *event, void *arg);
|
||||
|
||||
static void advertise(void)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
const char *name;
|
||||
int rc;
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info).
|
||||
* o Advertising tx power.
|
||||
* o Device name.
|
||||
* o 16-bit service UUIDs (alert notifications).
|
||||
*/
|
||||
|
||||
memset(&fields, 0, sizeof fields);
|
||||
|
||||
/* Advertise two flags:
|
||||
* o Discoverability in forthcoming advertisement (general)
|
||||
* o BLE-only (BR/EDR unsupported).
|
||||
*/
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
#if 0
|
||||
/* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assiging the
|
||||
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
|
||||
*/
|
||||
fields.tx_pwr_lvl_is_present = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
#endif
|
||||
|
||||
name = ble_svc_gap_device_name();
|
||||
fields.name = (uint8_t *)name;
|
||||
fields.name_len = (uint8_t) strlen(name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin advertising. */
|
||||
memset(&adv_params, 0, sizeof adv_params);
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void passkey_display(uint16_t conn_handle)
|
||||
{
|
||||
char buf[20];
|
||||
struct ble_sm_io pk;
|
||||
int rc;
|
||||
|
||||
bt_rand(&pk.passkey, sizeof(pk.passkey));
|
||||
/* Max value is 999999 */
|
||||
pk.passkey %= 1000000;
|
||||
pk.action = BLE_SM_IOACT_DISP;
|
||||
|
||||
rc = ble_sm_inject_io(conn_handle, &pk);
|
||||
assert(rc == 0);
|
||||
|
||||
snprintk(buf, sizeof(buf), "Passkey:\n%06lu", pk.passkey);
|
||||
|
||||
printk("%s\n", buf);
|
||||
board_show_text(buf, false, K_FOREVER);
|
||||
}
|
||||
|
||||
static void pairing_complete(uint16_t conn_handle, bool bonded)
|
||||
{
|
||||
printk("Pairing Complete\n");
|
||||
board_show_text("Pairing Complete", false, K_SECONDS(2));
|
||||
}
|
||||
|
||||
static void pairing_failed(uint16_t conn_handle)
|
||||
{
|
||||
printk("Pairing Failed\n");
|
||||
board_show_text("Pairing Failed", false, K_SECONDS(2));
|
||||
}
|
||||
|
||||
static void connected(uint16_t conn_handle, int err)
|
||||
{
|
||||
printk("Connected (err 0x%02x)\n", err);
|
||||
|
||||
if (err) {
|
||||
board_show_text("Connection failed", false, K_SECONDS(2));
|
||||
} else {
|
||||
board_show_text("Connected", false, K_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static void disconnected(uint16_t conn_handle, int reason)
|
||||
{
|
||||
printk("Disconnected (reason 0x%02x)\n", reason);
|
||||
|
||||
if (strcmp(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME), bt_get_name()) != 0 &&
|
||||
!mesh_is_initialized()) {
|
||||
/* Mesh will take over advertising control */
|
||||
ble_gap_adv_stop();
|
||||
mesh_start();
|
||||
} else {
|
||||
board_show_text("Disconnected", false, K_SECONDS(2));
|
||||
}
|
||||
}
|
||||
|
||||
static int gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
int rc;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
MODLOG_DFLT(INFO, "connection %s; status=%d ",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
if (event->connect.status == 0) {
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
print_conn_desc(&desc);
|
||||
connected(event->connect.conn_handle,
|
||||
event->connect.status);
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
advertise();
|
||||
}
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
|
||||
print_conn_desc(&event->disconnect.conn);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Connection terminated; resume advertising. */
|
||||
advertise();
|
||||
|
||||
disconnected(event->disconnect.conn.conn_handle,
|
||||
event->disconnect.reason);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
/* The central has updated the connection parameters. */
|
||||
MODLOG_DFLT(INFO, "connection updated; status=%d ",
|
||||
event->conn_update.status);
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_ENC_CHANGE:
|
||||
/* Encryption has been enabled or disabled for this connection. */
|
||||
MODLOG_DFLT(INFO, "encryption change event; status=%d ",
|
||||
event->enc_change.status);
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
if (desc.sec_state.bonded) {
|
||||
pairing_complete(event->enc_change.conn_handle, true);
|
||||
} else if(desc.sec_state.encrypted) {
|
||||
pairing_complete(event->enc_change.conn_handle, false);
|
||||
} else {
|
||||
pairing_failed(event->enc_change.conn_handle);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_PASSKEY_ACTION:
|
||||
MODLOG_DFLT(INFO, "passkey action event; conn_handle=%d action=%d numcmp=%d\n",
|
||||
event->passkey.conn_handle,
|
||||
event->passkey.params.action,
|
||||
event->passkey.params.numcmp);
|
||||
passkey_display(event->passkey.conn_handle);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING:
|
||||
/* We already have a bond with the peer, but it is attempting to
|
||||
* establish a new secure link. This app sacrifices security for
|
||||
* convenience: just throw away the old bond and accept the new link.
|
||||
*/
|
||||
|
||||
/* Delete the old bond. */
|
||||
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
ble_store_util_delete_peer(&desc.peer_id_addr);
|
||||
|
||||
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
|
||||
* continue with the pairing operation.
|
||||
*/
|
||||
return BLE_GAP_REPEAT_PAIRING_RETRY;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void on_sync(void)
|
||||
{
|
||||
int err;
|
||||
ble_addr_t addr;
|
||||
|
||||
/* Use NRPA */
|
||||
err = ble_hs_id_gen_rnd(1, &addr);
|
||||
assert(err == 0);
|
||||
err = ble_hs_id_set_rnd(addr.val);
|
||||
assert(err == 0);
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = mesh_init(addr.type);
|
||||
if (err) {
|
||||
printk("Initializing mesh failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Mesh initialized\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (reset_mesh) {
|
||||
bt_mesh_reset();
|
||||
reset_mesh = false;
|
||||
}
|
||||
|
||||
if (!mesh_is_initialized()) {
|
||||
advertise();
|
||||
} else {
|
||||
printk("Already provisioned\n");
|
||||
ble_svc_gap_device_name_set(bt_get_name());
|
||||
}
|
||||
|
||||
board_refresh_display();
|
||||
|
||||
printk("Board started\n");
|
||||
}
|
||||
|
||||
void schedule_mesh_reset(void)
|
||||
{
|
||||
reset_mesh = true;
|
||||
}
|
||||
|
||||
static void on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
const char *bt_get_name(void)
|
||||
{
|
||||
char buf[MESH_BADGE_NAME_ENCODE_SIZE];
|
||||
int rc, len;
|
||||
|
||||
rc = conf_get_stored_value("mesh_badge/badge_name",
|
||||
buf, sizeof(buf));
|
||||
if (rc == OS_ENOENT) {
|
||||
bt_set_name(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME));
|
||||
} else {
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
memset(badge_name, '\0', sizeof(badge_name));
|
||||
len = base64_decode(buf, badge_name);
|
||||
if (len < 0) {
|
||||
bt_set_name(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME));
|
||||
}
|
||||
|
||||
return badge_name;
|
||||
}
|
||||
|
||||
int bt_set_name(const char *name)
|
||||
{
|
||||
char buf[MESH_BADGE_NAME_ENCODE_SIZE];
|
||||
int rc;
|
||||
|
||||
memset(badge_name, '\0', sizeof(badge_name));
|
||||
memcpy(badge_name, name, strlen(name));
|
||||
base64_encode(badge_name, sizeof(badge_name), buf, 1);
|
||||
rc = conf_save_one("mesh_badge/badge_name", buf);
|
||||
assert(rc == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
err = board_init();
|
||||
if (err) {
|
||||
printk("board init failed (err %d)\n", err);
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = on_reset;
|
||||
ble_hs_cfg.sync_cb = on_sync;
|
||||
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY;
|
||||
|
||||
err = gatt_svr_init();
|
||||
assert(err == 0);
|
||||
|
||||
/*
|
||||
* As the last thing, process events from default event queue.
|
||||
*/
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "console/console.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
#include "mesh_badge.h"
|
||||
#include "mesh.h"
|
||||
#include "board.h"
|
||||
|
||||
#define BT_COMP_ID_LF 0x05f1
|
||||
|
||||
#define MOD_LF 0x0000
|
||||
#define OP_HELLO 0xbb
|
||||
#define OP_HEARTBEAT 0xbc
|
||||
#define OP_VND_HELLO BT_MESH_MODEL_OP_3(OP_HELLO, BT_COMP_ID_LF)
|
||||
#define OP_VND_HEARTBEAT BT_MESH_MODEL_OP_3(OP_HEARTBEAT, BT_COMP_ID_LF)
|
||||
|
||||
#define DEFAULT_TTL 31
|
||||
#define GROUP_ADDR 0xc123
|
||||
#define NET_IDX 0x000
|
||||
#define APP_IDX 0x000
|
||||
#define FLAGS 0
|
||||
static struct ble_npl_callout hello_work;
|
||||
static struct ble_npl_callout mesh_start_work;
|
||||
|
||||
static void heartbeat(const struct bt_mesh_hb_sub *sub, uint8_t hops,
|
||||
uint16_t feat)
|
||||
{
|
||||
board_show_text("Heartbeat Received", false, K_SECONDS(2));
|
||||
}
|
||||
|
||||
static struct bt_mesh_cfg_cli cfg_cli = {
|
||||
};
|
||||
|
||||
static void attention_on(struct bt_mesh_model *model)
|
||||
{
|
||||
board_show_text("Attention!", false, K_SECONDS(2));
|
||||
}
|
||||
|
||||
static void attention_off(struct bt_mesh_model *model)
|
||||
{
|
||||
board_refresh_display();
|
||||
}
|
||||
|
||||
static const struct bt_mesh_health_srv_cb health_srv_cb = {
|
||||
.attn_on = attention_on,
|
||||
.attn_off = attention_off,
|
||||
};
|
||||
|
||||
static struct bt_mesh_health_srv health_srv = {
|
||||
.cb = &health_srv_cb,
|
||||
};
|
||||
|
||||
static struct os_mbuf *bt_mesh_pub_msg_health_pub;
|
||||
static struct bt_mesh_model_pub health_pub;
|
||||
|
||||
static struct bt_mesh_model root_models[] = {
|
||||
BT_MESH_MODEL_CFG_SRV,
|
||||
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
|
||||
};
|
||||
|
||||
static void vnd_hello(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
char str[32];
|
||||
size_t len;
|
||||
|
||||
printk("Hello message from 0x%04x\n", ctx->addr);
|
||||
|
||||
if (ctx->addr == bt_mesh_model_elem(model)->addr) {
|
||||
printk("Ignoring message from self\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len = min(buf->om_len, 8);
|
||||
memcpy(str, buf->om_data, len);
|
||||
str[len] = '\0';
|
||||
|
||||
board_add_hello(ctx->addr, str);
|
||||
|
||||
strcpy(str + len, " says hi!");
|
||||
|
||||
board_show_text(str, false, K_SECONDS(3));
|
||||
|
||||
board_blink_leds();
|
||||
}
|
||||
|
||||
static void vnd_heartbeat(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
uint8_t init_ttl, hops;
|
||||
|
||||
/* Ignore messages from self */
|
||||
if (ctx->addr == bt_mesh_model_elem(model)->addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
init_ttl = net_buf_simple_pull_u8(buf);
|
||||
hops = init_ttl - ctx->recv_ttl + 1;
|
||||
|
||||
printk("Heartbeat from 0x%04x over %u hop%s\n", ctx->addr,
|
||||
hops, hops == 1 ? "" : "s");
|
||||
|
||||
board_add_heartbeat(ctx->addr, hops);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_model_op vnd_ops[] = {
|
||||
{ OP_VND_HELLO, 1, vnd_hello },
|
||||
{ OP_VND_HEARTBEAT, 1, vnd_heartbeat },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
static int pub_update(struct bt_mesh_model *mod)
|
||||
{
|
||||
struct os_mbuf *msg = mod->pub->msg;
|
||||
|
||||
printk("Preparing to send heartbeat\n");
|
||||
|
||||
bt_mesh_model_msg_init(msg, OP_VND_HEARTBEAT);
|
||||
net_buf_simple_add_u8(msg, DEFAULT_TTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct os_mbuf *bt_mesh_pub_msg_vnd_pub;
|
||||
static struct bt_mesh_model_pub vnd_pub;
|
||||
|
||||
static struct bt_mesh_model vnd_models[] = {
|
||||
BT_MESH_MODEL_VND(BT_COMP_ID_LF, MOD_LF, vnd_ops, &vnd_pub, NULL),
|
||||
};
|
||||
|
||||
static struct bt_mesh_elem elements[] = {
|
||||
BT_MESH_ELEM(0, root_models, vnd_models),
|
||||
};
|
||||
|
||||
static const struct bt_mesh_comp comp = {
|
||||
.cid = BT_COMP_ID_LF,
|
||||
.elem = elements,
|
||||
.elem_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
static size_t first_name_len(const char *name)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
for (len = 0; *name; name++, len++) {
|
||||
switch (*name) {
|
||||
case ' ':
|
||||
case ',':
|
||||
case '\n':
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void send_hello(struct ble_npl_event *work)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(3 + 8 + 4);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = NET_IDX,
|
||||
.app_idx = APP_IDX,
|
||||
.addr = GROUP_ADDR,
|
||||
.send_ttl = DEFAULT_TTL,
|
||||
};
|
||||
const char *name = bt_get_name();
|
||||
|
||||
bt_mesh_model_msg_init(msg, OP_VND_HELLO);
|
||||
net_buf_simple_add_mem(msg, name, first_name_len(name));
|
||||
|
||||
if (bt_mesh_model_send(&vnd_models[0], &ctx, msg, NULL, NULL) == 0) {
|
||||
board_show_text("Saying \"hi!\" to everyone", false,
|
||||
K_SECONDS(2));
|
||||
} else {
|
||||
board_show_text("Sending Failed!", false, K_SECONDS(2));
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
void mesh_send_hello(void)
|
||||
{
|
||||
k_work_submit(&hello_work);
|
||||
}
|
||||
|
||||
static int provision_and_configure(void)
|
||||
{
|
||||
static const uint8_t net_key[16] = {
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
|
||||
};
|
||||
static const uint8_t app_key[16] = {
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
};
|
||||
static const uint16_t iv_index;
|
||||
struct bt_mesh_cfg_mod_pub pub = {
|
||||
.addr = GROUP_ADDR,
|
||||
.app_idx = APP_IDX,
|
||||
.ttl = DEFAULT_TTL,
|
||||
.period = BT_MESH_PUB_PERIOD_SEC(10),
|
||||
};
|
||||
uint8_t dev_key[16];
|
||||
uint16_t addr;
|
||||
int err;
|
||||
|
||||
err = bt_rand(dev_key, sizeof(dev_key));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
do {
|
||||
err = bt_rand(&addr, sizeof(addr));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} while (!addr);
|
||||
|
||||
/* Make sure it's a unicast address (highest bit unset) */
|
||||
addr &= ~0x8000;
|
||||
|
||||
err = bt_mesh_provision(net_key, NET_IDX, FLAGS, iv_index, addr,
|
||||
dev_key);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
printk("Configuring...\n");
|
||||
|
||||
/* Add Application Key */
|
||||
bt_mesh_cfg_app_key_add(NET_IDX, addr, NET_IDX, APP_IDX, app_key, NULL);
|
||||
|
||||
/* Bind to vendor model */
|
||||
bt_mesh_cfg_mod_app_bind_vnd(NET_IDX, addr, addr, APP_IDX,
|
||||
MOD_LF, BT_COMP_ID_LF, NULL);
|
||||
|
||||
/* Bind to Health model */
|
||||
bt_mesh_cfg_mod_app_bind(NET_IDX, addr, addr, APP_IDX,
|
||||
BT_MESH_MODEL_ID_HEALTH_SRV, NULL);
|
||||
|
||||
/* Add model subscription */
|
||||
bt_mesh_cfg_mod_sub_add_vnd(NET_IDX, addr, addr, GROUP_ADDR,
|
||||
MOD_LF, BT_COMP_ID_LF, NULL);
|
||||
|
||||
bt_mesh_cfg_mod_pub_set_vnd(NET_IDX, addr, addr, MOD_LF, BT_COMP_ID_LF,
|
||||
&pub, NULL);
|
||||
|
||||
printk("Configuration complete\n");
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void start_mesh(struct ble_npl_event *work)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = provision_and_configure();
|
||||
if (err < 0) {
|
||||
board_show_text("Starting Mesh Failed", false,
|
||||
K_SECONDS(2));
|
||||
} else {
|
||||
char buf[32];
|
||||
|
||||
snprintk(buf, sizeof(buf),
|
||||
"Mesh Started\nAddr: 0x%04x", err);
|
||||
board_show_text(buf, false, K_SECONDS(4));
|
||||
}
|
||||
}
|
||||
|
||||
void mesh_start(void)
|
||||
{
|
||||
k_work_submit(&mesh_start_work);
|
||||
}
|
||||
|
||||
bool mesh_is_initialized(void)
|
||||
{
|
||||
return bt_mesh_is_provisioned();
|
||||
}
|
||||
|
||||
uint16_t mesh_get_addr(void)
|
||||
{
|
||||
return elements[0].addr;
|
||||
}
|
||||
|
||||
int mesh_init(uint8_t addr_type)
|
||||
{
|
||||
static const uint8_t dev_uuid[16] = { 0xc0, 0xff, 0xee };
|
||||
static const struct bt_mesh_prov prov = {
|
||||
.uuid = dev_uuid,
|
||||
};
|
||||
|
||||
hb_cb = { .recv = heartbeat };
|
||||
|
||||
bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(0);
|
||||
health_pub.msg = bt_mesh_pub_msg_health_pub;
|
||||
|
||||
bt_mesh_pub_msg_vnd_pub = NET_BUF_SIMPLE(3 + 1);
|
||||
vnd_pub.msg = bt_mesh_pub_msg_vnd_pub;
|
||||
vnd_pub.update = pub_update;
|
||||
|
||||
k_work_init(&hello_work, send_hello);
|
||||
k_work_init(&mesh_start_work, start_mesh);
|
||||
|
||||
return bt_mesh_init(addr_type, &prov, &comp);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
void mesh_send_hello(void);
|
||||
|
||||
uint16_t mesh_get_addr(void);
|
||||
bool mesh_is_initialized(void);
|
||||
void mesh_start(void);
|
||||
int mesh_init(uint8_t addr_type);
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
struct ble_gatt_register_ctxt;
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
void schedule_mesh_reset(void);
|
||||
const char *bt_get_name(void);
|
||||
int bt_set_name(const char *);
|
||||
|
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Phytec Messtechnik GmbH
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "os/mynewt.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_flash.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "mesh/glue.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
#include "mesh_badge.h"
|
||||
#include "display/cfb.h"
|
||||
#include "mesh.h"
|
||||
#include "board.h"
|
||||
|
||||
#define printk console_printf
|
||||
|
||||
enum font_size {
|
||||
FONT_BIG = 0,
|
||||
FONT_MEDIUM = 1,
|
||||
FONT_SMALL = 2,
|
||||
};
|
||||
|
||||
struct font_info {
|
||||
uint8_t columns;
|
||||
} fonts[] = {
|
||||
[FONT_BIG] = { .columns = 12 },
|
||||
[FONT_MEDIUM] = { .columns = 16 },
|
||||
[FONT_SMALL] = { .columns = 25 },
|
||||
};
|
||||
|
||||
#define LONG_PRESS_TIMEOUT K_SECONDS(1)
|
||||
|
||||
#define STAT_COUNT 128
|
||||
|
||||
#define EDGE (GPIO_INT_EDGE | GPIO_INT_DOUBLE_EDGE)
|
||||
|
||||
#ifdef SW0_GPIO_FLAGS
|
||||
#define PULL_UP SW0_GPIO_FLAGS
|
||||
#else
|
||||
#define PULL_UP 0
|
||||
#endif
|
||||
|
||||
static struct os_dev *epd_dev;
|
||||
static bool pressed;
|
||||
static bool stats_view;
|
||||
static struct k_delayed_work epd_work;
|
||||
static struct k_delayed_work long_press_work;
|
||||
|
||||
static struct {
|
||||
int pin;
|
||||
} leds[] = {
|
||||
{ .pin = LED_1, },
|
||||
{ .pin = RGB_LED_RED, },
|
||||
{ .pin = RGB_LED_GRN, },
|
||||
{ .pin = RGB_LED_BLU, },
|
||||
};
|
||||
|
||||
struct k_delayed_work led_timer;
|
||||
|
||||
static size_t print_line(enum font_size font_size, int row, const char *text,
|
||||
size_t len, bool center)
|
||||
{
|
||||
uint8_t font_height, font_width;
|
||||
char line[fonts[FONT_SMALL].columns + 1];
|
||||
int pad;
|
||||
|
||||
cfb_framebuffer_set_font(epd_dev, font_size);
|
||||
|
||||
len = min(len, fonts[font_size].columns);
|
||||
memcpy(line, text, len);
|
||||
line[len] = '\0';
|
||||
|
||||
if (center) {
|
||||
pad = (fonts[font_size].columns - len) / 2;
|
||||
} else {
|
||||
pad = 0;
|
||||
}
|
||||
|
||||
cfb_get_font_size(epd_dev, font_size, &font_width, &font_height);
|
||||
|
||||
if (cfb_print(epd_dev, line, font_width * pad, font_height * row)) {
|
||||
printk("Failed to print a string\n");
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t get_len(enum font_size font, const char *text)
|
||||
{
|
||||
const char *space = NULL;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i <= fonts[font].columns; i++) {
|
||||
switch (text[i]) {
|
||||
case '\n':
|
||||
case '\0':
|
||||
return i;
|
||||
case ' ':
|
||||
space = &text[i];
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got more characters than fits a line, and a space was
|
||||
* encountered, fall back to the last space.
|
||||
*/
|
||||
if (space) {
|
||||
return space - text;
|
||||
}
|
||||
|
||||
return fonts[font].columns;
|
||||
}
|
||||
|
||||
void board_blink_leds(void)
|
||||
{
|
||||
k_delayed_work_submit(&led_timer, K_MSEC(100));
|
||||
}
|
||||
|
||||
void board_show_text(const char *text, bool center, int32_t duration)
|
||||
{
|
||||
int i;
|
||||
|
||||
cfb_framebuffer_clear(epd_dev, false);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
size_t len;
|
||||
|
||||
while (*text == ' ' || *text == '\n') {
|
||||
text++;
|
||||
}
|
||||
|
||||
len = get_len(FONT_BIG, text);
|
||||
if (!len) {
|
||||
break;
|
||||
}
|
||||
|
||||
text += print_line(FONT_BIG, i, text, len, center);
|
||||
if (!*text) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cfb_framebuffer_finalize(epd_dev);
|
||||
|
||||
if (duration != K_FOREVER) {
|
||||
k_delayed_work_submit(&epd_work, duration);
|
||||
}
|
||||
}
|
||||
|
||||
static struct stat {
|
||||
uint16_t addr;
|
||||
char name[9];
|
||||
uint8_t min_hops;
|
||||
uint8_t max_hops;
|
||||
uint16_t hello_count;
|
||||
uint16_t heartbeat_count;
|
||||
} stats[STAT_COUNT] = {
|
||||
[0 ... (STAT_COUNT - 1)] = {
|
||||
.min_hops = BT_MESH_TTL_MAX,
|
||||
.max_hops = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static uint32_t stat_count;
|
||||
|
||||
#define NO_UPDATE -1
|
||||
|
||||
static int add_hello(uint16_t addr, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stats); i++) {
|
||||
struct stat *stat = &stats[i];
|
||||
|
||||
if (!stat->addr) {
|
||||
stat->addr = addr;
|
||||
strncpy(stat->name, name, sizeof(stat->name) - 1);
|
||||
stat->hello_count = 1;
|
||||
stat_count++;
|
||||
return i;
|
||||
}
|
||||
|
||||
if (stat->addr == addr) {
|
||||
/* Update name, incase it has changed */
|
||||
strncpy(stat->name, name, sizeof(stat->name) - 1);
|
||||
|
||||
if (stat->hello_count < 0xffff) {
|
||||
stat->hello_count++;
|
||||
return i;
|
||||
}
|
||||
|
||||
return NO_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
return NO_UPDATE;
|
||||
}
|
||||
|
||||
static int add_heartbeat(uint16_t addr, uint8_t hops)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stats); i++) {
|
||||
struct stat *stat = &stats[i];
|
||||
|
||||
if (!stat->addr) {
|
||||
stat->addr = addr;
|
||||
stat->heartbeat_count = 1;
|
||||
stat->min_hops = hops;
|
||||
stat->max_hops = hops;
|
||||
stat_count++;
|
||||
return i;
|
||||
}
|
||||
|
||||
if (stat->addr == addr) {
|
||||
if (hops < stat->min_hops) {
|
||||
stat->min_hops = hops;
|
||||
} else if (hops > stat->max_hops) {
|
||||
stat->max_hops = hops;
|
||||
}
|
||||
|
||||
if (stat->heartbeat_count < 0xffff) {
|
||||
stat->heartbeat_count++;
|
||||
return i;
|
||||
}
|
||||
|
||||
return NO_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
return NO_UPDATE;
|
||||
}
|
||||
|
||||
void board_add_hello(uint16_t addr, const char *name)
|
||||
{
|
||||
uint32_t sort_i;
|
||||
|
||||
sort_i = add_hello(addr, name);
|
||||
if (sort_i != NO_UPDATE) {
|
||||
}
|
||||
}
|
||||
|
||||
void board_add_heartbeat(uint16_t addr, uint8_t hops)
|
||||
{
|
||||
uint32_t sort_i;
|
||||
|
||||
sort_i = add_heartbeat(addr, hops);
|
||||
if (sort_i != NO_UPDATE) {
|
||||
}
|
||||
}
|
||||
|
||||
static void show_statistics(void)
|
||||
{
|
||||
int top[4] = { -1, -1, -1, -1 };
|
||||
int len, i, line = 0;
|
||||
struct stat *stat;
|
||||
char str[32];
|
||||
|
||||
cfb_framebuffer_clear(epd_dev, false);
|
||||
|
||||
len = snprintk(str, sizeof(str),
|
||||
"Own Address: 0x%04x", mesh_get_addr());
|
||||
print_line(FONT_SMALL, line++, str, len, false);
|
||||
|
||||
len = snprintk(str, sizeof(str),
|
||||
"Node Count: %lu", stat_count + 1);
|
||||
print_line(FONT_SMALL, line++, str, len, false);
|
||||
|
||||
/* Find the top sender */
|
||||
for (i = 0; i < ARRAY_SIZE(stats); i++) {
|
||||
int j;
|
||||
|
||||
stat = &stats[i];
|
||||
if (!stat->addr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stat->hello_count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(top); j++) {
|
||||
if (top[j] < 0) {
|
||||
top[j] = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stat->hello_count <= stats[top[j]].hello_count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Move other elements down the list */
|
||||
if (j < ARRAY_SIZE(top) - 1) {
|
||||
memmove(&top[j + 1], &top[j],
|
||||
((ARRAY_SIZE(top) - j - 1) *
|
||||
sizeof(top[j])));
|
||||
}
|
||||
|
||||
top[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat_count >= 0) {
|
||||
len = snprintk(str, sizeof(str), "Most messages from:");
|
||||
print_line(FONT_SMALL, line++, str, len, false);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(top); i++) {
|
||||
if (top[i] < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
stat = &stats[top[i]];
|
||||
|
||||
len = snprintk(str, sizeof(str), "%-3u 0x%04x %s",
|
||||
stat->hello_count, stat->addr,
|
||||
stat->name);
|
||||
print_line(FONT_SMALL, line++, str, len, false);
|
||||
}
|
||||
}
|
||||
|
||||
cfb_framebuffer_finalize(epd_dev);
|
||||
}
|
||||
|
||||
static void epd_update(struct ble_npl_event *work)
|
||||
{
|
||||
char buf[MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH)];
|
||||
int i;
|
||||
|
||||
if (stats_view) {
|
||||
show_statistics();
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(buf, bt_get_name(), sizeof(buf));
|
||||
|
||||
/* Convert commas to newlines */
|
||||
for (i = 0; buf[i] != '\0'; i++) {
|
||||
if (buf[i] == ',') {
|
||||
buf[i] = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
board_show_text(buf, true, K_FOREVER);
|
||||
}
|
||||
|
||||
static void long_press(struct ble_npl_event *work)
|
||||
{
|
||||
/* Treat as release so actual release doesn't send messages */
|
||||
pressed = false;
|
||||
stats_view = !stats_view;
|
||||
board_refresh_display();
|
||||
}
|
||||
|
||||
static bool button_is_pressed(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = (uint32_t) hal_gpio_read(BUTTON_1);
|
||||
|
||||
return !val;
|
||||
}
|
||||
|
||||
static void button_interrupt(struct os_event *ev)
|
||||
{
|
||||
int pin_pos = (int ) ev->ev_arg;
|
||||
|
||||
if (button_is_pressed() == pressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
pressed = !pressed;
|
||||
printk("Button %s\n", pressed ? "pressed" : "released");
|
||||
|
||||
if (pressed) {
|
||||
k_delayed_work_submit(&long_press_work, LONG_PRESS_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
k_delayed_work_cancel(&long_press_work);
|
||||
|
||||
if (!mesh_is_initialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Short press does currently nothing in statistics view */
|
||||
if (stats_view) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pin_pos == BUTTON_1) {
|
||||
mesh_send_hello();
|
||||
}
|
||||
}
|
||||
|
||||
static struct os_event button_event;
|
||||
|
||||
static void
|
||||
gpio_irq_handler(void *arg)
|
||||
{
|
||||
button_event.ev_arg = arg;
|
||||
os_eventq_put(os_eventq_dflt_get(), &button_event);
|
||||
}
|
||||
|
||||
static int configure_button(void)
|
||||
{
|
||||
button_event.ev_cb = button_interrupt;
|
||||
|
||||
hal_gpio_irq_init(BUTTON_1, gpio_irq_handler, (void *) BUTTON_1,
|
||||
HAL_GPIO_TRIG_BOTH, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(BUTTON_1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void led_timeout(struct ble_npl_event *work)
|
||||
{
|
||||
static int led_cntr;
|
||||
int i;
|
||||
|
||||
/* Disable all LEDs */
|
||||
for (i = 0; i < ARRAY_SIZE(leds); i++) {
|
||||
hal_gpio_write(leds[i].pin, 1);
|
||||
}
|
||||
|
||||
/* Stop after 5 iterations */
|
||||
if (led_cntr > (ARRAY_SIZE(leds) * 5)) {
|
||||
led_cntr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select and enable current LED */
|
||||
i = led_cntr++ % ARRAY_SIZE(leds);
|
||||
hal_gpio_write(leds[i].pin, 0);
|
||||
|
||||
k_delayed_work_submit(&led_timer, K_MSEC(100));
|
||||
}
|
||||
|
||||
static int configure_leds(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(leds); i++) {
|
||||
hal_gpio_init_out(leds[i].pin, 1);
|
||||
}
|
||||
|
||||
k_delayed_work_init(&led_timer, led_timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int erase_storage(void)
|
||||
{
|
||||
bt_set_name(MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME));
|
||||
ble_store_clear();
|
||||
schedule_mesh_reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void board_refresh_display(void)
|
||||
{
|
||||
k_delayed_work_submit(&epd_work, K_NO_WAIT);
|
||||
}
|
||||
|
||||
int board_init(void)
|
||||
{
|
||||
epd_dev = os_dev_lookup(MYNEWT_VAL(SSD1673_OS_DEV_NAME));
|
||||
if (epd_dev == NULL) {
|
||||
printk("SSD1673 device not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cfb_framebuffer_init(epd_dev)) {
|
||||
printk("Framebuffer initialization failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cfb_framebuffer_clear(epd_dev, true);
|
||||
|
||||
if (configure_button()) {
|
||||
printk("Failed to configure button\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (configure_leds()) {
|
||||
printk("LED init failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
k_delayed_work_init(&epd_work, epd_update);
|
||||
k_delayed_work_init(&long_press_work, long_press);
|
||||
|
||||
pressed = button_is_pressed();
|
||||
if (pressed) {
|
||||
printk("Erasing storage\n");
|
||||
board_show_text("Resetting Device", false, K_SECONDS(4));
|
||||
erase_storage();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
# Package: apps/mesh_badge
|
||||
|
||||
syscfg.vals:
|
||||
# Enable the shell task.
|
||||
SHELL_TASK: 1
|
||||
|
||||
# Set log level to info (disable debug logging).
|
||||
LOG_LEVEL: 1
|
||||
|
||||
# Default task settings
|
||||
OS_MAIN_STACK_SIZE: 768
|
||||
|
||||
# Newtmgr is not supported in this app, so disable newtmgr-over-shell.
|
||||
SHELL_NEWTMGR: 0
|
||||
|
||||
REEL_BOARD_ENABLE_ACTIVE_MODE: 1
|
||||
SPI_0_MASTER: 1
|
||||
|
||||
BLE_MESH: 1
|
||||
MSYS_1_BLOCK_COUNT: 48
|
||||
|
||||
BLE_SVC_GAP_DEVICE_NAME: '"reel board"'
|
||||
|
||||
BLE_SM_SC: 1
|
||||
BLE_SM_BONDING: 1
|
||||
BLE_MESH_RELAY: 1
|
||||
BLE_MESH_GATT_PROXY: 0
|
||||
BLE_MESH_PB_ADV: 0
|
||||
BLE_MESH_PB_GATT: 0
|
||||
BLE_MESH_ADV_BUF_COUNT: 30
|
||||
BLE_MESH_LABEL_COUNT: 0
|
||||
BLE_MESH_CFG_CLI: 1
|
||||
BLE_MESH_TX_SEG_MAX: 6
|
||||
BLE_MESH_TX_SEG_MSG_COUNT: 3
|
||||
BLE_MESH_RX_SEG_MSG_COUNT: 3
|
||||
BLE_MESH_CRPL: 128
|
||||
BLE_MESH_RPL_STORE_TIMEOUT: 120
|
||||
BLE_MESH_SETTINGS: 1
|
||||
CONFIG_NFFS: 1
|
||||
BLE_MESH_PB_ADV: 1
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_LL_ISO
|
||||
#define H_BLE_LL_ISO
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen);
|
||||
int ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen);
|
||||
int ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd);
|
||||
int ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen);
|
||||
int ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_create_big(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "syscfg/syscfg.h"
|
||||
#include "nimble/ble.h"
|
||||
#include "nimble/hci_common.h"
|
||||
#include "controller/ble_ll_iso.h"
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
|
||||
|
||||
int
|
||||
ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len,
|
||||
uint8_t *rspbuf, uint8_t *rsplen)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len,
|
||||
uint8_t *rspbuf, uint8_t *rsplen)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
/* Nothing to do here for now when HCI is supported */
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
ble_ll_iso_create_big(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST)
|
||||
int
|
||||
ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len,
|
||||
uint8_t *rspbuf, uint8_t *rsplen)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len)
|
||||
{
|
||||
return BLE_ERR_UNSUPPORTED;
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,68 @@
|
||||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
|
||||
## How to run NimBLE controller on Dialog DA1469x
|
||||
|
||||
Dialog DA1469x has separate Cortex-M0+ core inside CMAC hw block which can run
|
||||
NimBLE controller. This means DA1469x can run full NimBLE stack: host is running
|
||||
on M33 core while controller is running on M0+ core. Both communicate using
|
||||
standard HCI H4 protocol exchanged over mailboxes located in shared memory.
|
||||
|
||||
### Basic setup
|
||||
|
||||
In order to run full NimBLE stack on DA1469x you will need two newt targets: one
|
||||
for M33 (e.g. `dialog_da1469x-dk-pro` BSP) and one for M0+ (`dialog_cmac` BSP).
|
||||
|
||||
Once everything is configured properly, you only need to build target for M33.
|
||||
Target configured for M0+ will be build automatically and image is linked with
|
||||
M33 image so everything can be flashed at once just as if there is only single
|
||||
target used.
|
||||
|
||||
Target for M33 should be set and configured as any other BLE application. In
|
||||
order to use NimBLE controller on CMAC, set proper HCI transport via syscfg:
|
||||
|
||||
BLE_HCI_TRANSPORT: dialog_cmac
|
||||
|
||||
This will include proper transport, driver and add M0+ target to build process.
|
||||
|
||||
For M0+, there is sample target provided in `targets/dialog_cmac` and it's used
|
||||
by default unless overrided by syscfg in M33 target:
|
||||
|
||||
CMAC_IMAGE_TARGET_NAME: "@apache-mynewt-nimble/targets/dialog_cmac"
|
||||
|
||||
If you wish to create own target for M0+, make sure your target is set the same
|
||||
way (`app`, `bsp` and `build_profile`) as sample. Also it is recommended to use
|
||||
syscfg settings from sample target in new target.
|
||||
|
||||
### NimBLE configuration
|
||||
|
||||
Since host and controller are running on different cores, they both use separate
|
||||
configuration: host configuration is in M33 target, controller configuration is
|
||||
in M0+ target. There is currently no way to automatically synchronize both, so
|
||||
care needs to be taken when enabling features in either of targets.
|
||||
|
||||
A possible workaround is to use separate `.yml` file with all the NimBLE syscfg
|
||||
values settings and include it in both targets using `$import` directive which
|
||||
is supported by recent versions of `newt` tool.
|
||||
|
||||
### Advanced settings
|
||||
|
||||
(tbd)
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_XCVR_
|
||||
#define H_BLE_XCVR_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XCVR_TX_SCHED_DELAY_USECS (250)
|
||||
|
||||
/*
|
||||
* Define HW whitelist size. This is the total possible whitelist size;
|
||||
* not necessarily the size that will be used (may be smaller)
|
||||
*/
|
||||
#define BLE_HW_WHITE_LIST_SIZE (8)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_BLE_XCVR_ */
|
@ -0,0 +1,33 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
pkg.name: nimble/drivers/dialog_cmac
|
||||
pkg.description: BLE driver for Dialog CMAC
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
- ble
|
||||
- bluetooth
|
||||
pkg.deps:
|
||||
- "@apache-mynewt-nimble/nimble/controller"
|
||||
- "@apache-mynewt-core/crypto/tinycrypt"
|
||||
pkg.apis:
|
||||
- ble_driver
|
||||
pkg.req_apis:
|
||||
- ble_transport
|
@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include "mcu/mcu.h"
|
||||
#include "nimble/ble.h"
|
||||
#include "controller/ble_hw.h"
|
||||
#include "CMAC.h"
|
||||
#include "cmac_driver/cmac_shared.h"
|
||||
#include "mcu/mcu.h"
|
||||
#include "tinycrypt/aes.h"
|
||||
|
||||
static struct tc_aes_key_sched_struct g_ctx;
|
||||
|
||||
int
|
||||
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
|
||||
{
|
||||
cmac_rand_set_isr_cb(cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_rng_start(void)
|
||||
{
|
||||
/* Chime the M33 in case we need random numbers generated */
|
||||
cmac_rand_start();
|
||||
CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CMAC2SYS_IRQ_SET_Msk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_rng_stop(void)
|
||||
{
|
||||
cmac_rand_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BLE_HW_RESOLV_LIST_SIZE (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
|
||||
|
||||
struct ble_hw_resolv_irk {
|
||||
uint32_t key[4];
|
||||
};
|
||||
|
||||
struct ble_hw_resolv_list {
|
||||
uint8_t count;
|
||||
struct ble_hw_resolv_irk irk[BLE_HW_RESOLV_LIST_SIZE];
|
||||
};
|
||||
|
||||
struct ble_hw_resolv_proc {
|
||||
uint32_t hash;
|
||||
uint8_t f_configured;
|
||||
uint8_t f_active;
|
||||
uint8_t f_match;
|
||||
uint8_t f_done;
|
||||
struct ble_hw_resolv_irk *irk;
|
||||
struct ble_hw_resolv_irk *irk_end;
|
||||
uint32_t crypto_prand_in[4];
|
||||
uint32_t crypto_e_out[4];
|
||||
};
|
||||
|
||||
static struct ble_hw_resolv_list g_ble_hw_resolv_list;
|
||||
static struct ble_hw_resolv_proc g_ble_hw_resolv_proc;
|
||||
|
||||
int
|
||||
ble_hw_get_public_addr(ble_addr_t *addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_get_static_addr(ble_addr_t *addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_whitelist_clear(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ble_hw_whitelist_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_whitelist_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ble_hw_whitelist_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_whitelist_match(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
|
||||
{
|
||||
uint32_t in_addr;
|
||||
uint32_t out_addr;
|
||||
|
||||
/*
|
||||
* The following code bears some explanation. This function is called by
|
||||
* the LL task to encrypt blocks and calculate session keys. Address
|
||||
* resolution also calls this function. Furthermore, during connections,
|
||||
* the M0 crypto accelerator is used but this function is not called when
|
||||
* using it. During the entire connection event, the M0 crypto block cannot
|
||||
* be used as the crypto state (some of it) needs to remain un-changed.
|
||||
* Note that this is also true when address resolution is enabled: the
|
||||
* HW crypto block is set up and cannot be modified.
|
||||
*
|
||||
* Rather than attempt to share the M0 crypto block between the various
|
||||
* controller features which require it, we decided to use software to
|
||||
* perform the encryption task for anything being done at the link-layer
|
||||
* (outside of an ISR). If this function is called inside an ISR, and it
|
||||
* is when resolving addresses, the crypto accelerator is not being used
|
||||
* by a connection event. Thus, we check to see if we are inside of an ISR.
|
||||
* If so, we use the M0 crypto block. If outside of an ISR, we use the M33
|
||||
*/
|
||||
if (!os_arch_in_isr()) {
|
||||
tc_aes128_set_encrypt_key(&g_ctx, ecb->key);
|
||||
tc_aes_encrypt(ecb->cipher_text, ecb->plain_text, &g_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Need to retain state of in/out pointers */
|
||||
in_addr = CMAC->CM_CRYPTO_IN_ADR2_REG;
|
||||
out_addr = CMAC->CM_CRYPTO_OUT_ADR_REG;
|
||||
|
||||
while (CMAC->CM_CRYPTO_STAT_REG & CMAC_CM_CRYPTO_STAT_REG_CM_CRYPTO_BUSY_Msk);
|
||||
|
||||
/* RECB, memory in/out, encryption */
|
||||
CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ECB_ENC_EN_Msk |
|
||||
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_IN_SEL_Msk |
|
||||
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_OUT_SEL_Msk |
|
||||
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ENC_DECN_Msk;
|
||||
|
||||
CMAC->CM_CRYPTO_KEY_31_0_REG = get_le32(&ecb->key[0]);
|
||||
CMAC->CM_CRYPTO_KEY_63_32_REG = get_le32(&ecb->key[4]);
|
||||
CMAC->CM_CRYPTO_KEY_95_64_REG = get_le32(&ecb->key[8]);
|
||||
CMAC->CM_CRYPTO_KEY_127_96_REG = get_le32(&ecb->key[12]);
|
||||
CMAC->CM_CRYPTO_IN_ADR2_REG = (uint32_t)ecb->plain_text;
|
||||
CMAC->CM_CRYPTO_OUT_ADR_REG = (uint32_t)ecb->cipher_text;
|
||||
|
||||
CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
|
||||
CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
|
||||
while (!(CMAC->CM_EXC_STAT_REG & CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk));
|
||||
CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
|
||||
|
||||
CMAC->CM_CRYPTO_IN_ADR2_REG = in_addr;
|
||||
CMAC->CM_CRYPTO_OUT_ADR_REG = out_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_resolv_list_clear(void)
|
||||
{
|
||||
g_ble_hw_resolv_list.count = 0;
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_resolv_list_add(uint8_t *irk)
|
||||
{
|
||||
struct ble_hw_resolv_irk *e;
|
||||
|
||||
if (g_ble_hw_resolv_list.count == BLE_HW_RESOLV_LIST_SIZE) {
|
||||
return BLE_ERR_MEM_CAPACITY;
|
||||
}
|
||||
|
||||
e = &g_ble_hw_resolv_list.irk[g_ble_hw_resolv_list.count];
|
||||
/* Prepare key here so we do not need to do it during resolving */
|
||||
e->key[0] = get_le32(&irk[0]);
|
||||
e->key[1] = get_le32(&irk[4]);
|
||||
e->key[2] = get_le32(&irk[8]);
|
||||
e->key[3] = get_le32(&irk[12]);
|
||||
|
||||
g_ble_hw_resolv_list.count++;
|
||||
|
||||
return BLE_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_resolv_list_rmv(int index)
|
||||
{
|
||||
struct ble_hw_resolv_irk *e;
|
||||
|
||||
if (index < g_ble_hw_resolv_list.count) {
|
||||
g_ble_hw_resolv_list.count--;
|
||||
|
||||
e = &g_ble_hw_resolv_list.irk[index];
|
||||
memmove(e, e + 1, (g_ble_hw_resolv_list.count - index) * sizeof(e->key));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ble_hw_resolv_list_size(void)
|
||||
{
|
||||
return BLE_HW_RESOLV_LIST_SIZE;
|
||||
}
|
||||
|
||||
int
|
||||
ble_hw_resolv_list_match(void)
|
||||
{
|
||||
return g_ble_hw_resolv_proc.f_match ?
|
||||
g_ble_hw_resolv_proc.irk - g_ble_hw_resolv_list.irk : -1;
|
||||
}
|
||||
|
||||
static void
|
||||
ble_hw_resolv_proc_next(void)
|
||||
{
|
||||
void *src = &g_ble_hw_resolv_proc.irk->key;
|
||||
|
||||
if (g_ble_hw_resolv_proc.irk == g_ble_hw_resolv_proc.irk_end) {
|
||||
g_ble_hw_resolv_proc.f_done = 1;
|
||||
g_ble_hw_resolv_proc.f_active = 0;
|
||||
} else {
|
||||
__asm__ volatile (".syntax unified \n"
|
||||
" ldm %[ptr]!, {r1, r2, r3, r4} \n"
|
||||
" ldr %[ptr], =%[reg] \n"
|
||||
" stm %[ptr]!, {r1, r2, r3, r4} \n"
|
||||
: [ptr] "+l" (src)
|
||||
: [reg] "i" (&CMAC->CM_CRYPTO_KEY_31_0_REG)
|
||||
: "r1", "r2", "r3", "r4", "memory");
|
||||
|
||||
CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_resolv_proc_enable(void)
|
||||
{
|
||||
assert(!g_ble_hw_resolv_proc.f_active);
|
||||
|
||||
CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_ABORT_Msk;
|
||||
|
||||
CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ECB_ENC_EN_Msk |
|
||||
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_IN_SEL_Msk |
|
||||
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_OUT_SEL_Msk |
|
||||
CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ENC_DECN_Msk;
|
||||
|
||||
CMAC->CM_CRYPTO_IN_ADR2_REG = (uint32_t)g_ble_hw_resolv_proc.crypto_prand_in;
|
||||
CMAC->CM_CRYPTO_OUT_ADR_REG = (uint32_t)g_ble_hw_resolv_proc.crypto_e_out;
|
||||
|
||||
g_ble_hw_resolv_proc.irk = g_ble_hw_resolv_list.irk;
|
||||
g_ble_hw_resolv_proc.irk_end = g_ble_hw_resolv_list.irk +
|
||||
g_ble_hw_resolv_list.count;
|
||||
g_ble_hw_resolv_proc.f_configured = 1;
|
||||
g_ble_hw_resolv_proc.f_active = 0;
|
||||
|
||||
/*
|
||||
* It would be better to enable IRQ in ble_hw_resolv_proc_start, but this
|
||||
* would introduce a bit of latency when starting resolving procedure and
|
||||
* we need to save every us possible there in order to be able to resolve
|
||||
* RPA on time.
|
||||
*/
|
||||
NVIC_ClearPendingIRQ(CRYPTO_IRQn);
|
||||
NVIC_EnableIRQ(CRYPTO_IRQn);
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_resolv_proc_disable(void)
|
||||
{
|
||||
g_ble_hw_resolv_proc.f_configured = 0;
|
||||
g_ble_hw_resolv_proc.f_active = 0;
|
||||
g_ble_hw_resolv_proc.f_match = 0;
|
||||
g_ble_hw_resolv_proc.f_done = 1;
|
||||
|
||||
NVIC_DisableIRQ(CRYPTO_IRQn);
|
||||
}
|
||||
|
||||
void
|
||||
ble_hw_resolv_proc_start(const uint8_t *addr)
|
||||
{
|
||||
assert(g_ble_hw_resolv_proc.f_configured);
|
||||
|
||||
/* crypto_prand_in is already zeroed so prand is properly padded */
|
||||
g_ble_hw_resolv_proc.crypto_prand_in[3] = get_be24(&addr[3]) << 8;
|
||||
g_ble_hw_resolv_proc.hash = get_be24(&addr[0]);
|
||||
|
||||
g_ble_hw_resolv_proc.f_match = 0;
|
||||
g_ble_hw_resolv_proc.f_done = 0;
|
||||
g_ble_hw_resolv_proc.f_active = 1;
|
||||
|
||||
ble_hw_resolv_proc_next();
|
||||
}
|
||||
|
||||
void
|
||||
CRYPTO_IRQHandler(void)
|
||||
{
|
||||
uint32_t hash;
|
||||
|
||||
CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
|
||||
|
||||
hash = g_ble_hw_resolv_proc.crypto_e_out[3] >> 8;
|
||||
if (g_ble_hw_resolv_proc.hash == hash) {
|
||||
g_ble_hw_resolv_proc.f_active = 0;
|
||||
g_ble_hw_resolv_proc.f_match = 1;
|
||||
g_ble_hw_resolv_proc.f_done = 1;
|
||||
} else {
|
||||
g_ble_hw_resolv_proc.irk++;
|
||||
ble_hw_resolv_proc_next();
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _BLE_HW_PRIV_H_
|
||||
#define _BLE_HW_PRIV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void ble_hw_resolv_proc_enable(void);
|
||||
void ble_hw_resolv_proc_disable(void);
|
||||
void ble_hw_resolv_proc_start(const uint8_t *addr);
|
||||
|
||||
#endif /* _BLE_HW_PRIV_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,747 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "mcu/mcu.h"
|
||||
#include "mcu/cmac_timer.h"
|
||||
#include "controller/ble_phy.h"
|
||||
#include "cmac_driver/cmac_shared.h"
|
||||
#include "ble_rf_priv.h"
|
||||
|
||||
#define RF_CALIBRATION_0 (0x01)
|
||||
#define RF_CALIBRATION_1 (0x02)
|
||||
#define RF_CALIBRATION_2 (0x04)
|
||||
|
||||
static const int8_t g_ble_rf_power_lvls[] = {
|
||||
-18, -12, -8, -6, -3, -2, -1, 0, 1, 2, 3, 4, 4, 5, 6
|
||||
};
|
||||
|
||||
struct ble_phy_rf_data {
|
||||
uint8_t tx_power_cfg0;
|
||||
uint8_t tx_power_cfg1;
|
||||
uint8_t tx_power_cfg2;
|
||||
uint8_t tx_power_cfg3;
|
||||
uint32_t cal_res_1;
|
||||
uint32_t cal_res_2;
|
||||
uint32_t trim_val1_tx_1;
|
||||
uint32_t trim_val1_tx_2;
|
||||
uint32_t trim_val2_tx;
|
||||
uint32_t trim_val2_rx;
|
||||
uint8_t calibrate_req;
|
||||
};
|
||||
|
||||
static struct ble_phy_rf_data g_ble_phy_rf_data;
|
||||
|
||||
static inline uint32_t
|
||||
get_reg32(uint32_t addr)
|
||||
{
|
||||
volatile uint32_t *reg = (volatile uint32_t *)addr;
|
||||
|
||||
return *reg;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
get_reg32_bits(uint32_t addr, uint32_t mask)
|
||||
{
|
||||
volatile uint32_t *reg = (volatile uint32_t *)addr;
|
||||
|
||||
return (*reg & mask) >> __builtin_ctz(mask);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_reg8(uint32_t addr, uint8_t val)
|
||||
{
|
||||
volatile uint8_t *reg = (volatile uint8_t *)addr;
|
||||
|
||||
*reg = val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_reg16(uint32_t addr, uint16_t val)
|
||||
{
|
||||
volatile uint16_t *reg = (volatile uint16_t *)addr;
|
||||
|
||||
*reg = val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_reg32(uint32_t addr, uint32_t val)
|
||||
{
|
||||
volatile uint32_t *reg = (volatile uint32_t *)addr;
|
||||
|
||||
*reg = val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_reg32_bits(uint32_t addr, uint32_t mask, uint32_t val)
|
||||
{
|
||||
volatile uint32_t *reg = (volatile uint32_t *)addr;
|
||||
|
||||
*reg = (*reg & (~mask)) | (val << __builtin_ctz(mask));
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_reg32_mask(uint32_t addr, uint32_t mask, uint32_t val)
|
||||
{
|
||||
volatile uint32_t *reg = (volatile uint32_t *)addr;
|
||||
|
||||
*reg = (*reg & (~mask)) | (val & mask);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_reg16_mask(uint32_t addr, uint16_t mask, uint16_t val)
|
||||
{
|
||||
volatile uint16_t *reg = (volatile uint16_t *)addr;
|
||||
|
||||
*reg = (*reg & (~mask)) | (val & mask);
|
||||
}
|
||||
|
||||
static void
|
||||
delay_us(uint32_t delay_us)
|
||||
{
|
||||
while (delay_us--) {
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
|
||||
__NOP(); __NOP(); __NOP(); __NOP();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_apply_trim(volatile uint32_t *tv, unsigned len)
|
||||
{
|
||||
while (len) {
|
||||
*(volatile uint32_t *)tv[0] = tv[1];
|
||||
len -= 2;
|
||||
tv += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_apply_calibration(void)
|
||||
{
|
||||
set_reg32(0x40020094, g_ble_phy_rf_data.cal_res_1);
|
||||
if (g_ble_phy_rf_data.cal_res_2) {
|
||||
set_reg32_bits(0x40022018, 0xff800000, g_ble_phy_rf_data.cal_res_2);
|
||||
set_reg32_bits(0x40022018, 0x00007fc0, g_ble_phy_rf_data.cal_res_2);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
ble_rf_ldo_on(void)
|
||||
{
|
||||
set_reg8(0x40020004, 9);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ble_rf_ldo_off(void)
|
||||
{
|
||||
set_reg8(0x40020004, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ble_rf_rfcu_enable(void)
|
||||
{
|
||||
set_reg32_bits(0x50000010, 0x00000020, 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ble_rf_rfcu_disable(void)
|
||||
{
|
||||
set_reg32_bits(0x50000010, 0x00000020, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_rfcu_apply_recommended_settings(void)
|
||||
{
|
||||
set_reg16_mask(0x400200a0, 0x0001, 0x0001);
|
||||
set_reg16_mask(0x40021020, 0x03f0, 0x02f5);
|
||||
set_reg32_mask(0x40021018, 0x001fffff, 0x005a5809);
|
||||
set_reg32_mask(0x4002101c, 0x00001e01, 0x0040128c);
|
||||
set_reg32_mask(0x40021004, 0xffffff1f, 0x64442404);
|
||||
set_reg32_mask(0x40021008, 0xfcfcffff, 0x6b676665);
|
||||
set_reg32_mask(0x4002100c, 0x00fcfcfc, 0x9793736f);
|
||||
set_reg32_mask(0x40021010, 0x1f1f1c1f, 0x04072646);
|
||||
set_reg32_mask(0x40020000, 0x001ff000, 0x0f099820);
|
||||
set_reg16_mask(0x40020348, 0x00ff, 0x0855);
|
||||
set_reg16(0x40020350, 0x0234);
|
||||
set_reg16(0x40020354, 0x0a34);
|
||||
set_reg16(0x40020358, 0x0851);
|
||||
set_reg16(0x4002035c, 0x0a26);
|
||||
set_reg16(0x40020360, 0x0858);
|
||||
set_reg16(0x4002102c, 0xdfe7);
|
||||
set_reg32_mask(0x4002103c, 0x00c00000, 0x0024a19f);
|
||||
set_reg16_mask(0x40021000, 0x0008, 0x000b);
|
||||
set_reg16_mask(0x40020238, 0x03e0, 0x02c0);
|
||||
set_reg16_mask(0x4002023c, 0x03e0, 0x02c0);
|
||||
set_reg16_mask(0x40020244, 0x03e0, 0x0250);
|
||||
set_reg16_mask(0x40020248, 0x03e0, 0x02a0);
|
||||
set_reg16_mask(0x4002024c, 0x03e0, 0x02c0);
|
||||
set_reg16_mask(0x40020288, 0x03e0, 0x0300);
|
||||
set_reg16_mask(0x4002029c, 0x001f, 0x0019);
|
||||
set_reg16_mask(0x4002003c, 0x6000, 0x0788);
|
||||
set_reg16_mask(0x40020074, 0x7f00, 0x2007);
|
||||
set_reg32_mask(0x40020080, 0x00333330, 0x00222224);
|
||||
set_reg32_mask(0x40020068, 0x00000f0f, 0x00000f0d);
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_rfcu_apply_settings(void)
|
||||
{
|
||||
ble_rf_apply_trim(g_cmac_shared_data.trim.rfcu,
|
||||
g_cmac_shared_data.trim.rfcu_len);
|
||||
ble_rf_rfcu_apply_recommended_settings();
|
||||
}
|
||||
|
||||
static inline void
|
||||
ble_rf_synth_enable(void)
|
||||
{
|
||||
set_reg8(0x40020005, 3);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ble_rf_synth_disable(void)
|
||||
{
|
||||
set_reg8(0x40020005, 0);
|
||||
__NOP();
|
||||
__NOP();
|
||||
}
|
||||
|
||||
static bool
|
||||
ble_rf_synth_is_enabled(void)
|
||||
{
|
||||
return get_reg32_bits(0x40020004, 256);
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_synth_apply_recommended_settings(void)
|
||||
{
|
||||
set_reg32_mask(0x40022048, 0x0000000c, 0x000000d5);
|
||||
set_reg32_mask(0x40022050, 0x00000300, 0x00000300);
|
||||
set_reg16_mask(0x40022024, 0x0001, 0x0001);
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_synth_apply_settings(void)
|
||||
{
|
||||
ble_rf_apply_trim(g_cmac_shared_data.trim.synth,
|
||||
g_cmac_shared_data.trim.synth_len);
|
||||
ble_rf_synth_apply_recommended_settings();
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_calibration_0(void)
|
||||
{
|
||||
uint32_t bkp[10];
|
||||
|
||||
bkp[0] = get_reg32(0x40020208);
|
||||
bkp[1] = get_reg32(0x40020250);
|
||||
bkp[2] = get_reg32(0x40020254);
|
||||
bkp[3] = get_reg32(0x40021028);
|
||||
bkp[4] = get_reg32(0x40020020);
|
||||
bkp[5] = get_reg32(0x40020294);
|
||||
bkp[6] = get_reg32(0x4002103C);
|
||||
bkp[7] = get_reg32(0x400200A8);
|
||||
bkp[8] = get_reg32(0x40020000);
|
||||
bkp[9] = get_reg32(0x40022000);
|
||||
|
||||
set_reg32_bits(0x40020000, 0x00000002, 0);
|
||||
set_reg32_bits(0x40022000, 0x00000001, 0);
|
||||
set_reg32_mask(0x4002103C, 0x00201c00, 0x00001c00);
|
||||
set_reg32_bits(0x400200A8, 0x00000001, 1);
|
||||
set_reg8(0x40020006, 1);
|
||||
set_reg32(0x40020208, 0);
|
||||
set_reg32(0x40020250, 0);
|
||||
set_reg32(0x40020254, 0);
|
||||
set_reg32(0x40021028, 0x00F8A494);
|
||||
set_reg32(0x40020020, 8);
|
||||
set_reg32(0x40020294, 0);
|
||||
set_reg32(0x40020024, 0);
|
||||
|
||||
delay_us(5);
|
||||
if (get_reg32_bits(0x40020020, 0x00000002)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
set_reg32_bits(0x40020020, 0x00000001, 1);
|
||||
delay_us(15);
|
||||
if (!get_reg32_bits(0x40020020, 0x00000001)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
delay_us(300);
|
||||
if (get_reg32_bits(0x40020020, 0x00000001)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
set_reg32(0x40020024, 0);
|
||||
set_reg32(0x40020208, bkp[0]);
|
||||
set_reg32(0x40020250, bkp[1]);
|
||||
set_reg32(0x40020254, bkp[2]);
|
||||
set_reg32(0x40021028, bkp[3]);
|
||||
set_reg32(0x40020020, bkp[4]);
|
||||
set_reg32(0x40020294, bkp[5]);
|
||||
set_reg32(0x4002103C, bkp[6]);
|
||||
set_reg32(0x400200A8, bkp[7]);
|
||||
set_reg32(0x40020000, bkp[8]);
|
||||
set_reg32(0x40022000, bkp[9]);
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_calibration_1(void)
|
||||
{
|
||||
uint32_t bkp[12];
|
||||
uint32_t val;
|
||||
|
||||
bkp[0] = get_reg32(0x40020020);
|
||||
bkp[1] = get_reg32(0x40020208);
|
||||
bkp[2] = get_reg32(0x40020250);
|
||||
bkp[3] = get_reg32(0x40020254);
|
||||
bkp[4] = get_reg32(0x40020218);
|
||||
bkp[5] = get_reg32(0x4002021c);
|
||||
bkp[6] = get_reg32(0x40020220);
|
||||
bkp[7] = get_reg32(0x40020270);
|
||||
bkp[8] = get_reg32(0x4002027c);
|
||||
bkp[9] = get_reg32(0x4002101c);
|
||||
bkp[10] = get_reg32(0x40020000);
|
||||
bkp[11] = get_reg32(0x40022000);
|
||||
|
||||
set_reg32(0x4002103c, 0x0124a21f);
|
||||
set_reg32(0x40020208, 0);
|
||||
set_reg32(0x40020250, 0);
|
||||
set_reg32(0x40020254, 0);
|
||||
set_reg32(0x40020218, 0);
|
||||
set_reg32(0x4002021c, 0);
|
||||
set_reg32(0x40020220, 0);
|
||||
set_reg32(0x40020270, 0);
|
||||
set_reg32(0x4002027c, 0);
|
||||
set_reg32(0x40020000, 0x0f168820);
|
||||
set_reg32_bits(0x40022000, 0x00000001, 0);
|
||||
set_reg32_bits(0x4002101c, 0x00001e00, 0);
|
||||
set_reg32_bits(0x4002001c, 0x0000003f, 47);
|
||||
set_reg8(0x40020006, 1);
|
||||
set_reg32(0x40020020, 16);
|
||||
set_reg32_bits(0x4002003c, 0x00000800, 1);
|
||||
set_reg32(0x40020024, 0);
|
||||
|
||||
delay_us(5);
|
||||
if (get_reg32_bits(0x40020020, 0x00000002)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
set_reg32_bits(0x40020020, 0x00000001, 1);
|
||||
delay_us(15);
|
||||
if (!get_reg32_bits(0x40020020, 0x00000001)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
delay_us(300);
|
||||
if (get_reg32_bits(0x40020020, 0x00000001)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
val = get_reg32(0x40020090);
|
||||
set_reg32_bits(0x40020094, 0x0000000f, val);
|
||||
set_reg32_bits(0x40020094, 0x00000f00, val);
|
||||
set_reg32_bits(0x40020094, 0x000f0000, val);
|
||||
set_reg32_bits(0x40020094, 0x0f000000, val);
|
||||
g_ble_phy_rf_data.cal_res_1 = get_reg32(0x40020094);
|
||||
|
||||
done:
|
||||
set_reg32(0x40020024, 0);
|
||||
set_reg32(0x40020020, bkp[0]);
|
||||
set_reg32(0x40020208, bkp[1]);
|
||||
set_reg32(0x40020250, bkp[2]);
|
||||
set_reg32(0x40020254, bkp[3]);
|
||||
set_reg32(0x40020218, bkp[4]);
|
||||
set_reg32(0x4002021c, bkp[5]);
|
||||
set_reg32(0x40020220, bkp[6]);
|
||||
set_reg32(0x40020270, bkp[7]);
|
||||
set_reg32(0x4002027c, bkp[8]);
|
||||
set_reg32(0x4002101c, bkp[9]);
|
||||
set_reg32(0x40020000, bkp[10]);
|
||||
set_reg32(0x40022000, bkp[11]);
|
||||
set_reg32_bits(0x4002003c, 0x00000800, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_calibration_2(void)
|
||||
{
|
||||
uint32_t bkp[2];
|
||||
uint32_t k1;
|
||||
|
||||
set_reg8(0x40020005, 3);
|
||||
set_reg32(0x40022000, 0x00000300);
|
||||
set_reg32_bits(0x40022004, 0x0000007f, 20);
|
||||
bkp[0] = get_reg32(0x40022040);
|
||||
set_reg32(0x40022040, 0xffffffff);
|
||||
set_reg32_bits(0x40022018, 0x0000003f, 0);
|
||||
set_reg32_bits(0x40022018, 0x00008000, 0);
|
||||
set_reg32_bits(0x4002201c, 0x00000600, 2);
|
||||
set_reg32_bits(0x4002201c, 0x00000070, 4);
|
||||
set_reg32_bits(0x40022030, 0x3f000000, 22);
|
||||
set_reg32_bits(0x40022030, 0x00000fc0, 24);
|
||||
set_reg32_bits(0x40022030, 0x0000003f, 24);
|
||||
set_reg8(0x4002201c, 0x43);
|
||||
set_reg8(0x40020006, 2);
|
||||
delay_us(2);
|
||||
bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
|
||||
set_reg32_bits(0x4002024c, 0x000003e0, 0);
|
||||
set_reg8(0x40020006, 1);
|
||||
set_reg32_bits(0x400200ac, 0x00000003, 3);
|
||||
delay_us(30);
|
||||
delay_us(100);
|
||||
set_reg8(0x40020005, 3);
|
||||
k1 = get_reg32_bits(0x40022088, 0x000001ff);
|
||||
set_reg32(0x400200ac, 0);
|
||||
delay_us(20);
|
||||
set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
|
||||
delay_us(10);
|
||||
|
||||
set_reg32_bits(0x40022018, 0xff800000, k1);
|
||||
set_reg32_bits(0x40022018, 0x00007fc0, k1);
|
||||
set_reg8(0x4002201c, 0x41);
|
||||
set_reg32_bits(0x4002201c, 0x00000600, 2);
|
||||
set_reg8(0x40020006, 2);
|
||||
delay_us(2);
|
||||
bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
|
||||
set_reg32_bits(0x4002024c, 0x000003e0, 0);
|
||||
set_reg8(0x40020006, 1);
|
||||
set_reg32_bits(0x400200ac, 0x00000003, 3);
|
||||
delay_us(30);
|
||||
delay_us(100);
|
||||
set_reg8(0x40020005, 3);
|
||||
k1 = get_reg32_bits(0x40022088, 0x1ff);
|
||||
set_reg32(0x400200ac, 0);
|
||||
delay_us(20);
|
||||
set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
|
||||
delay_us(10);
|
||||
|
||||
set_reg32_bits(0x40022018, 0xff800000, k1);
|
||||
set_reg32_bits(0x40022018, 0x00007fc0, k1);
|
||||
set_reg8(0x4002201c, 0x41);
|
||||
set_reg32_bits(0x4002201c, 0x00000600, 2);
|
||||
set_reg8(0x40020006, 2);
|
||||
delay_us(2);
|
||||
bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
|
||||
set_reg32_bits(0x4002024c, 0x000003e0, 0);
|
||||
set_reg8(0x40020006, 1);
|
||||
set_reg32_bits(0x400200ac, 0x00000003, 3);
|
||||
delay_us(30);
|
||||
delay_us(100);
|
||||
set_reg8(0x40020005, 3);
|
||||
k1 = get_reg32_bits(0x40022088, 0x000001ff);
|
||||
set_reg32_bits(0x40022018, 0xff800000, k1);
|
||||
set_reg32_bits(0x40022018, 0x00007fc0, k1);
|
||||
set_reg32_bits(0x4002201c, 0x00000001, 0);
|
||||
set_reg32(0x40022040, bkp[0]);
|
||||
set_reg32_bits(0x40022018, 0x0000003f, 0x1c);
|
||||
set_reg32_bits(0x40022018, 0x00008000, 0);
|
||||
set_reg32_bits(0x40022030, 0x3f000000, 28);
|
||||
set_reg32_bits(0x40022030, 0x00000fc0, 30);
|
||||
set_reg32_bits(0x40022030, 0x0000003f, 30);
|
||||
set_reg32(0x400200ac, 0);
|
||||
delay_us(20);
|
||||
set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
|
||||
delay_us(10);
|
||||
|
||||
g_ble_phy_rf_data.cal_res_2 = k1;
|
||||
}
|
||||
|
||||
static void
|
||||
ble_rf_calibrate_int(uint8_t mask)
|
||||
{
|
||||
__disable_irq();
|
||||
|
||||
ble_rf_enable();
|
||||
delay_us(20);
|
||||
|
||||
ble_rf_synth_disable();
|
||||
ble_rf_synth_enable();
|
||||
ble_rf_synth_apply_settings();
|
||||
set_reg8(0x40020005, 1);
|
||||
|
||||
if (mask & RF_CALIBRATION_0) {
|
||||
ble_rf_calibration_0();
|
||||
}
|
||||
if (mask & RF_CALIBRATION_1) {
|
||||
ble_rf_calibration_1();
|
||||
}
|
||||
if (mask & RF_CALIBRATION_2) {
|
||||
ble_rf_calibration_2();
|
||||
}
|
||||
|
||||
ble_rf_disable();
|
||||
|
||||
__enable_irq();
|
||||
|
||||
#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
|
||||
g_cmac_shared_data.debug.cal_res_1 = g_ble_phy_rf_data.cal_res_1;
|
||||
g_cmac_shared_data.debug.cal_res_2 = g_ble_phy_rf_data.cal_res_2;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ble_rf_try_recalibrate(uint32_t idle_time_us)
|
||||
{
|
||||
/* Run recalibration if we have at least 1ms of time to spare and RF is
|
||||
* currently disabled. Calibration is much shorter than 1ms, but that gives
|
||||
* us good margin to make sure we can finish before next event.
|
||||
*/
|
||||
if (!g_ble_phy_rf_data.calibrate_req || (idle_time_us < 1000) ||
|
||||
ble_rf_is_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ble_rf_calibrate_int(RF_CALIBRATION_2);
|
||||
|
||||
g_ble_phy_rf_data.calibrate_req = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ble_rf_find_trim_reg(volatile uint32_t *tv, unsigned len, uint32_t reg)
|
||||
{
|
||||
while (len) {
|
||||
if (tv[0] == reg) {
|
||||
return tv[1];
|
||||
}
|
||||
len -= 2;
|
||||
tv += 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_init(void)
|
||||
{
|
||||
static bool done = false;
|
||||
uint32_t val;
|
||||
|
||||
ble_rf_disable();
|
||||
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode1,
|
||||
g_cmac_shared_data.trim.rfcu_mode1_len,
|
||||
0x4002004c);
|
||||
g_ble_phy_rf_data.trim_val1_tx_1 = val;
|
||||
|
||||
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode2,
|
||||
g_cmac_shared_data.trim.rfcu_mode2_len,
|
||||
0x4002004c);
|
||||
g_ble_phy_rf_data.trim_val1_tx_2 = val;
|
||||
|
||||
if (!g_ble_phy_rf_data.trim_val1_tx_1 || !g_ble_phy_rf_data.trim_val1_tx_2) {
|
||||
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu,
|
||||
g_cmac_shared_data.trim.rfcu_len,
|
||||
0x4002004c);
|
||||
if (!val) {
|
||||
val = 0x0300;
|
||||
}
|
||||
g_ble_phy_rf_data.trim_val1_tx_1 = val;
|
||||
g_ble_phy_rf_data.trim_val1_tx_2 = val;
|
||||
}
|
||||
|
||||
val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.synth,
|
||||
g_cmac_shared_data.trim.synth_len,
|
||||
0x40022038);
|
||||
if (!val) {
|
||||
val = 0x0198ff03;
|
||||
}
|
||||
g_ble_phy_rf_data.trim_val2_rx = val;
|
||||
g_ble_phy_rf_data.trim_val2_tx = val;
|
||||
set_reg32_bits((uint32_t)&g_ble_phy_rf_data.trim_val2_tx, 0x0001ff00, 0x87);
|
||||
|
||||
#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
|
||||
g_cmac_shared_data.debug.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1;
|
||||
g_cmac_shared_data.debug.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2;
|
||||
g_cmac_shared_data.debug.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx;
|
||||
g_cmac_shared_data.debug.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx;
|
||||
#endif
|
||||
|
||||
ble_rf_rfcu_enable();
|
||||
ble_rf_rfcu_apply_settings();
|
||||
g_ble_phy_rf_data.tx_power_cfg1 = get_reg32_bits(0x500000a4, 0xf0);
|
||||
g_ble_phy_rf_data.tx_power_cfg2 = get_reg32_bits(0x40020238, 0x000003e0);
|
||||
g_ble_phy_rf_data.tx_power_cfg3 = 0;
|
||||
ble_rf_rfcu_disable();
|
||||
|
||||
ble_rf_calibrate_int(RF_CALIBRATION_0 | RF_CALIBRATION_1 | RF_CALIBRATION_2);
|
||||
|
||||
done = true;
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_enable(void)
|
||||
{
|
||||
if (ble_rf_is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ble_rf_rfcu_enable();
|
||||
ble_rf_rfcu_apply_settings();
|
||||
ble_rf_ldo_on();
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_configure(void)
|
||||
{
|
||||
if (ble_rf_synth_is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ble_rf_synth_enable();
|
||||
ble_rf_synth_apply_settings();
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_stop(void)
|
||||
{
|
||||
ble_rf_synth_disable();
|
||||
set_reg8(0x40020006, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_disable(void)
|
||||
{
|
||||
ble_rf_stop();
|
||||
ble_rf_ldo_off();
|
||||
ble_rf_rfcu_disable();
|
||||
}
|
||||
|
||||
bool
|
||||
ble_rf_is_enabled(void)
|
||||
{
|
||||
return get_reg32_bits(0x40020008, 5) == 5;
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_calibrate_req(void)
|
||||
{
|
||||
g_ble_phy_rf_data.calibrate_req = 1;
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_setup_tx(uint8_t rf_chan, uint8_t phy_mode)
|
||||
{
|
||||
set_reg32_bits(0x40020000, 0x0f000000, g_ble_phy_rf_data.tx_power_cfg0);
|
||||
set_reg32_bits(0x500000a4, 0x000000f0, g_ble_phy_rf_data.tx_power_cfg1);
|
||||
set_reg32_bits(0x40020238, 0x000003e0, g_ble_phy_rf_data.tx_power_cfg2);
|
||||
set_reg32_bits(0x40020234, 0x000003e0, g_ble_phy_rf_data.tx_power_cfg3);
|
||||
|
||||
if (g_ble_phy_rf_data.tx_power_cfg0 < 13) {
|
||||
set_reg32(0x4002004c, g_ble_phy_rf_data.trim_val1_tx_1);
|
||||
} else {
|
||||
set_reg32(0x4002004c, g_ble_phy_rf_data.trim_val1_tx_2);
|
||||
}
|
||||
set_reg8(0x40020005, 3);
|
||||
set_reg8(0x40022004, rf_chan);
|
||||
if (phy_mode == BLE_PHY_MODE_2M) {
|
||||
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
|
||||
set_reg32(0x40022000, 0x00000303);
|
||||
#else
|
||||
set_reg32(0x40022000, 0x00000003);
|
||||
#endif
|
||||
} else {
|
||||
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
|
||||
set_reg32(0x40022000, 0x00000300);
|
||||
#else
|
||||
set_reg32(0x40022000, 0x00000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
ble_rf_apply_calibration();
|
||||
|
||||
set_reg32_bits(0x40022050, 0x00000200, 1);
|
||||
set_reg32_bits(0x40022050, 0x00000100, 0);
|
||||
set_reg32_bits(0x40022048, 0x01ffff00, 0x7700);
|
||||
set_reg32(0x40022038, g_ble_phy_rf_data.trim_val2_tx);
|
||||
|
||||
set_reg8(0x40020006, 3);
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_setup_rx(uint8_t rf_chan, uint8_t phy_mode)
|
||||
{
|
||||
set_reg32_bits(0x500000a4, 0x000000f0, g_ble_phy_rf_data.tx_power_cfg1);
|
||||
set_reg8(0x40020005, 3);
|
||||
set_reg8(0x40022004, rf_chan);
|
||||
if (phy_mode == BLE_PHY_MODE_2M) {
|
||||
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
|
||||
set_reg32(0x40022000, 0x00000303);
|
||||
set_reg32(0x40020000, 0x0f11b823);
|
||||
set_reg32(0x4002103c, 0x0125261b);
|
||||
#else
|
||||
set_reg32(0x40022000, 0x00000003);
|
||||
set_reg32(0x40020000, 0x0f0c2803);
|
||||
set_reg32(0x4002103c, 0x0125a61b);
|
||||
#endif
|
||||
set_reg32(0x40021020, 0x000002f5);
|
||||
set_reg32(0x4002102c, 0x0000d1d5);
|
||||
} else {
|
||||
#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
|
||||
set_reg32(0x40022000, 0x00000300);
|
||||
set_reg32(0x40020000, 0x0f099820);
|
||||
set_reg32(0x4002103c, 0x0124a21f);
|
||||
#else
|
||||
set_reg32(0x40022000, 0x00000000);
|
||||
set_reg32(0x40020000, 0x0f062800);
|
||||
set_reg32(0x4002103c, 0x01051e1f);
|
||||
#endif
|
||||
set_reg32(0x40021020, 0x000002f5);
|
||||
set_reg32(0x4002102c, 0x0000dfe7);
|
||||
}
|
||||
|
||||
ble_rf_apply_calibration();
|
||||
|
||||
set_reg32_bits(0x40022050, 0x00000200, 1);
|
||||
set_reg32_bits(0x40022050, 0x00000100, 1);
|
||||
set_reg32_bits(0x40022048, 0x01ffff00, 0);
|
||||
set_reg32(0x40022038, g_ble_phy_rf_data.trim_val2_rx);
|
||||
|
||||
set_reg8(0x40020006, 3);
|
||||
}
|
||||
|
||||
void
|
||||
ble_rf_set_tx_power(int dbm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(g_ble_rf_power_lvls); i++) {
|
||||
if (g_ble_rf_power_lvls[i] >= dbm) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_ble_phy_rf_data.tx_power_cfg0 = i + 1;
|
||||
}
|
||||
|
||||
int8_t
|
||||
ble_rf_get_rssi(void)
|
||||
{
|
||||
return (501 * get_reg32_bits(0x40021038, 0x000003ff) - 493000) / 4096;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _BLE_RF_PRIV_H_
|
||||
#define _BLE_RF_PRIV_H_
|
||||
|
||||
void ble_rf_init(void);
|
||||
void ble_rf_enable(void);
|
||||
void ble_rf_stop(void);
|
||||
void ble_rf_disable(void);
|
||||
bool ble_rf_is_enabled(void);
|
||||
void ble_rf_configure(void);
|
||||
|
||||
void ble_rf_calibrate(void);
|
||||
|
||||
void ble_rf_setup_tx(uint8_t rf_chan, uint8_t mode);
|
||||
void ble_rf_setup_rx(uint8_t rf_chan, uint8_t mode);
|
||||
|
||||
void ble_rf_set_tx_power(int dbm);
|
||||
int8_t ble_rf_get_rssi(void);
|
||||
|
||||
#endif /* _BLE_RF_PRIV_H_ */
|
@ -0,0 +1,29 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
syscfg.defs:
|
||||
BLE_PHY_RF_HP_MODE:
|
||||
description: Enable high-performance RF mode.
|
||||
value: 1
|
||||
|
||||
BLE_PHY_DEBUG_DSER:
|
||||
description: Enable DSER output from PHY
|
||||
value: 0
|
||||
|
||||
syscfg.restrictions:
|
||||
- BLE_LL_RFMGMT_ENABLE_TIME == 0 || BLE_LL_RFMGMT_ENABLE_TIME >= 20
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_XCVR_
|
||||
#define H_BLE_XCVR_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XCVR_RX_RADIO_RAMPUP_USECS (40)
|
||||
#define XCVR_TX_RADIO_RAMPUP_USECS (40)
|
||||
|
||||
/*
|
||||
* NOTE: we have to account for the RTC output compare issue. We want it to be
|
||||
* 5 ticks.
|
||||
*/
|
||||
#define XCVR_PROC_DELAY_USECS (153)
|
||||
#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS)
|
||||
#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS)
|
||||
#define XCVR_TX_SCHED_DELAY_USECS (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
|
||||
#define XCVR_RX_SCHED_DELAY_USECS (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
|
||||
|
||||
/*
|
||||
* Define HW whitelist size. This is the total possible whitelist size;
|
||||
* not necessarily the size that will be used (may be smaller)
|
||||
*/
|
||||
#define BLE_HW_WHITE_LIST_SIZE (8)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_BLE_XCVR_ */
|
@ -0,0 +1,31 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
pkg.name: nimble/drivers/nrf5340
|
||||
pkg.description: BLE driver for nRF5340 systems.
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
- ble
|
||||
- bluetooth
|
||||
|
||||
pkg.apis: ble_driver
|
||||
pkg.deps:
|
||||
- nimble
|
||||
- nimble/controller
|
@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <syscfg/syscfg.h>
|
||||
#include <os/os.h>
|
||||
#include <nimble/ble.h>
|
||||
#include <nimble/nimble_opt.h>
|
||||
#include <controller/ble_hw.h>
|
||||
|
||||
#include <ble/xcvr.h>
|
||||
#include <mcu/cmsis_nvic.h>
|
||||
#include <os/os_trace_api.h>
|
||||
|
||||
/* Total number of resolving list elements */
|
||||
#define BLE_HW_RESOLV_LIST_SIZE (16)
|
||||
|
||||
/* We use this to keep track of which entries are set to valid addresses */
|
||||
static uint8_t g_ble_hw_whitelist_mask;
|
||||
|
||||
/* Random number generator isr callback */
|
||||
static ble_rng_isr_cb_t ble_rng_isr_cb;
|
||||
|
||||
/* If LL privacy is enabled, allocate memory for AAR */
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
|
||||
|
||||
/* The NRF5340 supports up to 16 IRK entries */
|
||||
#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
|
||||
#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
|
||||
#else
|
||||
#define NRF_IRK_LIST_ENTRIES (16)
|
||||
#endif
|
||||
|
||||
/* NOTE: each entry is 16 bytes long. */
|
||||
uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
|
||||
|
||||
/* Current number of IRK entries */
|
||||
uint8_t g_nrf_num_irks;
|
||||
|
||||
#endif
|
||||
|
||||
/* Returns public device address or -1 if not present */
|
||||
int
|
||||
ble_hw_get_public_addr(ble_addr_t *addr)
|
||||
{
|
||||
uint32_t addr_high;
|
||||
uint32_t addr_low;
|
||||
|
||||
/* Does FICR have a public address */
|
||||
if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy into device address. We can do this because we know platform */
|
||||
addr_low = NRF_FICR_NS->DEVICEADDR[0];
|
||||
addr_high = NRF_FICR_NS->DEVICEADDR[1];
|
||||
memcpy(addr->val, &addr_low, 4);
|
||||
memcpy(&addr->val[4], &addr_high, 2);
|
||||
addr->type = BLE_ADDR_PUBLIC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns random static address or -1 if not present */
|
||||
int
|
||||
ble_hw_get_static_addr(ble_addr_t *addr)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) == 1) {
|
||||
memcpy(addr->val, (void *)&NRF_FICR_NS->DEVICEADDR[0], 4);
|
||||
memcpy(&addr->val[4], (void *)&NRF_FICR_NS->DEVICEADDR[1], 2);
|
||||
addr->val[5] |= 0xc0;
|
||||
addr->type = BLE_ADDR_RANDOM;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the whitelist
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
void
|
||||
ble_hw_whitelist_clear(void)
|
||||
{
|
||||
NRF_RADIO_NS->DACNF = 0;
|
||||
g_ble_hw_whitelist_mask = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a device to the hw whitelist
|
||||
*
|
||||
* @param addr
|
||||
* @param addr_type
|
||||
*
|
||||
* @return int 0: success, BLE error code otherwise
|
||||
*/
|
||||
int
|
||||
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
|
||||
{
|
||||
int i;
|
||||
uint32_t mask;
|
||||
|
||||
/* Find first ununsed device address match element */
|
||||
mask = 0x01;
|
||||
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
|
||||
if ((mask & g_ble_hw_whitelist_mask) == 0) {
|
||||
NRF_RADIO_NS->DAB[i] = get_le32(addr);
|
||||
NRF_RADIO_NS->DAP[i] = get_le16(addr + 4);
|
||||
if (addr_type == BLE_ADDR_RANDOM) {
|
||||
NRF_RADIO_NS->DACNF |= (mask << 8);
|
||||
}
|
||||
g_ble_hw_whitelist_mask |= mask;
|
||||
return BLE_ERR_SUCCESS;
|
||||
}
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
return BLE_ERR_MEM_CAPACITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a device from the hw whitelist
|
||||
*
|
||||
* @param addr
|
||||
* @param addr_type
|
||||
*
|
||||
*/
|
||||
void
|
||||
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
|
||||
{
|
||||
int i;
|
||||
uint16_t dap;
|
||||
uint16_t txadd;
|
||||
uint32_t dab;
|
||||
uint32_t mask;
|
||||
|
||||
/* Find first ununsed device address match element */
|
||||
dab = get_le32(addr);
|
||||
dap = get_le16(addr + 4);
|
||||
txadd = NRF_RADIO_NS->DACNF >> 8;
|
||||
mask = 0x01;
|
||||
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
|
||||
if (mask & g_ble_hw_whitelist_mask) {
|
||||
if ((dab == NRF_RADIO_NS->DAB[i]) && (dap == NRF_RADIO_NS->DAP[i])) {
|
||||
if (addr_type == !!(txadd & mask)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
if (i < BLE_HW_WHITE_LIST_SIZE) {
|
||||
g_ble_hw_whitelist_mask &= ~mask;
|
||||
NRF_RADIO_NS->DACNF &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the whitelist in HW
|
||||
*
|
||||
* @return int Number of devices allowed in whitelist
|
||||
*/
|
||||
uint8_t
|
||||
ble_hw_whitelist_size(void)
|
||||
{
|
||||
return BLE_HW_WHITE_LIST_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the whitelisted devices
|
||||
*/
|
||||
void
|
||||
ble_hw_whitelist_enable(void)
|
||||
{
|
||||
/* Enable the configured device addresses */
|
||||
NRF_RADIO_NS->DACNF |= g_ble_hw_whitelist_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the whitelisted devices
|
||||
*/
|
||||
void
|
||||
ble_hw_whitelist_disable(void)
|
||||
{
|
||||
/* Disable all whitelist devices */
|
||||
NRF_RADIO_NS->DACNF &= 0x0000ff00;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boolean function which returns true ('1') if there is a match on the
|
||||
* whitelist.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int
|
||||
ble_hw_whitelist_match(void)
|
||||
{
|
||||
return NRF_RADIO_NS->EVENTS_DEVMATCH;
|
||||
}
|
||||
|
||||
/* Encrypt data */
|
||||
int
|
||||
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
|
||||
{
|
||||
int rc;
|
||||
uint32_t end;
|
||||
uint32_t err;
|
||||
|
||||
/* Stop ECB */
|
||||
NRF_ECB_NS->TASKS_STOPECB = 1;
|
||||
/* XXX: does task stop clear these counters? Anyway to do this quicker? */
|
||||
NRF_ECB_NS->EVENTS_ENDECB = 0;
|
||||
NRF_ECB_NS->EVENTS_ERRORECB = 0;
|
||||
NRF_ECB_NS->ECBDATAPTR = (uint32_t)ecb;
|
||||
|
||||
/* Start ECB */
|
||||
NRF_ECB_NS->TASKS_STARTECB = 1;
|
||||
|
||||
/* Wait till error or done */
|
||||
rc = 0;
|
||||
while (1) {
|
||||
end = NRF_ECB_NS->EVENTS_ENDECB;
|
||||
err = NRF_ECB_NS->EVENTS_ERRORECB;
|
||||
if (end || err) {
|
||||
if (err) {
|
||||
rc = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Random number generator ISR.
|
||||
*/
|
||||
static void
|
||||
ble_rng_isr(void)
|
||||
{
|
||||
uint8_t rnum;
|
||||
|
||||
os_trace_isr_enter();
|
||||
|
||||
/* No callback? Clear and disable interrupts */
|
||||
if (ble_rng_isr_cb == NULL) {
|
||||
NRF_RNG_NS->INTENCLR = 1;
|
||||
NRF_RNG_NS->EVENTS_VALRDY = 0;
|
||||
(void)NRF_RNG_NS->SHORTS;
|
||||
os_trace_isr_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is a value ready grab it */
|
||||
if (NRF_RNG_NS->EVENTS_VALRDY) {
|
||||
NRF_RNG_NS->EVENTS_VALRDY = 0;
|
||||
rnum = (uint8_t)NRF_RNG_NS->VALUE;
|
||||
(*ble_rng_isr_cb)(rnum);
|
||||
}
|
||||
|
||||
os_trace_isr_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the random number generator
|
||||
*
|
||||
* @param cb
|
||||
* @param bias
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int
|
||||
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
|
||||
{
|
||||
/* Set bias */
|
||||
if (bias) {
|
||||
NRF_RNG_NS->CONFIG = 1;
|
||||
} else {
|
||||
NRF_RNG_NS->CONFIG = 0;
|
||||
}
|
||||
|
||||
/* If we were passed a function pointer we need to enable the interrupt */
|
||||
if (cb != NULL) {
|
||||
#ifndef RIOT_VERSION
|
||||
NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
|
||||
#endif
|
||||
#if MYNEWT
|
||||
NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
|
||||
#else
|
||||
ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
|
||||
#endif
|
||||
NVIC_EnableIRQ(RNG_IRQn);
|
||||
ble_rng_isr_cb = cb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the random number generator
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int
|
||||
ble_hw_rng_start(void)
|
||||
{
|
||||
os_sr_t sr;
|
||||
|
||||
/* No need for interrupt if there is no callback */
|
||||
OS_ENTER_CRITICAL(sr);
|
||||
NRF_RNG_NS->EVENTS_VALRDY = 0;
|
||||
if (ble_rng_isr_cb) {
|
||||
NRF_RNG_NS->INTENSET = 1;
|
||||
}
|
||||
NRF_RNG_NS->TASKS_START = 1;
|
||||
OS_EXIT_CRITICAL(sr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the random generator
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int
|
||||
ble_hw_rng_stop(void)
|
||||
{
|
||||
os_sr_t sr;
|
||||
|
||||
/* No need for interrupt if there is no callback */
|
||||
OS_ENTER_CRITICAL(sr);
|
||||
NRF_RNG_NS->INTENCLR = 1;
|
||||
NRF_RNG_NS->TASKS_STOP = 1;
|
||||
NRF_RNG_NS->EVENTS_VALRDY = 0;
|
||||
OS_EXIT_CRITICAL(sr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the random number generator.
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t
|
||||
ble_hw_rng_read(void)
|
||||
{
|
||||
uint8_t rnum;
|
||||
|
||||
/* Wait for a sample */
|
||||
while (NRF_RNG_NS->EVENTS_VALRDY == 0) {
|
||||
}
|
||||
|
||||
NRF_RNG_NS->EVENTS_VALRDY = 0;
|
||||
rnum = (uint8_t)NRF_RNG_NS->VALUE;
|
||||
|
||||
return rnum;
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
|
||||
/**
|
||||
* Clear the resolving list
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
void
|
||||
ble_hw_resolv_list_clear(void)
|
||||
{
|
||||
g_nrf_num_irks = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a device to the hw resolving list
|
||||
*
|
||||
* @param irk Pointer to IRK to add
|
||||
*
|
||||
* @return int 0: success, BLE error code otherwise
|
||||
*/
|
||||
int
|
||||
ble_hw_resolv_list_add(uint8_t *irk)
|
||||
{
|
||||
uint32_t *nrf_entry;
|
||||
|
||||
/* Find first ununsed device address match element */
|
||||
if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
|
||||
return BLE_ERR_MEM_CAPACITY;
|
||||
}
|
||||
|
||||
/* Copy into irk list */
|
||||
nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
|
||||
memcpy(nrf_entry, irk, 16);
|
||||
|
||||
/* Add to total */
|
||||
++g_nrf_num_irks;
|
||||
return BLE_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a device from the hw resolving list
|
||||
*
|
||||
* @param index Index of IRK to remove
|
||||
*/
|
||||
void
|
||||
ble_hw_resolv_list_rmv(int index)
|
||||
{
|
||||
uint32_t *irk_entry;
|
||||
|
||||
if (index < g_nrf_num_irks) {
|
||||
--g_nrf_num_irks;
|
||||
irk_entry = &g_nrf_irk_list[index];
|
||||
if (g_nrf_num_irks > index) {
|
||||
memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the resolving list. NOTE: this returns the maximum
|
||||
* allowable entries in the HW. Configuration options may limit this.
|
||||
*
|
||||
* @return int Number of devices allowed in resolving list
|
||||
*/
|
||||
uint8_t
|
||||
ble_hw_resolv_list_size(void)
|
||||
{
|
||||
return BLE_HW_RESOLV_LIST_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to determine if the address received was resolved.
|
||||
*
|
||||
* @return int Negative values indicate unresolved address; positive values
|
||||
* indicate index in resolving list of resolved address.
|
||||
*/
|
||||
int
|
||||
ble_hw_resolv_list_match(void)
|
||||
{
|
||||
uint32_t index;
|
||||
|
||||
if (NRF_AAR_NS->EVENTS_END) {
|
||||
if (NRF_AAR_NS->EVENTS_RESOLVED) {
|
||||
index = NRF_AAR_NS->STATUS;
|
||||
return (int)index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <syscfg/syscfg.h>
|
||||
#include <os/os_trace_api.h>
|
||||
|
||||
#if MYNEWT_VAL(BLE_PHY_SYSVIEW)
|
||||
|
||||
static os_trace_module_t g_ble_phy_trace_mod;
|
||||
uint32_t ble_phy_trace_off;
|
||||
|
||||
static void
|
||||
ble_phy_trace_module_send_desc(void)
|
||||
{
|
||||
os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u");
|
||||
os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u");
|
||||
os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable");
|
||||
}
|
||||
|
||||
void
|
||||
ble_phy_trace_init(void)
|
||||
{
|
||||
ble_phy_trace_off =
|
||||
os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3,
|
||||
ble_phy_trace_module_send_desc);
|
||||
}
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
syscfg.defs:
|
||||
BLE_PHY_SYSVIEW:
|
||||
description: >
|
||||
Enable SystemView tracing module for radio driver.
|
||||
value: 0
|
@ -0,0 +1,409 @@
|
||||
/* atomic operations */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997-2015, Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ATOMIC_H__
|
||||
#define __ATOMIC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef int atomic_t;
|
||||
typedef atomic_t atomic_val_t;
|
||||
|
||||
/**
|
||||
* @defgroup atomic_apis Atomic Services APIs
|
||||
* @ingroup kernel_apis
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Atomic compare-and-set.
|
||||
*
|
||||
* This routine performs an atomic compare-and-set on @a target. If the current
|
||||
* value of @a target equals @a old_value, @a target is set to @a new_value.
|
||||
* If the current value of @a target does not equal @a old_value, @a target
|
||||
* is left unchanged.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param old_value Original value to compare against.
|
||||
* @param new_value New value to store.
|
||||
* @return 1 if @a new_value is written, 0 otherwise.
|
||||
*/
|
||||
static inline int atomic_cas(atomic_t *target, atomic_val_t old_value,
|
||||
atomic_val_t new_value)
|
||||
{
|
||||
return __atomic_compare_exchange_n(target, &old_value, new_value,
|
||||
0, __ATOMIC_SEQ_CST,
|
||||
__ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic addition.
|
||||
*
|
||||
* This routine performs an atomic addition on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to add.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic subtraction.
|
||||
*
|
||||
* This routine performs an atomic subtraction on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to subtract.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic increment.
|
||||
*
|
||||
* This routine performs an atomic increment by 1 on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_inc(atomic_t *target)
|
||||
{
|
||||
return atomic_add(target, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic decrement.
|
||||
*
|
||||
* This routine performs an atomic decrement by 1 on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_dec(atomic_t *target)
|
||||
{
|
||||
return atomic_sub(target, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic get.
|
||||
*
|
||||
* This routine performs an atomic read on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_get(const atomic_t *target)
|
||||
{
|
||||
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic get-and-set.
|
||||
*
|
||||
* This routine atomically sets @a target to @a value and returns
|
||||
* the previous value of @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to write to @a target.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
/* This builtin, as described by Intel, is not a traditional
|
||||
* test-and-set operation, but rather an atomic exchange operation. It
|
||||
* writes value into *ptr, and returns the previous contents of *ptr.
|
||||
*/
|
||||
return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic clear.
|
||||
*
|
||||
* This routine atomically sets @a target to zero and returns its previous
|
||||
* value. (Hence, it is equivalent to atomic_set(target, 0).)
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_clear(atomic_t *target)
|
||||
{
|
||||
return atomic_set(target, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise inclusive OR.
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise inclusive OR of
|
||||
* @a target and @a value.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to OR.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise exclusive OR (XOR).
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
|
||||
* @a target and @a value.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to XOR
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise AND.
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise AND of @a target
|
||||
* and @a value.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to AND.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise NAND.
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise NAND of @a target
|
||||
* and @a value. (This operation is equivalent to target = ~(target & value).)
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to NAND.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
|
||||
static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize an atomic variable.
|
||||
*
|
||||
* This macro can be used to initialize an atomic variable. For example,
|
||||
* @code atomic_t my_var = ATOMIC_INIT(75); @endcode
|
||||
*
|
||||
* @param i Value to assign to atomic variable.
|
||||
*/
|
||||
#define ATOMIC_INIT(i) (i)
|
||||
|
||||
/**
|
||||
* @cond INTERNAL_HIDDEN
|
||||
*/
|
||||
|
||||
#define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
|
||||
#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1)))
|
||||
#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
|
||||
|
||||
/**
|
||||
* INTERNAL_HIDDEN @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Define an array of atomic variables.
|
||||
*
|
||||
* This macro defines an array of atomic variables containing at least
|
||||
* @a num_bits bits.
|
||||
*
|
||||
* @note
|
||||
* If used from file scope, the bits of the array are initialized to zero;
|
||||
* if used from within a function, the bits are left uninitialized.
|
||||
*
|
||||
* @param name Name of array of atomic variables.
|
||||
* @param num_bits Number of bits needed.
|
||||
*/
|
||||
#define ATOMIC_DEFINE(name, num_bits) \
|
||||
atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS]
|
||||
|
||||
/**
|
||||
* @brief Atomically test a bit.
|
||||
*
|
||||
* This routine tests whether bit number @a bit of @a target is set or not.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return 1 if the bit was set, 0 if it wasn't.
|
||||
*/
|
||||
static inline int
|
||||
atomic_test_bit(const atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
|
||||
|
||||
return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically test and clear a bit.
|
||||
*
|
||||
* Atomically clear bit number @a bit of @a target and return its old value.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return 1 if the bit was set, 0 if it wasn't.
|
||||
*/
|
||||
static inline int
|
||||
atomic_test_and_clear_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
atomic_val_t old;
|
||||
|
||||
old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically set a bit.
|
||||
*
|
||||
* Atomically set bit number @a bit of @a target and return its old value.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return 1 if the bit was set, 0 if it wasn't.
|
||||
*/
|
||||
static inline int
|
||||
atomic_test_and_set_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
atomic_val_t old;
|
||||
|
||||
old = atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically clear a bit.
|
||||
*
|
||||
* Atomically clear bit number @a bit of @a target.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void
|
||||
atomic_clear_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically set a bit.
|
||||
*
|
||||
* Atomically set bit number @a bit of @a target.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void
|
||||
atomic_set_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically set a bit to a given value.
|
||||
*
|
||||
* Atomically set bit number @a bit of @a target to value @a val.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
* @param val true for 1, false for 0.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
if (val) {
|
||||
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
} else {
|
||||
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ATOMIC_H__ */
|
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Tobias Svehagen
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _BLUETOOTH_MESH_CDB_H_
|
||||
#define _BLUETOOTH_MESH_CDB_H_
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
|
||||
#if MYNEWT_VAL(BLE_MESH_CDB)
|
||||
#define NODE_COUNT CONFIG_BT_MESH_NODE_COUNT
|
||||
#define SUBNET_COUNT CONFIG_BT_MESH_SUBNET_COUNT
|
||||
#define APP_KEY_COUNT CONFIG_BT_MESH_APP_KEY_COUNT
|
||||
#else
|
||||
#define NODE_COUNT 0
|
||||
#define SUBNET_COUNT 0
|
||||
#define APP_KEY_COUNT 0
|
||||
#endif
|
||||
|
||||
#include "atomic.h"
|
||||
|
||||
enum {
|
||||
BT_MESH_CDB_NODE_CONFIGURED,
|
||||
BT_MESH_CDB_NODE_BLACKLISTED,
|
||||
|
||||
BT_MESH_CDB_NODE_FLAG_COUNT
|
||||
};
|
||||
|
||||
struct bt_mesh_cdb_node {
|
||||
uint8_t uuid[16];
|
||||
uint16_t addr;
|
||||
uint16_t net_idx;
|
||||
uint8_t num_elem;
|
||||
uint8_t dev_key[16];
|
||||
|
||||
ATOMIC_DEFINE(flags, BT_MESH_CDB_NODE_FLAG_COUNT);
|
||||
};
|
||||
|
||||
struct bt_mesh_cdb_subnet {
|
||||
uint16_t net_idx;
|
||||
|
||||
bool kr_flag;
|
||||
uint8_t kr_phase;
|
||||
|
||||
struct {
|
||||
uint8_t net_key[16];
|
||||
} keys[2];
|
||||
};
|
||||
|
||||
struct bt_mesh_cdb_app_key {
|
||||
uint16_t net_idx;
|
||||
uint16_t app_idx;
|
||||
|
||||
struct {
|
||||
uint8_t app_key[16];
|
||||
} keys[2];
|
||||
};
|
||||
|
||||
enum {
|
||||
BT_MESH_CDB_VALID,
|
||||
BT_MESH_CDB_SUBNET_PENDING,
|
||||
BT_MESH_CDB_KEYS_PENDING,
|
||||
BT_MESH_CDB_NODES_PENDING,
|
||||
BT_MESH_CDB_IVU_IN_PROGRESS,
|
||||
|
||||
BT_MESH_CDB_FLAG_COUNT,
|
||||
};
|
||||
|
||||
struct bt_mesh_cdb {
|
||||
uint32_t iv_index;
|
||||
|
||||
ATOMIC_DEFINE(flags, BT_MESH_CDB_FLAG_COUNT);
|
||||
|
||||
struct bt_mesh_cdb_node nodes[NODE_COUNT];
|
||||
struct bt_mesh_cdb_subnet subnets[SUBNET_COUNT];
|
||||
struct bt_mesh_cdb_app_key app_keys[APP_KEY_COUNT];
|
||||
};
|
||||
|
||||
extern struct bt_mesh_cdb bt_mesh_cdb;
|
||||
|
||||
/** @brief Create the Mesh Configuration Database.
|
||||
*
|
||||
* Create and initialize the Mesh Configuration Database. A primary subnet,
|
||||
* ie one with NetIdx 0, will be added and the provided key will be used as
|
||||
* NetKey for that subnet.
|
||||
*
|
||||
* @param key The NetKey to be used for the primary subnet.
|
||||
*
|
||||
* @return 0 on success or negative error code on failure.
|
||||
*/
|
||||
int bt_mesh_cdb_create(const uint8_t key[16]);
|
||||
|
||||
/** @brief Clear the Mesh Configuration Database.
|
||||
*
|
||||
* Remove all nodes, subnets and app-keys stored in the database and mark
|
||||
* the database as invalid. The data will be cleared from persistent storage
|
||||
* if CONFIG_BT_SETTINGS is enabled.
|
||||
*/
|
||||
void bt_mesh_cdb_clear(void);
|
||||
|
||||
/** @brief Set and store the IV Index and IV Update flag.
|
||||
*
|
||||
* The IV Index stored in the CDB will be the one used during provisioning
|
||||
* of new nodes. This function is generally only used from inside the stack.
|
||||
*
|
||||
* This function will store the data to persistent storage if
|
||||
* CONFIG_BT_SETTINGS is enabled.
|
||||
*
|
||||
* @param iv_index The new IV Index to use.
|
||||
* @param iv_update True if there is an ongoing IV Update procedure.
|
||||
*/
|
||||
void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update);
|
||||
|
||||
/** @brief Allocate a node.
|
||||
*
|
||||
* Allocate a new node in the CDB.
|
||||
*
|
||||
* @param uuid UUID of the node.
|
||||
* @param addr Address of the node's primary element. If 0, the lowest
|
||||
* possible address available will be assigned to the node.
|
||||
* @param num_elem Number of elements that the node has.
|
||||
* @param net_idx NetIdx that the node was provisioned to.
|
||||
*
|
||||
* @return The new node or NULL if it cannot be allocated.
|
||||
*/
|
||||
struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr,
|
||||
uint8_t num_elem, uint16_t net_idx);
|
||||
|
||||
/** @brief Delete a node.
|
||||
*
|
||||
* Delete a node from the CDB.
|
||||
*
|
||||
* @param node The node to be deleted.
|
||||
* @param store If true, the node will be cleared from persistent storage.
|
||||
*/
|
||||
void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store);
|
||||
|
||||
/** @brief Get a node by address.
|
||||
*
|
||||
* Try to find the node that has the provided address assigned to one of its
|
||||
* elements.
|
||||
*
|
||||
* @param addr Address of the element to look for.
|
||||
*
|
||||
* @return The node that has an element with address addr or NULL if no such
|
||||
* node exists.
|
||||
*/
|
||||
struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr);
|
||||
|
||||
/** @brief Store node to persistent storage.
|
||||
*
|
||||
* @param node Node to be stored.
|
||||
*/
|
||||
void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node);
|
||||
|
||||
enum {
|
||||
BT_MESH_CDB_ITER_STOP = 0,
|
||||
BT_MESH_CDB_ITER_CONTINUE,
|
||||
};
|
||||
|
||||
/** @typedef bt_mesh_cdb_node_func_t
|
||||
* @brief Node iterator callback.
|
||||
*
|
||||
* @param node Node found.
|
||||
* @param user_data Data given.
|
||||
*
|
||||
* @return BT_MESH_CDB_ITER_CONTINUE to continue to iterate through the nodes
|
||||
* or BT_MESH_CDB_ITER_STOP to stop.
|
||||
*/
|
||||
typedef uint8_t (*bt_mesh_cdb_node_func_t)(struct bt_mesh_cdb_node *node,
|
||||
void *user_data);
|
||||
|
||||
/** @brief Node iterator.
|
||||
*
|
||||
* Iterate nodes in the Mesh Configuration Database. The callback function
|
||||
* will only be called for valid, ie allocated, nodes.
|
||||
*
|
||||
* @param func Callback function.
|
||||
* @param user_data Data to pass to the callback.
|
||||
*/
|
||||
void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data);
|
||||
|
||||
/** @brief Allocate a subnet.
|
||||
*
|
||||
* Allocate a new subnet in the CDB.
|
||||
*
|
||||
* @param net_idx NetIdx of the subnet.
|
||||
*
|
||||
* @return The new subnet or NULL if it cannot be allocated.
|
||||
*/
|
||||
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(uint16_t net_idx);
|
||||
|
||||
/** @brief Delete a subnet.
|
||||
*
|
||||
* Delete a subnet from the CDB.
|
||||
*
|
||||
* @param sub The subnet to be deleted.
|
||||
* @param store If true, the subnet will be cleared from persistent storage.
|
||||
*/
|
||||
void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store);
|
||||
|
||||
/** @brief Get a subnet by NetIdx
|
||||
*
|
||||
* Try to find the subnet with the specified NetIdx.
|
||||
*
|
||||
* @param net_idx NetIdx of the subnet to look for.
|
||||
*
|
||||
* @return The subnet with the specified NetIdx or NULL if no such subnet
|
||||
* exists.
|
||||
*/
|
||||
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx);
|
||||
|
||||
/** @brief Store subnet to persistent storage.
|
||||
*
|
||||
* @param sub Subnet to be stored.
|
||||
*/
|
||||
void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub);
|
||||
|
||||
/** @brief Get the flags for a subnet
|
||||
*
|
||||
* @param sub The subnet to get flags for.
|
||||
*
|
||||
* @return The flags for the subnet.
|
||||
*/
|
||||
uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub);
|
||||
|
||||
|
||||
/** @brief Allocate an application key.
|
||||
*
|
||||
* Allocate a new application key in the CDB.
|
||||
*
|
||||
* @param net_idx NetIdx of NetKey that the application key is bound to.
|
||||
* @param app_idx AppIdx of the application key.
|
||||
*
|
||||
* @return The new application key or NULL if it cannot be allocated.
|
||||
*/
|
||||
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(uint16_t net_idx,
|
||||
uint16_t app_idx);
|
||||
|
||||
/** @brief Delete an application key.
|
||||
*
|
||||
* Delete an application key from the CDB.
|
||||
*
|
||||
* @param key The application key to be deleted.
|
||||
* @param store If true, the key will be cleared from persistent storage.
|
||||
*/
|
||||
void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store);
|
||||
|
||||
/** @brief Get an application key by AppIdx
|
||||
*
|
||||
* Try to find the application key with the specified AppIdx.
|
||||
*
|
||||
* @param app_idx AppIdx of the application key to look for.
|
||||
*
|
||||
* @return The application key with the specified AppIdx or NULL if no such key
|
||||
* exists.
|
||||
*/
|
||||
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx);
|
||||
|
||||
/** @brief Store application key to persistent storage.
|
||||
*
|
||||
* @param key Application key to be stored.
|
||||
*/
|
||||
void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */
|
@ -0,0 +1,485 @@
|
||||
/** @file
|
||||
* @brief Bluetooth Mesh Runtime Configuration APIs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _BT_MESH_CFG_H_
|
||||
#define _BT_MESH_CFG_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
* @brief Bluetooth Mesh Runtime Configuration API
|
||||
* @defgroup bt_mesh_cfg Bluetooth Mesh Runtime Configuration
|
||||
* @ingroup bt_mesh
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Bluetooth Mesh Feature states */
|
||||
enum bt_mesh_feat_state {
|
||||
/** Feature is supported, but disabled. */
|
||||
BT_MESH_FEATURE_DISABLED,
|
||||
/** Feature is supported and enabled. */
|
||||
BT_MESH_FEATURE_ENABLED,
|
||||
/** Feature is not supported, and cannot be enabled. */
|
||||
BT_MESH_FEATURE_NOT_SUPPORTED,
|
||||
};
|
||||
|
||||
/* Legacy feature defines */
|
||||
#define BT_MESH_RELAY_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_RELAY_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
#define BT_MESH_RELAY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
|
||||
|
||||
#define BT_MESH_BEACON_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_BEACON_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
|
||||
#define BT_MESH_GATT_PROXY_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_GATT_PROXY_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
#define BT_MESH_GATT_PROXY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
|
||||
|
||||
#define BT_MESH_FRIEND_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_FRIEND_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
#define BT_MESH_FRIEND_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
|
||||
|
||||
#define BT_MESH_NODE_IDENTITY_STOPPED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_NODE_IDENTITY_RUNNING BT_MESH_FEATURE_ENABLED
|
||||
#define BT_MESH_NODE_IDENTITY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
|
||||
|
||||
/** @brief Enable or disable sending of the Secure Network Beacon.
|
||||
*
|
||||
* @param beacon New Secure Network Beacon state.
|
||||
*/
|
||||
void bt_mesh_beacon_set(bool beacon);
|
||||
|
||||
/** @brief Get the current Secure Network Beacon state.
|
||||
*
|
||||
* @returns Whether the Secure Network Beacon feature is enabled.
|
||||
*/
|
||||
bool bt_mesh_beacon_enabled(void);
|
||||
|
||||
/** @brief Set the default TTL value.
|
||||
*
|
||||
* The default TTL value is used when no explicit TTL value is set. Models will
|
||||
* use the default TTL value when @ref bt_mesh_msg_ctx::send_ttl is
|
||||
* @ref BT_MESH_TTL_DEFAULT.
|
||||
*
|
||||
* @param default_ttl The new default TTL value. Valid values are 0x00 and 0x02
|
||||
* to @ref BT_MESH_TTL_MAX.
|
||||
*
|
||||
* @retval 0 Successfully set the default TTL value.
|
||||
* @retval -EINVAL Invalid TTL value.
|
||||
*/
|
||||
int bt_mesh_default_ttl_set(uint8_t default_ttl);
|
||||
|
||||
/** @brief Get the current default TTL value.
|
||||
*
|
||||
* @return The current default TTL value.
|
||||
*/
|
||||
uint8_t bt_mesh_default_ttl_get(void);
|
||||
|
||||
/** @brief Set the Network Transmit parameters.
|
||||
*
|
||||
* The Network Transmit parameters determine the parameters local messages are
|
||||
* transmitted with.
|
||||
*
|
||||
* @see BT_MESH_TRANSMIT
|
||||
*
|
||||
* @param xmit New Network Transmit parameters. Use @ref BT_MESH_TRANSMIT for
|
||||
* encoding.
|
||||
*/
|
||||
void bt_mesh_net_transmit_set(uint8_t xmit);
|
||||
|
||||
/** @brief Get the current Network Transmit parameters.
|
||||
*
|
||||
* The @ref BT_MESH_TRANSMIT_COUNT and @ref BT_MESH_TRANSMIT_INT macros can be
|
||||
* used to decode the Network Transmit parameters.
|
||||
*
|
||||
* @return The current Network Transmit parameters.
|
||||
*/
|
||||
uint8_t bt_mesh_net_transmit_get(void);
|
||||
|
||||
/** @brief Configure the Relay feature.
|
||||
*
|
||||
* Enable or disable the Relay feature, and configure the parameters to
|
||||
* transmit relayed messages with.
|
||||
*
|
||||
* Support for the Relay feature must be enabled through the
|
||||
* @c CONFIG_BT_MESH_RELAY configuration option.
|
||||
*
|
||||
* @see BT_MESH_TRANSMIT
|
||||
*
|
||||
* @param relay New Relay feature state. Must be one of
|
||||
* @ref BT_MESH_FEATURE_ENABLED and
|
||||
* @ref BT_MESH_FEATURE_DISABLED.
|
||||
* @param xmit New Relay retransmit parameters. Use @ref BT_MESH_TRANSMIT for
|
||||
* encoding.
|
||||
*
|
||||
* @retval 0 Successfully changed the Relay configuration.
|
||||
* @retval -ENOTSUP The Relay feature is not supported.
|
||||
* @retval -EINVAL Invalid parameter.
|
||||
* @retval -EALREADY Already using the given parameters.
|
||||
*/
|
||||
int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit);
|
||||
|
||||
/** @brief Get the current Relay feature state.
|
||||
*
|
||||
* @returns The Relay feature state.
|
||||
*/
|
||||
enum bt_mesh_feat_state bt_mesh_relay_get(void);
|
||||
|
||||
/** @brief Get the current Relay Retransmit parameters.
|
||||
*
|
||||
* The @ref BT_MESH_TRANSMIT_COUNT and @ref BT_MESH_TRANSMIT_INT macros can be
|
||||
* used to decode the Relay Retransmit parameters.
|
||||
*
|
||||
* @return The current Relay Retransmit parameters, or 0 if relay is not
|
||||
* supported.
|
||||
*/
|
||||
uint8_t bt_mesh_relay_retransmit_get(void);
|
||||
|
||||
/** @brief Enable or disable the GATT Proxy feature.
|
||||
*
|
||||
* Support for the GATT Proxy feature must be enabled through the
|
||||
* @c CONFIG_BT_MESH_GATT_PROXY configuration option.
|
||||
*
|
||||
* @note The GATT Proxy feature only controls a Proxy node's ability to relay
|
||||
* messages to the mesh network. A node that supports GATT Proxy will
|
||||
* still advertise Connectable Proxy beacons, even if the feature is
|
||||
* disabled. The Proxy feature can only be fully disabled through compile
|
||||
* time configuration.
|
||||
*
|
||||
* @param gatt_proxy New GATT Proxy state. Must be one of
|
||||
* @ref BT_MESH_FEATURE_ENABLED and
|
||||
* @ref BT_MESH_FEATURE_DISABLED.
|
||||
*
|
||||
* @retval 0 Successfully changed the GATT Proxy feature state.
|
||||
* @retval -ENOTSUP The GATT Proxy feature is not supported.
|
||||
* @retval -EINVAL Invalid parameter.
|
||||
* @retval -EALREADY Already in the given state.
|
||||
*/
|
||||
int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy);
|
||||
|
||||
/** @brief Get the current GATT Proxy state.
|
||||
*
|
||||
* @returns The GATT Proxy feature state.
|
||||
*/
|
||||
enum bt_mesh_feat_state bt_mesh_gatt_proxy_get(void);
|
||||
|
||||
/** @brief Enable or disable the Friend feature.
|
||||
*
|
||||
* Any active friendships will be terminated immediately if the Friend feature
|
||||
* is disabled.
|
||||
*
|
||||
* Support for the Friend feature must be enabled through the
|
||||
* @c CONFIG_BT_MESH_FRIEND configuration option.
|
||||
*
|
||||
* @param friendship New Friend feature state. Must be one of
|
||||
* @ref BT_MESH_FEATURE_ENABLED and
|
||||
* @ref BT_MESH_FEATURE_DISABLED.
|
||||
*
|
||||
* @retval 0 Successfully changed the Friend feature state.
|
||||
* @retval -ENOTSUP The Friend feature is not supported.
|
||||
* @retval -EINVAL Invalid parameter.
|
||||
* @retval -EALREADY Already in the given state.
|
||||
*/
|
||||
int bt_mesh_friend_set(enum bt_mesh_feat_state friendship);
|
||||
|
||||
/** @brief Get the current Friend state.
|
||||
*
|
||||
* @returns The Friend feature state.
|
||||
*/
|
||||
enum bt_mesh_feat_state bt_mesh_friend_get(void);
|
||||
|
||||
/**
|
||||
* @brief Bluetooth Mesh Subnet Configuration
|
||||
* @defgroup bt_mesh_cfg_subnet Bluetooth Mesh Subnet Configuration
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Add a Subnet.
|
||||
*
|
||||
* Adds a subnet with the given network index and network key to the list of
|
||||
* known Subnets. All messages sent on the given Subnet will be processed by
|
||||
* this node, and the node may send and receive Network Beacons on the given
|
||||
* Subnet.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param key Root network key of the Subnet. All other keys are derived
|
||||
* from this.
|
||||
*
|
||||
* @retval STATUS_SUCCESS The Subnet was successfully added.
|
||||
* @retval STATUS_INSUFF_RESOURCES No room for this Subnet.
|
||||
* @retval STATUS_UNSPECIFIED The Subnet couldn't be created for some reason.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]);
|
||||
|
||||
/** @brief Update the given Subnet.
|
||||
*
|
||||
* Starts the Key Refresh procedure for this Subnet by adding a second set of
|
||||
* encryption keys. The Subnet will continue sending with the old key (but
|
||||
* receiving messages using both) until the Subnet enters Key Refresh phase 2.
|
||||
*
|
||||
* This allows a network configurator to replace old network and application
|
||||
* keys for the entire network, effectively removing access for all nodes that
|
||||
* aren't given the new keys.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param key New root network key of the Subnet.
|
||||
*
|
||||
* @retval STATUS_SUCCESS The Subnet was updated with a second key.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
* @retval STATUS_IDX_ALREADY_STORED The @c key value is the same as the
|
||||
* current key.
|
||||
* @retval STATUS_CANNOT_UPDATE The Subnet cannot be updated for some reason.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16]);
|
||||
|
||||
/** @brief Delete a Subnet.
|
||||
*
|
||||
* Removes the Subnet with the given network index from the node. The node will
|
||||
* stop sending Network Beacons with the given Subnet, and can no longer
|
||||
* process messages on this Subnet.
|
||||
*
|
||||
* All Applications bound to this Subnet are also deleted.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
*
|
||||
* @retval STATUS_SUCCESS The Subnet was deleted.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_del(uint16_t net_idx);
|
||||
|
||||
/** @brief Check whether a Subnet is known.
|
||||
*
|
||||
* @param net_idx Network index
|
||||
*
|
||||
* @return true if a Subnet with the given index exists, false otherwise.
|
||||
*/
|
||||
bool bt_mesh_subnet_exists(uint16_t net_idx);
|
||||
|
||||
/** @brief Set the Subnet's Key Refresh phase.
|
||||
*
|
||||
* The Key Refresh procedure is started by updating the Subnet keys through
|
||||
* @ref bt_mesh_subnet_update. This puts the Subnet in Key Refresh Phase 1.
|
||||
* Once all nodes have received the new Subnet key, Key Refresh Phase 2 can be
|
||||
* activated through this function to start transmitting with the new network
|
||||
* key. Finally, to revoke the old key, set the Key Refresh Phase to 3. This
|
||||
* removes the old keys from the node, and returns the Subnet back to normal
|
||||
* single-key operation with the new key set.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param phase Pointer to the new Key Refresh phase. Will return the actual
|
||||
* Key Refresh phase after updating.
|
||||
*
|
||||
* @retval STATUS_SUCCESS The Key Refresh phase of the Subnet was successfully
|
||||
* changed.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
* @retval STATUS_CANNOT_UPDATE The given phase change is invalid.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_kr_phase_set(uint16_t net_idx, uint8_t *phase);
|
||||
|
||||
/** @brief Get the Subnet's Key Refresh phase.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param phase Pointer to the Key Refresh variable to fill.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Successfully populated the @c phase variable.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_kr_phase_get(uint16_t net_idx, uint8_t *phase);
|
||||
|
||||
/** @brief Set the Node Identity state of the Subnet.
|
||||
*
|
||||
* The Node Identity state of a Subnet determines whether the Subnet advertises
|
||||
* connectable Node Identity beacons for Proxy Clients to connect to.
|
||||
* Once started, the Node Identity beacon runs for 60 seconds, or until it is
|
||||
* stopped.
|
||||
*
|
||||
* This function serves the same purpose as @ref bt_mesh_proxy_identity_enable,
|
||||
* but only acts on a single Subnet.
|
||||
*
|
||||
* GATT Proxy support must be enabled through
|
||||
* @option{CONFIG_BT_MESH_GATT_PROXY}.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param node_id New Node Identity state, must be either @ref
|
||||
* BT_MESH_FEATURE_ENABLED or @ref BT_MESH_FEATURE_DISABLED.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Successfully set the Node Identity state of the
|
||||
* Subnet.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
* @retval STATUS_FEAT_NOT_SUPP The Node Identity feature is not supported.
|
||||
* @retval STATUS_CANNOT_SET Couldn't set the Node Identity state.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx,
|
||||
enum bt_mesh_feat_state node_id);
|
||||
|
||||
/** @brief Get the Node Identity state of the Subnet.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param node_id Node Identity variable to fill.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Successfully populated the @c node_id variable.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx,
|
||||
enum bt_mesh_feat_state *node_id);
|
||||
|
||||
/** @brief Get a list of all known Subnet indexes.
|
||||
*
|
||||
* Builds a list of all known Subnet indexes in the @c net_idxs array.
|
||||
* If the @c net_idxs array is smaller than the list of known Subnets, this
|
||||
* function fills all available entries and returns @c -ENOMEM. In this
|
||||
* case, the next @c max entries of the list can be read out by calling
|
||||
* @code
|
||||
* bt_mesh_subnets_get(list, max, max);
|
||||
* @endcode
|
||||
*
|
||||
* Note that any changes to the Subnet list between calls to this function
|
||||
* could change the order and number of entries in the list.
|
||||
*
|
||||
* @param net_idxs Array to fill.
|
||||
* @param max Max number of indexes to return.
|
||||
* @param skip Number of indexes to skip. Enables batched processing of the
|
||||
* list.
|
||||
*
|
||||
* @return The number of indexes added to the @c net_idxs array, or @c -ENOMEM
|
||||
* if the number of known Subnets exceeds the @c max parameter.
|
||||
*/
|
||||
ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Bluetooth Mesh Application Configuration
|
||||
* @defgroup bt_mesh_cfg_app Bluetooth Mesh Application Configuration
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Add an Application key.
|
||||
*
|
||||
* Adds the Application with the given index to the list of known applications.
|
||||
* Allows the node to send and receive model messages encrypted with this
|
||||
* Application key.
|
||||
*
|
||||
* Every Application is bound to a specific Subnet. The node must know the
|
||||
* Subnet the Application is bound to before it can add the Application.
|
||||
*
|
||||
* @param app_idx Application index.
|
||||
* @param net_idx Network index the Application is bound to.
|
||||
* @param key Application key value.
|
||||
*
|
||||
* @retval STATUS_SUCCESS The Application was successfully added.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
* @retval STATUS_INSUFF_RESOURCES There's no room for storing this
|
||||
* Application.
|
||||
* @retval STATUS_INVALID_BINDING This AppIdx is already bound to another
|
||||
* Subnet.
|
||||
* @retval STATUS_IDX_ALREADY_STORED This AppIdx is already stored with a
|
||||
* different key value.
|
||||
* @retval STATUS_CANNOT_SET Cannot set the Application key for some reason.
|
||||
*/
|
||||
uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx,
|
||||
const uint8_t key[16]);
|
||||
|
||||
/** @brief Update an Application key.
|
||||
*
|
||||
* Update an Application with a second Application key, as part of the
|
||||
* Key Refresh procedure of the bound Subnet. The node will continue
|
||||
* transmitting with the old application key (but receiving on both) until the
|
||||
* Subnet enters Key Refresh phase 2. Once the Subnet enters Key Refresh phase
|
||||
* 3, the old application key will be deleted.
|
||||
*
|
||||
* @note The Application key can only be updated if the bound Subnet is in Key
|
||||
* Refresh phase 1.
|
||||
*
|
||||
* @param app_idx Application index.
|
||||
* @param net_idx Network index the Application is bound to, or
|
||||
* @ref BT_MESH_KEY_ANY to skip the binding check.
|
||||
* @param key New key value.
|
||||
*
|
||||
* @retval STATUS_SUCCESS The Application key was successfully updated.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
* @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx.
|
||||
* @retval STATUS_CANNOT_UPDATE The Application key cannot be updated for some
|
||||
* reason.
|
||||
* @retval STATUS_IDX_ALREADY_STORED This AppIdx is already updated with a
|
||||
* different key value.
|
||||
*/
|
||||
uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx,
|
||||
const uint8_t key[16]);
|
||||
|
||||
/** @brief Delete an Application key.
|
||||
*
|
||||
* All models bound to this application will remove this binding.
|
||||
* All models publishing with this application will stop publishing.
|
||||
*
|
||||
* @param app_idx Application index.
|
||||
* @param net_idx Network index.
|
||||
*
|
||||
* @retval STATUS_SUCCESS The Application key was successfully deleted.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
* @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx.
|
||||
*/
|
||||
uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx);
|
||||
|
||||
/** @brief Check if an Application key is known.
|
||||
*
|
||||
* @param app_idx Application index.
|
||||
*
|
||||
* @return true if the Application is known, false otherwise.
|
||||
*/
|
||||
bool bt_mesh_app_key_exists(uint16_t app_idx);
|
||||
|
||||
/** @brief Get a list of all known Application key indexes.
|
||||
*
|
||||
* Builds a list of all Application indexes for the given network index in the
|
||||
* @c app_idxs array. If the @c app_idxs array cannot fit all bound
|
||||
* Applications, this function fills all available entries and returns @c
|
||||
* -ENOMEM. In this case, the next @c max entries of the list can be read out
|
||||
* by calling
|
||||
* @code
|
||||
* bt_mesh_app_keys_get(net_idx, list, max, max);
|
||||
* @endcode
|
||||
*
|
||||
* Note that any changes to the Application key list between calls to this
|
||||
* function could change the order and number of entries in the list.
|
||||
*
|
||||
* @param net_idx Network Index to get the Applications of, or @ref
|
||||
* BT_MESH_KEY_ANY to get all Applications.
|
||||
* @param app_idxs Array to fill.
|
||||
* @param max Max number of indexes to return.
|
||||
* @param skip Number of indexes to skip. Enables batched processing of the
|
||||
* list.
|
||||
*
|
||||
* @return The number of indexes added to the @c app_idxs array, or @c -ENOMEM
|
||||
* if the number of known Applications exceeds the @c max parameter.
|
||||
*/
|
||||
ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max,
|
||||
off_t skip);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* _BT_MESH_CFG_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue