From c68288fb4afea47ba2977e472a8ff7ed780b853a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chehade=20Daniel=20=28=D0=A8=D0=B5=D1=85=D0=B0=D0=B4=D0=B5?= =?UTF-8?q?=20=D0=94=D0=B0=D0=BD=D0=B8=D1=8D=D0=BB=D1=8C=29?= <71555323+danielsheh02@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:47:01 +0300 Subject: [PATCH] Support common serial devices. --- .../configs/kernel-4.14/model-config.xml | 10 +- .../configs/kernel-4.14/system-config.xml | 9 +- .../include/trikControl/brickInterface.h | 3 + .../trikControl/serialDeviceInterface.h | 35 +++++ trikControl/src/brick.cpp | 20 ++- trikControl/src/brick.h | 3 + trikControl/src/lidar.cpp | 6 +- trikControl/src/lidar.h | 3 +- trikControl/src/lidarWorker.cpp | 47 ++----- trikControl/src/lidarWorker.h | 6 +- trikControl/src/serialDevice.cpp | 126 ++++++++++++++++++ trikControl/src/serialDevice.h | 43 ++++++ trikControl/trikControl.pro | 5 +- .../trikScriptRunnerInterface.h | 2 + 14 files changed, 263 insertions(+), 55 deletions(-) create mode 100644 trikControl/include/trikControl/serialDeviceInterface.h create mode 100644 trikControl/src/serialDevice.cpp create mode 100644 trikControl/src/serialDevice.h diff --git a/trikControl/configs/kernel-4.14/model-config.xml b/trikControl/configs/kernel-4.14/model-config.xml index e1738da7f..d87094e14 100644 --- a/trikControl/configs/kernel-4.14/model-config.xml +++ b/trikControl/configs/kernel-4.14/model-config.xml @@ -139,9 +139,13 @@ Note that device, even if listed here, may fail by itself, then it also will not --> - - - + + + + + diff --git a/trikControl/configs/kernel-4.14/system-config.xml b/trikControl/configs/kernel-4.14/system-config.xml index e395adc57..91c532412 100644 --- a/trikControl/configs/kernel-4.14/system-config.xml +++ b/trikControl/configs/kernel-4.14/system-config.xml @@ -72,7 +72,7 @@ equal to its class name. - + @@ -177,7 +177,8 @@ equal to its class name. - + + @@ -225,7 +226,9 @@ equal to its class name. - + + + diff --git a/trikControl/include/trikControl/brickInterface.h b/trikControl/include/trikControl/brickInterface.h index cce4fb85a..4ee6a704a 100644 --- a/trikControl/include/trikControl/brickInterface.h +++ b/trikControl/include/trikControl/brickInterface.h @@ -38,6 +38,7 @@ #include "lidarInterface.h" #include "i2cDeviceInterface.h" #include "irCameraInterface.h" +#include "serialDeviceInterface.h" #include @@ -135,6 +136,8 @@ public Q_SLOTS: /// Returns i2c device object Q_INVOKABLE virtual trikControl::I2cDeviceInterface *i2c(int bus, int address, int regSize = 1) = 0; + Q_INVOKABLE virtual trikControl::SerialDeviceInterface *serialDevice(QString port) = 0; + /// Returns QVector with image using camera on given port (video0 or video1). Q_INVOKABLE virtual QVector getStillImage() = 0; diff --git a/trikControl/include/trikControl/serialDeviceInterface.h b/trikControl/include/trikControl/serialDeviceInterface.h new file mode 100644 index 000000000..2ea00feda --- /dev/null +++ b/trikControl/include/trikControl/serialDeviceInterface.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include "deviceInterface.h" + +#include + +namespace trikControl { + +class TRIKCONTROL_EXPORT SerialDeviceInterface : public QObject, public DeviceInterface +{ + Q_OBJECT + +public : + virtual int writeByte(const char byte) = 0; + virtual int writeArray(const QByteArray data) = 0; + virtual QByteArray read(const int maxLen) = 0; + virtual int read(char *data, int maxLen) = 0; + virtual int readByte() = 0; + virtual QByteArray readAll() = 0; + virtual void begin(int baud) = 0; + virtual int available() = 0; + virtual bool atEnd() = 0; + virtual void init() = 0; + virtual void enableConnect() = 0; + +Q_SIGNALS: + void newData(); + +}; + +} + +Q_DECLARE_METATYPE(trikControl::SerialDeviceInterface *) diff --git a/trikControl/src/brick.cpp b/trikControl/src/brick.cpp index 746cb5f57..933199e22 100644 --- a/trikControl/src/brick.cpp +++ b/trikControl/src/brick.cpp @@ -57,6 +57,8 @@ #include "mspI2cCommunicator.h" #include "lidar.h" #include "irCamera.h" +#include "serialDeviceInterface.h" +#include "serialDevice.h" #include "mspBusAutoDetector.h" #include "moduleLoader.h" @@ -460,6 +462,15 @@ I2cDeviceInterface *Brick::smBusI2c(int bus, int address) [this](){ return mHardwareAbstraction->createMspI2c();}); } +SerialDeviceInterface *Brick::serialDevice(QString port) +{ + if (mSerialDevices.contains(port)) { + return mSerialDevices[port]; + } else { + return nullptr; + } +} + QVector Brick::getStillImage() { if (!mCamera) @@ -625,8 +636,13 @@ void Brick::createDevice(const QString &port) connect(mSoundSensors[port], &SoundSensor::stopped, this, &Brick::stopped); } else if (deviceClass == "fifo") { mFifos.insert(port, new Fifo(port, mConfigurer, *mHardwareAbstraction)); - } else if (deviceClass == "lidar") { - mLidars.insert(port, new Lidar(port, mConfigurer, *mHardwareAbstraction)); + } else if (deviceClass == "serialDevice") { + const auto &deviceType = mConfigurer.deviceType(port); + if (deviceType == "lidar") { + mLidars.insert(port, new Lidar(new SerialDevice(port, mConfigurer), *mHardwareAbstraction)); + } else if (deviceType == "commonSerialDevice") { + mSerialDevices.insert(port, new SerialDevice(port, mConfigurer)); + } } else if (deviceClass == "camera") { QScopedPointer tmp ( new CameraDevice(port, mMediaPath, mConfigurer, *mHardwareAbstraction) diff --git a/trikControl/src/brick.h b/trikControl/src/brick.h index ed13a59bb..a6bf1ca51 100644 --- a/trikControl/src/brick.h +++ b/trikControl/src/brick.h @@ -128,6 +128,8 @@ public Q_SLOTS: I2cDeviceInterface *smBusI2c(int bus, int address) override; + SerialDeviceInterface *serialDevice(QString port) override; + QVector getStillImage() override; SoundSensorInterface *soundSensor(const QString &port) override; @@ -202,6 +204,7 @@ public Q_SLOTS: QHash mFifos; // Has ownership. QHash mEventDevices; // Has ownership. QHash mI2cDevices; // Has ownership. + QHash mSerialDevices; // Has ownership. QString mPlayWavFileCommand; QString mPlayMp3FileCommand; diff --git a/trikControl/src/lidar.cpp b/trikControl/src/lidar.cpp index bdbf59a53..dd20baf1f 100644 --- a/trikControl/src/lidar.cpp +++ b/trikControl/src/lidar.cpp @@ -14,13 +14,11 @@ #include "lidar.h" -#include - using namespace trikControl; -Lidar::Lidar(const QString &port, const trikKernel::Configurer &configurer +Lidar::Lidar(SerialDeviceInterface *serialDevice , trikHal::HardwareAbstractionInterface &hardwareAbstraction) - : mLidarWorker(new LidarWorker(configurer.attributeByPort(port, "file"), hardwareAbstraction)) + : mLidarWorker(new LidarWorker(serialDevice, hardwareAbstraction)) { mLidarWorker->moveToThread(&mWorkerThread); diff --git a/trikControl/src/lidar.h b/trikControl/src/lidar.h index bddbe38bd..4fa6c3315 100644 --- a/trikControl/src/lidar.h +++ b/trikControl/src/lidar.h @@ -22,6 +22,7 @@ #include "lidarWorker.h" #include +#include "serialDeviceInterface.h" namespace trikKernel { class Configurer; @@ -42,7 +43,7 @@ class Lidar : public LidarInterface /// Constructor. /// @param port - port on which this sensor is configured. /// @param configurer - configurer object containing preparsed XML files with lidar parameters. - Lidar(const QString &port, const trikKernel::Configurer &configurer + Lidar(SerialDeviceInterface *serialDevice , trikHal::HardwareAbstractionInterface &hardwareAbstraction); ~Lidar() override; diff --git a/trikControl/src/lidarWorker.cpp b/trikControl/src/lidarWorker.cpp index 8114ebc6c..ad087d5de 100644 --- a/trikControl/src/lidarWorker.cpp +++ b/trikControl/src/lidarWorker.cpp @@ -51,12 +51,12 @@ static uint16_t get_unaligned_be16(const void *p) { return (((uint16_t)data[0]) << 8) + data[1]; } -trikControl::LidarWorker::LidarWorker(const QString &fileName +trikControl::LidarWorker::LidarWorker(SerialDeviceInterface *serialDevice , const trikHal::HardwareAbstractionInterface &) - : mSerial(fileName) + : mSerialDevice(serialDevice) , mLidarChunk(new uint8_t[LIDAR_DATA_CHUNK_SIZE]) , mResult(ANGLES_RAW_NUMBER, 0) - , mState("Lidar on " + fileName) + , mState("Lidar on ") { mState.start(); mWaitForInit.acquire(1); @@ -73,41 +73,12 @@ LidarWorker::Status LidarWorker::status() const void LidarWorker::init() { - // TODO: refactor TRIK system config - // quick-and-dirty hack to avoid serial port misuse - if (mSerial.portName() == "ttyS1" || - mSerial.portName() == "/dev/ttyS1") { - QFile consoleConfig("/etc/default/ttyS1"); - if (consoleConfig.open(QIODevice::ReadOnly)) { - QTextStream in(&consoleConfig); - QString line = in.readLine(); - if (line != "LINE_PROTOCOL=lidar" && - line != "LINE_PROTOCOL=nothing") { - QLOG_ERROR() << "Lidar: the serial port ttyS1 is not designated for lidar"; - mState.fail(); - mWaitForInit.release(1); - return; - } - } - } - - if (!mSerial.open(QIODevice::ReadOnly)) { - QLOG_ERROR() << "Lidar: failed to open serial port " << mSerial.portName() - << " in read-only mode: " << mSerial.error(); - mState.fail(); - mWaitForInit.release(1); - return; - } - mSerial.setBaudRate(230400); - mSerial.setDataBits(QSerialPort::Data8); - mSerial.setParity(QSerialPort::NoParity); - mSerial.setStopBits(QSerialPort::OneStop); - mSerial.setFlowControl(QSerialPort::NoFlowControl); + mSerialDevice->enableConnect(); - connect(&mSerial, &QSerialPort::readyRead, this, &LidarWorker::readData); + connect(mSerialDevice, &SerialDeviceInterface::newData, this, &LidarWorker::readData); mState.ready(); - QLOG_INFO() << "Lidar: opened serial port" << mSerial.portName(); + QLOG_INFO() << "Lidar inited"; mWaitForInit.release(1); } @@ -139,13 +110,13 @@ void LidarWorker::readData() uint8_t bytes[256]; auto s = reinterpret_cast(mLidarChunk.data()); - while (!mSerial.atEnd()) { + while (!mSerialDevice->atEnd()) { // read data block from serial port - auto bytesRead = mSerial.read((char *)bytes, sizeof(bytes)); + auto bytesRead = mSerialDevice->read((char *)bytes, sizeof(bytes)); if (bytesRead == 0) return; if (bytesRead < 0) { - QLOG_ERROR() << "Lidar: read failed: " << mSerial.error() << " in " << mSerial.portName(); + QLOG_ERROR() << "Lidar: read failed"; return; } diff --git a/trikControl/src/lidarWorker.h b/trikControl/src/lidarWorker.h index 8c9344b35..fc343d973 100644 --- a/trikControl/src/lidarWorker.h +++ b/trikControl/src/lidarWorker.h @@ -24,6 +24,7 @@ #include "deviceState.h" #include +#include "serialDeviceInterface.h" namespace trikControl { @@ -36,7 +37,7 @@ class LidarWorker : public QObject, public DeviceInterface /// Constructor. /// @param fileName - name of a FIFO file. /// @param hardwareAbstraction - interface to underlying hardware or operating system capabilities of a robot. - explicit LidarWorker(const QString &fileName, const trikHal::HardwareAbstractionInterface &hardwareAbstraction); + explicit LidarWorker(SerialDeviceInterface *serialDevice, const trikHal::HardwareAbstractionInterface &hardwareAbstraction); ~LidarWorker(); Status status() const override; @@ -63,8 +64,7 @@ private Q_SLOTS: bool checkChecksum(const uint8_t *data, size_t size); - /// serial port QT object - QSerialPort mSerial; + SerialDeviceInterface *mSerialDevice; /// buffer for unparsed raw data chunks from serial port QScopedArrayPointer mLidarChunk; diff --git a/trikControl/src/serialDevice.cpp b/trikControl/src/serialDevice.cpp new file mode 100644 index 000000000..89408a9d1 --- /dev/null +++ b/trikControl/src/serialDevice.cpp @@ -0,0 +1,126 @@ +#include "serialDevice.h" +#include +#include + +using namespace trikControl; + +SerialDevice::SerialDevice(const QString &port, const trikKernel::Configurer &configurer) + : mSerial(configurer.attributeByPort(port, "file")) + , mState("SerialDevice") +{ + init(); +} + +void SerialDevice::init() { + QFile consoleConfig("/etc/default/ttyS1"); + if (consoleConfig.open(QIODevice::ReadOnly)) { + QTextStream in(&consoleConfig); + QString line = in.readLine(); + if (line != "LINE_PROTOCOL=serialDevice" && + line != "LINE_PROTOCOL=nothing") { + QLOG_ERROR() << "Lidar: the serial port ttyS1 is not designated for lidar"; + mState.fail(); + return; + } + } + + if (!mSerial.open(QIODevice::ReadOnly)) { + QLOG_ERROR() << "Error open serial devide" << mSerial.portName() + << " in read-only mode: " << mSerial.error(); + return; + } + mSerial.setDataBits(QSerialPort::Data8); + mSerial.setParity(QSerialPort::NoParity); + mSerial.setStopBits(QSerialPort::OneStop); + mSerial.setFlowControl(QSerialPort::NoFlowControl); + mState.ready(); + QLOG_INFO() << "Serial device: opened serial port" << mSerial.portName(); +} + +void SerialDevice::enableConnect() { + connect(&mSerial, &QSerialPort::readyRead, this, &SerialDevice::newData); +} + +void SerialDevice::begin(int baud) { + mSerial.setBaudRate(baud); +} + +SerialDevice::~SerialDevice() +{ + mSerial.close(); +} + +SerialDevice::Status SerialDevice::status() const +{ + return mState.status(); +} + +int SerialDevice::available() { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to get available bytes from serial which is not ready, ignoring"; + return 0; + } + return mSerial.bytesAvailable(); +} + +int SerialDevice::writeByte(const char byte) { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to write to serial which is not ready, ignoring"; + return 0; + } + return mSerial.write(&byte, 1); +} + +int SerialDevice::writeArray(const QByteArray data) { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to write to serial which is not ready, ignoring"; + return 0; + } + return mSerial.write(data); +} + +QByteArray SerialDevice::read(const int maxLen) { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to read from serial which is not ready, ignoring"; + return 0; + } + return mSerial.read(maxLen); +} + +int SerialDevice::read(char *data, int maxLen) { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to read from serial which is not ready, ignoring"; + return 0; + } + auto bytesRead = mSerial.read(data, maxLen); + if (bytesRead < 0) { + QLOG_ERROR() << "Serial device: read failed: " << mSerial.error() << " in " << mSerial.portName(); + } + return bytesRead; +} + +bool SerialDevice::atEnd() { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to check if at end of serial buffer, ignoring"; + return true; + } + return mSerial.atEnd(); +} + +int SerialDevice::readByte() { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to read from serial which is not ready, ignoring"; + return 0; + } + char byte; + mSerial.read(&byte, 1); + return static_cast(byte); +} + +QByteArray SerialDevice::readAll() { + if (!mState.isReady()) { + QLOG_ERROR() << "Trying to read from serial which is not ready, ignoring"; + return 0; + } + return mSerial.readAll(); +} diff --git a/trikControl/src/serialDevice.h b/trikControl/src/serialDevice.h new file mode 100644 index 000000000..871b04c0b --- /dev/null +++ b/trikControl/src/serialDevice.h @@ -0,0 +1,43 @@ +#pragma once + +#include "serialDeviceInterface.h" +#include +#include +#include "deviceState.h" +#include + +namespace trikControl { + +class SerialDevice : public SerialDeviceInterface +{ + Q_OBJECT +public: + SerialDevice(const QString &port, const trikKernel::Configurer &configurer); + ~SerialDevice(); + Status status() const override; + +public Q_SLOTS: + int writeByte(const char byte); + int writeArray(const QByteArray data); + QByteArray read(const int maxLen); + int read(char *data, int maxLen); + int readByte(); + QByteArray readAll(); + void begin(int baud); + int available(); + bool atEnd(); + void init(); + void enableConnect(); + +Q_SIGNALS: + void newData(); + +public: + QSerialPort mSerial; + QString mResult; + DeviceState mState; + QByteArray mBuffer; + +}; + +} diff --git a/trikControl/trikControl.pro b/trikControl/trikControl.pro index 8f8d817d1..ba1fa84ac 100644 --- a/trikControl/trikControl.pro +++ b/trikControl/trikControl.pro @@ -49,6 +49,7 @@ PUBLIC_HEADERS += \ $$PWD/include/trikControl/trikControlDeclSpec.h \ $$PWD/include/trikControl/lidarInterface.h \ $$PWD/include/trikControl/irCameraInterface.h \ + $$PWD/include/trikControl/serialDeviceInterface.h \ # $$PWD/include/trikControl/headingSensorInterface.h \ HEADERS += \ @@ -115,7 +116,8 @@ HEADERS += \ $$PWD/src/lidarWorker.h \ $$PWD/src/irCamera.h \ $$PWD/src/irCameraWorker.h \ - $$PWD/src/i2cCommunicatorInterface.h + $$PWD/src/i2cCommunicatorInterface.h \ + $$PWD/src/serialDevice.h \ SOURCES += \ $$PWD/src/abstractVirtualSensorWorker.cpp \ @@ -181,6 +183,7 @@ SOURCES += \ $$PWD/src/lidarWorker.cpp \ $$PWD/src/irCamera.cpp \ $$PWD/src/irCameraWorker.cpp \ + $$PWD/src/serialDevice.cpp \ CONFIGS += \ $$PWD/configs diff --git a/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h b/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h index 361dde77e..103d15395 100644 --- a/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h +++ b/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h @@ -44,6 +44,7 @@ #include #include #include +#include #include "trikScriptControlInterface.h" @@ -68,6 +69,7 @@ TEMPLATE(trikControl::GamepadInterface) \ TEMPLATE(trikControl::GyroSensorInterface) \ TEMPLATE(trikControl::I2cDeviceInterface) \ + TEMPLATE(trikControl::SerialDeviceInterface) \ TEMPLATE(trikControl::IrCameraInterface) \ TEMPLATE(trikControl::KeysInterface) \ TEMPLATE(trikControl::LedInterface) \