Explorar el Código

add serial communication

xuqiang hace 5 meses
padre
commit
31b209c234
Se han modificado 7 ficheros con 452 adiciones y 1 borrados
  1. 2 1
      CMakeLists.txt
  2. 3 0
      include/appcontext.h
  3. 144 0
      include/ringbuffer.h
  4. 24 0
      include/serialport.h
  5. 5 0
      src/appcontext.cpp
  6. 153 0
      src/ringbuffer.c
  7. 121 0
      src/serialport.cpp

+ 2 - 1
CMakeLists.txt

@@ -42,7 +42,7 @@ set(CMAKE_PREFIX_PATH
     ${QT5_DIR}/lib/cmake
 )
 
-find_package(Qt5 REQUIRED COMPONENTS Widgets UiPlugin Network)
+find_package(Qt5 REQUIRED COMPONENTS Widgets UiPlugin Network SerialPort)
 
 set(PROJECT_SOURCE_DIR_LIST
     ${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -103,6 +103,7 @@ target_link_libraries(${PROJECT_NAME}
     Qt5::Widgets
     Qt5::UiPlugin
     Qt5::Network
+    Qt5::SerialPort
 )
 
 target_link_directories(${PROJECT_NAME}

+ 3 - 0
include/appcontext.h

@@ -5,6 +5,7 @@
 #include "pluginmanager.h"
 #include "projectmanager.h"
 #include "network.h"
+#include "serialport.h"
 
 class AppContext : public QObject
 {
@@ -18,11 +19,13 @@ public:
     PluginManager &pluginManager();
     ProjectManager &projectManager();
     Network &network();
+    SerialPort &serialPort();
 
 private:
     PluginManager m_pluginMgr;
     ProjectManager m_projectMgr;
     Network m_network;
+    SerialPort m_serialPort;
 
 };
 

+ 144 - 0
include/ringbuffer.h

@@ -0,0 +1,144 @@
+/**
+ * @file    ringbuffer.h
+ * @brief   ringbuffer header file.
+ *
+ * @details 
+ *
+ * @author  jlgwch
+ * @date    2023-10-16
+ * @version 1.0
+ *
+ * @history
+ *  - 2023-10-16: jlgwch - Created the file.
+ *
+ * @copyright Copyright (c) 2023~ jlgwch. All rights reserved.
+ */
+
+#ifndef __RINGBUFFER_H__
+#define __RINGBUFFER_H__
+
+#include <stdint.h>
+
+#ifndef __cplusplus
+#ifndef bool
+typedef enum boolean { false, true } bool;
+#endif
+#endif
+
+typedef uint8_t data_t;
+
+typedef struct
+{
+    int head;
+    int tail;
+    int full_size;
+    int buffer_size;
+    data_t* data;
+} ringbuffer_st;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialize a ring buffer.
+ *
+ * This function initializes a ring buffer with the given size.
+ *
+ * @param ringbuffer Pointer to the ring buffer structure to be initialized.
+ * @param size Size of the ring buffer.
+ * @return true if initialization is successful, false otherwise.
+ */
+bool ringbuffer_init(ringbuffer_st* ringbuffer, int size);
+
+/**
+ * @brief Release resources used by the ring buffer.
+ *
+ * This function releases any dynamically allocated memory associated with the ring buffer.
+ *
+ * @param ringbuffer Pointer to the ring buffer to be released.
+ */
+void ringbuffer_release(ringbuffer_st* ringbuffer);
+
+/**
+ * @brief Append data to the ring buffer.
+ *
+ * This function appends data to the ring buffer. If the buffer is full, do nothing.
+ *
+ * @param ringbuffer Pointer to the ring buffer.
+ * @param buffer Pointer to the data to be appended.
+ * @param size Size of the data to be appended.
+ * @return 0 if append is successful, -1 otherwise.
+ */
+int ringbuffer_append(ringbuffer_st* ringbuffer, const data_t* buffer, int size);
+
+/**
+ * @brief Read data from the ring buffer.
+ *
+ * This function reads data from the ring buffer. The function will attempt to read up to the given size.
+ *
+ * @param ringbuffer The ring buffer from which data is to be read.
+ * @param data Pointer to the buffer where read data will be stored.
+ * @param size Size of data to be read from the buffer.
+ * @return The number of bytes successfully read.
+ */
+int ringbuffer_read(ringbuffer_st ringbuffer, data_t* data, int size);
+
+/**
+ * @brief Get data from a specific index in the ring buffer.
+ *
+ * This function retrieves data from a specific index in the ring buffer without removing it.
+ *
+ * @param ringbuffer The ring buffer from which data is to be retrieved.
+ * @param index Index of the data to retrieve.
+ * @param data Pointer to the variable where the retrieved data will be stored.
+ * @return `0` if the data was successfully retrieved and stored in `data`; 
+ *         `-1` if the index is out of bounds or the data could not be retrieved.
+ */
+int ringbuffer_data(ringbuffer_st ringbuffer, data_t* data, int index);
+
+/**
+ * @brief Pop data from the front of the ring buffer.
+ *
+ * This function removes the specified number of elements from the front of the buffer.
+ *
+ * @param ringbuffer Pointer to the ring buffer.
+ * @param size Number of elements to remove from the front of the buffer.
+ */
+void ringbuffer_popup(ringbuffer_st* ringbuffer, int size);
+
+/**
+ * @brief Clear the ring buffer.
+ *
+ * This function clears all the data in the ring buffer, resetting it to an empty state.
+ *
+ * @param ringbuffer Pointer to the ring buffer.
+ */
+void ringbuffer_clear(ringbuffer_st* ringbuffer);
+
+/**
+ * @brief Check if the ring buffer is empty.
+ *
+ * This function checks if the ring buffer is empty, meaning no data is currently stored.
+ *
+ * @param ringbuffer The ring buffer to check for emptiness.
+ * @return true if the buffer is empty, false otherwise.
+ */
+bool ringbuffer_empty(ringbuffer_st ringbuffer);
+
+/**
+ * @brief Print the contents of the ring buffer.
+ *
+ * This function prints the info stored in the ring buffer.
+ *
+ * @param ringbuffer The ring buffer to print.
+ * @param print_buffer A boolean flag that controls whether the entire buffer contents should be printed.
+ *                     If `true`, the entire buffer will be printed; if `false`, only summary information will be printed.
+ */
+void ringbuffer_print(ringbuffer_st ringbuffer, bool print_buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __RINGBUFFER_H__

+ 24 - 0
include/serialport.h

@@ -0,0 +1,24 @@
+#ifndef __SERIALPORT_H__
+#define __SERIALPORT_H__
+
+#include <QSerialPort>
+#include "ringbuffer.h"
+
+class SerialPort : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit SerialPort(QObject *parent = nullptr);
+    ~SerialPort();
+
+private:
+    QSerialPort m_serialPort;
+    ringbuffer_st m_ringbuffer;
+
+signals:
+    void pageSwitch(int state = 1);
+
+};
+
+#endif  // SERIALPORT_H

+ 5 - 0
src/appcontext.cpp

@@ -34,3 +34,8 @@ Network &AppContext::network()
     return m_network;
 }
 
+SerialPort &AppContext::serialPort()
+{
+    return m_serialPort;
+}
+

+ 153 - 0
src/ringbuffer.c

@@ -0,0 +1,153 @@
+/**
+ * @file    ringbuffer.c
+ * @brief   ringbuffer source file.
+ *
+ * @details 
+ *
+ * @author  jlgwch
+ * @date    2023-10-16
+ * @version 1.0
+ *
+ * @history
+ *  - 2023-10-16: jlgwch - Created the file.
+ *
+ * @copyright Copyright (c) 2023~ jlgwch. All rights reserved.
+ */
+
+#include "ringbuffer.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool ringbuffer_init(ringbuffer_st* ringbuffer, int size)
+{
+    ringbuffer->head = 0;
+    ringbuffer->tail = 0;
+    ringbuffer->buffer_size = 0;
+    ringbuffer->full_size = size;
+    ringbuffer->data = (data_t*)malloc(size);
+    if(ringbuffer->data == NULL)
+        return false;
+    return true;
+}
+
+void ringbuffer_release(ringbuffer_st* ringbuffer)
+{
+    if(ringbuffer->data)
+        free(ringbuffer->data);
+    ringbuffer->head = 0;
+    ringbuffer->tail = 0;
+    ringbuffer->buffer_size = 0;
+    ringbuffer->full_size = 0;
+}
+
+int ringbuffer_append(ringbuffer_st* ringbuffer, const data_t* buffer, int size)
+{
+    int len = ringbuffer->full_size - ringbuffer->buffer_size;
+
+    if(len >= size)
+    {
+        for(int i=0;i<size;i++)
+        {
+            ringbuffer->data[ringbuffer->tail] = buffer[i];
+            ringbuffer->tail = (ringbuffer->tail + 1) % ringbuffer->full_size;
+            ringbuffer->buffer_size++;
+        }
+        return 0;
+    }
+    return -1;
+}
+
+int ringbuffer_read(ringbuffer_st ringbuffer, data_t* data, int size)
+{
+    if(ringbuffer.buffer_size == 0)
+        return 0;
+
+    int len = ringbuffer.full_size - ringbuffer.head;
+
+    if(size > ringbuffer.buffer_size)
+    {
+        if(len >= ringbuffer.buffer_size)
+        {
+            memcpy(data, ringbuffer.data + ringbuffer.head, ringbuffer.buffer_size);
+        }
+        else
+        {
+            memcpy(data, &ringbuffer.data[ringbuffer.head], len);
+            memcpy(data + len, ringbuffer.data, ringbuffer.buffer_size - len);
+        }
+
+        return ringbuffer.buffer_size;
+    }
+
+    if(len >= size)
+    {
+        memcpy(data, ringbuffer.data + ringbuffer.head, size);
+    }
+    else
+    {
+        memcpy(data, &ringbuffer.data[ringbuffer.head], len);
+        memcpy(data + len, ringbuffer.data, size - len);
+    }
+    return size;
+}
+
+int ringbuffer_data(ringbuffer_st ringbuffer, data_t* data, int index)
+{
+    if(index >= ringbuffer.buffer_size || !data)
+        return -1;
+
+    *data = ringbuffer.data[(ringbuffer.head + index) % ringbuffer.full_size];
+    return 0;
+}
+
+void ringbuffer_popup(ringbuffer_st* ringbuffer, int size)
+{
+    if(ringbuffer->buffer_size >= size)
+    {
+        ringbuffer->head = (ringbuffer->head + size) % ringbuffer->full_size;
+        ringbuffer->buffer_size -= size;
+    }
+    else
+    {
+        ringbuffer->head = (ringbuffer->head + ringbuffer->buffer_size) % ringbuffer->full_size;
+        ringbuffer->buffer_size = 0;
+    }
+}
+
+void ringbuffer_clear(ringbuffer_st* ringbuffer)
+{
+    ringbuffer->head = 0;
+    ringbuffer->tail = 0;
+    ringbuffer->buffer_size = 0;
+}
+
+bool ringbuffer_empty(ringbuffer_st ringbuffer)
+{
+    if(ringbuffer.buffer_size == 0)
+        return true;
+    return false;
+}
+
+void ringbuffer_print(ringbuffer_st ringbuffer, bool print_buffer)
+{
+    printf("head index:  %d\n", ringbuffer.head);
+    printf("tail index:  %d\n", ringbuffer.tail);
+    printf("full size:   %d\n", ringbuffer.full_size);
+    printf("buffer size: %d\n", ringbuffer.buffer_size);
+ 
+    if(ringbuffer.buffer_size > 0 && print_buffer)
+    {
+        printf("bufer hex:   ");
+        for(int i = 0; i < ringbuffer.buffer_size; i++)
+        {
+           if(i != 0 && i % 20 == 0)
+           {
+               printf("\n");
+               printf("             ");
+           }
+           printf("0x%02x ", ringbuffer.data[(ringbuffer.head + i) % ringbuffer.full_size]);
+        }
+        printf("\n");
+    }
+}

+ 121 - 0
src/serialport.cpp

@@ -0,0 +1,121 @@
+#include "serialport.h"
+#include <QSerialPortInfo>
+#include "logger.h"
+
+SerialPort::SerialPort(QObject *parent)
+    : QObject{parent}
+{
+    QList<QSerialPortInfo> serialPorts = QSerialPortInfo::availablePorts();
+    for (const QSerialPortInfo &info : serialPorts) {
+        LOG_INFO("Name         : {}", info.portName().toUtf8().data());
+        LOG_INFO("Description  : {}", info.description().toUtf8().data());
+        LOG_INFO("Manufacturer : {}", info.manufacturer().toUtf8().data());
+        LOG_INFO("Serial Number: {}", info.serialNumber().toUtf8().data());
+        LOG_INFO("Location     : {}", info.systemLocation().toUtf8().data());
+        LOG_INFO("Vendor ID    : {}", info.vendorIdentifier());
+        LOG_INFO("Product ID   : {}", info.productIdentifier());
+        LOG_INFO("-----------------------------------");
+    }
+
+    m_serialPort.setPortName("/dev/ttyS9"); 
+    m_serialPort.setBaudRate(QSerialPort::Baud115200);
+    m_serialPort.setDataBits(QSerialPort::Data8);
+    m_serialPort.setParity(QSerialPort::NoParity);
+    m_serialPort.setStopBits(QSerialPort::OneStop);
+    m_serialPort.setFlowControl(QSerialPort::NoFlowControl);
+
+    if (!m_serialPort.open(QIODevice::ReadOnly)) {
+        LOG_ERROR("failed to open port:", m_serialPort.errorString().toUtf8().data());
+        return;
+    }
+
+    ringbuffer_init(&m_ringbuffer, 64);
+    memset(m_ringbuffer.data, 0 , 64);
+
+    connect(&m_serialPort, &QSerialPort::readyRead, [this](){
+        QByteArray byteArray = m_serialPort.readAll();
+        LOG_DEBUG("serial received: {}", byteArray.toHex().data());  // 或直接输出 data
+        ringbuffer_append(&m_ringbuffer, (data_t*)byteArray.data(), byteArray.size());
+        int ret;
+        int frameSize;
+        data_t head[2];
+        data_t data;
+        data_t buffer[12];
+        data_t checkSum;
+        while(1)
+        {
+            if(m_ringbuffer.buffer_size < 12)
+                break;
+        
+            if(0 == ringbuffer_data(m_ringbuffer, &head[0], 0) && 0 == ringbuffer_data(m_ringbuffer, &head[1], 1))
+            {
+                if(0xAA == head[0] && 0x55 == head[1])
+                {
+                    ringbuffer_data(m_ringbuffer, &data, 2);
+                    frameSize = data;
+                    if(data != 12)
+                    {
+                        LOG_ERROR("frame size error");
+                        ringbuffer_popup(&m_ringbuffer, 2);
+                    }
+                    else
+                    {
+                        int size = ringbuffer_read(m_ringbuffer, buffer, frameSize);
+                        if(size == frameSize)
+                        {
+                            checkSum = 0x00;
+                            for(int i = 0; i < size - 3; i++)
+                            {
+                                checkSum += buffer[i];
+                            }
+
+                            if(buffer[3] != 0x11)
+                            {
+                                LOG_ERROR("cmd code error");
+                                ringbuffer_popup(&m_ringbuffer, 2);
+                                continue;
+                            }
+
+                            if(checkSum != buffer[size - 3])
+                            {
+                                LOG_ERROR("check sum error");
+                                ringbuffer_popup(&m_ringbuffer, 2);
+                                continue;
+                            }
+
+                            if(0xBB != buffer[size - 2] || 0x66 != buffer[size - 1])
+                            {
+                                LOG_ERROR("tail error");
+                                ringbuffer_popup(&m_ringbuffer, 2);
+                                continue;
+                            }
+
+                            if(buffer[4] == 0x00) {
+                                emit pageSwitch(-1);
+                            }
+                            else if(buffer[4] == 0x01) {
+                                emit pageSwitch();
+                            }
+
+                            LOG_DEBUG("key state                    : {:x}", buffer[4]);
+                            LOG_DEBUG("heating state                : {:x}", buffer[5]);
+                            LOG_DEBUG("screen temperature           : {}", static_cast<int8_t>(buffer[6]));
+                            LOG_DEBUG("Interface onboard temperature: {}", static_cast<int8_t>(buffer[7]));
+                            ringbuffer_popup(&m_ringbuffer, size);
+                        }
+                    }
+                }
+                else
+                {
+                    ringbuffer_popup(&m_ringbuffer, 1);
+                }
+            }
+        }
+
+    });
+}
+
+SerialPort::~SerialPort()
+{
+
+}