From 63d13cdb884e9bc80d87f19f0a8e54308f37de19 Mon Sep 17 00:00:00 2001 From: Paul Hollinsky Date: Thu, 13 Sep 2018 19:40:23 -0400 Subject: [PATCH] Allow polling for messages from C --- api/icsneoc/icsneoc.cpp | 64 ++++++++++++++++++++++ api/icsneoc/include/icsneoc.h | 31 +++++++++++ communication/message/include/neomessage.h | 34 ++++++++++++ communication/message/neomessage.cpp | 24 ++++++++ device/device.cpp | 11 +--- device/include/device.h | 1 + 6 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 communication/message/include/neomessage.h create mode 100644 communication/message/neomessage.cpp diff --git a/api/icsneoc/icsneoc.cpp b/api/icsneoc/icsneoc.cpp index b2b0bea..80b4a3a 100644 --- a/api/icsneoc/icsneoc.cpp +++ b/api/icsneoc/icsneoc.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace icsneo; @@ -21,6 +22,9 @@ static std::vector> connectableFoundDevices, connectedDe // Any shared_ptrs we've let go should be placed here so they're not accessed static std::vector freedDevices; +// We store an array of shared_ptr messages per device (by serial), this means we own the memory of the data pointer +static std::map>> polledMessageStorage; + void icsneoFindAllDevices(neodevice_t* devices, size_t* count) { icsneoFreeUnconnectedDevices(); // Mark previous results as freed so they can no longer be connected to auto foundDevices = icsneo::FindAllDevices(); @@ -127,4 +131,64 @@ bool icsneoIsOnline(const neodevice_t* device) { return false; return device->device->isOnline(); +} + +bool icsneoEnableMessagePolling(const neodevice_t* device) { + if(!icsneoIsValidNeoDevice(device)) + return false; + + device->device->enableMessagePolling(); + return true; +} + +bool icsneoDisableMessagePolling(const neodevice_t* device) { + if(!icsneoIsValidNeoDevice(device)) + return false; + + return device->device->disableMessagePolling(); +} + +bool icsneoGetMessages(const neodevice_t* device, neomessage_t* messages, size_t* items) { + if(!icsneoIsValidNeoDevice(device)) + return false; + + if(items == nullptr) + return false; + + if(messages == nullptr) { + // A NULL value for messages means the user wants the current size of the buffer into items + *items = device->device->getCurrentMessageCount(); + return true; + } + + std::vector>& storage = polledMessageStorage[device->serial]; + + if(!device->device->getMessages(storage, *items)) + return false; + + *items = storage.size(); + + for(size_t i = 0; i < *items; i++) { + // For each message, copy into neomessage_t buffer given + messages[i] = CreateNeoMessage(*(storage[i])); + } + + // The user now has until the next call of icsneoGetMessages (for this device) to use the data, after which point it's freed + // The user should copy the data out if they want it + return true; +} + +size_t icsneoGetPollingMessageLimit(const neodevice_t* device) { + if(!icsneoIsValidNeoDevice(device)) + return 0; + + return device->device->getPollingMessageLimit(); +} + +bool icsneoSetPollingMessageLimit(const neodevice_t* device, size_t newLimit) { + if(!icsneoIsValidNeoDevice(device)) + return false; + + device->device->setPollingMessageLimit(newLimit); + return true; } \ No newline at end of file diff --git a/api/icsneoc/include/icsneoc.h b/api/icsneoc/include/icsneoc.h index a734a46..f0841a4 100644 --- a/api/icsneoc/include/icsneoc.h +++ b/api/icsneoc/include/icsneoc.h @@ -3,6 +3,7 @@ #include #include "device/include/neodevice.h" // For neodevice_t +#include "communication/message/include/neomessage.h" // For neomessage_t and friends #include "platform/include/dynamiclib.h" // Dynamic library loading and exporting #ifndef ICSNEOC_DYNAMICLOAD @@ -31,6 +32,16 @@ extern bool DLLExport icsneoGoOffline(const neodevice_t* device); extern bool DLLExport icsneoIsOnline(const neodevice_t* device); +extern bool DLLExport icsneoEnableMessagePolling(const neodevice_t* device); + +extern bool DLLExport icsneoDisableMessagePolling(const neodevice_t* device); + +extern bool DLLExport icsneoGetMessages(const neodevice_t* device, neomessage_t* messages, size_t* items); + +extern size_t DLLExport icsneoGetPollingMessageLimit(const neodevice_t* device); + +extern bool DLLExport icsneoSetPollingMessageLimit(const neodevice_t* device, size_t newLimit); + #ifdef __cplusplus } #endif @@ -67,6 +78,21 @@ fn_icsneoGoOffline icsneoGoOffline; typedef bool(*fn_icsneoIsOnline)(const neodevice_t* device); fn_icsneoIsOnline icsneoIsOnline; +typedef bool(*fn_icsneoEnableMessagePolling)(const neodevice_t* device); +fn_icsneoEnableMessagePolling icsneoEnableMessagePolling; + +typedef bool(*fn_icsneoDisableMessagePolling)(const neodevice_t* device); +fn_icsneoDisableMessagePolling icsneoDisableMessagePolling; + +typedef bool(*fn_icsneoGetMessages)(const neodevice_t* device, neomessage_t* messages, size_t* items); +fn_icsneoGetMessages icsneoGetMessages; + +typedef size_t(*fn_icsneoGetPollingMessageLimit)(const neodevice_t* device); +fn_icsneoGetPollingMessageLimit icsneoGetPollingMessageLimit; + +typedef bool(*fn_icsneoSetPollingMessageLimit)(const neodevice_t* device, size_t newLimit); +fn_icsneoSetPollingMessageLimit icsneoSetPollingMessageLimit; + #define ICSNEO_IMPORT(func) func = (fn_##func)icsneoDynamicLibraryGetFunction(icsneoLibraryHandle, #func) #define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3 void* icsneoLibraryHandle = NULL; @@ -91,6 +117,11 @@ int icsneoInit() { ICSNEO_IMPORTASSERT(icsneoGoOnline); ICSNEO_IMPORTASSERT(icsneoGoOffline); ICSNEO_IMPORTASSERT(icsneoIsOnline); + ICSNEO_IMPORTASSERT(icsneoEnableMessagePolling); + ICSNEO_IMPORTASSERT(icsneoDisableMessagePolling); + ICSNEO_IMPORTASSERT(icsneoGetMessages); + ICSNEO_IMPORTASSERT(icsneoGetPollingMessageLimit); + ICSNEO_IMPORTASSERT(icsneoSetPollingMessageLimit); icsneoInitialized = true; return 0; diff --git a/communication/message/include/neomessage.h b/communication/message/include/neomessage.h new file mode 100644 index 0000000..88cf067 --- /dev/null +++ b/communication/message/include/neomessage.h @@ -0,0 +1,34 @@ +#ifndef __NEOMESSAGE_H_ +#define __NEOMESSAGE_H_ + +#include + +typedef struct { + uint16_t netid; + uint8_t type; + char header[4]; + const uint8_t* data; + size_t length; + uint64_t timestamp; + char reserved[8]; +} neomessage_t; + +typedef struct { + uint16_t netid; + uint8_t type; + uint32_t arbid; + const uint8_t* data; + size_t length; + uint64_t timestamp; + char reserved[8]; +} neomessage_can_t; + +#ifdef __cplusplus +#include "communication/message/include/message.h" + +namespace icsneo { + neomessage_t CreateNeoMessage(const Message& message); +}; +#endif + +#endif \ No newline at end of file diff --git a/communication/message/neomessage.cpp b/communication/message/neomessage.cpp new file mode 100644 index 0000000..190f86b --- /dev/null +++ b/communication/message/neomessage.cpp @@ -0,0 +1,24 @@ +#include "communication/message/include/neomessage.h" +#include "communication/message/include/canmessage.h" + +using namespace icsneo; + +neomessage_t icsneo::CreateNeoMessage(const Message& message) { + // This function is not responsible for storing the message! + // Keep the shared_ptr around for the lifetime of the data access + const auto type = message.network.getType(); + neomessage_t neomsg = { 0 }; // Clear out the memory + neomsg.netid = (uint32_t)message.network.getNetID(); + neomsg.type = (uint8_t)type; + neomsg.length = message.data.size(); + neomsg.data = message.data.data(); + neomsg.timestamp = message.timestamp; + + switch(type) { + case Network::Type::CAN: + ((neomessage_can_t*)&neomsg)->arbid = ((const CANMessage*)&message)->arbid; + break; + } + + return neomsg; +} \ No newline at end of file diff --git a/device/device.cpp b/device/device.cpp index f53ab0f..dbc0d04 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -94,7 +94,6 @@ std::vector> Device::getMessages() { bool Device::getMessages(std::vector>& container, size_t limit) { // A limit of zero indicates no limit - auto oglimit = limit; if(limit == 0) limit = (size_t)-1; @@ -108,7 +107,7 @@ bool Device::getMessages(std::vector>& container, size_ container.resize(actuallyRead); - return actuallyRead <= oglimit; + return true; } void Device::enforcePollingMessageLimit() { @@ -140,14 +139,6 @@ bool Device::goOnline() { if(!com->sendCommand(Communication::Command::RequestSerialNumber)) return false; - com->addMessageCallback(CANMessageCallback([](std::shared_ptr message) { - std::shared_ptr canMessage = std::static_pointer_cast(message); - std::cout << "CAN 0x" << std::hex << canMessage->arbid << std::dec << " [" << canMessage->data.size() << "] " << std::hex; - for(const auto& b : canMessage->data) - std::cout << (int)b << ' '; - std::cout << std::dec << std::endl; - })); - return online = true; } diff --git a/device/include/device.h b/device/include/device.h index 7dec685..3dff63c 100644 --- a/device/include/device.h +++ b/device/include/device.h @@ -43,6 +43,7 @@ public: bool disableMessagePolling(); std::vector> getMessages(); bool getMessages(std::vector>& container, size_t limit = 0); + size_t getCurrentMessageCount() { return pollingContainer.size_approx(); } size_t getPollingMessageLimit() { return pollingMessageLimit; } void setPollingMessageLimit(size_t newSize) { pollingMessageLimit = newSize;