/*
|
* 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 "mgmt/mgmt.h"
|
#include "smp/smp.h"
|
#include "app_smp/smp.h"
|
|
extern struct ble_npl_eventq * smp_get_dflt_eventq(void);
|
|
/**
|
* \addtogroup SMP
|
* @{
|
*/
|
|
/* smp ble mqueue */
|
struct os_mqueue g_smp_ble_mq;
|
|
/* ble smp transport */
|
struct smp_transport g_smp_ble_transport;
|
|
/* ble smp attr handle */
|
uint16_t g_ble_smp_attr_handle;
|
|
/**
|
* The vendor specific "smp" service consists of one write no-rsp
|
* characteristic for smp requests: a single-byte characteristic that can
|
* only accepts write-without-response commands. The contents of each write
|
* command contains an NMP request. NMP responses are sent back in the form of
|
* unsolicited notifications from the same characteristic.
|
*/
|
|
/* {8D53DC1D-1DB7-4CD3-868B-8A527460AA84} */
|
static const ble_uuid128_t gatt_svr_svc_smp =
|
BLE_UUID128_INIT(0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86,
|
0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d);
|
|
/* {DA2E7828-FBCE-4E01-AE9E-261174997C48} */
|
static const ble_uuid128_t gatt_svr_chr_smp =
|
BLE_UUID128_INIT(0x48, 0x7c, 0x99, 0x74, 0x11, 0x26, 0x9e, 0xae,
|
0x01, 0x4e, 0xce, 0xfb, 0x28, 0x78, 0x2e, 0xda);
|
|
static int
|
gatt_svr_chr_access_smp(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: smp */
|
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
.uuid = &gatt_svr_svc_smp.u,
|
.characteristics = (struct ble_gatt_chr_def[]) { {
|
/* Characteristic: Write No Rsp */
|
.uuid = &gatt_svr_chr_smp.u,
|
.access_cb = gatt_svr_chr_access_smp,
|
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY,
|
.val_handle = &g_ble_smp_attr_handle,
|
}, {
|
0, /* No more characteristics in this service */
|
} },
|
},
|
|
{
|
0, /* No more services */
|
},
|
};
|
|
static int
|
gatt_svr_chr_access_smp(uint16_t conn_handle, uint16_t attr_handle,
|
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
{
|
int rc;
|
struct os_mbuf *m_req;
|
|
switch (ctxt->op) {
|
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
/* Try to reuse the BLE packet mbuf as the smp request. This
|
* requires a two-byte usrhdr to hold the BLE connection handle so
|
* that the smp response can be sent to the correct peer. If
|
* it is not possible to reuse the mbuf, then allocate a new one
|
* and copy the request contents.
|
*/
|
if (OS_MBUF_USRHDR_LEN(ctxt->om) >= sizeof (conn_handle)) {
|
/* Sufficient usrhdr space already present. */
|
m_req = ctxt->om;
|
ctxt->om = NULL;
|
} else if (OS_MBUF_LEADINGSPACE(ctxt->om) >=
|
sizeof (conn_handle)) {
|
|
/* Usrhdr isn't present, but there is enough leading space to
|
* add one.
|
*/
|
m_req = ctxt->om;
|
ctxt->om = NULL;
|
|
m_req->om_pkthdr_len += sizeof (conn_handle);
|
} else {
|
/* The mbuf can't be reused. Allocate a new one and perform a
|
* copy. Don't set ctxt->om to NULL; let the NimBLE host free
|
* it.
|
*/
|
m_req = os_msys_get_pkthdr(OS_MBUF_PKTLEN(ctxt->om),
|
sizeof (conn_handle));
|
if (!m_req) {
|
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
}
|
rc = os_mbuf_appendfrom(m_req, ctxt->om, 0,
|
OS_MBUF_PKTLEN(ctxt->om));
|
if (rc) {
|
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
}
|
}
|
|
/* Write the connection handle to the smp request usrhdr. This
|
* is necessary so that we later know who to send the smp
|
* response to.
|
*/
|
memcpy(OS_MBUF_USRHDR(m_req), &conn_handle, sizeof(conn_handle));
|
|
rc = smp_rx_req(&g_smp_ble_transport, m_req);
|
if (rc) {
|
return BLE_ATT_ERR_UNLIKELY;
|
}
|
|
return 0;
|
|
default:
|
assert(0);
|
return BLE_ATT_ERR_UNLIKELY;
|
}
|
}
|
|
uint16_t
|
smp_ble_get_mtu(struct os_mbuf *req) {
|
|
uint16_t conn_handle;
|
uint16_t mtu;
|
|
memcpy(&conn_handle, OS_MBUF_USRHDR(req), sizeof (conn_handle));
|
mtu = ble_att_mtu(conn_handle);
|
if (!mtu) {
|
/* No longer connected. */
|
return 0;
|
}
|
|
/* 3 is the number of bytes for ATT notification base */
|
mtu = mtu - 3;
|
|
return (mtu);
|
}
|
|
/**
|
* SMP ble process mqueue event
|
* Gets an event from the smp mqueue and does a notify with the response
|
*
|
* @param eventq
|
* @return 0 on success; non-zero on failure
|
*/
|
|
static void
|
smp_ble_event_data_in(struct ble_npl_event *ev)
|
{
|
struct os_mbuf *m_resp;
|
uint16_t conn_handle;
|
|
while ((m_resp = os_mqueue_get(&g_smp_ble_mq)) != NULL) {
|
assert(OS_MBUF_USRHDR_LEN(m_resp) >= sizeof (conn_handle));
|
memcpy(&conn_handle, OS_MBUF_USRHDR(m_resp), sizeof (conn_handle));
|
ble_gattc_notify_custom(conn_handle, g_ble_smp_attr_handle,
|
m_resp);
|
}
|
}
|
|
static int
|
smp_ble_out(struct os_mbuf *om)
|
{
|
int rc;
|
|
rc = os_mqueue_put(&g_smp_ble_mq, smp_get_dflt_eventq(), om);
|
if (rc != 0) {
|
goto err;
|
}
|
|
return 0;
|
err:
|
os_mbuf_free_chain(om);
|
return rc;
|
}
|
|
/**
|
* SMP ble GATT server initialization
|
*
|
* @param eventq
|
* @return 0 on success; non-zero on failure
|
*/
|
int
|
smp_ble_gatt_svr_init(void)
|
{
|
int rc;
|
|
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
if (rc != 0) {
|
goto err;
|
}
|
|
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
if (rc != 0) {
|
return rc;
|
}
|
|
os_mqueue_init(&g_smp_ble_mq, &smp_ble_event_data_in, NULL);
|
|
rc = smp_transport_init(&g_smp_ble_transport, smp_ble_out, smp_ble_get_mtu);
|
|
err:
|
return rc;
|
}
|
|
void
|
smp_ble_pkg_init(void)
|
{
|
int rc;
|
|
rc = smp_ble_gatt_svr_init();
|
assert(rc == 0);
|
}
|
|
/**
|
* @} SMP
|
*/
|