Add Nimble in libs directory
This commit is contained in:
parent
032fad094c
commit
bdc10744fb
633 changed files with 228083 additions and 834 deletions
33
src/libs/mynewt-nimble/apps/advertiser/pkg.yml
Normal file
33
src/libs/mynewt-nimble/apps/advertiser/pkg.yml
Normal file
|
|
@ -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: "apps/advertiser"
|
||||
pkg.type: app
|
||||
pkg.description: "Basic advertiser 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/util"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gap"
|
||||
- "@apache-mynewt-nimble/nimble/transport"
|
||||
136
src/libs/mynewt-nimble/apps/advertiser/src/main.c
Normal file
136
src/libs/mynewt-nimble/apps/advertiser/src/main.c
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "os/os.h"
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "log/log.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
static const char *device_name = "Apache Mynewt";
|
||||
|
||||
/* adv_event() calls advertise(), so forward declaration is required */
|
||||
static void advertise(void);
|
||||
|
||||
static void
|
||||
set_ble_addr(void)
|
||||
{
|
||||
int rc;
|
||||
ble_addr_t addr;
|
||||
|
||||
/* generate new non-resolvable private address */
|
||||
rc = ble_hs_id_gen_rnd(1, &addr);
|
||||
assert(rc == 0);
|
||||
|
||||
/* set generated address */
|
||||
rc = ble_hs_id_set_rnd(addr.val);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
adv_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "Advertising completed, termination code: %d\n",
|
||||
event->adv_complete.reason);
|
||||
advertise();
|
||||
return 0;
|
||||
default:
|
||||
MODLOG_DFLT(ERROR, "Advertising event not handled\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
advertise(void)
|
||||
{
|
||||
int rc;
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
|
||||
/* set adv parameters */
|
||||
memset(&adv_params, 0, sizeof(adv_params));
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_NON;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
|
||||
memset(&fields, 0, sizeof(fields));
|
||||
|
||||
/* Fill the fields with advertising data - flags, tx power level, name */
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN;
|
||||
fields.tx_pwr_lvl_is_present = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
fields.name = (uint8_t *)device_name;
|
||||
fields.name_len = strlen(device_name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
assert(rc == 0);
|
||||
|
||||
MODLOG_DFLT(INFO, "Starting advertising...\n");
|
||||
|
||||
/* As own address type we use hard-coded value, because we generate
|
||||
NRPA and by definition it's random */
|
||||
rc = ble_gap_adv_start(BLE_OWN_ADDR_RANDOM, NULL, 10000,
|
||||
&adv_params, adv_event, NULL);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_sync(void)
|
||||
{
|
||||
set_ble_addr();
|
||||
|
||||
/* begin advertising */
|
||||
advertise();
|
||||
}
|
||||
|
||||
static void
|
||||
on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Initialize all packages. */
|
||||
sysinit();
|
||||
|
||||
ble_hs_cfg.sync_cb = on_sync;
|
||||
ble_hs_cfg.reset_cb = on_reset;
|
||||
|
||||
rc = ble_svc_gap_device_name_set(device_name);
|
||||
assert(rc == 0);
|
||||
|
||||
/* As the last thing, process events from default event queue. */
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
36
src/libs/mynewt-nimble/apps/blecent/pkg.yml
Normal file
36
src/libs/mynewt-nimble/apps/blecent/pkg.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# 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/blecent
|
||||
pkg.type: app
|
||||
pkg.description: Simple BLE central application.
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@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"
|
||||
- nimble/host
|
||||
- nimble/host/util
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/host/store/ram
|
||||
- nimble/transport
|
||||
111
src/libs/mynewt-nimble/apps/blecent/src/blecent.h
Normal file
111
src/libs/mynewt-nimble/apps/blecent/src/blecent.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* 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_BLECENT_
|
||||
#define H_BLECENT_
|
||||
|
||||
#include "os/mynewt.h"
|
||||
#include "modlog/modlog.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ble_hs_adv_fields;
|
||||
struct ble_gap_conn_desc;
|
||||
struct ble_hs_cfg;
|
||||
union ble_store_value;
|
||||
union ble_store_key;
|
||||
|
||||
#define BLECENT_SVC_ALERT_UUID 0x1811
|
||||
#define BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47
|
||||
#define BLECENT_CHR_NEW_ALERT 0x2A46
|
||||
#define BLECENT_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48
|
||||
#define BLECENT_CHR_UNR_ALERT_STAT_UUID 0x2A45
|
||||
#define BLECENT_CHR_ALERT_NOT_CTRL_PT 0x2A44
|
||||
|
||||
/** Misc. */
|
||||
void print_bytes(const uint8_t *bytes, int len);
|
||||
void print_mbuf(const struct os_mbuf *om);
|
||||
char *addr_str(const void *addr);
|
||||
void print_uuid(const ble_uuid_t *uuid);
|
||||
void print_conn_desc(const struct ble_gap_conn_desc *desc);
|
||||
void print_adv_fields(const struct ble_hs_adv_fields *fields);
|
||||
|
||||
/** Peer. */
|
||||
struct peer_dsc {
|
||||
SLIST_ENTRY(peer_dsc) next;
|
||||
struct ble_gatt_dsc dsc;
|
||||
};
|
||||
SLIST_HEAD(peer_dsc_list, peer_dsc);
|
||||
|
||||
struct peer_chr {
|
||||
SLIST_ENTRY(peer_chr) next;
|
||||
struct ble_gatt_chr chr;
|
||||
|
||||
struct peer_dsc_list dscs;
|
||||
};
|
||||
SLIST_HEAD(peer_chr_list, peer_chr);
|
||||
|
||||
struct peer_svc {
|
||||
SLIST_ENTRY(peer_svc) next;
|
||||
struct ble_gatt_svc svc;
|
||||
|
||||
struct peer_chr_list chrs;
|
||||
};
|
||||
SLIST_HEAD(peer_svc_list, peer_svc);
|
||||
|
||||
struct peer;
|
||||
typedef void peer_disc_fn(const struct peer *peer, int status, void *arg);
|
||||
|
||||
struct peer {
|
||||
SLIST_ENTRY(peer) next;
|
||||
|
||||
uint16_t conn_handle;
|
||||
|
||||
/** List of discovered GATT services. */
|
||||
struct peer_svc_list svcs;
|
||||
|
||||
/** Keeps track of where we are in the service discovery process. */
|
||||
uint16_t disc_prev_chr_val;
|
||||
struct peer_svc *cur_svc;
|
||||
|
||||
/** Callback that gets executed when service discovery completes. */
|
||||
peer_disc_fn *disc_cb;
|
||||
void *disc_cb_arg;
|
||||
};
|
||||
|
||||
int peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb,
|
||||
void *disc_cb_arg);
|
||||
const struct peer_dsc *
|
||||
peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
|
||||
const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid);
|
||||
const struct peer_chr *
|
||||
peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
|
||||
const ble_uuid_t *chr_uuid);
|
||||
const struct peer_svc *
|
||||
peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid);
|
||||
int peer_delete(uint16_t conn_handle);
|
||||
int peer_add(uint16_t conn_handle);
|
||||
int peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
525
src/libs/mynewt-nimble/apps/blecent/src/main.c
Normal file
525
src/libs/mynewt-nimble/apps/blecent/src/main.c
Normal file
|
|
@ -0,0 +1,525 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include "os/mynewt.h"
|
||||
#include "bsp/bsp.h"
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
|
||||
/* Mandatory services. */
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
/* Application-specified header. */
|
||||
#include "blecent.h"
|
||||
|
||||
static int blecent_gap_event(struct ble_gap_event *event, void *arg);
|
||||
|
||||
/**
|
||||
* Application callback. Called when the read of the ANS Supported New Alert
|
||||
* Category characteristic has completed.
|
||||
*/
|
||||
static int
|
||||
blecent_on_read(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "Read complete; status=%d conn_handle=%d", error->status,
|
||||
conn_handle);
|
||||
if (error->status == 0) {
|
||||
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
|
||||
print_mbuf(attr->om);
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Application callback. Called when the write to the ANS Alert Notification
|
||||
* Control Point characteristic has completed.
|
||||
*/
|
||||
static int
|
||||
blecent_on_write(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
MODLOG_DFLT(INFO,
|
||||
"Write complete; status=%d conn_handle=%d attr_handle=%d\n",
|
||||
error->status, conn_handle, attr->handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Application callback. Called when the attempt to subscribe to notifications
|
||||
* for the ANS Unread Alert Status characteristic has completed.
|
||||
*/
|
||||
static int
|
||||
blecent_on_subscribe(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d "
|
||||
"attr_handle=%d\n",
|
||||
error->status, conn_handle, attr->handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs three concurrent GATT operations against the specified peer:
|
||||
* 1. Reads the ANS Supported New Alert Category characteristic.
|
||||
* 2. Writes the ANS Alert Notification Control Point characteristic.
|
||||
* 3. Subscribes to notifications for the ANS Unread Alert Status
|
||||
* characteristic.
|
||||
*
|
||||
* If the peer does not support a required service, characteristic, or
|
||||
* descriptor, then the peer lied when it claimed support for the alert
|
||||
* notification service! When this happens, or if a GATT procedure fails,
|
||||
* this function immediately terminates the connection.
|
||||
*/
|
||||
static void
|
||||
blecent_read_write_subscribe(const struct peer *peer)
|
||||
{
|
||||
const struct peer_chr *chr;
|
||||
const struct peer_dsc *dsc;
|
||||
uint8_t value[2];
|
||||
int rc;
|
||||
|
||||
/* Read the supported-new-alert-category characteristic. */
|
||||
chr = peer_chr_find_uuid(peer,
|
||||
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
|
||||
BLE_UUID16_DECLARE(BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID));
|
||||
if (chr == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the Supported New "
|
||||
"Alert Category characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle,
|
||||
blecent_on_read, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to read characteristic; rc=%d\n",
|
||||
rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Write two bytes (99, 100) to the alert-notification-control-point
|
||||
* characteristic.
|
||||
*/
|
||||
chr = peer_chr_find_uuid(peer,
|
||||
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
|
||||
BLE_UUID16_DECLARE(BLECENT_CHR_ALERT_NOT_CTRL_PT));
|
||||
if (chr == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the Alert "
|
||||
"Notification Control Point characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
value[0] = 99;
|
||||
value[1] = 100;
|
||||
rc = ble_gattc_write_flat(peer->conn_handle, chr->chr.val_handle,
|
||||
value, sizeof value, blecent_on_write, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to write characteristic; rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
/* Subscribe to notifications for the Unread Alert Status characteristic.
|
||||
* A central enables notifications by writing two bytes (1, 0) to the
|
||||
* characteristic's client-characteristic-configuration-descriptor (CCCD).
|
||||
*/
|
||||
dsc = peer_dsc_find_uuid(peer,
|
||||
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
|
||||
BLE_UUID16_DECLARE(BLECENT_CHR_UNR_ALERT_STAT_UUID),
|
||||
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16));
|
||||
if (dsc == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD for the Unread Alert "
|
||||
"Status characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
value[0] = 1;
|
||||
value[1] = 0;
|
||||
rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle,
|
||||
value, sizeof value, blecent_on_subscribe, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to subscribe to characteristic; "
|
||||
"rc=%d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
/* Terminate the connection. */
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when service discovery of the specified peer has completed.
|
||||
*/
|
||||
static void
|
||||
blecent_on_disc_complete(const struct peer *peer, int status, void *arg)
|
||||
{
|
||||
|
||||
if (status != 0) {
|
||||
/* Service discovery failed. Terminate the connection. */
|
||||
MODLOG_DFLT(ERROR, "Error: Service discovery failed; status=%d "
|
||||
"conn_handle=%d\n", status, peer->conn_handle);
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Service discovery has completed successfully. Now we have a complete
|
||||
* list of services, characteristics, and descriptors that the peer
|
||||
* supports.
|
||||
*/
|
||||
MODLOG_DFLT(ERROR, "Service discovery complete; status=%d "
|
||||
"conn_handle=%d\n", status, peer->conn_handle);
|
||||
|
||||
/* Now perform three concurrent GATT procedures against the peer: read,
|
||||
* write, and subscribe to notifications.
|
||||
*/
|
||||
blecent_read_write_subscribe(peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the GAP general discovery procedure.
|
||||
*/
|
||||
static void
|
||||
blecent_scan(void)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
struct ble_gap_disc_params disc_params;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Tell the controller to filter duplicates; we don't want to process
|
||||
* repeated advertisements from the same device.
|
||||
*/
|
||||
disc_params.filter_duplicates = 1;
|
||||
|
||||
/**
|
||||
* Perform a passive scan. I.e., don't send follow-up scan requests to
|
||||
* each advertiser.
|
||||
*/
|
||||
disc_params.passive = 1;
|
||||
|
||||
/* Use defaults for the rest of the parameters. */
|
||||
disc_params.itvl = 0;
|
||||
disc_params.window = 0;
|
||||
disc_params.filter_policy = 0;
|
||||
disc_params.limited = 0;
|
||||
|
||||
rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
|
||||
blecent_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether we should tre to connect to the sender of the specified
|
||||
* advertisement. The function returns a positive result if the device
|
||||
* advertises connectability and support for the Alert Notification service.
|
||||
*/
|
||||
static int
|
||||
blecent_should_connect(const struct ble_gap_disc_desc *disc)
|
||||
{
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
/* The device has to be advertising connectability. */
|
||||
if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND &&
|
||||
disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* The device has to advertise support for the Alert Notification
|
||||
* service (0x1811).
|
||||
*/
|
||||
for (i = 0; i < fields.num_uuids16; i++) {
|
||||
if (ble_uuid_u16(&fields.uuids16[i].u) == BLECENT_SVC_ALERT_UUID) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the sender of the specified advertisement of it looks
|
||||
* interesting. A device is "interesting" if it advertises connectability and
|
||||
* support for the Alert Notification service.
|
||||
*/
|
||||
static void
|
||||
blecent_connect_if_interesting(const struct ble_gap_disc_desc *disc)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
int rc;
|
||||
|
||||
/* Don't do anything if we don't care about this advertiser. */
|
||||
if (!blecent_should_connect(disc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scanning must be stopped before a connection can be initiated. */
|
||||
rc = ble_gap_disc_cancel();
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(DEBUG, "Failed to cancel scan; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Figure out address to use for connect (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;
|
||||
}
|
||||
|
||||
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||
* timeout.
|
||||
*/
|
||||
rc = ble_gap_connect(own_addr_type, &disc->addr, 30000, NULL,
|
||||
blecent_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d "
|
||||
"addr=%s\n; rc=%d",
|
||||
disc->addr.type, addr_str(disc->addr.val), rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The nimble host executes this callback when a GAP event occurs. The
|
||||
* application associates a GAP event callback with each connection that is
|
||||
* established. blecent uses the same callback for all connections.
|
||||
*
|
||||
* @param event The event being signalled.
|
||||
* @param arg Application-specified argument; unused by
|
||||
* blecent.
|
||||
*
|
||||
* @return 0 if the application successfully handled the
|
||||
* event; nonzero on failure. The semantics
|
||||
* of the return code is specific to the
|
||||
* particular GAP event being signalled.
|
||||
*/
|
||||
static int
|
||||
blecent_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_DISC:
|
||||
rc = ble_hs_adv_parse_fields(&fields, event->disc.data,
|
||||
event->disc.length_data);
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* An advertisment report was received during GAP discovery. */
|
||||
print_adv_fields(&fields);
|
||||
|
||||
/* Try to connect to the advertiser if it looks interesting. */
|
||||
blecent_connect_if_interesting(&event->disc);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
if (event->connect.status == 0) {
|
||||
/* Connection successfully established. */
|
||||
MODLOG_DFLT(INFO, "Connection established ");
|
||||
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Remember peer. */
|
||||
rc = peer_add(event->connect.conn_handle);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Perform service discovery. */
|
||||
rc = peer_disc_all(event->connect.conn_handle,
|
||||
blecent_on_disc_complete, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Connection attempt failed; resume scanning. */
|
||||
MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n",
|
||||
event->connect.status);
|
||||
blecent_scan();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
/* Connection terminated. */
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
|
||||
print_conn_desc(&event->disconnect.conn);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Forget about peer. */
|
||||
peer_delete(event->disconnect.conn.conn_handle);
|
||||
|
||||
/* Resume scanning. */
|
||||
blecent_scan();
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISC_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "discovery complete; reason=%d\n",
|
||||
event->disc_complete.reason);
|
||||
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->enc_change.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
print_conn_desc(&desc);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_RX:
|
||||
/* Peer sent us a notification or indication. */
|
||||
MODLOG_DFLT(INFO, "received %s; conn_handle=%d attr_handle=%d "
|
||||
"attr_len=%d\n",
|
||||
event->notify_rx.indication ?
|
||||
"indication" :
|
||||
"notification",
|
||||
event->notify_rx.conn_handle,
|
||||
event->notify_rx.attr_handle,
|
||||
OS_MBUF_PKTLEN(event->notify_rx.om));
|
||||
|
||||
/* Attribute data is contained in event->notify_rx.attr_data. */
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.channel_id,
|
||||
event->mtu.value);
|
||||
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;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
blecent_on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
blecent_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Make sure we have proper identity address set (public preferred) */
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Begin scanning for a peripheral to connect to. */
|
||||
blecent_scan();
|
||||
}
|
||||
|
||||
/**
|
||||
* main
|
||||
*
|
||||
* All application logic and NimBLE host work is performed in default task.
|
||||
*
|
||||
* @return int NOTE: this function should never return!
|
||||
*/
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
/* Configure the host. */
|
||||
ble_hs_cfg.reset_cb = blecent_on_reset;
|
||||
ble_hs_cfg.sync_cb = blecent_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* Initialize data structures to track connected peers. */
|
||||
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name. */
|
||||
rc = ble_svc_gap_device_name_set("nimble-blecent");
|
||||
assert(rc == 0);
|
||||
|
||||
/* os start should never return. If it does, this should be an error */
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
209
src/libs/mynewt-nimble/apps/blecent/src/misc.c
Normal file
209
src/libs/mynewt-nimble/apps/blecent/src/misc.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* 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 "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "blecent.h"
|
||||
|
||||
/**
|
||||
* Utility function to log an array of bytes.
|
||||
*/
|
||||
void
|
||||
print_bytes(const uint8_t *bytes, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_mbuf(const struct os_mbuf *om)
|
||||
{
|
||||
int colon;
|
||||
|
||||
colon = 0;
|
||||
while (om != NULL) {
|
||||
if (colon) {
|
||||
MODLOG_DFLT(DEBUG, ":");
|
||||
} else {
|
||||
colon = 1;
|
||||
}
|
||||
print_bytes(om->om_data, om->om_len);
|
||||
om = SLIST_NEXT(om, om_next);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
addr_str(const void *addr)
|
||||
{
|
||||
static char buf[6 * 2 + 5 + 1];
|
||||
const uint8_t *u8p;
|
||||
|
||||
u8p = addr;
|
||||
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
print_uuid(const ble_uuid_t *uuid)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
MODLOG_DFLT(DEBUG, "%s", ble_uuid_to_str(uuid, buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs information about a connection to the console.
|
||||
*/
|
||||
void
|
||||
print_conn_desc(const struct ble_gap_conn_desc *desc)
|
||||
{
|
||||
MODLOG_DFLT(DEBUG, "handle=%d our_ota_addr_type=%d our_ota_addr=%s ",
|
||||
desc->conn_handle, desc->our_ota_addr.type,
|
||||
addr_str(desc->our_ota_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "our_id_addr_type=%d our_id_addr=%s ",
|
||||
desc->our_id_addr.type, addr_str(desc->our_id_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "peer_ota_addr_type=%d peer_ota_addr=%s ",
|
||||
desc->peer_ota_addr.type, addr_str(desc->peer_ota_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "peer_id_addr_type=%d peer_id_addr=%s ",
|
||||
desc->peer_id_addr.type, addr_str(desc->peer_id_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "conn_itvl=%d conn_latency=%d supervision_timeout=%d "
|
||||
"encrypted=%d authenticated=%d bonded=%d",
|
||||
desc->conn_itvl, desc->conn_latency,
|
||||
desc->supervision_timeout,
|
||||
desc->sec_state.encrypted,
|
||||
desc->sec_state.authenticated,
|
||||
desc->sec_state.bonded);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_adv_fields(const struct ble_hs_adv_fields *fields)
|
||||
{
|
||||
char s[BLE_HS_ADV_MAX_SZ];
|
||||
const uint8_t *u8p;
|
||||
int i;
|
||||
|
||||
if (fields->flags != 0) {
|
||||
MODLOG_DFLT(DEBUG, " flags=0x%02x\n", fields->flags);
|
||||
}
|
||||
|
||||
if (fields->uuids16 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uuids16(%scomplete)=",
|
||||
fields->uuids16_is_complete ? "" : "in");
|
||||
for (i = 0; i < fields->num_uuids16; i++) {
|
||||
print_uuid(&fields->uuids16[i].u);
|
||||
MODLOG_DFLT(DEBUG, " ");
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->uuids32 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uuids32(%scomplete)=",
|
||||
fields->uuids32_is_complete ? "" : "in");
|
||||
for (i = 0; i < fields->num_uuids32; i++) {
|
||||
print_uuid(&fields->uuids32[i].u);
|
||||
MODLOG_DFLT(DEBUG, " ");
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->uuids128 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uuids128(%scomplete)=",
|
||||
fields->uuids128_is_complete ? "" : "in");
|
||||
for (i = 0; i < fields->num_uuids128; i++) {
|
||||
print_uuid(&fields->uuids128[i].u);
|
||||
MODLOG_DFLT(DEBUG, " ");
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->name != NULL) {
|
||||
assert(fields->name_len < sizeof s - 1);
|
||||
memcpy(s, fields->name, fields->name_len);
|
||||
s[fields->name_len] = '\0';
|
||||
MODLOG_DFLT(DEBUG, " name(%scomplete)=%s\n",
|
||||
fields->name_is_complete ? "" : "in", s);
|
||||
}
|
||||
|
||||
if (fields->tx_pwr_lvl_is_present) {
|
||||
MODLOG_DFLT(DEBUG, " tx_pwr_lvl=%d\n", fields->tx_pwr_lvl);
|
||||
}
|
||||
|
||||
if (fields->slave_itvl_range != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " slave_itvl_range=");
|
||||
print_bytes(fields->slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->svc_data_uuid16 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " svc_data_uuid16=");
|
||||
print_bytes(fields->svc_data_uuid16, fields->svc_data_uuid16_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->public_tgt_addr != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " public_tgt_addr=");
|
||||
u8p = fields->public_tgt_addr;
|
||||
for (i = 0; i < fields->num_public_tgt_addrs; i++) {
|
||||
MODLOG_DFLT(DEBUG, "public_tgt_addr=%s ", addr_str(u8p));
|
||||
u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->appearance_is_present) {
|
||||
MODLOG_DFLT(DEBUG, " appearance=0x%04x\n", fields->appearance);
|
||||
}
|
||||
|
||||
if (fields->adv_itvl_is_present) {
|
||||
MODLOG_DFLT(DEBUG, " adv_itvl=0x%04x\n", fields->adv_itvl);
|
||||
}
|
||||
|
||||
if (fields->svc_data_uuid32 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " svc_data_uuid32=");
|
||||
print_bytes(fields->svc_data_uuid32, fields->svc_data_uuid32_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->svc_data_uuid128 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " svc_data_uuid128=");
|
||||
print_bytes(fields->svc_data_uuid128, fields->svc_data_uuid128_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->uri != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uri=");
|
||||
print_bytes(fields->uri, fields->uri_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->mfg_data != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " mfg_data=");
|
||||
print_bytes(fields->mfg_data, fields->mfg_data_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
}
|
||||
807
src/libs/mynewt-nimble/apps/blecent/src/peer.c
Normal file
807
src/libs/mynewt-nimble/apps/blecent/src/peer.c
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include "host/ble_hs.h"
|
||||
#include "blecent.h"
|
||||
|
||||
static void *peer_svc_mem;
|
||||
static struct os_mempool peer_svc_pool;
|
||||
|
||||
static void *peer_chr_mem;
|
||||
static struct os_mempool peer_chr_pool;
|
||||
|
||||
static void *peer_dsc_mem;
|
||||
static struct os_mempool peer_dsc_pool;
|
||||
|
||||
static void *peer_mem;
|
||||
static struct os_mempool peer_pool;
|
||||
static SLIST_HEAD(, peer) peers;
|
||||
|
||||
static struct peer_svc *
|
||||
peer_svc_find_range(struct peer *peer, uint16_t attr_handle);
|
||||
static struct peer_svc *
|
||||
peer_svc_find(struct peer *peer, uint16_t svc_start_handle,
|
||||
struct peer_svc **out_prev);
|
||||
int
|
||||
peer_svc_is_empty(const struct peer_svc *svc);
|
||||
|
||||
uint16_t
|
||||
chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr);
|
||||
int
|
||||
chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr);
|
||||
static struct peer_chr *
|
||||
peer_chr_find(const struct peer_svc *svc, uint16_t chr_def_handle,
|
||||
struct peer_chr **out_prev);
|
||||
static void
|
||||
peer_disc_chrs(struct peer *peer);
|
||||
|
||||
static int
|
||||
peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
|
||||
void *arg);
|
||||
|
||||
static struct peer *
|
||||
peer_find(uint16_t conn_handle)
|
||||
{
|
||||
struct peer *peer;
|
||||
|
||||
SLIST_FOREACH(peer, &peers, next) {
|
||||
if (peer->conn_handle == conn_handle) {
|
||||
return peer;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
peer_disc_complete(struct peer *peer, int rc)
|
||||
{
|
||||
peer->disc_prev_chr_val = 0;
|
||||
|
||||
/* Notify caller that discovery has completed. */
|
||||
if (peer->disc_cb != NULL) {
|
||||
peer->disc_cb(peer, rc, peer->disc_cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
static struct peer_dsc *
|
||||
peer_dsc_find_prev(const struct peer_chr *chr, uint16_t dsc_handle)
|
||||
{
|
||||
struct peer_dsc *prev;
|
||||
struct peer_dsc *dsc;
|
||||
|
||||
prev = NULL;
|
||||
SLIST_FOREACH(dsc, &chr->dscs, next) {
|
||||
if (dsc->dsc.handle >= dsc_handle) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = dsc;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static struct peer_dsc *
|
||||
peer_dsc_find(const struct peer_chr *chr, uint16_t dsc_handle,
|
||||
struct peer_dsc **out_prev)
|
||||
{
|
||||
struct peer_dsc *prev;
|
||||
struct peer_dsc *dsc;
|
||||
|
||||
prev = peer_dsc_find_prev(chr, dsc_handle);
|
||||
if (prev == NULL) {
|
||||
dsc = SLIST_FIRST(&chr->dscs);
|
||||
} else {
|
||||
dsc = SLIST_NEXT(prev, next);
|
||||
}
|
||||
|
||||
if (dsc != NULL && dsc->dsc.handle != dsc_handle) {
|
||||
dsc = NULL;
|
||||
}
|
||||
|
||||
if (out_prev != NULL) {
|
||||
*out_prev = prev;
|
||||
}
|
||||
return dsc;
|
||||
}
|
||||
|
||||
static int
|
||||
peer_dsc_add(struct peer *peer, uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc *gatt_dsc)
|
||||
{
|
||||
struct peer_dsc *prev;
|
||||
struct peer_dsc *dsc;
|
||||
struct peer_svc *svc;
|
||||
struct peer_chr *chr;
|
||||
|
||||
svc = peer_svc_find_range(peer, chr_val_handle);
|
||||
if (svc == NULL) {
|
||||
/* Can't find service for discovered descriptor; this shouldn't
|
||||
* happen.
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_HS_EUNKNOWN;
|
||||
}
|
||||
|
||||
chr = peer_chr_find(svc, chr_val_handle, NULL);
|
||||
if (chr == NULL) {
|
||||
/* Can't find characteristic for discovered descriptor; this shouldn't
|
||||
* happen.
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_HS_EUNKNOWN;
|
||||
}
|
||||
|
||||
dsc = peer_dsc_find(chr, gatt_dsc->handle, &prev);
|
||||
if (dsc != NULL) {
|
||||
/* Descriptor already discovered. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
dsc = os_memblock_get(&peer_dsc_pool);
|
||||
if (dsc == NULL) {
|
||||
/* Out of memory. */
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
memset(dsc, 0, sizeof *dsc);
|
||||
|
||||
dsc->dsc = *gatt_dsc;
|
||||
|
||||
if (prev == NULL) {
|
||||
SLIST_INSERT_HEAD(&chr->dscs, dsc, next);
|
||||
} else {
|
||||
SLIST_NEXT(prev, next) = dsc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
peer_disc_dscs(struct peer *peer)
|
||||
{
|
||||
struct peer_chr *chr;
|
||||
struct peer_svc *svc;
|
||||
int rc;
|
||||
|
||||
/* Search through the list of discovered characteristics for the first
|
||||
* characteristic that contains undiscovered descriptors. Then, discover
|
||||
* all descriptors belonging to that characteristic.
|
||||
*/
|
||||
SLIST_FOREACH(svc, &peer->svcs, next) {
|
||||
SLIST_FOREACH(chr, &svc->chrs, next) {
|
||||
if (!chr_is_empty(svc, chr) &&
|
||||
SLIST_EMPTY(&chr->dscs) &&
|
||||
peer->disc_prev_chr_val <= chr->chr.def_handle) {
|
||||
|
||||
rc = ble_gattc_disc_all_dscs(peer->conn_handle,
|
||||
chr->chr.val_handle,
|
||||
chr_end_handle(svc, chr),
|
||||
peer_dsc_disced, peer);
|
||||
if (rc != 0) {
|
||||
peer_disc_complete(peer, rc);
|
||||
}
|
||||
|
||||
peer->disc_prev_chr_val = chr->chr.val_handle;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* All descriptors discovered. */
|
||||
peer_disc_complete(peer, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
|
||||
void *arg)
|
||||
{
|
||||
struct peer *peer;
|
||||
int rc;
|
||||
|
||||
peer = arg;
|
||||
assert(peer->conn_handle == conn_handle);
|
||||
|
||||
switch (error->status) {
|
||||
case 0:
|
||||
rc = peer_dsc_add(peer, chr_val_handle, dsc);
|
||||
break;
|
||||
|
||||
case BLE_HS_EDONE:
|
||||
/* All descriptors in this characteristic discovered; start discovering
|
||||
* descriptors in the next characteristic.
|
||||
*/
|
||||
if (peer->disc_prev_chr_val > 0) {
|
||||
peer_disc_dscs(peer);
|
||||
}
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Error; abort discovery. */
|
||||
rc = error->status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
/* Error; abort discovery. */
|
||||
peer_disc_complete(peer, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr)
|
||||
{
|
||||
const struct peer_chr *next_chr;
|
||||
|
||||
next_chr = SLIST_NEXT(chr, next);
|
||||
if (next_chr != NULL) {
|
||||
return next_chr->chr.def_handle - 1;
|
||||
} else {
|
||||
return svc->svc.end_handle;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr)
|
||||
{
|
||||
return chr_end_handle(svc, chr) <= chr->chr.val_handle;
|
||||
}
|
||||
|
||||
static struct peer_chr *
|
||||
peer_chr_find_prev(const struct peer_svc *svc, uint16_t chr_val_handle)
|
||||
{
|
||||
struct peer_chr *prev;
|
||||
struct peer_chr *chr;
|
||||
|
||||
prev = NULL;
|
||||
SLIST_FOREACH(chr, &svc->chrs, next) {
|
||||
if (chr->chr.val_handle >= chr_val_handle) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = chr;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static struct peer_chr *
|
||||
peer_chr_find(const struct peer_svc *svc, uint16_t chr_val_handle,
|
||||
struct peer_chr **out_prev)
|
||||
{
|
||||
struct peer_chr *prev;
|
||||
struct peer_chr *chr;
|
||||
|
||||
prev = peer_chr_find_prev(svc, chr_val_handle);
|
||||
if (prev == NULL) {
|
||||
chr = SLIST_FIRST(&svc->chrs);
|
||||
} else {
|
||||
chr = SLIST_NEXT(prev, next);
|
||||
}
|
||||
|
||||
if (chr != NULL && chr->chr.val_handle != chr_val_handle) {
|
||||
chr = NULL;
|
||||
}
|
||||
|
||||
if (out_prev != NULL) {
|
||||
*out_prev = prev;
|
||||
}
|
||||
return chr;
|
||||
}
|
||||
|
||||
static void
|
||||
peer_chr_delete(struct peer_chr *chr)
|
||||
{
|
||||
struct peer_dsc *dsc;
|
||||
|
||||
while ((dsc = SLIST_FIRST(&chr->dscs)) != NULL) {
|
||||
SLIST_REMOVE_HEAD(&chr->dscs, next);
|
||||
os_memblock_put(&peer_dsc_pool, dsc);
|
||||
}
|
||||
|
||||
os_memblock_put(&peer_chr_pool, chr);
|
||||
}
|
||||
|
||||
static int
|
||||
peer_chr_add(struct peer *peer, uint16_t svc_start_handle,
|
||||
const struct ble_gatt_chr *gatt_chr)
|
||||
{
|
||||
struct peer_chr *prev;
|
||||
struct peer_chr *chr;
|
||||
struct peer_svc *svc;
|
||||
|
||||
svc = peer_svc_find(peer, svc_start_handle, NULL);
|
||||
if (svc == NULL) {
|
||||
/* Can't find service for discovered characteristic; this shouldn't
|
||||
* happen.
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_HS_EUNKNOWN;
|
||||
}
|
||||
|
||||
chr = peer_chr_find(svc, gatt_chr->def_handle, &prev);
|
||||
if (chr != NULL) {
|
||||
/* Characteristic already discovered. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
chr = os_memblock_get(&peer_chr_pool);
|
||||
if (chr == NULL) {
|
||||
/* Out of memory. */
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
memset(chr, 0, sizeof *chr);
|
||||
|
||||
chr->chr = *gatt_chr;
|
||||
|
||||
if (prev == NULL) {
|
||||
SLIST_INSERT_HEAD(&svc->chrs, chr, next);
|
||||
} else {
|
||||
SLIST_NEXT(prev, next) = chr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
peer_chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg)
|
||||
{
|
||||
struct peer *peer;
|
||||
int rc;
|
||||
|
||||
peer = arg;
|
||||
assert(peer->conn_handle == conn_handle);
|
||||
|
||||
switch (error->status) {
|
||||
case 0:
|
||||
rc = peer_chr_add(peer, peer->cur_svc->svc.start_handle, chr);
|
||||
break;
|
||||
|
||||
case BLE_HS_EDONE:
|
||||
/* All characteristics in this service discovered; start discovering
|
||||
* characteristics in the next service.
|
||||
*/
|
||||
if (peer->disc_prev_chr_val > 0) {
|
||||
peer_disc_chrs(peer);
|
||||
}
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = error->status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
/* Error; abort discovery. */
|
||||
peer_disc_complete(peer, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
peer_disc_chrs(struct peer *peer)
|
||||
{
|
||||
struct peer_svc *svc;
|
||||
int rc;
|
||||
|
||||
/* Search through the list of discovered service for the first service that
|
||||
* contains undiscovered characteristics. Then, discover all
|
||||
* characteristics belonging to that service.
|
||||
*/
|
||||
SLIST_FOREACH(svc, &peer->svcs, next) {
|
||||
if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) {
|
||||
peer->cur_svc = svc;
|
||||
rc = ble_gattc_disc_all_chrs(peer->conn_handle,
|
||||
svc->svc.start_handle,
|
||||
svc->svc.end_handle,
|
||||
peer_chr_disced, peer);
|
||||
if (rc != 0) {
|
||||
peer_disc_complete(peer, rc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* All characteristics discovered. */
|
||||
peer_disc_dscs(peer);
|
||||
}
|
||||
|
||||
int
|
||||
peer_svc_is_empty(const struct peer_svc *svc)
|
||||
{
|
||||
return svc->svc.end_handle <= svc->svc.start_handle;
|
||||
}
|
||||
|
||||
static struct peer_svc *
|
||||
peer_svc_find_prev(struct peer *peer, uint16_t svc_start_handle)
|
||||
{
|
||||
struct peer_svc *prev;
|
||||
struct peer_svc *svc;
|
||||
|
||||
prev = NULL;
|
||||
SLIST_FOREACH(svc, &peer->svcs, next) {
|
||||
if (svc->svc.start_handle >= svc_start_handle) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = svc;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static struct peer_svc *
|
||||
peer_svc_find(struct peer *peer, uint16_t svc_start_handle,
|
||||
struct peer_svc **out_prev)
|
||||
{
|
||||
struct peer_svc *prev;
|
||||
struct peer_svc *svc;
|
||||
|
||||
prev = peer_svc_find_prev(peer, svc_start_handle);
|
||||
if (prev == NULL) {
|
||||
svc = SLIST_FIRST(&peer->svcs);
|
||||
} else {
|
||||
svc = SLIST_NEXT(prev, next);
|
||||
}
|
||||
|
||||
if (svc != NULL && svc->svc.start_handle != svc_start_handle) {
|
||||
svc = NULL;
|
||||
}
|
||||
|
||||
if (out_prev != NULL) {
|
||||
*out_prev = prev;
|
||||
}
|
||||
return svc;
|
||||
}
|
||||
|
||||
static struct peer_svc *
|
||||
peer_svc_find_range(struct peer *peer, uint16_t attr_handle)
|
||||
{
|
||||
struct peer_svc *svc;
|
||||
|
||||
SLIST_FOREACH(svc, &peer->svcs, next) {
|
||||
if (svc->svc.start_handle <= attr_handle &&
|
||||
svc->svc.end_handle >= attr_handle) {
|
||||
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct peer_svc *
|
||||
peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid)
|
||||
{
|
||||
const struct peer_svc *svc;
|
||||
|
||||
SLIST_FOREACH(svc, &peer->svcs, next) {
|
||||
if (ble_uuid_cmp(&svc->svc.uuid.u, uuid) == 0) {
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct peer_chr *
|
||||
peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
|
||||
const ble_uuid_t *chr_uuid)
|
||||
{
|
||||
const struct peer_svc *svc;
|
||||
const struct peer_chr *chr;
|
||||
|
||||
svc = peer_svc_find_uuid(peer, svc_uuid);
|
||||
if (svc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SLIST_FOREACH(chr, &svc->chrs, next) {
|
||||
if (ble_uuid_cmp(&chr->chr.uuid.u, chr_uuid) == 0) {
|
||||
return chr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct peer_dsc *
|
||||
peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
|
||||
const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid)
|
||||
{
|
||||
const struct peer_chr *chr;
|
||||
const struct peer_dsc *dsc;
|
||||
|
||||
chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid);
|
||||
if (chr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SLIST_FOREACH(dsc, &chr->dscs, next) {
|
||||
if (ble_uuid_cmp(&dsc->dsc.uuid.u, dsc_uuid) == 0) {
|
||||
return dsc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
peer_svc_add(struct peer *peer, const struct ble_gatt_svc *gatt_svc)
|
||||
{
|
||||
struct peer_svc *prev;
|
||||
struct peer_svc *svc;
|
||||
|
||||
svc = peer_svc_find(peer, gatt_svc->start_handle, &prev);
|
||||
if (svc != NULL) {
|
||||
/* Service already discovered. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
svc = os_memblock_get(&peer_svc_pool);
|
||||
if (svc == NULL) {
|
||||
/* Out of memory. */
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
memset(svc, 0, sizeof *svc);
|
||||
|
||||
svc->svc = *gatt_svc;
|
||||
SLIST_INIT(&svc->chrs);
|
||||
|
||||
if (prev == NULL) {
|
||||
SLIST_INSERT_HEAD(&peer->svcs, svc, next);
|
||||
} else {
|
||||
SLIST_INSERT_AFTER(prev, svc, next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
peer_svc_delete(struct peer_svc *svc)
|
||||
{
|
||||
struct peer_chr *chr;
|
||||
|
||||
while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) {
|
||||
SLIST_REMOVE_HEAD(&svc->chrs, next);
|
||||
peer_chr_delete(chr);
|
||||
}
|
||||
|
||||
os_memblock_put(&peer_svc_pool, svc);
|
||||
}
|
||||
|
||||
static int
|
||||
peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_svc *service, void *arg)
|
||||
{
|
||||
struct peer *peer;
|
||||
int rc;
|
||||
|
||||
peer = arg;
|
||||
assert(peer->conn_handle == conn_handle);
|
||||
|
||||
switch (error->status) {
|
||||
case 0:
|
||||
rc = peer_svc_add(peer, service);
|
||||
break;
|
||||
|
||||
case BLE_HS_EDONE:
|
||||
/* All services discovered; start discovering characteristics. */
|
||||
if (peer->disc_prev_chr_val > 0) {
|
||||
peer_disc_chrs(peer);
|
||||
}
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = error->status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
/* Error; abort discovery. */
|
||||
peer_disc_complete(peer, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb, void *disc_cb_arg)
|
||||
{
|
||||
struct peer_svc *svc;
|
||||
struct peer *peer;
|
||||
int rc;
|
||||
|
||||
peer = peer_find(conn_handle);
|
||||
if (peer == NULL) {
|
||||
return BLE_HS_ENOTCONN;
|
||||
}
|
||||
|
||||
/* Undiscover everything first. */
|
||||
while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) {
|
||||
SLIST_REMOVE_HEAD(&peer->svcs, next);
|
||||
peer_svc_delete(svc);
|
||||
}
|
||||
|
||||
peer->disc_prev_chr_val = 1;
|
||||
peer->disc_cb = disc_cb;
|
||||
peer->disc_cb_arg = disc_cb_arg;
|
||||
|
||||
rc = ble_gattc_disc_all_svcs(conn_handle, peer_svc_disced, peer);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
peer_delete(uint16_t conn_handle)
|
||||
{
|
||||
struct peer_svc *svc;
|
||||
struct peer *peer;
|
||||
int rc;
|
||||
|
||||
peer = peer_find(conn_handle);
|
||||
if (peer == NULL) {
|
||||
return BLE_HS_ENOTCONN;
|
||||
}
|
||||
|
||||
SLIST_REMOVE(&peers, peer, peer, next);
|
||||
|
||||
while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) {
|
||||
SLIST_REMOVE_HEAD(&peer->svcs, next);
|
||||
peer_svc_delete(svc);
|
||||
}
|
||||
|
||||
rc = os_memblock_put(&peer_pool, peer);
|
||||
if (rc != 0) {
|
||||
return BLE_HS_EOS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
peer_add(uint16_t conn_handle)
|
||||
{
|
||||
struct peer *peer;
|
||||
|
||||
/* Make sure the connection handle is unique. */
|
||||
peer = peer_find(conn_handle);
|
||||
if (peer != NULL) {
|
||||
return BLE_HS_EALREADY;
|
||||
}
|
||||
|
||||
peer = os_memblock_get(&peer_pool);
|
||||
if (peer == NULL) {
|
||||
/* Out of memory. */
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
|
||||
memset(peer, 0, sizeof *peer);
|
||||
peer->conn_handle = conn_handle;
|
||||
|
||||
SLIST_INSERT_HEAD(&peers, peer, next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
peer_free_mem(void)
|
||||
{
|
||||
free(peer_mem);
|
||||
peer_mem = NULL;
|
||||
|
||||
free(peer_svc_mem);
|
||||
peer_svc_mem = NULL;
|
||||
|
||||
free(peer_chr_mem);
|
||||
peer_chr_mem = NULL;
|
||||
|
||||
free(peer_dsc_mem);
|
||||
peer_dsc_mem = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Free memory first in case this function gets called more than once. */
|
||||
peer_free_mem();
|
||||
|
||||
peer_mem = malloc(
|
||||
OS_MEMPOOL_BYTES(max_peers, sizeof (struct peer)));
|
||||
if (peer_mem == NULL) {
|
||||
rc = BLE_HS_ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = os_mempool_init(&peer_pool, max_peers,
|
||||
sizeof (struct peer), peer_mem,
|
||||
"peer_pool");
|
||||
if (rc != 0) {
|
||||
rc = BLE_HS_EOS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
peer_svc_mem = malloc(
|
||||
OS_MEMPOOL_BYTES(max_svcs, sizeof (struct peer_svc)));
|
||||
if (peer_svc_mem == NULL) {
|
||||
rc = BLE_HS_ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = os_mempool_init(&peer_svc_pool, max_svcs,
|
||||
sizeof (struct peer_svc), peer_svc_mem,
|
||||
"peer_svc_pool");
|
||||
if (rc != 0) {
|
||||
rc = BLE_HS_EOS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
peer_chr_mem = malloc(
|
||||
OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr)));
|
||||
if (peer_chr_mem == NULL) {
|
||||
rc = BLE_HS_ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = os_mempool_init(&peer_chr_pool, max_chrs,
|
||||
sizeof (struct peer_chr), peer_chr_mem,
|
||||
"peer_chr_pool");
|
||||
if (rc != 0) {
|
||||
rc = BLE_HS_EOS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
peer_dsc_mem = malloc(
|
||||
OS_MEMPOOL_BYTES(max_dscs, sizeof (struct peer_dsc)));
|
||||
if (peer_dsc_mem == NULL) {
|
||||
rc = BLE_HS_ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = os_mempool_init(&peer_dsc_pool, max_dscs,
|
||||
sizeof (struct peer_dsc), peer_dsc_mem,
|
||||
"peer_dsc_pool");
|
||||
if (rc != 0) {
|
||||
rc = BLE_HS_EOS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
peer_free_mem();
|
||||
return rc;
|
||||
}
|
||||
30
src/libs/mynewt-nimble/apps/blecent/syscfg.yml
Normal file
30
src/libs/mynewt-nimble/apps/blecent/syscfg.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# 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.vals:
|
||||
# DEBUG logging is a bit noisy; use INFO.
|
||||
LOG_LEVEL: 1
|
||||
|
||||
# Default task settings
|
||||
OS_MAIN_STACK_SIZE: 336
|
||||
|
||||
# Disable peripheral and broadcaster roles.
|
||||
BLE_ROLE_BROADCASTER: 0
|
||||
BLE_ROLE_CENTRAL: 1
|
||||
BLE_ROLE_OBSERVER: 1
|
||||
BLE_ROLE_PERIPHERAL: 0
|
||||
9
src/libs/mynewt-nimble/apps/blecsc/README.md
Normal file
9
src/libs/mynewt-nimble/apps/blecsc/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# BLE Cycling Speed and Cadence peripheral app.
|
||||
|
||||
The source files are located in the src/ directory.
|
||||
|
||||
pkg.yml contains the base definition of the app.
|
||||
|
||||
syscfg.yml contains setting definitions and overrides.
|
||||
|
||||
|
||||
40
src/libs/mynewt-nimble/apps/blecsc/pkg.yml
Normal file
40
src/libs/mynewt-nimble/apps/blecsc/pkg.yml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# 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/blecsc
|
||||
pkg.type: app
|
||||
pkg.description: BLE peripheral cycling speed and cadence sensor.
|
||||
pkg.author: "Maciej Jurczak"
|
||||
pkg.email: "mjurczak@gmail.com"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@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/sysinit"
|
||||
- "@apache-mynewt-core/sys/id"
|
||||
- nimble/controller
|
||||
- nimble/host
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/host/store/config
|
||||
- nimble/transport
|
||||
105
src/libs/mynewt-nimble/apps/blecsc/src/blecsc_sens.h
Normal file
105
src/libs/mynewt-nimble/apps/blecsc/src/blecsc_sens.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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_BLECSC_SENSOR_
|
||||
#define H_BLECSC_SENSOR_
|
||||
|
||||
#include "modlog/modlog.h"
|
||||
#include "nimble/ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Cycling Speed and Cadence configuration */
|
||||
#define GATT_CSC_UUID 0x1816
|
||||
#define GATT_CSC_MEASUREMENT_UUID 0x2A5B
|
||||
#define GATT_CSC_FEATURE_UUID 0x2A5C
|
||||
#define GATT_SENSOR_LOCATION_UUID 0x2A5D
|
||||
#define GATT_SC_CONTROL_POINT_UUID 0x2A55
|
||||
/* Device Information configuration */
|
||||
#define GATT_DEVICE_INFO_UUID 0x180A
|
||||
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
|
||||
#define GATT_MODEL_NUMBER_UUID 0x2A24
|
||||
|
||||
/*CSC Measurement flags*/
|
||||
#define CSC_MEASUREMENT_WHEEL_REV_PRESENT 0x01
|
||||
#define CSC_MEASUREMENT_CRANK_REV_PRESENT 0x02
|
||||
|
||||
/* CSC feature flags */
|
||||
#define CSC_FEATURE_WHEEL_REV_DATA 0x01
|
||||
#define CSC_FEATURE_CRANK_REV_DATA 0x02
|
||||
#define CSC_FEATURE_MULTIPLE_SENSOR_LOC 0x04
|
||||
|
||||
/* Sensor location enum */
|
||||
#define SENSOR_LOCATION_OTHER 0
|
||||
#define SENSOR_LOCATION_TOP_OF_SHOE 1
|
||||
#define SENSOR_LOCATION_IN_SHOE 2
|
||||
#define SENSOR_LOCATION_HIP 3
|
||||
#define SENSOR_LOCATION_FRONT_WHEEL 4
|
||||
#define SENSOR_LOCATION_LEFT_CRANK 5
|
||||
#define SENSOR_LOCATION_RIGHT_CRANK 6
|
||||
#define SENSOR_LOCATION_LEFT_PEDAL 7
|
||||
#define SENSOR_LOCATION_RIGHT_PEDAL 8
|
||||
#define SENSOR_LOCATION_FROT_HUB 9
|
||||
#define SENSOR_LOCATION_REAR_DROPOUT 10
|
||||
#define SENSOR_LOCATION_CHAINSTAY 11
|
||||
#define SENSOR_LOCATION_REAR_WHEEL 12
|
||||
#define SENSOR_LOCATION_REAR_HUB 13
|
||||
#define SENSOR_LOCATION_CHEST 14
|
||||
#define SENSOR_LOCATION_SPIDER 15
|
||||
#define SENSOR_LOCATION_CHAIN_RING 16
|
||||
|
||||
/* SC Control Point op codes */
|
||||
#define SC_CP_OP_SET_CUMULATIVE_VALUE 1
|
||||
#define SC_CP_OP_START_SENSOR_CALIBRATION 2
|
||||
#define SC_CP_OP_UPDATE_SENSOR_LOCATION 3
|
||||
#define SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS 4
|
||||
#define SC_CP_OP_RESPONSE 16
|
||||
|
||||
/*SC Control Point response values */
|
||||
#define SC_CP_RESPONSE_SUCCESS 1
|
||||
#define SC_CP_RESPONSE_OP_NOT_SUPPORTED 2
|
||||
#define SC_CP_RESPONSE_INVALID_PARAM 3
|
||||
#define SC_CP_RESPONSE_OP_FAILED 4
|
||||
|
||||
/* CSC simulation configuration */
|
||||
#define CSC_FEATURES (CSC_FEATURE_WHEEL_REV_DATA | \
|
||||
CSC_FEATURE_CRANK_REV_DATA |\
|
||||
CSC_FEATURE_MULTIPLE_SENSOR_LOC)
|
||||
|
||||
struct ble_csc_measurement_state {
|
||||
uint32_t cumulative_wheel_rev;
|
||||
uint16_t last_wheel_evt_time;
|
||||
uint16_t cumulative_crank_rev;
|
||||
uint16_t last_crank_evt_time;
|
||||
};
|
||||
|
||||
extern uint16_t csc_measurement_handle;
|
||||
extern uint16_t csc_control_point_handle;
|
||||
|
||||
int gatt_svr_init(struct ble_csc_measurement_state * csc_measurement_state);
|
||||
int gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle);
|
||||
void gatt_svr_set_cp_indicate(uint8_t indication_status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
385
src/libs/mynewt-nimble/apps/blecsc/src/gatt_svr.c
Normal file
385
src/libs/mynewt-nimble/apps/blecsc/src/gatt_svr.c
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
* 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 "os/mynewt.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "blecsc_sens.h"
|
||||
|
||||
#define CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED 0x81
|
||||
|
||||
static const char *manuf_name = "Apache Mynewt";
|
||||
static const char *model_num = "Mynewt CSC Sensor";
|
||||
|
||||
static const uint8_t csc_supported_sensor_locations[] = {
|
||||
SENSOR_LOCATION_FRONT_WHEEL,
|
||||
SENSOR_LOCATION_REAR_DROPOUT,
|
||||
SENSOR_LOCATION_CHAINSTAY,
|
||||
SENSOR_LOCATION_REAR_WHEEL
|
||||
};
|
||||
|
||||
static uint8_t sensor_location = SENSOR_LOCATION_REAR_DROPOUT;
|
||||
static struct ble_csc_measurement_state * measurement_state;
|
||||
uint16_t csc_measurement_handle;
|
||||
uint16_t csc_control_point_handle;
|
||||
uint8_t csc_cp_indication_status;
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_csc_measurement(uint16_t conn_handle,
|
||||
uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_csc_feature(uint16_t conn_handle,
|
||||
uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sensor_location(uint16_t conn_handle,
|
||||
uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
|
||||
uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_device_info(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[] = {
|
||||
{
|
||||
/* Service: Cycling Speed and Cadence */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_CSC_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: Cycling Speed and Cadence Measurement */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_CSC_MEASUREMENT_UUID),
|
||||
.access_cb = gatt_svr_chr_access_csc_measurement,
|
||||
.val_handle = &csc_measurement_handle,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
}, {
|
||||
/* Characteristic: Cycling Speed and Cadence features */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_CSC_FEATURE_UUID),
|
||||
.access_cb = gatt_svr_chr_access_csc_feature,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
/* Characteristic: Sensor Location */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_SENSOR_LOCATION_UUID),
|
||||
.access_cb = gatt_svr_chr_access_sensor_location,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
/* Characteristic: SC Control Point*/
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_SC_CONTROL_POINT_UUID),
|
||||
.access_cb = gatt_svr_chr_access_sc_control_point,
|
||||
.val_handle = &csc_control_point_handle,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
|
||||
{
|
||||
/* Service: Device Information */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: * Manufacturer name */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
/* Characteristic: Model number string */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_csc_measurement(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
return BLE_ATT_ERR_READ_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_csc_feature(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
static const uint16_t csc_feature = CSC_FEATURES;
|
||||
int rc;
|
||||
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
rc = os_mbuf_append(ctxt->om, &csc_feature, sizeof(csc_feature));
|
||||
|
||||
return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sensor_location(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
rc = os_mbuf_append(ctxt->om, &sensor_location, sizeof(sensor_location));
|
||||
|
||||
return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
|
||||
uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
uint8_t op_code;
|
||||
uint8_t new_sensor_location;
|
||||
uint8_t new_cumulative_wheel_rev_arr[4];
|
||||
struct os_mbuf *om_indication;
|
||||
uint8_t response = SC_CP_RESPONSE_OP_NOT_SUPPORTED;
|
||||
int ii;
|
||||
int rc;
|
||||
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
|
||||
|
||||
if (!csc_cp_indication_status) {
|
||||
MODLOG_DFLT(INFO, "SC Control Point; CCC descriptor "
|
||||
"improperly configured");
|
||||
return CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED;
|
||||
}
|
||||
|
||||
/* Read control point op code*/
|
||||
rc = os_mbuf_copydata(ctxt->om, 0, sizeof(op_code), &op_code);
|
||||
if (rc != 0){
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
MODLOG_DFLT(INFO, "SC Control Point; opcode=%d\n", op_code);
|
||||
|
||||
/* Allocate response buffer */
|
||||
om_indication = ble_hs_mbuf_att_pkt();
|
||||
|
||||
switch(op_code){
|
||||
#if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
|
||||
case SC_CP_OP_SET_CUMULATIVE_VALUE:
|
||||
/* Read new cumulative wheel revolutions value*/
|
||||
rc = os_mbuf_copydata(ctxt->om, 1,
|
||||
sizeof(new_cumulative_wheel_rev_arr),
|
||||
new_cumulative_wheel_rev_arr);
|
||||
if (rc != 0){
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
measurement_state->cumulative_wheel_rev =
|
||||
get_le32(new_cumulative_wheel_rev_arr);
|
||||
|
||||
MODLOG_DFLT(INFO, "SC Control Point; Set cumulative value = %d\n",
|
||||
measurement_state->cumulative_wheel_rev);
|
||||
|
||||
response = SC_CP_RESPONSE_SUCCESS;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)
|
||||
case SC_CP_OP_UPDATE_SENSOR_LOCATION:
|
||||
/* Read new sensor location value*/
|
||||
rc = os_mbuf_copydata(ctxt->om, 1, 1, &new_sensor_location);
|
||||
if (rc != 0){
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(INFO, "SC Control Point; Sensor location update = %d\n",
|
||||
new_sensor_location);
|
||||
|
||||
/* Verify if requested new location is on supported locations list */
|
||||
response = SC_CP_RESPONSE_INVALID_PARAM;
|
||||
for (ii = 0; ii < sizeof(csc_supported_sensor_locations); ii++){
|
||||
if (new_sensor_location == csc_supported_sensor_locations[ii]){
|
||||
sensor_location = new_sensor_location;
|
||||
response = SC_CP_RESPONSE_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS:
|
||||
response = SC_CP_RESPONSE_SUCCESS;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Append response value */
|
||||
rc = os_mbuf_append(om_indication, &response, sizeof(response));
|
||||
|
||||
if (rc != 0){
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
#if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)
|
||||
/* In case of supported locations request append locations list */
|
||||
if (op_code == SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS){
|
||||
rc = os_mbuf_append(om_indication, &csc_supported_sensor_locations,
|
||||
sizeof(csc_supported_sensor_locations));
|
||||
}
|
||||
|
||||
if (rc != 0){
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = ble_gattc_indicate_custom(conn_handle, csc_control_point_handle,
|
||||
om_indication);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
uint16_t uuid;
|
||||
int rc;
|
||||
|
||||
uuid = ble_uuid_u16(ctxt->chr->uuid);
|
||||
|
||||
if (uuid == GATT_MODEL_NUMBER_UUID) {
|
||||
rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
if (uuid == GATT_MANUFACTURER_NAME_UUID) {
|
||||
rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
int
|
||||
gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle)
|
||||
{
|
||||
int rc;
|
||||
struct os_mbuf *om;
|
||||
uint8_t data_buf[11];
|
||||
uint8_t data_offset = 1;
|
||||
|
||||
memset(data_buf, 0, sizeof(data_buf));
|
||||
|
||||
#if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
|
||||
data_buf[0] |= CSC_MEASUREMENT_WHEEL_REV_PRESENT;
|
||||
put_le16(&(data_buf[5]), measurement_state->last_wheel_evt_time);
|
||||
put_le32(&(data_buf[1]), measurement_state->cumulative_wheel_rev);
|
||||
data_offset += 6;
|
||||
#endif
|
||||
|
||||
#if (CSC_FEATURES & CSC_FEATURE_CRANK_REV_DATA)
|
||||
data_buf[0] |= CSC_MEASUREMENT_CRANK_REV_PRESENT;
|
||||
put_le16(&(data_buf[data_offset]),
|
||||
measurement_state->cumulative_crank_rev);
|
||||
put_le16(&(data_buf[data_offset + 2]),
|
||||
measurement_state->last_crank_evt_time);
|
||||
data_offset += 4;
|
||||
#endif
|
||||
|
||||
om = ble_hs_mbuf_from_flat(data_buf, data_offset);
|
||||
|
||||
rc = ble_gattc_notify_custom(conn_handle, csc_measurement_handle, om);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
gatt_svr_set_cp_indicate(uint8_t indication_status)
|
||||
{
|
||||
csc_cp_indication_status = indication_status;
|
||||
}
|
||||
|
||||
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(struct ble_csc_measurement_state * csc_measurement_state)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
measurement_state = csc_measurement_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
310
src/libs/mynewt-nimble/apps/blecsc/src/main.c
Normal file
310
src/libs/mynewt-nimble/apps/blecsc/src/main.c
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "os/mynewt.h"
|
||||
#include "console/console.h"
|
||||
#include "config/config.h"
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "blecsc_sens.h"
|
||||
|
||||
/* Wheel size for simulation calculations */
|
||||
#define CSC_SIM_WHEEL_CIRCUMFERENCE_MM 2000
|
||||
/* Simulated cadence lower limit */
|
||||
#define CSC_SIM_CRANK_RPM_MIN 20
|
||||
/* Simulated cadence upper limit */
|
||||
#define CSC_SIM_CRANK_RPM_MAX 100
|
||||
/* Simulated speed lower limit */
|
||||
#define CSC_SIM_SPEED_KPH_MIN 0
|
||||
/* Simulated speed upper limit */
|
||||
#define CSC_SIM_SPEED_KPH_MAX 35
|
||||
|
||||
/* Noticication status */
|
||||
static bool notify_state = false;
|
||||
|
||||
/* Connection handle */
|
||||
static uint16_t conn_handle;
|
||||
|
||||
static uint8_t blecsc_addr_type;
|
||||
|
||||
/* Advertised device name */
|
||||
static const char *device_name = "blecsc_sensor";
|
||||
|
||||
/* Measurement and notification timer */
|
||||
static struct os_callout blecsc_measure_timer;
|
||||
|
||||
/* Variable holds current CSC measurement state */
|
||||
static struct ble_csc_measurement_state csc_measurement_state;
|
||||
|
||||
/* Variable holds simulted speed (kilometers per hour) */
|
||||
static uint16_t csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN;
|
||||
|
||||
/* Variable holds simulated cadence (RPM) */
|
||||
static uint8_t csc_sim_crank_rpm = CSC_SIM_CRANK_RPM_MIN;
|
||||
|
||||
static int blecsc_gap_event(struct ble_gap_event *event, void *arg);
|
||||
|
||||
|
||||
/*
|
||||
* Enables advertising with parameters:
|
||||
* o General discoverable mode
|
||||
* o Undirected connectable mode
|
||||
*/
|
||||
static void
|
||||
blecsc_advertise(void)
|
||||
{
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info)
|
||||
* o Advertising tx power
|
||||
* o Device name
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assigning 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;
|
||||
|
||||
fields.name = (uint8_t *)device_name;
|
||||
fields.name_len = strlen(device_name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
/*
|
||||
* Set appearance.
|
||||
*/
|
||||
fields.appearance = ble_svc_gap_device_appearance();
|
||||
fields.appearance_is_present = 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(blecsc_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, blecsc_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update simulated CSC measurements.
|
||||
* Each call increments wheel and crank revolution counters by one and
|
||||
* computes last event time in order to match simulated candence and speed.
|
||||
* Last event time is expressedd in 1/1024th of second units.
|
||||
*
|
||||
* 60 * 1024
|
||||
* crank_dt = --------------
|
||||
* cadence[RPM]
|
||||
*
|
||||
*
|
||||
* circumference[mm] * 1024 * 60 * 60
|
||||
* wheel_dt = -------------------------------------
|
||||
* 10^6 * speed [kph]
|
||||
*/
|
||||
static void
|
||||
blecsc_simulate_speed_and_cadence(void)
|
||||
{
|
||||
uint16_t wheel_rev_period;
|
||||
uint16_t crank_rev_period;
|
||||
|
||||
/* Update simulated crank and wheel rotation speed */
|
||||
csc_sim_speed_kph++;
|
||||
if (csc_sim_speed_kph >= CSC_SIM_SPEED_KPH_MAX) {
|
||||
csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN;
|
||||
}
|
||||
|
||||
csc_sim_crank_rpm++;
|
||||
if (csc_sim_crank_rpm >= CSC_SIM_CRANK_RPM_MAX) {
|
||||
csc_sim_crank_rpm = CSC_SIM_CRANK_RPM_MIN;
|
||||
}
|
||||
|
||||
/* Calculate simulated measurement values */
|
||||
if (csc_sim_speed_kph > 0){
|
||||
wheel_rev_period = (36*64*CSC_SIM_WHEEL_CIRCUMFERENCE_MM) /
|
||||
(625*csc_sim_speed_kph);
|
||||
csc_measurement_state.cumulative_wheel_rev++;
|
||||
csc_measurement_state.last_wheel_evt_time += wheel_rev_period;
|
||||
}
|
||||
|
||||
if (csc_sim_crank_rpm > 0){
|
||||
crank_rev_period = (60*1024) / csc_sim_crank_rpm;
|
||||
csc_measurement_state.cumulative_crank_rev++;
|
||||
csc_measurement_state.last_crank_evt_time += crank_rev_period;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(INFO, "CSC simulated values: speed = %d kph, cadence = %d \n",
|
||||
csc_sim_speed_kph, csc_sim_crank_rpm);
|
||||
}
|
||||
|
||||
/* Run CSC measurement simulation and notify it to the client */
|
||||
static void
|
||||
blecsc_measurement(struct os_event *ev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = os_callout_reset(&blecsc_measure_timer, OS_TICKS_PER_SEC);
|
||||
assert(rc == 0);
|
||||
|
||||
blecsc_simulate_speed_and_cadence();
|
||||
|
||||
if (notify_state) {
|
||||
rc = gatt_svr_chr_notify_csc_measurement(conn_handle);
|
||||
assert(rc == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
blecsc_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
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\n",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
blecsc_advertise();
|
||||
conn_handle = 0;
|
||||
}
|
||||
else {
|
||||
conn_handle = event->connect.conn_handle;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
|
||||
conn_handle = 0;
|
||||
/* Connection terminated; resume advertising */
|
||||
blecsc_advertise();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "adv complete\n");
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
MODLOG_DFLT(INFO, "subscribe event attr_handle=%d\n",
|
||||
event->subscribe.attr_handle);
|
||||
|
||||
if (event->subscribe.attr_handle == csc_measurement_handle) {
|
||||
notify_state = event->subscribe.cur_notify;
|
||||
MODLOG_DFLT(INFO, "csc measurement notify state = %d\n",
|
||||
notify_state);
|
||||
}
|
||||
else if (event->subscribe.attr_handle == csc_control_point_handle) {
|
||||
gatt_svr_set_cp_indicate(event->subscribe.cur_indicate);
|
||||
MODLOG_DFLT(INFO, "csc control point indicate state = %d\n",
|
||||
event->subscribe.cur_indicate);
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.value);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
blecsc_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Figure out address to use while advertising (no privacy) */
|
||||
rc = ble_hs_id_infer_auto(0, &blecsc_addr_type);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Begin advertising */
|
||||
blecsc_advertise();
|
||||
}
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* The main task for the project. This function initializes the packages,
|
||||
* then starts serving events from default event queue.
|
||||
*
|
||||
* @return int NOTE: this function should never return!
|
||||
*/
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
/* Initialize the NimBLE host configuration */
|
||||
ble_hs_cfg.sync_cb = blecsc_on_sync;
|
||||
|
||||
/* Initialize measurement and notification timer */
|
||||
os_callout_init(&blecsc_measure_timer, os_eventq_dflt_get(),
|
||||
blecsc_measurement, NULL);
|
||||
rc = os_callout_reset(&blecsc_measure_timer, OS_TICKS_PER_SEC);
|
||||
assert(rc == 0);
|
||||
|
||||
rc = gatt_svr_init(&csc_measurement_state);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name */
|
||||
rc = ble_svc_gap_device_name_set(device_name);
|
||||
assert(rc == 0);
|
||||
|
||||
/* As the last thing, process events from default event queue */
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
38
src/libs/mynewt-nimble/apps/blecsc/syscfg.yml
Normal file
38
src/libs/mynewt-nimble/apps/blecsc/syscfg.yml
Normal file
|
|
@ -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.
|
||||
|
||||
|
||||
syscfg.vals:
|
||||
# Disable central and observer roles.
|
||||
BLE_ROLE_BROADCASTER: 1
|
||||
BLE_ROLE_CENTRAL: 0
|
||||
BLE_ROLE_OBSERVER: 0
|
||||
BLE_ROLE_PERIPHERAL: 1
|
||||
|
||||
# Disable unused eddystone feature.
|
||||
BLE_EDDYSTONE: 0
|
||||
|
||||
# Log reboot messages to a flash circular buffer.
|
||||
REBOOT_LOG_FCB: 1
|
||||
LOG_FCB: 1
|
||||
CONFIG_FCB: 1
|
||||
|
||||
# Set public device address.
|
||||
BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11})
|
||||
|
||||
# Set device appearance to Cycling Speed and Cadence Sensor
|
||||
BLE_SVC_GAP_APPEARANCE: BLE_SVC_GAP_APPEARANCE_CYC_SPEED_AND_CADENCE_SENSOR
|
||||
34
src/libs/mynewt-nimble/apps/blehci/pkg.yml
Normal file
34
src/libs/mynewt-nimble/apps/blehci/pkg.yml
Normal file
|
|
@ -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/blehci
|
||||
pkg.type: app
|
||||
pkg.description: BLE controller application exposing HCI over external interface
|
||||
pkg.author: "Johan Hedberg <johan.hedberg@intel.com>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@apache-mynewt-core/sys/console/stub"
|
||||
- "@apache-mynewt-core/sys/log/stub"
|
||||
- "@apache-mynewt-core/sys/stats/full"
|
||||
- "@apache-mynewt-core/kernel/os"
|
||||
- nimble/controller
|
||||
- nimble/transport
|
||||
|
||||
pkg.req_apis:
|
||||
- ble_transport
|
||||
33
src/libs/mynewt-nimble/apps/blehci/src/main.c
Normal file
33
src/libs/mynewt-nimble/apps/blehci/src/main.c
Normal file
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "os/mynewt.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
23
src/libs/mynewt-nimble/apps/blehci/syscfg.yml
Normal file
23
src/libs/mynewt-nimble/apps/blehci/syscfg.yml
Normal file
|
|
@ -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.vals:
|
||||
# Default task settings
|
||||
OS_MAIN_STACK_SIZE: 64
|
||||
# Use UART transport by default
|
||||
BLE_HCI_TRANSPORT: uart
|
||||
9
src/libs/mynewt-nimble/apps/blehr/README.md
Normal file
9
src/libs/mynewt-nimble/apps/blehr/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# BLE Heart Rate peripheral app.
|
||||
|
||||
The source files are located in the src/ directory.
|
||||
|
||||
pkg.yml contains the base definition of the app.
|
||||
|
||||
syscfg.yml contains setting definitions and overrides.
|
||||
|
||||
|
||||
40
src/libs/mynewt-nimble/apps/blehr/pkg.yml
Normal file
40
src/libs/mynewt-nimble/apps/blehr/pkg.yml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# 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/blehr
|
||||
pkg.type: app
|
||||
pkg.description: BLE peripheral heartrate sensor.
|
||||
pkg.author: "Szymon Czapracki"
|
||||
pkg.email: "szymon.czapracki@codecoup.pl"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@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/sysinit"
|
||||
- "@apache-mynewt-core/sys/id"
|
||||
- nimble/controller
|
||||
- nimble/host
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/host/store/config
|
||||
- nimble/transport/ram
|
||||
46
src/libs/mynewt-nimble/apps/blehr/src/blehr_sens.h
Normal file
46
src/libs/mynewt-nimble/apps/blehr/src/blehr_sens.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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_BLEHR_SENSOR_
|
||||
#define H_BLEHR_SENSOR_
|
||||
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Heart-rate configuration */
|
||||
#define GATT_HRS_UUID 0x180D
|
||||
#define GATT_HRS_MEASUREMENT_UUID 0x2A37
|
||||
#define GATT_HRS_BODY_SENSOR_LOC_UUID 0x2A38
|
||||
#define GATT_DEVICE_INFO_UUID 0x180A
|
||||
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
|
||||
#define GATT_MODEL_NUMBER_UUID 0x2A24
|
||||
|
||||
extern uint16_t hrs_hrm_handle;
|
||||
|
||||
int gatt_svr_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
177
src/libs/mynewt-nimble/apps/blehr/src/gatt_svr.c
Normal file
177
src/libs/mynewt-nimble/apps/blehr/src/gatt_svr.c
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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 "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "blehr_sens.h"
|
||||
|
||||
static const char *manuf_name = "Apache Mynewt";
|
||||
static const char *model_num = "Mynewt HR Sensor";
|
||||
uint16_t hrs_hrm_handle;
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_heart_rate(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_device_info(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[] = {
|
||||
{
|
||||
/* Service: Heart-rate */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_HRS_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: Heart-rate measurement */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_HRS_MEASUREMENT_UUID),
|
||||
.access_cb = gatt_svr_chr_access_heart_rate,
|
||||
.val_handle = &hrs_hrm_handle,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
}, {
|
||||
/* Characteristic: Body sensor location */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_HRS_BODY_SENSOR_LOC_UUID),
|
||||
.access_cb = gatt_svr_chr_access_heart_rate,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
|
||||
{
|
||||
/* Service: Device Information */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: * Manufacturer name */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
/* Characteristic: Model number string */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_heart_rate(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
/* Sensor location, set to "Chest" */
|
||||
static uint8_t body_sens_loc = 0x01;
|
||||
uint16_t uuid;
|
||||
int rc;
|
||||
|
||||
uuid = ble_uuid_u16(ctxt->chr->uuid);
|
||||
|
||||
if (uuid == GATT_HRS_BODY_SENSOR_LOC_UUID) {
|
||||
rc = os_mbuf_append(ctxt->om, &body_sens_loc, sizeof(body_sens_loc));
|
||||
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
uint16_t uuid;
|
||||
int rc;
|
||||
|
||||
uuid = ble_uuid_u16(ctxt->chr->uuid);
|
||||
|
||||
if (uuid == GATT_MODEL_NUMBER_UUID) {
|
||||
rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
if (uuid == GATT_MANUFACTURER_NAME_UUID) {
|
||||
rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
261
src/libs/mynewt-nimble/apps/blehr/src/main.c
Normal file
261
src/libs/mynewt-nimble/apps/blehr/src/main.c
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "os/mynewt.h"
|
||||
#include "console/console.h"
|
||||
#include "config/config.h"
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "blehr_sens.h"
|
||||
|
||||
static bool notify_state;
|
||||
|
||||
/* Connection handle */
|
||||
static uint16_t conn_handle;
|
||||
|
||||
static const char *device_name = "blehr_sensor";
|
||||
|
||||
static int blehr_gap_event(struct ble_gap_event *event, void *arg);
|
||||
|
||||
static uint8_t blehr_addr_type;
|
||||
|
||||
/* Sending notify data timer */
|
||||
static struct os_callout blehr_tx_timer;
|
||||
|
||||
/* Variable to simulate heart beats */
|
||||
static uint8_t heartrate = 90;
|
||||
|
||||
/*
|
||||
* Enables advertising with parameters:
|
||||
* o General discoverable mode
|
||||
* o Undirected connectable mode
|
||||
*/
|
||||
static void
|
||||
blehr_advertise(void)
|
||||
{
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info)
|
||||
* o Advertising tx power
|
||||
* o Device name
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assigning 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;
|
||||
|
||||
fields.name = (uint8_t *)device_name;
|
||||
fields.name_len = strlen(device_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(blehr_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, blehr_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
blehr_tx_hrate_stop(void)
|
||||
{
|
||||
os_callout_stop(&blehr_tx_timer);
|
||||
}
|
||||
|
||||
/* Reset heartrate measurment */
|
||||
static void
|
||||
blehr_tx_hrate_reset(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = os_callout_reset(&blehr_tx_timer, OS_TICKS_PER_SEC);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
/* This functions simulates heart beat and notifies it to the client */
|
||||
static void
|
||||
blehr_tx_hrate(struct os_event *ev)
|
||||
{
|
||||
static uint8_t hrm[2];
|
||||
int rc;
|
||||
struct os_mbuf *om;
|
||||
|
||||
if (!notify_state) {
|
||||
blehr_tx_hrate_stop();
|
||||
heartrate = 90;
|
||||
return;
|
||||
}
|
||||
|
||||
hrm[0] = 0x06; /* contact of a sensor */
|
||||
hrm[1] = heartrate; /* storing dummy data */
|
||||
|
||||
/* Simulation of heart beats */
|
||||
heartrate++;
|
||||
if (heartrate == 160) {
|
||||
heartrate = 90;
|
||||
}
|
||||
|
||||
om = ble_hs_mbuf_from_flat(hrm, sizeof(hrm));
|
||||
|
||||
rc = ble_gattc_notify_custom(conn_handle, hrs_hrm_handle, om);
|
||||
|
||||
assert(rc == 0);
|
||||
blehr_tx_hrate_reset();
|
||||
}
|
||||
|
||||
static int
|
||||
blehr_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
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\n",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
blehr_advertise();
|
||||
conn_handle = 0;
|
||||
}
|
||||
else {
|
||||
conn_handle = event->connect.conn_handle;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
|
||||
conn_handle = BLE_HS_CONN_HANDLE_NONE; /* reset conn_handle */
|
||||
|
||||
/* Connection terminated; resume advertising */
|
||||
blehr_advertise();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "adv complete\n");
|
||||
blehr_advertise();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d\n value handle; "
|
||||
"val_handle=%d\n",
|
||||
event->subscribe.cur_notify, hrs_hrm_handle);
|
||||
if (event->subscribe.attr_handle == hrs_hrm_handle) {
|
||||
notify_state = event->subscribe.cur_notify;
|
||||
blehr_tx_hrate_reset();
|
||||
} else if (event->subscribe.attr_handle != hrs_hrm_handle) {
|
||||
notify_state = event->subscribe.cur_notify;
|
||||
blehr_tx_hrate_stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.value);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
blehr_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Use privacy */
|
||||
rc = ble_hs_id_infer_auto(0, &blehr_addr_type);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Begin advertising */
|
||||
blehr_advertise();
|
||||
}
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* The main task for the project. This function initializes the packages,
|
||||
* then starts serving events from default event queue.
|
||||
*
|
||||
* @return int NOTE: this function should never return!
|
||||
*/
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
/* Initialize the NimBLE host configuration */
|
||||
ble_hs_cfg.sync_cb = blehr_on_sync;
|
||||
|
||||
os_callout_init(&blehr_tx_timer, os_eventq_dflt_get(),
|
||||
blehr_tx_hrate, NULL);
|
||||
|
||||
rc = gatt_svr_init();
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name */
|
||||
rc = ble_svc_gap_device_name_set(device_name);
|
||||
assert(rc == 0);
|
||||
|
||||
/* As the last thing, process events from default event queue */
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
35
src/libs/mynewt-nimble/apps/blehr/syscfg.yml
Normal file
35
src/libs/mynewt-nimble/apps/blehr/syscfg.yml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# 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.vals:
|
||||
# Disable central and observer roles.
|
||||
BLE_ROLE_BROADCASTER: 1
|
||||
BLE_ROLE_CENTRAL: 0
|
||||
BLE_ROLE_OBSERVER: 0
|
||||
BLE_ROLE_PERIPHERAL: 1
|
||||
|
||||
# Disable unused eddystone feature.
|
||||
BLE_EDDYSTONE: 0
|
||||
|
||||
# Log reboot messages to a flash circular buffer.
|
||||
REBOOT_LOG_FCB: 1
|
||||
LOG_FCB: 1
|
||||
CONFIG_FCB: 1
|
||||
|
||||
# Set public device address.
|
||||
BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11})
|
||||
37
src/libs/mynewt-nimble/apps/blemesh/pkg.yml
Normal file
37
src/libs/mynewt-nimble/apps/blemesh/pkg.yml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# 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/blemesh
|
||||
pkg.type: app
|
||||
pkg.description: Sample application for BLE Mesh node with on/off model
|
||||
pkg.author: "Łukasz Rymanowski <lukasz.rymanowski@codecoup.pl>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@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/ram
|
||||
- nimble/transport/ram
|
||||
468
src/libs/mynewt-nimble/apps/blemesh/src/main.c
Normal file
468
src/libs/mynewt-nimble/apps/blemesh/src/main.c
Normal file
|
|
@ -0,0 +1,468 @@
|
|||
/*
|
||||
* 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 "os/mynewt.h"
|
||||
#include "mesh/mesh.h"
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_system.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "shell/shell.h"
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "mesh/glue.h"
|
||||
|
||||
/* Company ID */
|
||||
#define CID_VENDOR 0x05C3
|
||||
#define STANDARD_TEST_ID 0x00
|
||||
#define TEST_ID 0x01
|
||||
static int recent_test_id = STANDARD_TEST_ID;
|
||||
|
||||
#define FAULT_ARR_SIZE 2
|
||||
|
||||
static bool has_reg_fault = true;
|
||||
|
||||
static struct bt_mesh_cfg_srv cfg_srv = {
|
||||
.relay = BT_MESH_RELAY_DISABLED,
|
||||
.beacon = BT_MESH_BEACON_ENABLED,
|
||||
#if MYNEWT_VAL(BLE_MESH_FRIEND)
|
||||
.frnd = BT_MESH_FRIEND_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_MESH_GATT_PROXY)
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
.default_ttl = 7,
|
||||
|
||||
/* 3 transmissions with 20ms interval */
|
||||
.net_transmit = BT_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = BT_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
static int
|
||||
fault_get_cur(struct bt_mesh_model *model,
|
||||
uint8_t *test_id,
|
||||
uint16_t *company_id,
|
||||
uint8_t *faults,
|
||||
uint8_t *fault_count)
|
||||
{
|
||||
uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff };
|
||||
|
||||
console_printf("fault_get_cur() has_reg_fault %u\n", has_reg_fault);
|
||||
|
||||
*test_id = recent_test_id;
|
||||
*company_id = CID_VENDOR;
|
||||
|
||||
*fault_count = min(*fault_count, sizeof(reg_faults));
|
||||
memcpy(faults, reg_faults, *fault_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fault_get_reg(struct bt_mesh_model *model,
|
||||
uint16_t company_id,
|
||||
uint8_t *test_id,
|
||||
uint8_t *faults,
|
||||
uint8_t *fault_count)
|
||||
{
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
console_printf("fault_get_reg() has_reg_fault %u\n", has_reg_fault);
|
||||
|
||||
*test_id = recent_test_id;
|
||||
|
||||
if (has_reg_fault) {
|
||||
uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff };
|
||||
|
||||
*fault_count = min(*fault_count, sizeof(reg_faults));
|
||||
memcpy(faults, reg_faults, *fault_count);
|
||||
} else {
|
||||
*fault_count = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fault_clear(struct bt_mesh_model *model, uint16_t company_id)
|
||||
{
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
has_reg_fault = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fault_test(struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id)
|
||||
{
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
if (test_id != STANDARD_TEST_ID && test_id != TEST_ID) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
recent_test_id = test_id;
|
||||
has_reg_fault = true;
|
||||
bt_mesh_fault_update(bt_mesh_model_elem(model));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bt_mesh_health_srv_cb health_srv_cb = {
|
||||
.fault_get_cur = &fault_get_cur,
|
||||
.fault_get_reg = &fault_get_reg,
|
||||
.fault_clear = &fault_clear,
|
||||
.fault_test = &fault_test,
|
||||
};
|
||||
|
||||
static struct bt_mesh_health_srv health_srv = {
|
||||
.cb = &health_srv_cb,
|
||||
};
|
||||
|
||||
static struct bt_mesh_model_pub health_pub;
|
||||
|
||||
static void
|
||||
health_pub_init(void)
|
||||
{
|
||||
health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(0);
|
||||
}
|
||||
|
||||
static struct bt_mesh_model_pub gen_level_pub;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub;
|
||||
|
||||
static uint8_t gen_on_off_state;
|
||||
static int16_t gen_level_state;
|
||||
|
||||
static void gen_onoff_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
|
||||
uint8_t *status;
|
||||
|
||||
console_printf("#mesh-onoff STATUS\n");
|
||||
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
|
||||
status = net_buf_simple_add(msg, 1);
|
||||
*status = gen_on_off_state;
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
console_printf("#mesh-onoff STATUS: send status failed\n");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static void gen_onoff_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-onoff GET\n");
|
||||
|
||||
gen_onoff_status(model, ctx);
|
||||
}
|
||||
|
||||
static void gen_onoff_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-onoff SET\n");
|
||||
|
||||
gen_on_off_state = buf->om_data[0];
|
||||
hal_gpio_write(LED_2, !gen_on_off_state);
|
||||
|
||||
gen_onoff_status(model, ctx);
|
||||
}
|
||||
|
||||
static void gen_onoff_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-onoff SET-UNACK\n");
|
||||
|
||||
gen_on_off_state = buf->om_data[0];
|
||||
hal_gpio_write(LED_2, !gen_on_off_state);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_model_op gen_onoff_op[] = {
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x01), 0, gen_onoff_get },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x02), 2, gen_onoff_set },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x03), 2, gen_onoff_set_unack },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
static void gen_level_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
|
||||
|
||||
console_printf("#mesh-level STATUS\n");
|
||||
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x08));
|
||||
net_buf_simple_add_le16(msg, gen_level_state);
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
console_printf("#mesh-level STATUS: send status failed\n");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static void gen_level_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-level GET\n");
|
||||
|
||||
gen_level_status(model, ctx);
|
||||
}
|
||||
|
||||
static void gen_level_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t level;
|
||||
|
||||
level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level SET: level=%d\n", level);
|
||||
|
||||
gen_level_status(model, ctx);
|
||||
|
||||
gen_level_state = level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_level_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t level;
|
||||
|
||||
level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level SET-UNACK: level=%d\n", level);
|
||||
|
||||
gen_level_state = level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_delta_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t delta_level;
|
||||
|
||||
delta_level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level DELTA-SET: delta_level=%d\n", delta_level);
|
||||
|
||||
gen_level_status(model, ctx);
|
||||
|
||||
gen_level_state += delta_level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_delta_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t delta_level;
|
||||
|
||||
delta_level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level DELTA-SET: delta_level=%d\n", delta_level);
|
||||
|
||||
gen_level_state += delta_level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_move_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
}
|
||||
|
||||
static void gen_move_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct bt_mesh_model_op gen_level_op[] = {
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x05), 0, gen_level_get },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x06), 3, gen_level_set },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x07), 3, gen_level_set_unack },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x09), 5, gen_delta_set },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x0a), 5, gen_delta_set_unack },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x0b), 3, gen_move_set },
|
||||
{ BT_MESH_MODEL_OP_2(0x82, 0x0c), 3, gen_move_set_unack },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
static struct bt_mesh_model root_models[] = {
|
||||
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_op,
|
||||
&gen_onoff_pub, NULL),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, gen_level_op,
|
||||
&gen_level_pub, NULL),
|
||||
};
|
||||
|
||||
static struct bt_mesh_model_pub vnd_model_pub;
|
||||
|
||||
static void vnd_model_recv(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
|
||||
|
||||
console_printf("#vendor-model-recv\n");
|
||||
|
||||
console_printf("data:%s len:%d\n", bt_hex(buf->om_data, buf->om_len),
|
||||
buf->om_len);
|
||||
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR));
|
||||
os_mbuf_append(msg, buf->om_data, buf->om_len);
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
console_printf("#vendor-model-recv: send rsp failed\n");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_model_op vnd_model_op[] = {
|
||||
{ BT_MESH_MODEL_OP_3(0x01, CID_VENDOR), 0, vnd_model_recv },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
static struct bt_mesh_model vnd_models[] = {
|
||||
BT_MESH_MODEL_VND(CID_VENDOR, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, vnd_model_op,
|
||||
&vnd_model_pub, NULL),
|
||||
};
|
||||
|
||||
static struct bt_mesh_elem elements[] = {
|
||||
BT_MESH_ELEM(0, root_models, vnd_models),
|
||||
};
|
||||
|
||||
static const struct bt_mesh_comp comp = {
|
||||
.cid = CID_VENDOR,
|
||||
.elem = elements,
|
||||
.elem_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
static int output_number(bt_mesh_output_action_t action, uint32_t number)
|
||||
{
|
||||
console_printf("OOB Number: %lu\n", number);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prov_complete(u16_t net_idx, u16_t addr)
|
||||
{
|
||||
console_printf("Local node provisioned, primary address 0x%04x\n", addr);
|
||||
}
|
||||
|
||||
static const uint8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
|
||||
|
||||
static const struct bt_mesh_prov prov = {
|
||||
.uuid = dev_uuid,
|
||||
.output_size = 4,
|
||||
.output_actions = BT_MESH_DISPLAY_NUMBER | BT_MESH_BEEP | BT_MESH_VIBRATE | BT_MESH_BLINK,
|
||||
.output_number = output_number,
|
||||
.complete = prov_complete,
|
||||
};
|
||||
|
||||
static void
|
||||
blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
blemesh_on_sync(void)
|
||||
{
|
||||
int err;
|
||||
ble_addr_t addr;
|
||||
|
||||
console_printf("Bluetooth initialized\n");
|
||||
|
||||
/* Use NRPA */
|
||||
err = ble_hs_id_gen_rnd(1, &addr);
|
||||
assert(err == 0);
|
||||
err = ble_hs_id_set_rnd(addr.val);
|
||||
assert(err == 0);
|
||||
|
||||
err = bt_mesh_init(addr.type, &prov, &comp);
|
||||
if (err) {
|
||||
console_printf("Initializing mesh failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (MYNEWT_VAL(BLE_MESH_SHELL))
|
||||
shell_register_default_module("mesh");
|
||||
#endif
|
||||
|
||||
console_printf("Mesh initialized\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
printk("Mesh network restored from flash\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
||||
#ifdef ARCH_sim
|
||||
mcu_sim_parse_args(argc, argv);
|
||||
#endif
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = blemesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = blemesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
hal_gpio_init_out(LED_2, 0);
|
||||
|
||||
health_pub_init();
|
||||
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
39
src/libs/mynewt-nimble/apps/blemesh/syscfg.yml
Normal file
39
src/libs/mynewt-nimble/apps/blemesh/syscfg.yml
Normal file
|
|
@ -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.
|
||||
#
|
||||
|
||||
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
|
||||
|
||||
# MCUmgr SMP is not supported in this app, so disable smp-over-shell.
|
||||
SHELL_MGMT: 0
|
||||
|
||||
BLE_MESH: 1
|
||||
MSYS_1_BLOCK_COUNT: 48
|
||||
|
||||
BLE_MESH_ADV_BUF_COUNT: 20
|
||||
BLE_MESH_TX_SEG_MAX: 6
|
||||
|
||||
BLE_MESH_SETTINGS: 0
|
||||
CONFIG_NFFS: 0
|
||||
37
src/libs/mynewt-nimble/apps/blemesh_light/pkg.yml
Normal file
37
src/libs/mynewt-nimble/apps/blemesh_light/pkg.yml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# 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/blemesh_light
|
||||
pkg.type: app
|
||||
pkg.description: Sample application for BLE Mesh node with Light model
|
||||
pkg.author: "Michał Narajowski <michal.narajowski@codecoup.pl>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@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/ram
|
||||
- nimble/transport/ram
|
||||
242
src/libs/mynewt-nimble/apps/blemesh_light/src/light_model.c
Normal file
242
src/libs/mynewt-nimble/apps/blemesh_light/src/light_model.c
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* 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 "syscfg/syscfg.h"
|
||||
|
||||
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
|
||||
|
||||
#include "mesh/mesh.h"
|
||||
#include "bsp.h"
|
||||
#include "pwm/pwm.h"
|
||||
#include "light_model.h"
|
||||
#include "ws2812.h"
|
||||
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
struct pwm_dev *pwm0;
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
struct pwm_dev *pwm1;
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
struct pwm_dev *pwm2;
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
struct pwm_dev *pwm3;
|
||||
#endif
|
||||
|
||||
static uint16_t top_val;
|
||||
#endif
|
||||
|
||||
#if (MYNEWT_VAL(USE_NEOPIXEL))
|
||||
static uint32_t neopixel[WS2812_NUM_LED];
|
||||
#endif
|
||||
|
||||
static u8_t gen_onoff_state;
|
||||
static s16_t gen_level_state;
|
||||
|
||||
static void light_set_lightness(u8_t percentage)
|
||||
{
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
int rc;
|
||||
|
||||
uint16_t pwm_val = (uint16_t) (percentage * top_val / 100);
|
||||
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
rc = pwm_set_duty_cycle(pwm0, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
rc = pwm_set_duty_cycle(pwm1, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
rc = pwm_set_duty_cycle(pwm2, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
rc = pwm_set_duty_cycle(pwm3, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#else
|
||||
int i;
|
||||
u32_t lightness;
|
||||
u8_t max_lightness = 0x1f;
|
||||
|
||||
lightness = (u8_t) (percentage * max_lightness / 100);
|
||||
|
||||
for (i = 0; i < WS2812_NUM_LED; i++) {
|
||||
neopixel[i] = (lightness | lightness << 8 | lightness << 16);
|
||||
}
|
||||
ws2812_write(neopixel);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void update_light_state(void)
|
||||
{
|
||||
u16_t level = (u16_t)gen_level_state;
|
||||
int percent = 100 * level / 0xffff;
|
||||
|
||||
if (gen_onoff_state == 0) {
|
||||
percent = 0;
|
||||
}
|
||||
light_set_lightness((uint8_t) percent);
|
||||
}
|
||||
|
||||
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state)
|
||||
{
|
||||
*state = gen_onoff_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state)
|
||||
{
|
||||
gen_onoff_state = state;
|
||||
update_light_state();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level)
|
||||
{
|
||||
*level = gen_level_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level)
|
||||
{
|
||||
gen_level_state = level;
|
||||
if ((u16_t)gen_level_state > 0x0000) {
|
||||
gen_onoff_state = 1;
|
||||
}
|
||||
if ((u16_t)gen_level_state == 0x0000) {
|
||||
gen_onoff_state = 0;
|
||||
}
|
||||
update_light_state();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness)
|
||||
{
|
||||
return light_model_gen_level_get(model, lightness);
|
||||
}
|
||||
|
||||
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness)
|
||||
{
|
||||
return light_model_gen_level_set(model, lightness);
|
||||
}
|
||||
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
struct pwm_dev_cfg dev_conf = {
|
||||
.n_cycles = 0,
|
||||
.int_prio = 3,
|
||||
};
|
||||
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
static struct pwm_chan_cfg led1_conf = {
|
||||
.pin = LED_1,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
static struct pwm_chan_cfg led2_conf = {
|
||||
.pin = LED_2,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
static struct pwm_chan_cfg led3_conf = {
|
||||
.pin = LED_3,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
static struct pwm_chan_cfg led4_conf = {
|
||||
.pin = LED_4,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
void init_pwm_dev(struct pwm_dev **pwm, char *dev_name, struct pwm_chan_cfg *chan_cfg)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
*pwm = (struct pwm_dev *) os_dev_open(dev_name, 0, NULL);
|
||||
assert(pwm);
|
||||
rc = pwm_configure_device(*pwm, &dev_conf);
|
||||
assert(rc == 0);
|
||||
rc = pwm_configure_channel(*pwm, 0, chan_cfg);
|
||||
assert(rc == 0);
|
||||
rc = pwm_enable(*pwm);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
int pwm_init(void)
|
||||
{
|
||||
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
init_pwm_dev(&pwm0, "pwm0", &led1_conf);
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
init_pwm_dev(&pwm1, "pwm1", &led2_conf);
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
init_pwm_dev(&pwm2, "pwm2", &led3_conf);
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
init_pwm_dev(&pwm3, "pwm3", &led4_conf);
|
||||
#endif
|
||||
|
||||
if (!pwm0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
top_val = (uint16_t) pwm_get_top_value(pwm0);
|
||||
update_light_state();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int light_model_init(void)
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
|
||||
int rc;
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
rc = pwm_init();
|
||||
assert(rc == 0);
|
||||
#else
|
||||
rc = ws2812_init();
|
||||
assert(rc == 0);
|
||||
update_light_state();
|
||||
#endif
|
||||
return rc;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
37
src/libs/mynewt-nimble/apps/blemesh_light/src/light_model.h
Normal file
37
src/libs/mynewt-nimble/apps/blemesh_light/src/light_model.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BT_MESH_LIGHT_MODEL_H
|
||||
#define __BT_MESH_LIGHT_MODEL_H
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state);
|
||||
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state);
|
||||
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level);
|
||||
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level);
|
||||
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness);
|
||||
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness);
|
||||
int light_model_init(void);
|
||||
|
||||
#endif
|
||||
113
src/libs/mynewt-nimble/apps/blemesh_light/src/main.c
Normal file
113
src/libs/mynewt-nimble/apps/blemesh_light/src/main.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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 "sysinit/sysinit.h"
|
||||
#include "os/os.h"
|
||||
#include "mesh/mesh.h"
|
||||
#include "console/console.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "shell/shell.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "mesh/glue.h"
|
||||
#include "mesh/testing.h"
|
||||
#include "mesh/model_srv.h"
|
||||
#include "light_model.h"
|
||||
|
||||
|
||||
static void model_bound_cb(u16_t addr, struct bt_mesh_model *model,
|
||||
u16_t key_idx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
console_printf("Model bound: remote addr 0x%04x key_idx 0x%04x model %p\n",
|
||||
addr, key_idx, model);
|
||||
|
||||
if (model->id != BT_MESH_MODEL_ID_GEN_LEVEL_SRV) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Hack for demo purposes */
|
||||
rc = bt_test_bind_app_key_to_model(model, key_idx,
|
||||
BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV);
|
||||
|
||||
if (rc) {
|
||||
console_printf("Failed to bind light lightness srv model to app_key");
|
||||
} else {
|
||||
console_printf("Successfuly bound light lightness srv model to app_key");
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_test_cb bt_test_cb = {
|
||||
.mesh_model_bound = model_bound_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
blemesh_on_sync(void)
|
||||
{
|
||||
console_printf("Bluetooth initialized\n");
|
||||
|
||||
shell_register_default_module("mesh");
|
||||
|
||||
bt_test_cb_register(&bt_test_cb);
|
||||
|
||||
light_model_init();
|
||||
bt_mesh_set_gen_onoff_srv_cb(light_model_gen_onoff_get,
|
||||
light_model_gen_onoff_set);
|
||||
bt_mesh_set_gen_level_srv_cb(light_model_gen_level_get,
|
||||
light_model_gen_level_set);
|
||||
bt_mesh_set_light_lightness_srv_cb(light_model_light_lightness_get,
|
||||
light_model_light_lightness_set);
|
||||
|
||||
console_printf("Mesh initialized\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
printk("Mesh network restored from flash\n");
|
||||
}
|
||||
|
||||
/* Hack for demo purposes */
|
||||
bt_test_shell_init();
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = blemesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = blemesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
138
src/libs/mynewt-nimble/apps/blemesh_light/src/ws2812.c
Normal file
138
src/libs/mynewt-nimble/apps/blemesh_light/src/ws2812.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* 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 "syscfg/syscfg.h"
|
||||
|
||||
#if (MYNEWT_VAL(USE_NEOPIXEL))
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "os/os.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "pwm/pwm.h"
|
||||
#include "nrfx.h"
|
||||
#include "nrfx_pwm.h"
|
||||
#include "ws2812.h"
|
||||
|
||||
#define BITS_PER_SEQ (24)
|
||||
#define BIT0 (0x8000 | 6)
|
||||
#define BIT1 (0x8000 | 11)
|
||||
|
||||
static const nrfx_pwm_t pwm = NRFX_PWM_INSTANCE(WS2812_PWM);
|
||||
|
||||
static const nrfx_pwm_config_t pwm_config = {
|
||||
.output_pins = { WS2812_GPIO, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED },
|
||||
.irq_priority = 3,
|
||||
.base_clock = NRF_PWM_CLK_16MHz,
|
||||
.count_mode = NRF_PWM_MODE_UP,
|
||||
.top_value = 20,
|
||||
.load_mode = NRF_PWM_LOAD_COMMON,
|
||||
.step_mode = NRF_PWM_STEP_AUTO,
|
||||
};
|
||||
|
||||
static uint16_t pwm_seq_values[2][BITS_PER_SEQ];
|
||||
|
||||
static const nrf_pwm_sequence_t pwm_seq[2] = {
|
||||
{
|
||||
.values.p_raw = pwm_seq_values[0],
|
||||
.length = BITS_PER_SEQ,
|
||||
.repeats = 0,
|
||||
.end_delay = 0,
|
||||
}, {
|
||||
.values.p_raw = pwm_seq_values[1],
|
||||
.length = BITS_PER_SEQ,
|
||||
.repeats = 0,
|
||||
.end_delay = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static uint32_t led_color[WS2812_NUM_LED];
|
||||
static int led_idx;
|
||||
|
||||
static void
|
||||
load_pixel(void)
|
||||
{
|
||||
uint16_t *seq_values;
|
||||
uint32_t grb;
|
||||
int i;
|
||||
|
||||
seq_values = pwm_seq_values[led_idx & 1];
|
||||
grb = led_color[led_idx];
|
||||
|
||||
for (i = 0; i < BITS_PER_SEQ; i++) {
|
||||
*seq_values = grb & 0x800000 ? BIT1 : BIT0;
|
||||
grb <<= 1;
|
||||
seq_values++;
|
||||
}
|
||||
|
||||
led_idx++;
|
||||
}
|
||||
|
||||
static void
|
||||
pwm_handler_func(nrfx_pwm_evt_type_t event_type)
|
||||
{
|
||||
switch (event_type) {
|
||||
case NRFX_PWM_EVT_END_SEQ0:
|
||||
case NRFX_PWM_EVT_END_SEQ1:
|
||||
load_pixel();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ws2812_init(void)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
|
||||
err = nrfx_pwm_init(&pwm, &pwm_config, pwm_handler_func);
|
||||
|
||||
return err != NRFX_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
ws2812_write(const uint32_t *rgb)
|
||||
{
|
||||
uint32_t grb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WS2812_NUM_LED; i++) {
|
||||
grb = 0;
|
||||
grb |= (rgb[i] & 0x00FF00) << 8;
|
||||
grb |= (rgb[i] & 0xFF0000) >> 8;
|
||||
grb |= (rgb[i] & 0x0000FF);
|
||||
|
||||
led_color[i] = grb;
|
||||
}
|
||||
|
||||
led_idx = 0;
|
||||
|
||||
load_pixel();
|
||||
load_pixel();
|
||||
nrfx_pwm_complex_playback(&pwm, &pwm_seq[0], &pwm_seq[1], WS2812_NUM_LED,
|
||||
NRFX_PWM_FLAG_SIGNAL_END_SEQ0 |
|
||||
NRFX_PWM_FLAG_SIGNAL_END_SEQ1 |
|
||||
NRFX_PWM_FLAG_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
42
src/libs/mynewt-nimble/apps/blemesh_light/src/ws2812.h
Normal file
42
src/libs/mynewt-nimble/apps/blemesh_light/src/ws2812.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* 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 __WS2812_H__
|
||||
#define __WS2812_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define WS2812_PWM 0
|
||||
#define WS2812_GPIO 30
|
||||
#define WS2812_NUM_LED 32
|
||||
|
||||
int ws2812_init(void);
|
||||
|
||||
int ws2812_write(const uint32_t *rgb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __WS2812_H__ */
|
||||
63
src/libs/mynewt-nimble/apps/blemesh_light/syscfg.yml
Normal file
63
src/libs/mynewt-nimble/apps/blemesh_light/syscfg.yml
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# 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:
|
||||
USE_NEOPIXEL:
|
||||
value: 0
|
||||
|
||||
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
|
||||
|
||||
# SMP is not supported in this app, so disable smp-over-shell.
|
||||
SHELL_MGMT: 0
|
||||
|
||||
MSYS_1_BLOCK_COUNT: 80
|
||||
|
||||
BLE_MESH_ADV_BUF_COUNT: 20
|
||||
BLE_MESH_TX_SEG_MAX: 6
|
||||
|
||||
BLE_MESH: 1
|
||||
BLE_MESH_SHELL: 1
|
||||
BLE_MESH_PROV: 1
|
||||
BLE_MESH_PB_ADV: 1
|
||||
BLE_MESH_PB_GATT: 1
|
||||
BLE_MESH_GATT_PROXY: 1
|
||||
BLE_MESH_TESTING: 1
|
||||
BLE_MESH_FRIEND: 0
|
||||
BLE_MESH_CFG_CLI: 1
|
||||
BLE_MESH_HEALTH_CLI: 0
|
||||
BLE_MESH_SHELL_MODELS: 1
|
||||
BLE_MESH_OOB_OUTPUT_ACTIONS: 0
|
||||
BLE_MESH_SETTINGS: 0
|
||||
CONFIG_NFFS: 0
|
||||
|
||||
USE_NEOPIXEL: 0
|
||||
|
||||
syscfg.vals.BLE_MESH_SHELL_MODELS:
|
||||
PWM_0: 1
|
||||
PWM_1: 1
|
||||
PWM_2: 1
|
||||
PWM_3: 1
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
### Bluetooth: Mesh OnOff Model
|
||||
|
||||
|
||||
#### Overview
|
||||
|
||||
This is a simple application demonstrating a Bluetooth mesh multi-element node.
|
||||
Each element has a mesh onoff client and server
|
||||
model which controls one of the 4 sets of buttons and LEDs .
|
||||
|
||||
Prior to provisioning, an unprovisioned beacon is broadcast that contains
|
||||
a UUID. Each button controls the state of its
|
||||
corresponding LED and does not initiate any mesh activity.
|
||||
|
||||
The models for button 1 and LED 1 are in the node's root element.
|
||||
The 3 remaining button/LED pairs are in elements 1 through 3.
|
||||
Assuming the provisioner assigns 0x100 to the root element,
|
||||
the secondary elements will appear at 0x101, 0x102 and 0x103.
|
||||
|
||||
After provisioning, the button clients must
|
||||
be configured to publish and the LED servers to subscribe.
|
||||
|
||||
If a LED server is provided with a publish address, it will
|
||||
also publish its status on an onoff state change.
|
||||
|
||||
If a button is pressed only once within a 1 second interval, it sends an
|
||||
"on" message. If it is pressed more than once, it
|
||||
sends an "off" message. The buttons are quite noisy and are debounced in
|
||||
the button_pressed() interrupt handler. An interrupt within 250ms of the
|
||||
previous is discarded. This might seem a little clumsy, but the alternative of
|
||||
using one button for "on" and another for "off" would reduce the number
|
||||
of onoff clients from 4 to 2.
|
||||
|
||||
#### Requirements
|
||||
************
|
||||
|
||||
This sample has been tested on the Nordic nRF52840-PDK board, but would
|
||||
likely also run on the nrf52_pca10040 board.
|
||||
|
||||
#### Building and Running
|
||||
********************
|
||||
|
||||
Prior to provisioning, each button controls its corresponding LED as one
|
||||
would expect with an actual switch.
|
||||
|
||||
Provisioning is done using the BlueZ meshctl utility. Below is an example that
|
||||
binds button 2 and LED 1 to application key 1. It then configures button 2
|
||||
to publish to group 0xc000 and LED 1 to subscribe to that group.
|
||||
|
||||
```
|
||||
discover-unprovisioned on
|
||||
provision <discovered UUID>
|
||||
menu config
|
||||
target 0100
|
||||
appkey-add 1
|
||||
bind 0 1 1000 # bind appkey 1 to LED server on element 0 (unicast 0100)
|
||||
sub-add 0100 c000 1000 # add subscription to group address c000 to the LED server
|
||||
bind 1 1 1001 # bind appkey 1 to button 2 on element 1 (unicast 0101)
|
||||
pub-set 0101 c000 1 0 0 1001 # publish button 2 to group address c000
|
||||
```
|
||||
|
||||
The meshctl utility maintains a persistent JSON database containing
|
||||
the mesh configuration. As additional nodes (boards) are provisioned, it
|
||||
assigns sequential unicast addresses based on the number of elements
|
||||
supported by the node. This example supports 4 elements per node.
|
||||
|
||||
The first or root element of the node contains models for configuration,
|
||||
health, and onoff. The secondary elements only
|
||||
have models for onoff. The meshctl target for configuration must be the
|
||||
root element's unicast address as it is the only one that has a
|
||||
configuration server model.
|
||||
|
||||
If meshctl is gracefully exited, it can be restarted and reconnected to
|
||||
network 0x0.
|
||||
|
||||
The meshctl utility also supports a onoff model client that can be used to
|
||||
change the state of any LED that is bound to application key 0x1.
|
||||
This is done by setting the target to the unicast address of the element
|
||||
that has that LED's model and issuing the onoff command.
|
||||
Group addresses are not supported.
|
||||
34
src/libs/mynewt-nimble/apps/blemesh_models_example_1/pkg.yml
Normal file
34
src/libs/mynewt-nimble/apps/blemesh_models_example_1/pkg.yml
Normal file
|
|
@ -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/blemesh_models_example_1
|
||||
pkg.type: app
|
||||
pkg.description: Sample application for BLE Mesh node with on/off model on nRF52840pdk
|
||||
pkg.author: "Michał Narajowski <michal.narajowski@codecoup.pl>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
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"
|
||||
- nimble/controller
|
||||
- nimble/host
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/transport/ram
|
||||
709
src/libs/mynewt-nimble/apps/blemesh_models_example_1/src/main.c
Normal file
709
src/libs/mynewt-nimble/apps/blemesh_models_example_1/src/main.c
Normal file
|
|
@ -0,0 +1,709 @@
|
|||
/* main.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* This application is specific to the Nordic nRF52840-PDK board.
|
||||
*
|
||||
* It supports the 4 buttons and 4 LEDs as mesh clients and servers.
|
||||
*
|
||||
* Prior to provisioning, a button inverts the state of the
|
||||
* corresponding LED.
|
||||
*
|
||||
* Button and LED 1 are in the root node.
|
||||
* The 3 remaining button/LED pairs are in element 1 through 3.
|
||||
* Assuming the provisioner assigns 0x100 to the root node,
|
||||
* the secondary elements will appear at 0x101, 0x102 and 0x103.
|
||||
*
|
||||
* It's anticipated that after provisioning, the button clients would
|
||||
* be configured to publish and the LED servers to subscribe.
|
||||
*
|
||||
* If a LED server is provided with a publish address, it will
|
||||
* also publish its status on a state change.
|
||||
*
|
||||
* Messages from a button to its corresponding LED are ignored as
|
||||
* the LED's state has already been changed locally by the button client.
|
||||
*
|
||||
* The buttons are debounced at a nominal 250ms. That value can be
|
||||
* changed as needed.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "os/mynewt.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "mesh/glue.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
#define CID_RUNTIME 0x05C3
|
||||
|
||||
/* Model Operation Codes */
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03)
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04)
|
||||
|
||||
static void gen_onoff_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
static void gen_onoff_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
static void gen_onoff_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
static void gen_onoff_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
/*
|
||||
* Server Configuration Declaration
|
||||
*/
|
||||
|
||||
static struct bt_mesh_cfg_srv cfg_srv = {
|
||||
.relay = BT_MESH_RELAY_DISABLED,
|
||||
.beacon = BT_MESH_BEACON_ENABLED,
|
||||
#if defined(CONFIG_BT_MESH_FRIEND)
|
||||
.frnd = BT_MESH_FRIEND_ENABLED,
|
||||
#else
|
||||
.frnd = BT_MESH_FRIEND_NOT_SUPPORTED,
|
||||
#endif
|
||||
#if defined(CONFIG_BT_MESH_GATT_PROXY)
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
.default_ttl = 7,
|
||||
|
||||
/* 3 transmissions with 20ms interval */
|
||||
.net_transmit = BT_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = BT_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
/*
|
||||
* Client Configuration Declaration
|
||||
*/
|
||||
|
||||
static struct bt_mesh_cfg_cli cfg_cli = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Health Server Declaration
|
||||
*/
|
||||
|
||||
static struct bt_mesh_health_srv health_srv = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Publication Declarations
|
||||
*
|
||||
* The publication messages are initialized to the
|
||||
* the size of the opcode + content
|
||||
*
|
||||
* For publication, the message must be in static or global as
|
||||
* it is re-transmitted several times. This occurs
|
||||
* after the function that called bt_mesh_model_publish() has
|
||||
* exited and the stack is no longer valid.
|
||||
*
|
||||
* Note that the additional 4 bytes for the AppMIC is not needed
|
||||
* because it is added to a stack variable at the time a
|
||||
* transmission occurs.
|
||||
*
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model_pub health_pub;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_0;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_0;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_1;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_1;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_2;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_2;
|
||||
|
||||
static struct os_mbuf *bt_mesh_pub_msg_health_pub;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
|
||||
|
||||
void init_pub(void)
|
||||
{
|
||||
bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(1 + 3 + 0);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv_s_0 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli_s_0 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv_s_1 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli_s_1 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv_s_2 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli_s_2 = NET_BUF_SIMPLE(2 + 2);
|
||||
|
||||
health_pub.msg = bt_mesh_pub_msg_health_pub;
|
||||
gen_onoff_pub_srv.msg = bt_mesh_pub_msg_gen_onoff_pub_srv;
|
||||
gen_onoff_pub_cli.msg = bt_mesh_pub_msg_gen_onoff_pub_cli;
|
||||
gen_onoff_pub_srv_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
|
||||
gen_onoff_pub_cli_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
|
||||
gen_onoff_pub_srv_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
|
||||
gen_onoff_pub_cli_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
|
||||
gen_onoff_pub_srv_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
|
||||
gen_onoff_pub_cli_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Models in an element must have unique op codes.
|
||||
*
|
||||
* The mesh stack dispatches a message to the first model in an element
|
||||
* that is also bound to an app key and supports the op code in the
|
||||
* received message.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* OnOff Model Server Op Dispatch Table
|
||||
*
|
||||
*/
|
||||
|
||||
static const struct bt_mesh_model_op gen_onoff_srv_op[] = {
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_GET, 0, gen_onoff_get },
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET, 2, gen_onoff_set },
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
/*
|
||||
* OnOff Model Client Op Dispatch Table
|
||||
*/
|
||||
|
||||
static const struct bt_mesh_model_op gen_onoff_cli_op[] = {
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, gen_onoff_status },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
struct onoff_state {
|
||||
u8_t current;
|
||||
u8_t previous;
|
||||
u8_t led_gpio_pin;
|
||||
};
|
||||
|
||||
/*
|
||||
* Declare and Initialize Element Contexts
|
||||
* Change to select different GPIO output pins
|
||||
*/
|
||||
|
||||
static struct onoff_state onoff_state_arr[] = {
|
||||
{ .led_gpio_pin = LED_1 },
|
||||
{ .led_gpio_pin = LED_2 },
|
||||
{ .led_gpio_pin = LED_3 },
|
||||
{ .led_gpio_pin = LED_4 },
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Element Model Declarations
|
||||
*
|
||||
* Element 0 Root Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model root_models[] = {
|
||||
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
|
||||
&gen_onoff_pub_srv, &onoff_state_arr[0]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli, &onoff_state_arr[0]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Element 1 Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model secondary_0_models[] = {
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
|
||||
&gen_onoff_pub_srv_s_0, &onoff_state_arr[1]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli_s_0, &onoff_state_arr[1]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Element 2 Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model secondary_1_models[] = {
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
|
||||
&gen_onoff_pub_srv_s_1, &onoff_state_arr[2]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli_s_1, &onoff_state_arr[2]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Element 3 Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model secondary_2_models[] = {
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
|
||||
&gen_onoff_pub_srv_s_2, &onoff_state_arr[3]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli_s_2, &onoff_state_arr[3]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Button to Client Model Assignments
|
||||
*/
|
||||
|
||||
struct bt_mesh_model *mod_cli_sw[] = {
|
||||
&root_models[4],
|
||||
&secondary_0_models[1],
|
||||
&secondary_1_models[1],
|
||||
&secondary_2_models[1],
|
||||
};
|
||||
|
||||
/*
|
||||
* LED to Server Model Assigmnents
|
||||
*/
|
||||
|
||||
struct bt_mesh_model *mod_srv_sw[] = {
|
||||
&root_models[3],
|
||||
&secondary_0_models[0],
|
||||
&secondary_1_models[0],
|
||||
&secondary_2_models[0],
|
||||
};
|
||||
|
||||
/*
|
||||
* Root and Secondary Element Declarations
|
||||
*/
|
||||
|
||||
static struct bt_mesh_elem elements[] = {
|
||||
BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
|
||||
BT_MESH_ELEM(0, secondary_0_models, BT_MESH_MODEL_NONE),
|
||||
BT_MESH_ELEM(0, secondary_1_models, BT_MESH_MODEL_NONE),
|
||||
BT_MESH_ELEM(0, secondary_2_models, BT_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
static const struct bt_mesh_comp comp = {
|
||||
.cid = CID_RUNTIME,
|
||||
.elem = elements,
|
||||
.elem_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
struct sw {
|
||||
u8_t sw_num;
|
||||
u8_t onoff_state;
|
||||
struct os_callout button_work;
|
||||
struct os_callout button_timer;
|
||||
};
|
||||
|
||||
|
||||
static u8_t button_press_cnt;
|
||||
static struct sw sw;
|
||||
|
||||
static u8_t trans_id;
|
||||
static u32_t time, last_time;
|
||||
static u16_t primary_addr;
|
||||
static u16_t primary_net_idx;
|
||||
|
||||
/*
|
||||
* Generic OnOff Model Server Message Handlers
|
||||
*
|
||||
* Mesh Model Specification 3.1.1
|
||||
*
|
||||
*/
|
||||
|
||||
static void gen_onoff_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
|
||||
struct onoff_state *state = model->user_data;
|
||||
|
||||
BT_INFO("addr 0x%04x onoff 0x%02x",
|
||||
bt_mesh_model_elem(model)->addr, state->current);
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
|
||||
net_buf_simple_add_u8(msg, state->current);
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
BT_ERR("Unable to send On Off Status response");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static void gen_onoff_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
struct os_mbuf *msg = model->pub->msg;
|
||||
struct onoff_state *state = model->user_data;
|
||||
int err;
|
||||
|
||||
state->current = net_buf_simple_pull_u8(buf);
|
||||
BT_INFO("addr 0x%02x state 0x%02x",
|
||||
bt_mesh_model_elem(model)->addr, state->current);
|
||||
|
||||
/* Pin set low turns on LED's on the nrf52840-pca10056 board */
|
||||
hal_gpio_write(state->led_gpio_pin,
|
||||
state->current ? 0 : 1);
|
||||
|
||||
/*
|
||||
* If a server has a publish address, it is required to
|
||||
* publish status on a state change
|
||||
*
|
||||
* See Mesh Profile Specification 3.7.6.1.2
|
||||
*
|
||||
* Only publish if there is an assigned address
|
||||
*/
|
||||
|
||||
if (state->previous != state->current &&
|
||||
model->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
|
||||
BT_INFO("publish last 0x%02x cur 0x%02x",
|
||||
state->previous,
|
||||
state->current);
|
||||
state->previous = state->current;
|
||||
bt_mesh_model_msg_init(msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
|
||||
net_buf_simple_add_u8(msg, state->current);
|
||||
err = bt_mesh_model_publish(model);
|
||||
if (err) {
|
||||
BT_ERR("bt_mesh_model_publish err %d", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_onoff_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
BT_INFO("");
|
||||
|
||||
gen_onoff_set_unack(model, ctx, buf);
|
||||
gen_onoff_get(model, ctx, buf);
|
||||
}
|
||||
|
||||
static void gen_onoff_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
u8_t state;
|
||||
|
||||
state = net_buf_simple_pull_u8(buf);
|
||||
|
||||
BT_INFO("Node 0x%04x OnOff status from 0x%04x with state 0x%02x",
|
||||
bt_mesh_model_elem(model)->addr, ctx->addr, state);
|
||||
}
|
||||
|
||||
static int output_number(bt_mesh_output_action_t action, u32_t number)
|
||||
{
|
||||
BT_INFO("OOB Number %u", number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_string(const char *str)
|
||||
{
|
||||
BT_INFO("OOB String %s", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prov_complete(u16_t net_idx, u16_t addr)
|
||||
{
|
||||
BT_INFO("provisioning complete for net_idx 0x%04x addr 0x%04x",
|
||||
net_idx, addr);
|
||||
primary_addr = addr;
|
||||
primary_net_idx = net_idx;
|
||||
}
|
||||
|
||||
static void prov_reset(void)
|
||||
{
|
||||
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
|
||||
}
|
||||
|
||||
static u8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
|
||||
|
||||
#define BUTTON_DEBOUNCE_DELAY_MS 250
|
||||
|
||||
/*
|
||||
* Map GPIO pins to button number
|
||||
* Change to select different GPIO input pins
|
||||
*/
|
||||
|
||||
static uint8_t pin_to_sw(int pin_pos)
|
||||
{
|
||||
switch (pin_pos) {
|
||||
case BUTTON_1: return 0;
|
||||
case BUTTON_2: return 1;
|
||||
case BUTTON_3: return 2;
|
||||
case BUTTON_4: return 3;
|
||||
default:break;
|
||||
}
|
||||
|
||||
BT_ERR("No match for GPIO pin 0x%08x", pin_pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void button_pressed(struct os_event *ev)
|
||||
{
|
||||
int pin_pos = (int ) ev->ev_arg;
|
||||
/*
|
||||
* One button press within a 1 second interval sends an on message
|
||||
* More than one button press sends an off message
|
||||
*/
|
||||
|
||||
time = k_uptime_get_32();
|
||||
|
||||
/* debounce the switch */
|
||||
if (time < last_time + BUTTON_DEBOUNCE_DELAY_MS) {
|
||||
last_time = time;
|
||||
return;
|
||||
}
|
||||
|
||||
if (button_press_cnt == 0) {
|
||||
os_callout_reset(&sw.button_timer, os_time_ms_to_ticks32(K_SECONDS(1)));
|
||||
}
|
||||
|
||||
BT_INFO("button_press_cnt 0x%02x", button_press_cnt);
|
||||
button_press_cnt++;
|
||||
|
||||
/* The variable pin_pos is the pin position in the GPIO register,
|
||||
* not the pin number. It's assumed that only one bit is set.
|
||||
*/
|
||||
|
||||
sw.sw_num = pin_to_sw(pin_pos);
|
||||
last_time = time;
|
||||
}
|
||||
|
||||
/*
|
||||
* Button Count Timer Worker
|
||||
*/
|
||||
|
||||
static void button_cnt_timer(struct os_event *work)
|
||||
{
|
||||
struct sw *button_sw = work->ev_arg;
|
||||
|
||||
button_sw->onoff_state = button_press_cnt == 1 ? 1 : 0;
|
||||
BT_INFO("button_press_cnt 0x%02x onoff_state 0x%02x",
|
||||
button_press_cnt, button_sw->onoff_state);
|
||||
button_press_cnt = 0;
|
||||
os_callout_reset(&sw.button_work, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Button Pressed Worker Task
|
||||
*/
|
||||
|
||||
static void button_pressed_worker(struct os_event *work)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(1);
|
||||
struct bt_mesh_model *mod_cli, *mod_srv;
|
||||
struct bt_mesh_model_pub *pub_cli, *pub_srv;
|
||||
struct sw *sw = work->ev_arg;
|
||||
u8_t sw_idx = sw->sw_num;
|
||||
int err;
|
||||
|
||||
mod_cli = mod_cli_sw[sw_idx];
|
||||
pub_cli = mod_cli->pub;
|
||||
|
||||
mod_srv = mod_srv_sw[sw_idx];
|
||||
pub_srv = mod_srv->pub;
|
||||
(void)pub_srv;
|
||||
|
||||
/* If unprovisioned, just call the set function.
|
||||
* The intent is to have switch-like behavior
|
||||
* prior to provisioning. Once provisioned,
|
||||
* the button and its corresponding led are no longer
|
||||
* associated and act independently. So, if a button is to
|
||||
* control its associated led after provisioning, the button
|
||||
* must be configured to either publish to the led's unicast
|
||||
* address or a group to which the led is subscribed.
|
||||
*/
|
||||
|
||||
if (primary_addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.addr = sw_idx + primary_addr,
|
||||
};
|
||||
|
||||
/* This is a dummy message sufficient
|
||||
* for the led server
|
||||
*/
|
||||
|
||||
net_buf_simple_add_u8(msg, sw->onoff_state);
|
||||
gen_onoff_set_unack(mod_srv, &ctx, msg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pub_cli->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
BT_INFO("publish to 0x%04x onoff 0x%04x sw_idx 0x%04x",
|
||||
pub_cli->addr, sw->onoff_state, sw_idx);
|
||||
bt_mesh_model_msg_init(pub_cli->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET);
|
||||
net_buf_simple_add_u8(pub_cli->msg, sw->onoff_state);
|
||||
net_buf_simple_add_u8(pub_cli->msg, trans_id++);
|
||||
err = bt_mesh_model_publish(mod_cli);
|
||||
if (err) {
|
||||
BT_ERR("bt_mesh_model_publish err %d", err);
|
||||
}
|
||||
|
||||
done:
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
/* Disable OOB security for SILabs Android app */
|
||||
|
||||
static const struct bt_mesh_prov prov = {
|
||||
.uuid = dev_uuid,
|
||||
#if 1
|
||||
.output_size = 6,
|
||||
.output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING),
|
||||
.output_number = output_number,
|
||||
.output_string = output_string,
|
||||
#else
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
.output_number = 0,
|
||||
#endif
|
||||
.complete = prov_complete,
|
||||
.reset = prov_reset,
|
||||
};
|
||||
|
||||
void init_led(u8_t dev)
|
||||
{
|
||||
hal_gpio_init_out(onoff_state_arr[dev].led_gpio_pin, 1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void init_button(int button)
|
||||
{
|
||||
button_event.ev_cb = button_pressed;
|
||||
|
||||
hal_gpio_irq_init(button, gpio_irq_handler, (void *)button,
|
||||
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(button);
|
||||
}
|
||||
|
||||
static void
|
||||
blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
blemesh_on_sync(void)
|
||||
{
|
||||
int err;
|
||||
ble_addr_t addr;
|
||||
|
||||
console_printf("Bluetooth initialized\n");
|
||||
|
||||
/* Use NRPA */
|
||||
err = ble_hs_id_gen_rnd(1, &addr);
|
||||
assert(err == 0);
|
||||
err = ble_hs_id_set_rnd(addr.val);
|
||||
assert(err == 0);
|
||||
|
||||
err = bt_mesh_init(addr.type, &prov, &comp);
|
||||
if (err) {
|
||||
console_printf("Initializing mesh failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
console_printf("Mesh network restored from flash\n");
|
||||
}
|
||||
|
||||
bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
|
||||
|
||||
console_printf("Mesh initialized\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#ifdef ARCH_sim
|
||||
mcu_sim_parse_args(argc, argv);
|
||||
#endif
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
BT_INFO("Initializing...");
|
||||
|
||||
/* Initialize the button debouncer */
|
||||
last_time = k_uptime_get_32();
|
||||
|
||||
/* Initialize button worker task*/
|
||||
os_callout_init(&sw.button_work, os_eventq_dflt_get(),
|
||||
button_pressed_worker, &sw);
|
||||
|
||||
/* Initialize button count timer */
|
||||
os_callout_init(&sw.button_timer, os_eventq_dflt_get(),
|
||||
button_cnt_timer, &sw);
|
||||
|
||||
/* Initialize LED's */
|
||||
init_led(0);
|
||||
init_led(1);
|
||||
init_led(2);
|
||||
init_led(3);
|
||||
|
||||
init_button(BUTTON_1);
|
||||
init_button(BUTTON_2);
|
||||
init_button(BUTTON_3);
|
||||
init_button(BUTTON_4);
|
||||
|
||||
init_pub();
|
||||
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = blemesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = blemesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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.
|
||||
#
|
||||
|
||||
syscfg.vals:
|
||||
# Set log level to info (disable debug logging).
|
||||
LOG_LEVEL: 1
|
||||
|
||||
# Default task settings
|
||||
OS_MAIN_STACK_SIZE: 768
|
||||
|
||||
# SMP is not supported in this app, so disable smp-over-shell.
|
||||
SHELL_MGMT: 0
|
||||
|
||||
MSYS_1_BLOCK_COUNT: 48
|
||||
|
||||
BLE_MESH: 1
|
||||
BLE_MESH_CFG_CLI: 1
|
||||
BLE_MESH_DEV_UUID: "((uint8_t[16]){0xdd, 0xdd, 0})"
|
||||
BLE_MESH_SETTINGS: 0
|
||||
CONFIG_NFFS: 0
|
||||
|
||||
BLE_MESH_ADV_BUF_COUNT: 20
|
||||
BLE_MESH_TX_SEG_MAX: 6
|
||||
101
src/libs/mynewt-nimble/apps/blemesh_models_example_2/README.md
Normal file
101
src/libs/mynewt-nimble/apps/blemesh_models_example_2/README.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#### Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
|
||||
##### Overview
|
||||
********
|
||||
|
||||
This is a application demonstrating a Bluetooth mesh node in
|
||||
which Root element has following models
|
||||
|
||||
- Generic OnOff Server
|
||||
- Generic OnOff Client
|
||||
- Generic Level Server
|
||||
- Generic Level Client
|
||||
- Generic Default Transition Time Server
|
||||
- Generic Default Transition Time Client
|
||||
- Generic Power OnOff Server
|
||||
- Generic Power OnOff Setup Server
|
||||
- Generic Power OnOff Client
|
||||
- Light Lightness Server
|
||||
- Light Lightness Setup Server
|
||||
- Light Lightness Client
|
||||
- Light CTL Server
|
||||
- Light CTL Setup Server
|
||||
- Light CTL Client
|
||||
- Vendor Model
|
||||
|
||||
And Secondary element has following models
|
||||
|
||||
- Generic Level Server
|
||||
- Generic Level Client
|
||||
- Light CTL Temperature Server
|
||||
|
||||
Prior to provisioning, an unprovisioned beacon is broadcast that contains
|
||||
a unique UUID. Each button controls the state of its
|
||||
corresponding LED and does not initiate any mesh activity
|
||||
|
||||
##### Associations of Models with hardware
|
||||
************************************
|
||||
For the nRF52840-PDK board, these are the model associations:
|
||||
|
||||
* LED1 is associated with generic OnOff Server's state which is part of Root element
|
||||
* LED2 is associated with Vendor Model which is part of Root element
|
||||
* LED3 is associated with generic Level (ROOT) / Light Lightness Actual value
|
||||
* LED4 is associated with generic Level (Secondary) / Light CTL Temperature value
|
||||
* Button1 and Button2 are associated with gen. OnOff Client or Vendor Model which is part of Root element
|
||||
* Button3 and Button4 are associated with gen. Level Client / Light Lightness Client / Light CTL Client which is part of Root element
|
||||
|
||||
States of Servers are bounded as per Bluetooth SIG Mesh Model Specification v1.0
|
||||
|
||||
After provisioning, the button clients must
|
||||
be configured to publish and the LED servers to subscribe.
|
||||
If a server is provided with a publish address, it will
|
||||
also publish its relevant status.
|
||||
|
||||
##### Requirements
|
||||
************
|
||||
This sample has been tested on the Nordic nRF52840-PDK board, but would
|
||||
likely also run on the nrf52_pca10040 board.
|
||||
|
||||
|
||||
##### Running
|
||||
************
|
||||
|
||||
Provisioning is done using the BlueZ meshctl utility. In this example, we'll use meshctl commands to bind:
|
||||
|
||||
- Button1, Button2, and LED1 to application key 1. It then configures Button1 and Button2
|
||||
to publish to group 0xC000 and LED1 to subscribe to that group.
|
||||
- Button3, Button4, and LED3 to application key 1. It then configures Button3 and Button4
|
||||
to publish to group 0xC000 and LED3 to subscribe to that group.
|
||||
|
||||
```
|
||||
discover-unprovisioned on
|
||||
provision <discovered UUID>
|
||||
menu config
|
||||
target 0100
|
||||
appkey-add 1
|
||||
bind 0 1 1000
|
||||
bind 0 1 1001
|
||||
bind 0 1 1002
|
||||
bind 0 1 1003
|
||||
sub-add 0100 c000 1000
|
||||
sub-add 0100 c000 1002
|
||||
pub-set 0100 c000 1 0 5 1001
|
||||
pub-set 0100 c000 1 0 5 1003
|
||||
```
|
||||
|
||||
The meshctl utility maintains a persistent JSON database containing
|
||||
the mesh configuration. As additional nodes (boards) are provisioned, it
|
||||
assigns sequential unicast addresses based on the number of elements
|
||||
supported by the node. This example supports 2 elements per node.
|
||||
|
||||
The meshctl target for configuration must be the root element's unicast
|
||||
address as it is the only one that has a configuration server model. If
|
||||
meshctl is gracefully exited, it can be restarted and reconnected to
|
||||
network 0x0.
|
||||
|
||||
The meshctl utility also supports a onoff model client that can be used to
|
||||
change the state of any LED that is bound to application key 0x1.
|
||||
This is done by setting the target to the unicast address of the element
|
||||
that has that LED's model and issuing the onoff command.
|
||||
Group addresses are not supported.
|
||||
|
||||
40
src/libs/mynewt-nimble/apps/blemesh_models_example_2/pkg.yml
Normal file
40
src/libs/mynewt-nimble/apps/blemesh_models_example_2/pkg.yml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# 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/blemesh_models_example_2
|
||||
pkg.type: app
|
||||
pkg.description: Sample application for BLE Mesh node with on/off, level, light and vendor models on nRF52840pdk
|
||||
pkg.author: "Michał Narajowski <michal.narajowski@codecoup.pl>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
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/encoding/base64"
|
||||
- "@apache-mynewt-core/sys/config"
|
||||
- nimble/controller
|
||||
- nimble/host
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/transport/ram
|
||||
|
||||
pkg.lflags:
|
||||
- -DFLOAT_SUPPORT
|
||||
- -lm
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bsp/bsp.h"
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
#include "app_gpio.h"
|
||||
#include "publisher.h"
|
||||
|
||||
int button_device[] = {
|
||||
BUTTON_1,
|
||||
BUTTON_2,
|
||||
BUTTON_3,
|
||||
BUTTON_4,
|
||||
};
|
||||
|
||||
int led_device[] = {
|
||||
LED_1,
|
||||
LED_2,
|
||||
LED_3,
|
||||
LED_4,
|
||||
};
|
||||
|
||||
static struct os_callout button_work;
|
||||
|
||||
static void button_pressed(struct os_event *ev)
|
||||
{
|
||||
os_callout_reset(&button_work, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void app_gpio_init(void)
|
||||
{
|
||||
/* LEDs configiuratin & setting */
|
||||
|
||||
hal_gpio_init_out(led_device[0], 1);
|
||||
hal_gpio_init_out(led_device[1], 1);
|
||||
hal_gpio_init_out(led_device[2], 1);
|
||||
hal_gpio_init_out(led_device[3], 1);
|
||||
|
||||
/* Buttons configiuratin & setting */
|
||||
|
||||
os_callout_init(&button_work, os_eventq_dflt_get(), publish, NULL);
|
||||
|
||||
button_event.ev_cb = button_pressed;
|
||||
|
||||
hal_gpio_irq_init(button_device[0], gpio_irq_handler, NULL,
|
||||
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(button_device[0]);
|
||||
|
||||
hal_gpio_irq_init(button_device[1], gpio_irq_handler, NULL,
|
||||
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(button_device[1]);
|
||||
|
||||
hal_gpio_irq_init(button_device[2], gpio_irq_handler, NULL,
|
||||
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(button_device[2]);
|
||||
|
||||
hal_gpio_irq_init(button_device[3], gpio_irq_handler, NULL,
|
||||
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(button_device[3]);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _APP_GPIO_H
|
||||
#define _APP_GPIO_H
|
||||
|
||||
/* GPIO */
|
||||
extern int button_device[];
|
||||
extern int led_device[];
|
||||
|
||||
void app_gpio_init(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "console/console.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "ble_mesh.h"
|
||||
#include "device_composition.h"
|
||||
|
||||
#define OOB_AUTH_ENABLE 1
|
||||
|
||||
#ifdef OOB_AUTH_ENABLE
|
||||
|
||||
static int output_number(bt_mesh_output_action_t action, u32_t number)
|
||||
{
|
||||
printk("OOB Number: %lu\n", number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_string(const char *str)
|
||||
{
|
||||
printk("OOB String: %s\n", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void prov_complete(u16_t net_idx, u16_t addr)
|
||||
{
|
||||
printk("Local node provisioned, primary address 0x%04x\n", addr);
|
||||
}
|
||||
|
||||
static void prov_reset(void)
|
||||
{
|
||||
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
|
||||
}
|
||||
|
||||
static u8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
|
||||
|
||||
static const struct bt_mesh_prov prov = {
|
||||
.uuid = dev_uuid,
|
||||
|
||||
#ifdef OOB_AUTH_ENABLE
|
||||
|
||||
.output_size = 6,
|
||||
.output_actions = BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING,
|
||||
.output_number = output_number,
|
||||
.output_string = output_string,
|
||||
|
||||
#endif
|
||||
|
||||
.complete = prov_complete,
|
||||
.reset = prov_reset,
|
||||
};
|
||||
|
||||
void blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
void blemesh_on_sync(void)
|
||||
{
|
||||
int err;
|
||||
ble_addr_t addr;
|
||||
|
||||
console_printf("Bluetooth initialized\n");
|
||||
|
||||
/* Use NRPA */
|
||||
err = ble_hs_id_gen_rnd(1, &addr);
|
||||
assert(err == 0);
|
||||
err = ble_hs_id_set_rnd(addr.val);
|
||||
assert(err == 0);
|
||||
|
||||
err = bt_mesh_init(addr.type, &prov, &comp);
|
||||
if (err) {
|
||||
console_printf("Initializing mesh failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
console_printf("Mesh network restored from flash\n");
|
||||
}
|
||||
|
||||
bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
|
||||
|
||||
console_printf("Mesh initialized\n");
|
||||
|
||||
bt_initialized();
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _BLE_MESH_H
|
||||
#define _BLE_MESH_H
|
||||
|
||||
#include "mesh/mesh.h"
|
||||
#include "mesh/glue.h"
|
||||
|
||||
/* Model Operation Codes */
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03)
|
||||
#define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04)
|
||||
|
||||
#define BT_MESH_MODEL_OP_GEN_LEVEL_GET BT_MESH_MODEL_OP_2(0x82, 0x05)
|
||||
#define BT_MESH_MODEL_OP_GEN_LEVEL_SET BT_MESH_MODEL_OP_2(0x82, 0x06)
|
||||
#define BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x07)
|
||||
#define BT_MESH_MODEL_OP_GEN_LEVEL_STATUS BT_MESH_MODEL_OP_2(0x82, 0x08)
|
||||
#define BT_MESH_MODEL_OP_GEN_DELTA_SET BT_MESH_MODEL_OP_2(0x82, 0x09)
|
||||
#define BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0A)
|
||||
#define BT_MESH_MODEL_OP_GEN_MOVE_SET BT_MESH_MODEL_OP_2(0x82, 0x0B)
|
||||
#define BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0C)
|
||||
|
||||
#define BT_MESH_MODEL_GEN_DEF_TRANS_TIME_STATUS BT_MESH_MODEL_OP_2(0x82, 0x10)
|
||||
|
||||
#define BT_MESH_MODEL_GEN_ONPOWERUP_STATUS BT_MESH_MODEL_OP_2(0x82, 0x12)
|
||||
|
||||
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_STATUS BT_MESH_MODEL_OP_2(0x82, 0x4E)
|
||||
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_LINEAR_STATUS \
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x52)
|
||||
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_LAST_STATUS \
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x54)
|
||||
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_DEFAULT_STATUS \
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x56)
|
||||
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_RANGE_STATUS \
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x58)
|
||||
|
||||
#define BT_MESH_MODEL_LIGHT_CTL_STATUS BT_MESH_MODEL_OP_2(0x82, 0x60)
|
||||
#define BT_MESH_MODEL_LIGHT_CTL_TEMP_RANGE_STATUS \
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x63)
|
||||
#define BT_MESH_MODEL_LIGHT_CTL_TEMP_STATUS BT_MESH_MODEL_OP_2(0x82, 0x66)
|
||||
#define BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS BT_MESH_MODEL_OP_2(0x82, 0x68)
|
||||
|
||||
void blemesh_on_reset(int reason);
|
||||
void blemesh_on_sync(void);
|
||||
void init_pub(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
void update_light_state(void);
|
||||
void bt_initialized(void);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_COMPOSITION_H
|
||||
#define _DEVICE_COMPOSITION_H
|
||||
|
||||
#define CID_RUNTIME 0x05C3
|
||||
|
||||
#define STATE_OFF 0x00
|
||||
#define STATE_ON 0x01
|
||||
#define STATE_DEFAULT 0x01
|
||||
#define STATE_RESTORE 0x02
|
||||
|
||||
/* Following 4 values are as per Mesh Model specification */
|
||||
#define LIGHTNESS_MIN 0x0001
|
||||
#define LIGHTNESS_MAX 0xFFFF
|
||||
#define TEMP_MIN 0x0320
|
||||
#define TEMP_MAX 0x4E20
|
||||
|
||||
/* Refer 7.2 of Mesh Model Specification */
|
||||
#define RANGE_SUCCESSFULLY_UPDATED 0x00
|
||||
#define CANNOT_SET_RANGE_MIN 0x01
|
||||
#define CANNOT_SET_RANGE_MAX 0x02
|
||||
|
||||
struct generic_onoff_state {
|
||||
u8_t onoff;
|
||||
u8_t target_onoff;
|
||||
|
||||
u8_t last_tid;
|
||||
u16_t last_src_addr;
|
||||
u16_t last_dst_addr;
|
||||
s64_t last_msg_timestamp;
|
||||
|
||||
s32_t tt_delta;
|
||||
|
||||
struct transition *transition;
|
||||
};
|
||||
|
||||
struct generic_level_state {
|
||||
s16_t level;
|
||||
s16_t target_level;
|
||||
|
||||
s16_t last_level;
|
||||
s32_t last_delta;
|
||||
|
||||
u8_t last_tid;
|
||||
u16_t last_src_addr;
|
||||
u16_t last_dst_addr;
|
||||
s64_t last_msg_timestamp;
|
||||
|
||||
s32_t tt_delta;
|
||||
|
||||
struct transition *transition;
|
||||
};
|
||||
|
||||
struct generic_onpowerup_state {
|
||||
u8_t onpowerup;
|
||||
};
|
||||
|
||||
struct gen_def_trans_time_state {
|
||||
u8_t tt;
|
||||
};
|
||||
|
||||
struct vendor_state {
|
||||
int current;
|
||||
u32_t response;
|
||||
u8_t last_tid;
|
||||
u16_t last_src_addr;
|
||||
u16_t last_dst_addr;
|
||||
s64_t last_msg_timestamp;
|
||||
};
|
||||
|
||||
struct light_lightness_state {
|
||||
u16_t linear;
|
||||
u16_t target_linear;
|
||||
|
||||
u16_t actual;
|
||||
u16_t target_actual;
|
||||
|
||||
u16_t last;
|
||||
u16_t def;
|
||||
|
||||
u8_t status_code;
|
||||
u16_t light_range_min;
|
||||
u16_t light_range_max;
|
||||
u32_t lightness_range;
|
||||
|
||||
u8_t last_tid;
|
||||
u16_t last_src_addr;
|
||||
u16_t last_dst_addr;
|
||||
s64_t last_msg_timestamp;
|
||||
|
||||
s32_t tt_delta_actual;
|
||||
s32_t tt_delta_linear;
|
||||
|
||||
struct transition *transition;
|
||||
};
|
||||
|
||||
struct light_ctl_state {
|
||||
u16_t lightness;
|
||||
u16_t target_lightness;
|
||||
|
||||
u16_t temp;
|
||||
u16_t target_temp;
|
||||
|
||||
s16_t delta_uv;
|
||||
s16_t target_delta_uv;
|
||||
|
||||
u8_t status_code;
|
||||
u16_t temp_range_min;
|
||||
u16_t temp_range_max;
|
||||
u32_t temperature_range;
|
||||
|
||||
u16_t lightness_def;
|
||||
u16_t temp_def;
|
||||
u32_t lightness_temp_def;
|
||||
s16_t delta_uv_def;
|
||||
|
||||
u32_t lightness_temp_last;
|
||||
|
||||
u8_t last_tid;
|
||||
u16_t last_src_addr;
|
||||
u16_t last_dst_addr;
|
||||
s64_t last_msg_timestamp;
|
||||
|
||||
s32_t tt_delta_lightness;
|
||||
s32_t tt_delta_temp;
|
||||
s32_t tt_delta_duv;
|
||||
|
||||
struct transition *transition;
|
||||
};
|
||||
|
||||
extern struct generic_onoff_state gen_onoff_srv_root_user_data;
|
||||
extern struct generic_level_state gen_level_srv_root_user_data;
|
||||
extern struct gen_def_trans_time_state gen_def_trans_time_srv_user_data;
|
||||
extern struct generic_onpowerup_state gen_power_onoff_srv_user_data;
|
||||
extern struct light_lightness_state light_lightness_srv_user_data;
|
||||
extern struct light_ctl_state light_ctl_srv_user_data;
|
||||
extern struct generic_level_state gen_level_srv_s0_user_data;
|
||||
|
||||
extern struct bt_mesh_model root_models[];
|
||||
extern struct bt_mesh_model vnd_models[];
|
||||
extern struct bt_mesh_model s0_models[];
|
||||
|
||||
extern const struct bt_mesh_comp comp;
|
||||
|
||||
void gen_onoff_publish(struct bt_mesh_model *model);
|
||||
void gen_level_publish(struct bt_mesh_model *model);
|
||||
void light_lightness_publish(struct bt_mesh_model *model);
|
||||
void light_lightness_linear_publish(struct bt_mesh_model *model);
|
||||
void light_ctl_publish(struct bt_mesh_model *model);
|
||||
void light_ctl_temp_publish(struct bt_mesh_model *model);
|
||||
|
||||
#endif
|
||||
250
src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/main.c
Normal file
250
src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/main.c
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
#include "app_gpio.h"
|
||||
#include "storage.h"
|
||||
|
||||
#include "ble_mesh.h"
|
||||
#include "device_composition.h"
|
||||
#include "no_transition_work_handler.h"
|
||||
#include "publisher.h"
|
||||
#include "state_binding.h"
|
||||
#include "transition.h"
|
||||
|
||||
static bool reset;
|
||||
|
||||
static void light_default_var_init(void)
|
||||
{
|
||||
gen_def_trans_time_srv_user_data.tt = 0x00;
|
||||
|
||||
gen_power_onoff_srv_user_data.onpowerup = STATE_DEFAULT;
|
||||
|
||||
light_lightness_srv_user_data.light_range_min = LIGHTNESS_MIN;
|
||||
light_lightness_srv_user_data.light_range_max = LIGHTNESS_MAX;
|
||||
light_lightness_srv_user_data.last = LIGHTNESS_MAX;
|
||||
light_lightness_srv_user_data.def = LIGHTNESS_MAX;
|
||||
|
||||
/* Following 2 values are as per specification */
|
||||
light_ctl_srv_user_data.temp_range_min = TEMP_MIN;
|
||||
light_ctl_srv_user_data.temp_range_max = TEMP_MAX;
|
||||
|
||||
light_ctl_srv_user_data.temp_def = TEMP_MIN;
|
||||
|
||||
light_ctl_srv_user_data.lightness_temp_last =
|
||||
(u32_t) ((LIGHTNESS_MAX << 16) | TEMP_MIN);
|
||||
}
|
||||
|
||||
static void light_default_status_init(void)
|
||||
{
|
||||
u16_t lightness;
|
||||
|
||||
lightness = (u16_t) (light_ctl_srv_user_data.lightness_temp_last >> 16);
|
||||
|
||||
if (lightness) {
|
||||
gen_onoff_srv_root_user_data.onoff = STATE_ON;
|
||||
} else {
|
||||
gen_onoff_srv_root_user_data.onoff = STATE_OFF;
|
||||
}
|
||||
|
||||
/* Retrieve Default Lightness & Temperature Values */
|
||||
|
||||
if (light_ctl_srv_user_data.lightness_temp_def) {
|
||||
light_ctl_srv_user_data.lightness_def = (u16_t)
|
||||
(light_ctl_srv_user_data.lightness_temp_def >> 16);
|
||||
|
||||
light_ctl_srv_user_data.temp_def = (u16_t)
|
||||
(light_ctl_srv_user_data.lightness_temp_def);
|
||||
}
|
||||
|
||||
light_lightness_srv_user_data.def =
|
||||
light_ctl_srv_user_data.lightness_def;
|
||||
|
||||
light_ctl_srv_user_data.temp = light_ctl_srv_user_data.temp_def;
|
||||
|
||||
/* Retrieve Range of Lightness & Temperature */
|
||||
|
||||
if (light_lightness_srv_user_data.lightness_range) {
|
||||
light_lightness_srv_user_data.light_range_max = (u16_t)
|
||||
(light_lightness_srv_user_data.lightness_range >> 16);
|
||||
|
||||
light_lightness_srv_user_data.light_range_min = (u16_t)
|
||||
(light_lightness_srv_user_data.lightness_range);
|
||||
}
|
||||
|
||||
if (light_ctl_srv_user_data.temperature_range) {
|
||||
light_ctl_srv_user_data.temp_range_max = (u16_t)
|
||||
(light_ctl_srv_user_data.temperature_range >> 16);
|
||||
|
||||
light_ctl_srv_user_data.temp_range_min = (u16_t)
|
||||
(light_ctl_srv_user_data.temperature_range);
|
||||
}
|
||||
|
||||
switch (gen_power_onoff_srv_user_data.onpowerup) {
|
||||
case STATE_OFF:
|
||||
gen_onoff_srv_root_user_data.onoff = STATE_OFF;
|
||||
state_binding(ONOFF, ONOFF_TEMP);
|
||||
break;
|
||||
case STATE_DEFAULT:
|
||||
gen_onoff_srv_root_user_data.onoff = STATE_ON;
|
||||
state_binding(ONOFF, ONOFF_TEMP);
|
||||
break;
|
||||
case STATE_RESTORE:
|
||||
light_lightness_srv_user_data.last = (u16_t)
|
||||
(light_ctl_srv_user_data.lightness_temp_last >> 16);
|
||||
|
||||
light_ctl_srv_user_data.temp =
|
||||
(u16_t) (light_ctl_srv_user_data.lightness_temp_last);
|
||||
|
||||
state_binding(ONPOWERUP, ONOFF_TEMP);
|
||||
break;
|
||||
}
|
||||
|
||||
default_tt = gen_def_trans_time_srv_user_data.tt;
|
||||
}
|
||||
|
||||
void update_light_state(void)
|
||||
{
|
||||
u8_t power, color;
|
||||
|
||||
power = 100 * ((float) lightness / 65535);
|
||||
color = 100 * ((float) (temperature + 32768) / 65535);
|
||||
|
||||
printk("power-> %d, color-> %d\n", power, color);
|
||||
|
||||
if (lightness) {
|
||||
/* LED1 On */
|
||||
hal_gpio_write(led_device[0], 0);
|
||||
} else {
|
||||
/* LED1 Off */
|
||||
hal_gpio_write(led_device[0], 1);
|
||||
}
|
||||
|
||||
if (power < 50) {
|
||||
/* LED3 On */
|
||||
hal_gpio_write(led_device[2], 0);
|
||||
} else {
|
||||
/* LED3 Off */
|
||||
hal_gpio_write(led_device[2], 1);
|
||||
}
|
||||
|
||||
if (color < 50) {
|
||||
/* LED4 On */
|
||||
hal_gpio_write(led_device[3], 0);
|
||||
} else {
|
||||
/* LED4 Off */
|
||||
hal_gpio_write(led_device[3], 1);
|
||||
}
|
||||
|
||||
if (*ptr_counter == 0 || reset == false) {
|
||||
reset = true;
|
||||
os_callout_reset(&no_transition_work, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void short_time_multireset_bt_mesh_unprovisioning(void)
|
||||
{
|
||||
if (reset_counter >= 4) {
|
||||
reset_counter = 0;
|
||||
printk("BT Mesh reset\n");
|
||||
bt_mesh_reset();
|
||||
} else {
|
||||
printk("Reset Counter -> %d\n", reset_counter);
|
||||
reset_counter++;
|
||||
}
|
||||
|
||||
save_on_flash(RESET_COUNTER);
|
||||
}
|
||||
|
||||
static void reset_counter_timer_handler(struct os_event *dummy)
|
||||
{
|
||||
reset_counter = 0;
|
||||
save_on_flash(RESET_COUNTER);
|
||||
printk("Reset Counter set to Zero\n");
|
||||
}
|
||||
|
||||
struct os_callout reset_counter_timer;
|
||||
|
||||
static void init_timers(void)
|
||||
{
|
||||
|
||||
os_callout_init(&reset_counter_timer, os_eventq_dflt_get(),
|
||||
reset_counter_timer_handler, NULL);
|
||||
os_callout_reset(&reset_counter_timer,
|
||||
os_time_ms_to_ticks32(K_MSEC(7000)));
|
||||
|
||||
no_transition_work_init();
|
||||
}
|
||||
|
||||
void bt_initialized(void)
|
||||
{
|
||||
light_default_status_init();
|
||||
|
||||
update_light_state();
|
||||
|
||||
randomize_publishers_TID();
|
||||
|
||||
short_time_multireset_bt_mesh_unprovisioning();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#ifdef ARCH_sim
|
||||
mcu_sim_parse_args(argc, argv);
|
||||
#endif
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
light_default_var_init();
|
||||
|
||||
app_gpio_init();
|
||||
|
||||
init_timers();
|
||||
|
||||
transition_timers_init();
|
||||
|
||||
init_pub();
|
||||
|
||||
ps_settings_init();
|
||||
|
||||
printk("Initializing...\n");
|
||||
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = blemesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = blemesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "ble_mesh.h"
|
||||
#include "device_composition.h"
|
||||
|
||||
#include "storage.h"
|
||||
|
||||
static void unsolicitedly_publish_states_work_handler(struct os_event *work)
|
||||
{
|
||||
gen_onoff_publish(&root_models[2]);
|
||||
gen_level_publish(&root_models[4]);
|
||||
light_lightness_publish(&root_models[11]);
|
||||
light_lightness_linear_publish(&root_models[11]);
|
||||
light_ctl_publish(&root_models[14]);
|
||||
|
||||
gen_level_publish(&s0_models[0]);
|
||||
light_ctl_temp_publish(&s0_models[2]);
|
||||
}
|
||||
|
||||
struct os_callout unsolicitedly_publish_states_work;
|
||||
|
||||
static void unsolicitedly_publish_states_timer_handler(struct os_event *dummy)
|
||||
{
|
||||
os_callout_reset(&unsolicitedly_publish_states_work, 0);
|
||||
}
|
||||
|
||||
struct os_callout unsolicitedly_publish_states_timer;
|
||||
|
||||
static void save_lightness_temp_last_values_timer_handler(struct os_event *dummy)
|
||||
{
|
||||
save_on_flash(LIGHTNESS_TEMP_LAST_STATE);
|
||||
}
|
||||
|
||||
struct os_callout save_lightness_temp_last_values_timer;
|
||||
|
||||
static void no_transition_work_handler(struct os_event *work)
|
||||
{
|
||||
os_callout_reset(&unsolicitedly_publish_states_timer,
|
||||
os_time_ms_to_ticks32(K_MSEC(5000)));
|
||||
|
||||
/* If Lightness & Temperature values remains stable for
|
||||
* 10 Seconds then & then only get stored on SoC flash.
|
||||
*/
|
||||
if (gen_power_onoff_srv_user_data.onpowerup == STATE_RESTORE) {
|
||||
os_callout_reset(&save_lightness_temp_last_values_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(10000)));
|
||||
}
|
||||
}
|
||||
|
||||
struct os_callout no_transition_work;
|
||||
|
||||
void no_transition_work_init(void)
|
||||
{
|
||||
os_callout_init(&no_transition_work, os_eventq_dflt_get(),
|
||||
no_transition_work_handler, NULL);
|
||||
os_callout_init(&save_lightness_temp_last_values_timer,
|
||||
os_eventq_dflt_get(),
|
||||
save_lightness_temp_last_values_timer_handler,
|
||||
NULL);
|
||||
os_callout_init(&unsolicitedly_publish_states_work, os_eventq_dflt_get(),
|
||||
unsolicitedly_publish_states_work_handler, NULL);
|
||||
os_callout_init(&unsolicitedly_publish_states_timer, os_eventq_dflt_get(),
|
||||
unsolicitedly_publish_states_timer_handler, NULL);
|
||||
}
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _NO_TRANSITION_WORK_HANDLER_H
|
||||
#define _NO_TRANSITION_WORK_HANDLER_H
|
||||
|
||||
extern struct os_callout no_transition_work;
|
||||
|
||||
void no_transition_work_init(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
|
||||
#include "app_gpio.h"
|
||||
|
||||
#include "ble_mesh.h"
|
||||
#include "device_composition.h"
|
||||
#include "publisher.h"
|
||||
|
||||
#define ONOFF
|
||||
#define GENERIC_LEVEL
|
||||
/* #define LIGHT_CTL */
|
||||
/* #define LIGHT_CTL_TEMP */
|
||||
|
||||
static bool is_randomization_of_TIDs_done;
|
||||
|
||||
#if (defined(ONOFF) || defined(ONOFF_TT))
|
||||
static u8_t tid_onoff;
|
||||
#elif defined(VND_MODEL_TEST)
|
||||
static u8_t tid_vnd;
|
||||
#endif
|
||||
|
||||
static u8_t tid_level;
|
||||
|
||||
void randomize_publishers_TID(void)
|
||||
{
|
||||
#if (defined(ONOFF) || defined(ONOFF_TT))
|
||||
bt_rand(&tid_onoff, sizeof(tid_onoff));
|
||||
#elif defined(VND_MODEL_TEST)
|
||||
bt_rand(&tid_vnd, sizeof(tid_vnd));
|
||||
#endif
|
||||
|
||||
bt_rand(&tid_level, sizeof(tid_level));
|
||||
|
||||
is_randomization_of_TIDs_done = true;
|
||||
}
|
||||
|
||||
static u32_t button_read(int button)
|
||||
{
|
||||
return (uint32_t) hal_gpio_read(button);
|
||||
}
|
||||
|
||||
void publish(struct os_event *work)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (is_randomization_of_TIDs_done == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (button_read(button_device[0]) == 0) {
|
||||
#if defined(ONOFF)
|
||||
bt_mesh_model_msg_init(root_models[3].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
|
||||
err = bt_mesh_model_publish(&root_models[3]);
|
||||
#elif defined(ONOFF_TT)
|
||||
bt_mesh_model_msg_init(root_models[3].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x28);
|
||||
err = bt_mesh_model_publish(&root_models[3]);
|
||||
#elif defined(VND_MODEL_TEST)
|
||||
bt_mesh_model_msg_init(vnd_models[0].pub->msg,
|
||||
BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME));
|
||||
net_buf_simple_add_le16(vnd_models[0].pub->msg, 0x0001);
|
||||
net_buf_simple_add_u8(vnd_models[0].pub->msg, tid_vnd++);
|
||||
err = bt_mesh_model_publish(&vnd_models[0]);
|
||||
#endif
|
||||
|
||||
} else if (button_read(button_device[1]) == 0) {
|
||||
#if defined(ONOFF)
|
||||
bt_mesh_model_msg_init(root_models[3].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x00);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
|
||||
err = bt_mesh_model_publish(&root_models[3]);
|
||||
#elif defined(ONOFF_TT)
|
||||
bt_mesh_model_msg_init(root_models[3].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x00);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x28);
|
||||
err = bt_mesh_model_publish(&root_models[3]);
|
||||
#elif defined(VND_MODEL_TEST)
|
||||
bt_mesh_model_msg_init(vnd_models[0].pub->msg,
|
||||
BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME));
|
||||
net_buf_simple_add_le16(vnd_models[0].pub->msg, 0x0000);
|
||||
net_buf_simple_add_u8(vnd_models[0].pub->msg, tid_vnd++);
|
||||
err = bt_mesh_model_publish(&vnd_models[0]);
|
||||
#endif
|
||||
|
||||
} else if (button_read(button_device[2]) == 0) {
|
||||
#if defined(GENERIC_LEVEL)
|
||||
bt_mesh_model_msg_init(root_models[5].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK);
|
||||
net_buf_simple_add_le16(root_models[5].pub->msg, LEVEL_S25);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[5]);
|
||||
#elif defined(ONOFF_GET)
|
||||
bt_mesh_model_msg_init(root_models[3].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_GET);
|
||||
err = bt_mesh_model_publish(&root_models[3]);
|
||||
#elif defined(GENERIC_DELTA_LEVEL)
|
||||
bt_mesh_model_msg_init(root_models[5].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK);
|
||||
net_buf_simple_add_le32(root_models[5].pub->msg, 100);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[5]);
|
||||
#elif defined(GENERIC_MOVE_LEVEL_TT)
|
||||
bt_mesh_model_msg_init(root_models[5].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK);
|
||||
net_buf_simple_add_le16(root_models[5].pub->msg, 13100);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, 0x00);
|
||||
err = bt_mesh_model_publish(&root_models[5]);
|
||||
#elif defined(LIGHT_LIGHTNESS_TT)
|
||||
bt_mesh_model_msg_init(root_models[13].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x4D));
|
||||
net_buf_simple_add_le16(root_models[13].pub->msg, LEVEL_U25);
|
||||
net_buf_simple_add_u8(root_models[13].pub->msg, tid_level++);
|
||||
net_buf_simple_add_u8(root_models[13].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[13].pub->msg, 0x28);
|
||||
err = bt_mesh_model_publish(&root_models[13]);
|
||||
#elif defined(LIGHT_CTL)
|
||||
bt_mesh_model_msg_init(root_models[16].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x5F));
|
||||
/* Lightness */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U25);
|
||||
/* Temperature (value should be from 0x0320 to 0x4E20 */
|
||||
/* This is as per 6.1.3.1 in Mesh Model Specification */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
|
||||
/* Delta UV */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[16]);
|
||||
#elif defined(LIGHT_CTL_TT)
|
||||
bt_mesh_model_msg_init(root_models[16].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x5F));
|
||||
/* Lightness */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U25);
|
||||
/* Temperature (value should be from 0x0320 to 0x4E20 */
|
||||
/* This is as per 6.1.3.1 in Mesh Model Specification */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
|
||||
/* Delta UV */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, 0x00);
|
||||
err = bt_mesh_model_publish(&root_models[16]);
|
||||
#elif defined(LIGHT_CTL_TEMP)
|
||||
bt_mesh_model_msg_init(root_models[16].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x65));
|
||||
/* Temperature (value should be from 0x0320 to 0x4E20 */
|
||||
/* This is as per 6.1.3.1 in Mesh Model Specification */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
|
||||
/* Delta UV */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[16]);
|
||||
#endif
|
||||
|
||||
} else if (button_read(button_device[3]) == 0) {
|
||||
#if defined(GENERIC_LEVEL)
|
||||
bt_mesh_model_msg_init(root_models[5].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK);
|
||||
net_buf_simple_add_le16(root_models[5].pub->msg, LEVEL_S100);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[5]);
|
||||
#elif defined(GENERIC_DELTA_LEVEL)
|
||||
bt_mesh_model_msg_init(root_models[5].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK);
|
||||
net_buf_simple_add_le32(root_models[5].pub->msg, -100);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[5]);
|
||||
#elif defined(GENERIC_MOVE_LEVEL_TT)
|
||||
bt_mesh_model_msg_init(root_models[5].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK);
|
||||
net_buf_simple_add_le16(root_models[5].pub->msg, -13100);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[5].pub->msg, 0x00);
|
||||
err = bt_mesh_model_publish(&root_models[5]);
|
||||
#elif defined(LIGHT_LIGHTNESS_TT)
|
||||
bt_mesh_model_msg_init(root_models[13].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x4D));
|
||||
net_buf_simple_add_le16(root_models[13].pub->msg, LEVEL_U100);
|
||||
net_buf_simple_add_u8(root_models[13].pub->msg, tid_level++);
|
||||
net_buf_simple_add_u8(root_models[13].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[13].pub->msg, 0x28);
|
||||
err = bt_mesh_model_publish(&root_models[13]);
|
||||
#elif defined(LIGHT_CTL)
|
||||
bt_mesh_model_msg_init(root_models[16].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x5F));
|
||||
/* Lightness */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U100);
|
||||
/* Temperature (value should be from 0x0320 to 0x4E20 */
|
||||
/* This is as per 6.1.3.1 in Mesh Model Specification */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
|
||||
/* Delta UV */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[16]);
|
||||
#elif defined(LIGHT_CTL_TT)
|
||||
bt_mesh_model_msg_init(root_models[16].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x5F));
|
||||
/* Lightness */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U100);
|
||||
/* Temperature (value should be from 0x0320 to 0x4E20 */
|
||||
/* This is as per 6.1.3.1 in Mesh Model Specification */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
|
||||
/* Delta UV */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, 0x00);
|
||||
err = bt_mesh_model_publish(&root_models[16]);
|
||||
#elif defined(LIGHT_CTL_TEMP)
|
||||
bt_mesh_model_msg_init(root_models[16].pub->msg,
|
||||
BT_MESH_MODEL_OP_2(0x82, 0x65));
|
||||
/* Temperature (value should be from 0x0320 to 0x4E20 */
|
||||
/* This is as per 6.1.3.1 in Mesh Model Specification */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
|
||||
/* Delta UV */
|
||||
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
|
||||
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
|
||||
err = bt_mesh_model_publish(&root_models[16]);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (err) {
|
||||
printk("bt_mesh_model_publish: err: %d\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _PUBLISHER_H
|
||||
#define _PUBLISHER_H
|
||||
|
||||
/* Others */
|
||||
#define LEVEL_S0 -32768
|
||||
#define LEVEL_S25 -16384
|
||||
#define LEVEL_S50 0
|
||||
#define LEVEL_S75 16384
|
||||
#define LEVEL_S100 32767
|
||||
|
||||
#define LEVEL_U0 0
|
||||
#define LEVEL_U25 16384
|
||||
#define LEVEL_U50 32768
|
||||
#define LEVEL_U75 49152
|
||||
#define LEVEL_U100 65535
|
||||
|
||||
void randomize_publishers_TID(void);
|
||||
void publish(struct os_event *work);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "ble_mesh.h"
|
||||
#include "device_composition.h"
|
||||
#include "state_binding.h"
|
||||
#include "transition.h"
|
||||
|
||||
|
||||
u16_t lightness, target_lightness;
|
||||
s16_t temperature, target_temperature;
|
||||
|
||||
static s32_t ceiling(float num)
|
||||
{
|
||||
s32_t inum;
|
||||
|
||||
inum = (s32_t) num;
|
||||
if (num == (float) inum) {
|
||||
return inum;
|
||||
}
|
||||
|
||||
return inum + 1;
|
||||
}
|
||||
|
||||
u16_t actual_to_linear(u16_t val)
|
||||
{
|
||||
float tmp;
|
||||
|
||||
tmp = ((float) val / 65535);
|
||||
|
||||
return (u16_t) ceiling(65535 * tmp * tmp);
|
||||
}
|
||||
|
||||
u16_t linear_to_actual(u16_t val)
|
||||
{
|
||||
return (u16_t) (65535 * sqrt(((float) val / 65535)));
|
||||
}
|
||||
|
||||
static void constrain_lightness(u16_t var)
|
||||
{
|
||||
if (var > 0 && var < light_lightness_srv_user_data.light_range_min) {
|
||||
var = light_lightness_srv_user_data.light_range_min;
|
||||
} else if (var > light_lightness_srv_user_data.light_range_max) {
|
||||
var = light_lightness_srv_user_data.light_range_max;
|
||||
}
|
||||
|
||||
lightness = var;
|
||||
}
|
||||
|
||||
static void constrain_lightness2(u16_t var)
|
||||
{
|
||||
/* This is as per Mesh Model Specification 3.3.2.2.3 */
|
||||
if (var > 0 && var < light_lightness_srv_user_data.light_range_min) {
|
||||
if (gen_level_srv_root_user_data.last_delta < 0) {
|
||||
var = 0U;
|
||||
} else {
|
||||
var = light_lightness_srv_user_data.light_range_min;
|
||||
}
|
||||
} else if (var > light_lightness_srv_user_data.light_range_max) {
|
||||
var = light_lightness_srv_user_data.light_range_max;
|
||||
}
|
||||
|
||||
lightness = var;
|
||||
}
|
||||
|
||||
static void constrain_target_lightness(u16_t var)
|
||||
{
|
||||
if (var > 0 &&
|
||||
var < light_lightness_srv_user_data.light_range_min) {
|
||||
var = light_lightness_srv_user_data.light_range_min;
|
||||
} else if (var > light_lightness_srv_user_data.light_range_max) {
|
||||
var = light_lightness_srv_user_data.light_range_max;
|
||||
}
|
||||
|
||||
target_lightness = var;
|
||||
}
|
||||
|
||||
static s16_t light_ctl_temp_to_level(u16_t temp)
|
||||
{
|
||||
float tmp;
|
||||
|
||||
/* Mesh Model Specification 6.1.3.1.1 2nd formula start */
|
||||
|
||||
tmp = (temp - light_ctl_srv_user_data.temp_range_min) * 65535;
|
||||
|
||||
tmp = tmp / (light_ctl_srv_user_data.temp_range_max -
|
||||
light_ctl_srv_user_data.temp_range_min);
|
||||
|
||||
return (s16_t) (tmp - 32768);
|
||||
|
||||
/* 6.1.3.1.1 2nd formula end */
|
||||
}
|
||||
|
||||
static u16_t level_to_light_ctl_temp(s16_t level)
|
||||
{
|
||||
u16_t tmp;
|
||||
float diff;
|
||||
|
||||
/* Mesh Model Specification 6.1.3.1.1 1st formula start */
|
||||
diff = (float) (light_ctl_srv_user_data.temp_range_max -
|
||||
light_ctl_srv_user_data.temp_range_min) / 65535;
|
||||
|
||||
|
||||
tmp = (u16_t) ((level + 32768) * diff);
|
||||
|
||||
return (light_ctl_srv_user_data.temp_range_min + tmp);
|
||||
|
||||
/* 6.1.3.1.1 1st formula end */
|
||||
}
|
||||
|
||||
void state_binding(u8_t light, u8_t temp)
|
||||
{
|
||||
switch (temp) {
|
||||
case ONOFF_TEMP:
|
||||
case CTL_TEMP:
|
||||
temperature =
|
||||
light_ctl_temp_to_level(light_ctl_srv_user_data.temp);
|
||||
|
||||
gen_level_srv_s0_user_data.level = temperature;
|
||||
break;
|
||||
case LEVEL_TEMP:
|
||||
temperature = gen_level_srv_s0_user_data.level;
|
||||
light_ctl_srv_user_data.temp =
|
||||
level_to_light_ctl_temp(temperature);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (light) {
|
||||
case ONPOWERUP:
|
||||
if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) {
|
||||
lightness = 0U;
|
||||
} else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
|
||||
lightness = light_lightness_srv_user_data.last;
|
||||
}
|
||||
break;
|
||||
case ONOFF:
|
||||
if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) {
|
||||
lightness = 0U;
|
||||
} else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
|
||||
if (light_lightness_srv_user_data.def == 0) {
|
||||
lightness = light_lightness_srv_user_data.last;
|
||||
} else {
|
||||
lightness = light_lightness_srv_user_data.def;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LEVEL:
|
||||
lightness = gen_level_srv_root_user_data.level + 32768;
|
||||
break;
|
||||
case DELTA_LEVEL:
|
||||
lightness = gen_level_srv_root_user_data.level + 32768;
|
||||
constrain_lightness2(lightness);
|
||||
goto jump;
|
||||
case ACTUAL:
|
||||
lightness = light_lightness_srv_user_data.actual;
|
||||
break;
|
||||
case LINEAR:
|
||||
lightness =
|
||||
linear_to_actual(light_lightness_srv_user_data.linear);
|
||||
break;
|
||||
case CTL:
|
||||
lightness = light_ctl_srv_user_data.lightness;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
constrain_lightness(lightness);
|
||||
|
||||
jump:
|
||||
if (lightness != 0) {
|
||||
light_lightness_srv_user_data.last = lightness;
|
||||
}
|
||||
|
||||
if (lightness) {
|
||||
gen_onoff_srv_root_user_data.onoff = STATE_ON;
|
||||
} else {
|
||||
gen_onoff_srv_root_user_data.onoff = STATE_OFF;
|
||||
}
|
||||
|
||||
gen_level_srv_root_user_data.level = lightness - 32768;
|
||||
light_lightness_srv_user_data.actual = lightness;
|
||||
light_lightness_srv_user_data.linear = actual_to_linear(lightness);
|
||||
light_ctl_srv_user_data.lightness = lightness;
|
||||
}
|
||||
|
||||
void calculate_lightness_target_values(u8_t type)
|
||||
{
|
||||
bool set_light_ctl_temp_target_value;
|
||||
u16_t tmp;
|
||||
|
||||
set_light_ctl_temp_target_value = true;
|
||||
|
||||
switch (type) {
|
||||
case ONOFF:
|
||||
if (gen_onoff_srv_root_user_data.target_onoff == 0) {
|
||||
tmp = 0U;
|
||||
} else {
|
||||
if (light_lightness_srv_user_data.def == 0) {
|
||||
tmp = light_lightness_srv_user_data.last;
|
||||
} else {
|
||||
tmp = light_lightness_srv_user_data.def;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LEVEL:
|
||||
tmp = gen_level_srv_root_user_data.target_level + 32768;
|
||||
break;
|
||||
case ACTUAL:
|
||||
tmp = light_lightness_srv_user_data.target_actual;
|
||||
break;
|
||||
case LINEAR:
|
||||
tmp = linear_to_actual(light_lightness_srv_user_data.target_linear);
|
||||
break;
|
||||
case CTL:
|
||||
set_light_ctl_temp_target_value = false;
|
||||
|
||||
tmp = light_ctl_srv_user_data.target_lightness;
|
||||
|
||||
target_temperature = light_ctl_temp_to_level(light_ctl_srv_user_data.target_temp);
|
||||
gen_level_srv_s0_user_data.target_level = target_temperature;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
constrain_target_lightness(tmp);
|
||||
|
||||
if (target_lightness) {
|
||||
gen_onoff_srv_root_user_data.target_onoff = STATE_ON;
|
||||
} else {
|
||||
gen_onoff_srv_root_user_data.target_onoff = STATE_OFF;
|
||||
}
|
||||
|
||||
gen_level_srv_root_user_data.target_level = target_lightness - 32768;
|
||||
|
||||
light_lightness_srv_user_data.target_actual = target_lightness;
|
||||
|
||||
light_lightness_srv_user_data.target_linear =
|
||||
actual_to_linear(target_lightness);
|
||||
|
||||
light_ctl_srv_user_data.target_lightness = target_lightness;
|
||||
|
||||
if (set_light_ctl_temp_target_value) {
|
||||
target_temperature = light_ctl_srv_user_data.temp;
|
||||
light_ctl_srv_user_data.target_temp = target_temperature;
|
||||
}
|
||||
}
|
||||
|
||||
void calculate_temp_target_values(u8_t type)
|
||||
{
|
||||
bool set_light_ctl_delta_uv_target_value;
|
||||
|
||||
set_light_ctl_delta_uv_target_value = true;
|
||||
|
||||
switch (type) {
|
||||
case LEVEL_TEMP:
|
||||
target_temperature = gen_level_srv_s0_user_data.target_level;
|
||||
light_ctl_srv_user_data.target_temp =
|
||||
level_to_light_ctl_temp(target_temperature);
|
||||
break;
|
||||
case CTL_TEMP:
|
||||
set_light_ctl_delta_uv_target_value = false;
|
||||
|
||||
target_temperature = light_ctl_temp_to_level(light_ctl_srv_user_data.target_temp);
|
||||
gen_level_srv_s0_user_data.target_level = target_temperature;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
target_lightness = light_ctl_srv_user_data.lightness;
|
||||
light_ctl_srv_user_data.target_lightness = target_lightness;
|
||||
|
||||
if (set_light_ctl_delta_uv_target_value) {
|
||||
|
||||
light_ctl_srv_user_data.target_delta_uv =
|
||||
light_ctl_srv_user_data.delta_uv;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _STATE_BINDING_H
|
||||
#define _STATE_BINDING_H
|
||||
|
||||
enum state_binding {
|
||||
ONPOWERUP = 0x01,
|
||||
ONOFF,
|
||||
LEVEL,
|
||||
DELTA_LEVEL,
|
||||
ACTUAL,
|
||||
LINEAR,
|
||||
CTL,
|
||||
IGNORE,
|
||||
|
||||
ONOFF_TEMP,
|
||||
LEVEL_TEMP,
|
||||
CTL_TEMP,
|
||||
IGNORE_TEMP
|
||||
};
|
||||
|
||||
extern u16_t lightness, target_lightness;
|
||||
extern s16_t temperature, target_temperature;
|
||||
|
||||
void state_binding(u8_t lightness, u8_t temperature);
|
||||
void calculate_lightness_target_values(u8_t type);
|
||||
void calculate_temp_target_values(u8_t type);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "base64/base64.h"
|
||||
#include "console/console.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
#include "ble_mesh.h"
|
||||
#include "device_composition.h"
|
||||
#include "storage.h"
|
||||
|
||||
static u8_t storage_id;
|
||||
u8_t reset_counter;
|
||||
|
||||
static void save_reset_counter(void)
|
||||
{
|
||||
char buf[5];
|
||||
|
||||
settings_str_from_bytes(&reset_counter, sizeof(reset_counter), buf,
|
||||
sizeof(buf));
|
||||
|
||||
settings_save_one("ps/rc", buf);
|
||||
}
|
||||
|
||||
static void save_gen_def_trans_time_state(void)
|
||||
{
|
||||
char buf[5];
|
||||
|
||||
settings_str_from_bytes(&gen_def_trans_time_srv_user_data.tt,
|
||||
sizeof(gen_def_trans_time_srv_user_data.tt),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/gdtt", buf);
|
||||
}
|
||||
|
||||
static void save_gen_onpowerup_state(void)
|
||||
{
|
||||
char buf[5];
|
||||
|
||||
settings_str_from_bytes(&gen_power_onoff_srv_user_data.onpowerup,
|
||||
sizeof(gen_power_onoff_srv_user_data.onpowerup),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/gpo", buf);
|
||||
|
||||
if (gen_power_onoff_srv_user_data.onpowerup == 0x02) {
|
||||
save_on_flash(LIGHTNESS_TEMP_LAST_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_lightness_temp_def_state(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_ctl_srv_user_data.lightness_temp_def =
|
||||
(u32_t) ((light_ctl_srv_user_data.lightness_def << 16) |
|
||||
light_ctl_srv_user_data.temp_def);
|
||||
|
||||
settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_def,
|
||||
sizeof(light_ctl_srv_user_data.lightness_temp_def),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/ltd", buf);
|
||||
}
|
||||
|
||||
static void save_lightness_temp_last_state(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_ctl_srv_user_data.lightness_temp_last =
|
||||
(u32_t) ((light_ctl_srv_user_data.lightness << 16) |
|
||||
light_ctl_srv_user_data.temp);
|
||||
|
||||
settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_last,
|
||||
sizeof(light_ctl_srv_user_data.lightness_temp_last),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/ltl", buf);
|
||||
|
||||
printk("Light CTL Last values have beed saved !!\n");
|
||||
}
|
||||
|
||||
static void save_lightness_range(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_lightness_srv_user_data.lightness_range =
|
||||
(u32_t) ((light_lightness_srv_user_data.light_range_max << 16) |
|
||||
light_lightness_srv_user_data.light_range_min);
|
||||
|
||||
settings_str_from_bytes(&light_lightness_srv_user_data.lightness_range,
|
||||
sizeof(light_lightness_srv_user_data.lightness_range),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/lr", buf);
|
||||
}
|
||||
|
||||
static void save_temperature_range(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_ctl_srv_user_data.temperature_range =
|
||||
(u32_t) ((light_ctl_srv_user_data.temp_range_max << 16) |
|
||||
light_ctl_srv_user_data.temp_range_min);
|
||||
|
||||
settings_str_from_bytes(&light_ctl_srv_user_data.temperature_range,
|
||||
sizeof(light_ctl_srv_user_data.temperature_range),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/tr", buf);
|
||||
}
|
||||
|
||||
static void storage_work_handler(struct os_event *work)
|
||||
{
|
||||
switch (storage_id) {
|
||||
case RESET_COUNTER:
|
||||
save_reset_counter();
|
||||
break;
|
||||
case GEN_DEF_TRANS_TIME_STATE:
|
||||
save_gen_def_trans_time_state();
|
||||
break;
|
||||
case GEN_ONPOWERUP_STATE:
|
||||
save_gen_onpowerup_state();
|
||||
break;
|
||||
case LIGHTNESS_TEMP_DEF_STATE:
|
||||
save_lightness_temp_def_state();
|
||||
break;
|
||||
case LIGHTNESS_TEMP_LAST_STATE:
|
||||
save_lightness_temp_last_state();
|
||||
break;
|
||||
case LIGHTNESS_RANGE:
|
||||
save_lightness_range();
|
||||
break;
|
||||
case TEMPERATURE_RANGE:
|
||||
save_temperature_range();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct os_callout storage_work;
|
||||
|
||||
void save_on_flash(u8_t id)
|
||||
{
|
||||
storage_id = id;
|
||||
os_callout_reset(&storage_work, 0);
|
||||
}
|
||||
|
||||
static int ps_set(int argc, char **argv, char *val)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (argc == 1) {
|
||||
if (!strcmp(argv[0], "rc")) {
|
||||
len = sizeof(reset_counter);
|
||||
|
||||
return settings_bytes_from_str(val, &reset_counter,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "gdtt")) {
|
||||
len = sizeof(gen_def_trans_time_srv_user_data.tt);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&gen_def_trans_time_srv_user_data.tt, &len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "gpo")) {
|
||||
len = sizeof(gen_power_onoff_srv_user_data.onpowerup);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&gen_power_onoff_srv_user_data.onpowerup, &len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "ltd")) {
|
||||
len = sizeof(light_ctl_srv_user_data.lightness_temp_def);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_ctl_srv_user_data.lightness_temp_def,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "ltl")) {
|
||||
len = sizeof(light_ctl_srv_user_data.
|
||||
lightness_temp_last);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_ctl_srv_user_data.lightness_temp_last,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "lr")) {
|
||||
len = sizeof(light_lightness_srv_user_data.
|
||||
lightness_range);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_lightness_srv_user_data.lightness_range,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "tr")) {
|
||||
len = sizeof(light_ctl_srv_user_data.
|
||||
temperature_range);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_ctl_srv_user_data. temperature_range,
|
||||
&len);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static struct conf_handler ps_settings = {
|
||||
.ch_name = "ps",
|
||||
.ch_set = ps_set,
|
||||
};
|
||||
|
||||
int ps_settings_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
os_callout_init(&storage_work, os_eventq_dflt_get(),
|
||||
storage_work_handler, NULL);
|
||||
|
||||
err = conf_register(&ps_settings);
|
||||
if (err) {
|
||||
printk("ps_settings_register failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _STORAGE_H
|
||||
#define _STORAGE_H
|
||||
|
||||
enum ps_variables_id {
|
||||
RESET_COUNTER = 0x01,
|
||||
GEN_DEF_TRANS_TIME_STATE,
|
||||
GEN_ONPOWERUP_STATE,
|
||||
LIGHTNESS_TEMP_DEF_STATE,
|
||||
LIGHTNESS_TEMP_LAST_STATE,
|
||||
LIGHTNESS_RANGE,
|
||||
TEMPERATURE_RANGE
|
||||
};
|
||||
|
||||
extern u8_t reset_counter;
|
||||
|
||||
extern struct os_callout storage_work;
|
||||
|
||||
int ps_settings_init(void);
|
||||
void save_on_flash(u8_t id);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,792 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "ble_mesh.h"
|
||||
#include "common.h"
|
||||
#include "device_composition.h"
|
||||
#include "state_binding.h"
|
||||
#include "transition.h"
|
||||
|
||||
struct os_callout onoff_work;
|
||||
struct os_callout level_lightness_work;
|
||||
struct os_callout level_temp_work;
|
||||
struct os_callout light_lightness_actual_work;
|
||||
struct os_callout light_lightness_linear_work;
|
||||
struct os_callout light_ctl_work;
|
||||
struct os_callout light_ctl_temp_work;
|
||||
|
||||
struct os_callout dummy_timer;
|
||||
|
||||
u8_t transition_type, default_tt;
|
||||
u32_t *ptr_counter;
|
||||
struct os_callout *ptr_timer = &dummy_timer;
|
||||
|
||||
struct transition lightness_transition, temp_transition;
|
||||
|
||||
/* Function to calculate Remaining Time (Start) */
|
||||
|
||||
void calculate_rt(struct transition *transition)
|
||||
{
|
||||
u8_t steps, resolution;
|
||||
s32_t duration_remainder;
|
||||
s64_t now;
|
||||
|
||||
if (transition->just_started) {
|
||||
transition->rt = transition->tt;
|
||||
} else {
|
||||
now = k_uptime_get();
|
||||
duration_remainder = transition->total_duration -
|
||||
(now - transition->start_timestamp);
|
||||
|
||||
if (duration_remainder > 620000) {
|
||||
/* > 620 seconds -> resolution = 0b11 [10 minutes] */
|
||||
resolution = 0x03;
|
||||
steps = duration_remainder / 600000;
|
||||
} else if (duration_remainder > 62000) {
|
||||
/* > 62 seconds -> resolution = 0b10 [10 seconds] */
|
||||
resolution = 0x02;
|
||||
steps = duration_remainder / 10000;
|
||||
} else if (duration_remainder > 6200) {
|
||||
/* > 6.2 seconds -> resolution = 0b01 [1 seconds] */
|
||||
resolution = 0x01;
|
||||
steps = duration_remainder / 1000;
|
||||
} else if (duration_remainder > 0) {
|
||||
/* <= 6.2 seconds -> resolution = 0b00 [100 ms] */
|
||||
resolution = 0x00;
|
||||
steps = duration_remainder / 100;
|
||||
} else {
|
||||
resolution = 0x00;
|
||||
steps = 0x00;
|
||||
}
|
||||
|
||||
transition->rt = (resolution << 6) | steps;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to calculate Remaining Time (End) */
|
||||
|
||||
static void bound_states_transition_type_reassignment(u8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case ONOFF:
|
||||
case LEVEL:
|
||||
case ACTUAL:
|
||||
case LINEAR:
|
||||
light_ctl_srv_user_data.transition = &lightness_transition;
|
||||
break;
|
||||
case CTL:
|
||||
light_ctl_srv_user_data.transition = &lightness_transition;
|
||||
gen_level_srv_s0_user_data.transition = &lightness_transition;
|
||||
break;
|
||||
case LEVEL_TEMP:
|
||||
case CTL_TEMP:
|
||||
gen_level_srv_s0_user_data.transition = &temp_transition;
|
||||
light_ctl_srv_user_data.transition = &temp_transition;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tt_values_calculator(struct transition *transition)
|
||||
{
|
||||
u8_t steps_multiplier, resolution;
|
||||
|
||||
resolution = (transition->tt >> 6);
|
||||
steps_multiplier = (transition->tt & 0x3F);
|
||||
|
||||
switch (resolution) {
|
||||
case 0: /* 100ms */
|
||||
transition->total_duration = steps_multiplier * 100;
|
||||
break;
|
||||
case 1: /* 1 second */
|
||||
transition->total_duration = steps_multiplier * 1000;
|
||||
break;
|
||||
case 2: /* 10 seconds */
|
||||
transition->total_duration = steps_multiplier * 10000;
|
||||
break;
|
||||
case 3: /* 10 minutes */
|
||||
transition->total_duration = steps_multiplier * 600000;
|
||||
break;
|
||||
}
|
||||
|
||||
transition->counter = ((float) transition->total_duration / 100);
|
||||
|
||||
if (transition->counter > DEVICE_SPECIFIC_RESOLUTION) {
|
||||
transition->counter = DEVICE_SPECIFIC_RESOLUTION;
|
||||
}
|
||||
|
||||
ptr_counter = &transition->counter;
|
||||
}
|
||||
|
||||
void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay)
|
||||
{
|
||||
bound_states_transition_type_reassignment(ONOFF);
|
||||
calculate_lightness_target_values(ONOFF);
|
||||
state->transition->tt = tt;
|
||||
state->transition->delay = delay;
|
||||
|
||||
if (tt != 0) {
|
||||
tt_values_calculator(state->transition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
state->transition->quo_tt = state->transition->total_duration /
|
||||
state->transition->counter;
|
||||
|
||||
state->tt_delta = ((float) (lightness - target_lightness) /
|
||||
state->transition->counter);
|
||||
}
|
||||
|
||||
void level_tt_values(struct generic_level_state *state, u8_t tt, u8_t delay)
|
||||
{
|
||||
if (state == &gen_level_srv_root_user_data) {
|
||||
bound_states_transition_type_reassignment(LEVEL);
|
||||
calculate_lightness_target_values(LEVEL);
|
||||
} else if (state == &gen_level_srv_s0_user_data) {
|
||||
bound_states_transition_type_reassignment(LEVEL_TEMP);
|
||||
calculate_temp_target_values(LEVEL_TEMP);
|
||||
}
|
||||
state->transition->tt = tt;
|
||||
state->transition->delay = delay;
|
||||
|
||||
if (tt != 0) {
|
||||
tt_values_calculator(state->transition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
state->transition->quo_tt = state->transition->total_duration /
|
||||
state->transition->counter;
|
||||
|
||||
state->tt_delta = ((float) (state->level - state->target_level) /
|
||||
state->transition->counter);
|
||||
}
|
||||
|
||||
void light_lightness_actual_tt_values(struct light_lightness_state *state,
|
||||
u8_t tt, u8_t delay)
|
||||
{
|
||||
bound_states_transition_type_reassignment(ACTUAL);
|
||||
calculate_lightness_target_values(ACTUAL);
|
||||
state->transition->tt = tt;
|
||||
state->transition->delay = delay;
|
||||
|
||||
if (tt != 0) {
|
||||
tt_values_calculator(state->transition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
state->transition->quo_tt = state->transition->total_duration /
|
||||
state->transition->counter;
|
||||
|
||||
state->tt_delta_actual =
|
||||
((float) (state->actual - state->target_actual) /
|
||||
state->transition->counter);
|
||||
}
|
||||
|
||||
void light_lightness_linear_tt_values(struct light_lightness_state *state,
|
||||
u8_t tt, u8_t delay)
|
||||
{
|
||||
bound_states_transition_type_reassignment(LINEAR);
|
||||
calculate_lightness_target_values(LINEAR);
|
||||
state->transition->tt = tt;
|
||||
state->transition->delay = delay;
|
||||
|
||||
if (tt != 0) {
|
||||
tt_values_calculator(state->transition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
state->transition->quo_tt = state->transition->total_duration /
|
||||
state->transition->counter;
|
||||
|
||||
state->tt_delta_linear =
|
||||
((float) (state->linear - state->target_linear) /
|
||||
state->transition->counter);
|
||||
}
|
||||
|
||||
void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay)
|
||||
{
|
||||
bound_states_transition_type_reassignment(CTL);
|
||||
calculate_lightness_target_values(CTL);
|
||||
state->transition->tt = tt;
|
||||
state->transition->delay = delay;
|
||||
|
||||
if (tt != 0) {
|
||||
tt_values_calculator(state->transition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
state->transition->quo_tt = state->transition->total_duration /
|
||||
state->transition->counter;
|
||||
|
||||
state->tt_delta_lightness =
|
||||
((float) (state->lightness - state->target_lightness) /
|
||||
state->transition->counter);
|
||||
|
||||
state->tt_delta_temp =
|
||||
((float) (state->temp - state->target_temp) /
|
||||
state->transition->counter);
|
||||
|
||||
state->tt_delta_duv =
|
||||
((float) (state->delta_uv - state->target_delta_uv) /
|
||||
state->transition->counter);
|
||||
}
|
||||
|
||||
void light_ctl_temp_tt_values(struct light_ctl_state *state,
|
||||
u8_t tt, u8_t delay)
|
||||
{
|
||||
bound_states_transition_type_reassignment(CTL_TEMP);
|
||||
calculate_temp_target_values(CTL_TEMP);
|
||||
state->transition->tt = tt;
|
||||
state->transition->delay = delay;
|
||||
|
||||
if (tt != 0) {
|
||||
tt_values_calculator(state->transition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
state->transition->quo_tt = state->transition->total_duration /
|
||||
state->transition->counter;
|
||||
|
||||
state->tt_delta_temp = ((float) (state->temp - state->target_temp) /
|
||||
state->transition->counter);
|
||||
|
||||
state->tt_delta_duv =
|
||||
((float) (state->delta_uv - state->target_delta_uv) /
|
||||
state->transition->counter);
|
||||
}
|
||||
|
||||
/* Timers related handlers & threads (Start) */
|
||||
static void onoff_work_handler(struct os_event *work)
|
||||
{
|
||||
struct generic_onoff_state *state = &gen_onoff_srv_root_user_data;
|
||||
|
||||
if (state->transition->just_started) {
|
||||
state->transition->just_started = false;
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state_binding(ONOFF, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
|
||||
if (state->target_onoff == STATE_ON) {
|
||||
state->onoff = STATE_ON;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->counter != 0) {
|
||||
state->transition->counter--;
|
||||
|
||||
lightness -= state->tt_delta;
|
||||
|
||||
state_binding(IGNORE, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
}
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state->onoff = state->target_onoff;
|
||||
lightness = target_lightness;
|
||||
|
||||
state_binding(IGNORE, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void level_lightness_work_handler(struct os_event *work)
|
||||
{
|
||||
u8_t level;
|
||||
struct generic_level_state *state = &gen_level_srv_root_user_data;
|
||||
|
||||
switch (transition_type) {
|
||||
case LEVEL_TT:
|
||||
level = LEVEL;
|
||||
break;
|
||||
case LEVEL_TT_DELTA:
|
||||
level = DELTA_LEVEL;
|
||||
break;
|
||||
case LEVEL_TT_MOVE:
|
||||
level = LEVEL;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->just_started) {
|
||||
state->transition->just_started = false;
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state_binding(level, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->counter != 0) {
|
||||
state->transition->counter--;
|
||||
|
||||
state->level -= state->tt_delta;
|
||||
|
||||
state_binding(level, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
}
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state->level = state->target_level;
|
||||
|
||||
state_binding(level, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void level_temp_work_handler(struct os_event *work)
|
||||
{
|
||||
struct generic_level_state *state = &gen_level_srv_s0_user_data;
|
||||
|
||||
switch (transition_type) {
|
||||
case LEVEL_TEMP_TT:
|
||||
break;
|
||||
case LEVEL_TEMP_TT_DELTA:
|
||||
break;
|
||||
case LEVEL_TEMP_TT_MOVE:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->just_started) {
|
||||
state->transition->just_started = false;
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state_binding(IGNORE, LEVEL_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->counter != 0) {
|
||||
state->transition->counter--;
|
||||
|
||||
state->level -= state->tt_delta;
|
||||
|
||||
state_binding(IGNORE, LEVEL_TEMP);
|
||||
update_light_state();
|
||||
}
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state->level = state->target_level;
|
||||
|
||||
state_binding(IGNORE, LEVEL_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_lightness_actual_work_handler(struct os_event *work)
|
||||
{
|
||||
struct light_lightness_state *state = &light_lightness_srv_user_data;
|
||||
|
||||
if (state->transition->just_started) {
|
||||
state->transition->just_started = false;
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state_binding(ACTUAL, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->counter != 0) {
|
||||
state->transition->counter--;
|
||||
|
||||
state->actual -= state->tt_delta_actual;
|
||||
|
||||
state_binding(ACTUAL, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
}
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state->actual = state->target_actual;
|
||||
|
||||
state_binding(ACTUAL, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_lightness_linear_work_handler(struct os_event *work)
|
||||
{
|
||||
struct light_lightness_state *state = &light_lightness_srv_user_data;
|
||||
|
||||
if (state->transition->just_started) {
|
||||
state->transition->just_started = false;
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state_binding(LINEAR, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->counter != 0) {
|
||||
state->transition->counter--;
|
||||
|
||||
state->linear -= state->tt_delta_linear;
|
||||
|
||||
state_binding(LINEAR, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
}
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state->linear = state->target_linear;
|
||||
|
||||
state_binding(LINEAR, IGNORE_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_ctl_work_handler(struct os_event *work)
|
||||
{
|
||||
struct light_ctl_state *state = &light_ctl_srv_user_data;
|
||||
|
||||
if (state->transition->just_started) {
|
||||
state->transition->just_started = false;
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state_binding(CTL, CTL_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->counter != 0) {
|
||||
state->transition->counter--;
|
||||
|
||||
/* Lightness */
|
||||
state->lightness -= state->tt_delta_lightness;
|
||||
|
||||
/* Temperature */
|
||||
state->temp -= state->tt_delta_temp;
|
||||
|
||||
/* Delta_UV */
|
||||
state->delta_uv -= state->tt_delta_duv;
|
||||
|
||||
state_binding(CTL, CTL_TEMP);
|
||||
update_light_state();
|
||||
}
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state->lightness = state->target_lightness;
|
||||
state->temp = state->target_temp;
|
||||
state->delta_uv = state->target_delta_uv;
|
||||
|
||||
state_binding(CTL, CTL_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_ctl_temp_work_handler(struct os_event *work)
|
||||
{
|
||||
struct light_ctl_state *state = &light_ctl_srv_user_data;
|
||||
|
||||
if (state->transition->just_started) {
|
||||
state->transition->just_started = false;
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state_binding(IGNORE, CTL_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->transition->counter != 0) {
|
||||
state->transition->counter--;
|
||||
|
||||
/* Temperature */
|
||||
state->temp -= state->tt_delta_temp;
|
||||
|
||||
/* Delta UV */
|
||||
state->delta_uv -= state->tt_delta_duv;
|
||||
|
||||
state_binding(IGNORE, CTL_TEMP);
|
||||
update_light_state();
|
||||
}
|
||||
|
||||
if (state->transition->counter == 0) {
|
||||
state->temp = state->target_temp;
|
||||
state->delta_uv = state->target_delta_uv;
|
||||
|
||||
state_binding(IGNORE, CTL_TEMP);
|
||||
update_light_state();
|
||||
|
||||
os_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void dummy_timer_handler(struct os_event *ev)
|
||||
{ }
|
||||
|
||||
static void onoff_tt_handler(struct os_event *ev)
|
||||
{
|
||||
struct generic_onoff_state *state = ev->ev_arg;
|
||||
|
||||
assert(state != NULL);
|
||||
os_callout_reset(&onoff_work, 0);
|
||||
os_callout_reset(&state->transition->timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void level_lightness_tt_handler(struct os_event *ev)
|
||||
{
|
||||
struct generic_level_state *state = ev->ev_arg;
|
||||
|
||||
assert(state != NULL);
|
||||
os_callout_reset(&level_lightness_work, 0);
|
||||
os_callout_reset(&state->transition->timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void level_temp_tt_handler(struct os_event *ev)
|
||||
{
|
||||
struct generic_level_state *state = ev->ev_arg;
|
||||
|
||||
assert(state != NULL);
|
||||
os_callout_reset(&level_temp_work, 0);
|
||||
os_callout_reset(&state->transition->timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_lightness_actual_tt_handler(struct os_event *ev)
|
||||
{
|
||||
struct light_lightness_state *state = ev->ev_arg;
|
||||
|
||||
assert(state != NULL);
|
||||
os_callout_reset(&light_lightness_actual_work, 0);
|
||||
os_callout_reset(&state->transition->timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_lightness_linear_tt_handler(struct os_event *ev)
|
||||
{
|
||||
struct light_lightness_state *state = ev->ev_arg;
|
||||
|
||||
assert(state != NULL);
|
||||
os_callout_reset(&light_lightness_linear_work, 0);
|
||||
os_callout_reset(&state->transition->timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_ctl_tt_handler(struct os_event *ev)
|
||||
{
|
||||
struct light_ctl_state *state = ev->ev_arg;
|
||||
|
||||
assert(state != NULL);
|
||||
os_callout_reset(&light_ctl_work, 0);
|
||||
os_callout_reset(&state->transition->timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_ctl_temp_tt_handler(struct os_event *ev)
|
||||
{
|
||||
struct light_ctl_state *state = ev->ev_arg;
|
||||
|
||||
assert(state != NULL);
|
||||
os_callout_reset(&light_ctl_temp_work, 0);
|
||||
os_callout_reset(&state->transition->timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
/* Timers related handlers & threads (End) */
|
||||
|
||||
/* Messages handlers (Start) */
|
||||
void onoff_handler(struct generic_onoff_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
os_callout_init(ptr_timer, os_eventq_dflt_get(),
|
||||
onoff_tt_handler, NULL);
|
||||
ptr_timer->c_ev.ev_arg = state;
|
||||
os_callout_reset(ptr_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void level_lightness_handler(struct generic_level_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
os_callout_init(ptr_timer, os_eventq_dflt_get(),
|
||||
level_lightness_tt_handler, NULL);
|
||||
ptr_timer->c_ev.ev_arg = state;
|
||||
os_callout_reset(ptr_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void level_temp_handler(struct generic_level_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
os_callout_init(ptr_timer, os_eventq_dflt_get(),
|
||||
level_temp_tt_handler, NULL);
|
||||
ptr_timer->c_ev.ev_arg = state;
|
||||
os_callout_reset(ptr_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_lightness_actual_handler(struct light_lightness_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
os_callout_init(ptr_timer, os_eventq_dflt_get(),
|
||||
light_lightness_actual_tt_handler, NULL);
|
||||
ptr_timer->c_ev.ev_arg = state;
|
||||
os_callout_reset(ptr_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_lightness_linear_handler(struct light_lightness_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
os_callout_init(ptr_timer, os_eventq_dflt_get(),
|
||||
light_lightness_linear_tt_handler, NULL);
|
||||
ptr_timer->c_ev.ev_arg = state;
|
||||
os_callout_reset(ptr_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_ctl_handler(struct light_ctl_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
os_callout_init(ptr_timer, os_eventq_dflt_get(),
|
||||
light_ctl_tt_handler, NULL);
|
||||
ptr_timer->c_ev.ev_arg = state;
|
||||
os_callout_reset(ptr_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_ctl_temp_handler(struct light_ctl_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
os_callout_init(ptr_timer, os_eventq_dflt_get(),
|
||||
light_ctl_temp_tt_handler, NULL);
|
||||
ptr_timer->c_ev.ev_arg = state;
|
||||
os_callout_reset(ptr_timer,
|
||||
os_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
/* Messages handlers (End) */
|
||||
|
||||
void transition_timers_init(void)
|
||||
{
|
||||
os_callout_init(&onoff_work, os_eventq_dflt_get(),
|
||||
onoff_work_handler, NULL);
|
||||
|
||||
os_callout_init(&level_lightness_work, os_eventq_dflt_get(),
|
||||
level_lightness_work_handler, NULL);
|
||||
os_callout_init(&level_temp_work, os_eventq_dflt_get(),
|
||||
level_temp_work_handler, NULL);
|
||||
|
||||
os_callout_init(&light_lightness_actual_work,
|
||||
os_eventq_dflt_get(),
|
||||
light_lightness_actual_work_handler, NULL);
|
||||
os_callout_init(&light_lightness_linear_work,
|
||||
os_eventq_dflt_get(),
|
||||
light_lightness_linear_work_handler, NULL);
|
||||
|
||||
os_callout_init(&light_ctl_work, os_eventq_dflt_get(),
|
||||
light_ctl_work_handler, NULL);
|
||||
os_callout_init(&light_ctl_temp_work, os_eventq_dflt_get(),
|
||||
light_ctl_temp_work_handler, NULL);
|
||||
|
||||
os_callout_init(&dummy_timer, os_eventq_dflt_get(),
|
||||
dummy_timer_handler, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
*
|
||||
* Copyright (c) 2018 Vikrant More
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _TRANSITION_H
|
||||
#define _TRANSITION_H
|
||||
|
||||
#define UNKNOWN_VALUE 0x3F
|
||||
#define DEVICE_SPECIFIC_RESOLUTION 10
|
||||
|
||||
enum level_transition_types {
|
||||
LEVEL_TT,
|
||||
LEVEL_TT_DELTA,
|
||||
LEVEL_TT_MOVE,
|
||||
|
||||
LEVEL_TEMP_TT,
|
||||
LEVEL_TEMP_TT_DELTA,
|
||||
LEVEL_TEMP_TT_MOVE,
|
||||
};
|
||||
|
||||
struct transition {
|
||||
bool just_started;
|
||||
u8_t tt;
|
||||
u8_t rt;
|
||||
u8_t delay;
|
||||
u32_t quo_tt;
|
||||
u32_t counter;
|
||||
u32_t total_duration;
|
||||
s64_t start_timestamp;
|
||||
|
||||
struct os_callout timer;
|
||||
};
|
||||
|
||||
extern u8_t transition_type, default_tt;
|
||||
extern u32_t *ptr_counter;
|
||||
extern struct os_callout *ptr_timer;
|
||||
|
||||
extern struct transition lightness_transition, temp_transition;
|
||||
|
||||
extern struct os_callout dummy_timer;
|
||||
|
||||
void calculate_rt(struct transition *transition);
|
||||
|
||||
|
||||
void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay);
|
||||
void level_tt_values(struct generic_level_state *state, u8_t tt, u8_t delay);
|
||||
void light_lightness_actual_tt_values(struct light_lightness_state *state,
|
||||
u8_t tt, u8_t delay);
|
||||
void light_lightness_linear_tt_values(struct light_lightness_state *state,
|
||||
u8_t tt, u8_t delay);
|
||||
void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay);
|
||||
void light_ctl_temp_tt_values(struct light_ctl_state *state,
|
||||
u8_t tt, u8_t delay);
|
||||
|
||||
void onoff_handler(struct generic_onoff_state *state);
|
||||
void level_lightness_handler(struct generic_level_state *state);
|
||||
void level_temp_handler(struct generic_level_state *state);
|
||||
void light_lightness_actual_handler(struct light_lightness_state *state);
|
||||
void light_lightness_linear_handler(struct light_lightness_state *state);
|
||||
void light_ctl_handler(struct light_ctl_state *state);
|
||||
void light_ctl_temp_handler(struct light_ctl_state *state);
|
||||
|
||||
void transition_timers_init(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
# 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.vals:
|
||||
# Set log level to info (disable debug logging).
|
||||
LOG_LEVEL: 1
|
||||
|
||||
# Default task settings
|
||||
OS_MAIN_STACK_SIZE: 4096
|
||||
|
||||
# SMP is not supported in this app, so disable smp-over-shell.
|
||||
SHELL_MGMT: 0
|
||||
|
||||
MSYS_1_BLOCK_COUNT: 48
|
||||
|
||||
FLOAT_USER: 1
|
||||
HARD_FLOAT: 1
|
||||
|
||||
BLE_MESH_DEV_UUID: "((uint8_t[16]){0xdd, 0xdd, 0})"
|
||||
BLE_MESH_ADV_BUF_COUNT: 60
|
||||
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_MSG_CACHE_SIZE: 100
|
||||
|
||||
BLE_MESH_SETTINGS: 1
|
||||
CONFIG_FCB: 1
|
||||
|
||||
BLE_MESH: 1
|
||||
BLE_MESH_RELAY: 1
|
||||
BLE_MESH_LOW_POWER: 0
|
||||
BLE_MESH_LPN_AUTO: 0
|
||||
BLE_MESH_FRIEND: 0
|
||||
|
||||
BLE_MESH_PROV: 1
|
||||
BLE_MESH_PB_ADV: 1
|
||||
BLE_MESH_PB_GATT: 1
|
||||
BLE_MESH_GATT_PROXY: 1
|
||||
|
||||
BLE_MESH_SUBNET_COUNT: 2
|
||||
BLE_MESH_APP_KEY_COUNT: 2
|
||||
BLE_MESH_MODEL_GROUP_COUNT: 2
|
||||
BLE_MESH_LABEL_COUNT: 3
|
||||
37
src/libs/mynewt-nimble/apps/blemesh_shell/pkg.yml
Normal file
37
src/libs/mynewt-nimble/apps/blemesh_shell/pkg.yml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# 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/blemesh_shell
|
||||
pkg.type: app
|
||||
pkg.description: Sample application for BLE Mesh node with shell support
|
||||
pkg.author: "Michał Narajowski <michal.narajowski@codecoup.pl>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@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/ram
|
||||
- nimble/transport/ram
|
||||
114
src/libs/mynewt-nimble/apps/blemesh_shell/src/main.c
Normal file
114
src/libs/mynewt-nimble/apps/blemesh_shell/src/main.c
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define MESH_LOG_MODULE BLE_MESH_LOG
|
||||
|
||||
#include <assert.h>
|
||||
#include "os/mynewt.h"
|
||||
#include "mesh/mesh.h"
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_system.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "shell/shell.h"
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "mesh/glue.h"
|
||||
#include "mesh/testing.h"
|
||||
|
||||
|
||||
void net_recv_ev(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst,
|
||||
const void *payload, size_t payload_len)
|
||||
{
|
||||
console_printf("Received net packet: ttl 0x%02x ctl 0x%02x src 0x%04x "
|
||||
"dst 0x%04x " "payload_len %d\n", ttl, ctl, src, dst,
|
||||
payload_len);
|
||||
}
|
||||
|
||||
static void model_bound_cb(u16_t addr, struct bt_mesh_model *model,
|
||||
u16_t key_idx)
|
||||
{
|
||||
console_printf("Model bound: remote addr 0x%04x key_idx 0x%04x model %p\n",
|
||||
addr, key_idx, model);
|
||||
}
|
||||
|
||||
static void model_unbound_cb(u16_t addr, struct bt_mesh_model *model,
|
||||
u16_t key_idx)
|
||||
{
|
||||
console_printf("Model unbound: remote addr 0x%04x key_idx 0x%04x "
|
||||
"model %p\n", addr, key_idx, model);
|
||||
}
|
||||
|
||||
static void invalid_bearer_cb(u8_t opcode)
|
||||
{
|
||||
console_printf("Invalid bearer: opcode 0x%02x\n", opcode);
|
||||
}
|
||||
|
||||
static void incomp_timer_exp_cb(void)
|
||||
{
|
||||
console_printf("Incomplete timer expired\n");
|
||||
}
|
||||
|
||||
static struct bt_test_cb bt_test_cb = {
|
||||
.mesh_net_recv = net_recv_ev,
|
||||
.mesh_model_bound = model_bound_cb,
|
||||
.mesh_model_unbound = model_unbound_cb,
|
||||
.mesh_prov_invalid_bearer = invalid_bearer_cb,
|
||||
.mesh_trans_incomp_timer_exp = incomp_timer_exp_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
blemesh_on_sync(void)
|
||||
{
|
||||
console_printf("Bluetooth initialized\n");
|
||||
|
||||
shell_register_default_module("mesh");
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_TESTING)) {
|
||||
bt_test_cb_register(&bt_test_cb);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = blemesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = blemesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
hal_gpio_init_out(LED_2, 0);
|
||||
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
57
src/libs/mynewt-nimble/apps/blemesh_shell/syscfg.yml
Normal file
57
src/libs/mynewt-nimble/apps/blemesh_shell/syscfg.yml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# 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.vals:
|
||||
# Enable the shell task.
|
||||
SHELL_TASK: 1
|
||||
|
||||
# Set log level to info (disable debug logging).
|
||||
LOG_LEVEL: 0
|
||||
|
||||
# Default task settings
|
||||
OS_MAIN_STACK_SIZE: 768
|
||||
|
||||
# SMP is not supported in this app, so disable smp-over-shell.
|
||||
SHELL_MGMT: 0
|
||||
|
||||
MSYS_1_BLOCK_COUNT: 80
|
||||
|
||||
BLE_MESH_ADV_BUF_COUNT: 20
|
||||
BLE_MESH_TX_SEG_MAX: 6
|
||||
|
||||
BLE_MESH: 1
|
||||
BLE_MESH_SHELL: 1
|
||||
BLE_MESH_PROV: 1
|
||||
BLE_MESH_PROVISIONER: 1
|
||||
BLE_MESH_RELAY: 1
|
||||
BLE_MESH_PB_ADV: 1
|
||||
BLE_MESH_PB_GATT: 1
|
||||
BLE_MESH_LOW_POWER: 1
|
||||
BLE_MESH_LPN_AUTO: 0
|
||||
BLE_MESH_GATT_PROXY: 1
|
||||
BLE_MESH_LABEL_COUNT: 2
|
||||
BLE_MESH_SUBNET_COUNT: 2
|
||||
BLE_MESH_MODEL_GROUP_COUNT: 2
|
||||
BLE_MESH_MODEL_EXTENSIONS: 1
|
||||
BLE_MESH_APP_KEY_COUNT: 4
|
||||
BLE_MESH_IV_UPDATE_TEST: 1
|
||||
BLE_MESH_TESTING: 1
|
||||
BLE_MESH_FRIEND: 1
|
||||
BLE_MESH_CFG_CLI: 1
|
||||
BLE_MESH_SETTINGS: 0
|
||||
CONFIG_NFFS: 0
|
||||
45
src/libs/mynewt-nimble/apps/bleprph/pkg.yml
Normal file
45
src/libs/mynewt-nimble/apps/bleprph/pkg.yml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# 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/bleprph
|
||||
pkg.type: app
|
||||
pkg.description: Simple BLE peripheral application.
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@apache-mynewt-core/boot/split"
|
||||
- "@mcuboot/boot/bootutil"
|
||||
- "@apache-mynewt-core/kernel/os"
|
||||
- "@apache-mynewt-core/mgmt/imgmgr"
|
||||
- "@apache-mynewt-core/mgmt/smp"
|
||||
- "@apache-mynewt-core/mgmt/smp/transport/ble"
|
||||
- "@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/sysinit"
|
||||
- "@apache-mynewt-core/sys/id"
|
||||
- nimble/host
|
||||
- nimble/host/services/ans
|
||||
- nimble/host/services/dis
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/host/store/config
|
||||
- nimble/host/util
|
||||
- nimble/transport
|
||||
61
src/libs/mynewt-nimble/apps/bleprph/src/bleprph.h
Normal file
61
src/libs/mynewt-nimble/apps/bleprph/src/bleprph.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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_BLEPRPH_
|
||||
#define H_BLEPRPH_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ble_hs_cfg;
|
||||
struct ble_gatt_register_ctxt;
|
||||
|
||||
/** GATT server. */
|
||||
#define GATT_SVR_SVC_ALERT_UUID 0x1811
|
||||
#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47
|
||||
#define GATT_SVR_CHR_NEW_ALERT 0x2A46
|
||||
#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48
|
||||
#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID 0x2A45
|
||||
#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT 0x2A44
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
/* PHY support */
|
||||
#if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
|
||||
#define CONN_HANDLE_INVALID 0xffff
|
||||
|
||||
void phy_init(void);
|
||||
void phy_conn_changed(uint16_t handle);
|
||||
void phy_update(uint8_t phy);
|
||||
#endif
|
||||
|
||||
/** Misc. */
|
||||
void print_bytes(const uint8_t *bytes, int len);
|
||||
void print_addr(const void *addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
204
src/libs/mynewt-nimble/apps/bleprph/src/gatt_svr.c
Normal file
204
src/libs/mynewt-nimble/apps/bleprph/src/gatt_svr.c
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* 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 "bsp/bsp.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "bleprph.h"
|
||||
|
||||
/**
|
||||
* The vendor specific security test service consists of two characteristics:
|
||||
* o random-number-generator: generates a random 32-bit number each time
|
||||
* it is read. This characteristic can only be read over an encrypted
|
||||
* connection.
|
||||
* o static-value: a single-byte characteristic that can always be read,
|
||||
* but can only be written over an encrypted connection.
|
||||
*/
|
||||
|
||||
/* 59462f12-9543-9999-12c8-58b459a2712d */
|
||||
static const ble_uuid128_t gatt_svr_svc_sec_test_uuid =
|
||||
BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
|
||||
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
|
||||
|
||||
/* 5c3a659e-897e-45e1-b016-007107c96df6 */
|
||||
static const ble_uuid128_t gatt_svr_chr_sec_test_rand_uuid =
|
||||
BLE_UUID128_INIT(0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
|
||||
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
|
||||
|
||||
/* 5c3a659e-897e-45e1-b016-007107c96df7 */
|
||||
static const ble_uuid128_t gatt_svr_chr_sec_test_static_uuid =
|
||||
BLE_UUID128_INIT(0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
|
||||
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
|
||||
|
||||
static uint8_t gatt_svr_sec_test_static_val;
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sec_test(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[] = {
|
||||
{
|
||||
/*** Service: Security test. */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &gatt_svr_svc_sec_test_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/*** Characteristic: Random number generator. */
|
||||
.uuid = &gatt_svr_chr_sec_test_rand_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_sec_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
|
||||
}, {
|
||||
/*** Characteristic: Static value. */
|
||||
.uuid = &gatt_svr_chr_sec_test_static_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_sec_test,
|
||||
.flags = BLE_GATT_CHR_F_READ |
|
||||
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
} },
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
|
||||
void *dst, uint16_t *len)
|
||||
{
|
||||
uint16_t om_len;
|
||||
int rc;
|
||||
|
||||
om_len = OS_MBUF_PKTLEN(om);
|
||||
if (om_len < min_len || om_len > max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rand_num;
|
||||
int rc;
|
||||
|
||||
uuid = ctxt->chr->uuid;
|
||||
|
||||
/* Determine which characteristic is being accessed by examining its
|
||||
* 128-bit UUID.
|
||||
*/
|
||||
|
||||
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) {
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
|
||||
/* Respond with a 32-bit random number. */
|
||||
rand_num = rand();
|
||||
rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0) {
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val,
|
||||
sizeof gatt_svr_sec_test_static_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
rc = gatt_svr_chr_write(ctxt->om,
|
||||
sizeof gatt_svr_sec_test_static_val,
|
||||
sizeof gatt_svr_sec_test_static_val,
|
||||
&gatt_svr_sec_test_static_val, NULL);
|
||||
return rc;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
359
src/libs/mynewt-nimble/apps/bleprph/src/main.c
Normal file
359
src/libs/mynewt-nimble/apps/bleprph/src/main.c
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "os/mynewt.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "console/console.h"
|
||||
#include "hal/hal_system.h"
|
||||
#include "config/config.h"
|
||||
#include "split/split.h"
|
||||
#if MYNEWT_VAL(BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM) >= 0
|
||||
#include "bootutil/image.h"
|
||||
#include "imgmgr/imgmgr.h"
|
||||
#include "services/dis/ble_svc_dis.h"
|
||||
#endif
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
/* Application-specified header. */
|
||||
#include "bleprph.h"
|
||||
|
||||
static int bleprph_gap_event(struct ble_gap_event *event, void *arg);
|
||||
|
||||
/**
|
||||
* Logs information about a connection to the console.
|
||||
*/
|
||||
static void
|
||||
bleprph_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables advertising with the following parameters:
|
||||
* o General discoverable mode.
|
||||
* o Undirected connectable mode.
|
||||
*/
|
||||
static void
|
||||
bleprph_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;
|
||||
|
||||
/* 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;
|
||||
|
||||
name = ble_svc_gap_device_name();
|
||||
fields.name = (uint8_t *)name;
|
||||
fields.name_len = strlen(name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
fields.uuids16 = (ble_uuid16_t[]){
|
||||
BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
|
||||
};
|
||||
fields.num_uuids16 = 1;
|
||||
fields.uuids16_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, bleprph_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The nimble host executes this callback when a GAP event occurs. The
|
||||
* application associates a GAP event callback with each connection that forms.
|
||||
* bleprph uses the same callback for all connections.
|
||||
*
|
||||
* @param event The type of event being signalled.
|
||||
* @param ctxt Various information pertaining to the event.
|
||||
* @param arg Application-specified argument; unuesd by
|
||||
* bleprph.
|
||||
*
|
||||
* @return 0 if the application successfully handled the
|
||||
* event; nonzero on failure. The semantics
|
||||
* of the return code is specific to the
|
||||
* particular GAP event being signalled.
|
||||
*/
|
||||
static int
|
||||
bleprph_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);
|
||||
bleprph_print_conn_desc(&desc);
|
||||
|
||||
#if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
|
||||
phy_conn_changed(event->connect.conn_handle);
|
||||
#endif
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
bleprph_advertise();
|
||||
}
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
|
||||
bleprph_print_conn_desc(&event->disconnect.conn);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
#if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
|
||||
phy_conn_changed(CONN_HANDLE_INVALID);
|
||||
#endif
|
||||
|
||||
/* Connection terminated; resume advertising. */
|
||||
bleprph_advertise();
|
||||
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->conn_update.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
bleprph_print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "advertise complete; reason=%d",
|
||||
event->adv_complete.reason);
|
||||
bleprph_advertise();
|
||||
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);
|
||||
bleprph_print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
|
||||
"reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
|
||||
event->subscribe.conn_handle,
|
||||
event->subscribe.attr_handle,
|
||||
event->subscribe.reason,
|
||||
event->subscribe.prev_notify,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_indicate,
|
||||
event->subscribe.cur_indicate);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.channel_id,
|
||||
event->mtu.value);
|
||||
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;
|
||||
|
||||
#if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
|
||||
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE:
|
||||
/* XXX: assume symmetric phy for now */
|
||||
phy_update(event->phy_updated.tx_phy);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bleprph_on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
bleprph_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Make sure we have proper identity address set (public preferred) */
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Begin advertising. */
|
||||
bleprph_advertise();
|
||||
}
|
||||
|
||||
/**
|
||||
* main
|
||||
*
|
||||
* The main task for the project. This function initializes the packages,
|
||||
* then starts serving events from default event queue.
|
||||
*
|
||||
* @return int NOTE: this function should never return!
|
||||
*/
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM) >= 0
|
||||
struct image_version ver;
|
||||
static char ver_str[IMGMGR_NMGR_MAX_VER];
|
||||
#endif
|
||||
int rc;
|
||||
|
||||
/* Initialize OS */
|
||||
sysinit();
|
||||
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = bleprph_on_reset;
|
||||
ble_hs_cfg.sync_cb = bleprph_on_sync;
|
||||
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
rc = gatt_svr_init();
|
||||
assert(rc == 0);
|
||||
|
||||
#if MYNEWT_VAL(BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM) >= 0
|
||||
/* Set firmware version in DIS */
|
||||
imgr_my_version(&ver);
|
||||
imgr_ver_str(&ver, ver_str);
|
||||
ble_svc_dis_firmware_revision_set(ver_str);
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
|
||||
phy_init();
|
||||
#endif
|
||||
|
||||
conf_load();
|
||||
|
||||
/* If this app is acting as the loader in a split image setup, jump into
|
||||
* the second stage application instead of starting the OS.
|
||||
*/
|
||||
#if MYNEWT_VAL(SPLIT_LOADER)
|
||||
{
|
||||
void *entry;
|
||||
rc = split_app_go(&entry, true);
|
||||
if (rc == 0) {
|
||||
hal_system_start(entry);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* As the last thing, process events from default event queue.
|
||||
*/
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
43
src/libs/mynewt-nimble/apps/bleprph/src/misc.c
Normal file
43
src/libs/mynewt-nimble/apps/bleprph/src/misc.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 "bleprph.h"
|
||||
|
||||
/**
|
||||
* Utility function to log an array of bytes.
|
||||
*/
|
||||
void
|
||||
print_bytes(const uint8_t *bytes, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
MODLOG_DFLT(INFO, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
128
src/libs/mynewt-nimble/apps/bleprph/src/phy.c
Normal file
128
src/libs/mynewt-nimble/apps/bleprph/src/phy.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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 "os/mynewt.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "bleprph.h"
|
||||
|
||||
#if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
|
||||
|
||||
static const int button_gpio[4] = MYNEWT_VAL(BLEPRPH_LE_PHY_BUTTON_GPIO);
|
||||
static const int led_gpio[3] = MYNEWT_VAL(BLEPRPH_LE_PHY_LED_GPIO);
|
||||
|
||||
#define PHY_TO_PTR(_mask, _opts) (void *)(((_opts) << 16) | ((_mask)))
|
||||
#define PTR_TO_PHY_MASK(_ptr) (uint8_t)(((int)_ptr) & 0x0ff)
|
||||
#define PTR_TO_PHY_OPTS(_ptr) (uint8_t)(((int)_ptr) >> 16)
|
||||
|
||||
static struct os_event gpio_event;
|
||||
|
||||
static uint16_t conn_handle = CONN_HANDLE_INVALID;
|
||||
|
||||
static void
|
||||
gpio_irq_handler(void *arg)
|
||||
{
|
||||
gpio_event.ev_arg = arg;
|
||||
os_eventq_put(os_eventq_dflt_get(), &gpio_event);
|
||||
}
|
||||
|
||||
static void
|
||||
gpio_event_handler(struct os_event *ev)
|
||||
{
|
||||
uint8_t phy_mask;
|
||||
uint8_t phy_opts;
|
||||
int sr;
|
||||
|
||||
OS_ENTER_CRITICAL(sr);
|
||||
phy_mask = PTR_TO_PHY_MASK(ev->ev_arg);
|
||||
phy_opts = PTR_TO_PHY_OPTS(ev->ev_arg);
|
||||
OS_EXIT_CRITICAL(sr);
|
||||
|
||||
if (conn_handle != CONN_HANDLE_INVALID) {
|
||||
ble_gap_set_prefered_le_phy(conn_handle, phy_mask, phy_mask, phy_opts);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setup_button_gpio(int button, uint8_t phy_mask, uint8_t phy_opts)
|
||||
{
|
||||
if (button < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
hal_gpio_irq_init(button, gpio_irq_handler, PHY_TO_PTR(phy_mask, phy_opts),
|
||||
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(button);
|
||||
}
|
||||
|
||||
void
|
||||
phy_init(void)
|
||||
{
|
||||
gpio_event.ev_cb = gpio_event_handler;
|
||||
|
||||
/*
|
||||
* XXX: we could make this configurable, but for now assume all pins are
|
||||
* valid, buttons gpio pins are pulled-up and LEDs are active-low - this
|
||||
* is valid for nRF52840 PDK.
|
||||
*/
|
||||
setup_button_gpio(button_gpio[0], BLE_GAP_LE_PHY_1M_MASK,
|
||||
BLE_GAP_LE_PHY_CODED_ANY);
|
||||
setup_button_gpio(button_gpio[1], BLE_GAP_LE_PHY_2M_MASK,
|
||||
BLE_GAP_LE_PHY_CODED_ANY);
|
||||
setup_button_gpio(button_gpio[2], BLE_GAP_LE_PHY_CODED_MASK,
|
||||
BLE_GAP_LE_PHY_CODED_S2);
|
||||
setup_button_gpio(button_gpio[3], BLE_GAP_LE_PHY_CODED_MASK,
|
||||
BLE_GAP_LE_PHY_CODED_S8);
|
||||
|
||||
hal_gpio_init_out(led_gpio[0], 1);
|
||||
hal_gpio_init_out(led_gpio[1], 1);
|
||||
hal_gpio_init_out(led_gpio[2], 1);
|
||||
}
|
||||
|
||||
void
|
||||
phy_conn_changed(uint16_t handle)
|
||||
{
|
||||
uint8_t phy = 0;
|
||||
|
||||
conn_handle = handle;
|
||||
|
||||
if (handle != CONN_HANDLE_INVALID) {
|
||||
/* XXX: assume symmetric phy for now */
|
||||
ble_gap_read_le_phy(handle, &phy, &phy);
|
||||
}
|
||||
|
||||
phy_update(phy);
|
||||
}
|
||||
|
||||
void
|
||||
phy_update(uint8_t phy)
|
||||
{
|
||||
if (conn_handle == CONN_HANDLE_INVALID) {
|
||||
hal_gpio_write(led_gpio[0], 1);
|
||||
hal_gpio_write(led_gpio[1], 1);
|
||||
hal_gpio_write(led_gpio[2], 1);
|
||||
} else {
|
||||
hal_gpio_write(led_gpio[0], !(phy == BLE_GAP_LE_PHY_1M));
|
||||
hal_gpio_write(led_gpio[1], !(phy == BLE_GAP_LE_PHY_2M));
|
||||
hal_gpio_write(led_gpio[2], !(phy == BLE_GAP_LE_PHY_CODED));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
68
src/libs/mynewt-nimble/apps/bleprph/syscfg.yml
Normal file
68
src/libs/mynewt-nimble/apps/bleprph/syscfg.yml
Normal file
|
|
@ -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.
|
||||
#
|
||||
|
||||
syscfg.defs:
|
||||
BLEPRPH_LE_PHY_SUPPORT:
|
||||
description: >
|
||||
Enable support for changing PHY preference on active connection.
|
||||
PHY preference change is triggered by configured GPIO pins.
|
||||
Current PHY is indicated using LEDs connected to configured
|
||||
GPIO pins.
|
||||
value: 0
|
||||
BLEPRPH_LE_PHY_BUTTON_GPIO:
|
||||
description: >
|
||||
GPIO pins for changing PHY preference on active connection. This
|
||||
is an array of 4 GPIO pin numbers for 1M, 2M, LE Coded S=2 and
|
||||
LE Coded S=8 respectively.
|
||||
value: "(int[]){ BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4 }"
|
||||
BLEPRPH_LE_PHY_LED_GPIO:
|
||||
description: >
|
||||
GPIO pins for indicating current PHY on active connection. This
|
||||
is an array of 3 GPIO pin numbers for 1M, 2M and LE Coded
|
||||
respectively.
|
||||
value: "(int[]){ LED_1, LED_2, LED_3 }"
|
||||
|
||||
syscfg.vals:
|
||||
# Disable central and observer roles.
|
||||
BLE_ROLE_BROADCASTER: 1
|
||||
BLE_ROLE_CENTRAL: 0
|
||||
BLE_ROLE_OBSERVER: 0
|
||||
BLE_ROLE_PERIPHERAL: 1
|
||||
|
||||
# Configure DIS
|
||||
BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM: 1
|
||||
|
||||
# Log reboot messages to a flash circular buffer.
|
||||
REBOOT_LOG_FCB: 1
|
||||
LOG_FCB: 1
|
||||
CONFIG_FCB: 1
|
||||
|
||||
# Enable smp commands.
|
||||
STATS_MGMT: 1
|
||||
LOG_MGMT: 1
|
||||
CONFIG_MGMT: 1
|
||||
|
||||
# OS main/default task
|
||||
OS_MAIN_STACK_SIZE: 512
|
||||
|
||||
# Lots of smaller mbufs are required for smp using typical BLE ATT MTU
|
||||
# values.
|
||||
MSYS_1_BLOCK_COUNT: 22
|
||||
MSYS_1_BLOCK_SIZE: 110
|
||||
|
||||
BLE_SVC_GAP_DEVICE_NAME: '"nimble-bleprph"'
|
||||
201
src/libs/mynewt-nimble/apps/blestress/README.md
Normal file
201
src/libs/mynewt-nimble/apps/blestress/README.md
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
BLE Stress Tests
|
||||
|
||||
******************************************************************************
|
||||
QUICK TIPS:
|
||||
You need 2 controllers supported by MyNewt. One will become TX device,
|
||||
the other will become RX device.
|
||||
|
||||
1. Set role (TX=0, RX=1) for current device in syscfg.yml
|
||||
BLE_STRESS_TEST_ROLE: 1
|
||||
|
||||
The RX has LED2 turned on.
|
||||
|
||||
2. Set (in syscfg.yml) number of times to repeat each tested action
|
||||
in use case, e.g. do 1000 times connect/disconnect to complete use case.
|
||||
RX_STRESS_REPEAT: 1000
|
||||
|
||||
3. To perform only specific test, go to rx_stress.c,
|
||||
find definition of rx_stress_main_task_fn(void *arg) and in place of
|
||||
for-loop just paste function rx_stress_start(i), where i is id of test.
|
||||
|
||||
******************************************************************************
|
||||
|
||||
No | Use case
|
||||
-----------------------------------------------------------------------------
|
||||
1 | Stress Connect -> Connect Cancel - repeat 1000
|
||||
| RX: Nothing
|
||||
| TX: Connect/Connect cancel
|
||||
|
|
||||
2 | Stress Connect/Disconnect legacy - repeat 1000
|
||||
| RX: Advertise legacy
|
||||
| TX: Connect/Disconnect
|
||||
|
|
||||
3 | Stress Connect/Disconnect ext adv - repeat 1000
|
||||
| RX: Advertise Ext
|
||||
| TX: Connect/Disconnect
|
||||
|
|
||||
4 | Stress connection params update (TX) - (1000)
|
||||
| RX: Advertise
|
||||
| TX: Connect/Connect param update
|
||||
|
|
||||
5 | Stress connection params update (RX) - (1000)
|
||||
| RX: Advertise/Connect param update
|
||||
| TX: Connect
|
||||
|
|
||||
6 | Stress Scan
|
||||
| RX: Advertise a known data pattern
|
||||
| TX: Scan and check received data with pattern
|
||||
|
|
||||
7 | Stress PHY Update (TX) - (1000)
|
||||
| RX: Advertise
|
||||
| TX: Connect/Phy update
|
||||
|
|
||||
8 | Stress PHY update (RX) - (1000)
|
||||
| RX: Advertise/Phy update
|
||||
| TX: Connect
|
||||
|
|
||||
9 | Stress multi connection
|
||||
| RX: Advertise Ext
|
||||
| TX: Establish and maintain as many instances as possible
|
||||
|
|
||||
10 | Stress L2CAP send
|
||||
| RX: Send 64kB of data with L2CAP
|
||||
| TX: Measure bit rate and max received data MTU
|
||||
|
|
||||
11 | Stress Advertise/Connect/Continue Adv/Disconnect
|
||||
| RX: Advertise Ext/Continue same advertise after connect
|
||||
| TX: Connect
|
||||
|
|
||||
12 | Stress GATT indicating
|
||||
| RX: Indicate
|
||||
| TX: Receive indication. Measure average time of indicating.
|
||||
|
|
||||
13 | Stress GATT notification
|
||||
| RX: Notify. Measure average time of notifying.
|
||||
| TX: Count the number of received notification.
|
||||
|
|
||||
14 | Stress GATT Subscribe/Notify/Unsubscribe
|
||||
| RX: Notify on subscribe
|
||||
| TX: Measure the average time from sending a subscription request
|
||||
| to receiving a notification.
|
||||
|
|
||||
15 | Stress Connect/Send/Disconnect
|
||||
| RX: Advertise/Send via ATT/Disconnect
|
||||
| TX: Receive notification. Measure time of notifying.
|
||||
|
||||
******************************************************************************
|
||||
Concept:
|
||||
The RX device advertises data containing a UUID128 of test use case that
|
||||
should be performed. The TX device scan for known UUIDs, when it finds,
|
||||
adapts to the advertised use case and runs a test.
|
||||
|
||||
Stress Task vs Semaphore:
|
||||
The rx_stress_start_auto function starts main stress test task that runs
|
||||
all stress tests one by one. The tests are based on event handling, so to
|
||||
synchronize main task with events, a semaphore is used. On use case start
|
||||
there is 0 tokens for semaphore. After main task starts one of use cases,
|
||||
it comes across a semaphore and has to wait. When use case is completed,
|
||||
1 token is released, so main task can use it to pass through semaphore.
|
||||
The tx_stress_start_auto function works analogically.
|
||||
|
||||
|
||||
Newt target set example:
|
||||
rymek@rymek:~/projects/bletiny_proj$ newt target show bletest_tx
|
||||
targets/bletest_tx
|
||||
app=@apache-mynewt-nimble/apps/blestress
|
||||
bsp=@apache-mynewt-core/hw/bsp/nordic_pca10056
|
||||
build_profile=debug
|
||||
syscfg=BLE_STRESS_TEST_ROLE=0
|
||||
rymek@rymek:~/projects/bletiny_proj$ newt target show bletest_rx
|
||||
targets/bletest_rx
|
||||
app=@apache-mynewt-nimble/apps/blestress
|
||||
bsp=@apache-mynewt-core/hw/bsp/nordic_pca10056
|
||||
build_profile=debug
|
||||
syscfg=BLE_STRESS_TEST_ROLE=1
|
||||
|
||||
|
||||
Example of expected logs on TX side(LOG_LEVEL > 1):
|
||||
Start test num 1
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 1 completed
|
||||
Start scan for test
|
||||
Start test num 2
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 2 completed
|
||||
Start scan for test
|
||||
Start test num 3
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 3 completed
|
||||
Start scan for test
|
||||
Start test num 4
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 4 completed
|
||||
Start scan for test
|
||||
Start test num 5
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 5 completed
|
||||
Start scan for test
|
||||
Start test num 6
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 6 completed
|
||||
Start scan for test
|
||||
Start test num 7
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 7 completed
|
||||
Start scan for test
|
||||
Start test num 8
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 8 completed
|
||||
All tests completed
|
||||
Tests results:
|
||||
Use case 1 - Stress Connect -> Connect Cancel:
|
||||
Con attempts = 20
|
||||
Con success = 0
|
||||
Use case 2 - Stress Connect/Disconnect legacy:
|
||||
Con attempts = 20
|
||||
Con success = 20
|
||||
Use case 3 - Stress Connect/Disconnect ext adv:
|
||||
Con attempts = 20
|
||||
Con success = 20
|
||||
Use case 4 - Stress connection params update (TX):
|
||||
Params updates = 20
|
||||
Use case 5 - Stress connection params update (RX):
|
||||
Params updates = 20
|
||||
Use case 6 - Stress Scan:
|
||||
Received first packets = 20
|
||||
Received all packets = 20
|
||||
Use case 7 - Stress PHY Update (TX):
|
||||
PHY updates = 20
|
||||
Use case 8 - Stress Connect -> Connect Cancel:
|
||||
PHY updates = 20
|
||||
|
||||
|
||||
Example of expected logs on RX side(LOG_LEVEL > 1):
|
||||
Start test num 2
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 2 completed
|
||||
Start test num 3
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 3 completed
|
||||
Start test num 4
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 4 completed
|
||||
Start test num 5
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 5 completed
|
||||
Start test num 6
|
||||
Received signal to switch test
|
||||
Start test num 7
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 7 completed
|
||||
Start test num 8
|
||||
>>>>>>>>>>>>>>>>>>>> Stress test 8 completed
|
||||
All tests completed
|
||||
Tests results:
|
||||
Use case 1 - Stress Connect -> Connect Cancel:
|
||||
Con attempts = 0
|
||||
Con success = 0
|
||||
Use case 2 - Stress Connect/Disconnect legacy:
|
||||
Con attempts = 20
|
||||
Con success = 20
|
||||
Use case 3 - Stress Connect/Disconnect ext adv:
|
||||
Con attempts = 20
|
||||
Con success = 20
|
||||
Use case 4 - Stress connection params update (TX):
|
||||
Params updates = 20
|
||||
Use case 5 - Stress connection params update (RX):
|
||||
Params updates = 20
|
||||
Use case 6 - Stress Scan:
|
||||
Received first packets = 0
|
||||
Received all packets = 0
|
||||
Use case 7 - Stress PHY Update (TX):
|
||||
PHY updates = 20
|
||||
Use case 8 - Stress Connect -> Connect Cancel:
|
||||
PHY updates = 20
|
||||
39
src/libs/mynewt-nimble/apps/blestress/pkg.yml
Normal file
39
src/libs/mynewt-nimble/apps/blestress/pkg.yml
Normal file
|
|
@ -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/blestress"
|
||||
pkg.type: app
|
||||
pkg.description: "Stress tests sample application."
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@mcuboot/boot/bootutil"
|
||||
- "@apache-mynewt-core/sys/log/modlog"
|
||||
- "@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/id"
|
||||
- "@apache-mynewt-nimble/nimble/controller"
|
||||
- "@apache-mynewt-nimble/nimble/host"
|
||||
- "@apache-mynewt-nimble/nimble/host/util"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gap"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gatt"
|
||||
- "@apache-mynewt-nimble/nimble/host/store/ram"
|
||||
- "@apache-mynewt-nimble/nimble/transport/ram"
|
||||
99
src/libs/mynewt-nimble/apps/blestress/src/main.c
Normal file
99
src/libs/mynewt-nimble/apps/blestress/src/main.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 "os/mynewt.h"
|
||||
#include "config/config.h"
|
||||
#include "bsp.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
/* Application-specified header. */
|
||||
#include "rx_stress.h"
|
||||
#include "tx_stress.h"
|
||||
#include "stress_gatt.h"
|
||||
|
||||
static void
|
||||
stress_test_on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
stress_test_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Make sure we have proper identity address set (public preferred) */
|
||||
rc = ble_hs_util_ensure_addr(1);
|
||||
assert(rc == 0);
|
||||
|
||||
#if MYNEWT_VAL(BLE_STRESS_TEST_ROLE)
|
||||
rx_stress_start_auto();
|
||||
#else
|
||||
tx_stress_start_auto();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* main
|
||||
*
|
||||
* The main task for the project. This function initializes the packages,
|
||||
* then starts serving events from default event queue.
|
||||
*
|
||||
* @return int NOTE: this function should never return!
|
||||
*/
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
sysinit();
|
||||
|
||||
ble_hs_cfg.reset_cb = stress_test_on_reset;
|
||||
ble_hs_cfg.sync_cb = stress_test_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* Please do not change name. Otherwise some tests could fail. */
|
||||
rc = ble_svc_gap_device_name_set("STRESS");
|
||||
assert(rc == 0);
|
||||
|
||||
conf_load();
|
||||
|
||||
rc = gatt_svr_init();
|
||||
assert(rc == 0);
|
||||
|
||||
#if MYNEWT_VAL(BLE_STRESS_TEST_ROLE)
|
||||
/* RX device */
|
||||
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
|
||||
hal_gpio_init_out(LED_2, 1);
|
||||
hal_gpio_toggle(LED_2);
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
os_eventq_run(os_eventq_dflt_get());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
224
src/libs/mynewt-nimble/apps/blestress/src/misc.c
Normal file
224
src/libs/mynewt-nimble/apps/blestress/src/misc.c
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* 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 "misc.h"
|
||||
|
||||
void
|
||||
rand_bytes(uint8_t *data, int len) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
data[i] = (uint8_t) rand() % UINT8_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to log an array of bytes.
|
||||
*/
|
||||
void
|
||||
print_bytes(const uint8_t *bytes, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_addr(const void *addr)
|
||||
{
|
||||
const uint8_t *u8p;
|
||||
|
||||
u8p = addr;
|
||||
MODLOG_DFLT(DEBUG, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
|
||||
}
|
||||
|
||||
void
|
||||
print_mbuf(const struct os_mbuf *om)
|
||||
{
|
||||
while (om != NULL) {
|
||||
print_bytes(om->om_data, om->om_len);
|
||||
om = SLIST_NEXT(om, om_next);
|
||||
|
||||
if(om == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Separate buf fields with colon to maintain continuity */
|
||||
MODLOG_DFLT(DEBUG, ":");
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
addr_str(const void *addr)
|
||||
{
|
||||
/* 6 bytes of MAC address * 2 signs for each byte in string + 5 colons to
|
||||
* separate bytes + 1 byte for null-character appended by sprintf
|
||||
*/
|
||||
static char buf[6 * 2 + 5 + 1];
|
||||
const uint8_t *u8p;
|
||||
|
||||
u8p = addr;
|
||||
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
print_uuid(const ble_uuid_t *uuid)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
MODLOG_DFLT(DEBUG, "%s", ble_uuid_to_str(uuid, buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs information about a connection to the console.
|
||||
*/
|
||||
void
|
||||
print_conn_desc(const struct ble_gap_conn_desc *desc)
|
||||
{
|
||||
MODLOG_DFLT(DEBUG, "handle=%d our_ota_addr_type=%d our_ota_addr=%s ",
|
||||
desc->conn_handle, desc->our_ota_addr.type,
|
||||
addr_str(desc->our_ota_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "our_id_addr_type=%d our_id_addr=%s ",
|
||||
desc->our_id_addr.type, addr_str(desc->our_id_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "peer_ota_addr_type=%d peer_ota_addr=%s ",
|
||||
desc->peer_ota_addr.type, addr_str(desc->peer_ota_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "peer_id_addr_type=%d peer_id_addr=%s ",
|
||||
desc->peer_id_addr.type, addr_str(desc->peer_id_addr.val));
|
||||
MODLOG_DFLT(DEBUG, "conn_itvl=%d conn_latency=%d supervision_timeout=%d "
|
||||
"encrypted=%d authenticated=%d bonded=%d",
|
||||
desc->conn_itvl, desc->conn_latency,
|
||||
desc->supervision_timeout,
|
||||
desc->sec_state.encrypted,
|
||||
desc->sec_state.authenticated,
|
||||
desc->sec_state.bonded);
|
||||
}
|
||||
|
||||
void
|
||||
print_adv_fields(const struct ble_hs_adv_fields *fields)
|
||||
{
|
||||
char s[BLE_HS_ADV_MAX_SZ];
|
||||
const uint8_t *u8p;
|
||||
int i;
|
||||
|
||||
if (fields->flags != 0) {
|
||||
MODLOG_DFLT(DEBUG, " flags=0x%02x\n", fields->flags);
|
||||
}
|
||||
|
||||
if (fields->uuids16 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uuids16(%scomplete)=",
|
||||
fields->uuids16_is_complete ? "" : "in");
|
||||
for (i = 0; i < fields->num_uuids16; i++) {
|
||||
print_uuid(&fields->uuids16[i].u);
|
||||
MODLOG_DFLT(DEBUG, " ");
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->uuids32 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uuids32(%scomplete)=",
|
||||
fields->uuids32_is_complete ? "" : "in");
|
||||
for (i = 0; i < fields->num_uuids32; i++) {
|
||||
print_uuid(&fields->uuids32[i].u);
|
||||
MODLOG_DFLT(DEBUG, " ");
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->uuids128 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uuids128(%scomplete)=",
|
||||
fields->uuids128_is_complete ? "" : "in");
|
||||
for (i = 0; i < fields->num_uuids128; i++) {
|
||||
print_uuid(&fields->uuids128[i].u);
|
||||
MODLOG_DFLT(DEBUG, " ");
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->name != NULL) {
|
||||
assert(fields->name_len < sizeof s - 1);
|
||||
memcpy(s, fields->name, fields->name_len);
|
||||
s[fields->name_len] = '\0';
|
||||
MODLOG_DFLT(DEBUG, " name(%scomplete)=%s\n",
|
||||
fields->name_is_complete ? "" : "in", s);
|
||||
}
|
||||
|
||||
if (fields->tx_pwr_lvl_is_present) {
|
||||
MODLOG_DFLT(DEBUG, " tx_pwr_lvl=%d\n", fields->tx_pwr_lvl);
|
||||
}
|
||||
|
||||
if (fields->slave_itvl_range != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " slave_itvl_range=");
|
||||
print_bytes(fields->slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->svc_data_uuid16 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " svc_data_uuid16=");
|
||||
print_bytes(fields->svc_data_uuid16, fields->svc_data_uuid16_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->public_tgt_addr != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " public_tgt_addr=");
|
||||
u8p = fields->public_tgt_addr;
|
||||
for (i = 0; i < fields->num_public_tgt_addrs; i++) {
|
||||
MODLOG_DFLT(DEBUG, "public_tgt_addr=%s ", addr_str(u8p));
|
||||
u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
||||
}
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->appearance_is_present) {
|
||||
MODLOG_DFLT(DEBUG, " appearance=0x%04x\n", fields->appearance);
|
||||
}
|
||||
|
||||
if (fields->adv_itvl_is_present) {
|
||||
MODLOG_DFLT(DEBUG, " adv_itvl=0x%04x\n", fields->adv_itvl);
|
||||
}
|
||||
|
||||
if (fields->svc_data_uuid32 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " svc_data_uuid32=");
|
||||
print_bytes(fields->svc_data_uuid32, fields->svc_data_uuid32_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->svc_data_uuid128 != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " svc_data_uuid128=");
|
||||
print_bytes(fields->svc_data_uuid128, fields->svc_data_uuid128_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->uri != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " uri=");
|
||||
print_bytes(fields->uri, fields->uri_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
|
||||
if (fields->mfg_data != NULL) {
|
||||
MODLOG_DFLT(DEBUG, " mfg_data=");
|
||||
print_bytes(fields->mfg_data, fields->mfg_data_len);
|
||||
MODLOG_DFLT(DEBUG, "\n");
|
||||
}
|
||||
}
|
||||
54
src/libs/mynewt-nimble/apps/blestress/src/misc.h
Normal file
54
src/libs/mynewt-nimble/apps/blestress/src/misc.h
Normal file
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef BLE_TGT_MISC_H
|
||||
#define BLE_TGT_MISC_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "host/ble_hs_adv.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void rand_bytes(uint8_t *data, int len);
|
||||
|
||||
void print_bytes(const uint8_t *bytes, int len);
|
||||
|
||||
void print_addr(const void *addr);
|
||||
|
||||
void print_mbuf(const struct os_mbuf *om);
|
||||
|
||||
char *addr_str(const void *addr);
|
||||
|
||||
void print_uuid(const ble_uuid_t *uuid);
|
||||
|
||||
void print_conn_desc(const struct ble_gap_conn_desc *desc);
|
||||
|
||||
void print_adv_fields(const struct ble_hs_adv_fields *fields);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //BLE_TGT_MISC_H
|
||||
1471
src/libs/mynewt-nimble/apps/blestress/src/rx_stress.c
Normal file
1471
src/libs/mynewt-nimble/apps/blestress/src/rx_stress.c
Normal file
File diff suppressed because it is too large
Load diff
53
src/libs/mynewt-nimble/apps/blestress/src/rx_stress.h
Normal file
53
src/libs/mynewt-nimble/apps/blestress/src/rx_stress.h
Normal file
|
|
@ -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 _BLE_STRESS_RX_H
|
||||
#define _BLE_STRESS_RX_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <console/console.h>
|
||||
#include <errno.h>
|
||||
#include <nrfx/hal/nrf_aar.h>
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include <host/ble_l2cap.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "stress.h"
|
||||
#include "stress_gatt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Executes stress tests one by one.
|
||||
*/
|
||||
void rx_stress_start_auto();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //_BLE_STRESS_RX_H
|
||||
389
src/libs/mynewt-nimble/apps/blestress/src/stress.c
Normal file
389
src/libs/mynewt-nimble/apps/blestress/src/stress.c
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* 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 "stress.h"
|
||||
|
||||
void
|
||||
com_stress_print_report(const struct com_stress_test_ctx *test_ctxs)
|
||||
{
|
||||
console_printf("\033[0;32mAll tests completed\033[0m\n");
|
||||
console_printf("Tests results:\n");
|
||||
|
||||
console_printf(
|
||||
"\033[0;33mUse case 1 - Stress Connect -> Connect Cancel: \n\033[0m");
|
||||
console_printf("Con attempts = %d\n", test_ctxs->con_stat[1].attempts_num);
|
||||
console_printf("Con success = %d\n", test_ctxs->con_stat[1].num);
|
||||
|
||||
console_printf(
|
||||
"\033[0;33mUse case 2 - Stress Connect/Disconnect legacy: \n\033[0m");
|
||||
console_printf("Con attempts = %d\n", test_ctxs->con_stat[2].attempts_num);
|
||||
console_printf("Con success = %d\n", test_ctxs->con_stat[2].num);
|
||||
|
||||
console_printf(
|
||||
"\033[0;33mUse case 3 - Stress Connect/Disconnect ext adv: \n\033[0m");
|
||||
console_printf("Con attempts = %d\n", test_ctxs->con_stat[3].attempts_num);
|
||||
console_printf("Con success = %d\n", test_ctxs->con_stat[3].num);
|
||||
|
||||
console_printf(
|
||||
"\033[0;33mUse case 4 - Stress connection params update (TX): \n\033[0m");
|
||||
console_printf("Params updates = %d\n",
|
||||
test_ctxs->con_stat[4].prms_upd_num);
|
||||
|
||||
console_printf(
|
||||
"\033[0;33mUse case 5 - Stress connection params update (RX): \n\033[0m");
|
||||
console_printf("Params updates = %d\n",
|
||||
test_ctxs->con_stat[5].prms_upd_num);
|
||||
|
||||
console_printf("\033[0;33mUse case 6 - Stress Scan: \n\033[0m");
|
||||
console_printf("Received first packets = %d\n",
|
||||
test_ctxs->s6_rcv_adv_first);
|
||||
console_printf("Received all packets = %d\n", test_ctxs->s6_rcv_adv_suc);
|
||||
|
||||
console_printf("\033[0;33mUse case 7 - Stress PHY Update (TX): \n\033[0m");
|
||||
console_printf("PHY updates = %d\n", test_ctxs->con_stat[7].phy_upd_num);
|
||||
|
||||
console_printf("\033[0;33mUse case 8 - Stress PHY Update (RX): \n\033[0m");
|
||||
console_printf("PHY updates = %d\n", test_ctxs->con_stat[8].phy_upd_num);
|
||||
|
||||
console_printf(
|
||||
"\033[0;33mUse case 9 - Stress multi connection: \n\033[0m");
|
||||
console_printf("Max reached num of connections = %d\n",
|
||||
test_ctxs->con_stat[9].max_num);
|
||||
|
||||
console_printf("\033[0;33mUse case 10 - Stress L2CAP send: \n\033[0m");
|
||||
console_printf("Average bit rate = %d\n", test_ctxs->s10_bit_rate);
|
||||
console_printf("Max received MTU = %lld\n", test_ctxs->s10_max_mtu);
|
||||
|
||||
console_printf("\033[0;33mUse case 11 - "
|
||||
"Stress Advertise/Connect/Continue adv \n\033[0m");
|
||||
// console_printf(" = %d\n",);
|
||||
|
||||
console_printf("\033[0;33mUse case 12 - "
|
||||
"Stress GATT indication: \n\033[0m");
|
||||
console_printf("Average bit rate = %d\n", test_ctxs->s12_notif_time);
|
||||
|
||||
console_printf("\033[0;33mUse case 13 - "
|
||||
"Stress GATT notification: \n\033[0m");
|
||||
console_printf("Average time = %d\n", test_ctxs->s13_notif_time);
|
||||
|
||||
console_printf("\033[0;33mUse case 14 - "
|
||||
"Stress GATT Subscribe/Notify/Unsubscribe: \n\033[0m");
|
||||
console_printf("Average time = %d\n", test_ctxs->s14_notif_time);
|
||||
|
||||
console_printf("\033[0;33mUse case 15 - "
|
||||
"Stress Connect/Send/Disconnect: \n\033[0m");
|
||||
console_printf("Con num = %d\n", test_ctxs->con_stat[15].num);
|
||||
}
|
||||
|
||||
void
|
||||
stress_clear_ctx_reusable_var(struct com_stress_test_ctx *ctx)
|
||||
{
|
||||
ctx->cur_test_id = 0;
|
||||
ctx->dev_addr.type = 0;
|
||||
ctx->dev_addr.type = 0;
|
||||
ctx->conn_handle = 0;
|
||||
ctx->chan = 0;
|
||||
ctx->rcv_data_bytes = 0;
|
||||
ctx->rcv_num = 0;
|
||||
ctx->send_num = 0;
|
||||
ctx->begin_us = 0;
|
||||
ctx->end_us = 0;
|
||||
ctx->time_sum = 0;
|
||||
ctx->bytes_sum = 0;
|
||||
ctx->timeout_flag = 0;
|
||||
ctx->rcv_data_flag = 0;
|
||||
}
|
||||
|
||||
int
|
||||
stress_fill_mbuf_with_pattern(struct os_mbuf *om, uint16_t len)
|
||||
{
|
||||
int rc, i, mul, rest;
|
||||
|
||||
mul = len / STRESS_PAT_LEN;
|
||||
rest = len % STRESS_PAT_LEN;
|
||||
|
||||
for (i = 0; i < mul; ++i) {
|
||||
rc = os_mbuf_append(om, &test_6_pattern[29], STRESS_PAT_LEN);
|
||||
|
||||
if (rc) {
|
||||
os_mbuf_free_chain(om);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
rc = os_mbuf_append(om, &test_6_pattern[29], rest);
|
||||
|
||||
if (rc) {
|
||||
os_mbuf_free_chain(om);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
stress_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu)
|
||||
{
|
||||
int rc;
|
||||
console_printf("LE CoC SDU received, chan: 0x%08lx, data len %d\n",
|
||||
(uint32_t) chan, OS_MBUF_PKTLEN(sdu));
|
||||
|
||||
rc = os_mbuf_free_chain(sdu);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Get buffer for data chain */
|
||||
sdu = os_msys_get_pkthdr(STRESS_COC_MTU, 0);
|
||||
assert(sdu != NULL);
|
||||
|
||||
/* Receive data chain */
|
||||
rc = ble_l2cap_recv_ready(chan, sdu);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
void
|
||||
stress_l2cap_coc_accept(uint16_t peer_mtu, struct ble_l2cap_chan *chan)
|
||||
{
|
||||
struct os_mbuf *sdu_rx;
|
||||
int rc;
|
||||
|
||||
console_printf("LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n",
|
||||
(uint32_t) chan, peer_mtu);
|
||||
|
||||
sdu_rx = os_msys_get_pkthdr(STRESS_COC_MTU, 0);
|
||||
assert(sdu_rx != NULL);
|
||||
|
||||
rc = ble_l2cap_recv_ready(chan, sdu_rx);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
void
|
||||
stress_start_timer(uint32_t timeout_ms, os_event_fn *ev_cb)
|
||||
{
|
||||
int rc;
|
||||
os_callout_stop(&stress_timer_callout);
|
||||
|
||||
os_callout_init(&stress_timer_callout, os_eventq_dflt_get(), ev_cb, NULL);
|
||||
|
||||
rc = os_callout_reset(&stress_timer_callout,
|
||||
os_time_ms_to_ticks32(timeout_ms));
|
||||
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
int64_t
|
||||
stress_calc_bit_rate(int64_t us, int64_t bytes_num)
|
||||
{
|
||||
int bit_rate;
|
||||
|
||||
/* Multiply by 1000000 so you don't lose accuracy */
|
||||
bit_rate = 1000000 * bytes_num / us;
|
||||
|
||||
return bit_rate;
|
||||
}
|
||||
|
||||
static int
|
||||
stress_disc_dsc_fn(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc *dsc,
|
||||
void *arg)
|
||||
{
|
||||
struct stress_gatt_search_ctx *search_ctx;
|
||||
static bool found = false;
|
||||
|
||||
search_ctx = (struct stress_gatt_search_ctx *) arg;
|
||||
|
||||
if (error->status == 0) {
|
||||
if (!ble_uuid_cmp(&dsc->uuid.u, &search_ctx->dsc_uuid.u) && !found) {
|
||||
MODLOG_DFLT(INFO, "Found chr descriptor\n");
|
||||
search_ctx->dsc_handle = dsc->handle;
|
||||
MODLOG_DFLT(INFO, "uuid=%#06x; handle=%#06x", dsc->uuid.u16.value,
|
||||
dsc->handle);
|
||||
found = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error->status == BLE_HS_EDONE) {
|
||||
MODLOG_DFLT(INFO, "Done descriptor discovery\n");
|
||||
|
||||
if (found) {
|
||||
found = false;
|
||||
search_ctx->disc_end_fn(search_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(ERROR, "\033[0;31mDid not find particular descriptor"
|
||||
"\033[0m\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(ERROR, "\033[0;31mError during descriptor discovery"
|
||||
"\033[0m\n");
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stress_disc_chr_fn(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg)
|
||||
{
|
||||
int rc;
|
||||
struct stress_gatt_search_ctx *search_ctx;
|
||||
static bool found = false;
|
||||
|
||||
search_ctx = (struct stress_gatt_search_ctx *) arg;
|
||||
|
||||
if (error->status == 0) {
|
||||
MODLOG_DFLT(INFO, "Found characteristic\n");
|
||||
search_ctx->chr_start_handle = chr->val_handle;
|
||||
found = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error->status == BLE_HS_EDONE) {
|
||||
MODLOG_DFLT(INFO, "Done characteristic discovery\n");
|
||||
|
||||
if (found) {
|
||||
found = false;
|
||||
|
||||
if (search_ctx->search_goal == STRESS_FIND_CHR) {
|
||||
search_ctx->disc_end_fn(search_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = ble_gattc_disc_all_dscs(conn_handle,
|
||||
search_ctx->chr_start_handle,
|
||||
search_ctx->srv_end_handle,
|
||||
&stress_disc_dsc_fn, search_ctx);
|
||||
assert(rc == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(ERROR, "\033[0;31mDid not find particular "
|
||||
"characteristic\033[0m\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(ERROR,
|
||||
"\033[0;31mError during characteristic discovery\033[0m\n");
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stress_disc_svc_fn(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_svc *service, void *arg)
|
||||
{
|
||||
int rc;
|
||||
struct stress_gatt_search_ctx *search_ctx = NULL;
|
||||
static bool found = false;
|
||||
|
||||
search_ctx = (struct stress_gatt_search_ctx *) arg;
|
||||
|
||||
if (error->status == 0) {
|
||||
MODLOG_DFLT(INFO, "Found service\n");
|
||||
search_ctx->srv_start_handle = service->start_handle;
|
||||
search_ctx->srv_end_handle = service->end_handle;
|
||||
found = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error->status == BLE_HS_EDONE) {
|
||||
MODLOG_DFLT(INFO, "Done service discovery\n");
|
||||
|
||||
if (found) {
|
||||
found = false;
|
||||
if (search_ctx->search_goal == STRESS_FIND_SRV) {
|
||||
search_ctx->disc_end_fn(search_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = ble_gattc_disc_chrs_by_uuid(conn_handle,
|
||||
search_ctx->srv_start_handle,
|
||||
search_ctx->srv_end_handle,
|
||||
&search_ctx->chr_uuid.u,
|
||||
&stress_disc_chr_fn,
|
||||
search_ctx);
|
||||
MODLOG_DFLT(INFO, "rc=%d\n", rc);
|
||||
assert(rc == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(ERROR,
|
||||
"\033[0;31mDid not find particular service\033[0m\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(ERROR, "\033[0;31mError during service discovery\033[0m\n");
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
stress_gatt_find_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid,
|
||||
const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid,
|
||||
stress_gatt_disc_end_fn *disc_end_fn,
|
||||
uint8_t search_goal)
|
||||
{
|
||||
static struct stress_gatt_search_ctx search_ctx;
|
||||
int rc;
|
||||
|
||||
search_ctx.conn_handle = conn_handle;
|
||||
ble_uuid_copy((ble_uuid_any_t *) &search_ctx.srv_uuid, srv_uuid);
|
||||
ble_uuid_copy((ble_uuid_any_t *) &search_ctx.chr_uuid, chr_uuid);
|
||||
ble_uuid_copy((ble_uuid_any_t *) &search_ctx.dsc_uuid, dsc_uuid);
|
||||
search_ctx.disc_end_fn = disc_end_fn;
|
||||
search_ctx.search_goal = search_goal;
|
||||
search_ctx.srv_start_handle = 0;
|
||||
search_ctx.srv_end_handle = 0;
|
||||
search_ctx.chr_start_handle = 0;
|
||||
search_ctx.dsc_handle = 0;
|
||||
|
||||
rc = ble_gattc_disc_svc_by_uuid(conn_handle, srv_uuid, &stress_disc_svc_fn,
|
||||
&search_ctx);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
void
|
||||
stress_find_svc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid,
|
||||
stress_gatt_disc_end_fn *disc_end_fn)
|
||||
{
|
||||
stress_gatt_find_handle(conn_handle, srv_uuid, NULL, NULL, disc_end_fn,
|
||||
STRESS_FIND_SRV);
|
||||
}
|
||||
|
||||
void
|
||||
stress_find_chr_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid,
|
||||
const ble_uuid_t *chr_uuid,
|
||||
stress_gatt_disc_end_fn *disc_end_fn)
|
||||
{
|
||||
stress_gatt_find_handle(conn_handle, srv_uuid, chr_uuid, NULL, disc_end_fn,
|
||||
STRESS_FIND_CHR);
|
||||
}
|
||||
|
||||
void
|
||||
stress_find_dsc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid,
|
||||
const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid,
|
||||
stress_gatt_disc_end_fn *disc_end_fn)
|
||||
{
|
||||
stress_gatt_find_handle(conn_handle, srv_uuid, chr_uuid, dsc_uuid,
|
||||
disc_end_fn, STRESS_FIND_DSC);
|
||||
}
|
||||
375
src/libs/mynewt-nimble/apps/blestress/src/stress.h
Normal file
375
src/libs/mynewt-nimble/apps/blestress/src/stress.h
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* 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_TGT_STRESS_H
|
||||
#define BLE_TGT_STRESS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <nimble/ble.h>
|
||||
#include <modlog/modlog.h>
|
||||
#include <os/mynewt.h>
|
||||
#include <console/console.h>
|
||||
#include <host/ble_l2cap.h>
|
||||
#include <host/ble_gatt.h>
|
||||
#include <host/ble_gap.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define STRESS_UUIDS_NUM (16)
|
||||
|
||||
/* No preferred PHY */
|
||||
#define TX_PHY_MASK 0
|
||||
#define RX_PHY_MASK 0
|
||||
/* L2CAP SDU */
|
||||
#define STRESS_COC_MTU (64000)
|
||||
|
||||
#define STRESS_FIND_SRV 1
|
||||
#define STRESS_FIND_CHR 2
|
||||
#define STRESS_FIND_DSC 3
|
||||
|
||||
struct os_callout stress_timer_callout;
|
||||
struct stress_gatt_search_ctx;
|
||||
typedef void stress_gatt_disc_end_fn(struct stress_gatt_search_ctx *search_ctx);
|
||||
|
||||
struct stress_gatt_search_ctx {
|
||||
/* Connection handle */
|
||||
uint16_t conn_handle;
|
||||
|
||||
/* Wanted service uuid */
|
||||
ble_uuid16_t srv_uuid;
|
||||
|
||||
/* Wanted characteristic uuid */
|
||||
ble_uuid16_t chr_uuid;
|
||||
|
||||
/* Wanted descriptor uuid */
|
||||
ble_uuid16_t dsc_uuid;
|
||||
|
||||
/* Search goal: 1 - service, 2 - characteristic, 3 - descriptor */
|
||||
uint8_t search_goal;
|
||||
|
||||
/* Callback after reaching the goal */
|
||||
stress_gatt_disc_end_fn *disc_end_fn;
|
||||
|
||||
/* Service start handle */
|
||||
uint16_t srv_start_handle;
|
||||
|
||||
/* Service end handle */
|
||||
uint16_t srv_end_handle;
|
||||
|
||||
/* Characteristic start handle */
|
||||
uint16_t chr_start_handle;
|
||||
|
||||
/* Descriptor handle */
|
||||
uint16_t dsc_handle;
|
||||
};
|
||||
|
||||
struct stress_con_stat {
|
||||
/* Number of successful connection attempts */
|
||||
int num;
|
||||
|
||||
/* Max number of established connections */
|
||||
int max_num;
|
||||
|
||||
/* Number connection attempts */
|
||||
int attempts_num;
|
||||
|
||||
/* Number of params updates */
|
||||
int prms_upd_num;
|
||||
|
||||
/* Number of PHY updates */
|
||||
int phy_upd_num;
|
||||
};
|
||||
|
||||
/* Common stress test context.
|
||||
* (Reusable) - auxiliary variable
|
||||
* (Stress x) - variable contains result of x stress test */
|
||||
struct com_stress_test_ctx {
|
||||
/* Which of tests are completed already. Each element for different
|
||||
* stress test. */
|
||||
bool completed[STRESS_UUIDS_NUM];
|
||||
|
||||
/* Connection stats. Each element for different stress test. */
|
||||
struct stress_con_stat con_stat[STRESS_UUIDS_NUM];
|
||||
|
||||
/* Reusable variables */
|
||||
|
||||
/* Stress test number */
|
||||
int cur_test_id;
|
||||
|
||||
/* Instance address */
|
||||
ble_addr_t dev_addr;
|
||||
|
||||
/* Connection handler */
|
||||
uint16_t conn_handle;
|
||||
|
||||
/* L2CAP channel (Reusable) */
|
||||
struct ble_l2cap_chan * chan;
|
||||
|
||||
/* Size of received data */
|
||||
int64_t rcv_data_bytes;
|
||||
|
||||
/* Number of received packages */
|
||||
int rcv_num;
|
||||
|
||||
/* Number of send actions */
|
||||
int send_num;
|
||||
|
||||
/* Variables for bit rate measurement */
|
||||
int64_t begin_us;
|
||||
int64_t end_us;
|
||||
int64_t time_sum;
|
||||
int64_t bytes_sum;
|
||||
|
||||
/* Timeout flag */
|
||||
bool timeout_flag;
|
||||
|
||||
/* Data received flag */
|
||||
bool rcv_data_flag;
|
||||
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
uint16_t dsc_handle;
|
||||
|
||||
/* Variables for test results */
|
||||
/* Reached timeout of scanning for test */
|
||||
bool scan_timeout;
|
||||
|
||||
/* Number of received first packets of adverts */
|
||||
int s6_rcv_adv_first;
|
||||
|
||||
/* Number of full received adverts */
|
||||
int s6_rcv_adv_suc;
|
||||
|
||||
/* L2CAP Send Bit Rate */
|
||||
int s10_bit_rate;
|
||||
|
||||
/* Average indication time */
|
||||
int s12_notif_time;
|
||||
|
||||
/* Average notification time */
|
||||
int s13_notif_time;
|
||||
|
||||
/* Average notification time */
|
||||
int s14_notif_time;
|
||||
|
||||
/* Max size of received MTU */
|
||||
int64_t s10_max_mtu;
|
||||
};
|
||||
|
||||
#define STRESS_PAT_LEN 1650
|
||||
|
||||
static const uint8_t test_6_pattern[STRESS_PAT_LEN] = {
|
||||
/* Random data */
|
||||
0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0a,
|
||||
0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14,
|
||||
0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1e,
|
||||
0x00, 0x20, 0x00, 0x22, 0x00, 0x24, 0x00, 0x26, 0x00, 0x28,
|
||||
0x00, 0x2a, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x32,
|
||||
0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c,
|
||||
0x00, 0x3e, 0x00, 0x40, 0x00, 0x42, 0x00, 0x44, 0x00, 0x46,
|
||||
0x00, 0x48, 0x00, 0x4a, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50,
|
||||
0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00, 0x58, 0x00, 0x5a,
|
||||
0x00, 0x5c, 0x00, 0x5e, 0x00, 0x60, 0x00, 0x62, 0x00, 0x64,
|
||||
0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c, 0x00, 0x6e,
|
||||
0x00, 0x70, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x78,
|
||||
0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x82,
|
||||
0x00, 0x84, 0x00, 0x86, 0x00, 0x88, 0x00, 0x8a, 0x00, 0x8c,
|
||||
0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96,
|
||||
0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa0,
|
||||
0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa,
|
||||
0x00, 0xac, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4,
|
||||
0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbe,
|
||||
0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc8,
|
||||
0x00, 0xca, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd2,
|
||||
0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdc,
|
||||
0x00, 0xde, 0x00, 0xe0, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6,
|
||||
0x00, 0xe8, 0x00, 0xea, 0x00, 0xec, 0x00, 0xee, 0x00, 0xf0,
|
||||
0x00, 0xf2, 0x00, 0xf4, 0x00, 0xf6, 0x00, 0xf8, 0x00, 0xfa,
|
||||
0x00, 0xfc, 0x00, 0xfe, 0x01, 0x01, 0x01, 0x03, 0x01, 0x05,
|
||||
0x01, 0x07, 0x01, 0x09, 0x01, 0x0b, 0x01, 0x0d, 0x01, 0x0f,
|
||||
0x01, 0x11, 0x01, 0x13, 0x01, 0x15, 0x01, 0x17, 0x01, 0x19,
|
||||
0x01, 0x1b, 0x01, 0x1d, 0x01, 0x1f, 0x01, 0x21, 0x01, 0x23,
|
||||
0x01, 0x25, 0x01, 0x27, 0x01, 0x29, 0x01, 0x2b, 0x01, 0x2d,
|
||||
0x01, 0x2f, 0x01, 0x31, 0x01, 0x33, 0x01, 0x35, 0x01, 0x37,
|
||||
0x01, 0x39, 0x01, 0x3b, 0x01, 0x3d, 0x01, 0x3f, 0x01, 0x41,
|
||||
0x01, 0x43, 0x01, 0x45, 0x01, 0x47, 0x01, 0x49, 0x01, 0x4b,
|
||||
0x01, 0x4d, 0x01, 0x4f, 0x01, 0x51, 0x01, 0x53, 0x01, 0x55,
|
||||
0x01, 0x57, 0x01, 0x59, 0x01, 0x5b, 0x01, 0x5d, 0x01, 0x5f,
|
||||
0x01, 0x61, 0x01, 0x63, 0x01, 0x65, 0x01, 0x67, 0x01, 0x69,
|
||||
0x01, 0x6b, 0x01, 0x6d, 0x01, 0x6f, 0x01, 0x71, 0x01, 0x73,
|
||||
0x01, 0x75, 0x01, 0x77, 0x01, 0x79, 0x01, 0x7b, 0x01, 0x7d,
|
||||
0x01, 0x7f, 0x01, 0x81, 0x01, 0x83, 0x01, 0x85, 0x01, 0x87,
|
||||
0x01, 0x89, 0x01, 0x8b, 0x01, 0x8d, 0x01, 0x8f, 0x01, 0x91,
|
||||
0x01, 0x93, 0x01, 0x95, 0x01, 0x97, 0x01, 0x99, 0x01, 0x9b,
|
||||
0x01, 0x9d, 0x01, 0x9f, 0x01, 0xa1, 0x01, 0xa3, 0x01, 0xa5,
|
||||
0x01, 0xa7, 0x01, 0xa9, 0x01, 0xab, 0x01, 0xad, 0x01, 0xaf,
|
||||
0x01, 0xb1, 0x01, 0xb3, 0x01, 0xb5, 0x01, 0xb7, 0x01, 0xb9,
|
||||
0x01, 0xbb, 0x01, 0xbd, 0x01, 0xbf, 0x01, 0xc1, 0x01, 0xc3,
|
||||
0x01, 0xc5, 0x01, 0xc7, 0x01, 0xc9, 0x01, 0xcb, 0x01, 0xcd,
|
||||
0x01, 0xcf, 0x01, 0xd1, 0x01, 0xd3, 0x01, 0xd5, 0x01, 0xd7,
|
||||
0x01, 0xd9, 0x01, 0xdb, 0x01, 0xdd, 0x01, 0xdf, 0x01, 0xe1,
|
||||
0x01, 0xe3, 0x01, 0xe5, 0x01, 0xe7, 0x01, 0xe9, 0x01, 0xeb,
|
||||
0x01, 0xed, 0x01, 0xef, 0x01, 0xf1, 0x01, 0xf3, 0x01, 0xf5,
|
||||
0x01, 0xf7, 0x01, 0xf9, 0x01, 0xfb, 0x01, 0xfd, 0x02, 0x00,
|
||||
0x02, 0x02, 0x02, 0x04, 0x02, 0x06, 0x02, 0x08, 0x02, 0x0a,
|
||||
0x02, 0x0c, 0x02, 0x0e, 0x02, 0x10, 0x02, 0x12, 0x02, 0x14,
|
||||
0x02, 0x16, 0x02, 0x18, 0x02, 0x1a, 0x02, 0x1c, 0x02, 0x1e,
|
||||
0x02, 0x20, 0x02, 0x22, 0x02, 0x24, 0x02, 0x26, 0x02, 0x28,
|
||||
0x02, 0x2a, 0x02, 0x2c, 0x02, 0x2e, 0x02, 0x30, 0x02, 0x32,
|
||||
0x02, 0x34, 0x02, 0x36, 0x02, 0x38, 0x02, 0x3a, 0x02, 0x3c,
|
||||
0x02, 0x3e, 0x02, 0x40, 0x02, 0x42, 0x02, 0x44, 0x02, 0x46,
|
||||
0x02, 0x48, 0x02, 0x4a, 0x02, 0x4c, 0x02, 0x4e, 0x02, 0x50,
|
||||
0x02, 0x52, 0x02, 0x54, 0x02, 0x56, 0x02, 0x58, 0x02, 0x5a,
|
||||
0x02, 0x5c, 0x02, 0x5e, 0x02, 0x60, 0x02, 0x62, 0x02, 0x64,
|
||||
0x02, 0x66, 0x02, 0x68, 0x02, 0x6a, 0x02, 0x6c, 0x02, 0x6e,
|
||||
0x02, 0x70, 0x02, 0x72, 0x02, 0x74, 0x02, 0x76, 0x02, 0x78,
|
||||
0x02, 0x7a, 0x02, 0x7c, 0x02, 0x7e, 0x02, 0x80, 0x02, 0x82,
|
||||
0x02, 0x84, 0x02, 0x86, 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c,
|
||||
0x02, 0x8e, 0x02, 0x90, 0x02, 0x92, 0x02, 0x94, 0x02, 0x96,
|
||||
0x02, 0x98, 0x02, 0x9a, 0x02, 0x9c, 0x02, 0x9e, 0x02, 0xa0,
|
||||
0x02, 0xa2, 0x02, 0xa4, 0x02, 0xa6, 0x02, 0xa8, 0x02, 0xaa,
|
||||
0x02, 0xac, 0x02, 0xae, 0x02, 0xb0, 0x02, 0xb2, 0x02, 0xb4,
|
||||
0x02, 0xb6, 0x02, 0xb8, 0x02, 0xba, 0x02, 0xbc, 0x02, 0xbe,
|
||||
0x02, 0xc0, 0x02, 0xc2, 0x02, 0xc4, 0x02, 0xc6, 0x02, 0xc8,
|
||||
0x02, 0xca, 0x02, 0xcc, 0x02, 0xce, 0x02, 0xd0, 0x02, 0xd2,
|
||||
0x02, 0xd4, 0x02, 0xd6, 0x02, 0xd8, 0x02, 0xda, 0x02, 0xdc,
|
||||
0x02, 0xde, 0x02, 0xe0, 0x02, 0xe2, 0x02, 0xe4, 0x02, 0xe6,
|
||||
0x02, 0xe8, 0x02, 0xea, 0x02, 0xec, 0x02, 0xee, 0x02, 0xf0,
|
||||
0x02, 0xf2, 0x02, 0xf4, 0x02, 0xf6, 0x02, 0xf8, 0x02, 0xfa,
|
||||
0x02, 0xfc, 0x02, 0xfe, 0x03, 0x01, 0x03, 0x03, 0x03, 0x05,
|
||||
0x03, 0x07, 0x03, 0x09, 0x03, 0x0b, 0x03, 0x0d, 0x03, 0x0f,
|
||||
0x03, 0x11, 0x03, 0x13, 0x03, 0x15, 0x03, 0x17, 0x03, 0x19,
|
||||
0x03, 0x1b, 0x03, 0x1d, 0x03, 0x1f, 0x03, 0x21, 0x03, 0x23,
|
||||
0x03, 0x25, 0x03, 0x27, 0x03, 0x29, 0x03, 0x2b, 0x03, 0x2d,
|
||||
0x03, 0x2f, 0x03, 0x31, 0x03, 0x33, 0x03, 0x35, 0x03, 0x37,
|
||||
0x03, 0x39, 0x03, 0x3b, 0x03, 0x3d, 0x03, 0x3f, 0x03, 0x41,
|
||||
0x03, 0x43, 0x03, 0x45, 0x03, 0x47, 0x03, 0x49, 0x03, 0x4b,
|
||||
0x03, 0x4d, 0x03, 0x4f, 0x03, 0x51, 0x03, 0x53, 0x03, 0x55,
|
||||
0x03, 0x57, 0x03, 0x59, 0x03, 0x5b, 0x03, 0x5d, 0x03, 0x5f,
|
||||
0x03, 0x61, 0x03, 0x63, 0x03, 0x65, 0x03, 0x67, 0x03, 0x69,
|
||||
0x03, 0x6b, 0x03, 0x6d, 0x03, 0x6f, 0x03, 0x71, 0x03, 0x73,
|
||||
0x03, 0x75, 0x03, 0x77, 0x03, 0x79, 0x03, 0x7b, 0x03, 0x7d,
|
||||
0x03, 0x7f, 0x03, 0x81, 0x03, 0x83, 0x03, 0x85, 0x03, 0x87,
|
||||
0x03, 0x89, 0x03, 0x8b, 0x03, 0x8d, 0x03, 0x8f, 0x03, 0x91,
|
||||
0x03, 0x93, 0x03, 0x95, 0x03, 0x97, 0x03, 0x99, 0x03, 0x9b,
|
||||
0x03, 0x9d, 0x03, 0x9f, 0x03, 0xa1, 0x03, 0xa3, 0x03, 0xa5,
|
||||
0x03, 0xa7, 0x03, 0xa9, 0x03, 0xab, 0x03, 0xad, 0x03, 0xaf,
|
||||
0x03, 0xb1, 0x03, 0xb3, 0x03, 0xb5, 0x03, 0xb7, 0x03, 0xb9,
|
||||
0x03, 0xbb, 0x03, 0xbd, 0x03, 0xbf, 0x03, 0xc1, 0x03, 0xc3,
|
||||
0x03, 0xc5, 0x03, 0xc7, 0x03, 0xc9, 0x03, 0xcb, 0x03, 0xcd,
|
||||
0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xd7,
|
||||
0x03, 0xd9, 0x03, 0xdb, 0x03, 0xdd, 0x03, 0xdf, 0x03, 0xe1,
|
||||
0x03, 0xe3, 0x03, 0xe5, 0x03, 0xe7, 0x03, 0xe9, 0x03, 0xeb,
|
||||
0x03, 0xed, 0x03, 0xef, 0x03, 0xf1, 0x03, 0xf3, 0x03, 0xf5,
|
||||
0x03, 0xf7, 0x03, 0xf9, 0x03, 0xfb, 0x03, 0xfd, 0x04, 0x00,
|
||||
0x04, 0x02, 0x04, 0x04, 0x04, 0x06, 0x04, 0x08, 0x04, 0x0a,
|
||||
0x04, 0x0c, 0x04, 0x0e, 0x04, 0x10, 0x04, 0x12, 0x04, 0x14,
|
||||
0x04, 0x16, 0x04, 0x18, 0x04, 0x1a, 0x04, 0x1c, 0x04, 0x1e,
|
||||
0x04, 0x20, 0x04, 0x22, 0x04, 0x24, 0x04, 0x26, 0x04, 0x28,
|
||||
0x04, 0x2a, 0x04, 0x2c, 0x04, 0x2e, 0x04, 0x30, 0x04, 0x32,
|
||||
0x04, 0x34, 0x04, 0x36, 0x04, 0x38, 0x04, 0x3a, 0x04, 0x3c,
|
||||
0x04, 0x3e, 0x04, 0x40, 0x04, 0x42, 0x04, 0x44, 0x04, 0x46,
|
||||
0x04, 0x48, 0x04, 0x4a, 0x04, 0x4c, 0x04, 0x4e, 0x04, 0x50,
|
||||
0x04, 0x52, 0x04, 0x54, 0x04, 0x56, 0x04, 0x58, 0x04, 0x5a,
|
||||
0x04, 0x5c, 0x04, 0x5e, 0x04, 0x60, 0x04, 0x62, 0x04, 0x64,
|
||||
0x04, 0x66, 0x04, 0x68, 0x04, 0x6a, 0x04, 0x6c, 0x04, 0x6e,
|
||||
0x04, 0x70, 0x04, 0x72, 0x04, 0x74, 0x04, 0x76, 0x04, 0x78,
|
||||
0x04, 0x7a, 0x04, 0x7c, 0x04, 0x7e, 0x04, 0x80, 0x04, 0x82,
|
||||
0x04, 0x84, 0x04, 0x86, 0x04, 0x88, 0x04, 0x8a, 0x04, 0x8c,
|
||||
0x04, 0x8e, 0x04, 0x90, 0x04, 0x92, 0x04, 0x94, 0x04, 0x96,
|
||||
0x04, 0x98, 0x04, 0x9a, 0x04, 0x9c, 0x04, 0x9e, 0x04, 0xa0,
|
||||
0x04, 0xa2, 0x04, 0xa4, 0x04, 0xa6, 0x04, 0xa8, 0x04, 0xaa,
|
||||
0x04, 0xac, 0x04, 0xae, 0x04, 0xb0, 0x04, 0xb2, 0x04, 0xb4,
|
||||
0x04, 0xb6, 0x04, 0xb8, 0x04, 0xba, 0x04, 0xbc, 0x04, 0xbe,
|
||||
0x04, 0xc0, 0x04, 0xc2, 0x04, 0xc4, 0x04, 0xc6, 0x04, 0xc8,
|
||||
0x04, 0xca, 0x04, 0xcc, 0x04, 0xce, 0x04, 0xd0, 0x04, 0xd2,
|
||||
0x04, 0xd4, 0x04, 0xd6, 0x04, 0xd8, 0x04, 0xda, 0x04, 0xdc,
|
||||
0x04, 0xde, 0x04, 0xe0, 0x04, 0xe2, 0x04, 0xe4, 0x04, 0xe6,
|
||||
0x04, 0xe8, 0x04, 0xea, 0x04, 0xec, 0x04, 0xee, 0x04, 0xf0,
|
||||
0x04, 0xf2, 0x04, 0xf4, 0x04, 0xf6, 0x04, 0xf8, 0x04, 0xfa,
|
||||
0x04, 0xfc, 0x04, 0xfe, 0x05, 0x01, 0x05, 0x03, 0x05, 0x05,
|
||||
0x05, 0x07, 0x05, 0x09, 0x05, 0x0b, 0x05, 0x0d, 0x05, 0x0f,
|
||||
0x05, 0x11, 0x05, 0x13, 0x05, 0x15, 0x05, 0x17, 0x05, 0x19,
|
||||
0x05, 0x1b, 0x05, 0x1d, 0x05, 0x1f, 0x05, 0x21, 0x05, 0x23,
|
||||
0x05, 0x25, 0x05, 0x27, 0x05, 0x29, 0x05, 0x2b, 0x05, 0x2d,
|
||||
0x05, 0x2f, 0x05, 0x31, 0x05, 0x33, 0x05, 0x35, 0x05, 0x37,
|
||||
0x05, 0x39, 0x05, 0x3b, 0x05, 0x3d, 0x05, 0x3f, 0x05, 0x41,
|
||||
0x05, 0x43, 0x05, 0x45, 0x05, 0x47, 0x05, 0x49, 0x05, 0x4b,
|
||||
0x05, 0x4d, 0x05, 0x4f, 0x05, 0x51, 0x05, 0x53, 0x05, 0x55,
|
||||
0x05, 0x57, 0x05, 0x59, 0x05, 0x5b, 0x05, 0x5d, 0x05, 0x5f,
|
||||
0x05, 0x61, 0x05, 0x63, 0x05, 0x65, 0x05, 0x67, 0x05, 0x69,
|
||||
0x05, 0x6b, 0x05, 0x6d, 0x05, 0x6f, 0x05, 0x71, 0x05, 0x73,
|
||||
0x05, 0x75, 0x05, 0x77, 0x05, 0x79, 0x05, 0x7b, 0x05, 0x7d,
|
||||
0x05, 0x7f, 0x05, 0x81, 0x05, 0x83, 0x05, 0x85, 0x05, 0x87,
|
||||
0x05, 0x89, 0x05, 0x8b, 0x05, 0x8d, 0x05, 0x8f, 0x05, 0x91,
|
||||
0x05, 0x93, 0x05, 0x95, 0x05, 0x97, 0x05, 0x99, 0x05, 0x9b,
|
||||
0x05, 0x9d, 0x05, 0x9f, 0x05, 0xa1, 0x05, 0xa3, 0x05, 0xa5,
|
||||
0x05, 0xa7, 0x05, 0xa9, 0x05, 0xab, 0x05, 0xad, 0x05, 0xaf,
|
||||
0x05, 0xb1, 0x05, 0xb3, 0x05, 0xb5, 0x05, 0xb7, 0x05, 0xb9,
|
||||
0x05, 0xbb, 0x05, 0xbd, 0x05, 0xbf, 0x05, 0xc1, 0x05, 0xc3,
|
||||
0x05, 0xc5, 0x05, 0xc7, 0x05, 0xc9, 0x05, 0xcb, 0x05, 0xcd,
|
||||
0x05, 0xcf, 0x05, 0xd1, 0x05, 0xd3, 0x05, 0xd5, 0x05, 0xd7,
|
||||
0x05, 0xd9, 0x05, 0xdb, 0x05, 0xdd, 0x05, 0xdf, 0x05, 0xe1,
|
||||
0x05, 0xe3, 0x05, 0xe5, 0x05, 0xe7, 0x05, 0xe9, 0x05, 0xeb,
|
||||
0x05, 0xed, 0x05, 0xef, 0x05, 0xf1, 0x05, 0xf3, 0x05, 0xf5,
|
||||
0x05, 0xf7, 0x05, 0xf9, 0x05, 0xfb, 0x05, 0xfd, 0x06, 0x00,
|
||||
0x06, 0x02, 0x06, 0x04, 0x06, 0x06, 0x06, 0x08, 0x06, 0x0a,
|
||||
0x06, 0x0c, 0x06, 0x0e, 0x06, 0x10, 0x06, 0x12, 0x06, 0x14,
|
||||
0x06, 0x16, 0x06, 0x18, 0x06, 0x1a, 0x06, 0x1c, 0x06, 0x1e,
|
||||
0x06, 0x20, 0x06, 0x22, 0x06, 0x24, 0x06, 0x26, 0x06, 0x28,
|
||||
0x06, 0x2a, 0x06, 0x2c, 0x06, 0x2e, 0x06, 0x30, 0x06, 0x32,
|
||||
0x06, 0x34, 0x06, 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, 0x3c,
|
||||
0x06, 0x3e, 0x06, 0x40, 0x06, 0x42, 0x06, 0x44, 0x06, 0x46,
|
||||
0x06, 0x48, 0x06, 0x4a, 0x06, 0x4c, 0x06, 0x4e, 0x06, 0x50,
|
||||
0x06, 0x52, 0x06, 0x54, 0x06, 0x56, 0x06, 0x58, 0x06, 0x5a,
|
||||
0x06, 0x5c, 0x06, 0x5e, 0x06, 0x60, 0x06, 0x62, 0x06, 0x64,
|
||||
0x06, 0x66, 0x06, 0x68, 0x06, 0x6a, 0x06, 0x6c, 0x06, 0x6e,
|
||||
0x06, 0x70, 0x06, 0x72, 0x06, 0x74, 0x06, 0x76, 0x06, 0x78,
|
||||
};
|
||||
|
||||
void stress_clear_ctx_reusable_var(struct com_stress_test_ctx *ctx);
|
||||
|
||||
void com_stress_print_report(const struct com_stress_test_ctx test_ctxs[]);
|
||||
|
||||
int stress_fill_mbuf_with_pattern(struct os_mbuf *om, uint16_t len);
|
||||
|
||||
void stress_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu);
|
||||
|
||||
void stress_l2cap_coc_accept(uint16_t peer_mtu, struct ble_l2cap_chan *chan);
|
||||
|
||||
void stress_start_timer(uint32_t timeout_ms, os_event_fn *ev_cb);
|
||||
|
||||
int64_t stress_calc_bit_rate(int64_t us, int64_t bytes_num);
|
||||
|
||||
void stress_find_svc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid,
|
||||
stress_gatt_disc_end_fn *disc_end_fn);
|
||||
void stress_find_chr_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid,
|
||||
const ble_uuid_t *chr_uuid,
|
||||
stress_gatt_disc_end_fn *disc_end_fn);
|
||||
|
||||
void stress_find_dsc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid,
|
||||
const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid,
|
||||
stress_gatt_disc_end_fn *disc_end_fn);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //BLE_TGT_STRESS_H
|
||||
155
src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.c
Normal file
155
src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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 "stress_gatt.h"
|
||||
|
||||
uint16_t hrs_hrm_handle = 0xffff;
|
||||
|
||||
static int
|
||||
stress_gatt_access_cb(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[] = {
|
||||
{
|
||||
/* Service: Heart-rate */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(STRESS_GATT_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) {
|
||||
{
|
||||
/* Characteristic: read test */
|
||||
.uuid = BLE_UUID16_DECLARE(STRESS_GATT_READ_UUID),
|
||||
.access_cb = stress_gatt_access_cb,
|
||||
.val_handle = &hrs_hrm_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
/* Characteristic: write test */
|
||||
.uuid = BLE_UUID16_DECLARE(STRESS_GATT_WRITE_UUID),
|
||||
.access_cb = stress_gatt_access_cb,
|
||||
.val_handle = &hrs_hrm_handle,
|
||||
.flags = BLE_GATT_CHR_F_WRITE,
|
||||
},
|
||||
{
|
||||
/* Characteristic: notify test */
|
||||
.uuid = BLE_UUID16_DECLARE(STRESS_GATT_NOTIFY_UUID),
|
||||
.access_cb = stress_gatt_access_cb,
|
||||
.val_handle = &hrs_hrm_handle,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
},
|
||||
{
|
||||
/* Characteristic: indicate test */
|
||||
.uuid = BLE_UUID16_DECLARE(STRESS_GATT_INDICATE_UUID),
|
||||
.access_cb = stress_gatt_access_cb,
|
||||
.val_handle = &hrs_hrm_handle,
|
||||
.flags = BLE_GATT_CHR_F_INDICATE,
|
||||
},
|
||||
{
|
||||
0, /* No more characteristics in this service */
|
||||
},}
|
||||
},
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
stress_gatt_access_cb(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
/* Sensor location, set to "Chest" */
|
||||
static uint8_t chr_value[] = "Hello";
|
||||
uint16_t uuid;
|
||||
int rc;
|
||||
|
||||
//chr_value = (uint8_t)rand() % 256;
|
||||
uuid = ble_uuid_u16(ctxt->chr->uuid);
|
||||
|
||||
switch(uuid){
|
||||
case STRESS_GATT_READ_UUID:
|
||||
MODLOG_DFLT(INFO, "GATT Read event\n");
|
||||
rc = os_mbuf_append(ctxt->om, &chr_value, sizeof(chr_value));
|
||||
assert(rc == 0);
|
||||
//return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
return 0;
|
||||
case STRESS_GATT_WRITE_UUID:
|
||||
MODLOG_DFLT(INFO, "GATT Write event\n");
|
||||
print_mbuf(ctxt->om);
|
||||
return 0;
|
||||
case STRESS_GATT_NOTIFY_UUID:
|
||||
MODLOG_DFLT(INFO, "GATT Notify event\n");
|
||||
return 0;
|
||||
case STRESS_GATT_INDICATE_UUID:
|
||||
MODLOG_DFLT(INFO, "GATT Indicate event\n");
|
||||
return 0;
|
||||
default:
|
||||
MODLOG_DFLT(ERROR, "GATT UUID does not exist\n");
|
||||
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;
|
||||
}
|
||||
54
src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.h
Normal file
54
src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.h
Normal file
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef BLE_TGT_STRESS_GATT_H
|
||||
#define BLE_TGT_STRESS_GATT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern uint16_t hrs_hrm_handle;
|
||||
|
||||
/* Heart-rate configuration */
|
||||
#define STRESS_GATT_UUID 0xC0DE
|
||||
#define STRESS_GATT_READ_UUID 0xC1DE
|
||||
#define STRESS_GATT_WRITE_UUID 0xC2DE
|
||||
#define STRESS_GATT_INDICATE_UUID 0xC3DE
|
||||
#define STRESS_GATT_NOTIFY_UUID 0xC4DE
|
||||
|
||||
int gatt_svr_init(void);
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif //BLE_TGT_STRESS_GATT_H
|
||||
1671
src/libs/mynewt-nimble/apps/blestress/src/tx_stress.c
Normal file
1671
src/libs/mynewt-nimble/apps/blestress/src/tx_stress.c
Normal file
File diff suppressed because it is too large
Load diff
49
src/libs/mynewt-nimble/apps/blestress/src/tx_stress.h
Normal file
49
src/libs/mynewt-nimble/apps/blestress/src/tx_stress.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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_STRESS_TX_H
|
||||
#define _BLE_STRESS_TX_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <host/ble_gap.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "stress.h"
|
||||
#include "stress_gatt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Scan and execute tests one by one.
|
||||
*/
|
||||
void tx_stress_start_auto();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //_BLE_STRESS_TX_H
|
||||
74
src/libs/mynewt-nimble/apps/blestress/syscfg.yml
Normal file
74
src/libs/mynewt-nimble/apps/blestress/syscfg.yml
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Settings this app defines.
|
||||
syscfg.defs:
|
||||
BLE_STRESS_TEST_ROLE:
|
||||
description: 0 - TX device, 1 - RX device
|
||||
value: 0
|
||||
|
||||
BLE_STRESS_REPEAT:
|
||||
description: Number of times to repeat each stress test use case
|
||||
value: 50
|
||||
|
||||
BLE_STRESS_UUID_BASE:
|
||||
description: Part of the test UUID that is specific to the current
|
||||
device couple.
|
||||
value: ((uint8_t[13]){0xA5, 0x4A, 0xB4, 0x44, 0xC3, 0xBF, 0xB5,
|
||||
0xF8, 0xF9, 0x42, 0x83, 0xA1, 0xDA})
|
||||
|
||||
# Settings this app overrides.
|
||||
syscfg.vals:
|
||||
# Change these settings:
|
||||
|
||||
# Set 0 to print all debug logs, but keep in mind that plenty of
|
||||
# adv packets will be lost during scan tests.
|
||||
LOG_LEVEL: 1
|
||||
|
||||
# The maximum number of concurrent connections. For some devices, this
|
||||
# value will need to be reduced due to the RAM capacity.
|
||||
BLE_MAX_CONNECTIONS: 50
|
||||
|
||||
# Should not change these settings:
|
||||
|
||||
# Enable Extended Advertising
|
||||
BLE_EXT_ADV: 1
|
||||
|
||||
# Max advertising data size
|
||||
BLE_EXT_ADV_MAX_SIZE: 1650
|
||||
|
||||
# Number of multi-advertising instances. Note that due
|
||||
# to historical reasons total number of advertising
|
||||
# instances is BLE_MULTI_ADV_INSTANCES + 1 as instance
|
||||
# 0 is always available
|
||||
BLE_MULTI_ADV_INSTANCES: 2
|
||||
|
||||
# Controller uses msys pool for storing advertising data and scan responses.
|
||||
# Since we advertise a lot of data (~4k in total) at the same time we need
|
||||
# to increase block count.
|
||||
MSYS_1_BLOCK_COUNT: 50
|
||||
|
||||
#
|
||||
BLE_L2CAP_COC_MAX_NUM: 2
|
||||
|
||||
# Enable 2M PHY
|
||||
BLE_LL_CFG_FEAT_LE_2M_PHY: 1
|
||||
|
||||
# Enable CODED PHY
|
||||
BLE_LL_CFG_FEAT_LE_CODED_PHY: 1
|
||||
39
src/libs/mynewt-nimble/apps/btshell/pkg.yml
Normal file
39
src/libs/mynewt-nimble/apps/btshell/pkg.yml
Normal file
|
|
@ -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/btshell
|
||||
pkg.type: app
|
||||
pkg.description: Shell application exposing the nimble GAP and GATT.
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@apache-mynewt-core/kernel/os"
|
||||
- "@apache-mynewt-core/sys/log/full"
|
||||
- "@apache-mynewt-core/sys/log/modlog"
|
||||
- "@apache-mynewt-core/sys/stats/full"
|
||||
- "@apache-mynewt-core/sys/console/full"
|
||||
- "@apache-mynewt-core/sys/shell"
|
||||
- nimble/host
|
||||
- nimble/host/services/gap
|
||||
- nimble/host/services/gatt
|
||||
- nimble/host/store/ram
|
||||
- nimble/transport
|
||||
|
||||
pkg.deps.BTSHELL_ANS:
|
||||
- nimble/host/services/ans
|
||||
212
src/libs/mynewt-nimble/apps/btshell/src/btshell.h
Normal file
212
src/libs/mynewt-nimble/apps/btshell/src/btshell.h
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* 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_BTSHELL_PRIV_
|
||||
#define H_BTSHELL_PRIV_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "os/mynewt.h"
|
||||
#include "nimble/ble.h"
|
||||
#include "nimble/nimble_opt.h"
|
||||
#include "modlog/modlog.h"
|
||||
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_gap.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ble_gap_white_entry;
|
||||
struct ble_hs_adv_fields;
|
||||
struct ble_gap_upd_params;
|
||||
struct ble_gap_conn_params;
|
||||
struct hci_adv_params;
|
||||
struct ble_l2cap_sig_update_req;
|
||||
struct ble_l2cap_sig_update_params;
|
||||
union ble_store_value;
|
||||
union ble_store_key;
|
||||
struct ble_gap_adv_params;
|
||||
struct ble_gap_conn_desc;
|
||||
struct ble_gap_disc_params;
|
||||
|
||||
struct btshell_dsc {
|
||||
SLIST_ENTRY(btshell_dsc) next;
|
||||
struct ble_gatt_dsc dsc;
|
||||
};
|
||||
SLIST_HEAD(btshell_dsc_list, btshell_dsc);
|
||||
|
||||
struct btshell_chr {
|
||||
SLIST_ENTRY(btshell_chr) next;
|
||||
struct ble_gatt_chr chr;
|
||||
|
||||
struct btshell_dsc_list dscs;
|
||||
};
|
||||
SLIST_HEAD(btshell_chr_list, btshell_chr);
|
||||
|
||||
struct btshell_svc {
|
||||
SLIST_ENTRY(btshell_svc) next;
|
||||
struct ble_gatt_svc svc;
|
||||
struct btshell_chr_list chrs;
|
||||
bool discovered;
|
||||
};
|
||||
|
||||
SLIST_HEAD(btshell_svc_list, btshell_svc);
|
||||
|
||||
struct btshell_l2cap_coc {
|
||||
SLIST_ENTRY(btshell_l2cap_coc) next;
|
||||
struct ble_l2cap_chan *chan;
|
||||
bool stalled;
|
||||
};
|
||||
|
||||
SLIST_HEAD(btshell_l2cap_coc_list, btshell_l2cap_coc);
|
||||
|
||||
struct btshell_conn {
|
||||
uint16_t handle;
|
||||
struct btshell_svc_list svcs;
|
||||
struct btshell_l2cap_coc_list coc_list;
|
||||
};
|
||||
|
||||
struct btshell_scan_opts {
|
||||
uint16_t limit;
|
||||
uint8_t ignore_legacy:1;
|
||||
uint8_t periodic_only:1;
|
||||
};
|
||||
|
||||
extern struct btshell_conn btshell_conns[MYNEWT_VAL(BLE_MAX_CONNECTIONS)];
|
||||
extern int btshell_num_conns;
|
||||
|
||||
int btshell_exchange_mtu(uint16_t conn_handle);
|
||||
int btshell_disc_svcs(uint16_t conn_handle);
|
||||
int btshell_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid);
|
||||
int btshell_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
|
||||
uint16_t end_handle);
|
||||
int btshell_disc_all_chrs_in_svc(uint16_t conn_handle, struct btshell_svc *svc);
|
||||
int btshell_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
|
||||
uint16_t end_handle, const ble_uuid_t *uuid);
|
||||
int btshell_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
|
||||
uint16_t end_handle);
|
||||
int btshell_disc_full(uint16_t conn_handle);
|
||||
int btshell_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
|
||||
uint16_t end_handle);
|
||||
int btshell_read(uint16_t conn_handle, uint16_t attr_handle);
|
||||
int btshell_read_long(uint16_t conn_handle, uint16_t attr_handle,
|
||||
uint16_t offset);
|
||||
int btshell_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
|
||||
uint16_t end_handle, const ble_uuid_t *uuid);
|
||||
int btshell_read_mult(uint16_t conn_handle, uint16_t *attr_handles,
|
||||
int num_attr_handles);
|
||||
int btshell_write(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct os_mbuf *om);
|
||||
int btshell_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct os_mbuf *om);
|
||||
int btshell_write_long(uint16_t conn_handle, uint16_t attr_handle,
|
||||
uint16_t offset, struct os_mbuf *om);
|
||||
int btshell_write_reliable(uint16_t conn_handle,
|
||||
struct ble_gatt_attr *attrs, int num_attrs);
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
int btshell_ext_adv_configure(uint8_t instance,
|
||||
const struct ble_gap_ext_adv_params *params,
|
||||
int8_t *selected_tx_power);
|
||||
int btshell_ext_adv_start(uint8_t instance, int duration,
|
||||
int max_events, bool restart);
|
||||
int btshell_ext_adv_stop(uint8_t instance);
|
||||
#endif
|
||||
int btshell_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr,
|
||||
int32_t duration_ms,
|
||||
const struct ble_gap_adv_params *params,
|
||||
bool restart);
|
||||
int btshell_adv_stop(void);
|
||||
int btshell_conn_initiate(uint8_t own_addr_type, const ble_addr_t *peer_addr,
|
||||
int32_t duration_ms,
|
||||
struct ble_gap_conn_params *params);
|
||||
int btshell_ext_conn_initiate(uint8_t own_addr_type,
|
||||
const ble_addr_t *peer_addr,
|
||||
int32_t duration_ms,
|
||||
struct ble_gap_conn_params *phy_1m_params,
|
||||
struct ble_gap_conn_params *phy_2m_params,
|
||||
struct ble_gap_conn_params *phy_coded_params);
|
||||
int btshell_conn_cancel(void);
|
||||
int btshell_term_conn(uint16_t conn_handle, uint8_t reason);
|
||||
int btshell_wl_set(ble_addr_t *addrs, int addrs_count);
|
||||
int btshell_scan(uint8_t own_addr_type, int32_t duration_ms,
|
||||
const struct ble_gap_disc_params *disc_params, void *cb_args);
|
||||
int btshell_ext_scan(uint8_t own_addr_type, uint16_t duration, uint16_t period,
|
||||
uint8_t filter_duplicates, uint8_t filter_policy,
|
||||
uint8_t limited,
|
||||
const struct ble_gap_ext_disc_params *uncoded_params,
|
||||
const struct ble_gap_ext_disc_params *coded_params,
|
||||
void *cb_args);
|
||||
int btshell_scan_cancel(void);
|
||||
int btshell_update_conn(uint16_t conn_handle,
|
||||
struct ble_gap_upd_params *params);
|
||||
void btshell_notify(uint16_t attr_handle);
|
||||
int btshell_datalen(uint16_t conn_handle, uint16_t tx_octets,
|
||||
uint16_t tx_time);
|
||||
int btshell_l2cap_update(uint16_t conn_handle,
|
||||
struct ble_l2cap_sig_update_params *params);
|
||||
int btshell_sec_start(uint16_t conn_handle);
|
||||
int btshell_sec_pair(uint16_t conn_handle);
|
||||
int btshell_sec_unpair(ble_addr_t *peer_addr);
|
||||
int btshell_sec_restart(uint16_t conn_handle, uint8_t key_size,
|
||||
uint8_t *ltk, uint16_t ediv,
|
||||
uint64_t rand_val, int auth);
|
||||
int btshell_tx_start(uint16_t conn_handle, uint16_t len, uint16_t rate,
|
||||
uint16_t num);
|
||||
void btshell_tx_stop(void);
|
||||
int btshell_rssi(uint16_t conn_handle, int8_t *out_rssi);
|
||||
int btshell_l2cap_create_srv(uint16_t psm, uint16_t mtu, int accept_response);
|
||||
int btshell_l2cap_connect(uint16_t conn, uint16_t psm, uint16_t mtu, uint8_t num);
|
||||
int btshell_l2cap_disconnect(uint16_t conn, uint16_t idx);
|
||||
int btshell_l2cap_send(uint16_t conn, uint16_t idx, uint16_t bytes);
|
||||
int btshell_l2cap_reconfig(uint16_t conn_handle, uint16_t mtu,
|
||||
uint8_t num, uint8_t idxs[]);
|
||||
|
||||
int btshell_gap_event(struct ble_gap_event *event, void *arg);
|
||||
void btshell_sync_stats(uint16_t handle);
|
||||
|
||||
/** GATT server. */
|
||||
#define GATT_SVR_SVC_ALERT_UUID 0x1811
|
||||
#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47
|
||||
#define GATT_SVR_CHR_NEW_ALERT 0x2A46
|
||||
#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48
|
||||
#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID 0x2A45
|
||||
#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT 0x2A44
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
void gatt_svr_print_svcs(void);
|
||||
|
||||
/** Misc. */
|
||||
void print_bytes(const uint8_t *bytes, int len);
|
||||
void print_mbuf(const struct os_mbuf *om);
|
||||
void print_addr(const void *addr);
|
||||
void print_uuid(const ble_uuid_t *uuid);
|
||||
int svc_is_empty(const struct btshell_svc *svc);
|
||||
uint16_t chr_end_handle(const struct btshell_svc *svc,
|
||||
const struct btshell_chr *chr);
|
||||
int chr_is_empty(const struct btshell_svc *svc, const struct btshell_chr *chr);
|
||||
void print_conn_desc(const struct ble_gap_conn_desc *desc);
|
||||
void print_svc(struct btshell_svc *svc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
4659
src/libs/mynewt-nimble/apps/btshell/src/cmd.c
Normal file
4659
src/libs/mynewt-nimble/apps/btshell/src/cmd.c
Normal file
File diff suppressed because it is too large
Load diff
68
src/libs/mynewt-nimble/apps/btshell/src/cmd.h
Normal file
68
src/libs/mynewt-nimble/apps/btshell/src/cmd.h
Normal file
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef CMD_H
|
||||
#define CMD_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "host/ble_uuid.h"
|
||||
|
||||
struct kv_pair {
|
||||
char *key;
|
||||
int val;
|
||||
};
|
||||
|
||||
uint32_t parse_arg_time_dflt(char *name, int step, uint32_t dflt, int *out_status);
|
||||
const struct kv_pair *parse_kv_find(const struct kv_pair *kvs, char *name);
|
||||
int parse_arg_find_idx(const char *key);
|
||||
char *parse_arg_extract(const char *key);
|
||||
long parse_arg_long_bounds(char *name, long min, long max, int *out_status);
|
||||
long parse_arg_long_bounds_dflt(char *name, long min, long max,
|
||||
long dflt, int *out_status);
|
||||
uint64_t parse_arg_uint64_bounds(char *name, uint64_t min,
|
||||
uint64_t max, int *out_status);
|
||||
long parse_arg_long(char *name, int *staus);
|
||||
uint8_t parse_arg_bool(char *name, int *status);
|
||||
uint8_t parse_arg_bool_dflt(char *name, uint8_t dflt, int *out_status);
|
||||
uint8_t parse_arg_uint8(char *name, int *status);
|
||||
uint8_t parse_arg_uint8_dflt(char *name, uint8_t dflt, int *out_status);
|
||||
uint16_t parse_arg_uint16(char *name, int *status);
|
||||
uint16_t parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status);
|
||||
uint32_t parse_arg_uint32(char *name, int *out_status);
|
||||
uint32_t parse_arg_uint32_dflt(char *name, uint32_t dflt, int *out_status);
|
||||
uint64_t parse_arg_uint64(char *name, int *out_status);
|
||||
int parse_arg_kv(char *name, const struct kv_pair *kvs, int *out_status);
|
||||
int parse_arg_kv_dflt(char *name, const struct kv_pair *kvs, int def_val,
|
||||
int *out_status);
|
||||
int parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len);
|
||||
int parse_arg_uint8_list_with_separator(char *name, char *separator, int max_len,
|
||||
uint8_t *dst, int *out_len);
|
||||
int parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len);
|
||||
int parse_arg_mac(char *name, uint8_t *dst);
|
||||
int parse_arg_addr(char *name, ble_addr_t *addr);
|
||||
int parse_arg_uuid(char *name, ble_uuid_any_t *uuid);
|
||||
int parse_arg_all(int argc, char **argv);
|
||||
int parse_eddystone_url(char *full_url, uint8_t *out_scheme, char *out_body,
|
||||
uint8_t *out_body_len, uint8_t *out_suffix);
|
||||
int cmd_parse_conn_start_end(uint16_t *out_conn, uint16_t *out_start,
|
||||
uint16_t *out_end);
|
||||
|
||||
void cmd_init(void);
|
||||
|
||||
#endif
|
||||
587
src/libs/mynewt-nimble/apps/btshell/src/cmd_gatt.c
Normal file
587
src/libs/mynewt-nimble/apps/btshell/src/cmd_gatt.c
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
/*
|
||||
* 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 <inttypes.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bsp/bsp.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#include "console/console.h"
|
||||
#include "btshell.h"
|
||||
#include "cmd.h"
|
||||
#include "cmd_gatt.h"
|
||||
|
||||
#define CMD_BUF_SZ 256
|
||||
static bssnz_t uint8_t cmd_buf[CMD_BUF_SZ];
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-discover *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_discover_characteristic(int argc, char **argv)
|
||||
{
|
||||
uint16_t start_handle;
|
||||
uint16_t conn_handle;
|
||||
uint16_t end_handle;
|
||||
ble_uuid_any_t uuid;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn start end' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = parse_arg_uuid("uuid", &uuid);
|
||||
if (rc == 0) {
|
||||
rc = btshell_disc_chrs_by_uuid(conn_handle, start_handle, end_handle,
|
||||
&uuid.u);
|
||||
} else if (rc == ENOENT) {
|
||||
rc = btshell_disc_all_chrs(conn_handle, start_handle, end_handle);
|
||||
} else {
|
||||
console_printf("invalid 'uuid' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
if (rc != 0) {
|
||||
console_printf("error discovering characteristics; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cmd_gatt_discover_descriptor(int argc, char **argv)
|
||||
{
|
||||
uint16_t start_handle;
|
||||
uint16_t conn_handle;
|
||||
uint16_t end_handle;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn start end' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = btshell_disc_all_dscs(conn_handle, start_handle, end_handle);
|
||||
if (rc != 0) {
|
||||
console_printf("error discovering descriptors; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cmd_gatt_discover_service(int argc, char **argv)
|
||||
{
|
||||
ble_uuid_any_t uuid;
|
||||
int conn_handle;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn_handle = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = parse_arg_uuid("uuid", &uuid);
|
||||
if (rc == 0) {
|
||||
rc = btshell_disc_svc_by_uuid(conn_handle, &uuid.u);
|
||||
} else if (rc == ENOENT) {
|
||||
rc = btshell_disc_svcs(conn_handle);
|
||||
} else {
|
||||
console_printf("invalid 'uuid' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
console_printf("error discovering services; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cmd_gatt_discover_full(int argc, char **argv)
|
||||
{
|
||||
int conn_handle;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn_handle = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = btshell_disc_full(conn_handle);
|
||||
if (rc != 0) {
|
||||
console_printf("error discovering all; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-exchange-mtu *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_exchange_mtu(int argc, char **argv)
|
||||
{
|
||||
uint16_t conn_handle;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn_handle = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = btshell_exchange_mtu(conn_handle);
|
||||
if (rc != 0) {
|
||||
console_printf("error exchanging mtu; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-notify *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_notify(int argc, char **argv)
|
||||
{
|
||||
uint16_t attr_handle;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
attr_handle = parse_arg_uint16("attr", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'attr' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
btshell_notify(attr_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-read *
|
||||
*****************************************************************************/
|
||||
|
||||
#define CMD_READ_MAX_ATTRS 8
|
||||
|
||||
int
|
||||
cmd_gatt_read(int argc, char **argv)
|
||||
{
|
||||
static uint16_t attr_handles[CMD_READ_MAX_ATTRS];
|
||||
uint16_t conn_handle;
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
uint16_t offset;
|
||||
ble_uuid_any_t uuid;
|
||||
uint8_t num_attr_handles;
|
||||
int is_uuid;
|
||||
int is_long;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn_handle = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
is_long = parse_arg_long("long", &rc);
|
||||
if (rc == ENOENT) {
|
||||
is_long = 0;
|
||||
} else if (rc != 0) {
|
||||
console_printf("invalid 'long' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (num_attr_handles = 0;
|
||||
num_attr_handles < CMD_READ_MAX_ATTRS;
|
||||
num_attr_handles++) {
|
||||
|
||||
attr_handles[num_attr_handles] = parse_arg_uint16("attr", &rc);
|
||||
if (rc == ENOENT) {
|
||||
break;
|
||||
} else if (rc != 0) {
|
||||
console_printf("invalid 'attr' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = parse_arg_uuid("uuid", &uuid);
|
||||
if (rc == ENOENT) {
|
||||
is_uuid = 0;
|
||||
} else if (rc == 0) {
|
||||
is_uuid = 1;
|
||||
} else {
|
||||
console_printf("invalid 'uuid' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
start = parse_arg_uint16("start", &rc);
|
||||
if (rc == ENOENT) {
|
||||
start = 0;
|
||||
} else if (rc != 0) {
|
||||
console_printf("invalid 'start' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
end = parse_arg_uint16("end", &rc);
|
||||
if (rc == ENOENT) {
|
||||
end = 0;
|
||||
} else if (rc != 0) {
|
||||
console_printf("invalid 'end' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
offset = parse_arg_uint16("offset", &rc);
|
||||
if (rc == ENOENT) {
|
||||
offset = 0;
|
||||
} else if (rc != 0) {
|
||||
console_printf("invalid 'offset' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (num_attr_handles == 1) {
|
||||
if (is_long) {
|
||||
rc = btshell_read_long(conn_handle, attr_handles[0], offset);
|
||||
} else {
|
||||
rc = btshell_read(conn_handle, attr_handles[0]);
|
||||
}
|
||||
} else if (num_attr_handles > 1) {
|
||||
rc = btshell_read_mult(conn_handle, attr_handles, num_attr_handles);
|
||||
} else if (is_uuid) {
|
||||
if (start == 0 || end == 0) {
|
||||
rc = EINVAL;
|
||||
} else {
|
||||
rc = btshell_read_by_uuid(conn_handle, start, end, &uuid.u);
|
||||
}
|
||||
} else {
|
||||
rc = EINVAL;
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
console_printf("error reading characteristic; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-service-changed *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_service_changed(int argc, char **argv)
|
||||
{
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
start = parse_arg_uint16("start", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'start' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
end = parse_arg_uint16("end", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'end' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
ble_svc_gatt_changed(start, end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-service-visibility *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_service_visibility(int argc, char **argv)
|
||||
{
|
||||
uint16_t handle;
|
||||
bool vis;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
handle = parse_arg_uint16("handle", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'handle' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
vis = parse_arg_bool("visibility", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'visibility' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
ble_gatts_svc_set_visibility(handle, vis);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-find-included-services *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_find_included_services(int argc, char **argv)
|
||||
{
|
||||
uint16_t start_handle;
|
||||
uint16_t conn_handle;
|
||||
uint16_t end_handle;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cmd_parse_conn_start_end(&conn_handle, &start_handle, &end_handle);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn start end' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = btshell_find_inc_svcs(conn_handle, start_handle, end_handle);
|
||||
if (rc != 0) {
|
||||
console_printf("error finding included services; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-show *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_show(int argc, char **argv)
|
||||
{
|
||||
struct btshell_conn *conn;
|
||||
struct btshell_svc *svc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < btshell_num_conns; i++) {
|
||||
conn = btshell_conns + i;
|
||||
|
||||
console_printf("CONNECTION: handle=%d\n", conn->handle);
|
||||
|
||||
SLIST_FOREACH(svc, &conn->svcs, next) {
|
||||
print_svc(svc);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cmd_gatt_show_local(int argc, char **argv)
|
||||
{
|
||||
gatt_svr_print_svcs();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $gatt-write *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_gatt_write(int argc, char **argv)
|
||||
{
|
||||
struct ble_gatt_attr attrs[MYNEWT_VAL(BLE_GATT_WRITE_MAX_ATTRS)] = { { 0 } };
|
||||
uint16_t attr_handle;
|
||||
uint16_t conn_handle;
|
||||
uint16_t offset;
|
||||
int total_attr_len;
|
||||
int num_attrs;
|
||||
int attr_len;
|
||||
int is_long;
|
||||
int no_rsp;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn_handle = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
no_rsp = parse_arg_bool_dflt("no_rsp", 0, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'no_rsp' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
is_long = parse_arg_bool_dflt("long", 0, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'long' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
total_attr_len = 0;
|
||||
num_attrs = 0;
|
||||
while (1) {
|
||||
attr_handle = parse_arg_uint16("attr", &rc);
|
||||
if (rc == ENOENT) {
|
||||
break;
|
||||
} else if (rc != 0) {
|
||||
rc = -rc;
|
||||
console_printf("invalid 'attr' parameter\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = parse_arg_byte_stream("value", sizeof cmd_buf - total_attr_len,
|
||||
cmd_buf + total_attr_len, &attr_len);
|
||||
if (rc == ENOENT) {
|
||||
break;
|
||||
} else if (rc != 0) {
|
||||
console_printf("invalid 'value' parameter\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
offset = parse_arg_uint16("offset", &rc);
|
||||
if (rc == ENOENT) {
|
||||
offset = 0;
|
||||
} else if (rc != 0) {
|
||||
console_printf("invalid 'offset' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (num_attrs >= sizeof attrs / sizeof attrs[0]) {
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
attrs[num_attrs].handle = attr_handle;
|
||||
attrs[num_attrs].offset = offset;
|
||||
attrs[num_attrs].om = ble_hs_mbuf_from_flat(cmd_buf + total_attr_len,
|
||||
attr_len);
|
||||
if (attrs[num_attrs].om == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
total_attr_len += attr_len;
|
||||
num_attrs++;
|
||||
}
|
||||
|
||||
if (no_rsp) {
|
||||
if (num_attrs != 1) {
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
rc = btshell_write_no_rsp(conn_handle, attrs[0].handle, attrs[0].om);
|
||||
attrs[0].om = NULL;
|
||||
} else if (is_long) {
|
||||
if (num_attrs != 1) {
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
rc = btshell_write_long(conn_handle, attrs[0].handle,
|
||||
attrs[0].offset, attrs[0].om);
|
||||
attrs[0].om = NULL;
|
||||
} else if (num_attrs > 1) {
|
||||
rc = btshell_write_reliable(conn_handle, attrs, num_attrs);
|
||||
} else if (num_attrs == 1) {
|
||||
rc = btshell_write(conn_handle, attrs[0].handle, attrs[0].om);
|
||||
attrs[0].om = NULL;
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
done:
|
||||
for (i = 0; i < sizeof attrs / sizeof attrs[0]; i++) {
|
||||
os_mbuf_free_chain(attrs[i].om);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
console_printf("error writing characteristic; rc=%d\n", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
39
src/libs/mynewt-nimble/apps/btshell/src/cmd_gatt.h
Normal file
39
src/libs/mynewt-nimble/apps/btshell/src/cmd_gatt.h
Normal file
|
|
@ -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 CMD_GATT_H
|
||||
#define CMD_GATT_H
|
||||
|
||||
#include "cmd.h"
|
||||
|
||||
int cmd_gatt_discover_characteristic(int argc, char **argv);
|
||||
int cmd_gatt_discover_descriptor(int argc, char **argv);
|
||||
int cmd_gatt_discover_service(int argc, char **argv);
|
||||
int cmd_gatt_discover_full(int argc, char **argv);
|
||||
int cmd_gatt_find_included_services(int argc, char **argv);
|
||||
int cmd_gatt_exchange_mtu(int argc, char **argv);
|
||||
int cmd_gatt_notify(int argc, char **argv);
|
||||
int cmd_gatt_read(int argc, char **argv);
|
||||
int cmd_gatt_service_changed(int argc, char **argv);
|
||||
int cmd_gatt_service_visibility(int argc, char **argv);
|
||||
int cmd_gatt_show(int argc, char **argv);
|
||||
int cmd_gatt_show_local(int argc, char **argv);
|
||||
int cmd_gatt_write(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
325
src/libs/mynewt-nimble/apps/btshell/src/cmd_l2cap.c
Normal file
325
src/libs/mynewt-nimble/apps/btshell/src/cmd_l2cap.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* 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 <inttypes.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/ble_l2cap.h"
|
||||
#include "console/console.h"
|
||||
#include "btshell.h"
|
||||
#include "cmd.h"
|
||||
#include "cmd_l2cap.h"
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* $l2cap-update *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_l2cap_update(int argc, char **argv)
|
||||
{
|
||||
struct ble_l2cap_sig_update_params params;
|
||||
uint16_t conn_handle;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn_handle = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
params.itvl_min = parse_arg_uint16_dflt("interval_min",
|
||||
BLE_GAP_INITIAL_CONN_ITVL_MIN,
|
||||
&rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'interval_min' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
params.itvl_max = parse_arg_uint16_dflt("interval_max",
|
||||
BLE_GAP_INITIAL_CONN_ITVL_MAX,
|
||||
&rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'interval_max' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
params.slave_latency = parse_arg_uint16_dflt("latency", 0, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'latency' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
params.timeout_multiplier = parse_arg_uint16_dflt("timeout", 0x0100, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'timeout' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = btshell_l2cap_update(conn_handle, ¶ms);
|
||||
if (rc != 0) {
|
||||
console_printf("error txing l2cap update; rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $l2cap-create-server *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_l2cap_create_server(int argc, char **argv)
|
||||
{
|
||||
uint16_t psm = 0;
|
||||
uint16_t mtu;
|
||||
int error;
|
||||
int accept_response = 0;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
psm = parse_arg_uint16("psm", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'psm' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
error = parse_arg_uint32_dflt("error", 0, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'error' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
mtu = parse_arg_uint16_dflt("mtu", 0, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'mtu' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (error) {
|
||||
case 1:
|
||||
accept_response = BLE_HS_EAUTHEN;
|
||||
break;
|
||||
case 2:
|
||||
accept_response = BLE_HS_EAUTHOR;
|
||||
break;
|
||||
case 3:
|
||||
accept_response = BLE_HS_EENCRYPT_KEY_SZ;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = btshell_l2cap_create_srv(psm, mtu, accept_response);
|
||||
if (rc) {
|
||||
console_printf("Server create error: 0x%02x\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
console_printf("Server created successfully\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $l2cap-connect *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_l2cap_connect(int argc, char **argv)
|
||||
{
|
||||
uint16_t conn = 0;
|
||||
uint16_t psm = 0;
|
||||
uint16_t mtu;
|
||||
uint8_t num;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
psm = parse_arg_uint16("psm", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'psm' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
mtu = parse_arg_uint16_dflt("mtu", 0, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'mtu' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
num = parse_arg_uint8_dflt("num", 1, &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'num' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return btshell_l2cap_connect(conn, psm, mtu, num);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $l2cap-disconnect *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_l2cap_disconnect(int argc, char **argv)
|
||||
{
|
||||
uint16_t conn;
|
||||
uint16_t idx;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
idx = parse_arg_uint16("idx", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'idx' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return btshell_l2cap_disconnect(conn, idx);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* $l2cap-send *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmd_l2cap_send(int argc, char **argv)
|
||||
{
|
||||
uint16_t conn;
|
||||
uint16_t idx;
|
||||
uint16_t bytes;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
idx = parse_arg_uint16("idx", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'idx' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
bytes = parse_arg_uint16("bytes", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'bytes' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return btshell_l2cap_send(conn, idx, bytes);
|
||||
}
|
||||
|
||||
int
|
||||
cmd_l2cap_show_coc(int argc, char **argv)
|
||||
{
|
||||
struct btshell_conn *conn = NULL;
|
||||
struct btshell_l2cap_coc *coc;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < btshell_num_conns; i++) {
|
||||
conn = btshell_conns + i;
|
||||
|
||||
if (SLIST_EMPTY(&conn->coc_list)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
console_printf("conn_handle: 0x%04x\n", conn->handle);
|
||||
j = 0;
|
||||
SLIST_FOREACH(coc, &conn->coc_list, next) {
|
||||
console_printf(" idx: %i, chan pointer = %p\n", j++, coc->chan);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cmd_l2cap_reconfig(int argc, char **argv)
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_L2CAP_ENHANCED_COC)
|
||||
uint16_t conn;
|
||||
uint16_t mtu;
|
||||
uint8_t idxs[5];
|
||||
int num;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_all(argc - 1, argv + 1);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
conn = parse_arg_uint16("conn", &rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'conn' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
mtu = parse_arg_uint16_dflt("mtu", 0,&rc);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'mtu' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = parse_arg_uint8_list_with_separator("idxs", ",", 5, idxs, &num);
|
||||
if (rc != 0) {
|
||||
console_printf("invalid 'idxs' parameter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return btshell_l2cap_reconfig(conn, mtu, num, idxs);
|
||||
#else
|
||||
console_printf("To enable this features set BLE_L2CAP_ENHANCED_COC\n");
|
||||
return ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
33
src/libs/mynewt-nimble/apps/btshell/src/cmd_l2cap.h
Normal file
33
src/libs/mynewt-nimble/apps/btshell/src/cmd_l2cap.h
Normal file
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef CMD_L2CAP_H
|
||||
#define CMD_L2CAP_H
|
||||
|
||||
#include "cmd.h"
|
||||
|
||||
int cmd_l2cap_update(int argc, char **argv);
|
||||
int cmd_l2cap_create_server(int argc, char **argv);
|
||||
int cmd_l2cap_connect(int argc, char **argv);
|
||||
int cmd_l2cap_disconnect(int argc, char **argv);
|
||||
int cmd_l2cap_send(int argc, char **argv);
|
||||
int cmd_l2cap_show_coc(int argc, char **argv);
|
||||
int cmd_l2cap_reconfig(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
638
src/libs/mynewt-nimble/apps/btshell/src/gatt_svr.c
Normal file
638
src/libs/mynewt-nimble/apps/btshell/src/gatt_svr.c
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include "bsp/bsp.h"
|
||||
#include "console/console.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "host/ble_gatt.h"
|
||||
#include "btshell.h"
|
||||
|
||||
/* 0000xxxx-8c26-476f-89a7-a108033a69c7 */
|
||||
#define PTS_UUID_DECLARE(uuid16) \
|
||||
((const ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT( \
|
||||
0xc7, 0x69, 0x3a, 0x03, 0x08, 0xa1, 0xa7, 0x89, \
|
||||
0x6f, 0x47, 0x26, 0x8c, uuid16, uuid16 >> 8, 0x00, 0x00 \
|
||||
)))
|
||||
|
||||
#define PTS_SVC 0x0001
|
||||
#define PTS_CHR_READ 0x0002
|
||||
#define PTS_CHR_WRITE 0x0003
|
||||
#define PTS_CHR_RELIABLE_WRITE 0x0004
|
||||
#define PTS_CHR_WRITE_NO_RSP 0x0005
|
||||
#define PTS_CHR_READ_WRITE 0x0006
|
||||
#define PTS_CHR_READ_WRITE_ENC 0x0007
|
||||
#define PTS_CHR_READ_WRITE_AUTHEN 0x0008
|
||||
#define PTS_DSC_READ 0x0009
|
||||
#define PTS_DSC_WRITE 0x000a
|
||||
#define PTS_DSC_READ_WRITE 0x000b
|
||||
#define PTS_DSC_READ_WRITE_ENC 0x000c
|
||||
#define PTS_DSC_READ_WRITE_AUTHEN 0x000d
|
||||
|
||||
#define PTS_LONG_SVC 0x0011
|
||||
#define PTS_LONG_CHR_READ 0x0012
|
||||
#define PTS_LONG_CHR_WRITE 0x0013
|
||||
#define PTS_LONG_CHR_RELIABLE_WRITE 0x0014
|
||||
#define PTS_LONG_CHR_READ_WRITE 0x0015
|
||||
#define PTS_LONG_CHR_READ_WRITE_ALT 0x0016
|
||||
#define PTS_LONG_CHR_READ_WRITE_ENC 0x0017
|
||||
#define PTS_LONG_CHR_READ_WRITE_AUTHEN 0x0018
|
||||
#define PTS_LONG_DSC_READ 0x0019
|
||||
#define PTS_LONG_DSC_WRITE 0x001a
|
||||
#define PTS_LONG_DSC_READ_WRITE 0x001b
|
||||
#define PTS_LONG_DSC_READ_WRITE_ENC 0x001c
|
||||
#define PTS_LONG_DSC_READ_WRITE_AUTHEN 0x001d
|
||||
|
||||
#define PTS_INC_SVC 0x001e
|
||||
#define PTS_CHR_READ_WRITE_ALT 0x001f
|
||||
|
||||
/**
|
||||
* The vendor specific security test service consists of two characteristics:
|
||||
* o random-number-generator: generates a random 32-bit number each time
|
||||
* it is read. This characteristic can only be read over an encrypted
|
||||
* connection.
|
||||
* o static-value: a single-byte characteristic that can always be read,
|
||||
* but can only be written over an encrypted connection.
|
||||
*/
|
||||
|
||||
/* 59462f12-9543-9999-12c8-58b459a2712d */
|
||||
static const ble_uuid128_t gatt_svr_svc_sec_test_uuid =
|
||||
BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
|
||||
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
|
||||
|
||||
/* 5c3a659e-897e-45e1-b016-007107c96df6 */
|
||||
static const ble_uuid128_t gatt_svr_chr_sec_test_rand_uuid =
|
||||
BLE_UUID128_INIT(0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
|
||||
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
|
||||
|
||||
/* 5c3a659e-897e-45e1-b016-007107c96df7 */
|
||||
static const ble_uuid128_t gatt_svr_chr_sec_test_static_uuid =
|
||||
BLE_UUID128_INIT(0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
|
||||
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
|
||||
|
||||
/* 5c3a659e-897e-45e1-b016-007107c96df8 */
|
||||
static const ble_uuid128_t gatt_svr_chr_sec_test_static_auth_uuid =
|
||||
BLE_UUID128_INIT(0xf8, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
|
||||
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
|
||||
|
||||
static uint8_t gatt_svr_sec_test_static_val;
|
||||
|
||||
static uint8_t gatt_svr_pts_static_val;
|
||||
static uint8_t gatt_svr_pts_static_long_val[30];
|
||||
static uint8_t gatt_svr_pts_static_long_val_alt[30];
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static int
|
||||
gatt_svr_access_test(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static int
|
||||
gatt_svr_long_access_test(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[] = {
|
||||
{
|
||||
/*** Service: PTS test. */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = PTS_UUID_DECLARE(PTS_SVC),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_READ),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_WRITE),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_RELIABLE_WRITE),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_RELIABLE_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_WRITE_NO_RSP),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ENC),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC |
|
||||
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
|
||||
.min_key_size = 16,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_AUTHEN),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN |
|
||||
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
|
||||
.descriptors = (struct ble_gatt_dsc_def[]){ {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_DSC_READ),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_DSC_WRITE),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.att_flags = BLE_ATT_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_DSC_READ_WRITE),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_DSC_READ_WRITE_ENC),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC |
|
||||
BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_ENC,
|
||||
.min_key_size = 16,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_DSC_READ_WRITE_AUTHEN),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_AUTHEN |
|
||||
BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_AUTHEN,
|
||||
}, {
|
||||
0, /* No more descriptors in this characteristic. */
|
||||
} }
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
} },
|
||||
},
|
||||
|
||||
{
|
||||
/*** Service: PTS long test. */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_SVC),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_WRITE),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.flags = BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_RELIABLE_WRITE),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_RELIABLE_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_ALT),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_ENC),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC |
|
||||
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
|
||||
.min_key_size = 16,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_AUTHEN),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN |
|
||||
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
|
||||
.descriptors = (struct ble_gatt_dsc_def[]){ {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_READ),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_WRITE),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.att_flags = BLE_ATT_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_READ_WRITE),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_WRITE,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_READ_WRITE_ENC),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC |
|
||||
BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_ENC,
|
||||
.min_key_size = 16,
|
||||
}, {
|
||||
.uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_READ_WRITE_AUTHEN),
|
||||
.access_cb = gatt_svr_long_access_test,
|
||||
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_AUTHEN |
|
||||
BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_AUTHEN,
|
||||
}, {
|
||||
0, /* No more descriptors in this characteristic. */
|
||||
} }
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
} },
|
||||
},
|
||||
|
||||
{
|
||||
/*** Service: Security test. */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &gatt_svr_svc_sec_test_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/*** Characteristic: Random number generator. */
|
||||
.uuid = &gatt_svr_chr_sec_test_rand_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_sec_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
|
||||
}, {
|
||||
/*** Characteristic: Static value. */
|
||||
.uuid = &gatt_svr_chr_sec_test_static_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_sec_test,
|
||||
.flags = BLE_GATT_CHR_F_READ |
|
||||
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
|
||||
}, {
|
||||
/*** Characteristic: Static value. */
|
||||
.uuid = &gatt_svr_chr_sec_test_static_auth_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_sec_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN,
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
} },
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ble_gatt_svc_def *inc_svcs[] = {
|
||||
&gatt_svr_svcs[0],
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_inc_svcs[] = {
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = PTS_UUID_DECLARE(PTS_INC_SVC),
|
||||
.includes = inc_svcs,
|
||||
.characteristics = (struct ble_gatt_chr_def[]) {{
|
||||
.uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ALT),
|
||||
.access_cb = gatt_svr_access_test,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
0, /* No more characteristics */
|
||||
}, },
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
|
||||
void *dst, uint16_t *len)
|
||||
{
|
||||
uint16_t om_len;
|
||||
int rc;
|
||||
|
||||
om_len = OS_MBUF_PKTLEN(om);
|
||||
if (om_len < min_len || om_len > max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rand_num;
|
||||
int rc;
|
||||
|
||||
uuid = ctxt->chr->uuid;
|
||||
|
||||
/* Determine which characteristic is being accessed by examining its
|
||||
* 128-bit UUID.
|
||||
*/
|
||||
|
||||
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) {
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
|
||||
/* Respond with a 32-bit random number. */
|
||||
rand_num = rand();
|
||||
rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0 ||
|
||||
ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_auth_uuid.u) == 0) {
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val,
|
||||
sizeof gatt_svr_sec_test_static_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
rc = gatt_svr_chr_write(ctxt->om,
|
||||
sizeof gatt_svr_sec_test_static_val,
|
||||
sizeof gatt_svr_sec_test_static_val,
|
||||
&gatt_svr_sec_test_static_val, NULL);
|
||||
return rc;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unknown characteristic; the nimble stack should not have called this
|
||||
* function.
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
/* This method is used for PTS testing only, to extract 16 bit value
|
||||
* from 128 bit vendor specific UUID.
|
||||
*/
|
||||
static uint16_t
|
||||
extract_uuid16_from_pts_uuid128(const ble_uuid_t *uuid)
|
||||
{
|
||||
const uint8_t *u8ptr;
|
||||
uint16_t uuid16;
|
||||
|
||||
u8ptr = BLE_UUID128(uuid)->value;
|
||||
uuid16 = u8ptr[12];
|
||||
uuid16 |= (uint16_t)u8ptr[13] << 8;
|
||||
return uuid16;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_access_test(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
uint16_t uuid16;
|
||||
int rc;
|
||||
|
||||
uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid);
|
||||
assert(uuid16 != 0);
|
||||
|
||||
switch (uuid16) {
|
||||
case PTS_CHR_READ:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val,
|
||||
sizeof gatt_svr_pts_static_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case PTS_CHR_WRITE:
|
||||
case PTS_CHR_RELIABLE_WRITE:
|
||||
case PTS_CHR_WRITE_NO_RSP:
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_val,
|
||||
&gatt_svr_pts_static_val, NULL);
|
||||
return rc;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val,
|
||||
sizeof gatt_svr_pts_static_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
assert(0);
|
||||
break;
|
||||
case PTS_CHR_READ_WRITE:
|
||||
case PTS_CHR_READ_WRITE_ENC:
|
||||
case PTS_CHR_READ_WRITE_AUTHEN:
|
||||
case PTS_CHR_READ_WRITE_ALT:
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_val,
|
||||
&gatt_svr_pts_static_val, NULL);
|
||||
return rc;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val,
|
||||
sizeof gatt_svr_pts_static_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
assert(0);
|
||||
break;
|
||||
case PTS_DSC_READ:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC);
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val,
|
||||
sizeof gatt_svr_pts_static_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case PTS_DSC_WRITE:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC);
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_val,
|
||||
&gatt_svr_pts_static_val, NULL);
|
||||
return rc;
|
||||
|
||||
case PTS_DSC_READ_WRITE:
|
||||
case PTS_DSC_READ_WRITE_ENC:
|
||||
case PTS_DSC_READ_WRITE_AUTHEN:
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) {
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_val,
|
||||
&gatt_svr_pts_static_val, NULL);
|
||||
return rc;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) {
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val,
|
||||
sizeof gatt_svr_pts_static_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
static int
|
||||
gatt_svr_long_access_test(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
uint16_t uuid16;
|
||||
int rc;
|
||||
|
||||
uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid);
|
||||
assert(uuid16 != 0);
|
||||
|
||||
switch (uuid16) {
|
||||
case PTS_LONG_CHR_READ:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val,
|
||||
sizeof gatt_svr_pts_static_long_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case PTS_LONG_CHR_WRITE:
|
||||
case PTS_LONG_CHR_RELIABLE_WRITE:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_long_val,
|
||||
&gatt_svr_pts_static_long_val, NULL);
|
||||
return rc;
|
||||
|
||||
case PTS_LONG_CHR_READ_WRITE:
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_long_val,
|
||||
&gatt_svr_pts_static_long_val, NULL);
|
||||
return rc;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val,
|
||||
sizeof gatt_svr_pts_static_long_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case PTS_LONG_CHR_READ_WRITE_ALT:
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_long_val_alt,
|
||||
&gatt_svr_pts_static_long_val_alt, NULL);
|
||||
return rc;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val_alt,
|
||||
sizeof gatt_svr_pts_static_long_val_alt);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case PTS_LONG_CHR_READ_WRITE_ENC:
|
||||
case PTS_LONG_CHR_READ_WRITE_AUTHEN:
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_long_val,
|
||||
&gatt_svr_pts_static_long_val, NULL);
|
||||
return rc;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val,
|
||||
sizeof gatt_svr_pts_static_long_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case PTS_LONG_DSC_READ:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC);
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val,
|
||||
sizeof gatt_svr_pts_static_long_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case PTS_LONG_DSC_WRITE:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC);
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_long_val,
|
||||
&gatt_svr_pts_static_long_val, NULL);
|
||||
return rc;
|
||||
|
||||
case PTS_LONG_DSC_READ_WRITE:
|
||||
case PTS_LONG_DSC_READ_WRITE_ENC:
|
||||
case PTS_LONG_DSC_READ_WRITE_AUTHEN:
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) {
|
||||
rc = gatt_svr_chr_write(ctxt->om,0,
|
||||
sizeof gatt_svr_pts_static_long_val,
|
||||
&gatt_svr_pts_static_long_val, NULL);
|
||||
return rc;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) {
|
||||
rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val,
|
||||
sizeof gatt_svr_pts_static_long_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gatt_svr_print_svcs(void)
|
||||
{
|
||||
ble_gatts_show_local();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_inc_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_inc_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
2630
src/libs/mynewt-nimble/apps/btshell/src/main.c
Normal file
2630
src/libs/mynewt-nimble/apps/btshell/src/main.c
Normal file
File diff suppressed because it is too large
Load diff
163
src/libs/mynewt-nimble/apps/btshell/src/misc.c
Normal file
163
src/libs/mynewt-nimble/apps/btshell/src/misc.c
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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 "console/console.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "host/ble_gap.h"
|
||||
|
||||
#include "btshell.h"
|
||||
|
||||
/**
|
||||
* Utility function to log an array of bytes.
|
||||
*/
|
||||
void
|
||||
print_bytes(const uint8_t *bytes, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
console_printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_mbuf(const struct os_mbuf *om)
|
||||
{
|
||||
int colon;
|
||||
|
||||
colon = 0;
|
||||
while (om != NULL) {
|
||||
if (colon) {
|
||||
console_printf(":");
|
||||
} else {
|
||||
colon = 1;
|
||||
}
|
||||
print_bytes(om->om_data, om->om_len);
|
||||
om = SLIST_NEXT(om, om_next);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_addr(const void *addr)
|
||||
{
|
||||
const uint8_t *u8p;
|
||||
|
||||
u8p = addr;
|
||||
console_printf("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
|
||||
}
|
||||
|
||||
void
|
||||
print_uuid(const ble_uuid_t *uuid)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
ble_uuid_to_str(uuid, buf);
|
||||
|
||||
console_printf("%s", buf);
|
||||
}
|
||||
|
||||
int
|
||||
svc_is_empty(const struct btshell_svc *svc)
|
||||
{
|
||||
return svc->svc.end_handle <= svc->svc.start_handle;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
chr_end_handle(const struct btshell_svc *svc, const struct btshell_chr *chr)
|
||||
{
|
||||
const struct btshell_chr *next_chr;
|
||||
|
||||
next_chr = SLIST_NEXT(chr, next);
|
||||
if (next_chr != NULL) {
|
||||
return next_chr->chr.def_handle - 1;
|
||||
} else {
|
||||
return svc->svc.end_handle;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
chr_is_empty(const struct btshell_svc *svc, const struct btshell_chr *chr)
|
||||
{
|
||||
return chr_end_handle(svc, chr) <= chr->chr.val_handle;
|
||||
}
|
||||
|
||||
void
|
||||
print_conn_desc(const struct ble_gap_conn_desc *desc)
|
||||
{
|
||||
console_printf("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);
|
||||
console_printf(" our_id_addr_type=%d our_id_addr=",
|
||||
desc->our_id_addr.type);
|
||||
print_addr(desc->our_id_addr.val);
|
||||
console_printf(" peer_ota_addr_type=%d peer_ota_addr=",
|
||||
desc->peer_ota_addr.type);
|
||||
print_addr(desc->peer_ota_addr.val);
|
||||
console_printf(" peer_id_addr_type=%d peer_id_addr=",
|
||||
desc->peer_id_addr.type);
|
||||
print_addr(desc->peer_id_addr.val);
|
||||
console_printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d"
|
||||
" key_size=%d encrypted=%d authenticated=%d bonded=%d\n",
|
||||
desc->conn_itvl, desc->conn_latency,
|
||||
desc->supervision_timeout,
|
||||
desc->sec_state.key_size,
|
||||
desc->sec_state.encrypted,
|
||||
desc->sec_state.authenticated,
|
||||
desc->sec_state.bonded);
|
||||
}
|
||||
|
||||
static void
|
||||
print_dsc(struct btshell_dsc *dsc)
|
||||
{
|
||||
console_printf(" dsc_handle=%d uuid=", dsc->dsc.handle);
|
||||
print_uuid(&dsc->dsc.uuid.u);
|
||||
console_printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_chr(struct btshell_chr *chr)
|
||||
{
|
||||
struct btshell_dsc *dsc;
|
||||
|
||||
console_printf(" def_handle=%d val_handle=%d properties=0x%02x "
|
||||
"uuid=", chr->chr.def_handle, chr->chr.val_handle,
|
||||
chr->chr.properties);
|
||||
print_uuid(&chr->chr.uuid.u);
|
||||
console_printf("\n");
|
||||
|
||||
SLIST_FOREACH(dsc, &chr->dscs, next) {
|
||||
print_dsc(dsc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_svc(struct btshell_svc *svc)
|
||||
{
|
||||
struct btshell_chr *chr;
|
||||
|
||||
console_printf(" start=%d end=%d uuid=", svc->svc.start_handle,
|
||||
svc->svc.end_handle);
|
||||
print_uuid(&svc->svc.uuid.u);
|
||||
console_printf("\n");
|
||||
|
||||
SLIST_FOREACH(chr, &svc->chrs, next) {
|
||||
print_chr(chr);
|
||||
}
|
||||
}
|
||||
734
src/libs/mynewt-nimble/apps/btshell/src/parse.c
Normal file
734
src/libs/mynewt-nimble/apps/btshell/src/parse.c
Normal file
|
|
@ -0,0 +1,734 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include "console/console.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "host/ble_eddystone.h"
|
||||
#include "cmd.h"
|
||||
#include "btshell.h"
|
||||
|
||||
#define CMD_MAX_ARGS 16
|
||||
|
||||
static char *cmd_args[CMD_MAX_ARGS][2];
|
||||
static int cmd_num_args;
|
||||
|
||||
int
|
||||
parse_arg_find_idx(const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cmd_num_args; i++) {
|
||||
if (strcmp(cmd_args[i][0], key) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
parse_arg_peek(const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cmd_num_args; i++) {
|
||||
if (strcmp(cmd_args[i][0], key) == 0) {
|
||||
return cmd_args[i][1];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
parse_arg_extract(const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cmd_num_args; i++) {
|
||||
if (strcmp(cmd_args[i][0], key) == 0) {
|
||||
/* Erase parameter. */
|
||||
cmd_args[i][0][0] = '\0';
|
||||
|
||||
return cmd_args[i][1];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which number base to use when parsing the specified numeric
|
||||
* string. This just avoids base '0' so that numbers don't get interpreted as
|
||||
* octal.
|
||||
*/
|
||||
static int
|
||||
parse_arg_long_base(char *sval)
|
||||
{
|
||||
if (sval[0] == '0' && sval[1] == 'x') {
|
||||
return 0;
|
||||
} else {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
long
|
||||
parse_long_bounds(char *sval, long min, long max, int *out_status)
|
||||
{
|
||||
char *endptr;
|
||||
long lval;
|
||||
|
||||
lval = strtol(sval, &endptr, parse_arg_long_base(sval));
|
||||
if (sval[0] != '\0' && *endptr == '\0' &&
|
||||
lval >= min && lval <= max) {
|
||||
|
||||
*out_status = 0;
|
||||
return lval;
|
||||
}
|
||||
|
||||
*out_status = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
parse_arg_long_bounds_peek(char *name, long min, long max, int *out_status)
|
||||
{
|
||||
char *sval;
|
||||
|
||||
sval = parse_arg_peek(name);
|
||||
if (sval == NULL) {
|
||||
*out_status = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
return parse_long_bounds(sval, min, max, out_status);
|
||||
}
|
||||
|
||||
long
|
||||
parse_arg_long_bounds(char *name, long min, long max, int *out_status)
|
||||
{
|
||||
char *sval;
|
||||
|
||||
sval = parse_arg_extract(name);
|
||||
if (sval == NULL) {
|
||||
*out_status = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
return parse_long_bounds(sval, min, max, out_status);
|
||||
}
|
||||
|
||||
long
|
||||
parse_arg_long_bounds_dflt(char *name, long min, long max,
|
||||
long dflt, int *out_status)
|
||||
{
|
||||
long val;
|
||||
int rc;
|
||||
|
||||
val = parse_arg_long_bounds(name, min, max, &rc);
|
||||
if (rc == ENOENT) {
|
||||
rc = 0;
|
||||
val = dflt;
|
||||
}
|
||||
|
||||
*out_status = rc;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
parse_arg_uint64_bounds(char *name, uint64_t min, uint64_t max, int *out_status)
|
||||
{
|
||||
char *endptr;
|
||||
char *sval;
|
||||
uint64_t lval;
|
||||
|
||||
sval = parse_arg_extract(name);
|
||||
if (sval == NULL) {
|
||||
*out_status = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lval = strtoull(sval, &endptr, parse_arg_long_base(sval));
|
||||
if (sval[0] != '\0' && *endptr == '\0' &&
|
||||
lval >= min && lval <= max) {
|
||||
|
||||
*out_status = 0;
|
||||
return lval;
|
||||
}
|
||||
|
||||
*out_status = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
parse_arg_long(char *name, int *out_status)
|
||||
{
|
||||
return parse_arg_long_bounds(name, LONG_MIN, LONG_MAX, out_status);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
parse_arg_bool(char *name, int *out_status)
|
||||
{
|
||||
return parse_arg_long_bounds(name, 0, 1, out_status);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
parse_arg_bool_dflt(char *name, uint8_t dflt, int *out_status)
|
||||
{
|
||||
return parse_arg_long_bounds_dflt(name, 0, 1, dflt, out_status);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
parse_arg_uint8(char *name, int *out_status)
|
||||
{
|
||||
return parse_arg_long_bounds(name, 0, UINT8_MAX, out_status);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
parse_arg_uint16(char *name, int *out_status)
|
||||
{
|
||||
return parse_arg_long_bounds(name, 0, UINT16_MAX, out_status);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
parse_arg_uint16_peek(char *name, int *out_status)
|
||||
{
|
||||
return parse_arg_long_bounds_peek(name, 0, UINT16_MAX, out_status);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
parse_arg_uint32(char *name, int *out_status)
|
||||
{
|
||||
return parse_arg_uint64_bounds(name, 0, UINT32_MAX, out_status);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
parse_arg_uint64(char *name, int *out_status)
|
||||
{
|
||||
return parse_arg_uint64_bounds(name, 0, UINT64_MAX, out_status);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
parse_arg_uint8_dflt(char *name, uint8_t dflt, int *out_status)
|
||||
{
|
||||
uint8_t val;
|
||||
int rc;
|
||||
|
||||
val = parse_arg_uint8(name, &rc);
|
||||
if (rc == ENOENT) {
|
||||
val = dflt;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
*out_status = rc;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status)
|
||||
{
|
||||
uint16_t val;
|
||||
int rc;
|
||||
|
||||
val = parse_arg_uint16(name, &rc);
|
||||
if (rc == ENOENT) {
|
||||
val = dflt;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
*out_status = rc;
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
parse_arg_uint32_dflt(char *name, uint32_t dflt, int *out_status)
|
||||
{
|
||||
uint32_t val;
|
||||
int rc;
|
||||
|
||||
val = parse_arg_uint32(name, &rc);
|
||||
if (rc == ENOENT) {
|
||||
val = dflt;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
*out_status = rc;
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
parse_time_unit_mult(const char *str)
|
||||
{
|
||||
if (!strcasecmp(str, "us")) {
|
||||
return 1;
|
||||
} else if (!strcasecmp(str, "ms")) {
|
||||
return 1000;
|
||||
} else if (!strcasecmp(str, "s")) {
|
||||
return 1000000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
parse_time_us(const char *str, int *out_status)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t val_div = 1;
|
||||
uint32_t val_mult = 1;
|
||||
uint32_t val_us;
|
||||
|
||||
while (isdigit(*str)) {
|
||||
val *= 10;
|
||||
val += *str - '0';
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '.') {
|
||||
str++;
|
||||
while (isdigit(*str)) {
|
||||
val *= 10;
|
||||
val += *str - '0';
|
||||
val_div *= 10;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
val_mult = parse_time_unit_mult(str);
|
||||
if (val_mult == 0) {
|
||||
*out_status = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val_mult > val_div) {
|
||||
val_us = val * (val_mult / val_div);
|
||||
} else {
|
||||
val_us = val * (val_div / val_mult);
|
||||
}
|
||||
|
||||
*out_status = 0;
|
||||
|
||||
return val_us;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
parse_arg_time_dflt(char *name, int step_us, uint32_t dflt, int *out_status)
|
||||
{
|
||||
const char *arg;
|
||||
uint32_t val;
|
||||
int rc;
|
||||
|
||||
arg = parse_arg_peek(name);
|
||||
if (!arg) {
|
||||
*out_status = 0;
|
||||
return dflt;
|
||||
}
|
||||
|
||||
val = parse_time_us(arg, &rc);
|
||||
if (rc) {
|
||||
val = parse_arg_uint32(name, &rc);
|
||||
if (rc == ENOENT) {
|
||||
*out_status = 0;
|
||||
return dflt;
|
||||
}
|
||||
} else {
|
||||
val /= step_us;
|
||||
parse_arg_extract(name);
|
||||
}
|
||||
|
||||
*out_status = rc;
|
||||
return val;
|
||||
}
|
||||
|
||||
const struct kv_pair *
|
||||
parse_kv_find(const struct kv_pair *kvs, char *name)
|
||||
{
|
||||
const struct kv_pair *kv;
|
||||
int i;
|
||||
|
||||
for (i = 0; kvs[i].key != NULL; i++) {
|
||||
kv = kvs + i;
|
||||
if (strcmp(name, kv->key) == 0) {
|
||||
return kv;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_kv(char *name, const struct kv_pair *kvs, int *out_status)
|
||||
{
|
||||
const struct kv_pair *kv;
|
||||
char *sval;
|
||||
|
||||
sval = parse_arg_extract(name);
|
||||
if (sval == NULL) {
|
||||
*out_status = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
kv = parse_kv_find(kvs, sval);
|
||||
if (kv == NULL) {
|
||||
*out_status = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_status = 0;
|
||||
return kv->val;
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_kv_dflt(char *name, const struct kv_pair *kvs, int def_val,
|
||||
int *out_status)
|
||||
{
|
||||
int val;
|
||||
int rc;
|
||||
|
||||
val = parse_arg_kv(name, kvs, &rc);
|
||||
if (rc == ENOENT) {
|
||||
rc = 0;
|
||||
val = def_val;
|
||||
}
|
||||
|
||||
*out_status = rc;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parse_arg_byte_stream_delim(char *sval, char *delims, int max_len,
|
||||
uint8_t *dst, int *out_len)
|
||||
{
|
||||
unsigned long ul;
|
||||
char *endptr;
|
||||
char *token;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
for (token = strtok(sval, delims);
|
||||
token != NULL;
|
||||
token = strtok(NULL, delims)) {
|
||||
|
||||
if (i >= max_len) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ul = strtoul(token, &endptr, 16);
|
||||
if (sval[0] == '\0' || *endptr != '\0' || ul > UINT8_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dst[i] = ul;
|
||||
i++;
|
||||
}
|
||||
|
||||
*out_len = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len)
|
||||
{
|
||||
char *sval;
|
||||
|
||||
sval = parse_arg_extract(name);
|
||||
if (sval == NULL) {
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
return parse_arg_byte_stream_delim(sval, ":-", max_len, dst, out_len);
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_uint8_list_with_separator(char *name, char *separator, int max_len,
|
||||
uint8_t *dst, int *out_len)
|
||||
{
|
||||
char *sval;
|
||||
|
||||
sval = parse_arg_extract(name);
|
||||
if (sval == NULL) {
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
return parse_arg_byte_stream_delim(sval, separator, max_len, dst, out_len);
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len)
|
||||
{
|
||||
int actual_len;
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_byte_stream(name, len, dst, &actual_len);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (actual_len != len) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_reverse_bytes(uint8_t *bytes, int len)
|
||||
{
|
||||
uint8_t tmp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
tmp = bytes[i];
|
||||
bytes[i] = bytes[len - i - 1];
|
||||
bytes[len - i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_mac(char *name, uint8_t *dst)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = parse_arg_byte_stream_exact_length(name, dst, 6);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
parse_reverse_bytes(dst, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_addr(char *name, ble_addr_t *addr)
|
||||
{
|
||||
char *arg;
|
||||
size_t len;
|
||||
uint8_t addr_type;
|
||||
bool addr_type_found;
|
||||
int rc;
|
||||
|
||||
arg = parse_arg_peek(name);
|
||||
if (!arg) {
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
if (len < 2) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
addr_type_found = false;
|
||||
if ((arg[len - 2] == ':') || (arg[len - 2] == '-')) {
|
||||
if (tolower(arg[len - 1]) == 'p') {
|
||||
addr_type = BLE_ADDR_PUBLIC;
|
||||
addr_type_found = true;
|
||||
} else if (tolower(arg[len - 1]) == 'r') {
|
||||
addr_type = BLE_ADDR_RANDOM;
|
||||
addr_type_found = true;
|
||||
}
|
||||
|
||||
if (addr_type_found) {
|
||||
arg[len - 2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
rc = parse_arg_mac(name, addr->val);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (addr_type_found) {
|
||||
addr->type = addr_type;
|
||||
} else {
|
||||
rc = EAGAIN;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_uuid(char *str, ble_uuid_any_t *uuid)
|
||||
{
|
||||
uint16_t uuid16;
|
||||
uint8_t val[16];
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
uuid16 = parse_arg_uint16_peek(str, &rc);
|
||||
switch (rc) {
|
||||
case ENOENT:
|
||||
parse_arg_extract(str);
|
||||
return ENOENT;
|
||||
|
||||
case 0:
|
||||
len = 2;
|
||||
val[0] = uuid16;
|
||||
val[1] = uuid16 >> 8;
|
||||
parse_arg_extract(str);
|
||||
break;
|
||||
|
||||
default:
|
||||
len = 16;
|
||||
rc = parse_arg_byte_stream_exact_length(str, val, 16);
|
||||
if (rc != 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
parse_reverse_bytes(val, 16);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ble_uuid_init_from_buf(uuid, val, len);
|
||||
if (rc != 0) {
|
||||
return EINVAL;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
parse_arg_all(int argc, char **argv)
|
||||
{
|
||||
char *key;
|
||||
char *val;
|
||||
int i;
|
||||
|
||||
cmd_num_args = 0;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
key = strtok(argv[i], "=");
|
||||
val = strtok(NULL, "=");
|
||||
|
||||
if (key != NULL && val != NULL) {
|
||||
if (strlen(key) == 0) {
|
||||
console_printf("Error: invalid argument: %s\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmd_num_args >= CMD_MAX_ARGS) {
|
||||
console_printf("Error: too many arguments");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd_args[cmd_num_args][0] = key;
|
||||
cmd_args[cmd_num_args][1] = val;
|
||||
cmd_num_args++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_eddystone_url(char *full_url, uint8_t *out_scheme, char *out_body,
|
||||
uint8_t *out_body_len, uint8_t *out_suffix)
|
||||
{
|
||||
static const struct {
|
||||
char *s;
|
||||
uint8_t scheme;
|
||||
} schemes[] = {
|
||||
{ "http://www.", BLE_EDDYSTONE_URL_SCHEME_HTTP_WWW },
|
||||
{ "https://www.", BLE_EDDYSTONE_URL_SCHEME_HTTPS_WWW },
|
||||
{ "http://", BLE_EDDYSTONE_URL_SCHEME_HTTP },
|
||||
{ "https://", BLE_EDDYSTONE_URL_SCHEME_HTTPS },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
char *s;
|
||||
uint8_t code;
|
||||
} suffixes[] = {
|
||||
{ ".com/", BLE_EDDYSTONE_URL_SUFFIX_COM_SLASH },
|
||||
{ ".org/", BLE_EDDYSTONE_URL_SUFFIX_ORG_SLASH },
|
||||
{ ".edu/", BLE_EDDYSTONE_URL_SUFFIX_EDU_SLASH },
|
||||
{ ".net/", BLE_EDDYSTONE_URL_SUFFIX_NET_SLASH },
|
||||
{ ".info/", BLE_EDDYSTONE_URL_SUFFIX_INFO_SLASH },
|
||||
{ ".biz/", BLE_EDDYSTONE_URL_SUFFIX_BIZ_SLASH },
|
||||
{ ".gov/", BLE_EDDYSTONE_URL_SUFFIX_GOV_SLASH },
|
||||
{ ".com", BLE_EDDYSTONE_URL_SUFFIX_COM },
|
||||
{ ".org", BLE_EDDYSTONE_URL_SUFFIX_ORG },
|
||||
{ ".edu", BLE_EDDYSTONE_URL_SUFFIX_EDU },
|
||||
{ ".net", BLE_EDDYSTONE_URL_SUFFIX_NET },
|
||||
{ ".info", BLE_EDDYSTONE_URL_SUFFIX_INFO },
|
||||
{ ".biz", BLE_EDDYSTONE_URL_SUFFIX_BIZ },
|
||||
{ ".gov", BLE_EDDYSTONE_URL_SUFFIX_GOV },
|
||||
};
|
||||
|
||||
char *prefix;
|
||||
char *suffix;
|
||||
int full_url_len;
|
||||
int prefix_len;
|
||||
int suffix_len;
|
||||
int suffix_idx;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
full_url_len = strlen(full_url);
|
||||
|
||||
rc = BLE_HS_EINVAL;
|
||||
for (i = 0; i < sizeof schemes / sizeof schemes[0]; i++) {
|
||||
prefix = schemes[i].s;
|
||||
prefix_len = strlen(schemes[i].s);
|
||||
|
||||
if (full_url_len >= prefix_len &&
|
||||
memcmp(full_url, prefix, prefix_len) == 0) {
|
||||
|
||||
*out_scheme = i;
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = BLE_HS_EINVAL;
|
||||
for (i = 0; i < sizeof suffixes / sizeof suffixes[0]; i++) {
|
||||
suffix = suffixes[i].s;
|
||||
suffix_len = strlen(suffixes[i].s);
|
||||
|
||||
suffix_idx = full_url_len - suffix_len;
|
||||
if (suffix_idx >= prefix_len &&
|
||||
memcmp(full_url + suffix_idx, suffix, suffix_len) == 0) {
|
||||
|
||||
*out_suffix = i;
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rc != 0) {
|
||||
*out_suffix = BLE_EDDYSTONE_URL_SUFFIX_NONE;
|
||||
*out_body_len = full_url_len - prefix_len;
|
||||
} else {
|
||||
*out_body_len = full_url_len - prefix_len - suffix_len;
|
||||
}
|
||||
|
||||
memcpy(out_body, full_url + prefix_len, *out_body_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
42
src/libs/mynewt-nimble/apps/btshell/syscfg.yml
Normal file
42
src/libs/mynewt-nimble/apps/btshell/syscfg.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# 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:
|
||||
BTSHELL_ANS:
|
||||
description: Include support for the alert notification service.
|
||||
value: 1
|
||||
|
||||
syscfg.vals:
|
||||
# Enable the shell task.
|
||||
SHELL_TASK: 1
|
||||
|
||||
# Set log level to info (disable debug logging).
|
||||
LOG_LEVEL: 1
|
||||
|
||||
# Disable security manager (pairing and bonding).
|
||||
BLE_SM_LEGACY: 0
|
||||
BLE_SM_SC: 0
|
||||
|
||||
# Default task settings
|
||||
OS_MAIN_STACK_SIZE: 512
|
||||
|
||||
# SMP is not supported in this app, so disable smp-over-shell.
|
||||
SHELL_MGMT: 0
|
||||
|
||||
syscfg.vals.BLE_MESH:
|
||||
MSYS_1_BLOCK_COUNT: 16
|
||||
14
src/libs/mynewt-nimble/apps/bttester/README
Normal file
14
src/libs/mynewt-nimble/apps/bttester/README
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Title: Bluetooth tester application
|
||||
|
||||
Description:
|
||||
|
||||
Tester application uses binary protocol to control Mynewt Nimble stack
|
||||
and is aimed at automated testing. It uses Bluetooth Testing Protocol (BTP)
|
||||
to drive Bluetooth stack. BTP commands and events are received and buffered for
|
||||
further processing.
|
||||
--------------------------------------------------------------------------------
|
||||
Supported Profiles:
|
||||
|
||||
GAP, GATT, SM, L2CAP, MESH
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
44
src/libs/mynewt-nimble/apps/bttester/pkg.yml
Normal file
44
src/libs/mynewt-nimble/apps/bttester/pkg.yml
Normal file
|
|
@ -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.
|
||||
#
|
||||
|
||||
pkg.name: apps/bttester
|
||||
pkg.type: app
|
||||
pkg.description: Bluetooth tester application
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
pkg.deps:
|
||||
- "@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"
|
||||
- "@apache-mynewt-nimble/nimble/controller"
|
||||
- "@apache-mynewt-nimble/nimble/host"
|
||||
- "@apache-mynewt-nimble/nimble/host/util"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gap"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gatt"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/dis"
|
||||
- "@apache-mynewt-nimble/nimble/host/store/ram"
|
||||
- "@apache-mynewt-nimble/nimble/transport/ram"
|
||||
- "@apache-mynewt-core/hw/drivers/uart"
|
||||
- "@apache-mynewt-core/hw/drivers/rtt"
|
||||
|
||||
405
src/libs/mynewt-nimble/apps/bttester/src/atomic.h
Normal file
405
src/libs/mynewt-nimble/apps/bttester/src/atomic.h
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ATOMIC_H__ */
|
||||
374
src/libs/mynewt-nimble/apps/bttester/src/bttester.c
Normal file
374
src/libs/mynewt-nimble/apps/bttester/src/bttester.c
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* bttester.c - Bluetooth Tester */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#include "bttester_pipe.h"
|
||||
#include "bttester.h"
|
||||
|
||||
#define CMD_QUEUED 2
|
||||
|
||||
static struct os_eventq avail_queue;
|
||||
static struct os_eventq *cmds_queue;
|
||||
static struct os_event bttester_ev[CMD_QUEUED];
|
||||
|
||||
struct btp_buf {
|
||||
struct os_event *ev;
|
||||
union {
|
||||
u8_t data[BTP_MTU];
|
||||
struct btp_hdr hdr;
|
||||
};
|
||||
};
|
||||
|
||||
static struct btp_buf cmd_buf[CMD_QUEUED];
|
||||
|
||||
static void supported_commands(u8_t *data, u16_t len)
|
||||
{
|
||||
u8_t buf[1];
|
||||
struct core_read_supported_commands_rp *rp = (void *) buf;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
tester_set_bit(buf, CORE_READ_SUPPORTED_COMMANDS);
|
||||
tester_set_bit(buf, CORE_READ_SUPPORTED_SERVICES);
|
||||
tester_set_bit(buf, CORE_REGISTER_SERVICE);
|
||||
tester_set_bit(buf, CORE_UNREGISTER_SERVICE);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_CORE, CORE_READ_SUPPORTED_COMMANDS,
|
||||
BTP_INDEX_NONE, (u8_t *) rp, sizeof(buf));
|
||||
}
|
||||
|
||||
static void supported_services(u8_t *data, u16_t len)
|
||||
{
|
||||
u8_t buf[1];
|
||||
struct core_read_supported_services_rp *rp = (void *) buf;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_CORE);
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_GAP);
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_GATT);
|
||||
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_L2CAP);
|
||||
#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */
|
||||
#if MYNEWT_VAL(BLE_MESH)
|
||||
tester_set_bit(buf, BTP_SERVICE_ID_MESH);
|
||||
#endif /* MYNEWT_VAL(BLE_MESH) */
|
||||
|
||||
tester_send(BTP_SERVICE_ID_CORE, CORE_READ_SUPPORTED_SERVICES,
|
||||
BTP_INDEX_NONE, (u8_t *) rp, sizeof(buf));
|
||||
}
|
||||
|
||||
static void register_service(u8_t *data, u16_t len)
|
||||
{
|
||||
struct core_register_service_cmd *cmd = (void *) data;
|
||||
u8_t status;
|
||||
|
||||
switch (cmd->id) {
|
||||
case BTP_SERVICE_ID_GAP:
|
||||
status = tester_init_gap();
|
||||
/* Rsp with success status will be handled by bt enable cb */
|
||||
if (status == BTP_STATUS_FAILED) {
|
||||
goto rsp;
|
||||
}
|
||||
return;
|
||||
case BTP_SERVICE_ID_GATT:
|
||||
status = tester_init_gatt();
|
||||
break;
|
||||
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
case BTP_SERVICE_ID_L2CAP:
|
||||
status = tester_init_l2cap();
|
||||
break;
|
||||
#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */
|
||||
#if MYNEWT_VAL(BLE_MESH)
|
||||
case BTP_SERVICE_ID_MESH:
|
||||
status = tester_init_mesh();
|
||||
break;
|
||||
#endif /* MYNEWT_VAL(BLE_MESH) */
|
||||
default:
|
||||
status = BTP_STATUS_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
rsp:
|
||||
tester_rsp(BTP_SERVICE_ID_CORE, CORE_REGISTER_SERVICE, BTP_INDEX_NONE,
|
||||
status);
|
||||
}
|
||||
|
||||
static void unregister_service(u8_t *data, u16_t len)
|
||||
{
|
||||
struct core_unregister_service_cmd *cmd = (void *) data;
|
||||
u8_t status;
|
||||
|
||||
switch (cmd->id) {
|
||||
case BTP_SERVICE_ID_GAP:
|
||||
status = tester_unregister_gap();
|
||||
break;
|
||||
case BTP_SERVICE_ID_GATT:
|
||||
status = tester_unregister_gatt();
|
||||
break;
|
||||
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
case BTP_SERVICE_ID_L2CAP:
|
||||
status = tester_unregister_l2cap();
|
||||
break;
|
||||
#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */
|
||||
#if MYNEWT_VAL(BLE_MESH)
|
||||
case BTP_SERVICE_ID_MESH:
|
||||
status = tester_unregister_mesh();
|
||||
break;
|
||||
#endif /* MYNEWT_VAL(BLE_MESH) */
|
||||
default:
|
||||
status = BTP_STATUS_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_CORE, CORE_UNREGISTER_SERVICE, BTP_INDEX_NONE,
|
||||
status);
|
||||
}
|
||||
|
||||
static void handle_core(u8_t opcode, u8_t index, u8_t *data,
|
||||
u16_t len)
|
||||
{
|
||||
if (index != BTP_INDEX_NONE) {
|
||||
tester_rsp(BTP_SERVICE_ID_CORE, opcode, index,
|
||||
BTP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case CORE_READ_SUPPORTED_COMMANDS:
|
||||
supported_commands(data, len);
|
||||
return;
|
||||
case CORE_READ_SUPPORTED_SERVICES:
|
||||
supported_services(data, len);
|
||||
return;
|
||||
case CORE_REGISTER_SERVICE:
|
||||
register_service(data, len);
|
||||
return;
|
||||
case CORE_UNREGISTER_SERVICE:
|
||||
unregister_service(data, len);
|
||||
return;
|
||||
default:
|
||||
tester_rsp(BTP_SERVICE_ID_CORE, opcode, BTP_INDEX_NONE,
|
||||
BTP_STATUS_UNKNOWN_CMD);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_handler(struct os_event *ev)
|
||||
{
|
||||
u16_t len;
|
||||
struct btp_buf *cmd;
|
||||
|
||||
if (!ev || !ev->ev_arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = ev->ev_arg;
|
||||
|
||||
len = sys_le16_to_cpu(cmd->hdr.len);
|
||||
if (MYNEWT_VAL(BTTESTER_BTP_LOG)) {
|
||||
console_printf("[DBG] received %d bytes: %s\n",
|
||||
sizeof(cmd->hdr) + len,
|
||||
bt_hex(cmd->data,
|
||||
sizeof(cmd->hdr) + len));
|
||||
}
|
||||
|
||||
/* TODO
|
||||
* verify if service is registered before calling handler
|
||||
*/
|
||||
|
||||
switch (cmd->hdr.service) {
|
||||
case BTP_SERVICE_ID_CORE:
|
||||
handle_core(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
case BTP_SERVICE_ID_GAP:
|
||||
tester_handle_gap(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
case BTP_SERVICE_ID_GATT:
|
||||
tester_handle_gatt(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
case BTP_SERVICE_ID_L2CAP:
|
||||
tester_handle_l2cap(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */
|
||||
#if MYNEWT_VAL(BLE_MESH)
|
||||
case BTP_SERVICE_ID_MESH:
|
||||
tester_handle_mesh(cmd->hdr.opcode, cmd->hdr.index,
|
||||
cmd->hdr.data, len);
|
||||
break;
|
||||
#endif /* MYNEWT_VAL(BLE_MESH) */
|
||||
default:
|
||||
tester_rsp(cmd->hdr.service, cmd->hdr.opcode,
|
||||
cmd->hdr.index, BTP_STATUS_FAILED);
|
||||
break;
|
||||
}
|
||||
|
||||
os_eventq_put(&avail_queue, ev);
|
||||
}
|
||||
|
||||
static u8_t *recv_cb(u8_t *buf, size_t *off)
|
||||
{
|
||||
struct btp_hdr *cmd = (void *) buf;
|
||||
struct os_event *new_ev;
|
||||
struct btp_buf *new_buf, *old_buf;
|
||||
u16_t len;
|
||||
|
||||
if (*off < sizeof(*cmd)) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
len = sys_le16_to_cpu(cmd->len);
|
||||
if (len > BTP_MTU - sizeof(*cmd)) {
|
||||
*off = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (*off < sizeof(*cmd) + len) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
new_ev = os_eventq_get_no_wait(&avail_queue);
|
||||
if (!new_ev) {
|
||||
SYS_LOG_ERR("BT tester: RX overflow");
|
||||
*off = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
old_buf = CONTAINER_OF(buf, struct btp_buf, data);
|
||||
os_eventq_put(cmds_queue, old_buf->ev);
|
||||
|
||||
new_buf = new_ev->ev_arg;
|
||||
*off = 0;
|
||||
return new_buf->data;
|
||||
}
|
||||
|
||||
static void avail_queue_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
os_eventq_init(&avail_queue);
|
||||
|
||||
for (i = 0; i < CMD_QUEUED; i++) {
|
||||
cmd_buf[i].ev = &bttester_ev[i];
|
||||
bttester_ev[i].ev_cb = cmd_handler;
|
||||
bttester_ev[i].ev_arg = &cmd_buf[i];
|
||||
|
||||
os_eventq_put(&avail_queue, &bttester_ev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void bttester_evq_set(struct os_eventq *evq)
|
||||
{
|
||||
cmds_queue = evq;
|
||||
}
|
||||
|
||||
void tester_init(void)
|
||||
{
|
||||
struct os_event *ev;
|
||||
struct btp_buf *buf;
|
||||
|
||||
avail_queue_init();
|
||||
bttester_evq_set(os_eventq_dflt_get());
|
||||
|
||||
ev = os_eventq_get(&avail_queue);
|
||||
buf = ev->ev_arg;
|
||||
|
||||
if (bttester_pipe_init()) {
|
||||
SYS_LOG_ERR("Failed to initialize pipe");
|
||||
return;
|
||||
}
|
||||
|
||||
bttester_pipe_register(buf->data, BTP_MTU, recv_cb);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_CORE, CORE_EV_IUT_READY, BTP_INDEX_NONE,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
void tester_send(u8_t service, u8_t opcode, u8_t index, u8_t *data,
|
||||
size_t len)
|
||||
{
|
||||
struct btp_hdr msg;
|
||||
|
||||
msg.service = service;
|
||||
msg.opcode = opcode;
|
||||
msg.index = index;
|
||||
msg.len = len;
|
||||
|
||||
bttester_pipe_send((u8_t *)&msg, sizeof(msg));
|
||||
if (data && len) {
|
||||
bttester_pipe_send(data, len);
|
||||
}
|
||||
|
||||
if (MYNEWT_VAL(BTTESTER_BTP_LOG)) {
|
||||
console_printf("[DBG] send %d bytes hdr: %s\n", sizeof(msg),
|
||||
bt_hex((char *) &msg, sizeof(msg)));
|
||||
if (data && len) {
|
||||
console_printf("[DBG] send %d bytes data: %s\n", len,
|
||||
bt_hex((char *) data, len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tester_send_buf(u8_t service, u8_t opcode, u8_t index,
|
||||
struct os_mbuf *data)
|
||||
{
|
||||
struct btp_hdr msg;
|
||||
|
||||
msg.service = service;
|
||||
msg.opcode = opcode;
|
||||
msg.index = index;
|
||||
msg.len = os_mbuf_len(data);
|
||||
|
||||
bttester_pipe_send((u8_t *)&msg, sizeof(msg));
|
||||
if (data && msg.len) {
|
||||
bttester_pipe_send_buf(data);
|
||||
}
|
||||
}
|
||||
|
||||
void tester_rsp(u8_t service, u8_t opcode, u8_t index, u8_t status)
|
||||
{
|
||||
struct btp_status s;
|
||||
|
||||
if (status == BTP_STATUS_SUCCESS) {
|
||||
tester_send(service, opcode, index, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
s.code = status;
|
||||
tester_send(service, BTP_STATUS, index, (u8_t *) &s, sizeof(s));
|
||||
}
|
||||
1010
src/libs/mynewt-nimble/apps/bttester/src/bttester.h
Normal file
1010
src/libs/mynewt-nimble/apps/bttester/src/bttester.h
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue