Add device sharing support

This commit is contained in:
Kyle Schwarz
2022-12-13 11:46:32 -05:00
parent 78465e0f20
commit a9157c82e5
46 changed files with 1946 additions and 102 deletions
@@ -21,11 +21,14 @@
#include <thread>
#include <queue>
#include <map>
#include <list>
namespace icsneo {
class Communication {
public:
typedef std::function<void(std::vector<uint8_t>&)> RawCallback;
// Note that the Packetizer is not created by the constructor,
// and should be done once the Communication module is in place.
Communication(
@@ -45,6 +48,7 @@ public:
void modeChangeIncoming() { driver->modeChangeIncoming(); }
void awaitModeChangeComplete() { driver->awaitModeChangeComplete(); }
bool rawWrite(const std::vector<uint8_t>& bytes) { return driver->write(bytes); }
void modifyRawCallbacks(std::function<void(std::list<Communication::RawCallback>&)>&& cb);
virtual bool sendPacket(std::vector<uint8_t>& bytes);
bool redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo);
void clearRedirectRead();
@@ -88,6 +92,8 @@ protected:
std::atomic<bool> redirectingRead{false};
std::function<void(std::vector<uint8_t>&&)> redirectionFn;
std::mutex redirectingReadMutex; // Don't allow read to be disabled while in the redirectionFn
std::mutex rawCallbacksMutex;
std::list<std::function<void(std::vector<uint8_t>&)>> rawCallbacks;
std::mutex syncMessageMutex;
void dispatchMessage(const std::shared_ptr<Message>& msg);
+4 -1
View File
@@ -9,6 +9,7 @@
#include <thread>
#include <mutex>
#include <condition_variable>
#include "icsneo/device/neodevice.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/third-party/concurrentqueue/blockingconcurrentqueue.h"
@@ -16,7 +17,7 @@ namespace icsneo {
class Driver {
public:
Driver(const device_eventhandler_t& handler) : report(handler) {}
Driver(const device_eventhandler_t& handler, neodevice_t& forDevice) : report(handler), device(forDevice) {}
virtual ~Driver() {}
virtual bool open() = 0;
virtual bool isOpen() = 0;
@@ -24,12 +25,14 @@ public:
virtual void awaitModeChangeComplete() {}
virtual bool isDisconnected() { return disconnected; };
virtual bool close() = 0;
virtual bool enableHeartbeat() const { return false; }
bool read(std::vector<uint8_t>& bytes, size_t limit = 0);
bool readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0);
bool write(const std::vector<uint8_t>& bytes);
virtual bool isEthernet() const { return false; }
device_eventhandler_t report;
neodevice_t& device;
size_t writeQueueSize = 50;
bool writeBlocks = true; // Otherwise it just fails when the queue is full
@@ -0,0 +1,42 @@
#ifndef __INTERPROCESSMAILBOX_H_
#define __INTERPROCESSMAILBOX_H_
#ifdef __cplusplus
#include <cstdint>
#include "icsneo/platform/sharedmemory.h"
#include "icsneo/platform/sharedsemaphore.h"
static constexpr uint16_t MESSAGE_COUNT = 1024;
static constexpr uint16_t BLOCK_SIZE = 2048;
using LengthFieldType = uint16_t;
static constexpr uint8_t LENGTH_FIELD_SIZE = sizeof(LengthFieldType);
static constexpr uint16_t MAX_DATA_SIZE = BLOCK_SIZE - LENGTH_FIELD_SIZE;
namespace icsneo {
class InterprocessMailbox {
public:
bool open(const std::string& name, bool create = false /* create the shared resources or not */);
bool close();
operator bool() const;
// data must be large enough to hold at least MAX_DATA_SIZE
// messageLength can be larger than MAX_DATA_SIZE if the message spans multiple blocks, only MAX_DATA_SIZE will be read
bool read(void* data, LengthFieldType& messageLength, const std::chrono::milliseconds& timeout);
// if messageLength is larger than MAX_DATA_SIZE it's expected that future write() calls will send the remaining data
bool write(const void* data, LengthFieldType messageLength, const std::chrono::milliseconds& timeout);
private:
icsneo::SharedSemaphore queuedSem;
icsneo::SharedSemaphore emptySem;
icsneo::SharedMemory sharedMem;
unsigned index = 0; // index into messages;
bool valid = false;
};
}
#endif // __cplusplus
#endif
+34
View File
@@ -0,0 +1,34 @@
#ifndef __SDIO_H_
#define __SDIO_H_
#ifdef __cplusplus
#include "icsneo/communication/driver.h"
#include "icsneo/communication/interprocessmailbox.h"
namespace icsneo {
class SDIO : public Driver {
public:
static void Find(std::vector<FoundDevice>& found);
SDIO(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err, forDevice) {}
~SDIO() { if(isOpen()) close(); }
bool open() override;
bool close() override;
bool isOpen() override;
bool enableHeartbeat() const override { return true; }
private:
void readTask() override;
void writeTask() override;
bool deviceOpen = false;
InterprocessMailbox outboundIO;
InterprocessMailbox inboundIO;
};
}
#endif // __cplusplus
#endif
+124
View File
@@ -0,0 +1,124 @@
#ifndef __SOCKET_H_
#define __SOCKET_H_
#ifdef __cplusplus
#include <vector>
#include <optional>
#include <string>
#include <memory>
#include <functional>
#include <mutex>
#include <atomic>
#ifdef _WIN32
#define NOMINMAX
#include <winsock2.h>
#include <ws2tcpip.h>
typedef SOCKET SocketFileDescriptor;
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#include <cerrno>
#include <string.h>
typedef int SocketFileDescriptor;
#endif
namespace icsneo {
enum class RPC {
DEVICE_FINDER_FIND_ALL,
DEVICE_FINDER_GET_SUPORTED_DEVICES,
DEVICE_OPEN,
DEVICE_GO_ONLINE,
DEVICE_GO_OFFLINE,
DEVICE_CLOSE,
DEVICE_LOCK,
DEVICE_UNLOCK,
SDIO_OPEN,
SDIO_CLOSE,
GET_EVENTS,
GET_LAST_ERROR,
GET_EVENT_COUNT,
DISCARD_EVENTS,
SET_EVENT_LIMIT,
GET_EVENT_LIMIT
};
static constexpr uint16_t RPC_PORT = 54949;
class SocketBase {
public:
enum class Protocol {
TCP = SOCK_STREAM,
};
bool open();
bool close();
bool connect();
bool isOpen();
bool isConnected();
bool read(void* output, std::size_t length);
bool write(const void* input, std::size_t length);
bool writeString(const std::string& str);
bool readString(std::string& str);
template<typename... Ts>
bool writeTyped(Ts... input) {
return (... && write(&input, sizeof(input)));
}
template<typename... Ts>
bool readTyped(Ts&... output) {
return (... && read(&output, sizeof(output)));
}
protected:
Protocol protocol;
uint16_t port;
SocketFileDescriptor sockFileDescriptor;
bool sockIsOpen = false;
bool sockIsConnected = false;
void setIgnoreSIGPIPE();
};
// RAII Socket
class ActiveSocket : public SocketBase {
public:
ActiveSocket(SocketFileDescriptor sockFD);
ActiveSocket(Protocol protocol, uint16_t port);
~ActiveSocket();
};
// RAII Socket IO
class LockedSocket : public SocketBase {
public:
LockedSocket(SocketBase& socket, std::unique_lock<std::mutex>&& lock);
private:
std::unique_lock<std::mutex> lock;
};
class Acceptor : public ActiveSocket {
public:
Acceptor(Protocol protocol, uint16_t port);
bool initialize();
std::shared_ptr<ActiveSocket> accept();
private:
bool isValid = false;
bool bind();
bool listen();
};
LockedSocket lockSocket();
}
#endif // __cplusplus
#endif