122 lines
3.4 KiB
C++
122 lines
3.4 KiB
C++
#ifndef SERIAL_PORT_WORKER_H_INCLUDED
|
|
#define SERIAL_PORT_WORKER_H_INCLUDED
|
|
|
|
#include <QObject>
|
|
#include <QString>
|
|
#include <QTimer>
|
|
#include <QSerialPort>
|
|
#include <QSerialPortInfo>
|
|
#include <QThread>
|
|
|
|
#include <assert.h>
|
|
#include <condition_variable>
|
|
#include <mutex>
|
|
#include <queue>
|
|
#include <deque>
|
|
#include <iostream>
|
|
#include <atomic>
|
|
|
|
|
|
struct Command {
|
|
enum : uint16_t {PRIORITY_1, PRIORITY_2, PRIORITY_3, PRIORITY_4, END_MARK};
|
|
enum : uint16_t {QUIT_SENTINEL = 0x1000, SEND_BLOCK_SIZE = 160};
|
|
uint32_t m_priority;
|
|
uint16_t m_priorityClass;
|
|
uint16_t m_cmdId;
|
|
char *m_sendBuffer;
|
|
char *m_recvBuffer;
|
|
uint8_t m_sendBufferLength;
|
|
uint8_t m_recvBufferLength; // expected result length
|
|
|
|
static std::atomic<uint8_t> m_nextSendBufferIndex;
|
|
static std::atomic<uint8_t> m_nextRecvBufferIndex;
|
|
static char m_sendBuffers[256][SEND_BLOCK_SIZE];
|
|
static char m_recvBuffers[256][SEND_BLOCK_SIZE];
|
|
|
|
static uint32_t getNextCommandPriority(uint8_t cmdType);
|
|
static char *getNextSendBuffer();
|
|
static char *getNextRecvBuffer();
|
|
|
|
public:
|
|
Command(uint16_t cmdId, uint8_t sendBufferLength, uint8_t recvBufferLength, uint8_t priorityClass);
|
|
Command();
|
|
|
|
friend bool operator< (Command const& lhs, Command const& rhs) {
|
|
return lhs.m_priority < rhs.m_priority;
|
|
}
|
|
|
|
friend std::ostream& operator<< (std::ostream& os, Command const& cmd) {
|
|
return os << "{ " << cmd.m_priority << ", '" << cmd.m_priority << "' } ";
|
|
}
|
|
};
|
|
|
|
/// \brief SerialPortWorker
|
|
///
|
|
/// SerialPortWorker sends and receives data from serial port
|
|
///
|
|
class SerialPortWorker : public QThread {
|
|
Q_OBJECT
|
|
|
|
/// \brief Internal serial port.
|
|
QSerialPort m_serialPort;
|
|
|
|
/// \brief Internal serial port info.
|
|
QSerialPortInfo m_serialPortInfo;
|
|
|
|
/// \brief Flag indicating if serial port is opened.
|
|
bool m_serialPortOpened;
|
|
|
|
/// \brief Port name of serial port.
|
|
QString m_portName;
|
|
|
|
/// \brief Baudrate of internal serial port.
|
|
enum QSerialPort::BaudRate m_baudRate;
|
|
|
|
std::priority_queue<Command, std::deque<Command>> m_sendQueue;
|
|
std::deque<Command> m_recvQueue;
|
|
std::mutex m_sendQueueMutex;
|
|
std::mutex m_recvQueueMutex;
|
|
std::condition_variable m_sendQueueCondVar;
|
|
std::condition_variable m_recvQueueCondVar;
|
|
|
|
std::atomic<uint32_t> m_bytesWritten;
|
|
std::atomic<uint32_t> m_bytesAvailable;
|
|
|
|
SerialPortWorker(QString portName, QSerialPort::BaudRate baudRate, QObject *parent = nullptr);
|
|
|
|
Command getNextCommand();
|
|
void insertResult(Command const &result);
|
|
|
|
enum : uint16_t {TIMEOUT = 100, WAIT_TIME_MAX = 1000};
|
|
|
|
public:
|
|
~SerialPortWorker();
|
|
|
|
SerialPortWorker(SerialPortWorker const &) = delete;
|
|
void operator=(SerialPortWorker const &) = delete;
|
|
|
|
// serial port im plugin anlegen. erst dann kann getInstance() benutzt werden
|
|
static SerialPortWorker &getInstance(QString portName, QSerialPort::BaudRate baudRate, QObject *parent = nullptr) {
|
|
static SerialPortWorker serialPortWorker(portName, baudRate, parent);
|
|
return serialPortWorker;
|
|
}
|
|
|
|
bool openSerialPort();
|
|
void closeSerialPort();
|
|
|
|
bool isPortOpen() const { return m_serialPortOpened; }
|
|
|
|
void insertCommand(Command const &cmd);
|
|
bool getNextResult(Command &result, int timeout = 1000);
|
|
|
|
virtual void run() override;
|
|
|
|
void quit();
|
|
|
|
private slots:
|
|
void getBytesAvailable();
|
|
bool getNumberOfBytesWritten(qint64);
|
|
};
|
|
|
|
#endif // SERIAL_PORT_WORKER_H_INCLUDED
|