Browse Source

✨ feat: 实现h4相关接口

目前实现了 H4 的相关接口,并且单元测试通过,不过目前实现不完全,测试用例覆盖也不全面,后面需要加强。
Jackistang 4 years ago
parent
commit
39e148ed4b

+ 397 - 0
3rd-party/ringbuffer.c

@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2012-09-30     Bernard      first version.
+ * 2013-05-08     Grissiom     reimplement
+ * 2016-08-18     heyuanjie    add interface
+ */
+
+// #include <rtthread.h>
+// #include <rtdevice.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
+{
+    if (rb->read_index == rb->write_index)
+    {
+        if (rb->read_mirror == rb->write_mirror)
+            return RT_RINGBUFFER_EMPTY;
+        else
+            return RT_RINGBUFFER_FULL;
+    }
+    return RT_RINGBUFFER_HALFFULL;
+}
+
+void rt_ringbuffer_init(struct rt_ringbuffer *rb,
+                        rt_uint8_t           *pool,
+                        rt_int16_t            size)
+{
+    RT_ASSERT(rb != RT_NULL);
+    RT_ASSERT(size > 0);
+
+    /* initialize read and write index */
+    rb->read_mirror = rb->read_index = 0;
+    rb->write_mirror = rb->write_index = 0;
+
+    /* set buffer pool and size */
+    rb->buffer_ptr = pool;
+    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
+}
+//RTM_EXPORT(rt_ringbuffer_init);
+
+/**
+ * put a block of data into ring buffer
+ */
+rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
+                            const rt_uint8_t     *ptr,
+                            rt_uint16_t           length)
+{
+    rt_uint16_t size;
+
+    RT_ASSERT(rb != RT_NULL);
+
+    /* whether has enough space */
+    size = rt_ringbuffer_space_len(rb);
+
+    /* no space */
+    if (size == 0)
+        return 0;
+
+    /* drop some data */
+    if (size < length)
+        length = size;
+
+    if (rb->buffer_size - rb->write_index > length)
+    {
+        /* read_index - write_index = empty space */
+        memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
+        /* this should not cause overflow because there is enough space for
+         * length of data in current mirror */
+        rb->write_index += length;
+        return length;
+    }
+
+    memcpy(&rb->buffer_ptr[rb->write_index],
+           &ptr[0],
+           rb->buffer_size - rb->write_index);
+    memcpy(&rb->buffer_ptr[0],
+           &ptr[rb->buffer_size - rb->write_index],
+           length - (rb->buffer_size - rb->write_index));
+
+    /* we are going into the other side of the mirror */
+    rb->write_mirror = ~rb->write_mirror;
+    rb->write_index = length - (rb->buffer_size - rb->write_index);
+
+    return length;
+}
+//RTM_EXPORT(rt_ringbuffer_put);
+
+/**
+ * put a block of data into ring buffer
+ *
+ * When the buffer is full, it will discard the old data.
+ */
+rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
+                            const rt_uint8_t     *ptr,
+                            rt_uint16_t           length)
+{
+    rt_uint16_t space_length;
+
+    RT_ASSERT(rb != RT_NULL);
+
+    space_length = rt_ringbuffer_space_len(rb);
+
+    if (length > rb->buffer_size)
+    {
+        ptr = &ptr[length - rb->buffer_size];
+        length = rb->buffer_size;
+    }
+
+    if (rb->buffer_size - rb->write_index > length)
+    {
+        /* read_index - write_index = empty space */
+        memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
+        /* this should not cause overflow because there is enough space for
+         * length of data in current mirror */
+        rb->write_index += length;
+
+        if (length > space_length)
+            rb->read_index = rb->write_index;
+
+        return length;
+    }
+
+    memcpy(&rb->buffer_ptr[rb->write_index],
+           &ptr[0],
+           rb->buffer_size - rb->write_index);
+    memcpy(&rb->buffer_ptr[0],
+           &ptr[rb->buffer_size - rb->write_index],
+           length - (rb->buffer_size - rb->write_index));
+
+    /* we are going into the other side of the mirror */
+    rb->write_mirror = ~rb->write_mirror;
+    rb->write_index = length - (rb->buffer_size - rb->write_index);
+
+    if (length > space_length)
+    {
+        rb->read_mirror = ~rb->read_mirror;
+        rb->read_index = rb->write_index;
+    }
+
+    return length;
+}
+//RTM_EXPORT(rt_ringbuffer_put_force);
+
+/**
+ *  get data from ring buffer
+ */
+rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
+                            rt_uint8_t           *ptr,
+                            rt_uint16_t           length)
+{
+    rt_size_t size;
+
+    RT_ASSERT(rb != RT_NULL);
+
+    /* whether has enough data  */
+    size = rt_ringbuffer_data_len(rb);
+
+    /* no data */
+    if (size == 0)
+        return 0;
+
+    /* less data */
+    if (size < length)
+        length = size;
+
+    if (rb->buffer_size - rb->read_index > length)
+    {
+        /* copy all of data */
+        memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
+        /* this should not cause overflow because there is enough space for
+         * length of data in current mirror */
+        rb->read_index += length;
+        return length;
+    }
+
+    memcpy(&ptr[0],
+           &rb->buffer_ptr[rb->read_index],
+           rb->buffer_size - rb->read_index);
+    memcpy(&ptr[rb->buffer_size - rb->read_index],
+           &rb->buffer_ptr[0],
+           length - (rb->buffer_size - rb->read_index));
+
+    /* we are going into the other side of the mirror */
+    rb->read_mirror = ~rb->read_mirror;
+    rb->read_index = length - (rb->buffer_size - rb->read_index);
+
+    return length;
+}
+//RTM_EXPORT(rt_ringbuffer_get);
+
+/**
+ *  peak data from ring buffer
+ */
+rt_size_t rt_ringbuffer_peak(struct rt_ringbuffer *rb, rt_uint8_t **ptr)
+{
+    RT_ASSERT(rb != RT_NULL);
+
+    *ptr = RT_NULL;
+
+    /* whether has enough data  */
+    rt_size_t size = rt_ringbuffer_data_len(rb);
+
+    /* no data */
+    if (size == 0)
+        return 0;
+
+    *ptr = &rb->buffer_ptr[rb->read_index];
+
+    if(rb->buffer_size - rb->read_index > size)
+    {
+        rb->read_index += size;
+        return size;
+    }
+
+    size = rb->buffer_size - rb->read_index;
+
+    /* we are going into the other side of the mirror */
+    rb->read_mirror = ~rb->read_mirror;
+    rb->read_index = 0;
+
+    return size;
+}
+//RTM_EXPORT(rt_ringbuffer_peak);
+
+/**
+ * put a character into ring buffer
+ */
+rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
+{
+    RT_ASSERT(rb != RT_NULL);
+
+    /* whether has enough space */
+    if (!rt_ringbuffer_space_len(rb))
+        return 0;
+
+    rb->buffer_ptr[rb->write_index] = ch;
+
+    /* flip mirror */
+    if (rb->write_index == rb->buffer_size-1)
+    {
+        rb->write_mirror = ~rb->write_mirror;
+        rb->write_index = 0;
+    }
+    else
+    {
+        rb->write_index++;
+    }
+
+    return 1;
+}
+//RTM_EXPORT(rt_ringbuffer_putchar);
+
+/**
+ * put a character into ring buffer
+ *
+ * When the buffer is full, it will discard one old data.
+ */
+rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
+{
+    enum rt_ringbuffer_state old_state;
+
+    RT_ASSERT(rb != RT_NULL);
+
+    old_state = rt_ringbuffer_status(rb);
+
+    rb->buffer_ptr[rb->write_index] = ch;
+
+    /* flip mirror */
+    if (rb->write_index == rb->buffer_size-1)
+    {
+        rb->write_mirror = ~rb->write_mirror;
+        rb->write_index = 0;
+        if (old_state == RT_RINGBUFFER_FULL)
+        {
+            rb->read_mirror = ~rb->read_mirror;
+            rb->read_index = rb->write_index;
+        }
+    }
+    else
+    {
+        rb->write_index++;
+        if (old_state == RT_RINGBUFFER_FULL)
+            rb->read_index = rb->write_index;
+    }
+
+    return 1;
+}
+//RTM_EXPORT(rt_ringbuffer_putchar_force);
+
+/**
+ * get a character from a ringbuffer
+ */
+rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
+{
+    RT_ASSERT(rb != RT_NULL);
+
+    /* ringbuffer is empty */
+    if (!rt_ringbuffer_data_len(rb))
+        return 0;
+
+    /* put character */
+    *ch = rb->buffer_ptr[rb->read_index];
+
+    if (rb->read_index == rb->buffer_size-1)
+    {
+        rb->read_mirror = ~rb->read_mirror;
+        rb->read_index = 0;
+    }
+    else
+    {
+        rb->read_index++;
+    }
+
+    return 1;
+}
+//RTM_EXPORT(rt_ringbuffer_getchar);
+
+/**
+ * get the size of data in rb
+ */
+rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
+{
+    switch (rt_ringbuffer_status(rb))
+    {
+    case RT_RINGBUFFER_EMPTY:
+        return 0;
+    case RT_RINGBUFFER_FULL:
+        return rb->buffer_size;
+    case RT_RINGBUFFER_HALFFULL:
+    default:
+        if (rb->write_index > rb->read_index)
+            return rb->write_index - rb->read_index;
+        else
+            return rb->buffer_size - (rb->read_index - rb->write_index);
+    };
+}
+//RTM_EXPORT(rt_ringbuffer_data_len);
+
+/**
+ * empty the rb
+ */
+void rt_ringbuffer_reset(struct rt_ringbuffer *rb)
+{
+    RT_ASSERT(rb != RT_NULL);
+
+    rb->read_mirror = 0;
+    rb->read_index = 0;
+    rb->write_mirror = 0;
+    rb->write_index = 0;
+}
+//RTM_EXPORT(rt_ringbuffer_reset);
+
+#ifdef RT_USING_HEAP
+
+struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t size)
+{
+    struct rt_ringbuffer *rb;
+    rt_uint8_t *pool;
+
+    RT_ASSERT(size > 0);
+
+    size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
+
+    rb = (struct rt_ringbuffer *)rt_malloc(sizeof(struct rt_ringbuffer));
+    if (rb == RT_NULL)
+        goto exit;
+
+    pool = (rt_uint8_t *)rt_malloc(size);
+    if (pool == RT_NULL)
+    {
+        rt_free(rb);
+        rb = RT_NULL;
+        goto exit;
+    }
+    rt_ringbuffer_init(rb, pool, size);
+
+exit:
+    return rb;
+}
+//RTM_EXPORT(rt_ringbuffer_create);
+
+void rt_ringbuffer_destroy(struct rt_ringbuffer *rb)
+{
+    RT_ASSERT(rb != RT_NULL);
+
+    rt_free(rb->buffer_ptr);
+    rt_free(rb);
+}
+//RTM_EXPORT(rt_ringbuffer_destroy);
+
+#endif

+ 116 - 0
3rd-party/ringbuffer.h

@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+#ifndef RINGBUFFER_H__
+#define RINGBUFFER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include <assert.h>
+
+typedef uint8_t  rt_uint8_t;
+typedef uint16_t rt_uint16_t;
+typedef int16_t  rt_int16_t;
+typedef size_t  rt_size_t;
+#define rt_inline static inline
+#define RT_ASSERT   assert
+#define RT_NULL NULL
+#define RT_ALIGN_SIZE 4
+/**
+ * @ingroup BasicDef
+ *
+ * @def RT_ALIGN_DOWN(size, align)
+ * Return the down number of aligned at specified width. RT_ALIGN_DOWN(13, 4)
+ * would return 12.
+ */
+#define RT_ALIGN_DOWN(size, align)      ((size) & ~((align) - 1))
+
+/* ring buffer */
+struct rt_ringbuffer
+{
+    rt_uint8_t *buffer_ptr;
+    /* use the msb of the {read,write}_index as mirror bit. You can see this as
+     * if the buffer adds a virtual mirror and the pointers point either to the
+     * normal or to the mirrored buffer. If the write_index has the same value
+     * with the read_index, but in a different mirror, the buffer is full.
+     * While if the write_index and the read_index are the same and within the
+     * same mirror, the buffer is empty. The ASCII art of the ringbuffer is:
+     *
+     *          mirror = 0                    mirror = 1
+     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
+     * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Full
+     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
+     *  read_idx-^                   write_idx-^
+     *
+     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
+     * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Empty
+     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
+     * read_idx-^ ^-write_idx
+     *
+     * The tradeoff is we could only use 32KiB of buffer for 16 bit of index.
+     * But it should be enough for most of the cases.
+     *
+     * Ref: http://en.wikipedia.org/wiki/Circular_buffer#Mirroring */
+    rt_uint16_t read_mirror : 1;
+    rt_uint16_t read_index : 15;
+    rt_uint16_t write_mirror : 1;
+    rt_uint16_t write_index : 15;
+    /* as we use msb of index as mirror bit, the size should be signed and
+     * could only be positive. */
+    rt_int16_t buffer_size;
+};
+
+enum rt_ringbuffer_state
+{
+    RT_RINGBUFFER_EMPTY,
+    RT_RINGBUFFER_FULL,
+    /* half full is neither full nor empty */
+    RT_RINGBUFFER_HALFFULL,
+};
+
+/**
+ * RingBuffer for DeviceDriver
+ *
+ * Please note that the ring buffer implementation of RT-Thread
+ * has no thread wait or resume feature.
+ */
+void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_uint8_t *pool, rt_int16_t size);
+void rt_ringbuffer_reset(struct rt_ringbuffer *rb);
+rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
+rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
+rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch);
+rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch);
+rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, rt_uint8_t *ptr, rt_uint16_t length);
+rt_size_t rt_ringbuffer_peak(struct rt_ringbuffer *rb, rt_uint8_t **ptr);
+rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch);
+rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb);
+
+#ifdef RT_USING_HEAP
+struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t length);
+void rt_ringbuffer_destroy(struct rt_ringbuffer *rb);
+#endif
+
+rt_inline rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb)
+{
+    RT_ASSERT(rb != RT_NULL);
+    return rb->buffer_size;
+}
+
+/** return the size of empty space in rb */
+#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 12 - 2
CMakeLists.txt

@@ -6,6 +6,7 @@ set(CMAKE_BUILD_TYPE "Debug")
 
 set(SOURCES
     # src/hci_transport_uart_linux.c
+    src/hci_transport_h4.c
 
 # porting os
     porting/os/linux/src/os_mutex.c
@@ -13,7 +14,12 @@ set(SOURCES
     porting/os/linux/src/os_task.c
     porting/os/linux/src/os_uart.c
 
-    tests/test.c)
+# 3rd-party
+    3rd-party/ringbuffer.c
+
+# test
+    tests/test.c
+    tests/test_hci_transport_h4.c)
 
 add_executable(hci_middleware
     ${SOURCES})
@@ -24,7 +30,11 @@ target_include_directories(hci_middleware
 
 # porting os
     ${PROJECT_SOURCE_DIR}/porting/os/include
-    ${PROJECT_SOURCE_DIR}/porting/os/linux/include)
+    ${PROJECT_SOURCE_DIR}/porting/os/linux/include
+
+# 3rd-party
+    ${PROJECT_SOURCE_DIR}/3rd-party/
+)
 
 target_link_libraries(hci_middleware
     PRIVATE

+ 6 - 2
include/hci_transport_h4.h

@@ -16,8 +16,12 @@ enum {
     HCI_TRANSPORT_H4_ISO,
 };
 
-extern int rt_hci_transport_h4_send(int type, uint8_t *buf, size_t size);
-extern void rt_hci_transport_h4_register_callback(void (*package_callback)(uint8_t type, uint8_t *buf, size_t size));
+struct rt_hci_transport_h4_config {
+    void (*package_callback)(int type, uint8_t *buf, size_t length);
+};
+
+extern int rt_hci_transport_h4_init(struct rt_hci_transport_h4_config *config);
+extern int rt_hci_transport_h4_send(int type, uint8_t *buf, size_t length);
 
 
 #ifdef __cplusplus

+ 2 - 0
porting/os/include/os_port.h

@@ -7,6 +7,8 @@
 extern "C" {
 #endif
 
+#define ARRAY_SIZE(array)   ((sizeof(array) / sizeof(array[0])))
+
 /*
  * Task
  */

+ 1 - 1
porting/os/linux/src/os_uart.c

@@ -225,7 +225,7 @@ int os_uart_send(uint8_t *buffer, uint16_t length)
 {
     int len = length;
     while (len > 0) {
-        uint16_t size = write(fd, buffer, len);
+        int size = write(fd, buffer, len);
         if (size <= 0)
             return -1;
         len -= size; 

+ 18 - 0
src/h4_inner.h

@@ -0,0 +1,18 @@
+#ifndef HCI_TRANSPORT_H4_INNER_
+#define HCI_TRANSPORT_H4_INNER_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int _hci_transport_h4_recv(uint8_t *buf, uint16_t size);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HCI_TRANSPORT_H4_INNER_ */

+ 88 - 0
src/hci_transport_h4.c

@@ -0,0 +1,88 @@
+#include "hci_transport_h4.h"
+#include "ringbuffer.h"
+#include "os_port.h"
+#include <string.h>
+#include <assert.h>
+
+static void (*g_package_cb)(int type, uint8_t *buf, size_t size);
+
+static struct rt_ringbuffer g_ringbuffer;
+static uint8_t g_ringbuffer_pool[512];
+
+int rt_hci_transport_h4_init(struct rt_hci_transport_h4_config *config)
+{
+    g_package_cb = config->package_callback;
+    rt_ringbuffer_init(&g_ringbuffer, g_ringbuffer_pool, ARRAY_SIZE(g_ringbuffer_pool));
+}
+
+int rt_hci_transport_h4_send(int type, uint8_t *buf, size_t size)
+{
+    uint8_t h4_buf[size+1];
+    h4_buf[0] = type;
+    memcpy(h4_buf+1, buf, size);
+
+    return os_uart_send(h4_buf, size+1) -1 ;    // Send buffer size, not include type.
+}
+
+struct hci_pkg_format {
+    uint8_t header;
+    uint8_t length;
+};
+
+/* Array index is received package type. */
+static struct hci_pkg_format g_pkg_fmt[] = {
+    {0, 0},
+    {0, 0},
+    {2, 2}, /* ACL: handle, PB PC flag is 2 bytes, Data total length is 2 bytes. */
+    {2, 1}, /* SCO: handle, packet status flag, RFU is 2 bytes, Data total length is 1 bytes. */
+    {1, 1}, /* Event: event code is 1 bytes, parameter total length is 1 bytes. */
+    {2, 2}, /* ISO: handle, PB TS flag, RFU is 2 bytes, Data total length is 2 bytes (MSB 14bits) */
+};
+
+static uint8_t recv_buffer[512];
+static uint16_t recv_index;
+int _hci_transport_h4_recv(uint8_t *buf, uint16_t buf_len)
+{
+    assert(buf);
+    assert(buf_len > 0);
+
+    /* Buffer is full, need increase buffer size. */
+    if (recv_index + buf_len > ARRAY_SIZE(recv_buffer))
+        return -1;
+    
+    memcpy(recv_buffer+recv_index, buf, buf_len);
+    recv_index += buf_len;
+
+    size_t recv_hci_size = recv_index - 1;  //  H4 type is 1 byte.
+    uint8_t idx = recv_buffer[0];
+
+    if (recv_hci_size >= (g_pkg_fmt[idx].header + g_pkg_fmt[idx].length)) {
+        uint8_t *ptr = recv_buffer + 1 + g_pkg_fmt[idx].header;
+        uint16_t data_length = *ptr;
+        //TODO 处理大小端问题,
+        // while (g_pkg_fmt[idx].length > 1) {
+
+        // }
+
+        size_t expect_hci_size= g_pkg_fmt[idx].header + g_pkg_fmt[idx].length + data_length;
+        /* Not one complete message stored in ringbuffer. */
+        if (recv_hci_size < expect_hci_size)
+            return 0;
+        
+        g_package_cb(recv_buffer[0], recv_buffer+1, expect_hci_size);
+
+        /* Reset receive buffer, copy data from end pointer to start pointer. */
+        if (recv_hci_size > expect_hci_size) {
+            void *start = recv_buffer;
+            void *end = recv_buffer + 1 + expect_hci_size;
+            uint16_t moving_size = recv_index - (1 + expect_hci_size);
+            recv_index = moving_size;   // Update receive buffer size.
+            memcpy(start, end, moving_size);
+        } else {
+            recv_index = 0;
+        }
+    }
+
+    return 0;
+}
+

+ 7 - 4
tests/test.c

@@ -8,7 +8,7 @@
 #define CU_ASSERT_ARRAY_EQUAL   CU_ASSERT_NSTRING_EQUAL
 
 
-struct os_uart_config config = {
+static struct os_uart_config config = {
     .device_name = "/dev/ttyACM0",
     .parity      = OS_UART_PARITY_NONE,
     .stopbit     = OS_UART_STOPBIT_1_BIT,
@@ -21,7 +21,7 @@ struct os_uart_config config = {
  * Opens the temporary file used by the tests.
  * Returns zero on success, non-zero otherwise.
  */
-int init_suite(void)
+static int init_suite(void)
 {
     os_uart_init(&config);
     return 0;
@@ -31,13 +31,13 @@ int init_suite(void)
  * Closes the temporary file used by the tests.
  * Returns zero on success, non-zero otherwise.
  */
-int clean_suite(void)
+static int clean_suite(void)
 {
     return 0;
 }
 
 
-void test_os_uart(void)
+static void test_os_uart(void)
 {
     uint8_t send_buf[] = {0x01, 0x03, 0x0C, 0x00};  // HCI Reset.
     int len = os_uart_send(send_buf, ARRAY_SIZE(send_buf));
@@ -51,6 +51,7 @@ void test_os_uart(void)
 }
 
 
+extern int test_hci_transport_h4_init(void);
 /* The main() function for setting up and running the tests.
  * Returns a CUE_SUCCESS on successful running, another
  * CUnit error code on failure.
@@ -79,6 +80,8 @@ int main()
         return CU_get_error();
     }
 
+    test_hci_transport_h4_init();
+
    /* Run all tests using the CUnit Basic interface */
    CU_basic_set_mode(CU_BRM_VERBOSE);
    CU_basic_run_tests();

+ 27 - 5
tests/test_hci_transport_h4.c

@@ -1,4 +1,5 @@
 #include "hci_transport_h4.h"
+#include "os_port.h"
 #include <stdio.h>
 #include <string.h>
 #include <CUnit/Basic.h>
@@ -8,32 +9,53 @@
 #define ARRAY_SIZE(array)   ((sizeof(array) / sizeof(array[0])))
 #define CU_ASSERT_ARRAY_EQUAL   CU_ASSERT_NSTRING_EQUAL
 
+static struct os_sem sync_sem;
 
-int init_suite(void)
+static int init_suite(void)
 {
+    if (os_sem_init(&sync_sem, 0))
+        return -1;
+    
     return 0;
 }
 
-int clean_suite(void)
+static int clean_suite(void)
 {
     return 0;
 }
 
 static uint8_t command1[] = { 0x03, 0x0C, 0x00 };
 static uint8_t event1[] = { 0x0E, 0x04, 0x01, 0x03, 0x0C, 0x00 };
-void h4_package_callback(uint8_t type, uint8_t *buf, size_t size)
+static void h4_package_callback(int type, uint8_t *buf, size_t size)
 {
     CU_ASSERT_EQUAL(type, HCI_TRANSPORT_H4_EVENT);
     CU_ASSERT_EQUAL(size, ARRAY_SIZE(event1));
     CU_ASSERT_ARRAY_EQUAL(buf, event1, size);
+
+    os_sem_release(&sync_sem);
 }
 
-void test_hci_transport_h4(void)
+static struct rt_hci_transport_h4_config config = {
+    .package_callback = h4_package_callback,
+};
+
+/* For mock test */
+#include "../src/h4_inner.h"
+
+static void test_hci_transport_h4(void)
 {
-    rt_hci_transport_h4_register_callback(h4_package_callback);
+    rt_hci_transport_h4_init(&config);
 
     int n = rt_hci_transport_h4_send(HCI_TRANSPORT_H4_COMMAND, command1, ARRAY_SIZE(command1));
     CU_ASSERT_EQUAL(n, ARRAY_SIZE(command1));
+
+    /* For mock test */
+    uint8_t recv_buf[] = {0x04, 0x0E, 0x04, 0x01, 0x03, 0x0C, 0x00};
+    int err = _hci_transport_h4_recv(recv_buf, ARRAY_SIZE(recv_buf));
+    CU_ASSERT_EQUAL(err, 0);
+
+    err = os_sem_take(&sync_sem, 1000);
+    CU_ASSERT_EQUAL(err, 0);
 }
 
 int test_hci_transport_h4_init(void)