소스 검색

Establish simple serial communication class for embedded development

lujw2 1 년 전
커밋
352491e8ba
4개의 변경된 파일228개의 추가작업 그리고 0개의 파일을 삭제
  1. 19 0
      CMakeLists.txt
  2. 51 0
      include/serial_com.hpp
  3. 26 0
      src/log.hpp
  4. 132 0
      src/serial_com.cpp

+ 19 - 0
CMakeLists.txt

@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.8)
+project(serial_communication)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+set(CMAKE_BUILD_TYPE "release")
+
+# Default to C++14
+if(NOT CMAKE_CXX_STANDARD)
+  set(CMAKE_CXX_STANDARD 17)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  add_compile_options(-Wall -Wextra -Wpedantic)
+endif()
+
+set(src src/serial_com.cpp)
+
+add_library(${PROJECT_NAME} SHARED ${src})
+target_include_directories(${PROJECT_NAME} PUBLIC include)

+ 51 - 0
include/serial_com.hpp

@@ -0,0 +1,51 @@
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#include <fcntl.h>
+#include <termio.h>
+#include <unistd.h>
+
+namespace CommunicationStuff {
+
+enum Status {
+    OK                     = 0,
+    DEV_NOT_FOUND          = -1,
+    BAUD_NOT_SUPPORT       = -2,
+    DATABITS_NOT_SUPPORT   = -3,
+    CONFIG_FAIL            = -4,
+    PARITYMODE_NOT_SUPPORT = -5,
+    STOPBITS_NOT_SUPPORT   = -6,
+};
+
+enum ParityMode {
+    PARITY_NONE = 0,
+    PARITY_ODD  = 1,
+    PARITY_EVEN = 2,
+};
+
+enum StopBits {
+    ONE = 1,
+    TWO = 2,
+};
+
+class Serial
+{
+  public:
+    Serial(const char* device);
+    ~Serial();
+    // Status open(const char* dev);
+    Status setup(const int baud_speed, const int data_bits,
+                 const int parity_mode, const int stop_bits);
+    Status change_baud(const int baud_speed);
+    // Status close();
+    int write(const unsigned char* buffer, int length);
+    int read(unsigned char* buffer, int length);
+
+  private:
+    int fd_;
+    struct termios options_;
+};
+
+}  // namespace CommunicationStuff
+
+#endif

+ 26 - 0
src/log.hpp

@@ -0,0 +1,26 @@
+#ifndef LOG_HPP
+#define LOG_HPP
+
+/**
+ * @brief define log function on linux or android
+ *
+ */
+
+#ifdef __linux__
+#include <cstdio>
+
+#define LOGI(fmt, ...) printf("[Info] " fmt "\n", ##__VA_ARGS__)
+#define LOGD(fmt, ...) printf("[Debug] " fmt "\n", ##__VA_ARGS__)
+#define LOGE(fmt, ...) printf("[Error] " fmt "\n", ##__VA_ARGS__)
+// #    define LOGE(...) printf("[ERROR]",format __VA_ARGS__)
+
+#else
+
+#    include <android/log.h>
+#    define LOGD(...)                                                          \
+        __android_log_print(ANDROID_LOG_INFO, "NoiseReduction", __VA_ARGS__)
+#    define LOGE(...)                                                          \
+        __android_log_print(ANDROID_LOG_ERROR, "NoiseReduction", __VA_ARGS__)
+#endif
+
+#endif  // MY_APPLICATION_MY_LOG_H

+ 132 - 0
src/serial_com.cpp

@@ -0,0 +1,132 @@
+#include "serial_com.hpp"
+
+#include <cstddef>
+#include <cstring>
+
+#include "log.hpp"
+
+namespace CommunicationStuff {
+static int transform_baud(int baud_speed);
+static int transform_data_bits(int data_bits);
+
+Serial::Serial(const char* device) : fd_(-1)
+{
+    fd_ = ::open(device, O_RDWR | O_NOCTTY | O_NDELAY);
+    if (fd_ == -1) {
+        LOGE("Fail to open serial port");
+    } else {
+        LOGI("Success to open serial port");
+    }
+}
+
+Serial::~Serial()
+{
+    if (fd_ >= 0) {
+        ::close(fd_);
+        LOGI("Success to close serial port");
+        fd_ = -1;
+    }
+}
+
+Status Serial::setup(const int baud_speed, const int data_bits,
+                     const int parity_mode, const int stop_bits)
+{
+    memset(&options_, 0, sizeof(options_));
+
+    int baud_speed_tmp = transform_baud(baud_speed);
+    if (baud_speed_tmp == -1) {
+        LOGE("Failed to set baud speed");
+        return BAUD_NOT_SUPPORT;
+    }
+    cfsetispeed(&options_, baud_speed_tmp);
+    cfsetospeed(&options_, baud_speed_tmp);
+
+    int data_bits_tmp = transform_data_bits(data_bits);
+    if (data_bits_tmp == -1) {
+        LOGE("Failed to set data bits");
+        return DATABITS_NOT_SUPPORT;
+    }
+    options_.c_cflag |= data_bits_tmp;
+
+    if (parity_mode == PARITY_ODD) {
+        options_.c_cflag |= PARENB;
+        options_.c_cflag |= PARODD;
+    } else if (parity_mode == PARITY_EVEN) {
+        options_.c_cflag &= ~PARODD;
+    } else if (parity_mode == PARITY_NONE) {
+        options_.c_cflag &= ~PARENB;
+
+    } else {
+        return PARITYMODE_NOT_SUPPORT;
+    }
+
+    if (stop_bits == TWO) {
+        options_.c_cflag |= CSTOPB;
+    } else if (stop_bits == ONE) {
+        options_.c_cflag &= ~CSTOPB;
+    } else {
+        return STOPBITS_NOT_SUPPORT;
+    }
+    // 修改控制模式,保证程序不会占用串口
+    options_.c_cflag |= CLOCAL;
+    // 修改控制模式,使得能够从串口中读取输入数据
+    options_.c_cflag |= CREAD;
+
+    options_.c_cc[VMIN]  = 1;
+    options_.c_cc[VTIME] = 10;
+    tcflush(fd_, TCIFLUSH);
+    tcsetattr(fd_, TCSANOW, &options_);
+
+    if (tcgetattr(fd_, &options_) != 0) {
+        LOGE("Failed to set serial port");
+        return CONFIG_FAIL;
+    }
+    LOGI("Success to set config.");
+
+    return OK;
+}
+
+Status Serial::change_baud(const int baud_speed) {
+    int baud_speed_tmp = transform_baud(baud_speed);
+    if (baud_speed_tmp == -1) {
+        LOGE("Failed to set baud speed");
+        return BAUD_NOT_SUPPORT;
+    }
+    cfsetispeed(&options_, baud_speed_tmp);
+    cfsetospeed(&options_, baud_speed_tmp);
+
+    return OK;
+}
+
+int Serial::write(const unsigned char* buffer, int length)
+{
+    return ::write(fd_, buffer, length);
+}
+
+int Serial::read(unsigned char* buffer, int length)
+{
+    return ::read(fd_, buffer, length);
+}
+
+static int transform_baud(int baud_speed)
+{
+    int baud_map[][2] = {{2400, B2400},    {4800, B4800},   {9600, B9600},
+                         {19200, B19200},  {38400, B38400}, {57600, B57600},
+                         {115200, B115200}};
+    for (size_t i = 0; i < sizeof(baud_map) / sizeof(int) / 2; i++) {
+        if (baud_map[i][0] == baud_speed) {
+            return baud_map[i][1];
+        }
+    }
+    return -1;
+}
+
+static int transform_data_bits(int data_bits)
+{
+    int map[][2] = {{5, CS5}, {6, CS6}, {7, CS7}, {8, CS8}};
+    for (size_t i = 0; i < sizeof(map) / sizeof(int) / 2; i++)
+        if (map[i][0] == data_bits)
+            return map[i][1];
+    return -1;
+}
+}  // namespace CommunicationStuff