#ifndef __DEVICE_H__ #define __DEVICE_H__ #ifdef __cplusplus #include #include #include #include #include #include "icsneo/api/eventmanager.h" #include "icsneo/device/neodevice.h" #include "icsneo/device/idevicesettings.h" #include "icsneo/device/nullsettings.h" #include "icsneo/device/devicetype.h" #include "icsneo/device/extensions/deviceextension.h" #include "icsneo/communication/communication.h" #include "icsneo/communication/packetizer.h" #include "icsneo/communication/encoder.h" #include "icsneo/communication/decoder.h" #include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/device/extensions/flexray/controller.h" #include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h" #include "icsneo/third-party/concurrentqueue/concurrentqueue.h" namespace icsneo { class Device { public: virtual ~Device() { if(isMessagePollingEnabled()) disableMessagePolling(); close(); if(heartbeatThread.joinable()) heartbeatThread.join(); } static std::string SerialNumToString(uint32_t serial); static uint32_t SerialStringToNum(const std::string& serial); static bool SerialStringIsNumeric(const std::string& serial); uint16_t getTimestampResolution() const; DeviceType getType() const { return DeviceType(data.type); } uint16_t getProductId() const { return productId; } std::string getSerial() const { return data.serial; } uint32_t getSerialNumber() const { return Device::SerialStringToNum(getSerial()); } const neodevice_t& getNeoDevice() const { return data; } std::string describe() const; friend std::ostream& operator<<(std::ostream& os, const Device& device) { os << device.describe(); return os; } virtual bool open(); virtual bool close(); virtual bool isOnline() const { return online; } virtual bool isOpen() const { return com->isOpen(); } virtual bool goOnline(); virtual bool goOffline(); // Message polling related functions bool enableMessagePolling(); bool disableMessagePolling(); bool isMessagePollingEnabled() { return messagePollingCallbackID != 0; }; std::pair>, bool> getMessages(); bool getMessages(std::vector>& container, size_t limit = 0, std::chrono::milliseconds timeout = std::chrono::milliseconds(0)); size_t getCurrentMessageCount() { return pollingContainer.size_approx(); } size_t getPollingMessageLimit() { return pollingMessageLimit; } void setPollingMessageLimit(size_t newSize) { pollingMessageLimit = newSize; enforcePollingMessageLimit(); } int addMessageCallback(const MessageCallback& cb) { return com->addMessageCallback(cb); } bool removeMessageCallback(int id) { return com->removeMessageCallback(id); } bool transmit(std::shared_ptr message); bool transmit(std::vector> messages); void setWriteBlocks(bool blocks); const std::vector& getSupportedRXNetworks() const { return supportedRXNetworks; } const std::vector& getSupportedTXNetworks() const { return supportedTXNetworks; } virtual bool isSupportedRXNetwork(const Network& net) const { return std::find(supportedRXNetworks.begin(), supportedRXNetworks.end(), net) != supportedRXNetworks.end(); } virtual bool isSupportedTXNetwork(const Network& net) const { return std::find(supportedTXNetworks.begin(), supportedTXNetworks.end(), net) != supportedTXNetworks.end(); } virtual size_t getNetworkCountByType(Network::Type) const; virtual Network getNetworkByNumber(Network::Type, size_t) const; virtual std::vector> getFlexRayControllers() const { return {}; } const device_eventhandler_t& getEventHandler() const { return report; } std::shared_ptr com; std::unique_ptr settings; protected: uint16_t productId = 0; bool online = false; int messagePollingCallbackID = 0; int internalHandlerCallbackID = 0; int messageReceivedCallbackID = 0; device_eventhandler_t report; // START Initialization Functions Device(neodevice_t neodevice = { 0 }) { data = neodevice; data.device = this; } template void initialize() { report = makeEventHandler(); auto driver = makeDriver(); setupDriver(*driver); auto encoder = makeEncoder(); setupEncoder(*encoder); auto decoder = makeDecoder(); setupDecoder(*decoder); com = makeCommunication(std::move(driver), std::bind(&Device::makeConfiguredPacketizer, this), std::move(encoder), std::move(decoder)); setupCommunication(*com); settings = makeSettings(com); setupSettings(*settings); setupSupportedRXNetworks(supportedRXNetworks); setupSupportedTXNetworks(supportedTXNetworks); setupExtensions(); } virtual device_eventhandler_t makeEventHandler() { return [this](APIEvent::Type type, APIEvent::Severity severity) { EventManager::GetInstance().add(type, severity, this); }; } template std::unique_ptr makeDriver() { return std::unique_ptr(new Driver(report, getWritableNeoDevice())); } virtual void setupDriver(Driver&) {} virtual std::unique_ptr makePacketizer() { return std::unique_ptr(new Packetizer(report)); } virtual void setupPacketizer(Packetizer&) {} std::unique_ptr makeConfiguredPacketizer() { auto packetizer = makePacketizer(); setupPacketizer(*packetizer); return packetizer; } virtual std::unique_ptr makeEncoder() { return std::unique_ptr(new Encoder(report)); } virtual void setupEncoder(Encoder&) {} virtual std::unique_ptr makeDecoder() { return std::unique_ptr(new Decoder(report)); } virtual void setupDecoder(Decoder&) {} virtual std::shared_ptr makeCommunication( std::unique_ptr t, std::function()> makeConfiguredPacketizer, std::unique_ptr e, std::unique_ptr d) { return std::make_shared(report, std::move(t), makeConfiguredPacketizer, std::move(e), std::move(d)); } virtual void setupCommunication(Communication&) {} template std::unique_ptr makeSettings(std::shared_ptr com) { return std::unique_ptr(new Settings(com)); } virtual void setupSettings(IDeviceSettings&) {} virtual void setupSupportedRXNetworks(std::vector&) {} virtual void setupSupportedTXNetworks(std::vector&) {} virtual void setupExtensions() {} void addExtension(std::shared_ptr&& extension); // Hook for devices such as FIRE which need to inject traffic before RequestSerialNumber // Return false to bail virtual bool afterCommunicationOpen() { return true; } template std::shared_ptr getExtension() const { std::shared_ptr ret; std::lock_guard lk(extensionsLock); for(auto& ext : extensions) { if((ret = std::dynamic_pointer_cast(ext))) break; } return ret; } // END Initialization Functions void handleInternalMessage(std::shared_ptr message); neodevice_t& getWritableNeoDevice() { return data; } private: neodevice_t data; std::shared_ptr latestResetStatus; mutable std::mutex extensionsLock; std::vector> extensions; void forEachExtension(std::function&)> fn); std::vector supportedTXNetworks; std::vector supportedRXNetworks; enum class LEDState : uint8_t { Offline = 0x04, CoreMiniRunning = 0x08, // This should override "offline" if the CoreMini is running Online = 0x10 }; LEDState ledState; void updateLEDState(); size_t pollingMessageLimit = 20000; moodycamel::BlockingConcurrentQueue> pollingContainer; void enforcePollingMessageLimit(); std::atomic stopHeartbeatThread{false}; std::thread heartbeatThread; }; } #endif // __cplusplus #endif