6#include "dawn/proto/simplebase.hxx"
11#include "dawn/io/common.hxx"
12#include "dawn/io/sdata.hxx"
16static inline uint32_t extractU32LE(
const uint8_t *p)
18 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
23 uint16_t crc = 0xFFFF;
25 for (
size_t i = 0; i < len; i++)
27 crc ^= (uint16_t)data[i] << 8;
28 for (
int j = 0; j < 8; j++)
32 crc = (crc << 1) ^ 0x1021;
44void CProtoSimpleBase::sendError(uint8_t error_code, uint8_t context)
46 uint8_t payload[2] = {error_code, context};
50#ifdef CONFIG_DAWN_IO_NOTIFY
51int CProtoSimpleBase::notifierCb(
void *priv,
io_ddata_t *data)
53 SProtoSimpleNotify *ctx;
57 uint8_t payload[4 + FRAME_MAX_PAYLOAD];
60 ctx = (SProtoSimpleNotify *)priv;
66 std::lock_guard<std::mutex> lock(proto->subsMutex);
67 if (proto->subscriptions.find(objid) == proto->subscriptions.end())
75 if (data_size > FRAME_MAX_PAYLOAD - 4)
77 DAWNERR(
"Data too large for notification\n");
81 payload[0] = (objid >> 0) & 0xFF;
82 payload[1] = (objid >> 8) & 0xFF;
83 payload[2] = (objid >> 16) & 0xFF;
84 payload[3] = (objid >> 24) & 0xFF;
86 std::memcpy(&payload[4], data->
getDataPtr(), data_size);
88 return proto->
sendFrame(CMD_NOTIFY, payload, 4 + data_size);
92void CProtoSimpleBase::cmdPing()
99 for (
auto *v : iobuffers)
101 if (objid == v->cfg->objid)
110void CProtoSimpleBase::cmdGetIO(
const uint8_t *payload,
size_t len)
112 const uint8_t *response;
121 sendError(STATUS_INVALID_FORMAT, CMD_GET_IO);
125 objid = extractU32LE(payload);
130 sendError(STATUS_INVALID_OBJ, CMD_GET_IO);
136 sendError(STATUS_WRITE_ONLY, CMD_GET_IO);
140 iodata = findIOBuffer(objid);
143 DAWNERR(
"Not found IO buffer\n");
144 sendError(STATUS_ERROR, CMD_GET_IO);
151 DAWNERR(
"get data failed\n");
152 sendError(STATUS_ERROR, CMD_GET_IO);
157 if (data_size > FRAME_MAX_PAYLOAD)
159 sendError(STATUS_ERROR, CMD_GET_IO);
163 response =
static_cast<const uint8_t *
>(iodata->
getDataPtr());
164 sendFrame(CMD_GET_IO, response, data_size);
167void CProtoSimpleBase::cmdSetIO(
const uint8_t *payload,
size_t len)
178 sendError(STATUS_INVALID_FORMAT, CMD_SET_IO);
182 objid = extractU32LE(payload);
187 sendError(STATUS_INVALID_OBJ, CMD_SET_IO);
193 sendError(STATUS_READ_ONLY, CMD_SET_IO);
197 iodata = findIOBuffer(objid);
200 DAWNERR(
"Not found IO buffer\n");
201 sendError(STATUS_ERROR, CMD_SET_IO);
211 sendError(STATUS_INVALID_FORMAT, CMD_SET_IO);
218 sendError(STATUS_ERROR, CMD_SET_IO);
224 old_size = iodata->N;
226 std::memcpy(iodata->
getDataPtr(), &payload[4], size);
228 iodata->N = old_size;
235 sendError(STATUS_ERROR, CMD_SET_IO);
239 std::memcpy(iodata->
getDataPtr(), &payload[4], size);
243 status = (ret == 0) ? STATUS_OK : STATUS_ERROR;
247void CProtoSimpleBase::cmdGetIOSeek(
const uint8_t *payload,
size_t len)
249 uint8_t response[FRAME_MAX_PAYLOAD];
261 sendError(STATUS_INVALID_FORMAT, CMD_GET_IO_SEEK);
265 objid = extractU32LE(payload);
266 offset = extractU32LE(&payload[4]);
271 sendError(STATUS_INVALID_OBJ, CMD_GET_IO_SEEK);
277 sendError(STATUS_WRITE_ONLY, CMD_GET_IO_SEEK);
283 sendError(STATUS_ERROR, CMD_GET_IO_SEEK);
290 sendError(STATUS_INVALID_FORMAT, CMD_GET_IO_SEEK);
294 iodata = findIOBuffer(objid);
297 DAWNERR(
"Not found IO buffer\n");
298 sendError(STATUS_ERROR, CMD_GET_IO_SEEK);
302 ret = io->
getData(*iodata, 1, offset);
305 DAWNERR(
"get data seek failed %d\n", ret);
306 sendError(STATUS_ERROR, CMD_GET_IO_SEEK);
310 avail = total - offset;
313 response[0] = (uint8_t)(objid & 0xFF);
314 response[1] = (uint8_t)((objid >> 8) & 0xFF);
315 response[2] = (uint8_t)((objid >> 16) & 0xFF);
316 response[3] = (uint8_t)((objid >> 24) & 0xFF);
318 response[4] = (uint8_t)(total & 0xFF);
319 response[5] = (uint8_t)((total >> 8) & 0xFF);
320 response[6] = (uint8_t)((total >> 16) & 0xFF);
321 response[7] = (uint8_t)((total >> 24) & 0xFF);
328void CProtoSimpleBase::cmdSetIOSeek(
const uint8_t *payload,
size_t len)
341 sendError(STATUS_INVALID_FORMAT, CMD_SET_IO_SEEK);
345 objid = extractU32LE(payload);
346 offset = extractU32LE(&payload[4]);
352 sendError(STATUS_INVALID_OBJ, CMD_SET_IO_SEEK);
358 sendError(STATUS_READ_ONLY, CMD_SET_IO_SEEK);
364 sendError(STATUS_ERROR, CMD_SET_IO_SEEK);
368 iodata = findIOBuffer(objid);
371 DAWNERR(
"Not found IO buffer\n");
372 sendError(STATUS_ERROR, CMD_SET_IO_SEEK);
378 sendError(STATUS_ERROR, CMD_SET_IO_SEEK);
382 old_size = iodata->N;
384 std::memcpy(iodata->
getDataPtr(), &payload[8], size);
385 ret = io->
setData(*iodata, offset);
386 iodata->N = old_size;
388 status = (ret == 0) ? STATUS_OK : STATUS_ERROR;
392void CProtoSimpleBase::cmdGetCfg(
const uint8_t *payload,
size_t len)
400 sendError(STATUS_INVALID_CFG, CMD_GET_CFG);
404 objid = extractU32LE(payload);
412 sendError(STATUS_INVALID_OBJ, CMD_GET_CFG);
416 sendError(STATUS_INVALID_CFG, CMD_GET_CFG);
419void CProtoSimpleBase::cmdSetCfg(
const uint8_t *payload,
size_t len)
427 sendError(STATUS_INVALID_CFG, CMD_SET_CFG);
431 objid = extractU32LE(payload);
439 sendError(STATUS_INVALID_OBJ, CMD_SET_CFG);
443 sendError(STATUS_INVALID_CFG, CMD_SET_CFG);
446void CProtoSimpleBase::cmdGetInfo(
const uint8_t *payload,
size_t len)
454 sendError(STATUS_INVALID_FORMAT, CMD_GET_INFO);
458 objid = extractU32LE(payload);
463 sendError(STATUS_INVALID_OBJ, CMD_GET_INFO);
469 response[0] = IO_TYPE_READ_WRITE;
473 response[0] = IO_TYPE_READ_ONLY;
477 response[0] = IO_TYPE_WRITE_ONLY;
481 sendError(STATUS_INVALID_OBJ, CMD_GET_INFO);
486 response[2] = (uint8_t)io->
getDtype();
491void CProtoSimpleBase::cmdListIOs()
493 uint8_t response[2 + FRAME_MAX_PAYLOAD - 2];
495 uint16_t count = (uint16_t)
getIOMap().size();
497 response[resp_len++] = (uint8_t)(count & 0xFF);
498 response[resp_len++] = (uint8_t)((count >> 8) & 0xFF);
500 for (
const auto &entry :
getIOMap())
504 if (resp_len + 4 > FRAME_MAX_PAYLOAD)
506 sendError(STATUS_ERROR, CMD_LIST_IOS);
512 response[resp_len++] = (uint8_t)(objid & 0xFF);
513 response[resp_len++] = (uint8_t)((objid >> 8) & 0xFF);
514 response[resp_len++] = (uint8_t)((objid >> 16) & 0xFF);
515 response[resp_len++] = (uint8_t)((objid >> 24) & 0xFF);
518 sendFrame(CMD_LIST_IOS, response, resp_len);
521#ifdef CONFIG_DAWN_IO_NOTIFY
522void CProtoSimpleBase::cmdSubscribe(
const uint8_t *payload,
size_t len)
530 sendError(STATUS_INVALID_FORMAT, CMD_SUBSCRIBE);
534 objid = extractU32LE(payload);
539 sendError(STATUS_INVALID_OBJ, CMD_SUBSCRIBE);
545 sendError(STATUS_ERROR, CMD_SUBSCRIBE);
550 std::lock_guard<std::mutex> lock(subsMutex);
551 subscriptions.insert(objid);
558void CProtoSimpleBase::cmdUnsubscribe(
const uint8_t *payload,
size_t len)
565 sendError(STATUS_INVALID_FORMAT, CMD_UNSUBSCRIBE);
569 objid = extractU32LE(payload);
572 std::lock_guard<std::mutex> lock(subsMutex);
573 subscriptions.erase(objid);
583 const uint8_t *payload;
584 uint16_t payload_len;
589 if (len < FRAME_MIN_LEN)
599 payload_len = (uint16_t)(frame[1] | (frame[2] << 8));
602 if (len != (
size_t)(FRAME_MIN_LEN + payload_len))
608 crc_recv = (uint16_t)(frame[4 + payload_len] | (frame[5 + payload_len] << 8));
610 if (crc_calc != crc_recv)
627 cmdGetIO(payload, payload_len);
633 cmdSetIO(payload, payload_len);
637 case CMD_GET_IO_SEEK:
639 cmdGetIOSeek(payload, payload_len);
643 case CMD_SET_IO_SEEK:
645 cmdSetIOSeek(payload, payload_len);
651 cmdGetCfg(payload, payload_len);
657 cmdSetCfg(payload, payload_len);
663 cmdGetInfo(payload, payload_len);
673#ifdef CONFIG_DAWN_IO_NOTIFY
676 cmdSubscribe(payload, payload_len);
680 case CMD_UNSUBSCRIBE:
682 cmdUnsubscribe(payload, payload_len);
689 sendError(STATUS_INVALID_CMD, cmd);
699 DAWNINFO(
"allocate object 0x%" PRIx32
"\n", cfg->objid);
702 iobinds.push_back(cfg);
712 for (
auto const *v : iobinds)
718 io =
getIO(v->objid);
721 DAWNERR(
"Failed to get IO 0x%08" PRIx32
"\n", v->objid);
728 DAWNERR(
"failed to allocate data\n");
732 iobuffers.push_back(tmp);
738 DAWNERR(
"failed to allocate register buffer\n");
742 tmp->iodata = iobuffer;
757 for (
auto *v : iobuffers)
770#ifdef CONFIG_DAWN_IO_NOTIFY
771int CProtoSimpleBase::setupNotifications()
775 for (
auto *v : iobuffers)
778 SProtoSimpleNotify *ctx;
780 io =
getIO(v->cfg->objid);
788 ctx =
new (std::nothrow) SProtoSimpleNotify[1]();
791 DAWNERR(
"Failed to allocate notification context\n");
795 ctx->objid = v->cfg->objid;
799 notifyContexts.push_back(ctx);
801 ret = io->setNotifier(notifierCb, 0, ctx);
804 DAWNERR(
"setNotifier failed for objid=0x%" PRIx32
"\n", ctx->objid);
806 notifyContexts.pop_back();
814void CProtoSimpleBase::cleanupNotifications()
817 std::lock_guard<std::mutex> lock(subsMutex);
818 subscriptions.clear();
822void CProtoSimpleBase::destroyNotifications()
824 cleanupNotifications();
826 for (
auto *ctx : notifyContexts)
831 notifyContexts.clear();
CIOCommon * getIO(SObjectId::ObjectId id)
Get an I/O object by ID.
void setObjectMapItem(SObjectId::ObjectId id, CObject *obj)
Set an item in the object map.
const std::map< SObjectId::ObjectId, CIOCommon * > & getIOMap() const
Get the I/O map for this object.
Base class for all I/O objects.
virtual bool isWrite() const =0
Check if IO supports write operations.
int setData(IODataCmn &data, size_t offset=0)
Set data for I/O (public interface with stats tracking).
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.
virtual size_t getDataDim() const =0
Get data vector dimension.
io_ddata_t * ddata_alloc(size_t batch, size_t chunk_size=0)
Allocate data buffer for this I/O.
virtual size_t getDataSize() const =0
Get data size in bytes.
virtual bool isRead() const =0
Check if IO supports read operations.
uint8_t getDtype() const
Get data type field.
Shared base for simple framed protocols.
static uint8_t FRAME_SYNC
Frame structure constants.
void allocObject(SProtoSimpleIOBind *cfg)
Store an allocated IO binding.
uint16_t calculateCrc(const uint8_t *data, size_t len)
Calculate 16-bit CRC checksum.
int handleFrame(const uint8_t *frame, size_t len)
Process a received frame.
int createBuffers()
Allocate shared per-IO data buffers.
static size_t SEEK_HDR_SIZE
Seek response constants.
int destroyBuffers()
Destroy shared per-IO data buffers.
virtual int sendFrame(uint8_t cmd, const uint8_t *payload, size_t len)=0
Send a framed response via the derived transport.
Out-of-tree user-extension hooks for Dawn.
Internal I/O data mapping for simple protocol handlers.
Configuration for binding an I/O object to a simple protocol.
uint32_t ObjectId
ObjectID type - single 32-bit value.
Heap-allocated dynamic I/O data buffer.
size_t getDataSize()
Get data size in bytes.
void * getDataPtr(size_t batch=0)
Get pointer to data only (skips timestamp if present).