Browse Source

[component] Sync to latest version.

armink 6 years ago
parent
commit
1805aadbbb
57 changed files with 2525 additions and 462 deletions
  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 */
     /* [IN] Size of the allocation unit */
     /* [-]  Working buffer */
     /* [-]  Working buffer */
     /* [IN] Size of 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;
     rt_free(work); work = RT_NULL;
 
 
     /* check flag status, we need clear the temp driver stored in disk[] */
     /* 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];
     d = fdt->fds[fd];
 
 
     /* check dfs_fd valid or not */
     /* check dfs_fd valid or not */
-    if (d->magic != DFS_FD_MAGIC)
+    if ((d == NULL) || (d->magic != DFS_FD_MAGIC))
     {
     {
         dfs_unlock();
         dfs_unlock();
         return NULL;
         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)
 char *getcwd(char *buf, size_t size)
 {
 {
 #ifdef DFS_USING_WORKDIR
 #ifdef DFS_USING_WORKDIR
-    rt_enter_critical();
+    dfs_lock();
     strncpy(buf, working_directory, size);
     strncpy(buf, working_directory, size);
-    rt_exit_critical();
+    dfs_unlock();
 #else
 #else
     rt_kprintf(NO_WORKING_DIR);
     rt_kprintf(NO_WORKING_DIR);
 #endif
 #endif

+ 22 - 4
components/drivers/Kconfig

@@ -16,6 +16,12 @@ config RT_USING_SERIAL
     select RT_USING_DEVICE
     select RT_USING_DEVICE
     default y
     default y
 
 
+if RT_USING_SERIAL
+    config RT_SERIAL_USING_DMA
+        bool "Enable serial DMA mode"
+        default y
+endif    
+
 config RT_USING_CAN
 config RT_USING_CAN
     bool "Using CAN device drivers"
     bool "Using CAN device drivers"
     default n
     default n
@@ -72,6 +78,10 @@ config RT_USING_PIN
     bool "Using generic GPIO device drivers"
     bool "Using generic GPIO device drivers"
     default y
     default y
 
 
+config RT_USING_ADC
+    bool "Using ADC device drivers"
+    default n
+
 config RT_USING_PWM
 config RT_USING_PWM
     bool "Using PWM device drivers"
     bool "Using PWM device drivers"
     default n
     default n
@@ -118,9 +128,8 @@ config RT_USING_RTC
         default n
         default n
     config RTC_SYNC_USING_NTP
     config RTC_SYNC_USING_NTP
         bool "Using NTP auto sync RTC time"
         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
         if RTC_SYNC_USING_NTP
         config RTC_NTP_FIRST_SYNC_DELAY
         config RTC_NTP_FIRST_SYNC_DELAY
@@ -165,7 +174,11 @@ config RT_USING_SPI
     bool "Using SPI Bus/Device device drivers"
     bool "Using SPI Bus/Device device drivers"
     default n
     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
         config RT_USING_SPI_MSD
             bool "Using SD/TF card driver with spi"
             bool "Using SD/TF card driver with spi"
             select RT_USING_DFS
             select RT_USING_DFS
@@ -182,6 +195,11 @@ config RT_USING_SPI
                 config RT_SFUD_USING_FLASH_INFO_TABLE
                 config RT_SFUD_USING_FLASH_INFO_TABLE
                 bool "Using defined supported flash chip information table"
                 bool "Using defined supported flash chip information table"
                 default y
                 default y
+                
+                config RT_SFUD_USING_QSPI
+                bool "Using QSPI mode support"
+                select RT_USING_QSPI
+                default n
 
 
                 config RT_DEBUG_SFUD
                 config RT_DEBUG_SFUD
                 bool "Show more SFUD debug information"
                 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)
 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;
     struct rt_audio_device *audio;
 
 
     RT_ASSERT(dev != RT_NULL);
     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
             //init pipe for record
             {
             {
-                rt_size_t size = CFG_AUDIO_RECORD_PIPE_SIZE;
                 rt_uint8_t *buf = rt_malloc(CFG_AUDIO_RECORD_PIPE_SIZE);
                 rt_uint8_t *buf = rt_malloc(CFG_AUDIO_RECORD_PIPE_SIZE);
 
 
                 if (buf == RT_NULL)
                 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;
                     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);
                              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)
 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
     //save data to record pipe
     rt_device_write(RT_DEVICE(RT_DEVICE(&audio_pipe)), 0, pbuf, len);
     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
 #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,
     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,
 rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
                       const char *name,
                       const char *name,
-                      enum rt_audio_pipe_flag flag,
+                      rt_int32_t flag,
                       rt_uint8_t *buf,
                       rt_uint8_t *buf,
                       rt_size_t size)
                       rt_size_t size)
 {
 {
@@ -258,7 +258,7 @@ rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe)
 }
 }
 
 
 #ifdef RT_USING_HEAP
 #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;
     rt_uint8_t *rb_memptr = RT_NULL;
     struct rt_audio_pipe *pipe = 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 */
     /* ring buffer in pipe device */
     struct rt_ringbuffer ringbuffer;
     struct rt_ringbuffer ringbuffer;
 
 
-    enum rt_audio_pipe_flag flag;
+    rt_int32_t flag;
 
 
     /* suspended list */
     /* suspended list */
     rt_list_t suspended_read_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,
 rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
                       const char *name,
                       const char *name,
-                      enum rt_audio_pipe_flag flag,
+                      rt_int32_t flag,
                       rt_uint8_t *buf,
                       rt_uint8_t *buf,
                       rt_size_t size);
                       rt_size_t size);
 rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe);
 rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe);
 #ifdef RT_USING_HEAP
 #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);
 void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe);
 #endif
 #endif
 #endif
 #endif

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

@@ -1,17 +1,16 @@
-定时器设备
-===
-  
-##功能
----
+# 定时器设备
+
+## 功能
+
 * 时间测量
 * 时间测量
 * 周期或单次执行回调函数
 * 周期或单次执行回调函数
   
   
-##编译
----
+## 编译
+
 1. 在rtconfig.h添加 `#define RT_USING_HWTIMER`
 1. 在rtconfig.h添加 `#define RT_USING_HWTIMER`
-  
-##使用流程
----
+
+## 使用流程
+
 1. 以读写方式打开设备
 1. 以读写方式打开设备
 2. 设置超时回调函数(如果需要)
 2. 设置超时回调函数(如果需要)
 3. 根据需要设置定时模式(单次/周期)
 3. 根据需要设置定时模式(单次/周期)
@@ -19,12 +18,12 @@
 5. 写入超时值,定时器随即启动
 5. 写入超时值,定时器随即启动
 6. 停止定时器(可选)
 6. 停止定时器(可选)
 7. 关闭设备(如果需要)
 7. 关闭设备(如果需要)
-  
+
 应用参考 [hwtimer_test] (/examples/test/hwtimer\_test.c)
 应用参考 [hwtimer_test] (/examples/test/hwtimer\_test.c)
 
 
-##驱动编写指南
----
-###操作接口
+## 驱动编写指南
+
+### 操作接口
 
 
 ``` 
 ``` 
 struct rt_hwtimer_ops
 struct rt_hwtimer_ops
@@ -43,8 +42,8 @@ struct rt_hwtimer_ops
 * count_get - <读取计数器值>
 * count_get - <读取计数器值>
 * control - <设置计数频率 >
 * control - <设置计数频率 >
 
 
-###定时器特征信息
-  
+### 定时器特征信息
+
 ```
 ```
 struct rt_hwtimer_info
 struct rt_hwtimer_info
 {
 {
@@ -60,7 +59,8 @@ struct rt_hwtimer_info
 * maxcnt  <计数器最大计数值>
 * maxcnt  <计数器最大计数值>
 * cntmode <递增计数/递减计数>
 * cntmode <递增计数/递减计数>
   
   
-###注册设备
+### 注册设备
+
 ```
 ```
 static rt_hwtimer_t _timer0;
 static rt_hwtimer_t _timer0;
 int stm32_hwtimer_init(void)
 int stm32_hwtimer_init(void)
@@ -73,8 +73,9 @@ int stm32_hwtimer_init(void)
     return 0;
     return 0;
 }
 }
 ```
 ```
-  
-###定时器中断
+
+### 定时器中断
+
 ```
 ```
 void timer_irq_handler(void)
 void timer_irq_handler(void)
 {
 {
@@ -84,15 +85,13 @@ void timer_irq_handler(void)
 }
 }
 ```
 ```
 
 
-##注意事项
----
-  
-<font color="#FF0000">可能出现定时误差</font>
-  
+## 注意事项
+
+**可能出现定时误差**
 
 
 误差原因:
 误差原因:
 
 
 假设计数器最大值0xFFFF,计数频率1Mhz,定时时间1秒又1微秒。
 假设计数器最大值0xFFFF,计数频率1Mhz,定时时间1秒又1微秒。
-  
+
 由于定时器一次最多只能计时到65535us,对于1000001us的定时要求。
 由于定时器一次最多只能计时到65535us,对于1000001us的定时要求。
 可以50000us定时20次完成,此时将会出现计算误差1us。
 可以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);
     cnt = timer->ops->count_get(timer);
     if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
     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;
     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 bit_order               :1;
     rt_uint32_t invert                  :1;
     rt_uint32_t invert                  :1;
     rt_uint32_t bufsz                   :16;
     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_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_CS_HIGH  (1<<4)                             /* Chipselect active high */
 #define RT_SPI_NO_CS    (1<<5)                             /* No chipselect */
 #define RT_SPI_NO_CS    (1<<5)                             /* No chipselect */
 #define RT_SPI_3WIRE    (1<<6)                             /* SI/SO pin shared */
 #define RT_SPI_3WIRE    (1<<6)                             /* SI/SO pin shared */
@@ -80,6 +83,7 @@ struct rt_spi_ops;
 struct rt_spi_bus
 struct rt_spi_bus
 {
 {
     struct rt_device parent;
     struct rt_device parent;
+    rt_uint8_t mode;
     const struct rt_spi_ops *ops;
     const struct rt_spi_ops *ops;
 
 
     struct rt_mutex lock;
     struct rt_mutex lock;
@@ -106,6 +110,55 @@ struct rt_spi_device
     struct rt_spi_configuration config;
     struct rt_spi_configuration config;
     void   *user_data;
     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))
 #define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev))
 
 
 /* register a SPI bus */
 /* register a SPI bus */
@@ -255,6 +308,61 @@ rt_inline void rt_spi_message_append(struct rt_spi_message *list,
     message->next = RT_NULL;
     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
 #ifdef __cplusplus
 }
 }
 #endif
 #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);
 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);
 void rt_rbb_blk_put(rt_rbb_blk_t block);
 rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb);
 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);
 void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block);
 
 
 /* rbb block queue API */
 /* rbb block queue API */

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

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

+ 4 - 1
components/drivers/misc/SConscript

@@ -7,7 +7,10 @@ group = []
 
 
 if GetDepend(['RT_USING_PIN']):
 if GetDepend(['RT_USING_PIN']):
     src = src + ['pin.c']
     src = src + ['pin.c']
-
+    
+if GetDepend(['RT_USING_ADC']):
+    src = src + ['adc.c']
+    
 if GetDepend(['RT_USING_PWM']):
 if GetDepend(['RT_USING_PWM']):
     src = src + ['rt_drv_pwm.c']
     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;
     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 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;
     rt_err_t result = RT_EOK;
 
 
     memset(device, 0, sizeof(struct rt_device_pwm));
     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->ops                 = ops;
     device->parent.user_data    = (void *)user_data;
     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 */
             /* enter sleep and wait to be waken up */
             pm->ops->enter(pm);
             pm->ops->enter(pm);
 
 
-            rt_hw_interrupt_enable(level);
-
             /* exit from low power mode */
             /* exit from low power mode */
             rt_pm_exit();
             rt_pm_exit();
 
 
+            rt_hw_interrupt_enable(level);
             return ;
             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-07     JasonJia     fix data bits error issue when using tcsetattr.
  * 2017-11-15     JasonJia     fix poll rx issue when data is full.
  * 2017-11-15     JasonJia     fix poll rx issue when data is full.
  *                             add TCFLSH and FIONREAD support.
  *                             add TCFLSH and FIONREAD support.
+ * 2018-12-08     Ernest Chen  add DMA choice
  */
  */
 
 
 #include <rthw.h>
 #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;
     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)
 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;
     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.
  * 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;
         return 0;
     }
     }
 }
 }
+#endif /* RT_SERIAL_USING_DMA */
 
 
 /* RT-Thread Device Interface */
 /* 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",
     LOG_D("open serial device: 0x%08x with open flag: 0x%04x",
         dev, oflag);
         dev, oflag);
+#ifdef RT_SERIAL_USING_DMA
     /* check device flag with the open flag */
     /* check device flag with the open flag */
     if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
     if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
         return -RT_EIO;
         return -RT_EIO;
     if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
     if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
         return -RT_EIO;
         return -RT_EIO;
+#endif /* RT_SERIAL_USING_DMA */
     if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
     if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
         return -RT_EIO;
         return -RT_EIO;
     if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
     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 */
     /* initialize the Rx/Tx structure according to open flag */
     if (serial->serial_rx == RT_NULL)
     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) {
             if (serial->config.bufsz == 0) {
                 struct rt_serial_rx_dma* rx_dma;
                 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;
             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
         else
         {
         {
             serial->serial_rx = RT_NULL;
             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
     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;
             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 (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;
             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 */
             /* configure low level device */
             serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
             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
         else
         {
         {
             serial->serial_tx = RT_NULL;
             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
     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;
             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 */
     /* set stream flag */
@@ -710,6 +725,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
         /* configure low level device */
         /* configure low level device */
         serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_RX);
         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)
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
     {
     {
         if (serial->config.bufsz == 0) {
         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;
         serial->serial_rx = RT_NULL;
         dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
         dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
     }
     }
-
+#endif /* RT_SERIAL_USING_DMA */
+    
     if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
     if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
     {
     {
         struct rt_serial_tx_fifo* tx_fifo;
         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 */
         /* configure low level device */
         serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
         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)
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
     {
     {
         struct rt_serial_tx_dma* tx_dma;
         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;
         serial->serial_tx = RT_NULL;
         dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
         dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
     }
     }
-
+#endif /* RT_SERIAL_USING_DMA */
     return RT_EOK;
     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);
         return _serial_int_rx(serial, buffer, size);
     }
     }
+#ifdef RT_SERIAL_USING_DMA
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
     {
     {
         return _serial_dma_rx(serial, buffer, size);
         return _serial_dma_rx(serial, buffer, size);
     }
     }
+#endif /* RT_SERIAL_USING_DMA */    
 
 
     return _serial_poll_rx(serial, buffer, size);
     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);
         return _serial_int_tx(serial, buffer, size);
     }
     }
+#ifdef RT_SERIAL_USING_DMA    
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
     else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
     {
     {
         return _serial_dma_tx(serial, buffer, size);
         return _serial_dma_tx(serial, buffer, size);
     }
     }
+#endif /* RT_SERIAL_USING_DMA */
     else
     else
     {
     {
         return _serial_poll_tx(serial, buffer, size);
         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));
             rt_completion_done(&(tx_fifo->completion));
             break;
             break;
         }
         }
+#ifdef RT_SERIAL_USING_DMA
         case RT_SERIAL_EVENT_TX_DMADONE:
         case RT_SERIAL_EVENT_TX_DMADONE:
         {
         {
             const void *data_ptr;
             const void *data_ptr;
             rt_size_t data_size;
             rt_size_t data_size;
             const void *last_data_ptr;
             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;
             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;
             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']
 CPPPATH = [cwd, cwd + '/../include']
 LOCAL_CCFLAGS = ''
 LOCAL_CCFLAGS = ''
 
 
+if GetDepend('RT_USING_QSPI'):
+    src += ['qspi_core.c']
+
 src_device = []
 src_device = []
 
 
 if GetDepend('RT_USING_SPI_WIFI'):
 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 缺货或停产给产品所带来的风险。
 [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.2KB ROM:5.5KB
   - 最小占用:RAM:0.1KB ROM:3.6KB
   - 最小占用: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
 ## 1、为什么选择 SFUD
 
 
@@ -23,37 +25,43 @@
 
 
 ### 2.1 已支持 Flash 
 ### 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 说明
 ### 2.2 API 说明
 
 
@@ -63,7 +71,7 @@
 
 
 将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。
 将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。
 
 
-> 注意:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
+> **注意**:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
 
 
 ```C
 ```C
 sfud_err sfud_init(void)
 sfud_err sfud_init(void)
@@ -79,7 +87,24 @@ sfud_err sfud_device_init(sfud_flash *flash)
 |:-----                                  |:----|
 |:-----                                  |:----|
 |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` 。
 在 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 设备表中的索引值|
 |index                                   |Flash 设备位于 FLash 设备表中的索引值|
 
 
-#### 2.2.4 读取 Flash 数据
+#### 2.2.5 读取 Flash 数据
 
 
 ```C
 ```C
 sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)
 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                                    |从起始地址开始读取数据的总大小|
 |size                                    |从起始地址开始读取数据的总大小|
 |data                                    |读取到的数据|
 |data                                    |读取到的数据|
 
 
-#### 2.2.5 擦除 Flash 数据
+#### 2.2.6 擦除 Flash 数据
 
 
 > 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 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                                    |起始地址|
 |addr                                    |起始地址|
 |size                                    |从起始地址开始擦除数据的总大小|
 |size                                    |从起始地址开始擦除数据的总大小|
 
 
-#### 2.2.6 擦除 Flash 全部数据
+#### 2.2.7 擦除 Flash 全部数据
 
 
 ```C
 ```C
 sfud_err sfud_chip_erase(const sfud_flash *flash)
 sfud_err sfud_chip_erase(const sfud_flash *flash)
@@ -128,7 +153,7 @@ sfud_err sfud_chip_erase(const sfud_flash *flash)
 |:-----                                  |:----|
 |:-----                                  |:----|
 |flash                                   |Flash 设备对象|
 |flash                                   |Flash 设备对象|
 
 
-#### 2.2.7 往 Flash 写数据
+#### 2.2.8 往 Flash 写数据
 
 
 ```C
 ```C
 sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
 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                                    |从起始地址开始写入数据的总大小|
 |size                                    |从起始地址开始写入数据的总大小|
 |data                                    |待写入的数据|
 |data                                    |待写入的数据|
 
 
-#### 2.2.8 先擦除再往 Flash 写数据
+#### 2.2.9 先擦除再往 Flash 写数据
 
 
 > 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 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                                    |从起始地址开始写入数据的总大小|
 |size                                    |从起始地址开始写入数据的总大小|
 |data                                    |待写入的数据|
 |data                                    |待写入的数据|
 
 
-#### 2.2.9 读取 Flash 状态
+#### 2.2.10 读取 Flash 状态
 
 
 ```C
 ```C
 sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
 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 设备对象|
 |flash                                   |Flash 设备对象|
 |status                                  |当前状态寄存器值|
 |status                                  |当前状态寄存器值|
 
 
-#### 2.2.10 写(修改) Flash 状态
+#### 2.2.11 写(修改) Flash 状态
 
 
 ```C
 ```C
 sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status)
 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()` 方法获取到设备表,再配合这个索引值来访问指定的设备。
 上面定义了两个 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 移植说明
 ### 2.4 移植说明
 
 
 移植文件位于 `/sfud/port/sfud_port.c` ,文件中的 `sfud_err sfud_spi_port_init(sfud_flash *flash)` 方法是库提供的移植方法,在里面完成各个设备 SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。更加详细的移植内容,可以参考 demo 中的各个平台的移植文件。
 移植文件位于 `/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/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/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 许可
 ### 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.
  * 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
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
  * 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);
 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
  * read flash data
  *
  *

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

@@ -45,6 +45,13 @@
 #define SFUD_USING_SFDP
 #define SFUD_USING_SFDP
 #endif
 #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
  * 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.
  * 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
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
  * a copy of this software and associated documentation files (the
@@ -78,7 +78,7 @@ if (!(EXPR))                                                                   \
     else {if (__delay_temp) {__delay_temp();} retry --;}
     else {if (__delay_temp) {__delay_temp();} retry --;}
 
 
 /* software version number */
 /* software version number */
-#define SFUD_SW_VERSION                             "1.0.6"
+#define SFUD_SW_VERSION                             "1.1.0"
 /*
 /*
  * all defined supported command
  * all defined supported command
  */
  */
@@ -118,6 +118,22 @@ if (!(EXPR))                                                                   \
 #define SFUD_CMD_READ_DATA                             0x03
 #define SFUD_CMD_READ_DATA                             0x03
 #endif
 #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
 #ifndef SFUD_CMD_MANUFACTURER_DEVICE_ID
 #define SFUD_CMD_MANUFACTURER_DEVICE_ID                0x90
 #define SFUD_CMD_MANUFACTURER_DEVICE_ID                0x90
 #endif
 #endif
@@ -183,6 +199,21 @@ typedef enum {
     SFUD_ERR_ADDR_OUT_OF_BOUND = 5,                        /**< address is out of flash bound */
     SFUD_ERR_ADDR_OUT_OF_BOUND = 5,                        /**< address is out of flash bound */
 } sfud_err;
 } 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 */
 /* 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);
 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;
     char *name;
     /* SPI bus write read data function */
     /* 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,
     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 */
     /* lock SPI bus */
     void (*lock)(const struct __sfud_spi *spi);
     void (*lock)(const struct __sfud_spi *spi);
     /* unlock SPI bus */
     /* unlock SPI bus */
@@ -243,6 +279,10 @@ typedef struct {
     } retry;
     } retry;
     void *user_data;                             /**< some user data */
     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
 #ifdef SFUD_USING_SFDP
     sfud_sfdp sfdp;                              /**< serial flash discoverable parameters by JEDEC standard */
     sfud_sfdp sfdp;                              /**< serial flash discoverable parameters by JEDEC standard */
 #endif
 #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.
  * 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
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
  * 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 type_id;                             /**< memory type ID */
     uint8_t capacity_id;                         /**< capacity ID */
     uint8_t capacity_id;                         /**< capacity ID */
     uint32_t capacity;                           /**< flash capacity (bytes) */
     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) */
     uint32_t erase_gran;                         /**< erase granularity (bytes) */
     uint8_t erase_gran_cmd;                      /**< erase granularity size block command */
     uint8_t erase_gran_cmd;                      /**< erase granularity size block command */
 } sfud_flash_chip;
 } 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 */
 /* SFUD support manufacturer JEDEC ID */
 #define SFUD_MF_ID_CYPRESS                             0x01
 #define SFUD_MF_ID_CYPRESS                             0x01
 #define SFUD_MF_ID_FUJITSU                             0x04
 #define SFUD_MF_ID_FUJITSU                             0x04
@@ -131,6 +141,42 @@ typedef struct {
 }
 }
 #endif /* SFUD_USING_FLASH_INFO_TABLE */
 #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
 #ifdef __cplusplus
 }
 }
 #endif
 #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.
  * 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
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
  * 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;
 static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
 #endif
 #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 software_init(const sfud_flash *flash);
 static sfud_err hardware_init(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,
 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;
     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
  * hardware initialize
  */
  */
 static sfud_err hardware_init(sfud_flash *flash) {
 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;
     sfud_err result = SFUD_SUCCESS;
     size_t i;
     size_t i;
@@ -162,6 +256,11 @@ static sfud_err hardware_init(sfud_flash *flash) {
         return result;
         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 */
     /* SPI write read function must be initialize */
     SFUD_ASSERT(flash->spi.wr);
     SFUD_ASSERT(flash->spi.wr);
     /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
     /* 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);
     result = wait_busy(flash);
 
 
     if (result == SFUD_SUCCESS) {
     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 */
     /* unlock SPI */
     if (spi->unlock) {
     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;
     return result;
 }
 }
 
 
-
 /**
 /**
  * erase all flash data
  * 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) {
         const uint8_t *data) {
     sfud_err result = SFUD_SUCCESS;
     sfud_err result = SFUD_SUCCESS;
     const sfud_spi *spi = &flash->spi;
     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;
     size_t data_size;
 
 
     SFUD_ASSERT(flash);
     SFUD_ASSERT(flash);
@@ -715,8 +821,16 @@ static sfud_err reset(const sfud_flash *flash) {
     SFUD_ASSERT(flash);
     SFUD_ASSERT(flash);
 
 
     cmd_data[0] = SFUD_CMD_ENABLE_RESET;
     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;
     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) {
     if (result == SFUD_SUCCESS) {
         result = wait_busy(flash);
         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;
     bus->ops = ops;
     /* initialize owner */
     /* initialize owner */
     bus->owner = RT_NULL;
     bus->owner = RT_NULL;
+    /* set bus mode */
+    bus->mode = RT_SPI_BUS_MODE_SPI;
 
 
     return RT_EOK;
     return RT_EOK;
 }
 }

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

@@ -23,11 +23,21 @@
 
 
 #ifndef RT_SFUD_DEFAULT_SPI_CFG
 #ifndef RT_SFUD_DEFAULT_SPI_CFG
 /* read the JEDEC SFDP command must run at 50 MHz or less */
 /* 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
 #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_err result = SFUD_SUCCESS;
     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->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) {
     if (write_size) {
         RT_ASSERT(write_buf);
         RT_ASSERT(write_buf);
     }
     }
     if (read_size) {
     if (read_size) {
         RT_ASSERT(read_buf);
         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;
     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) {
 static void spi_lock(const sfud_spi *spi) {
     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->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 */
     /* port SPI device interface */
     flash->spi.wr = spi_write_read;
     flash->spi.wr = spi_write_read;
+#ifdef SFUD_USING_QSPI
+    flash->spi.qspi_read = qspi_read;
+#endif
     flash->spi.lock = spi_lock;
     flash->spi.lock = spi_lock;
     flash->spi.unlock = spi_unlock;
     flash->spi.unlock = spi_unlock;
     flash->spi.user_data = flash;
     flash->spi.user_data = flash;
@@ -213,8 +285,7 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
     flash->retry.delay = retry_delay_100us;
     flash->retry.delay = retry_delay_100us;
     /* 60 seconds timeout */
     /* 60 seconds timeout */
     flash->retry.times = 60 * 10000;
     flash->retry.times = 60 * 10000;
-
-
+    
     return result;
     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 */
      * @note you also can change the SPI to other configuration after initialized finish */
     struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
     struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
     extern sfud_err sfud_device_init(sfud_flash *flash);
     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_flash_dev_name);
     RT_ASSERT(spi_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;
                 goto error;
             }
             }
             sfud_dev->spi.name = spi_dev_name_bak;
             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 */
         /* 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.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.bytes_per_sector = sfud_dev->chip.erase_gran;
             rtt_dev->geometry.block_size = 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 */
         /* register device */
@@ -402,14 +498,17 @@ static void sf(uint8_t argc, char **argv) {
             } else {
             } else {
                 char *spi_dev_name = argv[2];
                 char *spi_dev_name = argv[2];
                 rtt_dev_bak = rtt_dev;
                 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);
                 rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
                 if (!rtt_dev) {
                 if (!rtt_dev) {
                     return;
                     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;
                 sfud_dev = (sfud_flash_t)rtt_dev->user_data;
                 if (sfud_dev->chip.capacity < 1024 * 1024) {
                 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);
                     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;
                 addr = 0;
                 size = sfud_dev->chip.capacity;
                 size = sfud_dev->chip.capacity;
                 uint32_t start_time, time_cast;
                 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);
                 uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
 
 
                 if (write_data && read_data) {
                 if (write_data && read_data) {
@@ -561,6 +660,13 @@ static void sf(uint8_t argc, char **argv) {
                         } else {
                         } else {
                             result = sfud_read(sfud_dev, addr + i, size - i, read_data);
                             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) {
                         if (result != SFUD_SUCCESS) {
                             break;
                             break;
                         }
                         }

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

@@ -12,6 +12,7 @@
 #define _SPI_FLASH_SFUD_H_
 #define _SPI_FLASH_SFUD_H_
 
 
 #include <rtthread.h>
 #include <rtthread.h>
+#include <rtdevice.h>
 #include "./sfud/inc/sfud.h"
 #include "./sfud/inc/sfud.h"
 #include "spi_flash.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_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 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_token(struct rt_spi_device *device, uint8_t token);
 static rt_err_t _wait_ready(struct rt_spi_device *device);
 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;
     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)
 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;
     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;
             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
         /* 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.
            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)
             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);
                 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))
                 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
             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);
                 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)
                 if (result == RT_EOK)
                 {
                 {
@@ -622,23 +590,23 @@ static rt_err_t rt_msd_init(rt_device_t dev)
             /* try SD Ver1.x */
             /* try SD Ver1.x */
             while (1)
             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);
                 result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
                 if (result != RT_EOK)
                 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");
                     MSD_DEBUG("[info] It maybe SD1.x or MMC But it is Not response to CMD58!\r\n");
                     goto _exit;
                     goto _exit;
                 }
                 }
 
 
                 if (0 != (response[0] & 0xFE))
                 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");
                     MSD_DEBUG("[info] It look CMD58 as illegal command so it is not SD card!\r\n");
                     break;
                     break;
                 }
                 }
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
 
 
                 OCR = response[1];
                 OCR = response[1];
                 OCR = (OCR << 8) + response[2];
                 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)))
                     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");
                         MSD_DEBUG("[info] try CMD55 + ACMD41 timeout! mabey MMC card!\r\n");
                         break;
                         break;
                     }
                     }
 
 
-                    MSD_take_cs(msd->spi_device);
+                    rt_spi_take(msd->spi_device);
 
 
                     /* CMD55 APP_CMD */
                     /* CMD55 APP_CMD */
                     result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response);
                     result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response);
                     if (result != RT_EOK)
                     if (result != RT_EOK)
                     {
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         continue;
                         continue;
                     }
                     }
 
 
                     if (0 != (response[0] & 0xFE))
                     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");
                         MSD_DEBUG("[info] Not SD card2 , may be MMC\r\n");
                         break;
                         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);
                     result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x00, 0x00, response_r1, response);
                     if (result != RT_EOK)
                     if (result != RT_EOK)
                     {
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         continue;
                         continue;
                     }
                     }
 
 
                     if (0 != (response[0] & 0xFE))
                     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");
                         MSD_DEBUG("[info] Not SD card4 , may be MMC\r\n");
                         break;
                         break;
                     }
                     }
 
 
                     if (0 == (response[0] & 0xFF))
                     if (0 == (response[0] & 0xFF))
                     {
                     {
-                        MSD_release_cs(msd->spi_device);
+                        rt_spi_release(msd->spi_device);
                         is_sd_v1_x = RT_TRUE;
                         is_sd_v1_x = RT_TRUE;
                         MSD_DEBUG("[info] It is Ver1.X SD Memory Card!!!\r\n");
                         MSD_DEBUG("[info] It is Ver1.X SD Memory Card!!!\r\n");
                         break;
                         break;
@@ -716,7 +684,7 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                 uint32_t i;
                 uint32_t i;
 
 
                 MSD_DEBUG("[info] try MMC card!\r\n");
                 MSD_DEBUG("[info] try MMC card!\r\n");
-                MSD_release_cs(msd->spi_device);
+                rt_spi_release(msd->spi_device);
 
 
                 /* send dummy clock */
                 /* send dummy clock */
                 {
                 {
@@ -740,9 +708,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
                 tick_start = rt_tick_get();
                 tick_start = rt_tick_get();
                 while (1)
                 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);
                     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))
                     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();
                 tick_start = rt_tick_get();
                 while (1)
                 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);
                     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))
                     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)
         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);
             result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
             if (result != RT_EOK)
             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");
                 MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to CMD58!\r\n");
                 goto _exit;
                 goto _exit;
             }
             }
 
 
             if ((response[0] & 0xFE) != 0)
             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");
                 MSD_DEBUG("[err] It look CMD58 as illegal command so it is not SD card!\r\n");
                 result = RT_ERROR;
                 result = RT_ERROR;
                 goto _exit;
                 goto _exit;
             }
             }
 
 
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
 
 
             OCR = response[1];
             OCR = response[1];
             OCR = (OCR << 8) + response[2];
             OCR = (OCR << 8) + response[2];
@@ -822,10 +790,10 @@ static rt_err_t rt_msd_init(rt_device_t dev)
             /* try CMD55 + ACMD41 */
             /* try CMD55 + ACMD41 */
             do
             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)))
                 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");
                     MSD_DEBUG("[err] SD Ver2.x or later try CMD55 + ACMD41 timeout!\r\n");
                     result = RT_ERROR;
                     result = RT_ERROR;
                     goto _exit;
                     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) || (response[0] == 0x01))
                 if (result != RT_EOK)
                 if (result != RT_EOK)
                 {
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     continue;
                     continue;
                 }
                 }
 
 
                 if ((response[0] & 0xFE) != 0)
                 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");
                     MSD_DEBUG("[err] Not SD ready!\r\n");
                     result = RT_ERROR;
                     result = RT_ERROR;
                     goto _exit;
                     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);
                 result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x40000000, 0x77, response_r1, response);
                 if (result != RT_EOK)
                 if (result != RT_EOK)
                 {
                 {
-                    MSD_release_cs(msd->spi_device);
+                    rt_spi_release(msd->spi_device);
                     MSD_DEBUG("[err] ACMD41 fail!\r\n");
                     MSD_DEBUG("[err] ACMD41 fail!\r\n");
                     result = RT_ERROR;
                     result = RT_ERROR;
                     goto _exit;
                     goto _exit;
@@ -860,33 +828,33 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 
 
                 if ((response[0] & 0xFE) != 0)
                 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]);
                     MSD_DEBUG("[info] Not SD card4 , response : 0x%02X\r\n", response[0]);
 //                    break;
 //                    break;
                 }
                 }
             }
             }
             while (response[0] != MSD_RESPONSE_NO_ERROR);
             while (response[0] != MSD_RESPONSE_NO_ERROR);
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
             /* try CMD55 + ACMD41 */
             /* try CMD55 + ACMD41 */
 
 
             /* --Read OCR again */
             /* --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);
             result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
             if (result != RT_EOK)
             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");
                 MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to 2nd CMD58!\r\n");
                 goto _exit;
                 goto _exit;
             }
             }
 
 
             if ((response[0] & 0xFE) != 0)
             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");
                 MSD_DEBUG("[err] It look 2nd CMD58 as illegal command so it is not SD card!\r\n");
                 result = RT_ERROR;
                 result = RT_ERROR;
                 goto _exit;
                 goto _exit;
             }
             }
-            MSD_release_cs(msd->spi_device);
+            rt_spi_release(msd->spi_device);
 
 
             OCR = response[1];
             OCR = response[1];
             OCR = (OCR << 8) + response[2];
             OCR = (OCR << 8) + response[2];
@@ -933,14 +901,14 @@ static rt_err_t rt_msd_init(rt_device_t dev)
 
 
     /* set CRC */
     /* 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
 #ifdef MSD_USE_CRC
         result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x01, 0x83, response_r1, response);
         result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x01, 0x83, response_r1, response);
 #else
 #else
         result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x00, 0x91, response_r1, response);
         result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x00, 0x91, response_r1, response);
 #endif
 #endif
-        MSD_release_cs(msd->spi_device);
+        rt_spi_release(msd->spi_device);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         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]);
             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 */
     /* 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);
         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))
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         {
         {
             MSD_DEBUG("[err] CMD16 SET_BLOCKLEN fail! response : 0x%02X\r\n", response[0]);
             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];
         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, 0xAF, response_r1, response);
         result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0x00, response_r1, response);
         result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0x00, response_r1, response);
 
 
         if (result != RT_EOK)
         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");
             MSD_DEBUG("[err] CMD9 SEND_CSD timeout!\r\n");
             goto _exit;
             goto _exit;
         }
         }
 
 
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         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]);
             MSD_DEBUG("[err] CMD9 SEND_CSD fail! response : 0x%02X\r\n", response[0]);
             result = RT_ERROR;
             result = RT_ERROR;
             goto _exit;
             goto _exit;
         }
         }
 
 
         result = _read_block(msd->spi_device, CSD_buffer, MSD_CSD_LEN);
         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)
         if (result != RT_EOK)
         {
         {
             MSD_DEBUG("[err] read CSD fail!\r\n");
             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.data_width = 8;
         cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
         cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
         cfg.max_hz = msd->max_clock;
         cfg.max_hz = msd->max_clock;
-
         rt_spi_configure(msd->spi_device, &cfg);
         rt_spi_configure(msd->spi_device, &cfg);
     } /* config spi */
     } /* config spi */
 
 
 _exit:
 _exit:
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
     rt_mutex_release(&(msd->spi_device->bus->lock));
     return result;
     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;
         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? */
     /* SINGLE_BLOCK? */
     if (size == 1)
     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);
         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))
         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;
         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);
         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))
         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:
 _exit:
     /* release and exit */
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
 
     return size;
     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;
         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? */
     /* SINGLE_BLOCK? */
     if (size == 1)
     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);
         result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         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;
         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);
         result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         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:
 _exit:
     /* release and exit */
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
 
     return size;
     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;
         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? */
     /* SINGLE_BLOCK? */
     if (size == 1)
     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);
         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))
         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;
         struct rt_spi_message message;
         uint32_t i;
         uint32_t i;
 
 
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
 
 #ifdef MSD_USE_PRE_ERASED
 #ifdef MSD_USE_PRE_ERASED
         if (msd->card_type != MSD_CARD_TYPE_MMC)
         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:
 _exit:
     /* release and exit */
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
 
     return size;
     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;
         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? */
     /* SINGLE_BLOCK? */
     if (size == 1)
     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);
         result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos, 0x00, response_r1, response);
         if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
         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;
         struct rt_spi_message message;
         uint32_t i;
         uint32_t i;
 
 
-        MSD_take_cs(msd->spi_device);
+        rt_spi_take(msd->spi_device);
 
 
 #ifdef MSD_USE_PRE_ERASED
 #ifdef MSD_USE_PRE_ERASED
         /* CMD55 APP_CMD */
         /* 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:
 _exit:
     /* release and exit */
     /* release and exit */
-    MSD_release_cs(msd->spi_device);
+    rt_spi_release(msd->spi_device);
     rt_mutex_release(&(msd->spi_device->bus->lock));
     rt_mutex_release(&(msd->spi_device->bus->lock));
 
 
     return size;
     return size;

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

@@ -18,8 +18,10 @@
  * @param rbb ring block buffer object
  * @param rbb ring block buffer object
  * @param buf buffer
  * @param buf buffer
  * @param buf_size buffer size
  * @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)
 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 rbb ring block buffer object
  * @param blk_size block size
  * @param blk_size block size
  *
  *
+ * @note When your application need align access, please make the blk_szie is aligned.
+ *
  * @return != NULL: allocated block
  * @return != NULL: allocated block
  *            NULL: allocate failed
  *            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_rbb_blk_t head, tail, new = NULL;
 
 
     RT_ASSERT(rbb);
     RT_ASSERT(rbb);
-    RT_ASSERT(blk_size < 1L << 24);
+    RT_ASSERT(blk_size < (1L << 24));
 
 
     level = rt_hw_interrupt_disable();
     level = rt_hw_interrupt_disable();
 
 
@@ -277,6 +281,36 @@ __exit:
 }
 }
 RTM_EXPORT(rt_rbb_blk_get);
 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
  * 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);
             _get_string_descriptor(device, setup);
             break;
             break;
         case USB_DESC_TYPE_DEVICEQUALIFIER:
         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;
             break;
         case USB_DESC_TYPE_OTHERSPEED:
         case USB_DESC_TYPE_OTHERSPEED:
             _get_config_descriptor(device, setup);
             _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_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.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.key.len = password_len;
     ap_info.hidden = info->hidden;
     ap_info.hidden = info->hidden;
     ap_info.channel = info->channel;
     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 rt_wlan_dev_get_rssi(struct rt_wlan_device *device)
 {
 {
     int rssi = 0;
     int rssi = 0;
+    rt_err_t result = RT_EOK;
 
 
     if (device == RT_NULL)
     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;
     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 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)
     if (device == RT_NULL)
     {
     {
+        rt_set_errno(-RT_EIO);
         return -1;
         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;
     return level;
 }
 }
@@ -432,19 +449,21 @@ rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel)
     return result;
     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;
     rt_err_t result = RT_EOK;
-    int channel;
+    int channel = -1;
 
 
     if (device == RT_NULL)
     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);
     result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_CHANNEL, &channel);
     if (result != RT_EOK)
     if (result != RT_EOK)
     {
     {
+        rt_set_errno(result);
         return -1;
         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)
 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;
     rt_country_code_t country_code = RT_COUNTRY_UNKNOWN;
 
 
     if (device == RT_NULL)
     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);
     result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_COUNTRY, &country_code);
     if (result != RT_EOK)
     if (result != RT_EOK)
     {
     {
+        rt_set_errno(result);
         return RT_COUNTRY_UNKNOWN;
         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");
         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)
         if (wlan->ops->wlan_set_powersave)
-            wlan->ops->wlan_set_powersave(wlan, level);
+            err = wlan->ops->wlan_set_powersave(wlan, level);
         break;
         break;
     }
     }
     case RT_WLAN_CMD_GET_POWERSAVE:
     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");
         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)
         if (wlan->ops->wlan_cfg_promisc)
-            wlan->ops->wlan_cfg_promisc(wlan, start);
+            err = wlan->ops->wlan_cfg_promisc(wlan, start);
         break;
         break;
     }
     }
     case RT_WLAN_CMD_CFG_FILTER:
     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");
         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)
         if (wlan->ops->wlan_cfg_filter)
-            wlan->ops->wlan_cfg_filter(wlan, filter);
+            err = wlan->ops->wlan_cfg_filter(wlan, filter);
         break;
         break;
     }
     }
     case RT_WLAN_CMD_SET_CHANNEL:
     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;
         int channel = *(int *)args;
         LOG_D("%s %d cmd[%d]:%s  run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_CHANNEL, "RT_WLAN_CMD_SET_CHANNEL");
         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)
         if (wlan->ops->wlan_set_channel)
-            wlan->ops->wlan_set_channel(wlan, channel);
+            err = wlan->ops->wlan_set_channel(wlan, channel);
         break;
         break;
     }
     }
     case RT_WLAN_CMD_GET_CHANNEL:
     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");
         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)
         if (wlan->ops->wlan_set_country)
-            wlan->ops->wlan_set_country(wlan, country);
+            err = wlan->ops->wlan_set_country(wlan, country);
         break;
         break;
     }
     }
     case RT_WLAN_CMD_GET_COUNTRY:
     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");
         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)
         if (wlan->ops->wlan_set_mac)
-            wlan->ops->wlan_set_mac(wlan, mac);
+            err = wlan->ops->wlan_set_mac(wlan, mac);
         break;
         break;
     }
     }
     case RT_WLAN_CMD_GET_MAC:
     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");
         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)
         if (wlan->ops->wlan_get_mac)
-            wlan->ops->wlan_get_mac(wlan, mac);
+            err = wlan->ops->wlan_get_mac(wlan, mac);
         break;
         break;
     }
     }
     default:
     default:
@@ -733,22 +754,16 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
     return err;
     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__);
         LOG_E("F:%s L:%d parameter Wrongful", __FUNCTION__, __LINE__);
         return RT_NULL;
         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));
     rt_memset(wlan, 0, sizeof(struct rt_wlan_device));
 
 
     wlan->device.init       = _rt_wlan_dev_init;
     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->user_data  = user_data;
 
 
     wlan->flags = flag;
     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__);
     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
  * 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_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
  * 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
  * 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
 #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;
         return -RT_EIO;
     }
     }
     RT_WLAN_LOG_D("%s is run", __FUNCTION__);
     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)
     if (password_len > RT_WLAN_PASSWORD_MAX_LENGTH)
     {
     {
         RT_WLAN_LOG_E("key is to long! len:%d", password_len);
         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;
     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())
     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");
     RT_WLAN_LOG_D("%s is run active:%s", __FUNCTION__, _active ? "Active" : "Inactive");
     return _active;
     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(const char *ssid, const char *password);
 rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, 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_stop(void);
 rt_err_t rt_wlan_ap_get_info(struct rt_wlan_info *info);
 rt_err_t rt_wlan_ap_get_info(struct rt_wlan_info *info);
 int rt_wlan_ap_get_sta_num(void);
 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);
     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);
 MSH_CMD_EXPORT(list_sem, list semaphore in system);
 #endif
 #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"
                     bool "Support AT Commands stack"
                     default y
                     default y
                     depends on AT_USING_SOCKET
                     depends on AT_USING_SOCKET
+                    
+                config SAL_USING_TLS
+                    bool "Support MbedTLS protocol"
+                    default y
+                    depends on PKG_USING_MBEDTLS
             endmenu
             endmenu
         
         
         endif
         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;
             goto __exit;
         }
         }
         sock->state = AT_SOCKET_CONNECT;
         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 */
     /* socket passively closed, receive function return 0 */
     if (sock->state == AT_SOCKET_CLOSED)
     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;
         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 */
     /* non-blocking sockets receive data */
     if (flags & MSG_DONTWAIT)
     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'):
 if GetDepend('SAL_USING_AT'):
     src += Glob('impl/af_inet_at.c')
     src += Glob('impl/af_inet_at.c')
-    
+
 if GetDepend('SAL_USING_LWIP') or GetDepend('SAL_USING_AT'):
 if GetDepend('SAL_USING_LWIP') or GetDepend('SAL_USING_AT'):
     CPPPATH += [cwd + '/impl']
     CPPPATH += [cwd + '/impl']
 
 
+if GetDepend('SAL_USING_TLS'):
+    src += Glob('impl/proto_mbedtls.c')
+
 if GetDepend('SAL_USING_POSIX'):
 if GetDepend('SAL_USING_POSIX'):
     CPPPATH += [cwd + '/include/dfs_net']
     CPPPATH += [cwd + '/include/dfs_net']
     src += Glob('socket/net_sockets.c')
     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
 #endif
 
 
-static const struct proto_ops at_inet_stream_ops =
+static const struct sal_socket_ops at_socket_ops =
 {
 {
     at_socket,
     at_socket,
     at_closesocket,
     at_closesocket,
@@ -90,25 +90,30 @@ static int at_create(struct sal_socket *socket, int type, int protocol)
 
 
     //TODO Check type & protocol
     //TODO Check type & protocol
 
 
-    socket->ops = &at_inet_stream_ops;
+    socket->ops = &at_socket_ops;
 
 
     return 0;
     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,
     at_gethostbyname,
     NULL,
     NULL,
-    at_freeaddrinfo,
     at_getaddrinfo,
     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)
 int at_inet_init(void)
 {
 {
-    sal_proto_family_register(&at_inet_family_ops);
+    sal_proto_family_register(&at_inet_family);
 
 
     return 0;
     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
 #endif
 
 
-static const struct proto_ops lwip_inet_stream_ops = {
+static const struct sal_socket_ops lwip_socket_ops =
+{
     inet_socket,
     inet_socket,
     lwip_close,
     lwip_close,
     lwip_bind,
     lwip_bind,
@@ -286,25 +287,30 @@ static int inet_create(struct sal_socket *socket, int type, int protocol)
 
 
     //TODO Check type & protocol
     //TODO Check type & protocol
 
 
-    socket->ops = &lwip_inet_stream_ops;
+    socket->ops = &lwip_socket_ops;
 
 
     return 0;
     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,
     lwip_gethostbyname_r,
     lwip_gethostbyname_r,
-    lwip_freeaddrinfo,
     lwip_getaddrinfo,
     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)
 int lwip_inet_init(void)
 {
 {
-    sal_proto_family_register(&lwip_inet_family_ops);
+    sal_proto_family_register(&lwip_inet_family);
 
 
     return 0;
     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;
 typedef uint32_t socklen_t;
 #endif
 #endif
 
 
-/* sal socket magic word */
+/* SAL socket magic word */
 #define SAL_SOCKET_MAGIC               0x5A10
 #define SAL_SOCKET_MAGIC               0x5A10
 
 
 /* The maximum number of sockets structure */
 /* The maximum number of sockets structure */
@@ -38,12 +38,12 @@ typedef uint32_t socklen_t;
 #define SAL_PROTO_FAMILIES_NUM         4
 #define SAL_PROTO_FAMILIES_NUM         4
 #endif
 #endif
 
 
-/* sal socket offset */
+/* SAL socket offset */
 #ifndef SAL_SOCKET_OFFSET
 #ifndef SAL_SOCKET_OFFSET
 #define SAL_SOCKET_OFFSET              0
 #define SAL_SOCKET_OFFSET              0
 #endif
 #endif
 
 
-struct proto_ops
+struct sal_socket_ops
 {
 {
     int (*socket)     (int domain, int type, int protocol);
     int (*socket)     (int domain, int type, int protocol);
     int (*closesocket)(int s);
     int (*closesocket)(int s);
@@ -64,30 +64,38 @@ struct proto_ops
 #endif
 #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
 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 domain;
     int type;
     int type;
     int protocol;
     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 family;                        /* primary protocol families type */
     int sec_family;                    /* secondary 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 */
 /* SAL(Socket Abstraction Layer) initialize */
@@ -95,10 +103,11 @@ int sal_init(void);
 
 
 struct sal_socket *sal_get_socket(int sock);
 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
 #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 <rtthread.h>
 #include <sal_socket.h>
 #include <sal_socket.h>
+#ifdef SAL_USING_TLS
+#include <sal_tls.h>
+#endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {

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

@@ -6,6 +6,7 @@
  * Change Logs:
  * Change Logs:
  * Date           Author       Notes
  * Date           Author       Notes
  * 2018-05-23     ChenYong     First version
  * 2018-05-23     ChenYong     First version
+ * 2018-11-12     ChenYong     Add TLS support
  */
  */
 
 
 #include <rtthread.h>
 #include <rtthread.h>
@@ -13,6 +14,9 @@
 
 
 #include <sal_socket.h>
 #include <sal_socket.h>
 #include <sal_netdb.h>
 #include <sal_netdb.h>
+#ifdef SAL_USING_TLS
+#include <sal_tls.h>
+#endif
 #include <sal.h>
 #include <sal.h>
 
 
 #define DBG_ENABLE
 #define DBG_ENABLE
@@ -30,13 +34,32 @@ struct sal_socket_table
     struct sal_socket **sockets;
     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 */
 /* 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 */
 /* The global socket table */
 static struct sal_socket_table socket_table;
 static struct sal_socket_table socket_table;
 static struct rt_mutex sal_core_lock;
 static struct rt_mutex sal_core_lock;
 static rt_bool_t init_ok = RT_FALSE;
 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.
  * SAL (Socket Abstraction Layer) initialize.
  *
  *
@@ -47,7 +70,7 @@ int sal_init(void)
 {
 {
     int cn;
     int cn;
     
     
-    if(init_ok)
+    if (init_ok)
     {
     {
         LOG_D("Socket Abstraction Layer is already initialized.");
         LOG_D("Socket Abstraction Layer is already initialized.");
         return 0;
         return 0;
@@ -73,15 +96,32 @@ int sal_init(void)
 }
 }
 INIT_COMPONENT_EXPORT(sal_init);
 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.
  * This function will register protocol family to the global array of protocol families.
  *
  *
  * @param pf protocol family object
  * @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;
     rt_base_t level;
     int idx;
     int idx;
@@ -92,11 +132,11 @@ int sal_proto_family_register(const struct proto_family *pf)
     /* check protocol family is already registered */
     /* check protocol family is already registered */
     for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
     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 */
             /* enable interrupt */
             rt_hw_interrupt_enable(level);
             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;
             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++);
     for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM && proto_families[idx].create; idx++);
 
 
     /* can't find an empty protocol family entry */
     /* can't find an empty protocol family entry */
-    if(idx == SAL_PROTO_FAMILIES_NUM)
+    if (idx == SAL_PROTO_FAMILIES_NUM)
     {
     {
         /* enable interrupt */
         /* enable interrupt */
         rt_hw_interrupt_enable(level);
         rt_hw_interrupt_enable(level);
         return -1;
         return -1;
     }
     }
 
 
-    rt_strncpy(proto_families[idx].name, pf->name, rt_strlen(pf->name));
     proto_families[idx].family = pf->family;
     proto_families[idx].family = pf->family;
     proto_families[idx].sec_family = pf->sec_family;
     proto_families[idx].sec_family = pf->sec_family;
     proto_families[idx].create = pf->create;
     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 */
     /* enable interrupt */
     rt_hw_interrupt_enable(level);
     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
  * @return >=0 : unregister protocol family index
  *          -1 : unregister failed
  *          -1 : unregister failed
  */
  */
-int sal_proto_family_unregister(const struct proto_family *pf)
+int sal_proto_family_unregister(int family)
 {
 {
     int idx = 0;
     int idx = 0;
 
 
-    RT_ASSERT(pf != RT_NULL);
+    RT_ASSERT(family > 0 && family < AF_MAX);
 
 
     for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
     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;
             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
  * @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;
     int idx = 0;
 
 
-    RT_ASSERT(name != RT_NULL);
+    RT_ASSERT(family > 0 && family < AF_MAX);
 
 
     for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
     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];
             return &proto_families[idx];
         }
         }
@@ -238,7 +303,7 @@ static void sal_unlock(void)
  *
  *
  * @return protocol family structure address
  * @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;
     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)
 static int socket_init(int family, int type, int protocol, struct sal_socket **res)
 {
 {
     struct sal_socket *sock;
     struct sal_socket *sock;
-    struct proto_family *pf;
+    struct sal_proto_family *pf;
 
 
     if (family < 0 || family > AF_MAX)
     if (family < 0 || family > AF_MAX)
     {
     {
@@ -383,6 +448,11 @@ static int socket_new(void)
     sock = st->sockets[idx];
     sock = st->sockets[idx];
     sock->socket = idx + SAL_SOCKET_OFFSET;
     sock->socket = idx + SAL_SOCKET_OFFSET;
     sock->magic = SAL_SOCKET_MAGIC;
     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:
 __result:
     sal_unlock();
     sal_unlock();
@@ -474,6 +544,15 @@ int sal_shutdown(int socket, int how)
 
 
     if (sock->ops->shutdown((int) sock->user_data, how) == 0)
     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);
         rt_free(sock);
         socket_table.sockets[socket] = RT_NULL;
         socket_table.sockets[socket] = RT_NULL;
         return 0;
         return 0;
@@ -551,12 +630,46 @@ int sal_setsockopt(int socket, int level, int optname, const void *optval, sockl
         return -RT_ENOSYS;
         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);
     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)
 int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
 {
 {
     struct sal_socket *sock;
     struct sal_socket *sock;
+    int ret;
 
 
     sock = sal_get_socket(socket);
     sock = sal_get_socket(socket);
     if (!sock)
     if (!sock)
@@ -569,7 +682,20 @@ int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
         return -RT_ENOSYS;
         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)
 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;
         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);
     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,
 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;
         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);
     return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen);
+#endif
 }
 }
 
 
 int sal_socket(int domain, int type, int protocol)
 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);
     proto_socket = sock->ops->socket(domain, type, protocol);
     if (proto_socket >= 0)
     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;
         sock->user_data = (void *) proto_socket;
-
         return sock->socket;
         return sock->socket;
     }
     }
 
 
@@ -682,6 +851,15 @@ int sal_closesocket(int socket)
 
 
     if (sock->ops->closesocket((int) sock->user_data) == 0)
     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);        
         rt_free(sock);        
         socket_table.sockets[socket] = RT_NULL;
         socket_table.sockets[socket] = RT_NULL;
         return 0;
         return 0;
@@ -736,9 +914,9 @@ struct hostent *sal_gethostbyname(const char *name)
 
 
     for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
     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)
             if (hst != RT_NULL)
             {
             {
                 return hst;
                 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)
     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)
             if (res == 0)
             {
             {
                 return res;
                 return res;
@@ -769,20 +947,6 @@ int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
     return -1;
     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,
 int sal_getaddrinfo(const char *nodename,
        const char *servname,
        const char *servname,
        const struct addrinfo *hints,
        const struct addrinfo *hints,
@@ -792,9 +956,9 @@ int sal_getaddrinfo(const char *nodename,
 
 
     for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
     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)
             if (ret == 0)
             {
             {
                 return ret;
                 return ret;
@@ -804,3 +968,17 @@ int sal_getaddrinfo(const char *nodename,
 
 
     return -1;
     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
                 sfotware module version number
     endif
     endif
 
 
+config RT_USING_UTEST
+    bool "Enable utest (RT-Thread test framework)"
+    default n
+
 endmenu
 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_I(...)                     ulog_i(LOG_TAG, __VA_ARGS__)
 #define LOG_D(...)                     ulog_d(LOG_TAG, __VA_ARGS__)
 #define LOG_D(...)                     ulog_d(LOG_TAG, __VA_ARGS__)
 #define LOG_RAW(...)                   ulog_raw(__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
  * backend register and unregister

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

@@ -94,6 +94,12 @@ extern "C" {
     #define ulog_e(TAG, ...)
     #define ulog_e(TAG, ...)
 #endif /* (LOG_LVL >= LOG_LVL_ERROR) && (ULOG_OUTPUT_LVL >= LOG_LVL_ERROR) */
 #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. */
 /* assert for developer. */
 #ifdef ULOG_ASSERT_ENABLE
 #ifdef ULOG_ASSERT_ENABLE
     #define ULOG_ASSERT(EXPR)                                                 \
     #define ULOG_ASSERT(EXPR)                                                 \
@@ -132,6 +138,7 @@ extern "C" {
 #define log_d                          LOG_D
 #define log_d                          LOG_D
 #define log_v                          LOG_D
 #define log_v                          LOG_D
 #define log_raw                        LOG_RAW
 #define log_raw                        LOG_RAW
+#define log_hex                        LOG_HEX    
 #define ELOG_LVL_ASSERT                LOG_LVL_ASSERT
 #define ELOG_LVL_ASSERT                LOG_LVL_ASSERT
 #define ELOG_LVL_ERROR                 LOG_LVL_ERROR
 #define ELOG_LVL_ERROR                 LOG_LVL_ERROR
 #define ELOG_LVL_WARN                  LOG_LVL_WARNING
 #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__ */