#ifndef __COMMUNICATION_H_ #define __COMMUNICATION_H_ #ifdef __cplusplus #include "icsneo/communication/driver.h" #include "icsneo/communication/command.h" #include "icsneo/communication/network.h" #include "icsneo/communication/packet.h" #include "icsneo/communication/message/callback/messagecallback.h" #include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/logicaldiskinfomessage.h" #include "icsneo/device/deviceversion.h" #include "icsneo/api/eventmanager.h" #include "icsneo/communication/packetizer.h" #include "icsneo/communication/encoder.h" #include "icsneo/communication/decoder.h" #include #include #include #include #include #include namespace icsneo { class Communication { public: // Note that the Packetizer is not created by the constructor, // and should be done once the Communication module is in place. Communication( device_eventhandler_t report, std::unique_ptr&& driver, std::function()> makeConfiguredPacketizer, std::unique_ptr&& e, std::unique_ptr&& md) : makeConfiguredPacketizer(makeConfiguredPacketizer), encoder(std::move(e)), decoder(std::move(md)), driver(std::move(driver)), report(report) {} virtual ~Communication(); bool open(); bool close(); bool isOpen(); bool isDisconnected(); virtual void spawnThreads(); virtual void joinThreads(); void modeChangeIncoming() { driver->modeChangeIncoming(); } void awaitModeChangeComplete() { driver->awaitModeChangeComplete(); } bool rawWrite(const std::vector& bytes) { return driver->write(bytes); } virtual bool sendPacket(std::vector& bytes); bool redirectRead(std::function&&)> redirectTo); void clearRedirectRead(); void setWriteBlocks(bool blocks) { driver->writeBlocks = blocks; } virtual bool sendCommand(Command cmd, bool boolean) { return sendCommand(cmd, std::vector({ (uint8_t)boolean })); } virtual bool sendCommand(Command cmd, std::vector arguments = {}); bool sendCommand(ExtendedCommand cmd, std::vector arguments = {}); bool getSettingsSync(std::vector& data, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::shared_ptr getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::optional< std::vector< std::optional > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::shared_ptr getLogicalDiskInfoSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); int addMessageCallback(const MessageCallback& cb); bool removeMessageCallback(int id); std::shared_ptr waitForMessageSync( const std::shared_ptr& f = {}, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) { return waitForMessageSync([](){ return true; }, f, timeout); } // onceWaitingDo is a way to avoid race conditions. // Return false to bail early, in case your initial command failed. std::shared_ptr waitForMessageSync( std::function onceWaitingDo, const std::shared_ptr& f = {}, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::function()> makeConfiguredPacketizer; std::unique_ptr packetizer; std::unique_ptr encoder; std::unique_ptr decoder; std::unique_ptr driver; device_eventhandler_t report; protected: static int messageCallbackIDCounter; std::mutex messageCallbacksLock; std::map messageCallbacks; std::atomic closing{false}; std::atomic redirectingRead{false}; std::function&&)> redirectionFn; std::mutex redirectingReadMutex; // Don't allow read to be disabled while in the redirectionFn void dispatchMessage(const std::shared_ptr& msg); void handleInput(Packetizer& p, std::vector& readBytes); private: std::thread readTaskThread; void readTask(); }; } #endif // __cplusplus #endif