Prechádzať zdrojové kódy

[component] Sync to latest version.

armink 6 rokov pred
rodič
commit
1805aadbbb
57 zmenil súbory, kde vykonal 2525 pridanie a 462 odobranie
  1. 1 1
      components/dfs/filesystems/elmfat/dfs_elm.c
  2. 1 1
      components/dfs/src/dfs.c
  3. 2 2
      components/dfs/src/dfs_posix.c
  4. 22 4
      components/drivers/Kconfig
  5. 1 6
      components/drivers/audio/audio.c
  6. 3 3
      components/drivers/audio/audio_pipe.c
  7. 3 3
      components/drivers/audio/audio_pipe.h
  8. 24 25
      components/drivers/hwtimer/README_CN.md
  9. 1 1
      components/drivers/hwtimer/hwtimer.c
  10. 42 0
      components/drivers/include/drivers/adc.h
  11. 1 1
      components/drivers/include/drivers/serial.h
  12. 108 0
      components/drivers/include/drivers/spi.h
  13. 2 0
      components/drivers/include/ipc/ringblk_buf.h
  14. 4 0
      components/drivers/include/rtdevice.h
  15. 4 1
      components/drivers/misc/SConscript
  16. 219 0
      components/drivers/misc/adc.c
  17. 23 8
      components/drivers/misc/rt_drv_pwm.c
  18. 1 2
      components/drivers/pm/pm.c
  19. 67 43
      components/drivers/serial/serial.c
  20. 3 0
      components/drivers/spi/SConscript
  21. 265 0
      components/drivers/spi/qspi_core.c
  22. 74 42
      components/drivers/spi/sfud/README.md
  23. 18 1
      components/drivers/spi/sfud/inc/sfud.h
  24. 7 0
      components/drivers/spi/sfud/inc/sfud_cfg.h
  25. 43 3
      components/drivers/spi/sfud/inc/sfud_def.h
  26. 48 2
      components/drivers/spi/sfud/inc/sfud_flash_def.h
  27. 123 9
      components/drivers/spi/sfud/src/sfud.c
  28. 2 0
      components/drivers/spi/spi_core.c
  29. 131 25
      components/drivers/spi/spi_flash_sfud.c
  30. 1 0
      components/drivers/spi/spi_flash_sfud.h
  31. 59 131
      components/drivers/spi/spi_msd.c
  32. 37 3
      components/drivers/src/ringblk_buf.c
  33. 12 1
      components/drivers/usb/usbdevice/core/core.c
  34. 43 28
      components/drivers/wlan/wlan_dev.c
  35. 3 2
      components/drivers/wlan/wlan_dev.h
  36. 8 5
      components/drivers/wlan/wlan_mgnt.c
  37. 1 1
      components/drivers/wlan/wlan_mgnt.h
  38. 1 1
      components/finsh/cmd.c
  39. 0 15
      components/libc/compilers/dlib/sys/errno.h
  40. 5 0
      components/net/Kconfig
  41. 12 9
      components/net/at/at_socket/at_socket.c
  42. 4 1
      components/net/sal_socket/SConscript
  43. 14 9
      components/net/sal_socket/impl/af_inet_at.c
  44. 15 9
      components/net/sal_socket/impl/af_inet_lwip.c
  45. 239 0
      components/net/sal_socket/impl/proto_mbedtls.c
  46. 27 18
      components/net/sal_socket/include/sal.h
  47. 68 0
      components/net/sal_socket/include/sal_tls.h
  48. 3 0
      components/net/sal_socket/include/socket/sys_socket/sys/socket.h
  49. 224 46
      components/net/sal_socket/src/sal_socket.c
  50. 4 0
      components/utilities/Kconfig
  51. 1 0
      components/utilities/ulog/ulog.h
  52. 7 0
      components/utilities/ulog/ulog_def.h
  53. 8 0
      components/utilities/utest/SConscript
  54. 238 0
      components/utilities/utest/utest.c
  55. 159 0
      components/utilities/utest/utest.h
  56. 58 0
      components/utilities/utest/utest_assert.h
  57. 31 0
      components/utilities/utest/utest_log.h

+ 1 - 1
components/dfs/filesystems/elmfat/dfs_elm.c

@@ -265,7 +265,7 @@ int dfs_elm_mkfs(rt_device_t dev_id)
     /* [IN] Size of the allocation unit */
     /* [-]  Working buffer */
     /* [IN] Size of working buffer */
-    result = f_mkfs(logic_nbr, FM_ANY, 0, work, _MAX_SS);
+    result = f_mkfs(logic_nbr, FM_ANY|FM_SFD, 0, work, _MAX_SS);
     rt_free(work); work = RT_NULL;
 
     /* check flag status, we need clear the temp driver stored in disk[] */

+ 1 - 1
components/dfs/src/dfs.c

@@ -221,7 +221,7 @@ struct dfs_fd *fd_get(int fd)
     d = fdt->fds[fd];
 
     /* check dfs_fd valid or not */
-    if (d->magic != DFS_FD_MAGIC)
+    if ((d == NULL) || (d->magic != DFS_FD_MAGIC))
     {
         dfs_unlock();
         return NULL;

+ 2 - 2
components/dfs/src/dfs_posix.c

@@ -890,9 +890,9 @@ int access(const char *path, int amode)
 char *getcwd(char *buf, size_t size)
 {
 #ifdef DFS_USING_WORKDIR
-    rt_enter_critical();
+    dfs_lock();
     strncpy(buf, working_directory, size);
-    rt_exit_critical();
+    dfs_unlock();
 #else
     rt_kprintf(NO_WORKING_DIR);
 #endif

+ 22 - 4
components/drivers/Kconfig

@@ -16,6 +16,12 @@ config RT_USING_SERIAL
     select RT_USING_DEVICE
     default y
 
+if RT_USING_SERIAL
+    config RT_SERIAL_USING_DMA
+        bool "Enable serial DMA mode"
+        default y
+endif    
+
 config RT_USING_CAN
     bool "Using CAN device drivers"
     default n
@@ -72,6 +78,10 @@ config RT_USING_PIN
     bool "Using generic GPIO device drivers"
     default y
 
+config RT_USING_ADC
+    bool "Using ADC device drivers"
+    default n
+
 config RT_USING_PWM
     bool "Using PWM device drivers"
     default n
@@ -118,9 +128,8 @@ config RT_USING_RTC
         default n
     config RTC_SYNC_USING_NTP
         bool "Using NTP auto sync RTC time"
-        select PKG_USING_NETUTILS
-        select PKG_NETUTILS_NTP
-        default n
+        depends on PKG_NETUTILS_NTP
+        default y
 
         if RTC_SYNC_USING_NTP
         config RTC_NTP_FIRST_SYNC_DELAY
@@ -165,7 +174,11 @@ config RT_USING_SPI
     bool "Using SPI Bus/Device device drivers"
     default n
 
-    if RT_USING_SPI
+    if RT_USING_SPI  
+        config RT_USING_QSPI
+            bool "Enable QSPI mode"
+            default n
+
         config RT_USING_SPI_MSD
             bool "Using SD/TF card driver with spi"
             select RT_USING_DFS
@@ -182,6 +195,11 @@ config RT_USING_SPI
                 config RT_SFUD_USING_FLASH_INFO_TABLE
                 bool "Using defined supported flash chip information table"
                 default y
+                
+                config RT_SFUD_USING_QSPI
+                bool "Using QSPI mode support"
+                select RT_USING_QSPI
+                default n
 
                 config RT_DEBUG_SFUD
                 bool "Show more SFUD debug information"

+ 1 - 6
components/drivers/audio/audio.c

@@ -105,8 +105,6 @@ static rt_err_t _audio_dev_init(struct rt_device *dev)
 
 static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
 {
-    rt_err_t result = RT_EOK;
-    rt_base_t level;
     struct rt_audio_device *audio;
 
     RT_ASSERT(dev != RT_NULL);
@@ -159,7 +157,6 @@ static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
 
             //init pipe for record
             {
-                rt_size_t size = CFG_AUDIO_RECORD_PIPE_SIZE;
                 rt_uint8_t *buf = rt_malloc(CFG_AUDIO_RECORD_PIPE_SIZE);
 
                 if (buf == RT_NULL)
@@ -170,7 +167,7 @@ static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
                     return -RT_ENOMEM;
                 }
                 
-                rt_audio_pipe_init(&audio_pipe, "recpipe", RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD, buf,
+                rt_audio_pipe_init(&audio_pipe, "recpipe", (rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD), buf,
                              CFG_AUDIO_RECORD_PIPE_SIZE);
             }
 
@@ -536,8 +533,6 @@ void rt_audio_tx_complete(struct rt_audio_device *audio, rt_uint8_t *pbuf)
 
 void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len)
 {
-    rt_err_t result = RT_EOK;
-
     //save data to record pipe
     rt_device_write(RT_DEVICE(RT_DEVICE(&audio_pipe)), 0, pbuf, len);
 

+ 3 - 3
components/drivers/audio/audio_pipe.c

@@ -188,7 +188,7 @@ static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
 }
 
 #ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops audio_pipe_ops
+const static struct rt_device_ops audio_pipe_ops =
 {
     RT_NULL,
     RT_NULL,
@@ -213,7 +213,7 @@ const static struct rt_device_ops audio_pipe_ops
  */
 rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
                       const char *name,
-                      enum rt_audio_pipe_flag flag,
+                      rt_int32_t flag,
                       rt_uint8_t *buf,
                       rt_size_t size)
 {
@@ -258,7 +258,7 @@ rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe)
 }
 
 #ifdef RT_USING_HEAP
-rt_err_t rt_audio_pipe_create(const char *name, enum rt_audio_pipe_flag flag, rt_size_t size)
+rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size)
 {
     rt_uint8_t *rb_memptr = RT_NULL;
     struct rt_audio_pipe *pipe = RT_NULL;

+ 3 - 3
components/drivers/audio/audio_pipe.h

@@ -50,7 +50,7 @@ struct rt_audio_pipe
     /* ring buffer in pipe device */
     struct rt_ringbuffer ringbuffer;
 
-    enum rt_audio_pipe_flag flag;
+    rt_int32_t flag;
 
     /* suspended list */
     rt_list_t suspended_read_list;
@@ -64,12 +64,12 @@ struct rt_audio_pipe
 
 rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
                       const char *name,
-                      enum rt_audio_pipe_flag flag,
+                      rt_int32_t flag,
                       rt_uint8_t *buf,
                       rt_size_t size);
 rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe);
 #ifdef RT_USING_HEAP
-rt_err_t rt_audio_pipe_create(const char *name, enum rt_audio_pipe_flag flag, rt_size_t size);
+rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size);
 void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe);
 #endif
 #endif

+ 24 - 25
components/drivers/hwtimer/README_CN.md

@@ -1,17 +1,16 @@
-定时器设备
-===
-  
-##功能
----
+# 定时器设备
+
+## 功能
+
 * 时间测量
 * 周期或单次执行回调函数
   
-##编译
----
+## 编译
+
 1. 在rtconfig.h添加 `#define RT_USING_HWTIMER`
-  
-##使用流程
----
+
+## 使用流程
+
 1. 以读写方式打开设备
 2. 设置超时回调函数(如果需要)
 3. 根据需要设置定时模式(单次/周期)
@@ -19,12 +18,12 @@
 5. 写入超时值,定时器随即启动
 6. 停止定时器(可选)
 7. 关闭设备(如果需要)
-  
+
 应用参考 [hwtimer_test] (/examples/test/hwtimer\_test.c)
 
-##驱动编写指南
----
-###操作接口
+## 驱动编写指南
+
+### 操作接口
 
 ``` 
 struct rt_hwtimer_ops
@@ -43,8 +42,8 @@ struct rt_hwtimer_ops
 * count_get - <读取计数器值>
 * control - <设置计数频率 >
 
-###定时器特征信息
-  
+### 定时器特征信息
+
 ```
 struct rt_hwtimer_info
 {
@@ -60,7 +59,8 @@ struct rt_hwtimer_info
 * maxcnt  <计数器最大计数值>
 * cntmode <递增计数/递减计数>
   
-###注册设备
+### 注册设备
+
 ```
 static rt_hwtimer_t _timer0;
 int stm32_hwtimer_init(void)
@@ -73,8 +73,9 @@ int stm32_hwtimer_init(void)
     return 0;
 }
 ```
-  
-###定时器中断
+
+### 定时器中断
+
 ```
 void timer_irq_handler(void)
 {
@@ -84,15 +85,13 @@ void timer_irq_handler(void)
 }
 ```
 
-##注意事项
----
-  
-<font color="#FF0000">可能出现定时误差</font>
-  
+## 注意事项
+
+**可能出现定时误差**
 
 误差原因:
 
 假设计数器最大值0xFFFF,计数频率1Mhz,定时时间1秒又1微秒。
-  
+
 由于定时器一次最多只能计时到65535us,对于1000001us的定时要求。
 可以50000us定时20次完成,此时将会出现计算误差1us。

+ 1 - 1
components/drivers/hwtimer/hwtimer.c

@@ -153,7 +153,7 @@ static rt_size_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buff
     cnt = timer->ops->count_get(timer);
     if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
     {
-        cnt = timer->info->maxcnt - cnt;
+        cnt = (timer->freq * timer->period_sec) - cnt;
     }
 
     t = timer->overflow * timer->period_sec + cnt/(float)timer->freq;

+ 42 - 0
components/drivers/include/drivers/adc.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-05-07     aozima       the first version
+ * 2018-11-16     Ernest Chen  add finsh command and update adc function
+ */
+
+#ifndef __ADC_H__
+#define __ADC_H__
+#include <rtthread.h>
+
+struct rt_adc_device;
+struct rt_adc_ops
+{
+    rt_err_t (*enabled)(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled);
+    rt_err_t (*convert)(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value);
+};
+
+struct rt_adc_device
+{
+    struct rt_device parent;
+    const struct rt_adc_ops *ops;
+};
+typedef struct rt_adc_device *rt_adc_device_t;
+
+typedef enum
+{
+    RT_ADC_CMD_ENABLE,
+    RT_ADC_CMD_DISABLE,
+} rt_adc_cmd_t;
+
+rt_err_t rt_hw_adc_register(rt_adc_device_t adc,const char *name, const struct rt_adc_ops *ops, const void *user_data);
+
+rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel);
+rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel);
+rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel);
+
+#endif /* __ADC_H__ */

+ 1 - 1
components/drivers/include/drivers/serial.h

@@ -100,7 +100,7 @@ struct serial_configure
     rt_uint32_t bit_order               :1;
     rt_uint32_t invert                  :1;
     rt_uint32_t bufsz                   :16;
-    rt_uint32_t reserved                :4;
+    rt_uint32_t reserved                :6;
 };
 
 /*

+ 108 - 0
components/drivers/include/drivers/spi.h

@@ -45,6 +45,9 @@ extern "C"{
 
 #define RT_SPI_MODE_MASK    (RT_SPI_CPHA | RT_SPI_CPOL | RT_SPI_MSB)
 
+#define RT_SPI_BUS_MODE_SPI         (1<<0)       
+#define RT_SPI_BUS_MODE_QSPI        (1<<1)       
+
 #define RT_SPI_CS_HIGH  (1<<4)                             /* Chipselect active high */
 #define RT_SPI_NO_CS    (1<<5)                             /* No chipselect */
 #define RT_SPI_3WIRE    (1<<6)                             /* SI/SO pin shared */
@@ -80,6 +83,7 @@ struct rt_spi_ops;
 struct rt_spi_bus
 {
     struct rt_device parent;
+    rt_uint8_t mode;
     const struct rt_spi_ops *ops;
 
     struct rt_mutex lock;
@@ -106,6 +110,55 @@ struct rt_spi_device
     struct rt_spi_configuration config;
     void   *user_data;
 };
+
+struct rt_qspi_message
+{
+    struct rt_spi_message parent;
+
+    /* instruction stage */
+    struct
+    {
+        rt_uint8_t content;
+        rt_uint8_t qspi_lines;
+    } instruction;
+
+    /* address and alternate_bytes stage */
+    struct
+    {
+        rt_uint32_t content;
+        rt_uint8_t size;
+        rt_uint8_t qspi_lines;
+    } address, alternate_bytes;
+
+    /* dummy_cycles stage */
+    rt_uint32_t dummy_cycles;
+
+    /* number of lines in qspi data stage, the other configuration items are in parent */
+    rt_uint8_t qspi_data_lines;
+};
+
+struct rt_qspi_configuration
+{
+    struct rt_spi_configuration parent;
+    /* The size of medium */
+    rt_uint32_t medium_size;
+    /* double data rate mode */
+    rt_uint8_t ddr_mode;
+    /* the data lines max width which QSPI bus supported, such as 1, 2, 4 */
+    rt_uint8_t qspi_dl_width ;
+};
+
+struct rt_qspi_device
+{ 
+    struct rt_spi_device parent;
+
+    struct rt_qspi_configuration config;
+
+    void (*enter_qspi_mode)(struct rt_qspi_device *device);
+
+    void (*exit_qspi_mode)(struct rt_qspi_device *device);
+};
+
 #define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev))
 
 /* register a SPI bus */
@@ -255,6 +308,61 @@ rt_inline void rt_spi_message_append(struct rt_spi_message *list,
     message->next = RT_NULL;
 }
 
+/**
+ * This function can set configuration on QSPI device.
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param cfg the configuration pointer.
+ *
+ * @return the actual length of transmitted.
+ */
+rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg);
+
+/**
+ * This function can register a SPI bus for QSPI mode.
+ *
+ * @param bus the SPI bus for QSPI mode.
+ * @param name The name of the spi bus.
+ * @param ops the SPI bus instance to be registered.
+ *
+ * @return the actual length of transmitted.
+ */
+rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops);
+
+/**
+ * This function transmits data to QSPI device.
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param message the message pointer.
+ *
+ * @return the actual length of transmitted.
+ */
+rt_size_t rt_qspi_transfer_message(struct rt_qspi_device  *device, struct rt_qspi_message *message);
+
+/**
+ * This function can send data then receive data from QSPI device
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param send_buf the buffer to be transmitted to QSPI device.
+ * @param send_length the number of data to be transmitted.
+ * @param recv_buf the buffer to be recivied from QSPI device.
+ * @param recv_length the data to be recivied.
+ *
+ * @return the status of transmit.
+ */
+rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length,void *recv_buf, rt_size_t recv_length);
+
+/**
+ * This function can send data to QSPI device
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param send_buf the buffer to be transmitted to QSPI device.
+ * @param send_length the number of data to be transmitted.
+ *
+ * @return the status of transmit.
+ */
+rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length);
+
 #ifdef __cplusplus
 }
 #endif

+ 2 - 0
components/drivers/include/ipc/ringblk_buf.h

@@ -84,6 +84,8 @@ rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb);
 rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size);
 void rt_rbb_blk_put(rt_rbb_blk_t block);
 rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb);
+rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block);
+rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block);
 void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block);
 
 /* rbb block queue API */

+ 4 - 0
components/drivers/include/rtdevice.h

@@ -99,6 +99,10 @@ extern "C" {
 #include "drivers/cputime.h"
 #endif
 
+#ifdef RT_USING_ADC
+#include "drivers/adc.h"
+#endif
+
 #ifdef RT_USING_PWM
 #include "drivers/rt_drv_pwm.h"
 #endif

+ 4 - 1
components/drivers/misc/SConscript

@@ -7,7 +7,10 @@ group = []
 
 if GetDepend(['RT_USING_PIN']):
     src = src + ['pin.c']
-
+    
+if GetDepend(['RT_USING_ADC']):
+    src = src + ['adc.c']
+    
 if GetDepend(['RT_USING_PWM']):
     src = src + ['rt_drv_pwm.c']
 

+ 219 - 0
components/drivers/misc/adc.c

@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-05-07     aozima       the first version
+ * 2018-11-16     Ernest Chen  add finsh command and update adc function
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "adc"
+#define DBG_LEVEL DBG_INFO
+#define DBG_COLOR
+#include <rtdbg.h>
+
+static rt_size_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+    rt_err_t result = RT_EOK;
+    rt_size_t i;
+    struct rt_adc_device *adc = (struct rt_adc_device *)dev;
+    rt_uint32_t *value = (rt_uint32_t *)buffer;
+
+    for (i = 0; i < size; i += sizeof(int))
+    {
+        result = adc->ops->convert(adc, pos + i, value);
+        if (result != RT_EOK)
+        {
+            return 0;
+        }
+        value++;
+    }
+
+    return i;
+}
+
+static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args)
+{
+    rt_err_t result = RT_EOK;
+    rt_adc_device_t adc = (struct rt_adc_device *)dev;
+
+    if (adc->ops->enabled == RT_NULL)
+    {
+        return -RT_ENOSYS;
+    }
+    if (cmd == RT_ADC_CMD_ENABLE)
+    {
+        result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_TRUE);
+    }
+    else if (cmd == RT_ADC_CMD_DISABLE)
+    {
+        result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_FALSE);
+    }
+
+    return result;
+}
+
+rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data)
+{
+    rt_err_t result = RT_EOK;
+    RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL);
+
+    device->parent.type = RT_Device_Class_Miscellaneous;
+    device->parent.init = RT_NULL;
+    device->parent.open = RT_NULL;
+    device->parent.close = RT_NULL;
+    device->parent.read = _adc_read;
+    device->parent.write = RT_NULL;
+    device->parent.control = _adc_control;
+
+    device->ops = ops;
+    device->parent.user_data = (void *)user_data;
+
+    result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
+
+    return result;
+}
+
+rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel)
+{
+    rt_uint32_t value;
+
+    RT_ASSERT(dev);
+
+    dev->ops->convert(dev, channel, &value);
+
+    return value;
+}
+
+rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel)
+{
+    rt_err_t result = RT_EOK;
+
+    RT_ASSERT(dev);
+    if (dev->ops->enabled != RT_NULL)
+    {
+        result = dev->ops->enabled(dev, channel, RT_TRUE);
+    }
+    else
+    {
+        result = -RT_ENOSYS;
+    }
+
+    return result;
+}
+
+rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel)
+{
+    rt_err_t result = RT_EOK;
+
+    RT_ASSERT(dev);
+    if (dev->ops->enabled != RT_NULL)
+    {
+        result = dev->ops->enabled(dev, channel, RT_FALSE);
+    }
+    else
+    {
+        result = -RT_ENOSYS;
+    }
+
+    return result;
+}
+
+#ifdef FINSH_USING_MSH
+
+static int adc(int argc, char **argv)
+{
+    int value = 0;
+    int result = RT_EOK;
+    static rt_adc_device_t adc_device = RT_NULL;
+    char *result_str;
+
+    if (argc > 1)
+    {
+        if (!strcmp(argv[1], "probe"))
+        {
+            if (argc == 3)
+            {
+                adc_device = (rt_adc_device_t)rt_device_find(argv[2]);
+                result_str = (adc_device == RT_NULL) ? "failure" : "success";
+                rt_kprintf("probe %s %s \n", argv[2], result_str);
+            }
+            else
+            {
+                rt_kprintf("adc probe <adc_name>   - probe adc by name\n");
+            }
+        }
+        else
+        {
+            if (adc_device == RT_NULL)
+            {
+                rt_kprintf("Please using 'adc probe <adc_name>' first\n");
+                return -RT_ERROR;
+            }
+            if (!strcmp(argv[1], "enable"))
+            {
+                if (argc == 3)
+                {
+                    result = rt_adc_enable(adc_device, atoi(argv[2]));
+                    result_str = (result == RT_EOK) ? "success" : "failure";
+                    rt_kprintf("%s channel %d enables %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str);
+                }
+                else
+                {
+                    rt_kprintf("adc enable <channel>   - enable adc channel\n");
+                }
+            }
+            else if (!strcmp(argv[1], "read"))
+            {
+                if (argc == 3)
+                {
+                    value = rt_adc_read(adc_device, atoi(argv[2]));
+                    rt_kprintf("%s channel %d  read value is 0x%08X \n", adc_device->parent.parent.name, atoi(argv[2]), value);
+                }
+                else
+                {
+                    rt_kprintf("adc read <channel>     - read adc value on the channel\n");
+                }
+            }
+            else if (!strcmp(argv[1], "disable"))
+            {
+                if (argc == 3)
+                {
+                    result = rt_adc_disable(adc_device, atoi(argv[2]));
+                    result_str = (result == RT_EOK) ? "success" : "failure";
+                    rt_kprintf("%s channel %d disable %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str);
+                }
+                else
+                {
+                    rt_kprintf("adc disable <channel>  - disable adc channel\n");
+                }
+            }
+            else
+            {
+                rt_kprintf("Unknown command. Please enter 'adc' for help\n");
+            }
+        }
+    }
+    else
+    {
+        rt_kprintf("Usage: \n");
+        rt_kprintf("adc probe <adc_name>   - probe adc by name\n");
+        rt_kprintf("adc read <channel>     - read adc value on the channel\n");
+        rt_kprintf("adc disable <channel>  - disable adc channel\n");
+        rt_kprintf("adc enable <channel>   - enable adc channel\n");
+        result = -RT_ERROR;
+    }
+    return RT_EOK;
+}
+MSH_CMD_EXPORT(adc, adc function);
+
+#endif /* FINSH_USING_MSH */

+ 23 - 8
components/drivers/misc/rt_drv_pwm.c

@@ -88,21 +88,36 @@ static rt_size_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, r
     return size;
 }
 
+#ifdef RT_USING_DEVICE_OPS
+static const struct rt_device_ops pwm_device_ops =
+{
+    RT_NULL,
+    RT_NULL,
+    RT_NULL,
+    _pwm_read,
+    _pwm_write,
+    _pwm_control
+};
+#endif /* RT_USING_DEVICE_OPS */
+
 rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data)
 {
     rt_err_t result = RT_EOK;
 
     memset(device, 0, sizeof(struct rt_device_pwm));
 
-    device->parent.type         = RT_Device_Class_Miscellaneous;
-
-    device->parent.init         = RT_NULL;
-    device->parent.open         = RT_NULL;
-    device->parent.close        = RT_NULL;
-    device->parent.read         = _pwm_read;
-    device->parent.write        = _pwm_write;
-    device->parent.control      = _pwm_control;
+#ifdef RT_USING_DEVICE_OPS
+    device->parent.ops = &pwm_device_ops;
+#else
+    device->parent.init = RT_NULL;
+    device->parent.open = RT_NULL;
+    device->parent.close = RT_NULL;
+    device->parent.read  = _pwm_read;
+    device->parent.write = _pwm_write;
+    device->parent.control = _pwm_control;
+#endif /* RT_USING_DEVICE_OPS */
 
+    device->parent.type         = RT_Device_Class_Miscellaneous;
     device->ops                 = ops;
     device->parent.user_data    = (void *)user_data;
 

+ 1 - 2
components/drivers/pm/pm.c

@@ -151,11 +151,10 @@ void rt_pm_enter(void)
             /* enter sleep and wait to be waken up */
             pm->ops->enter(pm);
 
-            rt_hw_interrupt_enable(level);
-
             /* exit from low power mode */
             rt_pm_exit();
 
+            rt_hw_interrupt_enable(level);
             return ;
         }
     }

+ 67 - 43
components/drivers/serial/serial.c

@@ -21,6 +21,7 @@
  * 2017-11-07     JasonJia     fix data bits error issue when using tcsetattr.
  * 2017-11-15     JasonJia     fix poll rx issue when data is full.
  *                             add TCFLSH and FIONREAD support.
+ * 2018-12-08     Ernest Chen  add DMA choice
  */
 
 #include <rthw.h>
@@ -328,6 +329,7 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
     return size - length;
 }
 
+#if defined(RT_USING_POSIX) || defined(RT_SERIAL_USING_DMA)
 static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial)
 {
     struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
@@ -350,7 +352,9 @@ static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial)
         }
     }
 }
+#endif /* RT_USING_POSIX || RT_SERIAL_USING_DMA */
 
+#ifdef RT_SERIAL_USING_DMA
 /**
  * Calculate DMA received data length.
  *
@@ -527,6 +531,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
         return 0;
     }
 }
+#endif /* RT_SERIAL_USING_DMA */
 
 /* RT-Thread Device Interface */
 /*
@@ -561,11 +566,13 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
 
     LOG_D("open serial device: 0x%08x with open flag: 0x%04x",
         dev, oflag);
+#ifdef RT_SERIAL_USING_DMA
     /* check device flag with the open flag */
     if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
         return -RT_EIO;
     if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
         return -RT_EIO;
+#endif /* RT_SERIAL_USING_DMA */
     if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
         return -RT_EIO;
     if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
@@ -580,8 +587,27 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
 
     /* initialize the Rx/Tx structure according to open flag */
     if (serial->serial_rx == RT_NULL)
-    {
-        if (oflag & RT_DEVICE_FLAG_DMA_RX)
+    { 
+        if (oflag & RT_DEVICE_FLAG_INT_RX)
+        {
+            struct rt_serial_rx_fifo* rx_fifo;
+
+            rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
+                serial->config.bufsz);
+            RT_ASSERT(rx_fifo != RT_NULL);
+            rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
+            rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
+            rx_fifo->put_index = 0;
+            rx_fifo->get_index = 0;
+            rx_fifo->is_full = RT_FALSE;
+
+            serial->serial_rx = rx_fifo;
+            dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
+            /* configure low level device */
+            serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
+        }
+#ifdef RT_SERIAL_USING_DMA        
+        else if (oflag & RT_DEVICE_FLAG_DMA_RX)
         {
             if (serial->config.bufsz == 0) {
                 struct rt_serial_rx_dma* rx_dma;
@@ -608,24 +634,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
             }
             dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
         }
-        else if (oflag & RT_DEVICE_FLAG_INT_RX)
-        {
-            struct rt_serial_rx_fifo* rx_fifo;
-
-            rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
-                serial->config.bufsz);
-            RT_ASSERT(rx_fifo != RT_NULL);
-            rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
-            rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
-            rx_fifo->put_index = 0;
-            rx_fifo->get_index = 0;
-            rx_fifo->is_full = RT_FALSE;
-
-            serial->serial_rx = rx_fifo;
-            dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
-            /* configure low level device */
-            serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
-        }
+#endif /* RT_SERIAL_USING_DMA */
         else
         {
             serial->serial_rx = RT_NULL;
@@ -633,28 +642,17 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
     }
     else
     {
-        if (oflag & RT_DEVICE_FLAG_DMA_RX)
-            dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
-        else if (oflag & RT_DEVICE_FLAG_INT_RX)
+        if (oflag & RT_DEVICE_FLAG_INT_RX)
             dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
+#ifdef RT_SERIAL_USING_DMA
+        else if (oflag & RT_DEVICE_FLAG_DMA_RX)
+            dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
+#endif /* RT_SERIAL_USING_DMA */  
     }
 
     if (serial->serial_tx == RT_NULL)
     {
-        if (oflag & RT_DEVICE_FLAG_DMA_TX)
-        {
-            struct rt_serial_tx_dma* tx_dma;
-
-            tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
-            RT_ASSERT(tx_dma != RT_NULL);
-            tx_dma->activated = RT_FALSE;
-
-            rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
-            serial->serial_tx = tx_dma;
-
-            dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
-        }
-        else if (oflag & RT_DEVICE_FLAG_INT_TX)
+        if (oflag & RT_DEVICE_FLAG_INT_TX)
         {
             struct rt_serial_tx_fifo *tx_fifo;
 
@@ -668,6 +666,21 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
             /* configure low level device */
             serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
         }
+#ifdef RT_SERIAL_USING_DMA
+        else if (oflag & RT_DEVICE_FLAG_DMA_TX)
+        {
+            struct rt_serial_tx_dma* tx_dma;
+
+            tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
+            RT_ASSERT(tx_dma != RT_NULL);
+            tx_dma->activated = RT_FALSE;
+
+            rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
+            serial->serial_tx = tx_dma;
+
+            dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
+        }
+#endif /* RT_SERIAL_USING_DMA */
         else
         {
             serial->serial_tx = RT_NULL;
@@ -675,10 +688,12 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
     }
     else
     {
-        if (oflag & RT_DEVICE_FLAG_DMA_TX)
-            dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
-        else if (oflag & RT_DEVICE_FLAG_INT_TX)
+        if (oflag & RT_DEVICE_FLAG_INT_TX)
             dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
+#ifdef RT_SERIAL_USING_DMA
+        else if (oflag & RT_DEVICE_FLAG_DMA_TX)
+            dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
+#endif /* RT_SERIAL_USING_DMA */    
     }
 
     /* set stream flag */
@@ -710,6 +725,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
         /* configure low level device */
         serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_RX);
     }
+#ifdef RT_SERIAL_USING_DMA
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
     {
         if (serial->config.bufsz == 0) {
@@ -732,7 +748,8 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
         serial->serial_rx = RT_NULL;
         dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
     }
-
+#endif /* RT_SERIAL_USING_DMA */
+    
     if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
     {
         struct rt_serial_tx_fifo* tx_fifo;
@@ -746,6 +763,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
         /* configure low level device */
         serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
     }
+#ifdef RT_SERIAL_USING_DMA
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
     {
         struct rt_serial_tx_dma* tx_dma;
@@ -757,7 +775,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
         serial->serial_tx = RT_NULL;
         dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
     }
-
+#endif /* RT_SERIAL_USING_DMA */
     return RT_EOK;
 }
 
@@ -777,10 +795,12 @@ static rt_size_t rt_serial_read(struct rt_device *dev,
     {
         return _serial_int_rx(serial, buffer, size);
     }
+#ifdef RT_SERIAL_USING_DMA
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
     {
         return _serial_dma_rx(serial, buffer, size);
     }
+#endif /* RT_SERIAL_USING_DMA */    
 
     return _serial_poll_rx(serial, buffer, size);
 }
@@ -801,10 +821,12 @@ static rt_size_t rt_serial_write(struct rt_device *dev,
     {
         return _serial_int_tx(serial, buffer, size);
     }
+#ifdef RT_SERIAL_USING_DMA    
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
     {
         return _serial_dma_tx(serial, buffer, size);
     }
+#endif /* RT_SERIAL_USING_DMA */
     else
     {
         return _serial_poll_tx(serial, buffer, size);
@@ -1181,12 +1203,13 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
             rt_completion_done(&(tx_fifo->completion));
             break;
         }
+#ifdef RT_SERIAL_USING_DMA
         case RT_SERIAL_EVENT_TX_DMADONE:
         {
             const void *data_ptr;
             rt_size_t data_size;
             const void *last_data_ptr;
-            struct rt_serial_tx_dma* tx_dma;
+            struct rt_serial_tx_dma *tx_dma;
 
             tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
 
@@ -1246,6 +1269,7 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
             }
             break;
         }
+#endif /* RT_SERIAL_USING_DMA */
     }
 }
 

+ 3 - 0
components/drivers/spi/SConscript

@@ -6,6 +6,9 @@ src = ['spi_core.c', 'spi_dev.c']
 CPPPATH = [cwd, cwd + '/../include']
 LOCAL_CCFLAGS = ''
 
+if GetDepend('RT_USING_QSPI'):
+    src += ['qspi_core.c']
+
 src_device = []
 
 if GetDepend('RT_USING_SPI_WIFI'):

+ 265 - 0
components/drivers/spi/qspi_core.c

@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-16     zylx      first version.
+ */
+
+#include <drivers/spi.h>
+
+rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg)
+{
+    RT_ASSERT(device != RT_NULL);
+    RT_ASSERT(cfg != RT_NULL);
+    
+    struct rt_qspi_device *qspi_device = (struct rt_qspi_device *)device;
+    rt_err_t result = RT_EOK;
+
+    /* copy configuration items */
+    qspi_device->config.parent.mode = cfg->parent.mode;
+    qspi_device->config.parent.max_hz = cfg->parent.max_hz;
+    qspi_device->config.parent.data_width = cfg->parent.data_width;
+    qspi_device->config.parent.reserved = cfg->parent.reserved;
+    qspi_device->config.medium_size = cfg->medium_size;
+    qspi_device->config.ddr_mode = cfg->ddr_mode;
+    qspi_device->config.qspi_dl_width = cfg->qspi_dl_width;
+
+    result = rt_spi_configure(&device->parent, &cfg->parent);
+
+    return result;
+}
+
+rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops)
+{
+    rt_err_t result = RT_EOK;
+    
+    result = rt_spi_bus_register(bus, name, ops);
+    if(result == RT_EOK)
+    {
+        /* set SPI bus to qspi modes */
+        bus->mode = RT_SPI_BUS_MODE_QSPI;
+    }
+    
+    return result;
+}
+
+rt_size_t rt_qspi_transfer_message(struct rt_qspi_device  *device, struct rt_qspi_message *message)
+{
+    rt_err_t result;
+
+    RT_ASSERT(device != RT_NULL);
+    RT_ASSERT(message != RT_NULL);
+
+    result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
+    if (result != RT_EOK)
+    {
+        rt_set_errno(-RT_EBUSY);
+
+        return 0;
+    }
+
+    /* reset errno */
+    rt_set_errno(RT_EOK);
+
+    /* configure SPI bus */
+    if (device->parent.bus->owner != &device->parent)
+    {
+        /* not the same owner as current, re-configure SPI bus */
+        result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
+        if (result == RT_EOK)
+        {
+            /* set SPI bus owner */
+            device->parent.bus->owner = &device->parent;
+        }
+        else
+        {
+            /* configure SPI bus failed */
+            rt_set_errno(-RT_EIO);
+            goto __exit;
+        }
+    }
+
+    /* transmit each SPI message */
+
+    result = device->parent.bus->ops->xfer(&device->parent, &message->parent);
+    if (result == 0)
+    {
+        rt_set_errno(-RT_EIO);
+    }
+
+__exit:
+    /* release bus lock */
+    rt_mutex_release(&(device->parent.bus->lock));
+
+    return result;
+}
+
+rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length)
+{
+    RT_ASSERT(send_buf);
+    RT_ASSERT(recv_buf);
+    RT_ASSERT(send_length != 0);
+
+    struct rt_qspi_message message;
+    unsigned char *ptr = (unsigned char *)send_buf;
+    rt_size_t count = 0;
+    rt_err_t result = 0;
+
+    message.instruction.content = ptr[0];
+    message.instruction.qspi_lines = 1;
+    count++;
+
+    /* get address */
+    if (send_length > 1)
+    {
+        if (device->config.medium_size > 0x1000000 && send_length >= 5)
+        {
+            /* medium size greater than 16Mb, address size is 4 Byte */
+            message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
+            message.address.size = 32;
+            count += 4;
+        }
+        else if (send_length >= 4)
+        {
+            /* address size is 3 Byte */
+            message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
+            message.address.size = 24;
+            count += 3;
+        }
+        else
+        {
+            return -RT_ERROR;
+        }
+        message.address.qspi_lines = 1;
+    }
+    else
+    {
+        /* no address stage */
+        message.address.content = 0 ;
+        message.address.qspi_lines = 0;
+        message.address.size = 0;
+    }
+
+    message.alternate_bytes.content = 0;
+    message.alternate_bytes.size = 0;
+    message.alternate_bytes.qspi_lines = 0;
+
+    /* set dummy cycles */
+    if (count != send_length)
+    {
+        message.dummy_cycles = (send_length - count) * 8;
+
+    }
+    else
+    {
+        message.dummy_cycles = 0;
+    }
+
+    /* set recv buf and recv size */
+    message.parent.recv_buf = recv_buf;
+    message.parent.send_buf = RT_NULL;
+    message.parent.length = recv_length;
+    message.parent.cs_take = 1;
+    message.parent.cs_release = 1;
+
+    message.qspi_data_lines = 1;
+
+    result = rt_qspi_transfer_message(device, &message);
+    if (result == 0)
+    {
+        result = -RT_EIO;
+    }
+    else
+    {
+        result = recv_length;
+    }
+
+    return result;
+}
+
+rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
+{
+    RT_ASSERT(send_buf);
+    RT_ASSERT(length != 0);
+
+    struct rt_qspi_message message;
+    char *ptr = (char *)send_buf;
+    rt_size_t  count = 0;
+    rt_err_t result = 0;
+
+    message.instruction.content = ptr[0];
+    message.instruction.qspi_lines = 1;
+    count++;
+
+    /* get address */
+    if (length > 1)
+    {
+        if (device->config.medium_size > 0x1000000 && length >= 5)
+        {
+            /* medium size greater than 16Mb, address size is 4 Byte */
+            message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
+            message.address.size = 32;
+            message.address.qspi_lines = 1;
+            count += 4;
+        }
+        else if (length >= 4)
+        {
+            /* address size is 3 Byte */
+            message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
+            message.address.size = 24;
+            message.address.qspi_lines = 1;
+            count += 3;
+        }
+        else
+        {
+            return -RT_ERROR;
+        }
+
+    }
+    else
+    {
+        /* no address stage */
+        message.address.content = 0 ;
+        message.address.qspi_lines = 0;
+        message.address.size = 0;
+    }
+
+    message.alternate_bytes.content = 0;
+    message.alternate_bytes.size = 0;
+    message.alternate_bytes.qspi_lines = 0;
+
+    message.dummy_cycles = 0;
+
+    /* determine if there is data to send */
+    if (length - count > 0)
+    {
+        message.qspi_data_lines = 1;
+    }
+    else
+    {
+        message.qspi_data_lines = 0;
+
+    }
+    
+    /* set send buf and send size */
+    message.parent.send_buf = ptr + count;
+    message.parent.recv_buf = RT_NULL;
+    message.parent.length = length - count;
+    message.parent.cs_take = 1;
+    message.parent.cs_release = 1;
+
+    result = rt_qspi_transfer_message(device, &message);
+    if (result == 0)
+    {
+        result = -RT_EIO;
+    }
+    else
+    {
+        result = length;
+    }
+
+    return result;
+}

+ 74 - 42
components/drivers/spi/sfud/README.md

@@ -6,11 +6,13 @@
 
 [SFUD](https://github.com/armink/SFUD) 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
 
-- 主要特点:面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
+- 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
 - 资源占用
   - 标准占用:RAM:0.2KB ROM:5.5KB
   - 最小占用:RAM:0.1KB ROM:3.6KB
-- 设计思路:这里要首先跟大家介绍一个标准: **SFDP** ,它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数,如果该 Flash 不支持 SFDP,则查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/master/sfud/inc/sfud_flash_def.h#L110-L122) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。
+- 设计思路:
+  - **什么是 SFDP** :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。
+  - **不支持 SFDP 怎么办** :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/4bee2d0417a7ce853cc7aa3639b03fe825611fd9/sfud/inc/sfud_flash_def.h#L116-L142) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。
 
 ## 1、为什么选择 SFUD
 
@@ -23,37 +25,43 @@
 
 ### 2.1 已支持 Flash 
 
-下表为所有在 Demo 平台上进行过真机测试的 Flash。目前 SFUD 提供的 **Flash 参数信息表** 只包括下表中 **不支持** SFDP 标准的 Flash,其他不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护**  **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
-
-|型号|制造商|容量|最高速度|SFDP  标准|备注|
-|:--:|:----:|:--:|:--:|:--:|:--:|
-|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|已停产|
-|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持||
-|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持| by [slipperstree](https://github.com/slipperstree)|
-|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持||
-|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持| by [slipperstree](https://github.com/slipperstree)|
-|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持||
-|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持||
-|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持||
-|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持||
-|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持||
-|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持| by [JiapengLi](https://github.com/JiapengLi)|
-|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持||
-|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持| SST 已被 Microchip 收购|
-|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)|
-|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)|
-|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持||
-|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持||
-|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持| by [TanekLiang](https://github.com/TanekLiang) |
-|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持||
-|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持||
-|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持| by [yc_911](https://gitee.com/yc_911) |
-|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持||
-|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持||
-|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持||
-|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持||
-|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|SST 授权许可,会被识别为 SST25VF016B|
-|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|ADESTO 收购 Atmel 串行闪存产品线|
+下表为所有已在 Demo 平台上进行过真机测试过的 Flash。显示为 **不支持** SFDP 标准的 Flash 已经在 Flash 参数信息表中定义,更多不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护**  **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。
+
+如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
+
+|型号|制造商|容量|最高速度|SFDP  标准|QSPI 模式|备注|
+|:--:|:----:|:--:|:--:|:--:|:--:|----|
+|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|双线|已停产|
+|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持|双线||
+|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持|双线| by [slipperstree](https://github.com/slipperstree)|
+|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持|未测试||
+|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持|未测试| by [slipperstree](https://github.com/slipperstree)|
+|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持|双线||
+|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持|四线||
+|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持|四线||
+|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持|四线||
+|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持|双线||
+|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持|未测试| by [JiapengLi](https://github.com/JiapengLi)|
+|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持|双线||
+|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持|不支持| SST 已被 Microchip 收购|
+|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)|
+|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)|
+|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持|不支持||
+|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持|未测试||
+|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持|未测试| by [TanekLiang](https://github.com/TanekLiang) |
+|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持|双线||
+|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持|双线||
+|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持|未测试| by [yc_911](https://gitee.com/yc_911) |
+|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持|未测试||
+|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持|双线||
+|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持|支持||
+|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持|不支持||
+|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|不支持|SST 授权许可,会被识别为 SST25VF016B|
+|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|不支持|ADESTO 收购 Atmel 串行闪存产品线|
+
+> 注:QSPI 模式中,双线表示支持双线快读,四线表示支持四线快读。
+>
+> 一般情况下,支持四线快读的 FLASH 也支持两线快读。
 
 ### 2.2 API 说明
 
@@ -63,7 +71,7 @@
 
 将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。
 
-> 注意:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
+> **注意**:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
 
 ```C
 sfud_err sfud_init(void)
@@ -79,7 +87,24 @@ sfud_err sfud_device_init(sfud_flash *flash)
 |:-----                                  |:----|
 |flash                                   |待初始化的 Flash 设备|
 
-#### 2.2.3 获取 Flash 设备对象
+#### 2.2.3 使能快速读模式(仅当 SFUD 开启 QSPI 模式后可用)
+
+当 SFUD 开启 QSPI 模式后,SFUD 中的 Flash 驱动支持使用 QSPI 总线进行通信。相比传统的 SPI 模式,使用 QSPI 能够加速 Flash 数据的读取,但当数据需要写入时,由于 Flash 本身的数据写入速度慢于 SPI 传输速度,所以 QSPI 模式下的数据写入速度提升并不明显。
+
+所以 SFUD 对于 QSPI 模式的支持仅限于快速读命令。通过该函数可以配置 Flash 所使用的 QSPI 总线的实际支持的数据线最大宽度,例如:1 线(默认值,即传统的 SPI 模式)、2 线、4 线。
+
+设置后,SFUD 会去结合当前设定的 QSPI 总线数据线宽度,去 [QSPI Flash 扩展信息表](https://github.com/armink/SFUD/blob/069d2b409ec239f84d675b2c3d37894e908829e6/sfud/inc/sfud_flash_def.h#L149-L177) 中匹配最合适的、速度最快的快速读命令,之后用户在调用 sfud_read() 时,会使用 QSPI 模式的传输函数发送该命令。
+
+```C
+sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width)
+```
+
+| 参数            | 描述                                         |
+| :-------------- | :------------------------------------------- |
+| flash           | Flash 设备                                   |
+| data_line_width | QSPI 总线支持的数据线最大宽度,例如:1、2、4 |
+
+#### 2.2.4 获取 Flash 设备对象
 
 在 SFUD 配置文件中会定义 Flash 设备表,负责存放所有将要使用的 Flash 设备对象,所以 SFUD 支持多个 Flash 设备同时驱动。设备表的配置在 `/sfud/inc/sfud_cfg.h` 中 `SFUD_FLASH_DEVICE_TABLE` 宏定义,详细配置方法参照 [2.3 配置方法 Flash](#23-配置方法))。本方法通过 Flash 设备位于设备表中索引值来返回 Flash 设备对象,超出设备表范围返回 `NULL` 。
 
@@ -91,7 +116,7 @@ sfud_flash *sfud_get_device(size_t index)
 |:-----                                  |:----|
 |index                                   |Flash 设备位于 FLash 设备表中的索引值|
 
-#### 2.2.4 读取 Flash 数据
+#### 2.2.5 读取 Flash 数据
 
 ```C
 sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)
@@ -104,7 +129,7 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
 |size                                    |从起始地址开始读取数据的总大小|
 |data                                    |读取到的数据|
 
-#### 2.2.5 擦除 Flash 数据
+#### 2.2.6 擦除 Flash 数据
 
 > 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
 
@@ -118,7 +143,7 @@ sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size)
 |addr                                    |起始地址|
 |size                                    |从起始地址开始擦除数据的总大小|
 
-#### 2.2.6 擦除 Flash 全部数据
+#### 2.2.7 擦除 Flash 全部数据
 
 ```C
 sfud_err sfud_chip_erase(const sfud_flash *flash)
@@ -128,7 +153,7 @@ sfud_err sfud_chip_erase(const sfud_flash *flash)
 |:-----                                  |:----|
 |flash                                   |Flash 设备对象|
 
-#### 2.2.7 往 Flash 写数据
+#### 2.2.8 往 Flash 写数据
 
 ```C
 sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
@@ -141,7 +166,7 @@ sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const u
 |size                                    |从起始地址开始写入数据的总大小|
 |data                                    |待写入的数据|
 
-#### 2.2.8 先擦除再往 Flash 写数据
+#### 2.2.9 先擦除再往 Flash 写数据
 
 > 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
 
@@ -156,7 +181,7 @@ sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, c
 |size                                    |从起始地址开始写入数据的总大小|
 |data                                    |待写入的数据|
 
-#### 2.2.9 读取 Flash 状态
+#### 2.2.10 读取 Flash 状态
 
 ```C
 sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
@@ -167,7 +192,7 @@ sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
 |flash                                   |Flash 设备对象|
 |status                                  |当前状态寄存器值|
 
-#### 2.2.10 写(修改) Flash 状态
+#### 2.2.11 写(修改) Flash 状态
 
 ```C
 sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status)
@@ -234,6 +259,12 @@ enum {
 
 上面定义了两个 Flash 设备(大部分产品一个足以),两个设备的名称为 `"W25Q64CV"` 及 `"GD25Q64B"` ,分别对应 `"SPI1"` 及 `"SPI3"` 这两个 SPI 设备名称(在移植 SPI 接口时会用到,位于 `/sfud/port/sfud_port.c` ), `SFUD_W25Q16CV_DEVICE_INDEX` 与 `SFUD_GD25Q64B_DEVICE_INDEX` 这两个枚举定义了两个设备位于设备表中的索引,可以通过 `sfud_get_device_table()` 方法获取到设备表,再配合这个索引值来访问指定的设备。
 
+#### 2.3.6 QSPI 模式
+
+打开/关闭 `SFUD_USING_QSPI` 宏定义
+
+开启后,SFUD 也将支持使用 QSPI 总线连接的 Flash。
+
 ### 2.4 移植说明
 
 移植文件位于 `/sfud/port/sfud_port.c` ,文件中的 `sfud_err sfud_spi_port_init(sfud_flash *flash)` 方法是库提供的移植方法,在里面完成各个设备 SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。更加详细的移植内容,可以参考 demo 中的各个平台的移植文件。
@@ -258,6 +289,7 @@ enum {
 |:-----                           |:----|
 |[/demo/stm32f10x_non_os](https://github.com/armink/SFUD/tree/master/demo/stm32f10x_non_os) |STM32F10X 裸机平台|
 |[/demo/stm32f2xx_rtt](https://github.com/armink/SFUD/tree/master/demo/stm32f2xx_rtt)  |STM32F2XX + [RT-Thread](http://www.rt-thread.org/) 操作系统平台|
+|[/demo/stm32l475_non_os_qspi](https://github.com/armink/SFUD/tree/master/demo/stm32l475_non_os_qspi) |STM32L475 + QSPI 模式 裸机平台|
 
 ### 2.7 许可
 

+ 18 - 1
components/drivers/spi/sfud/inc/sfud.h

@@ -1,7 +1,7 @@
 /*
  * This file is part of the Serial Flash Universal Driver Library.
  *
- * Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
+ * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -75,6 +75,23 @@ size_t sfud_get_device_num(void);
  */
 const sfud_flash *sfud_get_device_table(void);
 
+#ifdef SFUD_USING_QSPI
+/**
+ * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
+ *
+ * it will find the appropriate fast-read instruction to replace the read instruction(0x03)
+ * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
+ *
+ * @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
+ *
+ * @param flash flash device
+ * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
+ *
+ * @return result
+ */
+sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width);
+#endif /* SFUD_USING_QSPI */
+
 /**
  * read flash data
  *

+ 7 - 0
components/drivers/spi/sfud/inc/sfud_cfg.h

@@ -45,6 +45,13 @@
 #define SFUD_USING_SFDP
 #endif
 
+/**
+ * SFUD will support QSPI mode.
+ */
+#ifdef RT_SFUD_USING_QSPI
+#define SFUD_USING_QSPI
+#endif
+
 /**
  * Using probe flash JEDEC ID then query defined supported flash chip information table. @see SFUD_FLASH_CHIP_TABLE
  */

+ 43 - 3
components/drivers/spi/sfud/inc/sfud_def.h

@@ -1,7 +1,7 @@
 /*
  * This file is part of the Serial Flash Universal Driver Library.
  *
- * Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
+ * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -78,7 +78,7 @@ if (!(EXPR))                                                                   \
     else {if (__delay_temp) {__delay_temp();} retry --;}
 
 /* software version number */
-#define SFUD_SW_VERSION                             "1.0.6"
+#define SFUD_SW_VERSION                             "1.1.0"
 /*
  * all defined supported command
  */
@@ -118,6 +118,22 @@ if (!(EXPR))                                                                   \
 #define SFUD_CMD_READ_DATA                             0x03
 #endif
 
+#ifndef SFUD_CMD_DUAL_OUTPUT_READ_DATA 
+#define SFUD_CMD_DUAL_OUTPUT_READ_DATA                 0x3B
+#endif
+
+#ifndef SFUD_CMD_DUAL_IO_READ_DATA 
+#define SFUD_CMD_DUAL_IO_READ_DATA                     0xBB
+#endif
+
+#ifndef SFUD_CMD_QUAD_IO_READ_DATA
+#define SFUD_CMD_QUAD_IO_READ_DATA                     0xEB
+#endif
+
+#ifndef SFUD_CMD_QUAD_OUTPUT_READ_DATA
+#define SFUD_CMD_QUAD_OUTPUT_READ_DATA                 0x6B
+#endif
+
 #ifndef SFUD_CMD_MANUFACTURER_DEVICE_ID
 #define SFUD_CMD_MANUFACTURER_DEVICE_ID                0x90
 #endif
@@ -183,6 +199,21 @@ typedef enum {
     SFUD_ERR_ADDR_OUT_OF_BOUND = 5,                        /**< address is out of flash bound */
 } sfud_err;
 
+#ifdef SFUD_USING_QSPI
+/**
+ * QSPI flash read cmd format
+ */
+typedef struct {
+    uint8_t instruction;
+    uint8_t instruction_lines;
+    uint8_t address_size;
+    uint8_t address_lines;
+    uint8_t alternate_bytes_lines;
+    uint8_t dummy_cycles;
+    uint8_t data_lines;
+} sfud_qspi_read_cmd_format;
+#endif /* SFUD_USING_QSPI */
+
 /* SPI bus write read data function type */
 typedef sfud_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size);
 
@@ -218,7 +249,12 @@ typedef struct __sfud_spi {
     char *name;
     /* SPI bus write read data function */
     sfud_err (*wr)(const struct __sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
-            size_t read_size);
+                   size_t read_size);
+#ifdef SFUD_USING_QSPI
+    /* QSPI fast read function */
+    sfud_err (*qspi_read)(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format,
+                          uint8_t *read_buf, size_t read_size);
+#endif
     /* lock SPI bus */
     void (*lock)(const struct __sfud_spi *spi);
     /* unlock SPI bus */
@@ -243,6 +279,10 @@ typedef struct {
     } retry;
     void *user_data;                             /**< some user data */
 
+#ifdef SFUD_USING_QSPI
+    sfud_qspi_read_cmd_format read_cmd_format;   /**< fast read cmd format */
+#endif
+
 #ifdef SFUD_USING_SFDP
     sfud_sfdp sfdp;                              /**< serial flash discoverable parameters by JEDEC standard */
 #endif

+ 48 - 2
components/drivers/spi/sfud/inc/sfud_flash_def.h

@@ -1,7 +1,7 @@
 /*
  * This file is part of the Serial Flash Universal Driver Library.
  *
- * Copyright (c) 2016-2017, Armink, <armink.ztl@gmail.com>
+ * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -59,11 +59,21 @@ typedef struct {
     uint8_t type_id;                             /**< memory type ID */
     uint8_t capacity_id;                         /**< capacity ID */
     uint32_t capacity;                           /**< flash capacity (bytes) */
-    uint16_t write_mode;                         /**< write mode  @see sfud_write_mode */
+    uint16_t write_mode;                         /**< write mode @see sfud_write_mode */
     uint32_t erase_gran;                         /**< erase granularity (bytes) */
     uint8_t erase_gran_cmd;                      /**< erase granularity size block command */
 } sfud_flash_chip;
 
+#ifdef SFUD_USING_QSPI
+/* QSPI flash chip's extended information compared with SPI flash */
+typedef struct {
+    uint8_t mf_id;                               /**< manufacturer ID */
+    uint8_t type_id;                             /**< memory type ID */
+    uint8_t capacity_id;                         /**< capacity ID */
+    uint8_t read_mode;                           /**< supported read mode on this qspi flash chip */
+} sfud_qspi_flash_ext_info;
+#endif
+
 /* SFUD support manufacturer JEDEC ID */
 #define SFUD_MF_ID_CYPRESS                             0x01
 #define SFUD_MF_ID_FUJITSU                             0x04
@@ -131,6 +141,42 @@ typedef struct {
 }
 #endif /* SFUD_USING_FLASH_INFO_TABLE */
 
+#ifdef SFUD_USING_QSPI
+/* This table saves flash read-fast instructions in QSPI mode, 
+ * SFUD can use this table to select the most appropriate read instruction for flash.
+ * | mf_id | type_id | capacity_id | qspi_read_mode |
+ */
+#define SFUD_FLASH_EXT_INFO_TABLE                                                                  \
+{                                                                                                  \
+    /* W25Q40BV */                                                                                 \
+    {SFUD_MF_ID_WINBOND, 0x40, 0x13, NORMAL_SPI_READ|DUAL_OUTPUT},                                 \
+    /* W25Q80JV */                                                                                 \
+    {SFUD_MF_ID_WINBOND, 0x40, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT},                                 \
+    /* W25Q16BV */                                                                                 \
+    {SFUD_MF_ID_WINBOND, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT},                                 \
+    /* W25Q32BV */                                                                                 \
+    {SFUD_MF_ID_WINBOND, 0x40, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT},                                 \
+    /* W25Q64JV */                                                                                 \
+    {SFUD_MF_ID_WINBOND, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO},     \
+    /* W25Q128JV */                                                                                \
+    {SFUD_MF_ID_WINBOND, 0x40, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO},     \
+    /* W25Q256FV */                                                                                \
+    {SFUD_MF_ID_WINBOND, 0x40, 0x19, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO},     \
+    /* EN25Q32B */                                                                                 \
+    {SFUD_MF_ID_EON, 0x30, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT|QUAD_IO},                             \
+    /* S25FL216K */                                                                                \
+    {SFUD_MF_ID_CYPRESS, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT},                                 \
+    /* A25L080 */                                                                                  \
+    {SFUD_MF_ID_AMIC, 0x30, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO},                            \
+    /* A25LQ64 */                                                                                  \
+    {SFUD_MF_ID_AMIC, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_IO},                    \
+    /* MX25L3206E and KH25L3206E */                                                                \
+    {SFUD_MF_ID_MICRONIX, 0x20, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT},                                \
+    /* GD25Q64B */                                                                                 \
+    {SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT},                              \
+}
+#endif /* SFUD_USING_QSPI */
+
 #ifdef __cplusplus
 }
 #endif

+ 123 - 9
components/drivers/spi/sfud/src/sfud.c

@@ -1,7 +1,7 @@
 /*
  * This file is part of the Serial Flash Universal Driver Library.
  *
- * Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
+ * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -46,6 +46,22 @@ static const sfud_mf mf_table[] = SFUD_MF_TABLE;
 static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
 #endif
 
+#ifdef SFUD_USING_QSPI
+/**
+ * flash read data mode
+ */
+enum sfud_qspi_read_mode {
+    NORMAL_SPI_READ = 1 << 0,               /**< mormal spi read mode */
+    DUAL_OUTPUT = 1 << 1,                   /**< qspi fast read dual output */
+    DUAL_IO = 1 << 2,                       /**< qspi fast read dual input/output */
+    QUAD_OUTPUT = 1 << 3,                   /**< qspi fast read quad output */
+    QUAD_IO = 1 << 4,                       /**< qspi fast read quad input/output */
+};
+
+/* QSPI flash chip's extended information table */
+static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE;
+#endif /* SFUD_USING_QSPI */
+
 static sfud_err software_init(const sfud_flash *flash);
 static sfud_err hardware_init(sfud_flash *flash);
 static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
@@ -146,11 +162,89 @@ const sfud_flash *sfud_get_device_table(void) {
     return flash_table;
 }
 
+#ifdef SFUD_USING_QSPI
+static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines,
+        uint8_t dummy_cycles, uint8_t data_lines) {
+    /* if medium size greater than 16Mb, use 4-Byte address, instruction should be added one */
+    if (flash->chip.capacity <= 0x1000000) {
+        flash->read_cmd_format.instruction = ins;
+        flash->read_cmd_format.address_size = 24;
+    } else {
+        flash->read_cmd_format.instruction = ins + 1;
+        flash->read_cmd_format.address_size = 32;
+    }
+
+    flash->read_cmd_format.instruction_lines = ins_lines;
+    flash->read_cmd_format.address_lines = addr_lines;
+    flash->read_cmd_format.alternate_bytes_lines = 0;
+    flash->read_cmd_format.dummy_cycles = dummy_cycles;
+    flash->read_cmd_format.data_lines = data_lines;
+}
+
+/**
+ * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
+ *
+ * it will find the appropriate fast-read instruction to replace the read instruction(0x03)
+ * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
+ *
+ * @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
+ *
+ * @param flash flash device
+ * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
+ *
+ * @return result
+ */
+sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
+    size_t i = 0;
+    uint8_t read_mode = NORMAL_SPI_READ;
+    sfud_err result = SFUD_SUCCESS;
+
+    SFUD_ASSERT(flash);
+    SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
+
+    /* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */
+    for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
+        if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
+                && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
+                && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
+            read_mode = qspi_flash_ext_info_table[i].read_mode;
+        }
+    }
+
+    /* determine qspi supports which read mode and set read_cmd_format struct */
+    switch (data_line_width) {
+    case 1:
+        qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
+        break;
+    case 2:
+        if (read_mode & DUAL_IO) {
+            qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 8, 2);
+        } else if (read_mode & DUAL_OUTPUT) {
+            qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
+        } else {
+            qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
+        }
+        break;
+    case 4:
+        if (read_mode & QUAD_IO) {
+            qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
+        } else if (read_mode & QUAD_OUTPUT) {
+            qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
+        } else {
+            qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
+        }
+        break;
+    }
+
+    return result;
+}
+#endif /* SFUD_USING_QSPI */
+
 /**
  * hardware initialize
  */
 static sfud_err hardware_init(sfud_flash *flash) {
-    extern sfud_err sfud_spi_port_init(sfud_flash *flash);
+    extern sfud_err sfud_spi_port_init(sfud_flash * flash);
 
     sfud_err result = SFUD_SUCCESS;
     size_t i;
@@ -162,6 +256,11 @@ static sfud_err hardware_init(sfud_flash *flash) {
         return result;
     }
 
+#ifdef SFUD_USING_QSPI
+    /* set default read instruction */
+    flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
+#endif /* SFUD_USING_QSPI */
+
     /* SPI write read function must be initialize */
     SFUD_ASSERT(flash->spi.wr);
     /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
@@ -315,10 +414,17 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
     result = wait_busy(flash);
 
     if (result == SFUD_SUCCESS) {
-        cmd_data[0] = SFUD_CMD_READ_DATA;
-        make_adress_byte_array(flash, addr, &cmd_data[1]);
-        cmd_size = flash->addr_in_4_byte ? 5 : 4;
-        result = spi->wr(spi, cmd_data, cmd_size, data, size);
+#ifdef SFUD_USING_QSPI
+        if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
+            result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
+        } else
+#endif
+        {
+            cmd_data[0] = SFUD_CMD_READ_DATA;
+            make_adress_byte_array(flash, addr, &cmd_data[1]);
+            cmd_size = flash->addr_in_4_byte ? 5 : 4;
+            result = spi->wr(spi, cmd_data, cmd_size, data, size);
+        }
     }
     /* unlock SPI */
     if (spi->unlock) {
@@ -328,7 +434,6 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
     return result;
 }
 
-
 /**
  * erase all flash data
  *
@@ -498,7 +603,8 @@ static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr,
         const uint8_t *data) {
     sfud_err result = SFUD_SUCCESS;
     const sfud_spi *spi = &flash->spi;
-    uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE], cmd_size;
+    static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE];
+    uint8_t cmd_size;
     size_t data_size;
 
     SFUD_ASSERT(flash);
@@ -715,8 +821,16 @@ static sfud_err reset(const sfud_flash *flash) {
     SFUD_ASSERT(flash);
 
     cmd_data[0] = SFUD_CMD_ENABLE_RESET;
+    result = spi->wr(spi, cmd_data, 1, NULL, 0);
+    if (result == SFUD_SUCCESS) {
+        result = wait_busy(flash);
+    } else {
+        SFUD_INFO("Error: Flash device reset failed.");
+        return result;
+    }
+
     cmd_data[1] = SFUD_CMD_RESET;
-    result = spi->wr(spi, cmd_data, 2, NULL, 0);
+    result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);
 
     if (result == SFUD_SUCCESS) {
         result = wait_busy(flash);

+ 2 - 0
components/drivers/spi/spi_core.c

@@ -34,6 +34,8 @@ rt_err_t rt_spi_bus_register(struct rt_spi_bus       *bus,
     bus->ops = ops;
     /* initialize owner */
     bus->owner = RT_NULL;
+    /* set bus mode */
+    bus->mode = RT_SPI_BUS_MODE_SPI;
 
     return RT_EOK;
 }

+ 131 - 25
components/drivers/spi/spi_flash_sfud.c

@@ -23,11 +23,21 @@
 
 #ifndef RT_SFUD_DEFAULT_SPI_CFG
 /* read the JEDEC SFDP command must run at 50 MHz or less */
-#define RT_SFUD_DEFAULT_SPI_CFG                 \
-{                                               \
-    .mode = RT_SPI_MODE_0 | RT_SPI_MSB,         \
-    .data_width = 8,                            \
-    .max_hz = 50 * 1000 * 1000,                 \
+#define RT_SFUD_DEFAULT_SPI_CFG                  \
+{                                                \
+    .mode = RT_SPI_MODE_0 | RT_SPI_MSB,          \
+    .data_width = 8,                             \
+    .max_hz = 50 * 1000 * 1000,                  \
+}
+#endif
+
+#ifdef SFUD_USING_QSPI
+#define RT_SFUD_DEFAULT_QSPI_CFG                 \
+{                                                \
+    RT_SFUD_DEFAULT_SPI_CFG,                     \
+    .medium_size = 0x800000,                     \
+    .ddr_mode = 0,                               \
+    .qspi_dl_width = 4,                          \
 }
 #endif
 
@@ -116,31 +126,90 @@ static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, si
     sfud_err result = SFUD_SUCCESS;
     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
-
+#ifdef SFUD_USING_QSPI
+    struct rt_qspi_device *qspi_dev = RT_NULL;
+#endif
     if (write_size) {
         RT_ASSERT(write_buf);
     }
     if (read_size) {
         RT_ASSERT(read_buf);
     }
-
-    if (write_size && read_size) {
-        if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
-            result = SFUD_ERR_TIMEOUT;
-        }
-    } else if (write_size) {
-        if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) {
-            result = SFUD_ERR_TIMEOUT;
+#ifdef SFUD_USING_QSPI
+    if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
+        qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
+        if (write_size && read_size) {
+            if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) == 0) {
+                result = SFUD_ERR_TIMEOUT;
+            }
+        } else if (write_size) {
+            if (rt_qspi_send(qspi_dev, write_buf, write_size) == 0) {
+                result = SFUD_ERR_TIMEOUT;
+            }
         }
-    } else {
-        if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) {
-            result = SFUD_ERR_TIMEOUT;
+    }
+    else
+#endif
+    {
+        if (write_size && read_size) {
+            if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
+                result = SFUD_ERR_TIMEOUT;
+            }
+        } else if (write_size) {
+            if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) {
+                result = SFUD_ERR_TIMEOUT;
+            }
+        } else {
+            if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) {
+                result = SFUD_ERR_TIMEOUT;
+            }
         }
     }
 
     return result;
 }
 
+#ifdef SFUD_USING_QSPI
+/**
+ * QSPI fast read data
+ */
+static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) {
+    struct rt_qspi_message message;
+    sfud_err result = SFUD_SUCCESS;
+
+    sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
+    struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
+    struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
+                             
+    /* set message struct */
+    message.instruction.content = qspi_read_cmd_format->instruction;
+    message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;
+
+    message.address.content = addr;
+    message.address.size = qspi_read_cmd_format->address_size;
+    message.address.qspi_lines = qspi_read_cmd_format->address_lines;
+
+    message.alternate_bytes.content = 0;
+    message.alternate_bytes.size = 0;
+    message.alternate_bytes.qspi_lines = 0;
+
+    message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;
+
+    message.parent.send_buf = RT_NULL;
+    message.parent.recv_buf = read_buf;
+    message.parent.length = read_size;
+    message.parent.cs_release = 1;
+    message.parent.cs_take = 1;
+    message.qspi_data_lines = qspi_read_cmd_format->data_lines;
+    
+    if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
+        result = SFUD_ERR_TIMEOUT;
+    }
+    
+    return result;
+}
+#endif
+
 static void spi_lock(const sfud_spi *spi) {
     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
@@ -203,6 +272,9 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
 
     /* port SPI device interface */
     flash->spi.wr = spi_write_read;
+#ifdef SFUD_USING_QSPI
+    flash->spi.qspi_read = qspi_read;
+#endif
     flash->spi.lock = spi_lock;
     flash->spi.unlock = spi_unlock;
     flash->spi.user_data = flash;
@@ -213,8 +285,7 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
     flash->retry.delay = retry_delay_100us;
     /* 60 seconds timeout */
     flash->retry.times = 60 * 10000;
-
-
+    
     return result;
 }
 
@@ -246,6 +317,10 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
      * @note you also can change the SPI to other configuration after initialized finish */
     struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
     extern sfud_err sfud_device_init(sfud_flash *flash);
+#ifdef SFUD_USING_QSPI
+    struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;
+    struct rt_qspi_device *qspi_dev = RT_NULL;
+#endif
 
     RT_ASSERT(spi_flash_dev_name);
     RT_ASSERT(spi_dev_name);
@@ -277,7 +352,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
                 goto error;
             }
             sfud_dev->spi.name = spi_dev_name_bak;
-            rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
+
+#ifdef SFUD_USING_QSPI
+            /* set the qspi line number and configure the QSPI bus */
+            if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
+                qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
+                qspi_cfg.qspi_dl_width = qspi_dev->config.qspi_dl_width;
+                rt_qspi_configure(qspi_dev, &qspi_cfg);
+            }
+            else
+#endif                
+                rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
         }
         /* SFUD flash device initialize */
         {
@@ -296,6 +381,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
             rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
             rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
             rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
+#ifdef SFUD_USING_QSPI
+            /* reconfigure the QSPI bus for medium size */
+            if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
+                qspi_cfg.medium_size = sfud_dev->chip.capacity;
+                rt_qspi_configure(qspi_dev, &qspi_cfg);
+                if(qspi_dev->enter_qspi_mode != RT_NULL)
+                    qspi_dev->enter_qspi_mode(qspi_dev);
+            }
+            /* set data lines width */
+            sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
+#endif /* SFUD_USING_QSPI */
         }
 
         /* register device */
@@ -402,14 +498,17 @@ static void sf(uint8_t argc, char **argv) {
             } else {
                 char *spi_dev_name = argv[2];
                 rtt_dev_bak = rtt_dev;
+                
+                /* delete the old SPI flash device */
+                if(rtt_dev_bak) {
+                    rt_sfud_flash_delete(rtt_dev_bak);
+                }
+                
                 rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
                 if (!rtt_dev) {
                     return;
                 }
-                /* already probe then delete the old SPI flash device */
-                if(rtt_dev_bak) {
-                    rt_sfud_flash_delete(rtt_dev_bak);
-                }
+
                 sfud_dev = (sfud_flash_t)rtt_dev->user_data;
                 if (sfud_dev->chip.capacity < 1024 * 1024) {
                     rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
@@ -520,7 +619,7 @@ static void sf(uint8_t argc, char **argv) {
                 addr = 0;
                 size = sfud_dev->chip.capacity;
                 uint32_t start_time, time_cast;
-                size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = 4096;
+                size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE;
                 uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
 
                 if (write_data && read_data) {
@@ -561,6 +660,13 @@ static void sf(uint8_t argc, char **argv) {
                         } else {
                             result = sfud_read(sfud_dev, addr + i, size - i, read_data);
                         }
+                        /* data check */
+                        if (memcmp(write_data, read_data, read_size))
+                        {
+                            rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
+                            result = SFUD_ERR_READ;
+                        }
+                        
                         if (result != SFUD_SUCCESS) {
                             break;
                         }

+ 1 - 0
components/drivers/spi/spi_flash_sfud.h

@@ -12,6 +12,7 @@
 #define _SPI_FLASH_SFUD_H_
 
 #include <rtthread.h>
+#include <rtdevice.h>
 #include "./sfud/inc/sfud.h"
 #include "spi_flash.h"
 

+ 59 - 131
components/drivers/spi/spi_msd.c

@@ -37,8 +37,6 @@ static struct msd_device  _msd_device;
 static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long);
 
 static rt_err_t MSD_take_owner(struct rt_spi_device *spi_device);
-static void MSD_take_cs(struct rt_spi_device *device);
-static void MSD_release_cs(struct rt_spi_device *device);
 
 static rt_err_t _wait_token(struct rt_spi_device *device, uint8_t token);
 static rt_err_t _wait_ready(struct rt_spi_device *device);
@@ -73,36 +71,6 @@ static rt_err_t MSD_take_owner(struct rt_spi_device *spi_device)
     return result;
 }
 
-static void MSD_take_cs(struct rt_spi_device *device)
-{
-    struct rt_spi_message message;
-
-    /* initial message */
-    message.send_buf = RT_NULL;
-    message.recv_buf = RT_NULL;
-    message.length = 0;
-    message.cs_take = 1;
-    message.cs_release = 0;
-
-    /* transfer message */
-    device->bus->ops->xfer(device, &message);
-}
-
-static void MSD_release_cs(struct rt_spi_device *device)
-{
-    struct rt_spi_message message;
-
-    /* initial message */
-    message.send_buf = RT_NULL;
-    message.recv_buf = RT_NULL;
-    message.length = 0;
-    message.cs_take = 0;
-    message.cs_release = 1;
-
-    /* transfer message */
-    device->bus->ops->xfer(device, &message);
-}
-
 static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long)
 {
     rt_tick_t tick_end = tick_start + tick_long;
@@ -517,7 +485,7 @@ static rt_err_t rt_msd_init(rt_device_t dev)
             goto _exit;
         }
 
-        MSD_release_cs(msd->spi_device);
+        rt_spi_release(msd->spi_device);
 
         /* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and
            start to supply at least 74 SD clocks to the SD card with keeping CMD line to high.
@@ -542,9 +510,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 
             while (1)
             {
-                MSD_take_cs(msd->spi_device);
+                rt_spi_take(msd->spi_device);
                 result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response);
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
 
                 if ((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE))
                 {
@@ -568,9 +536,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 
             do
             {
-                MSD_take_cs(msd->spi_device);
+                rt_spi_take(msd->spi_device);
                 result = _send_cmd(msd->spi_device, SEND_IF_COND, 0x01AA, 0x87, response_r7, response);
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
 
                 if (result == RT_EOK)
                 {
@@ -622,23 +590,23 @@ static rt_err_t rt_msd_init(rt_device_t dev)
             /* try SD Ver1.x */
             while (1)
             {
-                MSD_take_cs(msd->spi_device);
+                rt_spi_take(msd->spi_device);
 
                 result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
                 if (result != RT_EOK)
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     MSD_DEBUG("[info] It maybe SD1.x or MMC But it is Not response to CMD58!\r\n");
                     goto _exit;
                 }
 
                 if (0 != (response[0] & 0xFE))
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     MSD_DEBUG("[info] It look CMD58 as illegal command so it is not SD card!\r\n");
                     break;
                 }
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
 
                 OCR = response[1];
                 OCR = (OCR << 8) + response[2];
@@ -661,24 +629,24 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                 {
                     if (rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41)))
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         MSD_DEBUG("[info] try CMD55 + ACMD41 timeout! mabey MMC card!\r\n");
                         break;
                     }
 
-                    MSD_take_cs(msd->spi_device);
+                    rt_spi_take(msd->spi_device);
 
                     /* CMD55 APP_CMD */
                     result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response);
                     if (result != RT_EOK)
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         continue;
                     }
 
                     if (0 != (response[0] & 0xFE))
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         MSD_DEBUG("[info] Not SD card2 , may be MMC\r\n");
                         break;
                     }
@@ -687,20 +655,20 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                     result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x00, 0x00, response_r1, response);
                     if (result != RT_EOK)
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         continue;
                     }
 
                     if (0 != (response[0] & 0xFE))
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         MSD_DEBUG("[info] Not SD card4 , may be MMC\r\n");
                         break;
                     }
 
                     if (0 == (response[0] & 0xFF))
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         is_sd_v1_x = RT_TRUE;
                         MSD_DEBUG("[info] It is Ver1.X SD Memory Card!!!\r\n");
                         break;
@@ -716,7 +684,7 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                 uint32_t i;
 
                 MSD_DEBUG("[info] try MMC card!\r\n");
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
 
                 /* send dummy clock */
                 {
@@ -740,9 +708,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                 tick_start = rt_tick_get();
                 while (1)
                 {
-                    MSD_take_cs(msd->spi_device);
+                    rt_spi_take(msd->spi_device);
                     result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response);
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
 
                     if ((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE))
                     {
@@ -761,9 +729,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                 tick_start = rt_tick_get();
                 while (1)
                 {
-                    MSD_take_cs(msd->spi_device);
+                    rt_spi_take(msd->spi_device);
                     result = _send_cmd(msd->spi_device, SEND_OP_COND, 0x00, 0x00, response_r1, response);
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
 
                     if ((result == RT_EOK) && (response[0] == MSD_RESPONSE_NO_ERROR))
                     {
@@ -783,25 +751,25 @@ static rt_err_t rt_msd_init(rt_device_t dev)
         }
         else if (msd->card_type == MSD_CARD_TYPE_SD_V2_X)
         {
-            MSD_take_cs(msd->spi_device);
+            rt_spi_take(msd->spi_device);
 
             result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
             if (result != RT_EOK)
             {
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
                 MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to CMD58!\r\n");
                 goto _exit;
             }
 
             if ((response[0] & 0xFE) != 0)
             {
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
                 MSD_DEBUG("[err] It look CMD58 as illegal command so it is not SD card!\r\n");
                 result = RT_ERROR;
                 goto _exit;
             }
 
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
 
             OCR = response[1];
             OCR = (OCR << 8) + response[2];
@@ -822,10 +790,10 @@ static rt_err_t rt_msd_init(rt_device_t dev)
             /* try CMD55 + ACMD41 */
             do
             {
-                MSD_take_cs(msd->spi_device);
+                rt_spi_take(msd->spi_device);
                 if (rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41)))
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     MSD_DEBUG("[err] SD Ver2.x or later try CMD55 + ACMD41 timeout!\r\n");
                     result = RT_ERROR;
                     goto _exit;
@@ -836,13 +804,13 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 //                if((result != RT_EOK) || (response[0] == 0x01))
                 if (result != RT_EOK)
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     continue;
                 }
 
                 if ((response[0] & 0xFE) != 0)
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     MSD_DEBUG("[err] Not SD ready!\r\n");
                     result = RT_ERROR;
                     goto _exit;
@@ -852,7 +820,7 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                 result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x40000000, 0x77, response_r1, response);
                 if (result != RT_EOK)
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     MSD_DEBUG("[err] ACMD41 fail!\r\n");
                     result = RT_ERROR;
                     goto _exit;
@@ -860,33 +828,33 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 
                 if ((response[0] & 0xFE) != 0)
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     MSD_DEBUG("[info] Not SD card4 , response : 0x%02X\r\n", response[0]);
 //                    break;
                 }
             }
             while (response[0] != MSD_RESPONSE_NO_ERROR);
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
             /* try CMD55 + ACMD41 */
 
             /* --Read OCR again */
-            MSD_take_cs(msd->spi_device);
+            rt_spi_take(msd->spi_device);
             result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
             if (result != RT_EOK)
             {
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
                 MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to 2nd CMD58!\r\n");
                 goto _exit;
             }
 
             if ((response[0] & 0xFE) != 0)
             {
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
                 MSD_DEBUG("[err] It look 2nd CMD58 as illegal command so it is not SD card!\r\n");
                 result = RT_ERROR;
                 goto _exit;
             }
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
 
             OCR = response[1];
             OCR = (OCR << 8) + response[2];
@@ -933,14 +901,14 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 
     /* set CRC */
     {
-        MSD_release_cs(msd->spi_device);
-        MSD_take_cs(msd->spi_device);
+        rt_spi_release(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 #ifdef MSD_USE_CRC
         result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x01, 0x83, response_r1, response);
 #else
         result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x00, 0x91, response_r1, response);
 #endif
-        MSD_release_cs(msd->spi_device);
+        rt_spi_release(msd->spi_device);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         {
             MSD_DEBUG("[err] CMD59 CRC_ON_OFF fail! response : 0x%02X\r\n", response[0]);
@@ -951,10 +919,10 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 
     /* CMD16 SET_BLOCKLEN */
     {
-        MSD_release_cs(msd->spi_device);
-        MSD_take_cs(msd->spi_device);
+        rt_spi_release(msd->spi_device);
+        rt_spi_take(msd->spi_device);
         result = _send_cmd(msd->spi_device, SET_BLOCKLEN, SECTOR_SIZE, 0x00, response_r1, response);
-        MSD_release_cs(msd->spi_device);
+        rt_spi_release(msd->spi_device);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         {
             MSD_DEBUG("[err] CMD16 SET_BLOCKLEN fail! response : 0x%02X\r\n", response[0]);
@@ -969,27 +937,27 @@ static rt_err_t rt_msd_init(rt_device_t dev)
     {
         uint8_t CSD_buffer[MSD_CSD_LEN];
 
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 //        result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0xAF, response_r1, response);
         result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0x00, response_r1, response);
 
         if (result != RT_EOK)
         {
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
             MSD_DEBUG("[err] CMD9 SEND_CSD timeout!\r\n");
             goto _exit;
         }
 
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         {
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
             MSD_DEBUG("[err] CMD9 SEND_CSD fail! response : 0x%02X\r\n", response[0]);
             result = RT_ERROR;
             goto _exit;
         }
 
         result = _read_block(msd->spi_device, CSD_buffer, MSD_CSD_LEN);
-        MSD_release_cs(msd->spi_device);
+        rt_spi_release(msd->spi_device);
         if (result != RT_EOK)
         {
             MSD_DEBUG("[err] read CSD fail!\r\n");
@@ -1214,12 +1182,11 @@ static rt_err_t rt_msd_init(rt_device_t dev)
         cfg.data_width = 8;
         cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
         cfg.max_hz = msd->max_clock;
-
         rt_spi_configure(msd->spi_device, &cfg);
     } /* config spi */
 
 _exit:
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
     return result;
 }
@@ -1249,20 +1216,10 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
         goto _exit;
     }
 
-    /* config spi to high speed */
-    {
-        struct rt_spi_configuration cfg;
-        cfg.data_width = 8;
-        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
-        cfg.max_hz = msd->max_clock;
-
-        rt_spi_configure(msd->spi_device, &cfg);
-    } /* config spi */
-
     /* SINGLE_BLOCK? */
     if (size == 1)
     {
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
         result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1283,7 +1240,7 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
     {
         uint32_t i;
 
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
         result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1316,7 +1273,7 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
 
 _exit:
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
     return size;
@@ -1335,20 +1292,10 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r
         goto _exit;
     }
 
-    /* config spi to high speed */
-    {
-        struct rt_spi_configuration cfg;
-        cfg.data_width = 8;
-        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
-        cfg.max_hz = msd->max_clock;
-
-        rt_spi_configure(msd->spi_device, &cfg);
-    } /* config spi */
-
     /* SINGLE_BLOCK? */
     if (size == 1)
     {
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
         result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1369,7 +1316,7 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r
     {
         uint32_t i;
 
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
         result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1402,7 +1349,7 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r
 
 _exit:
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
     return size;
@@ -1422,20 +1369,11 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer,
         goto _exit;
     }
 
-    /* config spi to high speed */
-    {
-        struct rt_spi_configuration cfg;
-        cfg.data_width = 8;
-        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
-        cfg.max_hz = msd->max_clock;
-
-        rt_spi_configure(msd->spi_device, &cfg);
-    } /* config spi */
 
     /* SINGLE_BLOCK? */
     if (size == 1)
     {
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
         result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         {
@@ -1456,7 +1394,7 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer,
         struct rt_spi_message message;
         uint32_t i;
 
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
 #ifdef MSD_USE_PRE_ERASED
         if (msd->card_type != MSD_CARD_TYPE_MMC)
@@ -1531,7 +1469,7 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer,
 
 _exit:
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
     return size;
@@ -1550,20 +1488,10 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu
         goto _exit;
     }
 
-    /* config spi to high speed */
-    {
-        struct rt_spi_configuration cfg;
-        cfg.data_width = 8;
-        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
-        cfg.max_hz = msd->max_clock;
-
-        rt_spi_configure(msd->spi_device, &cfg);
-    } /* config spi */
-
     /* SINGLE_BLOCK? */
     if (size == 1)
     {
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
         result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         {
@@ -1584,7 +1512,7 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu
         struct rt_spi_message message;
         uint32_t i;
 
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
 #ifdef MSD_USE_PRE_ERASED
         /* CMD55 APP_CMD */
@@ -1655,7 +1583,7 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu
 
 _exit:
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
     return size;

+ 37 - 3
components/drivers/src/ringblk_buf.c

@@ -18,8 +18,10 @@
  * @param rbb ring block buffer object
  * @param buf buffer
  * @param buf_size buffer size
- * @param block_set
- * @param blk_max_num
+ * @param block_set block set
+ * @param blk_max_num max block number
+ *
+ * @note When your application need align access, please make the buffer address is aligned.
  */
 void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num)
 {
@@ -123,6 +125,8 @@ static rt_rbb_blk_t find_empty_blk_in_set(rt_rbb_t rbb)
  * @param rbb ring block buffer object
  * @param blk_size block size
  *
+ * @note When your application need align access, please make the blk_szie is aligned.
+ *
  * @return != NULL: allocated block
  *            NULL: allocate failed
  */
@@ -133,7 +137,7 @@ rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size)
     rt_rbb_blk_t head, tail, new = NULL;
 
     RT_ASSERT(rbb);
-    RT_ASSERT(blk_size < 1L << 24);
+    RT_ASSERT(blk_size < (1L << 24));
 
     level = rt_hw_interrupt_disable();
 
@@ -277,6 +281,36 @@ __exit:
 }
 RTM_EXPORT(rt_rbb_blk_get);
 
+/**
+ * return the block size
+ *
+ * @param block the block
+ *
+ * @return block size
+ */
+rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block)
+{
+    RT_ASSERT(block);
+
+    return block->size;
+}
+RTM_EXPORT(rt_rbb_blk_size);
+
+/**
+ * return the block buffer
+ *
+ * @param block the block
+ *
+ * @return block buffer
+ */
+rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block)
+{
+    RT_ASSERT(block);
+
+    return block->buf;
+}
+RTM_EXPORT(rt_rbb_blk_buf);
+
 /**
  * free the block
  *

+ 12 - 1
components/drivers/usb/usbdevice/core/core.c

@@ -194,7 +194,18 @@ static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup)
             _get_string_descriptor(device, setup);
             break;
         case USB_DESC_TYPE_DEVICEQUALIFIER:
-            _get_qualifier_descriptor(device, setup);
+            /* If a full-speed only device (with a device descriptor version number equal to 0200H) receives a
+            GetDescriptor() request for a device_qualifier, it must respond with a request error. The host must not make
+            a request for an other_speed_configuration descriptor unless it first successfully retrieves the
+            device_qualifier descriptor. */
+            if(device->dcd->device_is_hs)
+            {
+                _get_qualifier_descriptor(device, setup);
+            }
+            else
+            {
+                rt_usbd_ep0_set_stall(device);
+            }
             break;
         case USB_DESC_TYPE_OTHERSPEED:
             _get_config_descriptor(device, setup);

+ 43 - 28
components/drivers/wlan/wlan_dev.c

@@ -145,7 +145,10 @@ rt_err_t rt_wlan_dev_ap_start(struct rt_wlan_device *device, struct rt_wlan_info
 
     rt_memset(&ap_info, 0, sizeof(struct rt_ap_info));
     rt_memcpy(&ap_info.ssid, &info->ssid, sizeof(rt_wlan_ssid_t));
-    rt_memcpy(ap_info.key.val, password, password_len);
+    if (password != RT_NULL)
+    {
+        rt_memcpy(ap_info.key.val, password, password_len);
+    }
     ap_info.key.len = password_len;
     ap_info.hidden = info->hidden;
     ap_info.channel = info->channel;
@@ -184,13 +187,21 @@ rt_err_t rt_wlan_dev_ap_deauth(struct rt_wlan_device *device, rt_uint8_t mac[6])
 int rt_wlan_dev_get_rssi(struct rt_wlan_device *device)
 {
     int rssi = 0;
+    rt_err_t result = RT_EOK;
 
     if (device == RT_NULL)
     {
-        return -RT_EIO;
+        rt_set_errno(-RT_EIO);
+        return 0;
+    }
+
+    result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_RSSI, &rssi);
+    if (result != RT_EOK)
+    {
+        rt_set_errno(result);
+        return 0;
     }
 
-    rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_RSSI, &rssi);
     return rssi;
 }
 
@@ -235,14 +246,20 @@ rt_err_t rt_wlan_dev_set_powersave(struct rt_wlan_device *device, int level)
 
 int rt_wlan_dev_get_powersave(struct rt_wlan_device *device)
 {
-    int level = 0;
+    int level = -1;
+    rt_err_t result = RT_EOK;
 
     if (device == RT_NULL)
     {
+        rt_set_errno(-RT_EIO);
         return -1;
     }
 
-    rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_POWERSAVE, &level);
+    result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_POWERSAVE, &level);
+    if (result != RT_EOK)
+    {
+        rt_set_errno(result);
+    }
 
     return level;
 }
@@ -432,19 +449,21 @@ rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel)
     return result;
 }
 
-rt_err_t rt_wlan_dev_get_channel(struct rt_wlan_device *device)
+int rt_wlan_dev_get_channel(struct rt_wlan_device *device)
 {
     rt_err_t result = RT_EOK;
-    int channel;
+    int channel = -1;
 
     if (device == RT_NULL)
     {
-        return -RT_EIO;
+        rt_set_errno(-RT_EIO);
+        return -1;
     }
 
     result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_CHANNEL, &channel);
     if (result != RT_EOK)
     {
+        rt_set_errno(result);
         return -1;
     }
 
@@ -466,17 +485,19 @@ rt_err_t rt_wlan_dev_set_country(struct rt_wlan_device *device, rt_country_code_
 
 rt_country_code_t rt_wlan_dev_get_country(struct rt_wlan_device *device)
 {
-    int result = 0;
+    int result = RT_EOK;
     rt_country_code_t country_code = RT_COUNTRY_UNKNOWN;
 
     if (device == RT_NULL)
     {
-        return country_code;
+        rt_set_errno(-RT_EIO);
+        return RT_COUNTRY_UNKNOWN;
     }
 
     result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_COUNTRY, &country_code);
     if (result != RT_EOK)
     {
+        rt_set_errno(result);
         return RT_COUNTRY_UNKNOWN;
     }
 
@@ -641,7 +662,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
 
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_POWERSAVE, "RT_WLAN_CMD_SET_POWERSAVE");
         if (wlan->ops->wlan_set_powersave)
-            wlan->ops->wlan_set_powersave(wlan, level);
+            err = wlan->ops->wlan_set_powersave(wlan, level);
         break;
     }
     case RT_WLAN_CMD_GET_POWERSAVE:
@@ -659,7 +680,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
 
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_PROMISC, "RT_WLAN_CMD_CFG_PROMISC");
         if (wlan->ops->wlan_cfg_promisc)
-            wlan->ops->wlan_cfg_promisc(wlan, start);
+            err = wlan->ops->wlan_cfg_promisc(wlan, start);
         break;
     }
     case RT_WLAN_CMD_CFG_FILTER:
@@ -668,7 +689,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
 
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_FILTER, "RT_WLAN_CMD_CFG_FILTER");
         if (wlan->ops->wlan_cfg_filter)
-            wlan->ops->wlan_cfg_filter(wlan, filter);
+            err = wlan->ops->wlan_cfg_filter(wlan, filter);
         break;
     }
     case RT_WLAN_CMD_SET_CHANNEL:
@@ -676,7 +697,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
         int channel = *(int *)args;
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_CHANNEL, "RT_WLAN_CMD_SET_CHANNEL");
         if (wlan->ops->wlan_set_channel)
-            wlan->ops->wlan_set_channel(wlan, channel);
+            err = wlan->ops->wlan_set_channel(wlan, channel);
         break;
     }
     case RT_WLAN_CMD_GET_CHANNEL:
@@ -694,7 +715,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
 
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_COUNTRY, "RT_WLAN_CMD_SET_COUNTRY");
         if (wlan->ops->wlan_set_country)
-            wlan->ops->wlan_set_country(wlan, country);
+            err = wlan->ops->wlan_set_country(wlan, country);
         break;
     }
     case RT_WLAN_CMD_GET_COUNTRY:
@@ -711,7 +732,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
 
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_MAC, "RT_WLAN_CMD_SET_MAC");
         if (wlan->ops->wlan_set_mac)
-            wlan->ops->wlan_set_mac(wlan, mac);
+            err = wlan->ops->wlan_set_mac(wlan, mac);
         break;
     }
     case RT_WLAN_CMD_GET_MAC:
@@ -720,7 +741,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
 
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_MAC, "RT_WLAN_CMD_GET_MAC");
         if (wlan->ops->wlan_get_mac)
-            wlan->ops->wlan_get_mac(wlan, mac);
+            err = wlan->ops->wlan_get_mac(wlan, mac);
         break;
     }
     default:
@@ -733,22 +754,16 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
     return err;
 }
 
-struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data)
+rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data)
 {
-    struct rt_wlan_device *wlan;
+    rt_err_t err = RT_EOK;
 
-    if (name == RT_NULL || ops == RT_NULL)
+    if ((wlan == RT_NULL) || (name == RT_NULL) || (ops == RT_NULL))
     {
         LOG_E("F:%s L:%d parameter Wrongful", __FUNCTION__, __LINE__);
         return RT_NULL;
     }
 
-    wlan = rt_malloc(sizeof(struct rt_wlan_device));
-    if (wlan == RT_NULL)
-    {
-        LOG_E("F:%s L:%d", __FUNCTION__, __LINE__);
-        return RT_NULL;
-    }
     rt_memset(wlan, 0, sizeof(struct rt_wlan_device));
 
     wlan->device.init       = _rt_wlan_dev_init;
@@ -765,9 +780,9 @@ struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wl
     wlan->user_data  = user_data;
 
     wlan->flags = flag;
-    rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR);
+    err = rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR);
 
     LOG_D("F:%s L:%d run", __FUNCTION__, __LINE__);
 
-    return wlan;
+    return err;
 }

+ 3 - 2
components/drivers/wlan/wlan_dev.h

@@ -559,7 +559,7 @@ rt_err_t rt_wlan_dev_cfg_filter(struct rt_wlan_device *device, struct rt_wlan_fi
  * wlan device channel interface
  */
 rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel);
-rt_err_t rt_wlan_dev_get_channel(struct rt_wlan_device *device);
+int rt_wlan_dev_get_channel(struct rt_wlan_device *device);
 
 /*
  * wlan device country interface
@@ -576,7 +576,8 @@ rt_err_t rt_wlan_dev_report_data(struct rt_wlan_device *device, void *buff, int
 /*
  * wlan device register interface
  */
-struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data);
+rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name, 
+    const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data);
 
 #ifdef __cplusplus
 }

+ 8 - 5
components/drivers/wlan/wlan_mgnt.c

@@ -1320,7 +1320,10 @@ rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password)
         return -RT_EIO;
     }
     RT_WLAN_LOG_D("%s is run", __FUNCTION__);
-    password_len = rt_strlen(password);
+    if (password != RT_NULL)
+    {
+        password_len = rt_strlen(password);
+    }
     if (password_len > RT_WLAN_PASSWORD_MAX_LENGTH)
     {
         RT_WLAN_LOG_E("key is to long! len:%d", password_len);
@@ -1358,16 +1361,16 @@ rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password)
     return err;
 }
 
-int rt_wlan_ap_is_active(void)
+rt_bool_t rt_wlan_ap_is_active(void)
 {
-    int _active = 0;
+    rt_bool_t _active = RT_FALSE;
 
     if (_ap_is_null())
     {
-        return 0;
+        return RT_FALSE;
     }
 
-    _active = _ap_mgnt.state & RT_WLAN_STATE_ACTIVE ? 1 : 0;
+    _active = _ap_mgnt.state & RT_WLAN_STATE_ACTIVE ? RT_TRUE : RT_FALSE;
     RT_WLAN_LOG_D("%s is run active:%s", __FUNCTION__, _active ? "Active" : "Inactive");
     return _active;
 }

+ 1 - 1
components/drivers/wlan/wlan_mgnt.h

@@ -97,7 +97,7 @@ int rt_wlan_get_rssi(void);
  */
 rt_err_t rt_wlan_start_ap(const char *ssid, const char *password);
 rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password);
-int rt_wlan_ap_is_active(void);
+rt_bool_t rt_wlan_ap_is_active(void);
 rt_err_t rt_wlan_ap_stop(void);
 rt_err_t rt_wlan_ap_get_info(struct rt_wlan_info *info);
 int rt_wlan_ap_get_sta_num(void);

+ 1 - 1
components/finsh/cmd.c

@@ -199,7 +199,7 @@ long list_sem(void)
 
     return _list_sem(&info->object_list);
 }
-FINSH_FUNCTION_EXPORT(list_sem, list semaphone in system);
+FINSH_FUNCTION_EXPORT(list_sem, list semaphore in system);
 MSH_CMD_EXPORT(list_sem, list semaphore in system);
 #endif
 

+ 0 - 15
components/libc/compilers/dlib/sys/errno.h

@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date           Author       Notes
- */
-#ifndef SYS_ERRNO_H__
-#define SYS_ERRNO_H__
-
-#include <rtthread.h>
-
-
-#endif

+ 5 - 0
components/net/Kconfig

@@ -21,6 +21,11 @@ config RT_USING_SAL
                     bool "Support AT Commands stack"
                     default y
                     depends on AT_USING_SOCKET
+                    
+                config SAL_USING_TLS
+                    bool "Support MbedTLS protocol"
+                    default y
+                    depends on PKG_USING_MBEDTLS
             endmenu
         
         endif

+ 12 - 9
components/net/at/at_socket/at_socket.c

@@ -622,8 +622,20 @@ int at_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *f
             goto __exit;
         }
         sock->state = AT_SOCKET_CONNECT;
+        /* set AT socket receive data callback function */
+        at_dev_ops->at_set_event_cb(AT_SOCKET_EVT_RECV, at_recv_notice_cb);
+        at_dev_ops->at_set_event_cb(AT_SOCKET_EVT_CLOSED, at_closed_notice_cb);
     }
 
+    /* receive packet list last transmission of remaining data */
+    rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER);
+    if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0)
+    {
+        rt_mutex_release(sock->recv_lock);
+        goto __exit;
+    }
+    rt_mutex_release(sock->recv_lock);
+        
     /* socket passively closed, receive function return 0 */
     if (sock->state == AT_SOCKET_CLOSED)
     {
@@ -637,15 +649,6 @@ int at_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *f
         goto __exit;
     }
 
-    /* receive packet list last transmission of remaining data */
-    rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER);
-    if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0)
-    {
-        rt_mutex_release(sock->recv_lock);
-        goto __exit;
-    }
-    rt_mutex_release(sock->recv_lock);
-
     /* non-blocking sockets receive data */
     if (flags & MSG_DONTWAIT)
     {

+ 4 - 1
components/net/sal_socket/SConscript

@@ -15,10 +15,13 @@ if GetDepend('SAL_USING_LWIP'):
 
 if GetDepend('SAL_USING_AT'):
     src += Glob('impl/af_inet_at.c')
-    
+
 if GetDepend('SAL_USING_LWIP') or GetDepend('SAL_USING_AT'):
     CPPPATH += [cwd + '/impl']
 
+if GetDepend('SAL_USING_TLS'):
+    src += Glob('impl/proto_mbedtls.c')
+
 if GetDepend('SAL_USING_POSIX'):
     CPPPATH += [cwd + '/include/dfs_net']
     src += Glob('socket/net_sockets.c')

+ 14 - 9
components/net/sal_socket/impl/af_inet_at.c

@@ -62,7 +62,7 @@ static int at_poll(struct dfs_fd *file, struct rt_pollreq *req)
 }
 #endif
 
-static const struct proto_ops at_inet_stream_ops =
+static const struct sal_socket_ops at_socket_ops =
 {
     at_socket,
     at_closesocket,
@@ -90,25 +90,30 @@ static int at_create(struct sal_socket *socket, int type, int protocol)
 
     //TODO Check type & protocol
 
-    socket->ops = &at_inet_stream_ops;
+    socket->ops = &at_socket_ops;
 
     return 0;
 }
 
-static const struct proto_family at_inet_family_ops = {
-    "at",
-    AF_AT,
-    AF_INET,
-    at_create,
+static struct sal_proto_ops at_proto_ops =
+{
     at_gethostbyname,
     NULL,
-    at_freeaddrinfo,
     at_getaddrinfo,
+    at_freeaddrinfo,
+};
+
+static const struct sal_proto_family at_inet_family =
+{
+    AF_AT,
+    AF_INET,
+    at_create,
+    &at_proto_ops,
 };
 
 int at_inet_init(void)
 {
-    sal_proto_family_register(&at_inet_family_ops);
+    sal_proto_family_register(&at_inet_family);
 
     return 0;
 }

+ 15 - 9
components/net/sal_socket/impl/af_inet_lwip.c

@@ -259,7 +259,8 @@ static int inet_poll(struct dfs_fd *file, struct rt_pollreq *req)
 }
 #endif
 
-static const struct proto_ops lwip_inet_stream_ops = {
+static const struct sal_socket_ops lwip_socket_ops =
+{
     inet_socket,
     lwip_close,
     lwip_bind,
@@ -286,25 +287,30 @@ static int inet_create(struct sal_socket *socket, int type, int protocol)
 
     //TODO Check type & protocol
 
-    socket->ops = &lwip_inet_stream_ops;
+    socket->ops = &lwip_socket_ops;
 
     return 0;
 }
 
-static const struct proto_family lwip_inet_family_ops = {
-    "lwip",
-    AF_INET,
-    AF_INET,
-    inet_create,
+static struct sal_proto_ops lwip_proto_ops =
+{
     lwip_gethostbyname,
     lwip_gethostbyname_r,
-    lwip_freeaddrinfo,
     lwip_getaddrinfo,
+    lwip_freeaddrinfo,
+};
+
+static const struct sal_proto_family lwip_inet_family =
+{
+    AF_INET,
+    AF_INET,
+    inet_create,
+    &lwip_proto_ops,
 };
 
 int lwip_inet_init(void)
 {
-    sal_proto_family_register(&lwip_inet_family_ops);
+    sal_proto_family_register(&lwip_inet_family);
 
     return 0;
 }

+ 239 - 0
components/net/sal_socket/impl/proto_mbedtls.c

@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-12     ChenYong     First version
+ */
+
+#include <rtthread.h>
+
+#ifdef RT_USING_DFS
+#include <dfs_posix.h>
+#endif
+
+#ifdef SAL_USING_TLS
+#include <sal_tls.h>
+#endif
+#include <netdb.h>
+#include <sal.h>
+
+#ifdef SAL_USING_TLS
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include <mbedtls/config.h>
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include <tls_certificate.h>
+#include <tls_client.h>
+
+#ifndef SAL_MEBDTLS_BUFFER_LEN
+#define SAL_MEBDTLS_BUFFER_LEN         1024
+#endif
+
+static void *mebdtls_socket(int socket)
+{
+    MbedTLSSession *session = RT_NULL;
+    char *pers = "mbedtls";
+
+    if (socket < 0)
+    {
+        return RT_NULL;
+    }
+
+    session = (MbedTLSSession *) tls_calloc(1, sizeof(MbedTLSSession));
+    if (session == RT_NULL)
+    {
+        return RT_NULL;
+    }
+
+    session->buffer_len = SAL_MEBDTLS_BUFFER_LEN;
+    session->buffer = tls_calloc(1, session->buffer_len);
+    if (session->buffer == RT_NULL)
+    {
+        tls_free(session);
+        session = RT_NULL;
+        
+        return RT_NULL;
+    }
+
+    /* initialize TLS Client sesison */
+    if (mbedtls_client_init(session, (void *) pers, rt_strlen(pers)) != RT_EOK)
+    {
+        mbedtls_client_close(session);
+        return RT_NULL;
+    }  
+    session->server_fd.fd = socket;
+
+    return (void *)session;
+}
+
+int mbedtls_net_send_cb(void *ctx, const unsigned char *buf, size_t len)
+{
+    struct sal_socket *sock;
+    int socket, ret;
+
+    RT_ASSERT(ctx);
+    RT_ASSERT(buf);
+
+    socket = ((mbedtls_net_context *) ctx)->fd;
+    sock = sal_get_socket(socket);
+    if (sock == RT_NULL)
+    {
+        return -1;
+    }
+
+    /* Register scoket sendto option to TLS send data callback */
+    ret = sock->ops->sendto((int) sock->user_data, (void *)buf, len, 0, RT_NULL, RT_NULL);
+    if (ret < 0)
+    {
+#ifdef RT_USING_DFS
+        if ((fcntl(socket, F_GETFL) & O_NONBLOCK) == O_NONBLOCK)
+            return MBEDTLS_ERR_SSL_WANT_WRITE;
+#endif
+        if (errno == ECONNRESET)
+            return MBEDTLS_ERR_NET_CONN_RESET;
+        if ( errno == EINTR)
+            return MBEDTLS_ERR_SSL_WANT_READ;
+
+        return MBEDTLS_ERR_NET_SEND_FAILED ;
+    }
+
+    return ret;
+}
+
+int mbedtls_net_recv_cb( void *ctx, unsigned char *buf, size_t len)
+{
+    struct sal_socket *sock;
+    int socket, ret;
+
+    RT_ASSERT(ctx);
+    RT_ASSERT(buf);
+
+    socket = ((mbedtls_net_context *) ctx)->fd;
+    sock = sal_get_socket(socket);
+    if (sock == RT_NULL)
+    {
+        return -1;
+    }
+
+    /* Register scoket recvfrom option to TLS recv data callback */
+    ret = sock->ops->recvfrom((int) sock->user_data, (void *)buf, len, 0, RT_NULL, RT_NULL);
+    if (ret < 0)
+    {
+#ifdef RT_USING_DFS
+        if ((fcntl(socket, F_GETFL) & O_NONBLOCK) == O_NONBLOCK)
+            return MBEDTLS_ERR_SSL_WANT_WRITE;
+#endif
+        if (errno == ECONNRESET)
+            return MBEDTLS_ERR_NET_CONN_RESET;
+        if ( errno == EINTR)
+            return MBEDTLS_ERR_SSL_WANT_READ;
+
+        return MBEDTLS_ERR_NET_RECV_FAILED ;
+    }
+
+    return ret;
+}
+
+static int mbedtls_connect(void *sock)
+{
+    MbedTLSSession *session = RT_NULL;
+    int ret = 0;
+
+    RT_ASSERT(sock);
+
+    session = (MbedTLSSession *) sock;
+
+    /* Set the SSL Configure infromation */
+    ret = mbedtls_client_context(session);
+    if (ret < 0)
+    {
+        goto __exit;
+    }
+
+    /* Set the underlying BIO callbacks for write, read and read-with-timeout.  */
+    mbedtls_ssl_set_bio(&session->ssl, &session->server_fd, mbedtls_net_send_cb, mbedtls_net_recv_cb, RT_NULL);
+
+    while ((ret = mbedtls_ssl_handshake(&session->ssl)) != 0)
+    {
+        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+        {
+            goto __exit;
+        }
+    }
+
+    /* Return the result of the certificate verification */
+    ret = mbedtls_ssl_get_verify_result(&session->ssl);
+    if (ret != 0)
+    {
+        rt_memset(session->buffer, 0x00, session->buffer_len);
+        mbedtls_x509_crt_verify_info((char *)session->buffer, session->buffer_len, "  ! ", ret);
+        goto __exit;
+    }
+    
+    return ret;
+
+__exit:
+    if (session)
+    {
+        mbedtls_client_close(session);
+    }
+
+    return ret;
+}
+
+static int mbedtls_closesocket(void *sock)
+{
+    struct sal_socket *ssock;
+    int socket;
+    
+    if (sock == RT_NULL)
+    {
+        return 0;
+    }
+    
+    socket = ((MbedTLSSession *) sock)->server_fd.fd;
+    ssock = sal_get_socket(socket);
+    if (ssock == RT_NULL)
+    {
+        return -1;
+    }
+    
+    /* Close TLS client session, and clean user-data in SAL socket */
+    mbedtls_client_close((MbedTLSSession *) sock);
+    ssock->user_data_tls = RT_NULL;
+    
+    return 0;
+}
+
+static const struct sal_proto_tls_ops mbedtls_proto_ops= 
+{
+    RT_NULL,
+    mebdtls_socket,
+    mbedtls_connect,
+    (int (*)(void *sock, const void *data, size_t size)) mbedtls_client_write,
+    (int (*)(void *sock, void *mem, size_t len)) mbedtls_client_read,
+    mbedtls_closesocket,
+};
+
+static const struct sal_proto_tls mbedtls_proto =
+{
+    "mbedtls",
+    &mbedtls_proto_ops,
+};
+
+int sal_mbedtls_proto_init(void)
+{
+    /* register MbedTLS protocol options to SAL */
+    sal_proto_tls_register(&mbedtls_proto);
+
+    return 0;
+}
+INIT_COMPONENT_EXPORT(sal_mbedtls_proto_init);
+
+#endif /* SAL_USING_TLS */

+ 27 - 18
components/net/sal_socket/include/sal.h

@@ -25,7 +25,7 @@ extern "C" {
 typedef uint32_t socklen_t;
 #endif
 
-/* sal socket magic word */
+/* SAL socket magic word */
 #define SAL_SOCKET_MAGIC               0x5A10
 
 /* The maximum number of sockets structure */
@@ -38,12 +38,12 @@ typedef uint32_t socklen_t;
 #define SAL_PROTO_FAMILIES_NUM         4
 #endif
 
-/* sal socket offset */
+/* SAL socket offset */
 #ifndef SAL_SOCKET_OFFSET
 #define SAL_SOCKET_OFFSET              0
 #endif
 
-struct proto_ops
+struct sal_socket_ops
 {
     int (*socket)     (int domain, int type, int protocol);
     int (*closesocket)(int s);
@@ -64,30 +64,38 @@ struct proto_ops
 #endif
 };
 
+struct sal_proto_ops
+{
+    struct hostent* (*gethostbyname)  (const char *name);
+    int             (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
+    int             (*getaddrinfo)    (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
+    void            (*freeaddrinfo)   (struct addrinfo *ai);
+};
+
 struct sal_socket
 {
-    uint32_t magic;                    /* sal socket magic word */
+    uint32_t magic;                    /* SAL socket magic word */
 
-    int socket;                        /* sal socket descriptor */
+    int socket;                        /* SAL socket descriptor */
     int domain;
     int type;
     int protocol;
 
-    const struct proto_ops  *ops;      /* socket options */
-    void *user_data;                   /* specific sal socket data */
+    const struct sal_socket_ops *ops;  /* socket options */
+
+    void *user_data;                   /* user-specific data */
+#ifdef SAL_USING_TLS
+    void *user_data_tls;               /* user-specific TLS data */
+#endif
 };
 
-struct proto_family
+struct sal_proto_family
 {
-    char name[RT_NAME_MAX];
     int family;                        /* primary protocol families type */
     int sec_family;                    /* secondary protocol families type */
-    int             (*create)(struct sal_socket *sal_socket, int type, int protocol);   /* register socket options */
+    int (*create)(struct sal_socket *sal_socket, int type, int protocol);   /* register socket options */
 
-    struct hostent* (*gethostbyname)  (const char *name);
-    int             (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
-    void            (*freeaddrinfo)   (struct addrinfo *ai);
-    int             (*getaddrinfo)    (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
+    struct sal_proto_ops *ops;             /* protocol family options */
 };
 
 /* SAL(Socket Abstraction Layer) initialize */
@@ -95,10 +103,11 @@ int sal_init(void);
 
 struct sal_socket *sal_get_socket(int sock);
 
-/* protocol family register and unregister operate */
-int sal_proto_family_register(const struct proto_family *pf);
-int sal_proto_family_unregister(const struct proto_family *pf);
-struct proto_family *sal_proto_family_find(const char *name);
+/* SAL protocol family register and unregister operate */
+int sal_proto_family_register(const struct sal_proto_family *pf);
+int sal_proto_family_unregister(int family);
+rt_bool_t sal_proto_family_is_registered(int family);
+struct sal_proto_family *sal_proto_family_find(int family);
 
 #ifdef __cplusplus
 }

+ 68 - 0
components/net/sal_socket/include/sal_tls.h

@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-10     ChenYong     First version
+ */
+#ifndef __SAL_TLS_H__
+#define __SAL_TLS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtthread.h>
+
+/* Protocol level for TLS.
+ * Here, the same socket protocol level for TLS as in Linux was used.
+ */
+#define SOL_TLS             282
+
+/* Socket options for TLS */
+
+/* Socket option to select TLS credentials to use. */
+#define TLS_CRET_LIST        1
+/* Socket option to set select ciphersuites to use. */
+#define TLS_CIPHERSUITE_LIST 2
+/* Socket option to set peer verification level for TLS connection. */
+#define TLS_PEER_VERIFY      3
+/* Socket option to set role for DTLS connection. */
+#define TLS_DTLS_ROLE        4
+
+/* Protocol numbers for TLS protocols */
+#define PROTOCOL_TLS         256
+#define PROTOCOL_DTLS        257
+
+
+struct sal_proto_tls_ops
+{
+    int (*init)(void);
+    void* (*socket)(int socket);
+    int (*connect)(void *sock);
+    int (*send)(void *sock, const void *data, size_t size);
+    int (*recv)(void *sock, void *mem, size_t len);
+    int (*closesocket)(void *sock);
+
+    int (*set_cret_list)(void *sock, const void *cert, size_t size);              /* Set TLS credentials */
+    int (*set_ciphersurite)(void *sock, const void* ciphersurite, size_t size);   /* Set select ciphersuites */
+    int (*set_peer_verify)(void *sock, const void* peer_verify, size_t size);     /* Set peer verification */
+    int (*set_dtls_role)(void *sock, const void *dtls_role, size_t size);         /* Set role for DTLS */
+};
+
+struct sal_proto_tls
+{
+    char name[RT_NAME_MAX];                      /* TLS protocol name */
+    const struct sal_proto_tls_ops *ops;         /* SAL TLS protocol options */
+};
+
+/* SAL TLS protocol register */
+int sal_proto_tls_register(const struct sal_proto_tls *pt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SAL_TLS_H__ */

+ 3 - 0
components/net/sal_socket/include/socket/sys_socket/sys/socket.h

@@ -14,6 +14,9 @@
 
 #include <rtthread.h>
 #include <sal_socket.h>
+#ifdef SAL_USING_TLS
+#include <sal_tls.h>
+#endif
 
 #ifdef __cplusplus
 extern "C" {

+ 224 - 46
components/net/sal_socket/src/sal_socket.c

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2018-05-23     ChenYong     First version
+ * 2018-11-12     ChenYong     Add TLS support
  */
 
 #include <rtthread.h>
@@ -13,6 +14,9 @@
 
 #include <sal_socket.h>
 #include <sal_netdb.h>
+#ifdef SAL_USING_TLS
+#include <sal_tls.h>
+#endif
 #include <sal.h>
 
 #define DBG_ENABLE
@@ -30,13 +34,32 @@ struct sal_socket_table
     struct sal_socket **sockets;
 };
 
+#ifdef SAL_USING_TLS
+/* The global TLS protocol options */
+static struct sal_proto_tls *proto_tls;
+#endif
+
 /* The global array of available protocol families */
-static struct proto_family proto_families[SAL_PROTO_FAMILIES_NUM];
+static struct sal_proto_family proto_families[SAL_PROTO_FAMILIES_NUM];
 /* The global socket table */
 static struct sal_socket_table socket_table;
 static struct rt_mutex sal_core_lock;
 static rt_bool_t init_ok = RT_FALSE;
 
+#define IS_SOCKET_PROTO_TLS(sock)                (((sock)->protocol == PROTOCOL_TLS) || \
+                                                 ((sock)->protocol == PROTOCOL_DTLS))
+#define SAL_SOCKOPS_PROTO_TLS_VALID(sock, name)  (proto_tls && (proto_tls->ops->name) && IS_SOCKET_PROTO_TLS(sock))
+
+#define SAL_SOCKOPT_PROTO_TLS_EXEC(sock, name, optval, optlen)                    \
+do                                                                                \
+{                                                                                 \
+    if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, name))                                  \
+    {                                                                             \
+        return proto_tls->ops->name((sock)->user_data_tls, (optval), (optlen));   \
+    }                                                                             \
+}while(0)                                                                         \
+
+
 /**
  * SAL (Socket Abstraction Layer) initialize.
  *
@@ -47,7 +70,7 @@ int sal_init(void)
 {
     int cn;
     
-    if(init_ok)
+    if (init_ok)
     {
         LOG_D("Socket Abstraction Layer is already initialized.");
         return 0;
@@ -73,15 +96,32 @@ int sal_init(void)
 }
 INIT_COMPONENT_EXPORT(sal_init);
 
+/**
+ * This function will register TLS protocol to the global TLS protocol.
+ *
+ * @param pt TLS protocol object
+ *
+ * @return 0: TLS protocol object register success
+ */
+#ifdef SAL_USING_TLS
+int sal_proto_tls_register(const struct sal_proto_tls *pt)
+{
+    RT_ASSERT(pt);
+    proto_tls = (struct sal_proto_tls *) pt;
+
+    return 0;
+}
+#endif
+
 /**
  * This function will register protocol family to the global array of protocol families.
  *
  * @param pf protocol family object
  *
- * @return   0 : protocol family object register success
- *          -1 : the global array of available protocol families is full
+ * @return  0: protocol family object register success
+ *         -1: the global array of available protocol families is full
  */
-int sal_proto_family_register(const struct proto_family *pf)
+int sal_proto_family_register(const struct sal_proto_family *pf)
 {
     rt_base_t level;
     int idx;
@@ -92,11 +132,11 @@ int sal_proto_family_register(const struct proto_family *pf)
     /* check protocol family is already registered */
     for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
     {
-        if(rt_strcmp(proto_families[idx].name, pf->name) == 0)
+        if (proto_families[idx].family == pf->family && proto_families[idx].create)
         {
             /* enable interrupt */
             rt_hw_interrupt_enable(level);
-            LOG_E("%s protocol family is already registered!", pf->name);
+            LOG_E("%s protocol family is already registered!", pf->family);
             return -1;
         }
     }
@@ -105,22 +145,22 @@ int sal_proto_family_register(const struct proto_family *pf)
     for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM && proto_families[idx].create; idx++);
 
     /* can't find an empty protocol family entry */
-    if(idx == SAL_PROTO_FAMILIES_NUM)
+    if (idx == SAL_PROTO_FAMILIES_NUM)
     {
         /* enable interrupt */
         rt_hw_interrupt_enable(level);
         return -1;
     }
 
-    rt_strncpy(proto_families[idx].name, pf->name, rt_strlen(pf->name));
     proto_families[idx].family = pf->family;
     proto_families[idx].sec_family = pf->sec_family;
     proto_families[idx].create = pf->create;
 
-    proto_families[idx].gethostbyname = pf->gethostbyname;
-    proto_families[idx].gethostbyname_r = pf->gethostbyname_r;
-    proto_families[idx].freeaddrinfo = pf->freeaddrinfo;
-    proto_families[idx].getaddrinfo = pf->getaddrinfo;
+    proto_families[idx].ops = pf->ops;
+    proto_families[idx].ops->gethostbyname = pf->ops->gethostbyname;
+    proto_families[idx].ops->gethostbyname_r = pf->ops->gethostbyname_r;
+    proto_families[idx].ops->freeaddrinfo = pf->ops->freeaddrinfo;
+    proto_families[idx].ops->getaddrinfo = pf->ops->getaddrinfo;
 
     /* enable interrupt */
     rt_hw_interrupt_enable(level);
@@ -136,17 +176,17 @@ int sal_proto_family_register(const struct proto_family *pf)
  * @return >=0 : unregister protocol family index
  *          -1 : unregister failed
  */
-int sal_proto_family_unregister(const struct proto_family *pf)
+int sal_proto_family_unregister(int family)
 {
     int idx = 0;
 
-    RT_ASSERT(pf != RT_NULL);
+    RT_ASSERT(family > 0 && family < AF_MAX);
 
     for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
     {
-        if(rt_strcmp(proto_families[idx].name, pf->name) == 0)
+        if (proto_families[idx].family == family && proto_families[idx].create)
         {
-            rt_memset(&proto_families[idx], 0x00, sizeof(struct proto_family));
+            rt_memset(&proto_families[idx], 0x00, sizeof(struct sal_proto_family));
 
             return idx;
         }
@@ -156,21 +196,46 @@ int sal_proto_family_unregister(const struct proto_family *pf)
 }
 
 /**
- * This function will get protocol family by name.
+ * This function will judge whether protocol family is registered
  *
- * @param name protocol family name
+ * @param family protocol family number
+ *
+ * @return 1: protocol family is registered
+ *         0: protocol family is not registered
+ */
+rt_bool_t sal_proto_family_is_registered(int family)
+{
+    int idx = 0;
+
+    RT_ASSERT(family > 0 && family < AF_MAX);
+
+    for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
+    {
+        if (proto_families[idx].family == family && proto_families[idx].create)
+        {
+            return RT_TRUE;
+        }
+    }
+
+    return RT_FALSE;
+}
+
+/**
+ * This function will get protocol family object by family number.
+ *
+ * @param family protocol family number
  *
  * @return protocol family object
  */
-struct proto_family *sal_proto_family_find(const char *name)
+struct sal_proto_family *sal_proto_family_find(int family)
 {
     int idx = 0;
 
-    RT_ASSERT(name != RT_NULL);
+    RT_ASSERT(family > 0 && family < AF_MAX);
 
     for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
     {
-        if (rt_strcmp(proto_families[idx].name, name) == 0)
+        if (proto_families[idx].family == family && proto_families[idx].create)
         {
             return &proto_families[idx];
         }
@@ -238,7 +303,7 @@ static void sal_unlock(void)
  *
  * @return protocol family structure address
  */
-static struct proto_family *get_proto_family(int family)
+static struct sal_proto_family *get_proto_family(int family)
 {
     int idx;
 
@@ -278,7 +343,7 @@ static struct proto_family *get_proto_family(int family)
 static int socket_init(int family, int type, int protocol, struct sal_socket **res)
 {
     struct sal_socket *sock;
-    struct proto_family *pf;
+    struct sal_proto_family *pf;
 
     if (family < 0 || family > AF_MAX)
     {
@@ -383,6 +448,11 @@ static int socket_new(void)
     sock = st->sockets[idx];
     sock->socket = idx + SAL_SOCKET_OFFSET;
     sock->magic = SAL_SOCKET_MAGIC;
+    sock->ops = RT_NULL;
+    sock->user_data = RT_NULL;
+#ifdef SAL_USING_TLS
+    sock->user_data_tls = RT_NULL;
+#endif
 
 __result:
     sal_unlock();
@@ -474,6 +544,15 @@ int sal_shutdown(int socket, int how)
 
     if (sock->ops->shutdown((int) sock->user_data, how) == 0)
     {
+#ifdef SAL_USING_TLS
+        if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket))
+        {
+            if (proto_tls->ops->closesocket(sock->user_data_tls) < 0)
+            {
+                return -1;
+            }
+        }
+#endif
         rt_free(sock);
         socket_table.sockets[socket] = RT_NULL;
         return 0;
@@ -551,12 +630,46 @@ int sal_setsockopt(int socket, int level, int optname, const void *optval, sockl
         return -RT_ENOSYS;
     }
 
+#ifdef SAL_USING_TLS
+    if (level == SOL_TLS)
+    {
+        switch (optname)
+        {
+        case TLS_CRET_LIST:
+            SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_cret_list, optval, optlen);
+            break;
+
+        case TLS_CIPHERSUITE_LIST:
+            SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_ciphersurite, optval, optlen);
+            break;
+
+        case TLS_PEER_VERIFY:
+            SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_peer_verify, optval, optlen);
+            break;
+
+        case TLS_DTLS_ROLE:
+            SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_dtls_role, optval, optlen);
+            break;
+
+        default:
+            return -1;
+        }
+
+        return 0;
+    }
+    else
+    {
+        return sock->ops->setsockopt((int) sock->user_data, level, optname, optval, optlen);
+    }
+#else
     return sock->ops->setsockopt((int) sock->user_data, level, optname, optval, optlen);
+#endif /* SAL_USING_TLS */
 }
 
 int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
 {
     struct sal_socket *sock;
+    int ret;
 
     sock = sal_get_socket(socket);
     if (!sock)
@@ -569,7 +682,20 @@ int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
         return -RT_ENOSYS;
     }
 
-    return sock->ops->connect((int) sock->user_data, name, namelen);
+    ret = sock->ops->connect((int) sock->user_data, name, namelen);
+#ifdef SAL_USING_TLS
+    if (ret >= 0 && SAL_SOCKOPS_PROTO_TLS_VALID(sock, connect))
+    {
+        if (proto_tls->ops->connect(sock->user_data_tls) < 0)
+        {
+            return -1;
+        }
+        
+        return ret;
+    }
+#endif
+
+    return ret;
 }
 
 int sal_listen(int socket, int backlog)
@@ -606,7 +732,24 @@ int sal_recvfrom(int socket, void *mem, size_t len, int flags,
         return -RT_ENOSYS;
     }
 
+#ifdef SAL_USING_TLS
+    if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, recv))
+    {
+        int ret;
+        
+        if ((ret = proto_tls->ops->recv(sock->user_data_tls, mem, len)) < 0)
+        {
+            return -1;
+        }   
+        return ret;
+    }
+    else
+    {
+        return sock->ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen);
+    }
+#else
     return sock->ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen);
+#endif
 }
 
 int sal_sendto(int socket, const void *dataptr, size_t size, int flags,
@@ -625,7 +768,24 @@ int sal_sendto(int socket, const void *dataptr, size_t size, int flags,
         return -RT_ENOSYS;
     }
 
+#ifdef SAL_USING_TLS
+    if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, send))
+    {
+        int ret;
+        
+        if ((ret = proto_tls->ops->send(sock->user_data_tls, dataptr, size)) < 0)
+        {
+            return -1;
+        }      
+        return ret;
+    }
+    else
+    {
+        return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen);
+    }
+#else
     return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen);
+#endif
 }
 
 int sal_socket(int domain, int type, int protocol)
@@ -657,8 +817,17 @@ int sal_socket(int domain, int type, int protocol)
     proto_socket = sock->ops->socket(domain, type, protocol);
     if (proto_socket >= 0)
     {
+#ifdef SAL_USING_TLS
+        if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, socket))
+        {
+            sock->user_data_tls = proto_tls->ops->socket(proto_socket);
+            if (sock->user_data_tls == RT_NULL)
+            {
+                return -1;
+            }
+        }
+#endif
         sock->user_data = (void *) proto_socket;
-
         return sock->socket;
     }
 
@@ -682,6 +851,15 @@ int sal_closesocket(int socket)
 
     if (sock->ops->closesocket((int) sock->user_data) == 0)
     {
+#ifdef SAL_USING_TLS
+        if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket))
+        {
+            if (proto_tls->ops->closesocket(sock->user_data_tls) < 0)
+            {
+                return -1;
+            }
+        }
+#endif
         rt_free(sock);        
         socket_table.sockets[socket] = RT_NULL;
         return 0;
@@ -736,9 +914,9 @@ struct hostent *sal_gethostbyname(const char *name)
 
     for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
     {
-        if (proto_families[i].gethostbyname)
+        if (proto_families[i].ops && proto_families[i].ops->gethostbyname)
         {
-            hst = proto_families[i].gethostbyname(name);
+            hst = proto_families[i].ops->gethostbyname(name);
             if (hst != RT_NULL)
             {
                 return hst;
@@ -756,9 +934,9 @@ int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
 
     for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
     {
-        if (proto_families[i].gethostbyname_r)
+        if (proto_families[i].ops && proto_families[i].ops->gethostbyname_r)
         {
-            res = proto_families[i].gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
+            res = proto_families[i].ops->gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
             if (res == 0)
             {
                 return res;
@@ -769,20 +947,6 @@ int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
     return -1;
 }
 
-void sal_freeaddrinfo(struct addrinfo *ai)
-{
-    int i;
-
-    for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
-    {
-        if (proto_families[i].freeaddrinfo)
-        {
-            proto_families[i].freeaddrinfo(ai);
-            return;
-        }
-    }
-}
-
 int sal_getaddrinfo(const char *nodename,
        const char *servname,
        const struct addrinfo *hints,
@@ -792,9 +956,9 @@ int sal_getaddrinfo(const char *nodename,
 
     for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
     {
-        if (proto_families[i].getaddrinfo)
+        if (proto_families[i].ops && proto_families[i].ops->getaddrinfo)
         {
-            ret = proto_families[i].getaddrinfo(nodename, servname, hints, res);
+            ret = proto_families[i].ops->getaddrinfo(nodename, servname, hints, res);
             if (ret == 0)
             {
                 return ret;
@@ -804,3 +968,17 @@ int sal_getaddrinfo(const char *nodename,
 
     return -1;
 }
+
+void sal_freeaddrinfo(struct addrinfo *ai)
+{
+    int i;
+
+    for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
+    {
+        if (proto_families[i].ops && proto_families[i].ops->freeaddrinfo)
+        {
+            proto_families[i].ops->freeaddrinfo(ai);
+            return;
+        }
+    }
+}

+ 4 - 0
components/utilities/Kconfig

@@ -230,4 +230,8 @@ config RT_USING_ULOG
                 sfotware module version number
     endif
 
+config RT_USING_UTEST
+    bool "Enable utest (RT-Thread test framework)"
+    default n
+
 endmenu

+ 1 - 0
components/utilities/ulog/ulog.h

@@ -45,6 +45,7 @@ void ulog_deinit(void);
 #define LOG_I(...)                     ulog_i(LOG_TAG, __VA_ARGS__)
 #define LOG_D(...)                     ulog_d(LOG_TAG, __VA_ARGS__)
 #define LOG_RAW(...)                   ulog_raw(__VA_ARGS__)
+#define LOG_HEX(name, width, buf, size)      ulog_hex(name, width, buf, size)
 
 /*
  * backend register and unregister

+ 7 - 0
components/utilities/ulog/ulog_def.h

@@ -94,6 +94,12 @@ extern "C" {
     #define ulog_e(TAG, ...)
 #endif /* (LOG_LVL >= LOG_LVL_ERROR) && (ULOG_OUTPUT_LVL >= LOG_LVL_ERROR) */
 
+#if (LOG_LVL >= LOG_LVL_DBG) && (ULOG_OUTPUT_LVL >= LOG_LVL_DBG)
+    #define ulog_hex(TAG, width, buf, size)     ulog_hexdump(TAG, width, buf, size)
+#else
+    #define ulog_hex(TAG, width, buf, size)
+#endif /* (LOG_LVL >= LOG_LVL_DBG) && (ULOG_OUTPUT_LVL >= LOG_LVL_DBG) */    
+    
 /* assert for developer. */
 #ifdef ULOG_ASSERT_ENABLE
     #define ULOG_ASSERT(EXPR)                                                 \
@@ -132,6 +138,7 @@ extern "C" {
 #define log_d                          LOG_D
 #define log_v                          LOG_D
 #define log_raw                        LOG_RAW
+#define log_hex                        LOG_HEX    
 #define ELOG_LVL_ASSERT                LOG_LVL_ASSERT
 #define ELOG_LVL_ERROR                 LOG_LVL_ERROR
 #define ELOG_LVL_WARN                  LOG_LVL_WARNING

+ 8 - 0
components/utilities/utest/SConscript

@@ -0,0 +1,8 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+CPPPATH = [cwd]
+group   = DefineGroup('utest', src, depend = ['RT_USING_UTEST'], CPPPATH = CPPPATH)
+
+Return('group')

+ 238 - 0
components/utilities/utest/utest.c

@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-19     MurphyZhao   the first version
+ */
+
+#include "utest.h"
+#include <rtthread.h>
+#include <finsh.h>
+
+#undef DBG_SECTION_NAME
+#undef DBG_LEVEL
+#undef DBG_COLOR
+#undef DBG_ENABLE
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME          "utest"
+#ifdef UTEST_DEBUG
+#define DBG_LEVEL                 DBG_LOG
+#else
+#define DBG_LEVEL                 DBG_INFO
+#endif
+#define DBG_COLOR
+#include <rtdbg.h>
+
+#if RT_CONSOLEBUF_SIZE < 256
+#error "RT_CONSOLEBUF_SIZE is less than 256!"
+#endif
+
+static utest_tc_export_t tc_table = RT_NULL;
+static rt_size_t tc_num;
+static struct utest local_utest = {UTEST_PASSED, 0, 0};
+
+#if defined(__ICCARM__) || defined(__ICCRX__)         /* for IAR compiler */
+#pragma section="UtestTcTab"
+#endif
+
+int utest_init(void)
+{
+    /* initialize the utest commands table.*/
+#if defined(__CC_ARM)                                 /* ARM C Compiler */
+    extern const int UtestTcTab$$Base;
+    extern const int UtestTcTab$$Limit;
+    tc_table = (utest_tc_export_t)&UtestTcTab$$Base;
+    tc_num = (utest_tc_export_t)&UtestTcTab$$Limit - tc_table;
+#elif defined (__ICCARM__) || defined(__ICCRX__)      /* for IAR Compiler */
+    tc_table = (utest_tc_export_t)__section_begin("UtestTcTab");
+    tc_num = (utest_tc_export_t)__section_end("UtestTcTab") - tc_table;
+#elif defined (__GNUC__)                              /* for GCC Compiler */
+    extern const int __rt_utest_tc_tab_start;
+    extern const int __rt_utest_tc_tab_end;
+    tc_table = (utest_tc_export_t)&__rt_utest_tc_tab_start;
+    tc_num = (utest_tc_export_t) &__rt_utest_tc_tab_end - tc_table;
+#endif /* defined(__CC_ARM) */
+
+    LOG_I("utest is initialize success.");
+    LOG_I("total utest testcase num: (%d)", tc_num);
+    return tc_num;
+}
+INIT_COMPONENT_EXPORT(utest_init);
+
+static void utest_tc_list(void)
+{
+    rt_size_t i = 0;
+
+    LOG_I("Commands list : ");
+
+    for (i = 0; i < tc_num; i++)
+    {
+        LOG_I("[testcase name]:%s; [run timeout]:%d", tc_table[i].name, tc_table[i].run_timeout);
+    }
+}
+MSH_CMD_EXPORT_ALIAS(utest_tc_list, utest_list, output all utest testcase);
+
+static const char *file_basename(const char *file)
+{
+    char *end_ptr = RT_NULL;
+    char *rst = RT_NULL;
+
+    if (!((end_ptr = strrchr(file, '\\')) != RT_NULL || \
+        (end_ptr = strrchr(file, '/')) != RT_NULL) || \
+        (rt_strlen(file) < 2))
+    {
+        rst = (char *)file;
+    }
+    else
+    {
+        rst = (char *)(end_ptr + 1);
+    }
+    return (const char *)rst;
+}
+
+static void utest_run(const char *utest_name)
+{
+    rt_size_t i = 0;
+
+    LOG_I("[==========] [ utest    ] started");
+    while(i < tc_num)
+    {
+        if (utest_name && rt_strcmp(utest_name, tc_table[i].name))
+        {
+            i++;
+            continue;
+        }
+
+        LOG_I("[----------] [ testcase ] (%s) started", tc_table[i].name);
+        if (tc_table[i].init != RT_NULL)
+        {
+            if (tc_table[i].init() != RT_EOK)
+            {
+                LOG_I("[  FAILED  ] [ result   ] testcase (%s)", tc_table[i].name);
+                goto __tc_continue;
+            }
+        }
+
+        if (tc_table[i].tc != RT_NULL)
+        {
+            tc_table[i].tc();
+            if (local_utest.failed_num == 0)
+            {
+                LOG_I("[  PASSED  ] [ result   ] testcase (%s)", tc_table[i].name);
+            }
+            else
+            {
+                LOG_I("[  FAILED  ] [ result   ] testcase (%s)", tc_table[i].name);
+            }
+        }
+        else
+        {
+            LOG_I("[  FAILED  ] [ result   ] testcase (%s)", tc_table[i].name);
+        }
+
+        if (tc_table[i].cleanup != RT_NULL)
+        {
+            if (tc_table[i].cleanup() != RT_EOK)
+            {
+                LOG_I("[  FAILED  ] [ result   ] testcase (%s)", tc_table[i].name);
+                goto __tc_continue;
+            }
+        }
+
+__tc_continue:
+        LOG_I("[----------] [ testcase ] (%s) finished", tc_table[i].name);
+
+        i++;
+    }
+    LOG_I("[==========] [ utest    ] finished");
+}
+
+static void utest_testcase_run(int argc, char** argv)
+{
+    char utest_name[UTEST_NAME_MAX_LEN];
+
+    if (argc == 1)
+    {
+        utest_run(RT_NULL);
+    }
+    else if (argc == 2)
+    {
+        rt_memset(utest_name, 0x0, sizeof(utest_name));
+        rt_strncpy(utest_name, argv[1], sizeof(utest_name) -1);
+        utest_run(utest_name);
+    }
+    else
+    {
+        LOG_E("[  error   ] at (%s:%d), in param error.", __func__, __LINE__);
+    }
+}
+MSH_CMD_EXPORT_ALIAS(utest_testcase_run, utest_run, utest_run [testcase name]);
+
+utest_t utest_handle_get(void)
+{
+    return (utest_t)&local_utest;
+}
+
+void utest_unit_run(test_unit_func func, const char *unit_func_name)
+{
+    // LOG_I("[==========] utest unit name: (%s)", unit_func_name);
+    local_utest.error = UTEST_PASSED;
+    local_utest.passed_num = 0;
+    local_utest.failed_num = 0;
+
+    if (func != RT_NULL)
+    {
+        func();
+    }
+}
+
+void utest_assert(int value, const char *file, int line, const char *func, const char *msg)
+{
+    if (!(value))
+    {
+        local_utest.error = UTEST_FAILED;
+        local_utest.failed_num ++;
+        LOG_E("[  ASSERT  ] [ unit     ] at (%s); func: (%s:%d); msg: (%s)", file_basename(file), func, line, msg);
+    }
+    else
+    {
+        LOG_D("[    OK    ] [ unit     ] (%s:%d) is passed", func, line);
+        local_utest.error = UTEST_PASSED;
+        local_utest.passed_num ++;
+    }
+}
+
+void utest_assert_string(const char *a, const char *b, rt_bool_t equal, const char *file, int line, const char *func, const char *msg)
+{
+    if (a == RT_NULL || b == RT_NULL)
+    {
+        utest_assert(0, file, line, func, msg);
+    }
+
+    if (equal)
+    {
+        if (rt_strcmp(a, b) == 0)
+        {
+            utest_assert(1, file, line, func, msg);
+        }
+        else
+        {
+            utest_assert(0, file, line, func, msg);
+        }
+    }
+    else
+    {
+        if (rt_strcmp(a, b) == 0)
+        {
+            utest_assert(0, file, line, func, msg);
+        }
+        else
+        {
+            utest_assert(1, file, line, func, msg);
+        }
+    }
+}

+ 159 - 0
components/utilities/utest/utest.h

@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-19     MurphyZhao   the first version
+ */
+
+#ifndef __UTEST_H__
+#define __UTEST_H__
+
+#include <rtthread.h>
+#include "utest_log.h"
+
+/**
+ * utest_error
+ * 
+ * @brief Test result.
+ * 
+ * @member UTEST_PASSED Test success.
+ * @member UTEST_FAILED Test failed.
+ * @member UTEST_PASSED Test skipped.
+ * 
+*/
+enum utest_error
+{
+    UTEST_PASSED  = 0,
+    UTEST_FAILED  = 1,
+    UTEST_SKIPPED = 2
+};
+typedef enum utest_error utest_err_e;
+
+/**
+ * utest
+ * 
+ * @brief utest data structure.
+ * 
+ * @member error      Error number from enum `utest_error`.
+ * @member passed_num Total number of tests passed.
+ * @member failed_num Total number of tests failed.
+ * 
+*/
+struct utest
+{
+    utest_err_e error;
+    uint32_t passed_num;
+    uint32_t failed_num;
+};
+typedef struct utest *utest_t;
+
+/**
+ * utest_tc_export
+ * 
+ * @brief utest testcase data structure.
+ *        Will export the data to `UtestTcTab` section in flash.
+ * 
+ * @member name        Testcase name.
+ * @member run_timeout Testcase maximum test time.
+ * @member init        Necessary initialization before executing the test case function.
+ * @member tc          Total number of tests failed.
+ * @member cleanup     Total number of tests failed.
+ * 
+*/
+struct utest_tc_export {
+    const char  *name;
+    uint32_t     run_timeout;
+    rt_err_t   (*init)(void);
+    void       (*tc)(void);
+    rt_err_t   (*cleanup)(void);
+};
+typedef struct utest_tc_export *utest_tc_export_t;
+
+/**
+ * test_unit_func
+ * 
+ * @brief Unit test handler function pointer.
+ * 
+*/
+typedef void (*test_unit_func)(void);
+
+/**
+ * utest_unit_run
+ * 
+ * @brief Unit test function executor.
+ *        No need for the user to call this function directly
+ * 
+ * @param func           Unit test function.
+ * @param unit_func_name Unit test function name.
+ * 
+ * @return void
+ * 
+*/
+void utest_unit_run(test_unit_func func, const char *unit_func_name);
+
+/**
+ * utest_handle_get
+ * 
+ * @brief Get the utest data structure handle.
+ *        No need for the user to call this function directly
+ * 
+ * @param void
+ * 
+ * @return utest_t type. (struct utest *)
+ * 
+*/
+utest_t utest_handle_get(void);
+
+/**
+ * UTEST_NAME_MAX_LEN
+ * 
+ * @brief Testcase name maximum length.
+ * 
+*/
+#define UTEST_NAME_MAX_LEN (128u)
+
+/**
+ * UTEST_TC_EXPORT
+ * 
+ * @brief Export testcase function to `UtestTcTab` section in flash.
+ *        Used in application layer.
+ * 
+ * @param testcase The testcase function.
+ * @param name     The testcase name.
+ * @param init     The initialization function of the test case.
+ * @param cleanup  The cleanup function of the test case.
+ * @param timeout  Testcase maximum test time.
+ * 
+ * @return None
+ * 
+*/
+#define UTEST_TC_EXPORT(testcase, name, init, cleanup, timeout)                \
+    RT_USED static const struct utest_tc_export _utest_testcase                \
+    SECTION("UtestTcTab") =                                                    \
+    {                                                                          \
+        name,                                                                  \
+        timeout,                                                               \
+        init,                                                                  \
+        testcase,                                                              \
+        cleanup                                                                \
+    }
+
+/**
+ * UTEST_UNIT_RUN
+ * 
+ * @brief Unit test function executor.
+ *        Used in `testcase` function in application.
+ * 
+ * @param test_unit_func Unit test function
+ * 
+ * @return None
+ * 
+*/
+#define UTEST_UNIT_RUN(test_unit_func)                                         \
+    utest_unit_run(test_unit_func, #test_unit_func);                           \
+    if(utest_handle_get()->failed_num != 0) return;
+
+#endif /* __UTEST_H__ */

+ 58 - 0
components/utilities/utest/utest_assert.h

@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-19     MurphyZhao   the first version
+ */
+
+#ifndef __UTEST_ASSERT_H__
+#define __UTEST_ASSERT_H__
+
+#include "utest.h"
+#include <rtthread.h>
+
+/* No need for the user to use this function directly */
+void utest_assert(int value, const char *file, int line, const char *func, const char *msg);
+
+/* No need for the user to use this function directly */
+void utest_assert_string(const char *a, const char *b, rt_bool_t equal, const char *file, int line, const char *func, const char *msg);
+
+/* No need for the user to use this macro directly */
+#define __utest_assert(value, msg) utest_assert(value, __FILE__, __LINE__, __func__, msg)
+
+/**
+ * uassert_x macros
+ * 
+ * @brief Get the utest data structure handle.
+ *        No need for the user to call this function directly.
+ * 
+ * @macro uassert_true          if @value is true,     not assert, means passing.
+ * @macro uassert_false         if @value is false,    not assert, means passing.
+ * @macro uassert_null          if @value is null,     not assert, means passing.
+ * @macro uassert_not_null      if @value is not null, not assert, means passing.
+ * @macro uassert_int_equal     if @a equal to @b,     not assert, means passing. Integer type test.
+ * @macro uassert_int_not_equal if @a not equal to @b, not assert, means passing. Integer type test.
+ * @macro uassert_str_equal     if @a equal to @b,     not assert, means passing. String type test.
+ * @macro uassert_str_not_equal if @a not equal to @b, not assert, means passing. String type test.
+ * @macro uassert_in_range      if @value is in range of min and max,     not assert, means passing.
+ * @macro uassert_not_in_range  if @value is not in range of min and max, not assert, means passing.
+ * 
+*/
+#define uassert_true(value)      __utest_assert(value, "(" #value ") is false")
+#define uassert_false(value)     __utest_assert(!(value), "(" #value ") is true")
+#define uassert_null(value)      __utest_assert((const char *)(value) == NULL, "(" #value ") is not null")
+#define uassert_not_null(value)  __utest_assert((const char *)(value) != NULL, "(" #value ") is null")
+
+#define uassert_int_equal(a, b)      __utest_assert((a) == (b), "(" #a ") not equal to (" #b ")")
+#define uassert_int_not_equal(a, b)  __utest_assert((a) != (b), "(" #a ") equal to (" #b ")")
+
+#define uassert_str_equal(a, b)      utest_assert_string((const char*)(a), (const char*)(b), RT_TRUE, __FILE__, __LINE__, __func__, "string not equal")
+#define uassert_str_not_equal(a, b)  utest_assert_string((const char*)(a), (const char*)(b), RT_FALSE, __FILE__, __LINE__, __func__, "string equal")
+
+#define uassert_in_range(value, min, max)     __utest_assert(((value >= min) && (value <= max)), "(" #value ") not in range("#min","#max")") 
+#define uassert_not_in_range(value, min, max) __utest_assert(!((value >= min) && (value <= max)), "(" #value ") in range("#min","#max")")
+
+#endif /* __UTEST_ASSERT_H__ */

+ 31 - 0
components/utilities/utest/utest_log.h

@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-11-19     MurphyZhao   the first version
+ */
+
+#ifndef __UTEST_LOG_H__
+#define __UTEST_LOG_H__
+
+#define UTEST_DEBUG
+
+#undef DBG_SECTION_NAME
+#undef DBG_LEVEL
+#undef DBG_COLOR
+#undef DBG_ENABLE
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME          "testcase"
+#ifdef UTEST_DEBUG
+#define DBG_LEVEL                 DBG_LOG
+#else
+#define DBG_LEVEL                 DBG_INFO
+#endif
+#define DBG_COLOR
+#include <rtdbg.h>
+
+#endif /* __UTEST_LOG_H__ */