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) \