mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 09:28:40 +02:00
Add device sharing support
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user