6#include "dawn/proto/nimble/prph_imds.hxx"
11#include "dawn/io/common.hxx"
12#include "dawn/io/sdata.hxx"
13#include "dawn/proto/nimble/gatt_runtime.hxx"
14#include "host/ble_hs_mbuf.h"
15#include "os/os_mbuf.h"
19#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
20static ble_uuid_any_t *imdsMakeUuid16(uint16_t value)
22 ble_uuid_any_t *uuid =
new (std::nothrow) ble_uuid_any_t{};
28 uuid->u.type = BLE_UUID_TYPE_16;
29 uuid->u16.value = value;
33static void imdsFreeUuid(
const ble_uuid_t *uuid)
37 delete reinterpret_cast<const ble_uuid_any_t *
>(uuid);
42#ifdef CONFIG_DAWN_IO_NOTIFY
43int CProtoNimblePrphImds::notifierCb(
void *priv,
io_ddata_t *data)
45 SPrphNotiferCb *ncb =
static_cast<SPrphNotiferCb *
>(priv);
49 DAWNERR(
"NULL ncb pointer in notifier\n");
57 DAWNERR(
"NULL io pointer in notifier\n");
63 std::memcpy(ncb->data->getDataPtr(), data->
getDataPtr(), ncb->data->getDataSize());
67 ble_gatts_chr_updated(ncb->handle);
73#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
74int CProtoNimblePrphImds::descriptorCb(uint16_t conn_handle,
76 struct ble_gatt_access_ctxt *ctxt,
79 SImdsDscCb *dcb =
static_cast<SImdsDscCb *
>(arg);
85 if (dcb ==
nullptr || ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC)
87 return BLE_ATT_ERR_UNLIKELY;
90 ret = os_mbuf_append(ctxt->om, dcb->data, dcb->len);
93 DAWNERR(
"IMDS descriptor append failed %d\n", ret);
94 return BLE_ATT_ERR_UNLIKELY;
103template<
typename T,
size_t WriteBytes>
104int CProtoNimblePrphImds::callback(uint16_t conn_handle,
105 uint16_t attr_handle,
106 struct ble_gatt_access_ctxt *ctxt,
109 SPrphNotiferCb *ncb =
static_cast<SPrphNotiferCb *
>(arg);
111 uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid);
116 case BLE_GATT_ACCESS_OP_READ_CHR:
120#ifdef CONFIG_DAWN_IO_NOTIFY
126 ret = io->
getData(*ncb->data, 1);
129 return BLE_ATT_ERR_UNLIKELY;
149 DAWNERR(
"IMDS data type not supported yet\n");
150 return BLE_ATT_ERR_UNLIKELY;
155 ret = os_mbuf_append(ctxt->om, &retval, WriteBytes);
158 DAWNERR(
"os_mbuf_append failed %d\n", ret);
166 DAWNERR(
"IMDS GATT operation not supported\n");
167 return BLE_ATT_ERR_UNLIKELY;
172int CProtoNimblePrphImds::allocIMDS()
176 svc.type = BLE_GATT_SVC_TYPE_PRIMARY;
178 svc.includes =
nullptr;
186 svc.characteristics =
new (std::nothrow) ble_gatt_chr_def[noChar]();
187 if (svc.characteristics ==
nullptr)
189 DAWNERR(
"Failed to allocate characteristics\n");
196int CProtoNimblePrphImds::createIMDS()
198 const uint32_t *char_uuid =
nullptr;
202 if (svc.characteristics ==
nullptr)
204 DAWNERR(
"Failed to allocate characteristics\n");
210 svc.type = BLE_GATT_SVC_TYPE_PRIMARY;
212 svc.includes =
nullptr;
214 for (
auto const objid :
vio)
222 struct ble_gatt_chr_def *chr =
const_cast<struct ble_gatt_chr_def *
>(&svc.characteristics[j]);
226 DAWNERR(
"IMDS IO not found\n");
234 DAWNERR(
"seekable IO not supported by IMDS"
235 " (objid=0x%08" PRIx32
")\n",
240 SPrphNotiferCb *ncb = nimbleGattNotifierCreate(io);
243 DAWNERR(
"IMDS notifier allocation failed\n");
249 nimbleGattChrInit(*chr, ncb);
254#ifdef CONFIG_DAWN_IO_NOTIFY
255 ret = nimbleGattChrNotifySet(*chr, *io, *ncb, notifierCb, objid);
258 DAWNERR(
"IMDS notifier setup failed\n");
262 nimbleGattChrAccessSet(*chr, *io);
266 switch (ioTypeMap[objid])
270 chr->access_cb = CProtoNimblePrphImds::callback<int16_t>;
277 chr->access_cb = CProtoNimblePrphImds::callback<int16_t>;
284 chr->access_cb = CProtoNimblePrphImds::callback<uint32_t>;
291 chr->access_cb = CProtoNimblePrphImds::callback<uint8_t>;
300 chr->access_cb = CProtoNimblePrphImds::callback<int16_t>;
309 chr->access_cb = CProtoNimblePrphImds::callback<uint32_t, 3>;
316 DAWNERR(
"unknown IMDS type %d\n", ioTypeMap[objid]);
317 nimbleGattChrNotifierFree(*chr);
324 if (char_uuid ==
nullptr)
326 DAWNERR(
"No UUID for IMDS IO\n");
327 nimbleGattChrNotifierFree(*chr);
331 ret = nimbleGattChrUuid128Set(*chr, char_uuid);
334 DAWNERR(
"IMDS UUID allocation failed\n");
335 nimbleGattChrNotifierFree(*chr);
339 ret = configureDescriptors(chr, objid);
342 nimbleGattChrUuidFree(*chr);
343 nimbleGattChrNotifierFree(*chr);
355void CProtoNimblePrphImds::deleteIMDS()
360 if (svc.characteristics)
362 for (
size_t i = 0; i < noChar - 1; i++)
364 if (svc.characteristics[i].uuid)
366 nimbleGattChrUuidFree(
const_cast<struct ble_gatt_chr_def &
>(svc.characteristics[i]));
369#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
370 if (svc.characteristics[i].descriptors)
372 struct ble_gatt_dsc_def *dsc =
373 const_cast<struct ble_gatt_dsc_def *
>(svc.characteristics[i].descriptors);
375 for (
size_t j = 0; dsc[j].uuid !=
nullptr; j++)
377 SImdsDscCb *dcb =
static_cast<SImdsDscCb *
>(dsc[j].arg);
379 imdsFreeUuid(dsc[j].uuid);
387 nimbleGattChrNotifierFree(
const_cast<struct ble_gatt_chr_def &
>(svc.characteristics[i]));
390 delete[]
const_cast<ble_gatt_chr_def *
>(svc.characteristics);
392 svc.characteristics =
nullptr;
397int CProtoNimblePrphImds::configureDescriptors(
struct ble_gatt_chr_def *chr,
400#ifndef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
405 const auto metaIt = ioMetaMap.find(objid);
407 struct ble_gatt_dsc_def *dsc;
411 if (metaIt == ioMetaMap.end())
416 meta =
const_cast<SImdsMeta *
>(&metaIt->second);
418# ifdef CONFIG_DAWN_PROTO_NIMBLE_IMDS_DESC_USER_DESCRIPTION
419 if (meta->desc & IMDS_DESC_USER_DESCRIPTION)
430 dsc =
new (std::nothrow) ble_gatt_dsc_def[count + 1]();
436# ifdef CONFIG_DAWN_PROTO_NIMBLE_IMDS_DESC_USER_DESCRIPTION
437 if (meta->desc & IMDS_DESC_USER_DESCRIPTION)
439 SImdsDscCb *dcb =
new (std::nothrow) SImdsDscCb{};
440 ble_uuid_any_t *uuid = imdsMakeUuid16(UUID16_CHR_USER_DESCRIPTION);
441 if (dcb ==
nullptr || uuid ==
nullptr)
444 imdsFreeUuid(uuid ? &uuid->u : nullptr);
449 dcb->kind = IMDS_DESC_USER_DESCRIPTION;
451 while (dcb->len < IMDS_USER_DESCRIPTION_MAX && meta->userDescription[dcb->len] !=
'\0')
453 dcb->data[dcb->len] =
static_cast<uint8_t
>(meta->userDescription[dcb->len]);
457 dsc[idx].uuid = &uuid->u;
458 dsc[idx].att_flags = BLE_ATT_F_READ;
459 dsc[idx].access_cb = descriptorCb;
465 chr->descriptors = dsc;
470void CProtoNimblePrphImds::allocObject(
const SProtoNimblePrphIOBindImdsObjid &obj,
473 uint8_t type = cfgIdIOBindImdsCfgObjTypeGet(obj.cfg);
474#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
478 DAWNINFO(
"IMDS allocate type=%d object 0x%" PRIx32
"\n", type, obj.objid.v);
482 ioTypeMap.insert_or_assign(obj.objid.v, type);
484#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
485 for (
size_t i = 0; i < obj.extCount; i++)
487 uint8_t kind = cfgIdIOBindImdsExtKindGet(ext[0]);
488 uint8_t size = cfgIdIOBindImdsExtSizeGet(ext[0]);
489 const uint32_t *data = &ext[1];
495 size_t bytes =
static_cast<size_t>(size) *
sizeof(uint32_t);
496 bytes = bytes < IMDS_USER_DESCRIPTION_MAX ? bytes : IMDS_USER_DESCRIPTION_MAX;
498# ifdef CONFIG_DAWN_PROTO_NIMBLE_IMDS_DESC_USER_DESCRIPTION
499 meta.desc |= IMDS_DESC_USER_DESCRIPTION;
500 std::memcpy(meta.userDescription, data, bytes);
507 DAWNERR(
"unknown IMDS extension kind %u\n", kind);
517 ioMetaMap.insert_or_assign(obj.objid.v, meta);
525 vio.push_back(obj.objid.v);
536 const SProtoNimblePrphIOBindImds *tmp =
537 reinterpret_cast<const SProtoNimblePrphIOBindImds *
>(&item->
data[k]);
539 uint8_t size = cfgIdIOBindImdsCfg0SizeGet(tmp->cfg0);
541 size_t pos = k +
sizeof(SProtoNimblePrphIOBindImds) /
sizeof(uint32_t);
543 for (
size_t i = 0; i < size; i++)
545 const SProtoNimblePrphIOBindImdsObjid *obj =
546 reinterpret_cast<const SProtoNimblePrphIOBindImdsObjid *
>(&item->
data[pos]);
547 const uint32_t *ext =
548 &item->
data[pos +
sizeof(SProtoNimblePrphIOBindImdsObjid) /
sizeof(uint32_t)];
552 allocObject(*obj, ext);
554 pos +=
sizeof(SProtoNimblePrphIOBindImdsObjid) /
sizeof(uint32_t);
555 for (
size_t j = 0; j < obj->extCount; j++)
557 pos += 1 + cfgIdIOBindImdsExtSizeGet(item->
data[pos]);
576CProtoNimblePrphImds::~CProtoNimblePrphImds()
602 DAWNERR(
"IMDS service registration failed\n");
Base class for all I/O objects.
int getData(IODataCmn &data, size_t len, size_t offset=0)
Get data from I/O (public interface with stats tracking).
virtual bool isNotify() const =0
Check if IO supports notifications.
virtual bool isSeekable() const
Check if IO supports partial (seekable) access.
SObjectId::ObjectId getIdV() const
Get object identifier as raw 32-bit value.
uint8_t getDtype() const
Get data type field.
int deinit()
Deinitialize service.
int init()
Initialize service.
int start()
Start service.
@ IMDS_EXT_USER_DESCRIPTION
Characteristic User Description descriptor.
@ PRPH_IMDS_TYPE_LIGHT
Industrial illuminance / light sensor.
@ PRPH_IMDS_TYPE_GAS
Industrial gas resistance sensor (non-standard UUID).
@ PRPH_IMDS_TYPE_TEMP
Industrial temperature sensor.
@ PRPH_IMDS_TYPE_UVIDX
Industrial UV index sensor.
@ PRPH_IMDS_TYPE_HUM
Industrial humidity sensor.
@ PRPH_IMDS_TYPE_PRESS
Industrial pressure sensor.
Interface for BLE peripheral services with GATT characteristics.
virtual int startService(int id)=0
Start a specific service.
static uint32_t UUID_UVIDX[4]
UV Index Characteristic UUID (0x2A76).
virtual size_t getObjectsLen()=0
Get count of registered I/O objects.
static float charScaleGet(uint16_t u)
Get scaling factor for a characteristic UUID.
virtual CIOCommon * getObject(SObjectId::ObjectId id)=0
Get protocol object by ID.
static uint32_t UUID_PRESS[4]
Pressure Characteristic UUID (0x2A6D).
static uint32_t UUID_TEMP[4]
Temperature Characteristic UUID (0x2A6E).
static uint32_t UUID_ILLUMINANCE[4]
Illuminance Characteristic UUID (0x2AFB).
static uint32_t UUID_RESISTANCE[4]
Electric Resistance Characteristic UUID (0x272A).
virtual int serviceRegister(struct ble_gatt_svc_def *svc)=0
Register a GATT service with the peripheral.
virtual void regObject(SObjectId::ObjectId id)=0
Register an I/O object for this service.
static uint32_t UUID_IMDS[4]
Industrial Measurement Device Service UUID (0x185A).
static uint32_t UUID_HUM[4]
Humidity Characteristic UUID (0x2A6F).
virtual int stopService(int id)=0
Stop a specific service.
Base interface for GATT services exposed by BLE peripheral.
std::vector< SObjectId::ObjectId > vio
Vector of I/O objects exposed by this service.
const SObjectCfg::SObjectCfgItem * desc
Configuration descriptor for this service.
IProtoNimblePrphCb * cb
Callback interface to peripheral.
Out-of-tree user-extension hooks for Dawn.
Single configuration item within object.
ObjectCfgData_t data[]
Configuration data array (flexible, size from cfgid.s.size).
UObjectCfgId cfgid
Configuration ID header (type, class, id, size, rw, dtype).
@ DTYPE_FLOAT
IEEE 754 single-precision floating point (32-bit).
uint32_t ObjectId
ObjectID type - single 32-bit value.
Heap-allocated dynamic I/O data buffer.
void * getDataPtr(size_t batch=0)
Get pointer to data only (skips timestamp if present).
uint32_t size
Configuration data size in 32-bit words (bits 5-14, max 1023).
struct dawn::SObjectCfg::UObjectCfgId::@10 s
Bit-field structure for named member access.