diff --git a/components/dfs/filesystems/elmfat/dfs_elm.c b/components/dfs/filesystems/elmfat/dfs_elm.c
index 290cf7c4bb46ceeb876a96fdbaed6bedbbabc636..582333a714963891150762e91ace48f50666be86 100644
--- a/components/dfs/filesystems/elmfat/dfs_elm.c
+++ b/components/dfs/filesystems/elmfat/dfs_elm.c
@@ -265,7 +265,7 @@ int dfs_elm_mkfs(rt_device_t dev_id)
/* [IN] Size of the allocation unit */
/* [-] Working buffer */
/* [IN] Size of working buffer */
- result = f_mkfs(logic_nbr, FM_ANY, 0, work, _MAX_SS);
+ result = f_mkfs(logic_nbr, FM_ANY|FM_SFD, 0, work, _MAX_SS);
rt_free(work); work = RT_NULL;
/* check flag status, we need clear the temp driver stored in disk[] */
diff --git a/components/dfs/src/dfs.c b/components/dfs/src/dfs.c
index 38a1813421ead9cae1672b001997155290e53b8a..cf0b2b0ef99485bbe017d98e83e7d91e2724ce57 100644
--- a/components/dfs/src/dfs.c
+++ b/components/dfs/src/dfs.c
@@ -221,7 +221,7 @@ struct dfs_fd *fd_get(int fd)
d = fdt->fds[fd];
/* check dfs_fd valid or not */
- if (d->magic != DFS_FD_MAGIC)
+ if ((d == NULL) || (d->magic != DFS_FD_MAGIC))
{
dfs_unlock();
return NULL;
diff --git a/components/dfs/src/dfs_posix.c b/components/dfs/src/dfs_posix.c
index 97531ad59cf35f8d443e040cb316aedda179668a..f47a60ee5dc34da490b16155143b43f326205b90 100644
--- a/components/dfs/src/dfs_posix.c
+++ b/components/dfs/src/dfs_posix.c
@@ -890,9 +890,9 @@ int access(const char *path, int amode)
char *getcwd(char *buf, size_t size)
{
#ifdef DFS_USING_WORKDIR
- rt_enter_critical();
+ dfs_lock();
strncpy(buf, working_directory, size);
- rt_exit_critical();
+ dfs_unlock();
#else
rt_kprintf(NO_WORKING_DIR);
#endif
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index 824b3e00da646f79dbc46d077e78c922cec963c8..d8dc5e74581600d4aa120032518e00d5849fa49e 100755
--- a/components/drivers/Kconfig
+++ b/components/drivers/Kconfig
@@ -16,6 +16,12 @@ config RT_USING_SERIAL
select RT_USING_DEVICE
default y
+if RT_USING_SERIAL
+ config RT_SERIAL_USING_DMA
+ bool "Enable serial DMA mode"
+ default y
+endif
+
config RT_USING_CAN
bool "Using CAN device drivers"
default n
@@ -72,6 +78,10 @@ config RT_USING_PIN
bool "Using generic GPIO device drivers"
default y
+config RT_USING_ADC
+ bool "Using ADC device drivers"
+ default n
+
config RT_USING_PWM
bool "Using PWM device drivers"
default n
@@ -118,9 +128,8 @@ config RT_USING_RTC
default n
config RTC_SYNC_USING_NTP
bool "Using NTP auto sync RTC time"
- select PKG_USING_NETUTILS
- select PKG_NETUTILS_NTP
- default n
+ depends on PKG_NETUTILS_NTP
+ default y
if RTC_SYNC_USING_NTP
config RTC_NTP_FIRST_SYNC_DELAY
@@ -165,7 +174,11 @@ config RT_USING_SPI
bool "Using SPI Bus/Device device drivers"
default n
- if RT_USING_SPI
+ if RT_USING_SPI
+ config RT_USING_QSPI
+ bool "Enable QSPI mode"
+ default n
+
config RT_USING_SPI_MSD
bool "Using SD/TF card driver with spi"
select RT_USING_DFS
@@ -182,6 +195,11 @@ config RT_USING_SPI
config RT_SFUD_USING_FLASH_INFO_TABLE
bool "Using defined supported flash chip information table"
default y
+
+ config RT_SFUD_USING_QSPI
+ bool "Using QSPI mode support"
+ select RT_USING_QSPI
+ default n
config RT_DEBUG_SFUD
bool "Show more SFUD debug information"
diff --git a/components/drivers/audio/audio.c b/components/drivers/audio/audio.c
index 14dddb38ea9803cdb3f1610c1af42dcb8f738f19..6a5ebc87415fcfae2ba586470c0ba9c94c11c506 100644
--- a/components/drivers/audio/audio.c
+++ b/components/drivers/audio/audio.c
@@ -105,8 +105,6 @@ static rt_err_t _audio_dev_init(struct rt_device *dev)
static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
{
- rt_err_t result = RT_EOK;
- rt_base_t level;
struct rt_audio_device *audio;
RT_ASSERT(dev != RT_NULL);
@@ -159,7 +157,6 @@ static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
//init pipe for record
{
- rt_size_t size = CFG_AUDIO_RECORD_PIPE_SIZE;
rt_uint8_t *buf = rt_malloc(CFG_AUDIO_RECORD_PIPE_SIZE);
if (buf == RT_NULL)
@@ -170,7 +167,7 @@ static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
return -RT_ENOMEM;
}
- rt_audio_pipe_init(&audio_pipe, "recpipe", RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD, buf,
+ rt_audio_pipe_init(&audio_pipe, "recpipe", (rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD), buf,
CFG_AUDIO_RECORD_PIPE_SIZE);
}
@@ -536,8 +533,6 @@ void rt_audio_tx_complete(struct rt_audio_device *audio, rt_uint8_t *pbuf)
void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len)
{
- rt_err_t result = RT_EOK;
-
//save data to record pipe
rt_device_write(RT_DEVICE(RT_DEVICE(&audio_pipe)), 0, pbuf, len);
diff --git a/components/drivers/audio/audio_pipe.c b/components/drivers/audio/audio_pipe.c
index 242305e20457d50958f4f0484f6b84f1230df885..4df9fd8a49bba87b7ced38a5a3853653f12be717 100644
--- a/components/drivers/audio/audio_pipe.c
+++ b/components/drivers/audio/audio_pipe.c
@@ -188,7 +188,7 @@ static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
}
#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops audio_pipe_ops
+const static struct rt_device_ops audio_pipe_ops =
{
RT_NULL,
RT_NULL,
@@ -213,7 +213,7 @@ const static struct rt_device_ops audio_pipe_ops
*/
rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
const char *name,
- enum rt_audio_pipe_flag flag,
+ rt_int32_t flag,
rt_uint8_t *buf,
rt_size_t size)
{
@@ -258,7 +258,7 @@ rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe)
}
#ifdef RT_USING_HEAP
-rt_err_t rt_audio_pipe_create(const char *name, enum rt_audio_pipe_flag flag, rt_size_t size)
+rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size)
{
rt_uint8_t *rb_memptr = RT_NULL;
struct rt_audio_pipe *pipe = RT_NULL;
diff --git a/components/drivers/audio/audio_pipe.h b/components/drivers/audio/audio_pipe.h
index c34f72b019b8fae467eb7453a27afdc8b06110ca..85a3eb17933f01aec601c482be63aaec6bc8b22c 100644
--- a/components/drivers/audio/audio_pipe.h
+++ b/components/drivers/audio/audio_pipe.h
@@ -50,7 +50,7 @@ struct rt_audio_pipe
/* ring buffer in pipe device */
struct rt_ringbuffer ringbuffer;
- enum rt_audio_pipe_flag flag;
+ rt_int32_t flag;
/* suspended list */
rt_list_t suspended_read_list;
@@ -64,12 +64,12 @@ struct rt_audio_pipe
rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
const char *name,
- enum rt_audio_pipe_flag flag,
+ rt_int32_t flag,
rt_uint8_t *buf,
rt_size_t size);
rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe);
#ifdef RT_USING_HEAP
-rt_err_t rt_audio_pipe_create(const char *name, enum rt_audio_pipe_flag flag, rt_size_t size);
+rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size);
void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe);
#endif
#endif
diff --git a/components/drivers/hwtimer/README_CN.md b/components/drivers/hwtimer/README_CN.md
index fb3b4fa60a25b8a21e17448b73b2870d0f5dce43..810b1b1d80bff4d751ccaac916490234c16b44b8 100644
--- a/components/drivers/hwtimer/README_CN.md
+++ b/components/drivers/hwtimer/README_CN.md
@@ -1,17 +1,16 @@
-定时器设备
-===
-
-##功能
----
+# 定时器设备
+
+## 功能
+
* 时间测量
* 周期或单次执行回调函数
-##编译
----
+## 编译
+
1. 在rtconfig.h添加 `#define RT_USING_HWTIMER`
-
-##使用流程
----
+
+## 使用流程
+
1. 以读写方式打开设备
2. 设置超时回调函数(如果需要)
3. 根据需要设置定时模式(单次/周期)
@@ -19,12 +18,12 @@
5. 写入超时值,定时器随即启动
6. 停止定时器(可选)
7. 关闭设备(如果需要)
-
+
应用参考 [hwtimer_test] (/examples/test/hwtimer\_test.c)
-##驱动编写指南
----
-###操作接口
+## 驱动编写指南
+
+### 操作接口
```
struct rt_hwtimer_ops
@@ -43,8 +42,8 @@ struct rt_hwtimer_ops
* count_get - <读取计数器值>
* control - <设置计数频率 >
-###定时器特征信息
-
+### 定时器特征信息
+
```
struct rt_hwtimer_info
{
@@ -60,7 +59,8 @@ struct rt_hwtimer_info
* maxcnt <计数器最大计数值>
* cntmode <递增计数/递减计数>
-###注册设备
+### 注册设备
+
```
static rt_hwtimer_t _timer0;
int stm32_hwtimer_init(void)
@@ -73,8 +73,9 @@ int stm32_hwtimer_init(void)
return 0;
}
```
-
-###定时器中断
+
+### 定时器中断
+
```
void timer_irq_handler(void)
{
@@ -84,15 +85,13 @@ void timer_irq_handler(void)
}
```
-##注意事项
----
-
-可能出现定时误差
-
+## 注意事项
+
+**可能出现定时误差**
误差原因:
假设计数器最大值0xFFFF,计数频率1Mhz,定时时间1秒又1微秒。
-
+
由于定时器一次最多只能计时到65535us,对于1000001us的定时要求。
可以50000us定时20次完成,此时将会出现计算误差1us。
diff --git a/components/drivers/hwtimer/hwtimer.c b/components/drivers/hwtimer/hwtimer.c
index cd85b3baefca170b8278863bbaf90d7e83262d69..83a76c7b9d8e31dde95e47a8bfed576d8ebef2ab 100644
--- a/components/drivers/hwtimer/hwtimer.c
+++ b/components/drivers/hwtimer/hwtimer.c
@@ -153,7 +153,7 @@ static rt_size_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buff
cnt = timer->ops->count_get(timer);
if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
{
- cnt = timer->info->maxcnt - cnt;
+ cnt = (timer->freq * timer->period_sec) - cnt;
}
t = timer->overflow * timer->period_sec + cnt/(float)timer->freq;
diff --git a/components/drivers/include/drivers/adc.h b/components/drivers/include/drivers/adc.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e3498e7910f8e9d647291b9a8d9c6e58d74304e
--- /dev/null
+++ b/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
+
+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__ */
diff --git a/components/drivers/include/drivers/serial.h b/components/drivers/include/drivers/serial.h
index af5d6262516875ef30f216d855d9b5f398290c03..45095af63f36f5749154fa1055731975804db884 100644
--- a/components/drivers/include/drivers/serial.h
+++ b/components/drivers/include/drivers/serial.h
@@ -100,7 +100,7 @@ struct serial_configure
rt_uint32_t bit_order :1;
rt_uint32_t invert :1;
rt_uint32_t bufsz :16;
- rt_uint32_t reserved :4;
+ rt_uint32_t reserved :6;
};
/*
diff --git a/components/drivers/include/drivers/spi.h b/components/drivers/include/drivers/spi.h
index 84b589ace0f0efa91df34f7902bf28d398bf6224..04a65421a53cada4a3227e8f6a8f343f76452598 100644
--- a/components/drivers/include/drivers/spi.h
+++ b/components/drivers/include/drivers/spi.h
@@ -45,6 +45,9 @@ extern "C"{
#define RT_SPI_MODE_MASK (RT_SPI_CPHA | RT_SPI_CPOL | RT_SPI_MSB)
+#define RT_SPI_BUS_MODE_SPI (1<<0)
+#define RT_SPI_BUS_MODE_QSPI (1<<1)
+
#define RT_SPI_CS_HIGH (1<<4) /* Chipselect active high */
#define RT_SPI_NO_CS (1<<5) /* No chipselect */
#define RT_SPI_3WIRE (1<<6) /* SI/SO pin shared */
@@ -80,6 +83,7 @@ struct rt_spi_ops;
struct rt_spi_bus
{
struct rt_device parent;
+ rt_uint8_t mode;
const struct rt_spi_ops *ops;
struct rt_mutex lock;
@@ -106,6 +110,55 @@ struct rt_spi_device
struct rt_spi_configuration config;
void *user_data;
};
+
+struct rt_qspi_message
+{
+ struct rt_spi_message parent;
+
+ /* instruction stage */
+ struct
+ {
+ rt_uint8_t content;
+ rt_uint8_t qspi_lines;
+ } instruction;
+
+ /* address and alternate_bytes stage */
+ struct
+ {
+ rt_uint32_t content;
+ rt_uint8_t size;
+ rt_uint8_t qspi_lines;
+ } address, alternate_bytes;
+
+ /* dummy_cycles stage */
+ rt_uint32_t dummy_cycles;
+
+ /* number of lines in qspi data stage, the other configuration items are in parent */
+ rt_uint8_t qspi_data_lines;
+};
+
+struct rt_qspi_configuration
+{
+ struct rt_spi_configuration parent;
+ /* The size of medium */
+ rt_uint32_t medium_size;
+ /* double data rate mode */
+ rt_uint8_t ddr_mode;
+ /* the data lines max width which QSPI bus supported, such as 1, 2, 4 */
+ rt_uint8_t qspi_dl_width ;
+};
+
+struct rt_qspi_device
+{
+ struct rt_spi_device parent;
+
+ struct rt_qspi_configuration config;
+
+ void (*enter_qspi_mode)(struct rt_qspi_device *device);
+
+ void (*exit_qspi_mode)(struct rt_qspi_device *device);
+};
+
#define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev))
/* register a SPI bus */
@@ -255,6 +308,61 @@ rt_inline void rt_spi_message_append(struct rt_spi_message *list,
message->next = RT_NULL;
}
+/**
+ * This function can set configuration on QSPI device.
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param cfg the configuration pointer.
+ *
+ * @return the actual length of transmitted.
+ */
+rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg);
+
+/**
+ * This function can register a SPI bus for QSPI mode.
+ *
+ * @param bus the SPI bus for QSPI mode.
+ * @param name The name of the spi bus.
+ * @param ops the SPI bus instance to be registered.
+ *
+ * @return the actual length of transmitted.
+ */
+rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops);
+
+/**
+ * This function transmits data to QSPI device.
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param message the message pointer.
+ *
+ * @return the actual length of transmitted.
+ */
+rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message);
+
+/**
+ * This function can send data then receive data from QSPI device
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param send_buf the buffer to be transmitted to QSPI device.
+ * @param send_length the number of data to be transmitted.
+ * @param recv_buf the buffer to be recivied from QSPI device.
+ * @param recv_length the data to be recivied.
+ *
+ * @return the status of transmit.
+ */
+rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length,void *recv_buf, rt_size_t recv_length);
+
+/**
+ * This function can send data to QSPI device
+ *
+ * @param device the QSPI device attached to QSPI bus.
+ * @param send_buf the buffer to be transmitted to QSPI device.
+ * @param send_length the number of data to be transmitted.
+ *
+ * @return the status of transmit.
+ */
+rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length);
+
#ifdef __cplusplus
}
#endif
diff --git a/components/drivers/include/ipc/ringblk_buf.h b/components/drivers/include/ipc/ringblk_buf.h
index 653fa2a60bbd3323eb3f2615d21d625694ff4d54..94fc2cfff33c8fa96263197ee998a11aedc924a1 100644
--- a/components/drivers/include/ipc/ringblk_buf.h
+++ b/components/drivers/include/ipc/ringblk_buf.h
@@ -84,6 +84,8 @@ rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb);
rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size);
void rt_rbb_blk_put(rt_rbb_blk_t block);
rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb);
+rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block);
+rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block);
void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block);
/* rbb block queue API */
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index 1843432768d944ba96b083fb1133c34384f3c89b..d59b40cc47d4e00d30e14509dec20765b45f26cb 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -99,6 +99,10 @@ extern "C" {
#include "drivers/cputime.h"
#endif
+#ifdef RT_USING_ADC
+#include "drivers/adc.h"
+#endif
+
#ifdef RT_USING_PWM
#include "drivers/rt_drv_pwm.h"
#endif
diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript
index 4cc5f80084c8ee2f938e87d240e5e89a488a6e79..c45ba524c5d2a1d2f79831d56402d3d526cd4abf 100644
--- a/components/drivers/misc/SConscript
+++ b/components/drivers/misc/SConscript
@@ -7,7 +7,10 @@ group = []
if GetDepend(['RT_USING_PIN']):
src = src + ['pin.c']
-
+
+if GetDepend(['RT_USING_ADC']):
+ src = src + ['adc.c']
+
if GetDepend(['RT_USING_PWM']):
src = src + ['rt_drv_pwm.c']
diff --git a/components/drivers/misc/adc.c b/components/drivers/misc/adc.c
new file mode 100644
index 0000000000000000000000000000000000000000..83e789a6e4271d004e80302c174522eba5f6ff68
--- /dev/null
+++ b/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
+#include
+
+#include
+#include
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "adc"
+#define DBG_LEVEL DBG_INFO
+#define DBG_COLOR
+#include
+
+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 - probe adc by name\n");
+ }
+ }
+ else
+ {
+ if (adc_device == RT_NULL)
+ {
+ rt_kprintf("Please using 'adc probe ' 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 - 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 - 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 - disable adc channel\n");
+ }
+ }
+ else
+ {
+ rt_kprintf("Unknown command. Please enter 'adc' for help\n");
+ }
+ }
+ }
+ else
+ {
+ rt_kprintf("Usage: \n");
+ rt_kprintf("adc probe - probe adc by name\n");
+ rt_kprintf("adc read - read adc value on the channel\n");
+ rt_kprintf("adc disable - disable adc channel\n");
+ rt_kprintf("adc enable - enable adc channel\n");
+ result = -RT_ERROR;
+ }
+ return RT_EOK;
+}
+MSH_CMD_EXPORT(adc, adc function);
+
+#endif /* FINSH_USING_MSH */
diff --git a/components/drivers/misc/rt_drv_pwm.c b/components/drivers/misc/rt_drv_pwm.c
index 6890e0e7932b72d926879708df2961b2d4e36cd4..2b7986b4d80ec371c4f2adc539c26ea9d2f37ce6 100644
--- a/components/drivers/misc/rt_drv_pwm.c
+++ b/components/drivers/misc/rt_drv_pwm.c
@@ -88,21 +88,36 @@ static rt_size_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, r
return size;
}
+#ifdef RT_USING_DEVICE_OPS
+static const struct rt_device_ops pwm_device_ops =
+{
+ RT_NULL,
+ RT_NULL,
+ RT_NULL,
+ _pwm_read,
+ _pwm_write,
+ _pwm_control
+};
+#endif /* RT_USING_DEVICE_OPS */
+
rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data)
{
rt_err_t result = RT_EOK;
memset(device, 0, sizeof(struct rt_device_pwm));
- device->parent.type = RT_Device_Class_Miscellaneous;
-
- device->parent.init = RT_NULL;
- device->parent.open = RT_NULL;
- device->parent.close = RT_NULL;
- device->parent.read = _pwm_read;
- device->parent.write = _pwm_write;
- device->parent.control = _pwm_control;
+#ifdef RT_USING_DEVICE_OPS
+ device->parent.ops = &pwm_device_ops;
+#else
+ device->parent.init = RT_NULL;
+ device->parent.open = RT_NULL;
+ device->parent.close = RT_NULL;
+ device->parent.read = _pwm_read;
+ device->parent.write = _pwm_write;
+ device->parent.control = _pwm_control;
+#endif /* RT_USING_DEVICE_OPS */
+ device->parent.type = RT_Device_Class_Miscellaneous;
device->ops = ops;
device->parent.user_data = (void *)user_data;
diff --git a/components/drivers/pm/pm.c b/components/drivers/pm/pm.c
index 655c4b4c02e180e7141729685142a436012c46f9..c300414444e651024f284fefcd6035d8f02274f1 100644
--- a/components/drivers/pm/pm.c
+++ b/components/drivers/pm/pm.c
@@ -151,11 +151,10 @@ void rt_pm_enter(void)
/* enter sleep and wait to be waken up */
pm->ops->enter(pm);
- rt_hw_interrupt_enable(level);
-
/* exit from low power mode */
rt_pm_exit();
+ rt_hw_interrupt_enable(level);
return ;
}
}
diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c
index 959d8444c10b7c3a53edb1724be21d502608a0e7..c5932df7d9db6eeb914db216b189b97e164f1e5a 100644
--- a/components/drivers/serial/serial.c
+++ b/components/drivers/serial/serial.c
@@ -21,6 +21,7 @@
* 2017-11-07 JasonJia fix data bits error issue when using tcsetattr.
* 2017-11-15 JasonJia fix poll rx issue when data is full.
* add TCFLSH and FIONREAD support.
+ * 2018-12-08 Ernest Chen add DMA choice
*/
#include
@@ -328,6 +329,7 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
return size - length;
}
+#if defined(RT_USING_POSIX) || defined(RT_SERIAL_USING_DMA)
static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial)
{
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
@@ -350,7 +352,9 @@ static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial)
}
}
}
+#endif /* RT_USING_POSIX || RT_SERIAL_USING_DMA */
+#ifdef RT_SERIAL_USING_DMA
/**
* Calculate DMA received data length.
*
@@ -527,6 +531,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
return 0;
}
}
+#endif /* RT_SERIAL_USING_DMA */
/* RT-Thread Device Interface */
/*
@@ -561,11 +566,13 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
LOG_D("open serial device: 0x%08x with open flag: 0x%04x",
dev, oflag);
+#ifdef RT_SERIAL_USING_DMA
/* check device flag with the open flag */
if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
return -RT_EIO;
if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
return -RT_EIO;
+#endif /* RT_SERIAL_USING_DMA */
if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
return -RT_EIO;
if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
@@ -580,8 +587,27 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
/* initialize the Rx/Tx structure according to open flag */
if (serial->serial_rx == RT_NULL)
- {
- if (oflag & RT_DEVICE_FLAG_DMA_RX)
+ {
+ if (oflag & RT_DEVICE_FLAG_INT_RX)
+ {
+ struct rt_serial_rx_fifo* rx_fifo;
+
+ rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
+ serial->config.bufsz);
+ RT_ASSERT(rx_fifo != RT_NULL);
+ rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
+ rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
+ rx_fifo->put_index = 0;
+ rx_fifo->get_index = 0;
+ rx_fifo->is_full = RT_FALSE;
+
+ serial->serial_rx = rx_fifo;
+ dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
+ /* configure low level device */
+ serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
+ }
+#ifdef RT_SERIAL_USING_DMA
+ else if (oflag & RT_DEVICE_FLAG_DMA_RX)
{
if (serial->config.bufsz == 0) {
struct rt_serial_rx_dma* rx_dma;
@@ -608,24 +634,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
}
dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
}
- else if (oflag & RT_DEVICE_FLAG_INT_RX)
- {
- struct rt_serial_rx_fifo* rx_fifo;
-
- rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
- serial->config.bufsz);
- RT_ASSERT(rx_fifo != RT_NULL);
- rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
- rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
- rx_fifo->put_index = 0;
- rx_fifo->get_index = 0;
- rx_fifo->is_full = RT_FALSE;
-
- serial->serial_rx = rx_fifo;
- dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
- /* configure low level device */
- serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
- }
+#endif /* RT_SERIAL_USING_DMA */
else
{
serial->serial_rx = RT_NULL;
@@ -633,28 +642,17 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
}
else
{
- if (oflag & RT_DEVICE_FLAG_DMA_RX)
- dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
- else if (oflag & RT_DEVICE_FLAG_INT_RX)
+ if (oflag & RT_DEVICE_FLAG_INT_RX)
dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
+#ifdef RT_SERIAL_USING_DMA
+ else if (oflag & RT_DEVICE_FLAG_DMA_RX)
+ dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
+#endif /* RT_SERIAL_USING_DMA */
}
if (serial->serial_tx == RT_NULL)
{
- if (oflag & RT_DEVICE_FLAG_DMA_TX)
- {
- struct rt_serial_tx_dma* tx_dma;
-
- tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
- RT_ASSERT(tx_dma != RT_NULL);
- tx_dma->activated = RT_FALSE;
-
- rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
- serial->serial_tx = tx_dma;
-
- dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
- }
- else if (oflag & RT_DEVICE_FLAG_INT_TX)
+ if (oflag & RT_DEVICE_FLAG_INT_TX)
{
struct rt_serial_tx_fifo *tx_fifo;
@@ -668,6 +666,21 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
/* configure low level device */
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
}
+#ifdef RT_SERIAL_USING_DMA
+ else if (oflag & RT_DEVICE_FLAG_DMA_TX)
+ {
+ struct rt_serial_tx_dma* tx_dma;
+
+ tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
+ RT_ASSERT(tx_dma != RT_NULL);
+ tx_dma->activated = RT_FALSE;
+
+ rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
+ serial->serial_tx = tx_dma;
+
+ dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
+ }
+#endif /* RT_SERIAL_USING_DMA */
else
{
serial->serial_tx = RT_NULL;
@@ -675,10 +688,12 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
}
else
{
- if (oflag & RT_DEVICE_FLAG_DMA_TX)
- dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
- else if (oflag & RT_DEVICE_FLAG_INT_TX)
+ if (oflag & RT_DEVICE_FLAG_INT_TX)
dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
+#ifdef RT_SERIAL_USING_DMA
+ else if (oflag & RT_DEVICE_FLAG_DMA_TX)
+ dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
+#endif /* RT_SERIAL_USING_DMA */
}
/* set stream flag */
@@ -710,6 +725,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
/* configure low level device */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_RX);
}
+#ifdef RT_SERIAL_USING_DMA
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
{
if (serial->config.bufsz == 0) {
@@ -732,7 +748,8 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
serial->serial_rx = RT_NULL;
dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
}
-
+#endif /* RT_SERIAL_USING_DMA */
+
if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
{
struct rt_serial_tx_fifo* tx_fifo;
@@ -746,6 +763,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
/* configure low level device */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX);
}
+#ifdef RT_SERIAL_USING_DMA
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
{
struct rt_serial_tx_dma* tx_dma;
@@ -757,7 +775,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
serial->serial_tx = RT_NULL;
dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX;
}
-
+#endif /* RT_SERIAL_USING_DMA */
return RT_EOK;
}
@@ -777,10 +795,12 @@ static rt_size_t rt_serial_read(struct rt_device *dev,
{
return _serial_int_rx(serial, buffer, size);
}
+#ifdef RT_SERIAL_USING_DMA
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
{
return _serial_dma_rx(serial, buffer, size);
}
+#endif /* RT_SERIAL_USING_DMA */
return _serial_poll_rx(serial, buffer, size);
}
@@ -801,10 +821,12 @@ static rt_size_t rt_serial_write(struct rt_device *dev,
{
return _serial_int_tx(serial, buffer, size);
}
+#ifdef RT_SERIAL_USING_DMA
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX)
{
return _serial_dma_tx(serial, buffer, size);
}
+#endif /* RT_SERIAL_USING_DMA */
else
{
return _serial_poll_tx(serial, buffer, size);
@@ -1181,12 +1203,13 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
rt_completion_done(&(tx_fifo->completion));
break;
}
+#ifdef RT_SERIAL_USING_DMA
case RT_SERIAL_EVENT_TX_DMADONE:
{
const void *data_ptr;
rt_size_t data_size;
const void *last_data_ptr;
- struct rt_serial_tx_dma* tx_dma;
+ struct rt_serial_tx_dma *tx_dma;
tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
@@ -1246,6 +1269,7 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
}
break;
}
+#endif /* RT_SERIAL_USING_DMA */
}
}
diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript
index ee423c33db428305c8dae0cd1684e9f330630115..b88671ebc93e8a554bf262efbf495663f98dbb1a 100644
--- a/components/drivers/spi/SConscript
+++ b/components/drivers/spi/SConscript
@@ -6,6 +6,9 @@ src = ['spi_core.c', 'spi_dev.c']
CPPPATH = [cwd, cwd + '/../include']
LOCAL_CCFLAGS = ''
+if GetDepend('RT_USING_QSPI'):
+ src += ['qspi_core.c']
+
src_device = []
if GetDepend('RT_USING_SPI_WIFI'):
diff --git a/components/drivers/spi/qspi_core.c b/components/drivers/spi/qspi_core.c
new file mode 100644
index 0000000000000000000000000000000000000000..c9ff6a963799a9b179d907236fb044029f20b843
--- /dev/null
+++ b/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
+
+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;
+}
diff --git a/components/drivers/spi/sfud/README.md b/components/drivers/spi/sfud/README.md
index 7394321243522852bf7ad1274383701aaee2bb5b..c732d06dbe6773ebda1a00c4536240877ec06869 100644
--- a/components/drivers/spi/sfud/README.md
+++ b/components/drivers/spi/sfud/README.md
@@ -6,11 +6,13 @@
[SFUD](https://github.com/armink/SFUD) 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
-- 主要特点:面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
+- 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
- 资源占用
- 标准占用:RAM:0.2KB ROM:5.5KB
- 最小占用:RAM:0.1KB ROM:3.6KB
-- 设计思路:这里要首先跟大家介绍一个标准: **SFDP** ,它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数,如果该 Flash 不支持 SFDP,则查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/master/sfud/inc/sfud_flash_def.h#L110-L122) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。
+- 设计思路:
+ - **什么是 SFDP** :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。
+ - **不支持 SFDP 怎么办** :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/4bee2d0417a7ce853cc7aa3639b03fe825611fd9/sfud/inc/sfud_flash_def.h#L116-L142) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。
## 1、为什么选择 SFUD
@@ -23,37 +25,43 @@
### 2.1 已支持 Flash
-下表为所有在 Demo 平台上进行过真机测试的 Flash。目前 SFUD 提供的 **Flash 参数信息表** 只包括下表中 **不支持** SFDP 标准的 Flash,其他不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护** **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
-
-|型号|制造商|容量|最高速度|SFDP 标准|备注|
-|:--:|:----:|:--:|:--:|:--:|:--:|
-|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|已停产|
-|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持||
-|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持| by [slipperstree](https://github.com/slipperstree)|
-|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持||
-|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持| by [slipperstree](https://github.com/slipperstree)|
-|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持||
-|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持||
-|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持||
-|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持||
-|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持||
-|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持| by [JiapengLi](https://github.com/JiapengLi)|
-|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持||
-|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持| SST 已被 Microchip 收购|
-|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)|
-|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)|
-|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持||
-|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持||
-|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持| by [TanekLiang](https://github.com/TanekLiang) |
-|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持||
-|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持||
-|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持| by [yc_911](https://gitee.com/yc_911) |
-|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持||
-|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持||
-|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持||
-|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持||
-|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|SST 授权许可,会被识别为 SST25VF016B|
-|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|ADESTO 收购 Atmel 串行闪存产品线|
+下表为所有已在 Demo 平台上进行过真机测试过的 Flash。显示为 **不支持** SFDP 标准的 Flash 已经在 Flash 参数信息表中定义,更多不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护** **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。
+
+如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
+
+|型号|制造商|容量|最高速度|SFDP 标准|QSPI 模式|备注|
+|:--:|:----:|:--:|:--:|:--:|:--:|----|
+|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|双线|已停产|
+|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持|双线||
+|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持|双线| by [slipperstree](https://github.com/slipperstree)|
+|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持|未测试||
+|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持|未测试| by [slipperstree](https://github.com/slipperstree)|
+|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持|双线||
+|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持|四线||
+|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持|四线||
+|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持|四线||
+|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持|双线||
+|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持|未测试| by [JiapengLi](https://github.com/JiapengLi)|
+|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持|双线||
+|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持|不支持| SST 已被 Microchip 收购|
+|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)|
+|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)|
+|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持|不支持||
+|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持|未测试||
+|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持|未测试| by [TanekLiang](https://github.com/TanekLiang) |
+|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持|双线||
+|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持|双线||
+|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持|未测试| by [yc_911](https://gitee.com/yc_911) |
+|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持|未测试||
+|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持|双线||
+|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持|支持||
+|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持|不支持||
+|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|不支持|SST 授权许可,会被识别为 SST25VF016B|
+|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|不支持|ADESTO 收购 Atmel 串行闪存产品线|
+
+> 注:QSPI 模式中,双线表示支持双线快读,四线表示支持四线快读。
+>
+> 一般情况下,支持四线快读的 FLASH 也支持两线快读。
### 2.2 API 说明
@@ -63,7 +71,7 @@
将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。
-> 注意:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
+> **注意**:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
```C
sfud_err sfud_init(void)
@@ -79,7 +87,24 @@ sfud_err sfud_device_init(sfud_flash *flash)
|:----- |:----|
|flash |待初始化的 Flash 设备|
-#### 2.2.3 获取 Flash 设备对象
+#### 2.2.3 使能快速读模式(仅当 SFUD 开启 QSPI 模式后可用)
+
+当 SFUD 开启 QSPI 模式后,SFUD 中的 Flash 驱动支持使用 QSPI 总线进行通信。相比传统的 SPI 模式,使用 QSPI 能够加速 Flash 数据的读取,但当数据需要写入时,由于 Flash 本身的数据写入速度慢于 SPI 传输速度,所以 QSPI 模式下的数据写入速度提升并不明显。
+
+所以 SFUD 对于 QSPI 模式的支持仅限于快速读命令。通过该函数可以配置 Flash 所使用的 QSPI 总线的实际支持的数据线最大宽度,例如:1 线(默认值,即传统的 SPI 模式)、2 线、4 线。
+
+设置后,SFUD 会去结合当前设定的 QSPI 总线数据线宽度,去 [QSPI Flash 扩展信息表](https://github.com/armink/SFUD/blob/069d2b409ec239f84d675b2c3d37894e908829e6/sfud/inc/sfud_flash_def.h#L149-L177) 中匹配最合适的、速度最快的快速读命令,之后用户在调用 sfud_read() 时,会使用 QSPI 模式的传输函数发送该命令。
+
+```C
+sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width)
+```
+
+| 参数 | 描述 |
+| :-------------- | :------------------------------------------- |
+| flash | Flash 设备 |
+| data_line_width | QSPI 总线支持的数据线最大宽度,例如:1、2、4 |
+
+#### 2.2.4 获取 Flash 设备对象
在 SFUD 配置文件中会定义 Flash 设备表,负责存放所有将要使用的 Flash 设备对象,所以 SFUD 支持多个 Flash 设备同时驱动。设备表的配置在 `/sfud/inc/sfud_cfg.h` 中 `SFUD_FLASH_DEVICE_TABLE` 宏定义,详细配置方法参照 [2.3 配置方法 Flash](#23-配置方法))。本方法通过 Flash 设备位于设备表中索引值来返回 Flash 设备对象,超出设备表范围返回 `NULL` 。
@@ -91,7 +116,7 @@ sfud_flash *sfud_get_device(size_t index)
|:----- |:----|
|index |Flash 设备位于 FLash 设备表中的索引值|
-#### 2.2.4 读取 Flash 数据
+#### 2.2.5 读取 Flash 数据
```C
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)
@@ -104,7 +129,7 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
|size |从起始地址开始读取数据的总大小|
|data |读取到的数据|
-#### 2.2.5 擦除 Flash 数据
+#### 2.2.6 擦除 Flash 数据
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
@@ -118,7 +143,7 @@ sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size)
|addr |起始地址|
|size |从起始地址开始擦除数据的总大小|
-#### 2.2.6 擦除 Flash 全部数据
+#### 2.2.7 擦除 Flash 全部数据
```C
sfud_err sfud_chip_erase(const sfud_flash *flash)
@@ -128,7 +153,7 @@ sfud_err sfud_chip_erase(const sfud_flash *flash)
|:----- |:----|
|flash |Flash 设备对象|
-#### 2.2.7 往 Flash 写数据
+#### 2.2.8 往 Flash 写数据
```C
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
@@ -141,7 +166,7 @@ sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const u
|size |从起始地址开始写入数据的总大小|
|data |待写入的数据|
-#### 2.2.8 先擦除再往 Flash 写数据
+#### 2.2.9 先擦除再往 Flash 写数据
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
@@ -156,7 +181,7 @@ sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, c
|size |从起始地址开始写入数据的总大小|
|data |待写入的数据|
-#### 2.2.9 读取 Flash 状态
+#### 2.2.10 读取 Flash 状态
```C
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
@@ -167,7 +192,7 @@ sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
|flash |Flash 设备对象|
|status |当前状态寄存器值|
-#### 2.2.10 写(修改) Flash 状态
+#### 2.2.11 写(修改) Flash 状态
```C
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status)
@@ -234,6 +259,12 @@ enum {
上面定义了两个 Flash 设备(大部分产品一个足以),两个设备的名称为 `"W25Q64CV"` 及 `"GD25Q64B"` ,分别对应 `"SPI1"` 及 `"SPI3"` 这两个 SPI 设备名称(在移植 SPI 接口时会用到,位于 `/sfud/port/sfud_port.c` ), `SFUD_W25Q16CV_DEVICE_INDEX` 与 `SFUD_GD25Q64B_DEVICE_INDEX` 这两个枚举定义了两个设备位于设备表中的索引,可以通过 `sfud_get_device_table()` 方法获取到设备表,再配合这个索引值来访问指定的设备。
+#### 2.3.6 QSPI 模式
+
+打开/关闭 `SFUD_USING_QSPI` 宏定义
+
+开启后,SFUD 也将支持使用 QSPI 总线连接的 Flash。
+
### 2.4 移植说明
移植文件位于 `/sfud/port/sfud_port.c` ,文件中的 `sfud_err sfud_spi_port_init(sfud_flash *flash)` 方法是库提供的移植方法,在里面完成各个设备 SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。更加详细的移植内容,可以参考 demo 中的各个平台的移植文件。
@@ -258,6 +289,7 @@ enum {
|:----- |:----|
|[/demo/stm32f10x_non_os](https://github.com/armink/SFUD/tree/master/demo/stm32f10x_non_os) |STM32F10X 裸机平台|
|[/demo/stm32f2xx_rtt](https://github.com/armink/SFUD/tree/master/demo/stm32f2xx_rtt) |STM32F2XX + [RT-Thread](http://www.rt-thread.org/) 操作系统平台|
+|[/demo/stm32l475_non_os_qspi](https://github.com/armink/SFUD/tree/master/demo/stm32l475_non_os_qspi) |STM32L475 + QSPI 模式 裸机平台|
### 2.7 许可
diff --git a/components/drivers/spi/sfud/inc/sfud.h b/components/drivers/spi/sfud/inc/sfud.h
index be1ccb208eb63a0ff1a62f786458e0e61c86b586..2b68c38216f707f8d20ae007529ec74c4e769ef4 100644
--- a/components/drivers/spi/sfud/inc/sfud.h
+++ b/components/drivers/spi/sfud/inc/sfud.h
@@ -1,7 +1,7 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
- * Copyright (c) 2016, Armink,
+ * Copyright (c) 2016-2018, Armink,
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -75,6 +75,23 @@ size_t sfud_get_device_num(void);
*/
const sfud_flash *sfud_get_device_table(void);
+#ifdef SFUD_USING_QSPI
+/**
+ * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
+ *
+ * it will find the appropriate fast-read instruction to replace the read instruction(0x03)
+ * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
+ *
+ * @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
+ *
+ * @param flash flash device
+ * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
+ *
+ * @return result
+ */
+sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width);
+#endif /* SFUD_USING_QSPI */
+
/**
* read flash data
*
diff --git a/components/drivers/spi/sfud/inc/sfud_cfg.h b/components/drivers/spi/sfud/inc/sfud_cfg.h
index 59189a9693da402949a0ce0e356f2cf03b7aac23..051de6d577fa943a55e75262b6fce4127b81add4 100644
--- a/components/drivers/spi/sfud/inc/sfud_cfg.h
+++ b/components/drivers/spi/sfud/inc/sfud_cfg.h
@@ -45,6 +45,13 @@
#define SFUD_USING_SFDP
#endif
+/**
+ * SFUD will support QSPI mode.
+ */
+#ifdef RT_SFUD_USING_QSPI
+#define SFUD_USING_QSPI
+#endif
+
/**
* Using probe flash JEDEC ID then query defined supported flash chip information table. @see SFUD_FLASH_CHIP_TABLE
*/
diff --git a/components/drivers/spi/sfud/inc/sfud_def.h b/components/drivers/spi/sfud/inc/sfud_def.h
index 1b0e8a3986331f3d6cd2e533fecf51f348df0859..fe7876618ba6b55362fe735b5c7a5d3f765ab07a 100644
--- a/components/drivers/spi/sfud/inc/sfud_def.h
+++ b/components/drivers/spi/sfud/inc/sfud_def.h
@@ -1,7 +1,7 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
- * Copyright (c) 2016, Armink,
+ * Copyright (c) 2016-2018, Armink,
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -78,7 +78,7 @@ if (!(EXPR)) \
else {if (__delay_temp) {__delay_temp();} retry --;}
/* software version number */
-#define SFUD_SW_VERSION "1.0.6"
+#define SFUD_SW_VERSION "1.1.0"
/*
* all defined supported command
*/
@@ -118,6 +118,22 @@ if (!(EXPR)) \
#define SFUD_CMD_READ_DATA 0x03
#endif
+#ifndef SFUD_CMD_DUAL_OUTPUT_READ_DATA
+#define SFUD_CMD_DUAL_OUTPUT_READ_DATA 0x3B
+#endif
+
+#ifndef SFUD_CMD_DUAL_IO_READ_DATA
+#define SFUD_CMD_DUAL_IO_READ_DATA 0xBB
+#endif
+
+#ifndef SFUD_CMD_QUAD_IO_READ_DATA
+#define SFUD_CMD_QUAD_IO_READ_DATA 0xEB
+#endif
+
+#ifndef SFUD_CMD_QUAD_OUTPUT_READ_DATA
+#define SFUD_CMD_QUAD_OUTPUT_READ_DATA 0x6B
+#endif
+
#ifndef SFUD_CMD_MANUFACTURER_DEVICE_ID
#define SFUD_CMD_MANUFACTURER_DEVICE_ID 0x90
#endif
@@ -183,6 +199,21 @@ typedef enum {
SFUD_ERR_ADDR_OUT_OF_BOUND = 5, /**< address is out of flash bound */
} sfud_err;
+#ifdef SFUD_USING_QSPI
+/**
+ * QSPI flash read cmd format
+ */
+typedef struct {
+ uint8_t instruction;
+ uint8_t instruction_lines;
+ uint8_t address_size;
+ uint8_t address_lines;
+ uint8_t alternate_bytes_lines;
+ uint8_t dummy_cycles;
+ uint8_t data_lines;
+} sfud_qspi_read_cmd_format;
+#endif /* SFUD_USING_QSPI */
+
/* SPI bus write read data function type */
typedef sfud_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size);
@@ -218,7 +249,12 @@ typedef struct __sfud_spi {
char *name;
/* SPI bus write read data function */
sfud_err (*wr)(const struct __sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
- size_t read_size);
+ size_t read_size);
+#ifdef SFUD_USING_QSPI
+ /* QSPI fast read function */
+ sfud_err (*qspi_read)(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format,
+ uint8_t *read_buf, size_t read_size);
+#endif
/* lock SPI bus */
void (*lock)(const struct __sfud_spi *spi);
/* unlock SPI bus */
@@ -243,6 +279,10 @@ typedef struct {
} retry;
void *user_data; /**< some user data */
+#ifdef SFUD_USING_QSPI
+ sfud_qspi_read_cmd_format read_cmd_format; /**< fast read cmd format */
+#endif
+
#ifdef SFUD_USING_SFDP
sfud_sfdp sfdp; /**< serial flash discoverable parameters by JEDEC standard */
#endif
diff --git a/components/drivers/spi/sfud/inc/sfud_flash_def.h b/components/drivers/spi/sfud/inc/sfud_flash_def.h
index 2022a043b2fe7f70c287d10995e9b4d3390a70de..89223755573b87a422d633f2bef934e5d35f2a12 100644
--- a/components/drivers/spi/sfud/inc/sfud_flash_def.h
+++ b/components/drivers/spi/sfud/inc/sfud_flash_def.h
@@ -1,7 +1,7 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
- * Copyright (c) 2016-2017, Armink,
+ * Copyright (c) 2016-2018, Armink,
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -59,11 +59,21 @@ typedef struct {
uint8_t type_id; /**< memory type ID */
uint8_t capacity_id; /**< capacity ID */
uint32_t capacity; /**< flash capacity (bytes) */
- uint16_t write_mode; /**< write mode @see sfud_write_mode */
+ uint16_t write_mode; /**< write mode @see sfud_write_mode */
uint32_t erase_gran; /**< erase granularity (bytes) */
uint8_t erase_gran_cmd; /**< erase granularity size block command */
} sfud_flash_chip;
+#ifdef SFUD_USING_QSPI
+/* QSPI flash chip's extended information compared with SPI flash */
+typedef struct {
+ uint8_t mf_id; /**< manufacturer ID */
+ uint8_t type_id; /**< memory type ID */
+ uint8_t capacity_id; /**< capacity ID */
+ uint8_t read_mode; /**< supported read mode on this qspi flash chip */
+} sfud_qspi_flash_ext_info;
+#endif
+
/* SFUD support manufacturer JEDEC ID */
#define SFUD_MF_ID_CYPRESS 0x01
#define SFUD_MF_ID_FUJITSU 0x04
@@ -131,6 +141,42 @@ typedef struct {
}
#endif /* SFUD_USING_FLASH_INFO_TABLE */
+#ifdef SFUD_USING_QSPI
+/* This table saves flash read-fast instructions in QSPI mode,
+ * SFUD can use this table to select the most appropriate read instruction for flash.
+ * | mf_id | type_id | capacity_id | qspi_read_mode |
+ */
+#define SFUD_FLASH_EXT_INFO_TABLE \
+{ \
+ /* W25Q40BV */ \
+ {SFUD_MF_ID_WINBOND, 0x40, 0x13, NORMAL_SPI_READ|DUAL_OUTPUT}, \
+ /* W25Q80JV */ \
+ {SFUD_MF_ID_WINBOND, 0x40, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT}, \
+ /* W25Q16BV */ \
+ {SFUD_MF_ID_WINBOND, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \
+ /* W25Q32BV */ \
+ {SFUD_MF_ID_WINBOND, 0x40, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \
+ /* W25Q64JV */ \
+ {SFUD_MF_ID_WINBOND, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
+ /* W25Q128JV */ \
+ {SFUD_MF_ID_WINBOND, 0x40, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
+ /* W25Q256FV */ \
+ {SFUD_MF_ID_WINBOND, 0x40, 0x19, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
+ /* EN25Q32B */ \
+ {SFUD_MF_ID_EON, 0x30, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT|QUAD_IO}, \
+ /* S25FL216K */ \
+ {SFUD_MF_ID_CYPRESS, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \
+ /* A25L080 */ \
+ {SFUD_MF_ID_AMIC, 0x30, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO}, \
+ /* A25LQ64 */ \
+ {SFUD_MF_ID_AMIC, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_IO}, \
+ /* MX25L3206E and KH25L3206E */ \
+ {SFUD_MF_ID_MICRONIX, 0x20, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \
+ /* GD25Q64B */ \
+ {SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT}, \
+}
+#endif /* SFUD_USING_QSPI */
+
#ifdef __cplusplus
}
#endif
diff --git a/components/drivers/spi/sfud/src/sfud.c b/components/drivers/spi/sfud/src/sfud.c
index e3376555ca909f192a5180b5bfa720847c9845f4..30e0d949f1e7ddcc2d56786c80edd96fa679b206 100644
--- a/components/drivers/spi/sfud/src/sfud.c
+++ b/components/drivers/spi/sfud/src/sfud.c
@@ -1,7 +1,7 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
- * Copyright (c) 2016, Armink,
+ * Copyright (c) 2016-2018, Armink,
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -46,6 +46,22 @@ static const sfud_mf mf_table[] = SFUD_MF_TABLE;
static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
#endif
+#ifdef SFUD_USING_QSPI
+/**
+ * flash read data mode
+ */
+enum sfud_qspi_read_mode {
+ NORMAL_SPI_READ = 1 << 0, /**< mormal spi read mode */
+ DUAL_OUTPUT = 1 << 1, /**< qspi fast read dual output */
+ DUAL_IO = 1 << 2, /**< qspi fast read dual input/output */
+ QUAD_OUTPUT = 1 << 3, /**< qspi fast read quad output */
+ QUAD_IO = 1 << 4, /**< qspi fast read quad input/output */
+};
+
+/* QSPI flash chip's extended information table */
+static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE;
+#endif /* SFUD_USING_QSPI */
+
static sfud_err software_init(const sfud_flash *flash);
static sfud_err hardware_init(sfud_flash *flash);
static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
@@ -146,11 +162,89 @@ const sfud_flash *sfud_get_device_table(void) {
return flash_table;
}
+#ifdef SFUD_USING_QSPI
+static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines,
+ uint8_t dummy_cycles, uint8_t data_lines) {
+ /* if medium size greater than 16Mb, use 4-Byte address, instruction should be added one */
+ if (flash->chip.capacity <= 0x1000000) {
+ flash->read_cmd_format.instruction = ins;
+ flash->read_cmd_format.address_size = 24;
+ } else {
+ flash->read_cmd_format.instruction = ins + 1;
+ flash->read_cmd_format.address_size = 32;
+ }
+
+ flash->read_cmd_format.instruction_lines = ins_lines;
+ flash->read_cmd_format.address_lines = addr_lines;
+ flash->read_cmd_format.alternate_bytes_lines = 0;
+ flash->read_cmd_format.dummy_cycles = dummy_cycles;
+ flash->read_cmd_format.data_lines = data_lines;
+}
+
+/**
+ * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
+ *
+ * it will find the appropriate fast-read instruction to replace the read instruction(0x03)
+ * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
+ *
+ * @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
+ *
+ * @param flash flash device
+ * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
+ *
+ * @return result
+ */
+sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
+ size_t i = 0;
+ uint8_t read_mode = NORMAL_SPI_READ;
+ sfud_err result = SFUD_SUCCESS;
+
+ SFUD_ASSERT(flash);
+ SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
+
+ /* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */
+ for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
+ if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
+ && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
+ && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
+ read_mode = qspi_flash_ext_info_table[i].read_mode;
+ }
+ }
+
+ /* determine qspi supports which read mode and set read_cmd_format struct */
+ switch (data_line_width) {
+ case 1:
+ qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
+ break;
+ case 2:
+ if (read_mode & DUAL_IO) {
+ qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 8, 2);
+ } else if (read_mode & DUAL_OUTPUT) {
+ qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
+ } else {
+ qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
+ }
+ break;
+ case 4:
+ if (read_mode & QUAD_IO) {
+ qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
+ } else if (read_mode & QUAD_OUTPUT) {
+ qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
+ } else {
+ qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
+ }
+ break;
+ }
+
+ return result;
+}
+#endif /* SFUD_USING_QSPI */
+
/**
* hardware initialize
*/
static sfud_err hardware_init(sfud_flash *flash) {
- extern sfud_err sfud_spi_port_init(sfud_flash *flash);
+ extern sfud_err sfud_spi_port_init(sfud_flash * flash);
sfud_err result = SFUD_SUCCESS;
size_t i;
@@ -162,6 +256,11 @@ static sfud_err hardware_init(sfud_flash *flash) {
return result;
}
+#ifdef SFUD_USING_QSPI
+ /* set default read instruction */
+ flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
+#endif /* SFUD_USING_QSPI */
+
/* SPI write read function must be initialize */
SFUD_ASSERT(flash->spi.wr);
/* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
@@ -315,10 +414,17 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
result = wait_busy(flash);
if (result == SFUD_SUCCESS) {
- cmd_data[0] = SFUD_CMD_READ_DATA;
- make_adress_byte_array(flash, addr, &cmd_data[1]);
- cmd_size = flash->addr_in_4_byte ? 5 : 4;
- result = spi->wr(spi, cmd_data, cmd_size, data, size);
+#ifdef SFUD_USING_QSPI
+ if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
+ result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
+ } else
+#endif
+ {
+ cmd_data[0] = SFUD_CMD_READ_DATA;
+ make_adress_byte_array(flash, addr, &cmd_data[1]);
+ cmd_size = flash->addr_in_4_byte ? 5 : 4;
+ result = spi->wr(spi, cmd_data, cmd_size, data, size);
+ }
}
/* unlock SPI */
if (spi->unlock) {
@@ -328,7 +434,6 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
return result;
}
-
/**
* erase all flash data
*
@@ -498,7 +603,8 @@ static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr,
const uint8_t *data) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
- uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE], cmd_size;
+ static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE];
+ uint8_t cmd_size;
size_t data_size;
SFUD_ASSERT(flash);
@@ -715,8 +821,16 @@ static sfud_err reset(const sfud_flash *flash) {
SFUD_ASSERT(flash);
cmd_data[0] = SFUD_CMD_ENABLE_RESET;
+ result = spi->wr(spi, cmd_data, 1, NULL, 0);
+ if (result == SFUD_SUCCESS) {
+ result = wait_busy(flash);
+ } else {
+ SFUD_INFO("Error: Flash device reset failed.");
+ return result;
+ }
+
cmd_data[1] = SFUD_CMD_RESET;
- result = spi->wr(spi, cmd_data, 2, NULL, 0);
+ result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);
if (result == SFUD_SUCCESS) {
result = wait_busy(flash);
diff --git a/components/drivers/spi/spi_core.c b/components/drivers/spi/spi_core.c
index 9e404d7c9480b1cdafeee2d8564c72d1b3eeee0a..64b0d2e4964482c6d0657f3af66eda20af40e737 100644
--- a/components/drivers/spi/spi_core.c
+++ b/components/drivers/spi/spi_core.c
@@ -34,6 +34,8 @@ rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus,
bus->ops = ops;
/* initialize owner */
bus->owner = RT_NULL;
+ /* set bus mode */
+ bus->mode = RT_SPI_BUS_MODE_SPI;
return RT_EOK;
}
diff --git a/components/drivers/spi/spi_flash_sfud.c b/components/drivers/spi/spi_flash_sfud.c
index e622527d7a9ec6082a32c8130d9c0b2ab8a74288..c8ff8f1b3bff69cd8ec42c7d8c7dffc4fd2d95e1 100644
--- a/components/drivers/spi/spi_flash_sfud.c
+++ b/components/drivers/spi/spi_flash_sfud.c
@@ -23,11 +23,21 @@
#ifndef RT_SFUD_DEFAULT_SPI_CFG
/* read the JEDEC SFDP command must run at 50 MHz or less */
-#define RT_SFUD_DEFAULT_SPI_CFG \
-{ \
- .mode = RT_SPI_MODE_0 | RT_SPI_MSB, \
- .data_width = 8, \
- .max_hz = 50 * 1000 * 1000, \
+#define RT_SFUD_DEFAULT_SPI_CFG \
+{ \
+ .mode = RT_SPI_MODE_0 | RT_SPI_MSB, \
+ .data_width = 8, \
+ .max_hz = 50 * 1000 * 1000, \
+}
+#endif
+
+#ifdef SFUD_USING_QSPI
+#define RT_SFUD_DEFAULT_QSPI_CFG \
+{ \
+ RT_SFUD_DEFAULT_SPI_CFG, \
+ .medium_size = 0x800000, \
+ .ddr_mode = 0, \
+ .qspi_dl_width = 4, \
}
#endif
@@ -116,31 +126,90 @@ static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, si
sfud_err result = SFUD_SUCCESS;
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
-
+#ifdef SFUD_USING_QSPI
+ struct rt_qspi_device *qspi_dev = RT_NULL;
+#endif
if (write_size) {
RT_ASSERT(write_buf);
}
if (read_size) {
RT_ASSERT(read_buf);
}
-
- if (write_size && read_size) {
- if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
- result = SFUD_ERR_TIMEOUT;
- }
- } else if (write_size) {
- if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) {
- result = SFUD_ERR_TIMEOUT;
+#ifdef SFUD_USING_QSPI
+ if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
+ qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
+ if (write_size && read_size) {
+ if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) == 0) {
+ result = SFUD_ERR_TIMEOUT;
+ }
+ } else if (write_size) {
+ if (rt_qspi_send(qspi_dev, write_buf, write_size) == 0) {
+ result = SFUD_ERR_TIMEOUT;
+ }
}
- } else {
- if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) {
- result = SFUD_ERR_TIMEOUT;
+ }
+ else
+#endif
+ {
+ if (write_size && read_size) {
+ if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
+ result = SFUD_ERR_TIMEOUT;
+ }
+ } else if (write_size) {
+ if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) {
+ result = SFUD_ERR_TIMEOUT;
+ }
+ } else {
+ if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) {
+ result = SFUD_ERR_TIMEOUT;
+ }
}
}
return result;
}
+#ifdef SFUD_USING_QSPI
+/**
+ * QSPI fast read data
+ */
+static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) {
+ struct rt_qspi_message message;
+ sfud_err result = SFUD_SUCCESS;
+
+ sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
+ struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
+ struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
+
+ /* set message struct */
+ message.instruction.content = qspi_read_cmd_format->instruction;
+ message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;
+
+ message.address.content = addr;
+ message.address.size = qspi_read_cmd_format->address_size;
+ message.address.qspi_lines = qspi_read_cmd_format->address_lines;
+
+ message.alternate_bytes.content = 0;
+ message.alternate_bytes.size = 0;
+ message.alternate_bytes.qspi_lines = 0;
+
+ message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;
+
+ message.parent.send_buf = RT_NULL;
+ message.parent.recv_buf = read_buf;
+ message.parent.length = read_size;
+ message.parent.cs_release = 1;
+ message.parent.cs_take = 1;
+ message.qspi_data_lines = qspi_read_cmd_format->data_lines;
+
+ if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
+ result = SFUD_ERR_TIMEOUT;
+ }
+
+ return result;
+}
+#endif
+
static void spi_lock(const sfud_spi *spi) {
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
@@ -203,6 +272,9 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
/* port SPI device interface */
flash->spi.wr = spi_write_read;
+#ifdef SFUD_USING_QSPI
+ flash->spi.qspi_read = qspi_read;
+#endif
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
flash->spi.user_data = flash;
@@ -213,8 +285,7 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
flash->retry.delay = retry_delay_100us;
/* 60 seconds timeout */
flash->retry.times = 60 * 10000;
-
-
+
return result;
}
@@ -246,6 +317,10 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
* @note you also can change the SPI to other configuration after initialized finish */
struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
extern sfud_err sfud_device_init(sfud_flash *flash);
+#ifdef SFUD_USING_QSPI
+ struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;
+ struct rt_qspi_device *qspi_dev = RT_NULL;
+#endif
RT_ASSERT(spi_flash_dev_name);
RT_ASSERT(spi_dev_name);
@@ -277,7 +352,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
goto error;
}
sfud_dev->spi.name = spi_dev_name_bak;
- rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
+
+#ifdef SFUD_USING_QSPI
+ /* set the qspi line number and configure the QSPI bus */
+ if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
+ qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
+ qspi_cfg.qspi_dl_width = qspi_dev->config.qspi_dl_width;
+ rt_qspi_configure(qspi_dev, &qspi_cfg);
+ }
+ else
+#endif
+ rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
}
/* SFUD flash device initialize */
{
@@ -296,6 +381,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
+#ifdef SFUD_USING_QSPI
+ /* reconfigure the QSPI bus for medium size */
+ if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
+ qspi_cfg.medium_size = sfud_dev->chip.capacity;
+ rt_qspi_configure(qspi_dev, &qspi_cfg);
+ if(qspi_dev->enter_qspi_mode != RT_NULL)
+ qspi_dev->enter_qspi_mode(qspi_dev);
+ }
+ /* set data lines width */
+ sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
+#endif /* SFUD_USING_QSPI */
}
/* register device */
@@ -402,14 +498,17 @@ static void sf(uint8_t argc, char **argv) {
} else {
char *spi_dev_name = argv[2];
rtt_dev_bak = rtt_dev;
+
+ /* delete the old SPI flash device */
+ if(rtt_dev_bak) {
+ rt_sfud_flash_delete(rtt_dev_bak);
+ }
+
rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
if (!rtt_dev) {
return;
}
- /* already probe then delete the old SPI flash device */
- if(rtt_dev_bak) {
- rt_sfud_flash_delete(rtt_dev_bak);
- }
+
sfud_dev = (sfud_flash_t)rtt_dev->user_data;
if (sfud_dev->chip.capacity < 1024 * 1024) {
rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
@@ -520,7 +619,7 @@ static void sf(uint8_t argc, char **argv) {
addr = 0;
size = sfud_dev->chip.capacity;
uint32_t start_time, time_cast;
- size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = 4096;
+ size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE;
uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
if (write_data && read_data) {
@@ -561,6 +660,13 @@ static void sf(uint8_t argc, char **argv) {
} else {
result = sfud_read(sfud_dev, addr + i, size - i, read_data);
}
+ /* data check */
+ if (memcmp(write_data, read_data, read_size))
+ {
+ rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
+ result = SFUD_ERR_READ;
+ }
+
if (result != SFUD_SUCCESS) {
break;
}
diff --git a/components/drivers/spi/spi_flash_sfud.h b/components/drivers/spi/spi_flash_sfud.h
index 3173b9786d89d76ec6e9ec71b255cb5e7beed673..af1ed58790c16efc9a552fdadaebe530e1fbcae7 100644
--- a/components/drivers/spi/spi_flash_sfud.h
+++ b/components/drivers/spi/spi_flash_sfud.h
@@ -12,6 +12,7 @@
#define _SPI_FLASH_SFUD_H_
#include
+#include
#include "./sfud/inc/sfud.h"
#include "spi_flash.h"
diff --git a/components/drivers/spi/spi_msd.c b/components/drivers/spi/spi_msd.c
index ed121e184decbc0a8b93bb18aa786572e8a9763b..a109fd94888e58e776c3f931e2a88e0db5bc8309 100644
--- a/components/drivers/spi/spi_msd.c
+++ b/components/drivers/spi/spi_msd.c
@@ -37,8 +37,6 @@ static struct msd_device _msd_device;
static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long);
static rt_err_t MSD_take_owner(struct rt_spi_device *spi_device);
-static void MSD_take_cs(struct rt_spi_device *device);
-static void MSD_release_cs(struct rt_spi_device *device);
static rt_err_t _wait_token(struct rt_spi_device *device, uint8_t token);
static rt_err_t _wait_ready(struct rt_spi_device *device);
@@ -73,36 +71,6 @@ static rt_err_t MSD_take_owner(struct rt_spi_device *spi_device)
return result;
}
-static void MSD_take_cs(struct rt_spi_device *device)
-{
- struct rt_spi_message message;
-
- /* initial message */
- message.send_buf = RT_NULL;
- message.recv_buf = RT_NULL;
- message.length = 0;
- message.cs_take = 1;
- message.cs_release = 0;
-
- /* transfer message */
- device->bus->ops->xfer(device, &message);
-}
-
-static void MSD_release_cs(struct rt_spi_device *device)
-{
- struct rt_spi_message message;
-
- /* initial message */
- message.send_buf = RT_NULL;
- message.recv_buf = RT_NULL;
- message.length = 0;
- message.cs_take = 0;
- message.cs_release = 1;
-
- /* transfer message */
- device->bus->ops->xfer(device, &message);
-}
-
static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long)
{
rt_tick_t tick_end = tick_start + tick_long;
@@ -517,7 +485,7 @@ static rt_err_t rt_msd_init(rt_device_t dev)
goto _exit;
}
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
/* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and
start to supply at least 74 SD clocks to the SD card with keeping CMD line to high.
@@ -542,9 +510,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
while (1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response);
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
if ((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE))
{
@@ -568,9 +536,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
do
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, SEND_IF_COND, 0x01AA, 0x87, response_r7, response);
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
if (result == RT_EOK)
{
@@ -622,23 +590,23 @@ static rt_err_t rt_msd_init(rt_device_t dev)
/* try SD Ver1.x */
while (1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[info] It maybe SD1.x or MMC But it is Not response to CMD58!\r\n");
goto _exit;
}
if (0 != (response[0] & 0xFE))
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[info] It look CMD58 as illegal command so it is not SD card!\r\n");
break;
}
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
OCR = response[1];
OCR = (OCR << 8) + response[2];
@@ -661,24 +629,24 @@ static rt_err_t rt_msd_init(rt_device_t dev)
{
if (rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41)))
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[info] try CMD55 + ACMD41 timeout! mabey MMC card!\r\n");
break;
}
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
/* CMD55 APP_CMD */
result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response);
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
continue;
}
if (0 != (response[0] & 0xFE))
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[info] Not SD card2 , may be MMC\r\n");
break;
}
@@ -687,20 +655,20 @@ static rt_err_t rt_msd_init(rt_device_t dev)
result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x00, 0x00, response_r1, response);
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
continue;
}
if (0 != (response[0] & 0xFE))
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[info] Not SD card4 , may be MMC\r\n");
break;
}
if (0 == (response[0] & 0xFF))
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
is_sd_v1_x = RT_TRUE;
MSD_DEBUG("[info] It is Ver1.X SD Memory Card!!!\r\n");
break;
@@ -716,7 +684,7 @@ static rt_err_t rt_msd_init(rt_device_t dev)
uint32_t i;
MSD_DEBUG("[info] try MMC card!\r\n");
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
/* send dummy clock */
{
@@ -740,9 +708,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
tick_start = rt_tick_get();
while (1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response);
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
if ((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE))
{
@@ -761,9 +729,9 @@ static rt_err_t rt_msd_init(rt_device_t dev)
tick_start = rt_tick_get();
while (1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, SEND_OP_COND, 0x00, 0x00, response_r1, response);
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
if ((result == RT_EOK) && (response[0] == MSD_RESPONSE_NO_ERROR))
{
@@ -783,25 +751,25 @@ static rt_err_t rt_msd_init(rt_device_t dev)
}
else if (msd->card_type == MSD_CARD_TYPE_SD_V2_X)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to CMD58!\r\n");
goto _exit;
}
if ((response[0] & 0xFE) != 0)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] It look CMD58 as illegal command so it is not SD card!\r\n");
result = RT_ERROR;
goto _exit;
}
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
OCR = response[1];
OCR = (OCR << 8) + response[2];
@@ -822,10 +790,10 @@ static rt_err_t rt_msd_init(rt_device_t dev)
/* try CMD55 + ACMD41 */
do
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
if (rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41)))
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] SD Ver2.x or later try CMD55 + ACMD41 timeout!\r\n");
result = RT_ERROR;
goto _exit;
@@ -836,13 +804,13 @@ static rt_err_t rt_msd_init(rt_device_t dev)
// if((result != RT_EOK) || (response[0] == 0x01))
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
continue;
}
if ((response[0] & 0xFE) != 0)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] Not SD ready!\r\n");
result = RT_ERROR;
goto _exit;
@@ -852,7 +820,7 @@ static rt_err_t rt_msd_init(rt_device_t dev)
result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x40000000, 0x77, response_r1, response);
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] ACMD41 fail!\r\n");
result = RT_ERROR;
goto _exit;
@@ -860,33 +828,33 @@ static rt_err_t rt_msd_init(rt_device_t dev)
if ((response[0] & 0xFE) != 0)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[info] Not SD card4 , response : 0x%02X\r\n", response[0]);
// break;
}
}
while (response[0] != MSD_RESPONSE_NO_ERROR);
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
/* try CMD55 + ACMD41 */
/* --Read OCR again */
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response);
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to 2nd CMD58!\r\n");
goto _exit;
}
if ((response[0] & 0xFE) != 0)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] It look 2nd CMD58 as illegal command so it is not SD card!\r\n");
result = RT_ERROR;
goto _exit;
}
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
OCR = response[1];
OCR = (OCR << 8) + response[2];
@@ -933,14 +901,14 @@ static rt_err_t rt_msd_init(rt_device_t dev)
/* set CRC */
{
- MSD_release_cs(msd->spi_device);
- MSD_take_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
+ rt_spi_take(msd->spi_device);
#ifdef MSD_USE_CRC
result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x01, 0x83, response_r1, response);
#else
result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x00, 0x91, response_r1, response);
#endif
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
{
MSD_DEBUG("[err] CMD59 CRC_ON_OFF fail! response : 0x%02X\r\n", response[0]);
@@ -951,10 +919,10 @@ static rt_err_t rt_msd_init(rt_device_t dev)
/* CMD16 SET_BLOCKLEN */
{
- MSD_release_cs(msd->spi_device);
- MSD_take_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, SET_BLOCKLEN, SECTOR_SIZE, 0x00, response_r1, response);
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
{
MSD_DEBUG("[err] CMD16 SET_BLOCKLEN fail! response : 0x%02X\r\n", response[0]);
@@ -969,27 +937,27 @@ static rt_err_t rt_msd_init(rt_device_t dev)
{
uint8_t CSD_buffer[MSD_CSD_LEN];
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
// result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0xAF, response_r1, response);
result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0x00, response_r1, response);
if (result != RT_EOK)
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] CMD9 SEND_CSD timeout!\r\n");
goto _exit;
}
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
{
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
MSD_DEBUG("[err] CMD9 SEND_CSD fail! response : 0x%02X\r\n", response[0]);
result = RT_ERROR;
goto _exit;
}
result = _read_block(msd->spi_device, CSD_buffer, MSD_CSD_LEN);
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
if (result != RT_EOK)
{
MSD_DEBUG("[err] read CSD fail!\r\n");
@@ -1214,12 +1182,11 @@ static rt_err_t rt_msd_init(rt_device_t dev)
cfg.data_width = 8;
cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
cfg.max_hz = msd->max_clock;
-
rt_spi_configure(msd->spi_device, &cfg);
} /* config spi */
_exit:
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
rt_mutex_release(&(msd->spi_device->bus->lock));
return result;
}
@@ -1249,20 +1216,10 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
goto _exit;
}
- /* config spi to high speed */
- {
- struct rt_spi_configuration cfg;
- cfg.data_width = 8;
- cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
- cfg.max_hz = msd->max_clock;
-
- rt_spi_configure(msd->spi_device, &cfg);
- } /* config spi */
-
/* SINGLE_BLOCK? */
if (size == 1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1283,7 +1240,7 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
{
uint32_t i;
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1316,7 +1273,7 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
_exit:
/* release and exit */
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
rt_mutex_release(&(msd->spi_device->bus->lock));
return size;
@@ -1335,20 +1292,10 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r
goto _exit;
}
- /* config spi to high speed */
- {
- struct rt_spi_configuration cfg;
- cfg.data_width = 8;
- cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
- cfg.max_hz = msd->max_clock;
-
- rt_spi_configure(msd->spi_device, &cfg);
- } /* config spi */
-
/* SINGLE_BLOCK? */
if (size == 1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos, 0x00, response_r1, response);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1369,7 +1316,7 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r
{
uint32_t i;
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos, 0x00, response_r1, response);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
@@ -1402,7 +1349,7 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r
_exit:
/* release and exit */
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
rt_mutex_release(&(msd->spi_device->bus->lock));
return size;
@@ -1422,20 +1369,11 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer,
goto _exit;
}
- /* config spi to high speed */
- {
- struct rt_spi_configuration cfg;
- cfg.data_width = 8;
- cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
- cfg.max_hz = msd->max_clock;
-
- rt_spi_configure(msd->spi_device, &cfg);
- } /* config spi */
/* SINGLE_BLOCK? */
if (size == 1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
{
@@ -1456,7 +1394,7 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer,
struct rt_spi_message message;
uint32_t i;
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
#ifdef MSD_USE_PRE_ERASED
if (msd->card_type != MSD_CARD_TYPE_MMC)
@@ -1531,7 +1469,7 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer,
_exit:
/* release and exit */
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
rt_mutex_release(&(msd->spi_device->bus->lock));
return size;
@@ -1550,20 +1488,10 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu
goto _exit;
}
- /* config spi to high speed */
- {
- struct rt_spi_configuration cfg;
- cfg.data_width = 8;
- cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
- cfg.max_hz = msd->max_clock;
-
- rt_spi_configure(msd->spi_device, &cfg);
- } /* config spi */
-
/* SINGLE_BLOCK? */
if (size == 1)
{
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos, 0x00, response_r1, response);
if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR))
{
@@ -1584,7 +1512,7 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu
struct rt_spi_message message;
uint32_t i;
- MSD_take_cs(msd->spi_device);
+ rt_spi_take(msd->spi_device);
#ifdef MSD_USE_PRE_ERASED
/* CMD55 APP_CMD */
@@ -1655,7 +1583,7 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu
_exit:
/* release and exit */
- MSD_release_cs(msd->spi_device);
+ rt_spi_release(msd->spi_device);
rt_mutex_release(&(msd->spi_device->bus->lock));
return size;
diff --git a/components/drivers/src/ringblk_buf.c b/components/drivers/src/ringblk_buf.c
index 1a74bf1d2448462b1894d4fb9fa8c5d152b30682..74ced674fea2b8540f228ed4ae40a5a90fcc76b8 100644
--- a/components/drivers/src/ringblk_buf.c
+++ b/components/drivers/src/ringblk_buf.c
@@ -18,8 +18,10 @@
* @param rbb ring block buffer object
* @param buf buffer
* @param buf_size buffer size
- * @param block_set
- * @param blk_max_num
+ * @param block_set block set
+ * @param blk_max_num max block number
+ *
+ * @note When your application need align access, please make the buffer address is aligned.
*/
void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num)
{
@@ -123,6 +125,8 @@ static rt_rbb_blk_t find_empty_blk_in_set(rt_rbb_t rbb)
* @param rbb ring block buffer object
* @param blk_size block size
*
+ * @note When your application need align access, please make the blk_szie is aligned.
+ *
* @return != NULL: allocated block
* NULL: allocate failed
*/
@@ -133,7 +137,7 @@ rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size)
rt_rbb_blk_t head, tail, new = NULL;
RT_ASSERT(rbb);
- RT_ASSERT(blk_size < 1L << 24);
+ RT_ASSERT(blk_size < (1L << 24));
level = rt_hw_interrupt_disable();
@@ -277,6 +281,36 @@ __exit:
}
RTM_EXPORT(rt_rbb_blk_get);
+/**
+ * return the block size
+ *
+ * @param block the block
+ *
+ * @return block size
+ */
+rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block)
+{
+ RT_ASSERT(block);
+
+ return block->size;
+}
+RTM_EXPORT(rt_rbb_blk_size);
+
+/**
+ * return the block buffer
+ *
+ * @param block the block
+ *
+ * @return block buffer
+ */
+rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block)
+{
+ RT_ASSERT(block);
+
+ return block->buf;
+}
+RTM_EXPORT(rt_rbb_blk_buf);
+
/**
* free the block
*
diff --git a/components/drivers/usb/usbdevice/core/core.c b/components/drivers/usb/usbdevice/core/core.c
index fb850d6d2b154d7305cb3b9a13edfebc645ec345..4e3a3e9280006763b823a724f3b33e1adfbf5039 100644
--- a/components/drivers/usb/usbdevice/core/core.c
+++ b/components/drivers/usb/usbdevice/core/core.c
@@ -194,7 +194,18 @@ static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup)
_get_string_descriptor(device, setup);
break;
case USB_DESC_TYPE_DEVICEQUALIFIER:
- _get_qualifier_descriptor(device, setup);
+ /* If a full-speed only device (with a device descriptor version number equal to 0200H) receives a
+ GetDescriptor() request for a device_qualifier, it must respond with a request error. The host must not make
+ a request for an other_speed_configuration descriptor unless it first successfully retrieves the
+ device_qualifier descriptor. */
+ if(device->dcd->device_is_hs)
+ {
+ _get_qualifier_descriptor(device, setup);
+ }
+ else
+ {
+ rt_usbd_ep0_set_stall(device);
+ }
break;
case USB_DESC_TYPE_OTHERSPEED:
_get_config_descriptor(device, setup);
diff --git a/components/drivers/wlan/wlan_dev.c b/components/drivers/wlan/wlan_dev.c
index d86dfb25d350b9b0774cb1b03d886d0209c36f8a..0beac52aae4905b22f9a69f33a7d14b4badcae18 100644
--- a/components/drivers/wlan/wlan_dev.c
+++ b/components/drivers/wlan/wlan_dev.c
@@ -145,7 +145,10 @@ rt_err_t rt_wlan_dev_ap_start(struct rt_wlan_device *device, struct rt_wlan_info
rt_memset(&ap_info, 0, sizeof(struct rt_ap_info));
rt_memcpy(&ap_info.ssid, &info->ssid, sizeof(rt_wlan_ssid_t));
- rt_memcpy(ap_info.key.val, password, password_len);
+ if (password != RT_NULL)
+ {
+ rt_memcpy(ap_info.key.val, password, password_len);
+ }
ap_info.key.len = password_len;
ap_info.hidden = info->hidden;
ap_info.channel = info->channel;
@@ -184,13 +187,21 @@ rt_err_t rt_wlan_dev_ap_deauth(struct rt_wlan_device *device, rt_uint8_t mac[6])
int rt_wlan_dev_get_rssi(struct rt_wlan_device *device)
{
int rssi = 0;
+ rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
- return -RT_EIO;
+ rt_set_errno(-RT_EIO);
+ return 0;
+ }
+
+ result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_RSSI, &rssi);
+ if (result != RT_EOK)
+ {
+ rt_set_errno(result);
+ return 0;
}
- rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_RSSI, &rssi);
return rssi;
}
@@ -235,14 +246,20 @@ rt_err_t rt_wlan_dev_set_powersave(struct rt_wlan_device *device, int level)
int rt_wlan_dev_get_powersave(struct rt_wlan_device *device)
{
- int level = 0;
+ int level = -1;
+ rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
+ rt_set_errno(-RT_EIO);
return -1;
}
- rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_POWERSAVE, &level);
+ result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_POWERSAVE, &level);
+ if (result != RT_EOK)
+ {
+ rt_set_errno(result);
+ }
return level;
}
@@ -432,19 +449,21 @@ rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel)
return result;
}
-rt_err_t rt_wlan_dev_get_channel(struct rt_wlan_device *device)
+int rt_wlan_dev_get_channel(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
- int channel;
+ int channel = -1;
if (device == RT_NULL)
{
- return -RT_EIO;
+ rt_set_errno(-RT_EIO);
+ return -1;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_CHANNEL, &channel);
if (result != RT_EOK)
{
+ rt_set_errno(result);
return -1;
}
@@ -466,17 +485,19 @@ rt_err_t rt_wlan_dev_set_country(struct rt_wlan_device *device, rt_country_code_
rt_country_code_t rt_wlan_dev_get_country(struct rt_wlan_device *device)
{
- int result = 0;
+ int result = RT_EOK;
rt_country_code_t country_code = RT_COUNTRY_UNKNOWN;
if (device == RT_NULL)
{
- return country_code;
+ rt_set_errno(-RT_EIO);
+ return RT_COUNTRY_UNKNOWN;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_COUNTRY, &country_code);
if (result != RT_EOK)
{
+ rt_set_errno(result);
return RT_COUNTRY_UNKNOWN;
}
@@ -641,7 +662,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_POWERSAVE, "RT_WLAN_CMD_SET_POWERSAVE");
if (wlan->ops->wlan_set_powersave)
- wlan->ops->wlan_set_powersave(wlan, level);
+ err = wlan->ops->wlan_set_powersave(wlan, level);
break;
}
case RT_WLAN_CMD_GET_POWERSAVE:
@@ -659,7 +680,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_PROMISC, "RT_WLAN_CMD_CFG_PROMISC");
if (wlan->ops->wlan_cfg_promisc)
- wlan->ops->wlan_cfg_promisc(wlan, start);
+ err = wlan->ops->wlan_cfg_promisc(wlan, start);
break;
}
case RT_WLAN_CMD_CFG_FILTER:
@@ -668,7 +689,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_FILTER, "RT_WLAN_CMD_CFG_FILTER");
if (wlan->ops->wlan_cfg_filter)
- wlan->ops->wlan_cfg_filter(wlan, filter);
+ err = wlan->ops->wlan_cfg_filter(wlan, filter);
break;
}
case RT_WLAN_CMD_SET_CHANNEL:
@@ -676,7 +697,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
int channel = *(int *)args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_CHANNEL, "RT_WLAN_CMD_SET_CHANNEL");
if (wlan->ops->wlan_set_channel)
- wlan->ops->wlan_set_channel(wlan, channel);
+ err = wlan->ops->wlan_set_channel(wlan, channel);
break;
}
case RT_WLAN_CMD_GET_CHANNEL:
@@ -694,7 +715,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_COUNTRY, "RT_WLAN_CMD_SET_COUNTRY");
if (wlan->ops->wlan_set_country)
- wlan->ops->wlan_set_country(wlan, country);
+ err = wlan->ops->wlan_set_country(wlan, country);
break;
}
case RT_WLAN_CMD_GET_COUNTRY:
@@ -711,7 +732,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_MAC, "RT_WLAN_CMD_SET_MAC");
if (wlan->ops->wlan_set_mac)
- wlan->ops->wlan_set_mac(wlan, mac);
+ err = wlan->ops->wlan_set_mac(wlan, mac);
break;
}
case RT_WLAN_CMD_GET_MAC:
@@ -720,7 +741,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_MAC, "RT_WLAN_CMD_GET_MAC");
if (wlan->ops->wlan_get_mac)
- wlan->ops->wlan_get_mac(wlan, mac);
+ err = wlan->ops->wlan_get_mac(wlan, mac);
break;
}
default:
@@ -733,22 +754,16 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
return err;
}
-struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data)
+rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data)
{
- struct rt_wlan_device *wlan;
+ rt_err_t err = RT_EOK;
- if (name == RT_NULL || ops == RT_NULL)
+ if ((wlan == RT_NULL) || (name == RT_NULL) || (ops == RT_NULL))
{
LOG_E("F:%s L:%d parameter Wrongful", __FUNCTION__, __LINE__);
return RT_NULL;
}
- wlan = rt_malloc(sizeof(struct rt_wlan_device));
- if (wlan == RT_NULL)
- {
- LOG_E("F:%s L:%d", __FUNCTION__, __LINE__);
- return RT_NULL;
- }
rt_memset(wlan, 0, sizeof(struct rt_wlan_device));
wlan->device.init = _rt_wlan_dev_init;
@@ -765,9 +780,9 @@ struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wl
wlan->user_data = user_data;
wlan->flags = flag;
- rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR);
+ err = rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR);
LOG_D("F:%s L:%d run", __FUNCTION__, __LINE__);
- return wlan;
+ return err;
}
diff --git a/components/drivers/wlan/wlan_dev.h b/components/drivers/wlan/wlan_dev.h
index f46f3c001fd27f5b6f05703a5de9352b1f7dd2fc..a9300be9d79237bfe589485370065f439c0d0e5b 100644
--- a/components/drivers/wlan/wlan_dev.h
+++ b/components/drivers/wlan/wlan_dev.h
@@ -559,7 +559,7 @@ rt_err_t rt_wlan_dev_cfg_filter(struct rt_wlan_device *device, struct rt_wlan_fi
* wlan device channel interface
*/
rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel);
-rt_err_t rt_wlan_dev_get_channel(struct rt_wlan_device *device);
+int rt_wlan_dev_get_channel(struct rt_wlan_device *device);
/*
* wlan device country interface
@@ -576,7 +576,8 @@ rt_err_t rt_wlan_dev_report_data(struct rt_wlan_device *device, void *buff, int
/*
* wlan device register interface
*/
-struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data);
+rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name,
+ const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data);
#ifdef __cplusplus
}
diff --git a/components/drivers/wlan/wlan_mgnt.c b/components/drivers/wlan/wlan_mgnt.c
index 1d0b0c4aa7f15f866c1c193ce6f036bb810b9a88..bdddac1fa2f2c081216195bfa38017270db85176 100644
--- a/components/drivers/wlan/wlan_mgnt.c
+++ b/components/drivers/wlan/wlan_mgnt.c
@@ -1320,7 +1320,10 @@ rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password)
return -RT_EIO;
}
RT_WLAN_LOG_D("%s is run", __FUNCTION__);
- password_len = rt_strlen(password);
+ if (password != RT_NULL)
+ {
+ password_len = rt_strlen(password);
+ }
if (password_len > RT_WLAN_PASSWORD_MAX_LENGTH)
{
RT_WLAN_LOG_E("key is to long! len:%d", password_len);
@@ -1358,16 +1361,16 @@ rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password)
return err;
}
-int rt_wlan_ap_is_active(void)
+rt_bool_t rt_wlan_ap_is_active(void)
{
- int _active = 0;
+ rt_bool_t _active = RT_FALSE;
if (_ap_is_null())
{
- return 0;
+ return RT_FALSE;
}
- _active = _ap_mgnt.state & RT_WLAN_STATE_ACTIVE ? 1 : 0;
+ _active = _ap_mgnt.state & RT_WLAN_STATE_ACTIVE ? RT_TRUE : RT_FALSE;
RT_WLAN_LOG_D("%s is run active:%s", __FUNCTION__, _active ? "Active" : "Inactive");
return _active;
}
diff --git a/components/drivers/wlan/wlan_mgnt.h b/components/drivers/wlan/wlan_mgnt.h
index d11d9ee3472d3013b7d927befa599d74831e9784..f4d9e0cff9aabcf7e5efa717a41116f283735606 100644
--- a/components/drivers/wlan/wlan_mgnt.h
+++ b/components/drivers/wlan/wlan_mgnt.h
@@ -97,7 +97,7 @@ int rt_wlan_get_rssi(void);
*/
rt_err_t rt_wlan_start_ap(const char *ssid, const char *password);
rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password);
-int rt_wlan_ap_is_active(void);
+rt_bool_t rt_wlan_ap_is_active(void);
rt_err_t rt_wlan_ap_stop(void);
rt_err_t rt_wlan_ap_get_info(struct rt_wlan_info *info);
int rt_wlan_ap_get_sta_num(void);
diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c
index c66f72e650938dff48a10c886f96d0e2dbce8b7c..a497af6e3154710b46df443a0fc3b40ddc8f5ff2 100644
--- a/components/finsh/cmd.c
+++ b/components/finsh/cmd.c
@@ -199,7 +199,7 @@ long list_sem(void)
return _list_sem(&info->object_list);
}
-FINSH_FUNCTION_EXPORT(list_sem, list semaphone in system);
+FINSH_FUNCTION_EXPORT(list_sem, list semaphore in system);
MSH_CMD_EXPORT(list_sem, list semaphore in system);
#endif
diff --git a/components/libc/compilers/dlib/sys/errno.h b/components/libc/compilers/dlib/sys/errno.h
deleted file mode 100644
index 1ecb58b74c41648b53dad5358c811406c8aa5d30..0000000000000000000000000000000000000000
--- a/components/libc/compilers/dlib/sys/errno.h
+++ /dev/null
@@ -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
-
-
-#endif
diff --git a/components/net/Kconfig b/components/net/Kconfig
index c302dec152749c34eaa6b042a4e78a690822998b..cef3ceacd3ab0d7ddc1f85accde2a79423395cf2 100644
--- a/components/net/Kconfig
+++ b/components/net/Kconfig
@@ -21,6 +21,11 @@ config RT_USING_SAL
bool "Support AT Commands stack"
default y
depends on AT_USING_SOCKET
+
+ config SAL_USING_TLS
+ bool "Support MbedTLS protocol"
+ default y
+ depends on PKG_USING_MBEDTLS
endmenu
endif
diff --git a/components/net/at/at_socket/at_socket.c b/components/net/at/at_socket/at_socket.c
index 01646f0d89e0699ff7894a42b8a76fb22bc2708c..3925f0f57cd8f45ee72928be4d7b119f9e0bc8a0 100644
--- a/components/net/at/at_socket/at_socket.c
+++ b/components/net/at/at_socket/at_socket.c
@@ -622,8 +622,20 @@ int at_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *f
goto __exit;
}
sock->state = AT_SOCKET_CONNECT;
+ /* set AT socket receive data callback function */
+ at_dev_ops->at_set_event_cb(AT_SOCKET_EVT_RECV, at_recv_notice_cb);
+ at_dev_ops->at_set_event_cb(AT_SOCKET_EVT_CLOSED, at_closed_notice_cb);
}
+ /* receive packet list last transmission of remaining data */
+ rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER);
+ if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0)
+ {
+ rt_mutex_release(sock->recv_lock);
+ goto __exit;
+ }
+ rt_mutex_release(sock->recv_lock);
+
/* socket passively closed, receive function return 0 */
if (sock->state == AT_SOCKET_CLOSED)
{
@@ -637,15 +649,6 @@ int at_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *f
goto __exit;
}
- /* receive packet list last transmission of remaining data */
- rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER);
- if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0)
- {
- rt_mutex_release(sock->recv_lock);
- goto __exit;
- }
- rt_mutex_release(sock->recv_lock);
-
/* non-blocking sockets receive data */
if (flags & MSG_DONTWAIT)
{
diff --git a/components/net/sal_socket/SConscript b/components/net/sal_socket/SConscript
index e9621933592c2a9b94739603948e92cb4731b2eb..cc7634f7d96aa728b160c2c5bad4cdd12cd1e4df 100644
--- a/components/net/sal_socket/SConscript
+++ b/components/net/sal_socket/SConscript
@@ -15,10 +15,13 @@ if GetDepend('SAL_USING_LWIP'):
if GetDepend('SAL_USING_AT'):
src += Glob('impl/af_inet_at.c')
-
+
if GetDepend('SAL_USING_LWIP') or GetDepend('SAL_USING_AT'):
CPPPATH += [cwd + '/impl']
+if GetDepend('SAL_USING_TLS'):
+ src += Glob('impl/proto_mbedtls.c')
+
if GetDepend('SAL_USING_POSIX'):
CPPPATH += [cwd + '/include/dfs_net']
src += Glob('socket/net_sockets.c')
diff --git a/components/net/sal_socket/impl/af_inet_at.c b/components/net/sal_socket/impl/af_inet_at.c
index c064283a617d7e13f0c581ed8acf878583a3033c..90d1537967f60e163112fcb9a356454c9fde747d 100644
--- a/components/net/sal_socket/impl/af_inet_at.c
+++ b/components/net/sal_socket/impl/af_inet_at.c
@@ -62,7 +62,7 @@ static int at_poll(struct dfs_fd *file, struct rt_pollreq *req)
}
#endif
-static const struct proto_ops at_inet_stream_ops =
+static const struct sal_socket_ops at_socket_ops =
{
at_socket,
at_closesocket,
@@ -90,25 +90,30 @@ static int at_create(struct sal_socket *socket, int type, int protocol)
//TODO Check type & protocol
- socket->ops = &at_inet_stream_ops;
+ socket->ops = &at_socket_ops;
return 0;
}
-static const struct proto_family at_inet_family_ops = {
- "at",
- AF_AT,
- AF_INET,
- at_create,
+static struct sal_proto_ops at_proto_ops =
+{
at_gethostbyname,
NULL,
- at_freeaddrinfo,
at_getaddrinfo,
+ at_freeaddrinfo,
+};
+
+static const struct sal_proto_family at_inet_family =
+{
+ AF_AT,
+ AF_INET,
+ at_create,
+ &at_proto_ops,
};
int at_inet_init(void)
{
- sal_proto_family_register(&at_inet_family_ops);
+ sal_proto_family_register(&at_inet_family);
return 0;
}
diff --git a/components/net/sal_socket/impl/af_inet_lwip.c b/components/net/sal_socket/impl/af_inet_lwip.c
index 9e726c87e91dcc5b4775a707aca55fcd30a36310..0826b052ab93df5e8d860d6a5112f683a87aa8b7 100644
--- a/components/net/sal_socket/impl/af_inet_lwip.c
+++ b/components/net/sal_socket/impl/af_inet_lwip.c
@@ -259,7 +259,8 @@ static int inet_poll(struct dfs_fd *file, struct rt_pollreq *req)
}
#endif
-static const struct proto_ops lwip_inet_stream_ops = {
+static const struct sal_socket_ops lwip_socket_ops =
+{
inet_socket,
lwip_close,
lwip_bind,
@@ -286,25 +287,30 @@ static int inet_create(struct sal_socket *socket, int type, int protocol)
//TODO Check type & protocol
- socket->ops = &lwip_inet_stream_ops;
+ socket->ops = &lwip_socket_ops;
return 0;
}
-static const struct proto_family lwip_inet_family_ops = {
- "lwip",
- AF_INET,
- AF_INET,
- inet_create,
+static struct sal_proto_ops lwip_proto_ops =
+{
lwip_gethostbyname,
lwip_gethostbyname_r,
- lwip_freeaddrinfo,
lwip_getaddrinfo,
+ lwip_freeaddrinfo,
+};
+
+static const struct sal_proto_family lwip_inet_family =
+{
+ AF_INET,
+ AF_INET,
+ inet_create,
+ &lwip_proto_ops,
};
int lwip_inet_init(void)
{
- sal_proto_family_register(&lwip_inet_family_ops);
+ sal_proto_family_register(&lwip_inet_family);
return 0;
}
diff --git a/components/net/sal_socket/impl/proto_mbedtls.c b/components/net/sal_socket/impl/proto_mbedtls.c
new file mode 100644
index 0000000000000000000000000000000000000000..8ed9f67ff1cdf500f12db2e0704961b134ff1ace
--- /dev/null
+++ b/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
+
+#ifdef RT_USING_DFS
+#include
+#endif
+
+#ifdef SAL_USING_TLS
+#include
+#endif
+#include
+#include
+
+#ifdef SAL_USING_TLS
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include
+#include
+
+#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 */
diff --git a/components/net/sal_socket/include/sal.h b/components/net/sal_socket/include/sal.h
index 68248742d6822c9911af38a6bd8732eb6a02ceb5..17d44eef77b47d67f383bd65e4510928b14bd508 100644
--- a/components/net/sal_socket/include/sal.h
+++ b/components/net/sal_socket/include/sal.h
@@ -25,7 +25,7 @@ extern "C" {
typedef uint32_t socklen_t;
#endif
-/* sal socket magic word */
+/* SAL socket magic word */
#define SAL_SOCKET_MAGIC 0x5A10
/* The maximum number of sockets structure */
@@ -38,12 +38,12 @@ typedef uint32_t socklen_t;
#define SAL_PROTO_FAMILIES_NUM 4
#endif
-/* sal socket offset */
+/* SAL socket offset */
#ifndef SAL_SOCKET_OFFSET
#define SAL_SOCKET_OFFSET 0
#endif
-struct proto_ops
+struct sal_socket_ops
{
int (*socket) (int domain, int type, int protocol);
int (*closesocket)(int s);
@@ -64,30 +64,38 @@ struct proto_ops
#endif
};
+struct sal_proto_ops
+{
+ struct hostent* (*gethostbyname) (const char *name);
+ int (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
+ int (*getaddrinfo) (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
+ void (*freeaddrinfo) (struct addrinfo *ai);
+};
+
struct sal_socket
{
- uint32_t magic; /* sal socket magic word */
+ uint32_t magic; /* SAL socket magic word */
- int socket; /* sal socket descriptor */
+ int socket; /* SAL socket descriptor */
int domain;
int type;
int protocol;
- const struct proto_ops *ops; /* socket options */
- void *user_data; /* specific sal socket data */
+ const struct sal_socket_ops *ops; /* socket options */
+
+ void *user_data; /* user-specific data */
+#ifdef SAL_USING_TLS
+ void *user_data_tls; /* user-specific TLS data */
+#endif
};
-struct proto_family
+struct sal_proto_family
{
- char name[RT_NAME_MAX];
int family; /* primary protocol families type */
int sec_family; /* secondary protocol families type */
- int (*create)(struct sal_socket *sal_socket, int type, int protocol); /* register socket options */
+ int (*create)(struct sal_socket *sal_socket, int type, int protocol); /* register socket options */
- struct hostent* (*gethostbyname) (const char *name);
- int (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
- void (*freeaddrinfo) (struct addrinfo *ai);
- int (*getaddrinfo) (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
+ struct sal_proto_ops *ops; /* protocol family options */
};
/* SAL(Socket Abstraction Layer) initialize */
@@ -95,10 +103,11 @@ int sal_init(void);
struct sal_socket *sal_get_socket(int sock);
-/* protocol family register and unregister operate */
-int sal_proto_family_register(const struct proto_family *pf);
-int sal_proto_family_unregister(const struct proto_family *pf);
-struct proto_family *sal_proto_family_find(const char *name);
+/* SAL protocol family register and unregister operate */
+int sal_proto_family_register(const struct sal_proto_family *pf);
+int sal_proto_family_unregister(int family);
+rt_bool_t sal_proto_family_is_registered(int family);
+struct sal_proto_family *sal_proto_family_find(int family);
#ifdef __cplusplus
}
diff --git a/components/net/sal_socket/include/sal_tls.h b/components/net/sal_socket/include/sal_tls.h
new file mode 100644
index 0000000000000000000000000000000000000000..7681b313bdf7daf8d6c86d8a9f9263e7405c3555
--- /dev/null
+++ b/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
+
+/* 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__ */
diff --git a/components/net/sal_socket/include/socket/sys_socket/sys/socket.h b/components/net/sal_socket/include/socket/sys_socket/sys/socket.h
index dd2c3850a6ffce225e64360b63d864830081ed50..04470aa84a522a233b3ea2e3b238a825ddc51ae8 100644
--- a/components/net/sal_socket/include/socket/sys_socket/sys/socket.h
+++ b/components/net/sal_socket/include/socket/sys_socket/sys/socket.h
@@ -14,6 +14,9 @@
#include
#include
+#ifdef SAL_USING_TLS
+#include
+#endif
#ifdef __cplusplus
extern "C" {
diff --git a/components/net/sal_socket/src/sal_socket.c b/components/net/sal_socket/src/sal_socket.c
index ac36cb2139e53f808d3048e5b64ef5180e307422..dba8e66254d0781c7f71df16a2e5387a330afa10 100644
--- a/components/net/sal_socket/src/sal_socket.c
+++ b/components/net/sal_socket/src/sal_socket.c
@@ -6,6 +6,7 @@
* Change Logs:
* Date Author Notes
* 2018-05-23 ChenYong First version
+ * 2018-11-12 ChenYong Add TLS support
*/
#include
@@ -13,6 +14,9 @@
#include
#include
+#ifdef SAL_USING_TLS
+#include
+#endif
#include
#define DBG_ENABLE
@@ -30,13 +34,32 @@ struct sal_socket_table
struct sal_socket **sockets;
};
+#ifdef SAL_USING_TLS
+/* The global TLS protocol options */
+static struct sal_proto_tls *proto_tls;
+#endif
+
/* The global array of available protocol families */
-static struct proto_family proto_families[SAL_PROTO_FAMILIES_NUM];
+static struct sal_proto_family proto_families[SAL_PROTO_FAMILIES_NUM];
/* The global socket table */
static struct sal_socket_table socket_table;
static struct rt_mutex sal_core_lock;
static rt_bool_t init_ok = RT_FALSE;
+#define IS_SOCKET_PROTO_TLS(sock) (((sock)->protocol == PROTOCOL_TLS) || \
+ ((sock)->protocol == PROTOCOL_DTLS))
+#define SAL_SOCKOPS_PROTO_TLS_VALID(sock, name) (proto_tls && (proto_tls->ops->name) && IS_SOCKET_PROTO_TLS(sock))
+
+#define SAL_SOCKOPT_PROTO_TLS_EXEC(sock, name, optval, optlen) \
+do \
+{ \
+ if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, name)) \
+ { \
+ return proto_tls->ops->name((sock)->user_data_tls, (optval), (optlen)); \
+ } \
+}while(0) \
+
+
/**
* SAL (Socket Abstraction Layer) initialize.
*
@@ -47,7 +70,7 @@ int sal_init(void)
{
int cn;
- if(init_ok)
+ if (init_ok)
{
LOG_D("Socket Abstraction Layer is already initialized.");
return 0;
@@ -73,15 +96,32 @@ int sal_init(void)
}
INIT_COMPONENT_EXPORT(sal_init);
+/**
+ * This function will register TLS protocol to the global TLS protocol.
+ *
+ * @param pt TLS protocol object
+ *
+ * @return 0: TLS protocol object register success
+ */
+#ifdef SAL_USING_TLS
+int sal_proto_tls_register(const struct sal_proto_tls *pt)
+{
+ RT_ASSERT(pt);
+ proto_tls = (struct sal_proto_tls *) pt;
+
+ return 0;
+}
+#endif
+
/**
* This function will register protocol family to the global array of protocol families.
*
* @param pf protocol family object
*
- * @return 0 : protocol family object register success
- * -1 : the global array of available protocol families is full
+ * @return 0: protocol family object register success
+ * -1: the global array of available protocol families is full
*/
-int sal_proto_family_register(const struct proto_family *pf)
+int sal_proto_family_register(const struct sal_proto_family *pf)
{
rt_base_t level;
int idx;
@@ -92,11 +132,11 @@ int sal_proto_family_register(const struct proto_family *pf)
/* check protocol family is already registered */
for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
{
- if(rt_strcmp(proto_families[idx].name, pf->name) == 0)
+ if (proto_families[idx].family == pf->family && proto_families[idx].create)
{
/* enable interrupt */
rt_hw_interrupt_enable(level);
- LOG_E("%s protocol family is already registered!", pf->name);
+ LOG_E("%s protocol family is already registered!", pf->family);
return -1;
}
}
@@ -105,22 +145,22 @@ int sal_proto_family_register(const struct proto_family *pf)
for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM && proto_families[idx].create; idx++);
/* can't find an empty protocol family entry */
- if(idx == SAL_PROTO_FAMILIES_NUM)
+ if (idx == SAL_PROTO_FAMILIES_NUM)
{
/* enable interrupt */
rt_hw_interrupt_enable(level);
return -1;
}
- rt_strncpy(proto_families[idx].name, pf->name, rt_strlen(pf->name));
proto_families[idx].family = pf->family;
proto_families[idx].sec_family = pf->sec_family;
proto_families[idx].create = pf->create;
- proto_families[idx].gethostbyname = pf->gethostbyname;
- proto_families[idx].gethostbyname_r = pf->gethostbyname_r;
- proto_families[idx].freeaddrinfo = pf->freeaddrinfo;
- proto_families[idx].getaddrinfo = pf->getaddrinfo;
+ proto_families[idx].ops = pf->ops;
+ proto_families[idx].ops->gethostbyname = pf->ops->gethostbyname;
+ proto_families[idx].ops->gethostbyname_r = pf->ops->gethostbyname_r;
+ proto_families[idx].ops->freeaddrinfo = pf->ops->freeaddrinfo;
+ proto_families[idx].ops->getaddrinfo = pf->ops->getaddrinfo;
/* enable interrupt */
rt_hw_interrupt_enable(level);
@@ -136,17 +176,17 @@ int sal_proto_family_register(const struct proto_family *pf)
* @return >=0 : unregister protocol family index
* -1 : unregister failed
*/
-int sal_proto_family_unregister(const struct proto_family *pf)
+int sal_proto_family_unregister(int family)
{
int idx = 0;
- RT_ASSERT(pf != RT_NULL);
+ RT_ASSERT(family > 0 && family < AF_MAX);
for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
{
- if(rt_strcmp(proto_families[idx].name, pf->name) == 0)
+ if (proto_families[idx].family == family && proto_families[idx].create)
{
- rt_memset(&proto_families[idx], 0x00, sizeof(struct proto_family));
+ rt_memset(&proto_families[idx], 0x00, sizeof(struct sal_proto_family));
return idx;
}
@@ -156,21 +196,46 @@ int sal_proto_family_unregister(const struct proto_family *pf)
}
/**
- * This function will get protocol family by name.
+ * This function will judge whether protocol family is registered
*
- * @param name protocol family name
+ * @param family protocol family number
+ *
+ * @return 1: protocol family is registered
+ * 0: protocol family is not registered
+ */
+rt_bool_t sal_proto_family_is_registered(int family)
+{
+ int idx = 0;
+
+ RT_ASSERT(family > 0 && family < AF_MAX);
+
+ for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
+ {
+ if (proto_families[idx].family == family && proto_families[idx].create)
+ {
+ return RT_TRUE;
+ }
+ }
+
+ return RT_FALSE;
+}
+
+/**
+ * This function will get protocol family object by family number.
+ *
+ * @param family protocol family number
*
* @return protocol family object
*/
-struct proto_family *sal_proto_family_find(const char *name)
+struct sal_proto_family *sal_proto_family_find(int family)
{
int idx = 0;
- RT_ASSERT(name != RT_NULL);
+ RT_ASSERT(family > 0 && family < AF_MAX);
for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++)
{
- if (rt_strcmp(proto_families[idx].name, name) == 0)
+ if (proto_families[idx].family == family && proto_families[idx].create)
{
return &proto_families[idx];
}
@@ -238,7 +303,7 @@ static void sal_unlock(void)
*
* @return protocol family structure address
*/
-static struct proto_family *get_proto_family(int family)
+static struct sal_proto_family *get_proto_family(int family)
{
int idx;
@@ -278,7 +343,7 @@ static struct proto_family *get_proto_family(int family)
static int socket_init(int family, int type, int protocol, struct sal_socket **res)
{
struct sal_socket *sock;
- struct proto_family *pf;
+ struct sal_proto_family *pf;
if (family < 0 || family > AF_MAX)
{
@@ -383,6 +448,11 @@ static int socket_new(void)
sock = st->sockets[idx];
sock->socket = idx + SAL_SOCKET_OFFSET;
sock->magic = SAL_SOCKET_MAGIC;
+ sock->ops = RT_NULL;
+ sock->user_data = RT_NULL;
+#ifdef SAL_USING_TLS
+ sock->user_data_tls = RT_NULL;
+#endif
__result:
sal_unlock();
@@ -474,6 +544,15 @@ int sal_shutdown(int socket, int how)
if (sock->ops->shutdown((int) sock->user_data, how) == 0)
{
+#ifdef SAL_USING_TLS
+ if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket))
+ {
+ if (proto_tls->ops->closesocket(sock->user_data_tls) < 0)
+ {
+ return -1;
+ }
+ }
+#endif
rt_free(sock);
socket_table.sockets[socket] = RT_NULL;
return 0;
@@ -551,12 +630,46 @@ int sal_setsockopt(int socket, int level, int optname, const void *optval, sockl
return -RT_ENOSYS;
}
+#ifdef SAL_USING_TLS
+ if (level == SOL_TLS)
+ {
+ switch (optname)
+ {
+ case TLS_CRET_LIST:
+ SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_cret_list, optval, optlen);
+ break;
+
+ case TLS_CIPHERSUITE_LIST:
+ SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_ciphersurite, optval, optlen);
+ break;
+
+ case TLS_PEER_VERIFY:
+ SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_peer_verify, optval, optlen);
+ break;
+
+ case TLS_DTLS_ROLE:
+ SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_dtls_role, optval, optlen);
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+ }
+ else
+ {
+ return sock->ops->setsockopt((int) sock->user_data, level, optname, optval, optlen);
+ }
+#else
return sock->ops->setsockopt((int) sock->user_data, level, optname, optval, optlen);
+#endif /* SAL_USING_TLS */
}
int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
{
struct sal_socket *sock;
+ int ret;
sock = sal_get_socket(socket);
if (!sock)
@@ -569,7 +682,20 @@ int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
return -RT_ENOSYS;
}
- return sock->ops->connect((int) sock->user_data, name, namelen);
+ ret = sock->ops->connect((int) sock->user_data, name, namelen);
+#ifdef SAL_USING_TLS
+ if (ret >= 0 && SAL_SOCKOPS_PROTO_TLS_VALID(sock, connect))
+ {
+ if (proto_tls->ops->connect(sock->user_data_tls) < 0)
+ {
+ return -1;
+ }
+
+ return ret;
+ }
+#endif
+
+ return ret;
}
int sal_listen(int socket, int backlog)
@@ -606,7 +732,24 @@ int sal_recvfrom(int socket, void *mem, size_t len, int flags,
return -RT_ENOSYS;
}
+#ifdef SAL_USING_TLS
+ if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, recv))
+ {
+ int ret;
+
+ if ((ret = proto_tls->ops->recv(sock->user_data_tls, mem, len)) < 0)
+ {
+ return -1;
+ }
+ return ret;
+ }
+ else
+ {
+ return sock->ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen);
+ }
+#else
return sock->ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen);
+#endif
}
int sal_sendto(int socket, const void *dataptr, size_t size, int flags,
@@ -625,7 +768,24 @@ int sal_sendto(int socket, const void *dataptr, size_t size, int flags,
return -RT_ENOSYS;
}
+#ifdef SAL_USING_TLS
+ if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, send))
+ {
+ int ret;
+
+ if ((ret = proto_tls->ops->send(sock->user_data_tls, dataptr, size)) < 0)
+ {
+ return -1;
+ }
+ return ret;
+ }
+ else
+ {
+ return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen);
+ }
+#else
return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen);
+#endif
}
int sal_socket(int domain, int type, int protocol)
@@ -657,8 +817,17 @@ int sal_socket(int domain, int type, int protocol)
proto_socket = sock->ops->socket(domain, type, protocol);
if (proto_socket >= 0)
{
+#ifdef SAL_USING_TLS
+ if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, socket))
+ {
+ sock->user_data_tls = proto_tls->ops->socket(proto_socket);
+ if (sock->user_data_tls == RT_NULL)
+ {
+ return -1;
+ }
+ }
+#endif
sock->user_data = (void *) proto_socket;
-
return sock->socket;
}
@@ -682,6 +851,15 @@ int sal_closesocket(int socket)
if (sock->ops->closesocket((int) sock->user_data) == 0)
{
+#ifdef SAL_USING_TLS
+ if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket))
+ {
+ if (proto_tls->ops->closesocket(sock->user_data_tls) < 0)
+ {
+ return -1;
+ }
+ }
+#endif
rt_free(sock);
socket_table.sockets[socket] = RT_NULL;
return 0;
@@ -736,9 +914,9 @@ struct hostent *sal_gethostbyname(const char *name)
for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
{
- if (proto_families[i].gethostbyname)
+ if (proto_families[i].ops && proto_families[i].ops->gethostbyname)
{
- hst = proto_families[i].gethostbyname(name);
+ hst = proto_families[i].ops->gethostbyname(name);
if (hst != RT_NULL)
{
return hst;
@@ -756,9 +934,9 @@ int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
{
- if (proto_families[i].gethostbyname_r)
+ if (proto_families[i].ops && proto_families[i].ops->gethostbyname_r)
{
- res = proto_families[i].gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
+ res = proto_families[i].ops->gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
if (res == 0)
{
return res;
@@ -769,20 +947,6 @@ int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
return -1;
}
-void sal_freeaddrinfo(struct addrinfo *ai)
-{
- int i;
-
- for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
- {
- if (proto_families[i].freeaddrinfo)
- {
- proto_families[i].freeaddrinfo(ai);
- return;
- }
- }
-}
-
int sal_getaddrinfo(const char *nodename,
const char *servname,
const struct addrinfo *hints,
@@ -792,9 +956,9 @@ int sal_getaddrinfo(const char *nodename,
for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
{
- if (proto_families[i].getaddrinfo)
+ if (proto_families[i].ops && proto_families[i].ops->getaddrinfo)
{
- ret = proto_families[i].getaddrinfo(nodename, servname, hints, res);
+ ret = proto_families[i].ops->getaddrinfo(nodename, servname, hints, res);
if (ret == 0)
{
return ret;
@@ -804,3 +968,17 @@ int sal_getaddrinfo(const char *nodename,
return -1;
}
+
+void sal_freeaddrinfo(struct addrinfo *ai)
+{
+ int i;
+
+ for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i)
+ {
+ if (proto_families[i].ops && proto_families[i].ops->freeaddrinfo)
+ {
+ proto_families[i].ops->freeaddrinfo(ai);
+ return;
+ }
+ }
+}
diff --git a/components/utilities/Kconfig b/components/utilities/Kconfig
index e830d94578bb18fd361c0dc99bac96d96b8585b5..8e43cfa0a0ff96ead711429f7c122e2457bd4d46 100644
--- a/components/utilities/Kconfig
+++ b/components/utilities/Kconfig
@@ -230,4 +230,8 @@ config RT_USING_ULOG
sfotware module version number
endif
+config RT_USING_UTEST
+ bool "Enable utest (RT-Thread test framework)"
+ default n
+
endmenu
diff --git a/components/utilities/ulog/ulog.h b/components/utilities/ulog/ulog.h
index 792c098568c0cb4aafcb82288dac60fde6395359..c78d72eda5e012f30599943e5bcc860f235255ec 100644
--- a/components/utilities/ulog/ulog.h
+++ b/components/utilities/ulog/ulog.h
@@ -45,6 +45,7 @@ void ulog_deinit(void);
#define LOG_I(...) ulog_i(LOG_TAG, __VA_ARGS__)
#define LOG_D(...) ulog_d(LOG_TAG, __VA_ARGS__)
#define LOG_RAW(...) ulog_raw(__VA_ARGS__)
+#define LOG_HEX(name, width, buf, size) ulog_hex(name, width, buf, size)
/*
* backend register and unregister
diff --git a/components/utilities/ulog/ulog_def.h b/components/utilities/ulog/ulog_def.h
index 8df3dd2087a3a117876f979618cdfe9106b0ed62..e7c033f71c9bd28f031fa2fdf49339d71a0b1892 100644
--- a/components/utilities/ulog/ulog_def.h
+++ b/components/utilities/ulog/ulog_def.h
@@ -94,6 +94,12 @@ extern "C" {
#define ulog_e(TAG, ...)
#endif /* (LOG_LVL >= LOG_LVL_ERROR) && (ULOG_OUTPUT_LVL >= LOG_LVL_ERROR) */
+#if (LOG_LVL >= LOG_LVL_DBG) && (ULOG_OUTPUT_LVL >= LOG_LVL_DBG)
+ #define ulog_hex(TAG, width, buf, size) ulog_hexdump(TAG, width, buf, size)
+#else
+ #define ulog_hex(TAG, width, buf, size)
+#endif /* (LOG_LVL >= LOG_LVL_DBG) && (ULOG_OUTPUT_LVL >= LOG_LVL_DBG) */
+
/* assert for developer. */
#ifdef ULOG_ASSERT_ENABLE
#define ULOG_ASSERT(EXPR) \
@@ -132,6 +138,7 @@ extern "C" {
#define log_d LOG_D
#define log_v LOG_D
#define log_raw LOG_RAW
+#define log_hex LOG_HEX
#define ELOG_LVL_ASSERT LOG_LVL_ASSERT
#define ELOG_LVL_ERROR LOG_LVL_ERROR
#define ELOG_LVL_WARN LOG_LVL_WARNING
diff --git a/components/utilities/utest/SConscript b/components/utilities/utest/SConscript
new file mode 100644
index 0000000000000000000000000000000000000000..dc77bc2591a0269e33ac90114eb8e04bfd994e87
--- /dev/null
+++ b/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')
diff --git a/components/utilities/utest/utest.c b/components/utilities/utest/utest.c
new file mode 100644
index 0000000000000000000000000000000000000000..0f5a206d3c1027206feba8f99c93d616d2acaef8
--- /dev/null
+++ b/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
+#include
+
+#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
+
+#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);
+ }
+ }
+}
diff --git a/components/utilities/utest/utest.h b/components/utilities/utest/utest.h
new file mode 100644
index 0000000000000000000000000000000000000000..5a7e8af7214bb56c2211c8124040c6cee1794051
--- /dev/null
+++ b/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
+#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__ */
diff --git a/components/utilities/utest/utest_assert.h b/components/utilities/utest/utest_assert.h
new file mode 100644
index 0000000000000000000000000000000000000000..997e8ae7f32cb8563684d21ab2b0b4eb26493330
--- /dev/null
+++ b/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
+
+/* 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__ */
diff --git a/components/utilities/utest/utest_log.h b/components/utilities/utest/utest_log.h
new file mode 100644
index 0000000000000000000000000000000000000000..c954046b7627bfa33c20c0ec8f0fae3d47671c95
--- /dev/null
+++ b/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
+
+#endif /* __UTEST_LOG_H__ */