Dawn Framework 1.0
Universal data acquisition framework for embedded systems
prph_bas.cxx
1// dawn/src/proto/nimble/prph_bas.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/proto/nimble/prph_bas.hxx"
7
8#include <cstring>
9#include <errno.h>
10#include <new>
11
12#include "dawn/io/common.hxx"
13
14extern "C"
15{
16#include "services/bas/ble_svc_bas.h"
17}
18
19using namespace dawn;
20
21int CProtoNimblePrphBas::notifierCb(void *priv, io_ddata_t *data)
22{
23 SPrphNotiferCb *ncb = static_cast<SPrphNotiferCb *>(priv);
24
25 if (ncb == nullptr)
26 {
27 DAWNERR("NULL ncb pointer in BAS notifier\n");
28 return -EINVAL;
29 }
30
31 if (data == nullptr)
32 {
33 DAWNERR("NULL data pointer in BAS notifier\n");
34 return -EINVAL;
35 }
36
37 if (ncb->data == nullptr)
38 {
39 DAWNERR("NULL BAS data buffer in notifier\n");
40 return -EINVAL;
41 }
42
43 std::memcpy(ncb->data->getDataPtr(), data->getDataPtr(), ncb->data->getDataSize());
44
45 ble_svc_bas_battery_level_set(*static_cast<uint8_t *>(ncb->data->getDataPtr()));
46
47 return OK;
48}
49
50void CProtoNimblePrphBas::allocObject(const SObjectId::UObjectId &obj)
51{
52 DAWNINFO("allocate object 0x%" PRIx32 "\n", obj.v);
53
54 // Allocate object in map
55
56 cb->regObject(obj.v);
57
58 vio.push_back(obj.v);
59}
60
61// Assumption: Configuration item passed by caller is a valid type supported by
62// this class.
63void CProtoNimblePrphBas::configureDesc(const SObjectCfg::SObjectCfgItem *item)
64{
65 if (item->cfgid.s.size != 1)
66 {
67 DAWNERR("Invalid BAS config size: %d\n", item->cfgid.s.size);
68 return;
69 }
70
71 const auto *tmp = reinterpret_cast<const SProtoNimblePrphIOBindBas *>(&item->data);
72
73 // Allocate object
74
75 allocObject(tmp->objid);
76}
77
78CProtoNimblePrphBas::CProtoNimblePrphBas(const SObjectCfg::SObjectCfgItem *desc_,
80 : IProtoNimblePrphService(desc_, cb_)
81 , ncb(nullptr)
82{
83 // Service ID not assigned yet
84
85 id = -1;
86}
87
88CProtoNimblePrphBas::~CProtoNimblePrphBas()
89{
90 deinit();
91}
92
94{
95 // Configure object
96
97 configureDesc(desc);
98
99 // Battery Service
100
101 ble_svc_bas_init();
102
103 // Register servie in peripheral handler
104
105 id = cb->serviceRegister(nullptr);
106 if (id < 0)
107 {
108 DAWNERR("BAS service registration failed\n");
109 return -EIO;
110 }
111
112 return OK;
113}
114
116{
117 if (ncb != nullptr)
118 {
119#ifdef CONFIG_DAWN_IO_NOTIFY
120 if (ncb->io != nullptr && ncb->io->isNotify())
121 {
122 ncb->io->setNotifier(nullptr, 0, nullptr);
123 }
124#endif
125
126 delete ncb->data;
127 delete ncb;
128 ncb = nullptr;
129 }
130
131 return OK;
132}
133
134int CProtoNimblePrphBas::bindObject()
135{
136 CIOCommon *io;
137 int ret;
138
139 if (ncb != nullptr)
140 {
141 return OK;
142 }
143
144 if (vio.size() != 1)
145 {
146 DAWNERR("BAS requires exactly one battery-level IO\n");
147 return -EINVAL;
148 }
149
150 io = cb->getObject(vio[0]);
151 if (io == nullptr)
152 {
153 DAWNERR("BAS IO not found\n");
154 return -EIO;
155 }
156
157 if (io->isSeekable())
158 {
159 DAWNERR("seekable IO not supported by BAS (objid=0x%08" PRIx32 ")\n", io->getIdV());
160 return -ENOTSUP;
161 }
162
163 if (!io->isNotify())
164 {
165 DAWNERR("BAS requires notify-capable IO (objid=0x%08" PRIx32 ")\n", io->getIdV());
166 return -ENOTSUP;
167 }
168
169 if (io->getDataSize() < sizeof(uint8_t))
170 {
171 DAWNERR("BAS IO data size too small: %zu\n", io->getDataSize());
172 return -EINVAL;
173 }
174
175 ncb = new (std::nothrow) SPrphNotiferCb();
176 if (ncb == nullptr)
177 {
178 DAWNERR("BAS notifier allocation failed\n");
179 return -ENOMEM;
180 }
181
182 ncb->io = io;
183 ncb->handle = 0;
184 ncb->data = io->ddata_alloc(1);
185 if (ncb->data == nullptr)
186 {
187 DAWNERR("BAS data allocation failed\n");
188 delete ncb;
189 ncb = nullptr;
190 return -ENOMEM;
191 }
192
193 ret = io->setNotifier(notifierCb, 0, ncb);
194 if (ret < 0)
195 {
196 DAWNERR("ERROR: set notifier failed for BAS objId = 0x%" PRIx32 "\n", vio[0]);
197 delete ncb->data;
198 delete ncb;
199 ncb = nullptr;
200 return ret;
201 }
202
203 return OK;
204}
205
206int CProtoNimblePrphBas::updateBatteryLevel()
207{
208 uint8_t level;
209 int ret;
210
211 if (ncb == nullptr || ncb->io == nullptr || ncb->data == nullptr)
212 {
213 return -EINVAL;
214 }
215
216 ret = ncb->io->getData(*ncb->data, 1);
217 if (ret < 0)
218 {
219 return ret;
220 }
221
222 level = *static_cast<uint8_t *>(ncb->data->getDataPtr());
223 return ble_svc_bas_battery_level_set(level);
224}
225
227{
228 int ret;
229
230 ret = bindObject();
231 if (ret != OK)
232 {
233 return ret;
234 }
235
236 ret = updateBatteryLevel();
237 if (ret != OK)
238 {
239 return ret;
240 }
241
242 // Signal start to peripheral handler
243
244 return cb->startService(id);
245}
246
248{
249 // Signal stop to peripheral handler
250
251 return cb->stopService(id);
252}
Base class for all I/O objects.
Definition common.hxx:27
virtual bool isNotify() const =0
Check if IO supports notifications.
virtual bool isSeekable() const
Check if IO supports partial (seekable) access.
Definition common.hxx:502
io_ddata_t * ddata_alloc(size_t batch, size_t chunk_size=0)
Allocate data buffer for this I/O.
Definition common.cxx:247
virtual size_t getDataSize() const =0
Get data size in bytes.
SObjectId::ObjectId getIdV() const
Get object identifier as raw 32-bit value.
Definition object.cxx:155
int stop()
Stop service.
Definition prph_bas.cxx:247
int init()
Initialize service.
Definition prph_bas.cxx:93
int start()
Start service.
Definition prph_bas.cxx:226
int deinit()
Deinitialize service.
Definition prph_bas.cxx:115
Interface for BLE peripheral services with GATT characteristics.
Definition iprph.hxx:24
virtual int startService(int id)=0
Start a specific service.
virtual CIOCommon * getObject(SObjectId::ObjectId id)=0
Get protocol object by ID.
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.
virtual int stopService(int id)=0
Stop a specific service.
Base interface for GATT services exposed by BLE peripheral.
Definition iprph.hxx:467
std::vector< SObjectId::ObjectId > vio
Vector of I/O objects exposed by this service.
Definition iprph.hxx:557
const SObjectCfg::SObjectCfgItem * desc
Configuration descriptor for this service.
Definition iprph.hxx:574
IProtoNimblePrphCb * cb
Callback interface to peripheral.
Definition iprph.hxx:566
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
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).
Heap-allocated dynamic I/O data buffer.
Definition ddata.hxx:21
void * getDataPtr(size_t batch=0)
Get pointer to data only (skips timestamp if present).
Definition ddata.hxx:180
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.
32-bit encoded object identifier (union with bit field).
Definition objectid.hxx:218
ObjectId v
Raw 32-bit ObjectID value (for comparison, hashing, storage).
Definition objectid.hxx:221