Quellcode durchsuchen

✨ feat: Add linux uart

Add linux uart implement, and hci_transport_uart.h Interface testcases.
Jackistang vor 4 Jahren
Ursprung
Commit
b8300d5df5
7 geänderte Dateien mit 375 neuen und 6 gelöschten Zeilen
  1. 2 0
      .gitignore
  2. 21 0
      CMakeLists.txt
  3. 2 0
      src/chipset.h
  4. 3 0
      src/hci_transport_h4.h
  5. 30 6
      src/hci_transport_uart.h
  6. 231 0
      src/hci_transport_uart_linux.c
  7. 86 0
      tests/test.c

+ 2 - 0
.gitignore

@@ -9,3 +9,5 @@ install_manifest.txt
 compile_commands.json
 CTestTestfile.cmake
 _deps
+.vscode/
+build/

+ 21 - 0
CMakeLists.txt

@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.12)
+
+project(hci_middleware)
+
+set(CMAKE_BUILD_TYPE "Debug")
+
+set(SOURCES
+    src/hci_transport_uart_linux.c
+    
+    tests/test.c)
+
+add_executable(hci_middleware
+    ${SOURCES})
+
+target_include_directories(hci_middleware
+    PRIVATE
+    ${PROJECT_SOURCE_DIR}/src)
+
+target_link_libraries(hci_middleware
+    PRIVATE
+    cunit)

+ 2 - 0
src/chipset.h

@@ -1,6 +1,8 @@
 #ifndef HCI_TRANSPORT_CHIPSET
 #define HCI_TRANSPORT_CHIPSET
 
+#include <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 3 - 0
src/hci_transport_h4.h

@@ -1,6 +1,9 @@
 #ifndef HCI_TRANSPORT_H4
 #define HCI_TRANSPORT_H4
 
+#include <stdint.h>
+#include <stddef.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 30 - 6
src/hci_transport_uart.h

@@ -1,21 +1,45 @@
 #ifndef HCI_TRANSPORT_UART
 #define HCI_TRANSPORT_UART
 
+#include <stdint.h>
+#include <stdbool.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+enum {
+    UART_PARITY_EVEN,
+    UART_PARITY_ODD,
+    UART_PARITY_NONE,
+};
+
+enum {
+    UART_STOPBIT_1_BIT,
+    UART_STOPBIT_2_BIT,
+};
+
+enum {
+    UART_DATABIT_5_BIT,
+    UART_DATABIT_6_BIT,
+    UART_DATABIT_7_BIT,
+    UART_DATABIT_8_BIT,
+};
+
 struct hci_transport_uart_config {
-    const char *device_name,
-    uint32_t baudrate,
-    bool flowcontrol,
+    const char *device_name;
+    int parity;
+    int stopbit;
+    int databit;
+    uint32_t baudrate;
+    bool flowcontrol;
 };
 
-int rt_hci_transport_uart_init(struct hci_transport_uart_config *config);
+extern int rt_hci_transport_uart_init(struct hci_transport_uart_config *config);
 
-void rt_hci_transport_uart_send(uint8_t *buffer, uint16_t length);
+extern int rt_hci_transport_uart_send(uint8_t *buffer, uint16_t length);
 
-void rt_hci_transport_uart_recv(uint8_t *buffer, uint16_t length)
+extern int rt_hci_transport_uart_recv(uint8_t *buffer, uint16_t length);
 
 #ifdef __cplusplus
 }

+ 231 - 0
src/hci_transport_uart_linux.c

@@ -0,0 +1,231 @@
+#include "hci_transport_uart.h"
+#include <termios.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+static int fd;
+
+enum {
+    UART_TYPE_BAUDRATE,
+    UART_TYPE_DATABIT,
+    UART_TYPE_STOPBIT,
+    UART_TYPE_PARITY,
+    UART_TYPE_FLOWCONTROL,
+    UART_TYPE_INIT,
+};
+
+static int set_baudrate(struct termios * toptions, uint32_t baudrate)
+{
+    printf("h4_set_baudrate %u\n", baudrate);
+
+    speed_t brate = baudrate; // let you override switch below if needed
+    switch(baudrate) {
+        case    9600: brate=B9600;    break;
+        case   19200: brate=B19200;   break;
+        case   38400: brate=B38400;   break;
+        case 57600:  brate=B57600;  break;
+        case 115200: brate=B115200; break;
+#ifdef B230400
+        case 230400: brate=B230400; break;
+#endif
+#ifdef B460800
+        case 460800: brate=B460800; break;
+#endif
+#ifdef B500000
+        case  500000: brate=B500000;  break;
+#endif
+#ifdef B576000
+        case  576000: brate=B576000;  break;
+#endif
+#ifdef B921600
+        case 921600: brate=B921600; break;
+#endif
+#ifdef B1000000
+        case 1000000: brate=B1000000; break;
+#endif
+#ifdef B1152000
+        case 1152000: brate=B1152000; break;
+#endif
+#ifdef B1500000
+        case 1500000: brate=B1500000; break;
+#endif
+#ifdef B2000000
+        case 2000000: brate=B2000000; break;
+#endif
+#ifdef B2500000
+        case 2500000: brate=B2500000; break;
+#endif
+#ifdef B3000000
+        case 3000000: brate=B3000000; break;
+#endif
+#ifdef B3500000
+        case 3500000: brate=B3500000; break;
+#endif
+#ifdef B400000
+        case 4000000: brate=B4000000; break;
+#endif
+        default:
+            printf("can't set baudrate %dn\n", baudrate );
+            return -1;
+    }
+    cfsetospeed(toptions, brate);
+    cfsetispeed(toptions, brate);
+
+    return 0;
+}
+
+static int set_parity(struct termios * toptions, int parity)
+{
+    switch (parity){
+        case UART_PARITY_NONE:
+            toptions->c_cflag &= ~PARENB;
+            toptions->c_cflag &= ~PARODD;
+            break;
+        case UART_PARITY_EVEN:
+            toptions->c_cflag |=  PARENB;
+            toptions->c_cflag &= ~PARODD;
+            break;
+        case UART_PARITY_ODD:
+            toptions->c_cflag |= PARENB;
+            toptions->c_cflag |= PARODD;
+        default:
+            break;
+    }
+    return 0;
+}
+
+static int set_stopbit(struct termios * toptions, int stopbit)
+{
+    switch (stopbit) {
+    case UART_STOPBIT_1_BIT:
+        toptions->c_cflag &= ~CSTOPB;
+        break;
+    case UART_STOPBIT_2_BIT:
+        toptions->c_cflag |= CSTOPB;
+        break;
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+static int set_databit(struct termios * toptions, int databit)
+{
+    toptions->c_cflag &= ~CSIZE;
+    switch (databit) {
+    case UART_DATABIT_5_BIT:
+        toptions->c_cflag |= CS5;
+        break;
+    case UART_DATABIT_6_BIT:
+        toptions->c_cflag |= CS6;
+        break;
+    case UART_DATABIT_7_BIT:
+        toptions->c_cflag |= CS7;
+        break;
+    case UART_DATABIT_8_BIT:
+        toptions->c_cflag |= CS8;
+        break;
+    default:
+        toptions->c_cflag |= CS8;
+        break;
+    }
+}
+
+static int set_flowcontrol(struct termios * toptions, bool flowcontrol)
+{
+    if (flowcontrol) {
+        // with flow control
+        toptions->c_cflag |= CRTSCTS;
+    } else {
+        // no flow control
+        toptions->c_cflag &= ~CRTSCTS;
+    }
+
+    return 0;
+}
+
+static int hci_transport_uart_set_params(int type, void *params)
+{
+    int err;
+    struct termios toptions;
+    if (tcgetattr(fd, &toptions) < 0) {
+        printf("Couldn't get term attributes\n");
+        return -1;
+    }
+
+    switch (type) {
+    case UART_TYPE_INIT:
+        toptions.c_cflag |= CREAD;
+    case UART_TYPE_BAUDRATE:
+        set_baudrate(&toptions, *(uint32_t *)params);
+        break;
+    case UART_TYPE_DATABIT:
+        set_databit(&toptions, *(int *)params);
+        break;
+    case UART_TYPE_STOPBIT:
+        set_stopbit(&toptions, *(int *)params);
+        break;
+    case UART_TYPE_PARITY:
+        set_parity(&toptions, *(int *)params);
+        break;
+    case UART_TYPE_FLOWCONTROL:
+        set_flowcontrol(&toptions, *(bool *)params);
+        break;
+    default:
+        break;
+    }
+
+    if (type == UART_TYPE_BAUDRATE)
+        err = tcsetattr(fd, TCSADRAIN, &toptions);
+    else
+        err = tcsetattr(fd, TCSANOW, &toptions);
+
+    if (err < 0) {
+        printf("Couldn't set term attributes\n");
+        return -1;
+    }
+    return 0;
+}
+
+int rt_hci_transport_uart_init(struct hci_transport_uart_config *config)
+{
+    fd = open(config->device_name, O_RDWR | O_NOCTTY);
+    if (fd == -1) {
+        perror("Open hci transport uart error");
+        return -1;
+    }
+
+    int err;
+    if ((err = hci_transport_uart_set_params(UART_TYPE_BAUDRATE, &config->baudrate)))
+        return -1;
+    if ((err = hci_transport_uart_set_params(UART_TYPE_DATABIT, &config->databit)))
+        return -1;
+    if ((err = hci_transport_uart_set_params(UART_TYPE_STOPBIT, &config->stopbit)))
+        return -1;
+    if ((err = hci_transport_uart_set_params(UART_TYPE_PARITY, &config->parity)))
+        return -1;
+    if ((err = hci_transport_uart_set_params(UART_TYPE_FLOWCONTROL, &config->flowcontrol)))
+        return -1;
+    
+    return 0;
+}
+
+int rt_hci_transport_uart_send(uint8_t *buffer, uint16_t length)
+{
+    int len = length;
+    while (len > 0) {
+        uint16_t size = write(fd, buffer, len);
+        if (size <= 0)
+            return -1;
+        len -= size; 
+    }
+
+    return length;
+}
+
+int rt_hci_transport_uart_recv(uint8_t *buffer, uint16_t length)
+{
+    return read(fd, buffer, length);
+}

+ 86 - 0
tests/test.c

@@ -0,0 +1,86 @@
+#include "hci_transport_uart.h"
+#include <stdio.h>
+#include <string.h>
+#include <CUnit/Basic.h>
+#include <CUnit/TestDB.h>
+
+#define ARRAY_SIZE(array)   ((sizeof(array) / sizeof(array[0])))
+#define CU_ASSERT_ARRAY_EQUAL   CU_ASSERT_NSTRING_EQUAL
+
+
+struct hci_transport_uart_config config = {
+    .device_name = "/dev/ttyUSB0",
+    .parity      = UART_PARITY_NONE,
+    .stopbit     = UART_STOPBIT_1_BIT,
+    .databit     = UART_DATABIT_8_BIT,
+    .baudrate    = 115200,
+    .flowcontrol = true,
+};
+
+/* The suite initialization function.
+ * Opens the temporary file used by the tests.
+ * Returns zero on success, non-zero otherwise.
+ */
+int init_suite(void)
+{
+    rt_hci_transport_uart_init(&config);
+    return 0;
+}
+
+/* The suite cleanup function.
+ * Closes the temporary file used by the tests.
+ * Returns zero on success, non-zero otherwise.
+ */
+int clean_suite(void)
+{
+    return 0;
+}
+
+
+void test_rt_hci_transport_uart(void)
+{
+    uint8_t send_buf[] = {0x1, 0x2, 0x3};
+    int len = rt_hci_transport_uart_send(send_buf, ARRAY_SIZE(send_buf));
+    CU_ASSERT_EQUAL(len, 3);
+
+    uint8_t recv_buf[6];
+    len = rt_hci_transport_uart_recv(recv_buf, ARRAY_SIZE(recv_buf));
+    CU_ASSERT_EQUAL(len, 3);
+    CU_ASSERT_ARRAY_EQUAL(recv_buf, send_buf, len);
+}
+
+
+/* The main() function for setting up and running the tests.
+ * Returns a CUE_SUCCESS on successful running, another
+ * CUnit error code on failure.
+ */
+int main()
+{
+   CU_pSuite pSuite = NULL;
+
+   /* initialize the CUnit test registry */
+   if (CUE_SUCCESS != CU_initialize_registry())
+      return CU_get_error();
+
+    CU_TestInfo test_array[] = {
+        {"test hci transport uart", test_rt_hci_transport_uart},
+        // {"test slip receive frame", test_slip_receive_frame},
+        CU_TEST_INFO_NULL,
+    };
+
+    CU_SuiteInfo suites[] = {
+        {"suite1", init_suite, clean_suite, NULL, NULL, test_array},
+        CU_SUITE_INFO_NULL,
+    };
+
+    if (CUE_SUCCESS != CU_register_suites(suites)) {
+        CU_cleanup_registry();
+        return CU_get_error();
+    }
+
+   /* Run all tests using the CUnit Basic interface */
+   CU_basic_set_mode(CU_BRM_VERBOSE);
+   CU_basic_run_tests();
+   CU_cleanup_registry();
+   return CU_get_error();
+}