diff --git a/.config b/.config
index c7beee0..700a3c1 100644
--- a/.config
+++ b/.config
@@ -50,8 +50,8 @@ CONFIG_RT_USING_MUTEX=y
CONFIG_RT_USING_EVENT=y
CONFIG_RT_USING_MAILBOX=y
CONFIG_RT_USING_MESSAGEQUEUE=y
-# CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY is not set
-# CONFIG_RT_USING_SIGNALS is not set
+CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY=y
+CONFIG_RT_USING_SIGNALS=y
# end of Inter-Thread communication
#
@@ -1054,7 +1054,25 @@ CONFIG_PKG_LITTLEFS_VER="v2.11.2"
# CONFIG_PKG_USING_DM9051 is not set
# CONFIG_PKG_USING_SSD1306 is not set
# CONFIG_PKG_USING_QKEY is not set
-# CONFIG_PKG_USING_RS485 is not set
+CONFIG_PKG_USING_RS485=y
+CONFIG_PKG_RS485_PATH="/packages/peripherals/rs485"
+CONFIG_RS485_USING_DEV=y
+# CONFIG_RS485_USING_DMA_RX is not set
+# CONFIG_RS485_USING_INT_TX is not set
+# CONFIG_RS485_USING_DMA_TX is not set
+CONFIG_RS485_SW_DLY_US=0
+# CONFIG_RS485_USING_TEST is not set
+# CONFIG_RS485_USING_SAMPLE_MASTER is not set
+# CONFIG_RS485_USING_SAMPLE_SLAVE is not set
+# CONFIG_PKG_USING_RS485_LATEST_VERSION is not set
+CONFIG_PKG_USING_RS485_V106=y
+# CONFIG_PKG_USING_RS485_V105 is not set
+# CONFIG_PKG_USING_RS485_V104 is not set
+# CONFIG_PKG_USING_RS485_V103 is not set
+# CONFIG_PKG_USING_RS485_V102 is not set
+# CONFIG_PKG_USING_RS485_V101 is not set
+# CONFIG_PKG_USING_RS485_V100 is not set
+CONFIG_PKG_RS485_VER="v1.06"
# CONFIG_PKG_USING_RS232 is not set
# CONFIG_PKG_USING_NES is not set
# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set
diff --git a/.cproject b/.cproject
index 2b6e442..5065da1 100644
--- a/.cproject
+++ b/.cproject
@@ -144,6 +144,7 @@
+
@@ -323,6 +324,7 @@
+
@@ -465,6 +467,7 @@
+
@@ -611,6 +614,7 @@
+
@@ -643,7 +647,7 @@
-
+
diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
index ffb2113..674858f 100644
--- a/.settings/language.settings.xml
+++ b/.settings/language.settings.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/applications/DATA_uart.c b/applications/DATA_uart.c
index 9d7be8f..a312b8f 100644
--- a/applications/DATA_uart.c
+++ b/applications/DATA_uart.c
@@ -11,151 +11,85 @@
*/
#include
#include
-#include // ← 显式包含,确保 RT_SERIAL_EVENT_RX_IDLE 可见
#include "data_comm.h"
+#include
#define DBG_TAG "SCCM_link"
#define DBG_LVL DBG_LOG
#include
-#define SAMPLE_UART_NAME "uart1"
-#define RX_LINE_BUF_SIZE 1024
-
-static rt_device_t serial;
static struct rt_semaphore rx_sem;
-// 接收回调
-static rt_err_t uart_rx_ind(rt_device_t dev, rt_size_t size)
-{
- // 注意:在 RT-Thread 5.x,当使用 INT_RX 时,size 是接收到的字节数
- // 但若启用了 RX_IDLE 模式,底层驱动会在 IDLE 时回调,并传入事件
- // 安全做法:检查是否为事件(高位标志)
- // if (size & RT_SERIAL_EVENT_RX_IDLE)
- {
- LOG_D("RX IDLE event received");
- rt_sem_release(&rx_sem);
- return RT_EOK;
- }
-
- // 如果是普通数据(size > 0),也可处理,但本例依赖 IDLE 触发
- return RT_EOK;
-}
+#define RX_LINE_BUF_SIZE 1024
+#define RS485_SAMPLE_SLAVE_SERIAL "uart1"
+#define RS485_SAMPLE_SLAVE_BAUDRATE 115200
+#define RS485_SAMPLE_MASTER_PARITY 0 //0 -- none parity
+#define RS485_SAMPLE_SLAVE_PIN -1 //-1 -- nonuse rs485 mode control
+#define RS485_SAMPLE_SLAVE_LVL 1
+#define RS485_TOM_MS 50
-static int read_line_from_uart(char *buf, int maxlen)
+void uart_thread_entry(void *parameter)
{
- char ch;
- int len = 0;
+ rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
- while (len < maxlen - 1)
- {
- // 注意:在 INT_RX 模式下,rt_device_read 会从驱动内部 buffer 读取
- rt_size_t result = rt_device_read(serial, 0, &ch, 1);
- if (result <= 0)
+ static rt_uint8_t input[RX_LINE_BUF_SIZE];
+ rs485_inst_t *hinst = rs485_create(RS485_SAMPLE_SLAVE_SERIAL, RS485_SAMPLE_SLAVE_BAUDRATE,
+ RS485_SAMPLE_MASTER_PARITY, RS485_SAMPLE_SLAVE_PIN, RS485_SAMPLE_SLAVE_LVL);
+
+ if (hinst == RT_NULL)
{
- break; // 无更多数据
+ LOG_E("create LINK instance fail.");
+ return;
}
- buf[len++] = ch;
- if (ch == '\n')
+ rs485_set_recv_tmo(hinst, RS485_TOM_MS);
+ if (rs485_connect(hinst) != RT_EOK)
{
- buf[len] = '\0';
- return len;
+ rs485_destory(hinst);
+ LOG_E("LINK connect fail.");
+ return;
}
- }
-
- buf[len] = '\0';
- return len;
-}
-
-void uart_thread_entry(void *parameter)
-{
- char input[RX_LINE_BUF_SIZE];
- int len;
- rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
+ LOG_I("SCCM thread running on %s", RS485_SAMPLE_SLAVE_SERIAL);
- serial = rt_device_find(SAMPLE_UART_NAME);
- if (!serial)
+ while (1)
{
- LOG_E("Cannot find %s", SAMPLE_UART_NAME);
- return;
- }
-
- // Step 1: 设置串口基本参数(波特率等)
- struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
- config.baud_rate = BAUD_RATE_115200; // 根据需要调整
- config.data_bits = DATA_BITS_8;
- config.stop_bits = STOP_BITS_1;
- config.parity = PARITY_NONE;
- config.bufsz = RX_LINE_BUF_SIZE; // 驱动内部接收 buffer 大小
- rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
+ int len = rs485_recv(hinst, input, sizeof(input));
- // Step 2: 【关键】启用 RX IDLE 模式
- // rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, (void*)RT_SERIAL_RX_IDLE);
-
- // Step 3: 打开串口(使用中断接收)
- rt_err_t result = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX);
- if (result != RT_EOK)
- {
- LOG_E("Failed to open %s, error=%d", SAMPLE_UART_NAME, result);
- return;
+ if (len > 0)
+ {
+ // 动态分配请求结构体(见之前完整代码)
+ struct proc_request *req = rt_malloc(sizeof(struct proc_request));
+ if (!req) continue;
+ rt_strncpy(req->input, (const char *)input, sizeof(req->input));
+ req->input_len = len;
+ req->sem = rt_malloc(sizeof(struct rt_semaphore));
+ if (!req->sem) {
+ rt_free(req);
+ continue;
+ }
+ rt_sem_init(req->sem, "uart_resp", 0, RT_IPC_FLAG_FIFO);
+
+ // 发送到处理线程
+ if (rt_mq_send(proc_mq, &req, sizeof(req)) == RT_EOK)
+ {
+ // 等待处理完成
+ if (rt_sem_take(req->sem, rt_tick_from_millisecond(100)) >= RT_EOK)
+ {
+ rs485_send(hinst, req->output, req->output_len);
+ }
+ }
+ // 清理
+ rt_sem_detach(req->sem); // 或 rt_sem_delete
+ rt_free(req->sem);
+ rt_free(req);
+ }
}
-
- // Step 4: 设置回调
- rt_device_set_rx_indicate(serial, uart_rx_ind);
-
- LOG_I("SCCM thread (IDLE mode) running on %s", SAMPLE_UART_NAME);
-
- while (1)
- {
- // 等待数据就绪
- if (rt_sem_take(&rx_sem, RT_WAITING_FOREVER) == RT_EOK)
- {
- // 处理接收到的数据(提取完整行)
- while ((len = get_line(input, sizeof(input))) > 0)
- {
- // 动态分配请求结构体(见之前完整代码)
- struct proc_request *req = rt_malloc(sizeof(struct proc_request));
- if (!req) continue;
-
- rt_strncpy(req->input, input, sizeof(req->input));
- req->input_len = len;
- //req->input[len]='\0';
-
- req->sem = rt_malloc(sizeof(struct rt_semaphore));
- if (!req->sem) {
- rt_free(req);
- continue;
- }
- rt_sem_init(req->sem, "uart_resp", 0, RT_IPC_FLAG_FIFO);
-
- // 发送到处理线程
- if (rt_mq_send(proc_mq, &req, sizeof(req)) == RT_EOK)
- {
- // 等待处理完成
- if (rt_sem_take(req->sem, RT_WAITING_FOREVER) == RT_EOK)
- {
- rt_device_write(serial, 0, req->output, req->output_len);
- }
- }
-
- // 清理
- rt_sem_detach(req->sem); // 或 rt_sem_delete
- rt_free(req->sem);
- rt_free(req);
- }
- }
- }
}
int start_uart_thread(void)
{
- rt_thread_t tid = rt_thread_create("data_uart",
- uart_thread_entry,
- RT_NULL,
- 2048,
- 25,
- 10);
+ rt_thread_t tid = rt_thread_create("uart1",uart_thread_entry,RT_NULL,2048,20,10);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
diff --git a/applications/data/DATA_comm.c b/applications/data/DATA_comm.c
index eef7384..f6a47e0 100644
--- a/applications/data/DATA_comm.c
+++ b/applications/data/DATA_comm.c
@@ -9,6 +9,7 @@
*/
/* DATA_comm.c */
#include
+#include
#include "cjson.h"
#include
#include
@@ -24,11 +25,10 @@
#include
rt_mq_t proc_mq;
+//static struct proc_request *req;
char cjson_falg=0;//是否解析cjson
-char *json_buffer=NULL;
-
-//
+char *json_buffer=NULL;//
/**
* 截取两个指定子串之间的内容
@@ -432,17 +432,18 @@ void proc_thread_entry(void *parameter)
while (1)
{
// 接收请求指针
- if (rt_mq_recv(proc_mq, &req, sizeof(req), RT_WAITING_FOREVER) == RT_EOK)
+ if (rt_mq_recv(proc_mq, &req, sizeof(req), RT_WAITING_FOREVER) >= RT_EOK)
{
if (!req) continue;
memcpy(DATA_api,req->input,5);
extract_between(req->input, "[", "]", DATA_machins, sizeof(DATA_machins));
-
if(strcmp(DATA_machins,machine_ID)==0)
{
char *p=strstr(req->input,"]");
- if(!p){cjson_falg=0;}
- else {
+ if(!p)
+ {
+ cjson_falg=0;
+ }else {
p += strlen("]");
}
@@ -481,8 +482,7 @@ int data_comm_init(void)
}
dat_comm_stack = rt_memheap_alloc(&sram_DTCMRAM, 1024*6);
- dat_err = rt_thread_init(&dat_comm_thread, "dat_comm", proc_thread_entry, RT_NULL,
- dat_comm_stack, 1024*6, 15, 10);
+ dat_err = rt_thread_init(&dat_comm_thread, "dat_comm", proc_thread_entry, RT_NULL,dat_comm_stack, 1024*6, 15, 10);
if(dat_err != RT_EOK)
{
diff --git a/applications/main.c b/applications/main.c
index 563a451..e62fd35 100644
--- a/applications/main.c
+++ b/applications/main.c
@@ -12,7 +12,6 @@
#include
#include
#include "DB_SQLite.h"
-#include "DATA_comm.h"
#include "DATA_uart.h"
#define DBG_TAG "main"
@@ -23,19 +22,9 @@ extern rt_sem_t mount_sem; // 引用上面SD挂载线程定义的信号量
int main(void)
{
- /*volatile uint32_t *sdram_test = (uint32_t*)0xC0000000;
- *sdram_test = 0xAABBCCDD;
- rt_thread_mdelay(1); // 等待稳定
- if (*sdram_test != 0xAABBCCDD)
- {
- rt_kprintf("SDRAM init failed!\n");
- while (1); // 卡死,不要继续
- }
- rt_kprintf("SDRAM test OK\n");*/
-
rt_sem_take(mount_sem, rt_tick_from_millisecond(5000)); // 等待挂载完成,最多等待 5 秒
thread_DB_SQLite();
- //start_uart_thread();
+ start_uart_thread();
thread_RUN_LED();//运行指示灯线程
return RT_EOK;
}
diff --git a/applications/sql/DB_SQLite.c b/applications/sql/DB_SQLite.c
index df777c6..51617df 100644
--- a/applications/sql/DB_SQLite.c
+++ b/applications/sql/DB_SQLite.c
@@ -282,10 +282,10 @@ static void db_sqlite(void *parameter) {
// 默认启用数据库
db_enabled = RT_TRUE;
- while (1) {
- rt_thread_mdelay(500);
+ while (1)
+ {
// 接收命令
- if (rt_mq_recv(db_mq, &cmd, sizeof(struct db_command), RT_WAITING_FOREVER) != RT_EOK)
+ if (rt_mq_recv(db_mq, &cmd, sizeof(struct db_command), RT_WAITING_FOREVER) <= RT_EOK)
continue;
//检查排队超时
@@ -310,30 +310,32 @@ static void db_sqlite(void *parameter) {
if (cmd.type == DB_CMD_EXIT) break;
continue;
}
+
//打开数据库(如果未打开)
rt_mutex_take(state_mutex, RT_WAITING_FOREVER);
+ if (!g_db && current_enabled)
{
- if (!g_db && current_enabled) {
- int rc = sqlite3_open(DB_NAME, &g_db);
- if (rc != SQLITE_OK) {
- rt_kprintf("Failed to open DB at %s: %s\n", DB_NAME, sqlite3_errmsg(g_db));
- sqlite3_close(g_db);
- g_db = RT_NULL;
- rt_mutex_release(state_mutex);
- return_disabled(&cmd);
- continue;
- } else {
- rt_kprintf("Opened database: %s\n", DB_NAME);
- }
+ int rc = sqlite3_open(DB_NAME, &g_db);
+ if (rc != SQLITE_OK)
+ {
+ rt_kprintf("Failed to open DB at %s: %s\n", DB_NAME, sqlite3_errmsg(g_db));
+ sqlite3_close(g_db);
+ g_db = RT_NULL;
+ rt_mutex_release(state_mutex);
+ return_disabled(&cmd);
+ continue;
+ } else {
+ rt_kprintf("Opened database: %s\n", DB_NAME);
}
}
+
rt_mutex_release(state_mutex);
//执行命令
handle_db_command(&cmd);
//返回结果
- if (cmd.reply_sem) {
+ if (cmd.reply_sem != RT_NULL) {
rt_sem_release(cmd.reply_sem);
}
@@ -372,80 +374,55 @@ static void db_sqlite(void *parameter) {
*/
rt_err_t db_send_command(enum db_cmd_type type, const char* sql, rt_int32_t timeout_ms)
{
- struct db_command cmd;
- rt_sem_t sem = RT_NULL;
- rt_err_t result = RT_EOK;
-
- // 1. 创建临时信号量用于同步
- sem = rt_sem_create("db_rep", 0, RT_IPC_FLAG_FIFO);
- if (sem == RT_NULL)
- {
- rt_kprintf("Failed to create reply semaphore!\n");
- return -RT_ENOMEM;
- }
-
- // 2. 构造命令
- rt_memset(&cmd, 0, sizeof(cmd));
- cmd.type = type;
- rt_strncpy(cmd.sql, sql, MAX_SQL_LEN - 1);
- cmd.reply_sem = sem;
- cmd.send_tick = rt_tick_get();
-
- // 3. 发送命令到消息队列
- if (rt_mq_send(db_mq, &cmd, sizeof(cmd)) != RT_EOK)
- {
- rt_kprintf("Failed to send command to db_mq!\n");
- rt_sem_delete(sem);
- return -RT_ERROR;
- }
-
- // 4. 等待数据库线程处理完成(超时保护)
- if (timeout_ms > 0)
- {
- rt_int32_t tick = rt_tick_from_millisecond(timeout_ms);
- result = rt_sem_take(sem, tick);
- }
- else
- {
- result = rt_sem_take(sem, RT_WAITING_FOREVER); // 永久等待(慎用)
- }
-
- // 5. 检查结果
- if (result == RT_EOK)
- {
- rt_kprintf("SQL executed: code=%d\n", cmd.result_code);
- if (type == DB_CMD_SELECT || strlen(cmd.result) > 0)
- {
- rt_kprintf("Result: %s\n", cmd.result);
- }
- }
- else if (result == -RT_ETIMEOUT)
- {
- rt_kprintf("Database response timeout!\n");
- }
- else
- {
- rt_kprintf("Wait failed: %d\n", result);
- }
-
- // 6. 删除信号量
- rt_sem_delete(sem);
-
- return result;
+ if (!sql || !db_mq) {
+ return -RT_EINVAL;
+ }
+
+ struct db_command cmd;
+ rt_sem_t sem = rt_sem_create("db_rep", 0, RT_IPC_FLAG_FIFO);
+ if (sem == RT_NULL) {
+ return -RT_ENOMEM;
+ }
+
+ // 初始化命令结构体
+ rt_memset(&cmd, 0, sizeof(cmd));
+ cmd.type = type;
+ rt_strncpy(cmd.sql, sql, MAX_SQL_LEN - 1);
+ cmd.reply_sem = sem;
+ cmd.send_tick = rt_tick_get();
+
+ // 发送命令到数据库线程队列
+ if (rt_mq_send(db_mq, &cmd, sizeof(cmd)) != RT_EOK) {
+ rt_sem_delete(sem);
+ return -RT_ERROR;
+ }
+
+ // 计算等待 tick(兼容 RT_WAITING_FOREVER)
+ rt_int32_t wait_ticks;
+ if (timeout_ms == RT_WAITING_FOREVER) {
+ wait_ticks = RT_WAITING_FOREVER;
+ } else if (timeout_ms <= 0) {
+ wait_ticks = 0; // 立即超时
+ } else {
+ wait_ticks = rt_tick_from_millisecond(timeout_ms);
+ }
+
+ // 等待数据库线程处理完成
+ rt_err_t result = rt_sem_take(sem, wait_ticks);
+ //rt_sem_delete(sem);
+ return result;
}
/* 线程 */
void thread_DB_SQLite(void)
{
rt_thread_t tid;
- tid = rt_thread_create("db_sql", db_sqlite, RT_NULL, 1024 *32, 20, 10);
+ tid = rt_thread_create("db_sql", db_sqlite, RT_NULL, 1024 *48, 20, 10);
- if (tid != RT_NULL)
- {
- rt_thread_startup(tid);
- }
- else
- {
- LOG_D("Failed to create SQLite thread!\n");
- }
+ if (tid != RT_NULL)
+ {
+ rt_thread_startup(tid);
+ }else{
+ LOG_D("Failed to create SQLite thread!\n");
+ }
}
diff --git a/applications/sql/DB_SQLite.h b/applications/sql/DB_SQLite.h
index 6551beb..f580bd1 100644
--- a/applications/sql/DB_SQLite.h
+++ b/applications/sql/DB_SQLite.h
@@ -6,9 +6,10 @@
* Change Logs:
* Date Author Notes
* 2025-10-20 Administrator the first version
+ * 2025-11-29 Qwen Add auto_delete_sem to fix semaphore UAF
*/
#ifndef APPLICATIONS_DB_DB_SQLITE_H_
-#define APPLICATIONS_DB_SQLITE_SYS_H_
+#define APPLICATIONS_DB_DB_SQLITE_H_ // ← 注意:修正宏名,与文件路径一致(原为 _SYS_H_)
#include
@@ -69,6 +70,7 @@ struct db_command
char result[MAX_RESULT_LEN]; /**< 结果或错误信息 */
rt_sem_t reply_sem; /**< 回应信号量(由调用方创建,用于同步) */
rt_tick_t send_tick; /**< 发送时刻的系统 tick,用于超时检测 */
+ rt_bool_t auto_delete_sem; /**< 是否由数据库线程自动删除 reply_sem */
};
/* ========================
diff --git a/packages/packages.dbsqlite b/packages/packages.dbsqlite
index 844513c..fc48dd6 100644
Binary files a/packages/packages.dbsqlite and b/packages/packages.dbsqlite differ
diff --git a/packages/pkgs.json b/packages/pkgs.json
index b3be19d..ad7ddd1 100644
--- a/packages/pkgs.json
+++ b/packages/pkgs.json
@@ -18,5 +18,10 @@
"path": "/packages/system/littlefs",
"ver": "v2.11.2",
"name": "LITTLEFS"
+ },
+ {
+ "path": "/packages/peripherals/rs485",
+ "ver": "v1.06",
+ "name": "RS485"
}
]
\ No newline at end of file
diff --git a/packages/rs485-v1.06/LICENSE b/packages/rs485-v1.06/LICENSE
new file mode 100644
index 0000000..19e3071
--- /dev/null
+++ b/packages/rs485-v1.06/LICENSE
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+(This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.)
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ {description}
+ Copyright (C) {year} {fullname}
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random
+ Hacker.
+
+ {signature of Ty Coon}, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/packages/rs485-v1.06/SConscript b/packages/rs485-v1.06/SConscript
new file mode 100644
index 0000000..2ac4a83
--- /dev/null
+++ b/packages/rs485-v1.06/SConscript
@@ -0,0 +1,9 @@
+from building import *
+
+cwd = GetCurrentDir()
+path = [cwd+'/inc']
+src = Glob('src/*.c')
+
+group = DefineGroup('rs485', src, depend = ['PKG_USING_RS485'], CPPPATH = path)
+
+Return('group')
\ No newline at end of file
diff --git a/packages/rs485-v1.06/inc/rs485.h b/packages/rs485-v1.06/inc/rs485.h
new file mode 100644
index 0000000..d31688a
--- /dev/null
+++ b/packages/rs485-v1.06/inc/rs485.h
@@ -0,0 +1,135 @@
+/*
+ * rs485.h
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-06-08 qiyongzhong first version
+ * 2020-12-17 qiyongzhong add sample
+ * 2020-12-18 qiyongzhong add rs485_send_then_recv
+ */
+
+#ifndef __DRV_RS485_H__
+#define __DRV_RS485_H__
+
+#include
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+//#define RS485_USING_TEST //使用测试功能
+//#define RS485_USING_SAMPLE_SLAVE //使用从机示例
+//#define RS485_USING_SAMPLE_MASTER //使用主机示例
+//#define RS485_USING_DMA_RX //使用DMA接收
+//#define RS485_USING_INT_TX //使用中断发送
+//#define RS485_USING_DMA_TX //使用DMA发送
+
+#ifndef RS485_SW_DLY_US
+#define RS485_SW_DLY_US 0 //发送引脚控制切换延时
+#endif
+
+#define RS485_TX_COMP_TMO_MAX (3 * RT_TICK_PER_SECOND)//最大DMA传输完成超时
+#define RS485_BYTE_TMO_MIN 2 //最小字节超时
+#define RS485_BYTE_TMO_MAX 200 //最大字节超时
+
+typedef struct rs485_inst rs485_inst_t;
+
+/*
+ * @brief create rs485 instance dynamically
+ * @param serial - serial device name
+ * @param baudrate - serial baud rate
+ * @param parity - serial parity mode
+ * @param pin - mode contrle pin
+ * @param level - send mode level
+ * @retval instance handle
+ */
+rs485_inst_t * rs485_create(const char *serial, int baudrate, int parity, int pin, int level);
+
+/*
+ * @brief destory rs485 instance created dynamically
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_destory(rs485_inst_t * hinst);
+
+/*
+ * @brief config rs485 params
+ * @param hinst - instance handle
+ * @param baudrate - baudrate of communication
+ * @param databits - data bits, 5~8
+ * @param parity - parity bit, 0~2, 0 - none, 1 - odd, 2 - even
+ * @param stopbits - stop bits, 0~1, 0 - 1 stop bit, 1 - 2 stop bits
+ * @retval 0 - success, other - error
+ */
+int rs485_config(rs485_inst_t * hinst, int baudrate, int databits, int parity, int stopbits);
+
+/*
+ * @brief set wait datas timeout for receiving
+ * @param hinst - instance handle
+ * @param tmo_ms - receive wait timeout, 0--no wait, <0--wait forever, >0--wait timeout, default = 0
+ * @retval 0 - success, other - error
+ */
+int rs485_set_recv_tmo(rs485_inst_t * hinst, int tmo_ms);
+
+/*
+ * @brief set byte interval timeout for receiving
+ * @param hinst - instance handle
+ * @param tmo_ms - byte interval timeout, default is calculated from baudrate
+ * @retval 0 - success, other - error
+ */
+int rs485_set_byte_tmo(rs485_inst_t * hinst, int tmo_ms);
+
+/*
+ * @brief open rs485 connect
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_connect(rs485_inst_t * hinst);
+
+/*
+ * @brief close rs485 connect
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_disconn(rs485_inst_t * hinst);
+
+/*
+ * @brief receive datas from rs485
+ * @param hinst - instance handle
+ * @param buf - buffer addr
+ * @param size - maximum length of received datas
+ * @retval >=0 - length of received datas, <0 - error
+ */
+int rs485_recv(rs485_inst_t * hinst, void *buf, int size);
+
+/*
+ * @brief send datas to rs485
+ * @param hinst - instance handle
+ * @param buf - buffer addr
+ * @param size - length of send datas
+ * @retval >=0 - length of sent datas, <0 - error
+ */
+int rs485_send(rs485_inst_t * hinst, void *buf, int size);
+
+/*
+ * @brief break rs485 receive wait
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_break_recv(rs485_inst_t * hinst);
+
+/*
+ * @brief send data to rs485 and then receive response data from rs485
+ * @param hinst - instance handle
+ * @param send_buf - send buffer addr
+ * @param send_len - length of send datas
+ * @param recv_buf - recv buffer addr
+ * @param recv_size - maximum length of received datas
+ * @retval >=0 - length of received datas, <0 - error
+ */
+int rs485_send_then_recv(rs485_inst_t * hinst, void *send_buf, int send_len, void *recv_buf, int recv_size);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/packages/rs485-v1.06/readme.md b/packages/rs485-v1.06/readme.md
new file mode 100644
index 0000000..3bf855e
--- /dev/null
+++ b/packages/rs485-v1.06/readme.md
@@ -0,0 +1,136 @@
+# RS485驱动包
+
+## 1.简介
+
+**rs485** rs485接口通信驱动包。
+
+### 1.1目录结构
+
+`rs485` 软件包目录结构如下所示:
+
+```
+rs485
+├───inc // 头文件目录
+│ └───rs485.h // API 接口头文件
+├───src // 源码目录
+│ | rs485.c // 主模块
+│ | rs485_test.c // 测试模块
+│ | rs485_sample_slave.c // 从模式示例
+│ └───rs485_sample_master.c // 主模式示例
+│ license // 软件包许可证
+│ readme.md // 软件包使用说明
+└───SConscript // RT-Thread 默认的构建脚本
+```
+
+### 1.2许可证
+
+rs485 package 遵循 LGPLv2.1 许可,详见 `LICENSE` 文件。
+
+### 1.3依赖
+
+- RT_Thread 4.0
+- serial
+- pin
+
+## 2.使用
+
+### 2.1接口函数说明
+
+#### rs485_inst_t * rs485_create(char *serial, int baudrate, int parity, int pin, int level);
+- 功能 :动态创建rs485实例
+- 参数 :serial--串口设备名称
+- 参数 :baudrate--串口波特率
+- 参数 :parity--串口检验位
+- 参数 :pin--rs485收发模式控制引脚
+- 参数 :level--发送模式控制电平
+- 返回 :成功返回实例指针,失败返回NULL
+
+#### int rs485_destory(rs485_inst_t * hinst);
+- 功能 :销毁rs485实例
+- 参数 :hinst--rs485实例指针
+- 返回 :0--成功,其它--失败
+
+#### int rs485_config(rs485_inst_t * hinst, int baudrate, int databits, int parity, int stopbits);
+- 功能 :配置rs485通信参数
+- 参数 :hinst--rs485实例指针
+- 参数 :baudrate--通信波特率
+- 参数 :databits--数据位数, 5~8
+- 参数 :parity--检验位, 0~2, 0--无校验, 1--奇校验, 2--偶校验
+- 参数 :stopbits--停止位, 0~1, 0--1个停止位, 1--2个停止位
+- 返回 :0--成功,其它--错误
+
+#### int rs485_set_recv_tmo(rs485_inst_t * hinst, int tmo_ms);
+- 功能 :设置rs485接收超时时间
+- 参数 :hinst--rs485实例指针
+- 参数 :tmo_ms--超时时间,单位ms
+- 返回 :0--成功,其它--错误
+
+#### int rs485_set_byte_tmo(rs485_inst_t * hinst, int tmo_ms);
+- 功能 :设置rs485接收字节间隔超时时间
+- 参数 :hinst--rs485实例指针
+- 参数 :tmo_ms--超时时间,单位ms
+- 返回 :0--成功,其它--错误
+
+#### int rs485_connect(rs485_inst_t * hinst);
+- 功能 :打开rs485连接
+- 参数 :hinst--rs485实例指针
+- 返回 :0--成功,其它--错误
+
+#### int rs485_disconn(rs485_inst_t * hinst);
+- 功能 :关闭rs485连接
+- 参数 :hinst--rs485实例指针
+- 返回 :0--成功,其它--错误
+
+#### int rs485_recv(rs485_inst_t * hinst, void *buf, int size);
+- 功能 :从rs485接收数据
+- 参数 :hinst--rs485实例指针
+- 参数 :buf--接收数据缓冲区指针
+- 参数 :size--缓冲区尺寸
+- 返回 :>=0--接收到的数据长度,<0--错误
+
+#### int rs485_send(rs485_inst_t * hinst, void *buf, int size);
+- 功能 :向rs485发送数据
+- 参数 :hinst--rs485实例指针
+- 参数 :buf--发送数据缓冲区指针
+- 参数 :size--发送数据长度
+- 返回 :>=0--发送的数据长度,<0--错误
+
+#### int rs485_break_recv(rs485_inst_t * hinst);
+- 功能 :中断rs485接收等待
+- 参数 :hinst--rs485实例指针
+- 返回 :0--成功,其它--错误
+
+#### int rs485_send_then_recv(rs485_inst_t * hinst, void *send_buf, int send_len, void *recv_buf, int recv_size);
+- 功能 :先向rs485发送命令数据,然后从rs485接收响应数据,在多线程使用同一rs485时,可不受打扰地完成发送命令接收响应功能
+- 参数 :hinst--rs485实例指针
+- 参数 :send_buf--发送数据缓冲区指针
+- 参数 :send_len--发送数据长度
+- 参数 :recv_buf--接收数据缓冲区指针
+- 参数 :recv_size--接收缓冲区尺寸
+- 返回 :>=0--接收到的数据长度,<0--错误
+
+### 2.2获取组件
+
+- **方式1:**
+通过 *Env配置工具* 或 *RT-Thread studio* 开启软件包,根据需要配置各项参数;配置路径为 *RT-Thread online packages -> peripherals packages -> rs485*
+
+
+### 2.3配置参数说明
+
+| 参数宏 | 说明 |
+| ---- | ---- |
+| RS485_USING_TEST | 使用测试功能
+| RS485_TEST_SERIAL | 串口设备名称
+| RS485_TEST_BAUDRATE | 串口波特率
+| RS485_TEST_PARITY | 串口校验位
+| RS485_TEST_PIN | 收发模式控制引脚
+| RS485_TEST_LEVEL | 发送模式控制电平
+| RS485_TEST_BUF_SIZE | 缓冲区尺寸
+| RS485_TEST_RECV_TMO | 接收超时时间
+
+## 3. 联系方式
+
+* 维护:qiyongzhong
+* 主页:https://github.com/qiyongzhong0/rt-thread-rs485
+* 主页:https://gitee.com/qiyongzhong0/rt-thread-rs485
+* 邮箱:917768104@qq.com
diff --git a/packages/rs485-v1.06/src/rs485.c b/packages/rs485-v1.06/src/rs485.c
new file mode 100644
index 0000000..a19869c
--- /dev/null
+++ b/packages/rs485-v1.06/src/rs485.c
@@ -0,0 +1,625 @@
+/*
+ * drv_rs485.c
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-06-08 qiyongzhong first version
+ * 2020-12-14 qiyongzhong fix bug and release v1.0
+ * 2020-12-17 qiyongzhong fix log tag
+ * 2020-12-18 qiyongzhong add rs485_send_then_recv
+ * 2023-09-19 qiyongzhong add switch delay
+ * 2024-12-05 qiyongzhong add dma-rx, int-tx, dma-tx
+ */
+
+#include
+#include
+#include
+#include
+
+#define DBG_TAG "rs485"
+#define DBG_LVL DBG_INFO
+#include
+
+#define RS485_EVT_RX_IND (1<<0)
+#define RS485_EVT_RX_BREAK (1<<1)
+
+struct rs485_inst
+{
+ rt_device_t serial; //serial device handle
+ rt_mutex_t lock; //mutex handle
+ rt_event_t evt; //event handle
+ rt_uint8_t status; //connect status
+ rt_uint8_t level; //control pin send mode level, 0--low, 1--high
+ rt_int16_t pin; //control pin number used, -1--no using
+ rt_int32_t timeout; //receive block timeout, ms
+ rt_int32_t byte_tmo; //receive byte interval timeout, ms
+#ifdef RS485_USING_DMA_TX
+ rt_int32_t tx_dly_ms;
+ struct rt_completion tx_comp;//send completion
+#endif
+};
+
+#ifdef RS485_USING_DMA_TX
+static rt_err_t rs485_send_comp_hook(rt_device_t dev, void *buffer)
+{
+ rs485_inst_t *hinst = (rs485_inst_t *)(dev->user_data);
+ rt_completion_done(&(hinst->tx_comp));
+ return(RT_EOK);
+}
+#endif
+
+static rt_err_t rs485_recv_ind_hook(rt_device_t dev, rt_size_t size)
+{
+ rs485_inst_t *hinst = (rs485_inst_t *)(dev->user_data);
+ if (hinst->evt)
+ {
+ rt_event_send(hinst->evt, RS485_EVT_RX_IND);
+ }
+ return(RT_EOK);
+}
+
+static int rs485_cal_byte_tmo(int baudrate)
+{
+ int tmo = (40 * 1000) / baudrate;
+ if (tmo < RS485_BYTE_TMO_MIN)
+ {
+ tmo = RS485_BYTE_TMO_MIN;
+ }
+ else if (tmo > RS485_BYTE_TMO_MAX)
+ {
+ tmo = RS485_BYTE_TMO_MAX;
+ }
+ return (tmo);
+}
+
+static void rs485_mode_set(rs485_inst_t *hinst, int mode) // mode : 0--receive mode, 1--send mode
+{
+ if (hinst->pin < 0)
+ {
+ return;
+ }
+
+ if (mode)
+ {
+ rt_pin_write(hinst->pin, hinst->level);
+#if (RS485_SW_DLY_US > 0)
+ rt_hw_us_delay(RS485_SW_DLY_US);
+#endif
+ }
+ else
+ {
+#ifdef RS485_USING_DMA_TX
+ rt_completion_wait(&(hinst->tx_comp), RS485_TX_COMP_TMO_MAX);
+ rt_thread_mdelay(hinst->tx_dly_ms);//等待末尾数据传输完成
+#elif (RS485_SW_DLY_US > 0)
+ rt_hw_us_delay(RS485_SW_DLY_US);
+#endif
+ rt_pin_write(hinst->pin, !hinst->level);
+ }
+}
+
+static int rs485_dev_open(rs485_inst_t *hinst)
+{
+#ifdef RS485_USING_DMA_RX
+
+ #ifdef RS485_USING_DMA_TX
+ if (rt_device_open(hinst->serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX) == RT_EOK)
+ {
+ return(RT_EOK);
+ }
+ #endif
+
+ #ifdef RS485_USING_INT_TX
+ if (rt_device_open(hinst->serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_INT_TX) == RT_EOK)
+ {
+ return(RT_EOK);
+ }
+ #endif
+
+ if (rt_device_open(hinst->serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX) == RT_EOK)
+ {
+ return(RT_EOK);
+ }
+
+#endif
+
+ #ifdef RS485_USING_DMA_TX
+ if (rt_device_open(hinst->serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_TX) == RT_EOK)
+ {
+ return(RT_EOK);
+ }
+ #endif
+
+ #ifdef RS485_USING_INT_TX
+ if (rt_device_open(hinst->serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX) == RT_EOK)
+ {
+ return(RT_EOK);
+ }
+ #endif
+
+ if (rt_device_open(hinst->serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX) == RT_EOK)
+ {
+ return(RT_EOK);
+ }
+
+ return(-RT_ERROR);
+}
+
+/*
+ * @brief create rs485 instance dynamically
+ * @param serial - serial device name
+ * @param baudrate - serial baud rate
+ * @param parity - serial parity mode
+ * @param pin - mode contrle pin
+ * @param level - send mode level
+ * @retval instance handle
+ */
+rs485_inst_t * rs485_create(const char *name, int baudrate, int parity, int pin, int level)
+{
+ rs485_inst_t *hinst;
+ rt_device_t dev;
+
+ dev = rt_device_find(name);
+ if (dev == RT_NULL)
+ {
+ LOG_E("rs485 instance initiliaze error, the serial device(%s) no found.", name);
+ return(RT_NULL);
+ }
+
+ if (dev->type != RT_Device_Class_Char)
+ {
+ LOG_E("rs485 instance initiliaze error, the serial device(%s) type is not char.", name);
+ return(RT_NULL);
+ }
+
+ hinst = rt_malloc(sizeof(struct rs485_inst));
+ if (hinst == RT_NULL)
+ {
+ LOG_E("rs485 create fail. no memory for rs485 create instance.");
+ return(RT_NULL);
+ }
+
+ hinst->lock = rt_mutex_create(name, RT_IPC_FLAG_FIFO);
+ if (hinst->lock == RT_NULL)
+ {
+ rt_free(hinst);
+ LOG_E("rs485 create fail. no memory for rs485 create mutex.");
+ return(RT_NULL);
+ }
+
+ hinst->evt = rt_event_create(name, RT_IPC_FLAG_FIFO);
+ if (hinst->evt == RT_NULL)
+ {
+ rt_mutex_delete(hinst->lock);
+ rt_free(hinst);
+ LOG_E("rs485 create fail. no memory for rs485 create event.");
+ return(RT_NULL);
+ }
+
+#ifdef RS485_USING_DMA_TX
+ hinst->tx_dly_ms = ((2 * 11 *1000) / baudrate) + 1;
+ rt_completion_init(&(hinst->tx_comp));
+#endif
+
+ hinst->serial = dev;
+ hinst->status = 0;
+ hinst->pin = pin;
+ hinst->level = (level != 0);
+ hinst->timeout = 0;
+ hinst->byte_tmo = rs485_cal_byte_tmo(baudrate);
+
+ rs485_config(hinst, baudrate, 8, parity, 0);
+
+ LOG_D("rs485 create success.");
+
+ return(hinst);
+}
+
+/*
+ * @brief destory rs485 instance created dynamically
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_destory(rs485_inst_t * hinst)
+{
+ if (hinst == RT_NULL)
+ {
+ LOG_E("rs485 destory fail. hinst is NULL.");
+ return(-RT_ERROR);
+ }
+
+ rs485_disconn(hinst);
+
+ if (hinst->lock)
+ {
+ rt_mutex_delete(hinst->lock);
+ hinst->lock = RT_NULL;
+ }
+
+ if (hinst->evt)
+ {
+ rt_event_delete(hinst->evt);
+ hinst->evt = RT_NULL;
+ }
+
+ rt_free(hinst);
+
+ LOG_D("rs485 destory success.");
+
+ return(RT_EOK);
+}
+
+/*
+ * @brief config rs485 params
+ * @param hinst - instance handle
+ * @param baudrate - baudrate of communication
+ * @param databits - data bits, 5~8
+ * @param parity - parity bit, 0~2, 0 - none, 1 - odd, 2 - even
+ * @param stopbits - stop bits, 0~1, 0 - 1 stop bit, 1 - 2 stop bits
+ * @retval 0 - success, other - error
+ */
+int rs485_config(rs485_inst_t * hinst, int baudrate, int databits, int parity, int stopbits)
+{
+ struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
+
+ if (hinst == RT_NULL)
+ {
+ LOG_E("rs485 config fail. hinst is NULL.");
+ return(-RT_ERROR);
+ }
+
+#ifdef RS485_USING_DMA_TX
+ hinst->tx_dly_ms = ((2 * 11 *1000) / baudrate) + 1;
+#endif
+
+ hinst->byte_tmo = rs485_cal_byte_tmo(baudrate);
+
+ config.baud_rate = baudrate;
+ config.data_bits = databits;
+ config.parity = parity;
+ config.stop_bits = stopbits;
+ rt_device_control(hinst->serial, RT_DEVICE_CTRL_CONFIG, &config);
+
+ return(RT_EOK);
+}
+
+/*
+ * @brief set wait datas timeout for receiving
+ * @param hinst - instance handle
+ * @param tmo_ms - receive wait timeout, 0--no wait, <0--wait forever, >0--wait timeout, default = 0
+ * @retval 0 - success, other - error
+ */
+int rs485_set_recv_tmo(rs485_inst_t * hinst, int tmo_ms)
+{
+ if (hinst == RT_NULL)
+ {
+ LOG_E("rs485 set recv timeout fail. hinst is NULL.");
+ return(-RT_ERROR);
+ }
+
+ hinst->timeout = tmo_ms;
+
+ LOG_D("rs485 set recv timeout success. the value is %d.", tmo_ms);
+
+ return(RT_EOK);
+}
+
+/*
+ * @brief set byte interval timeout for receiving
+ * @param hinst - instance handle
+ * @param tmo_ms - byte interval timeout, default is calculated from baudrate
+ * @retval 0 - success, other - error
+ */
+int rs485_set_byte_tmo(rs485_inst_t * hinst, int tmo_ms)
+{
+ if (hinst == RT_NULL)
+ {
+ LOG_E("rs485 set byte timeout fail. hinst is NULL.");
+ return(-RT_ERROR);
+ }
+
+ if (tmo_ms < RS485_BYTE_TMO_MIN)
+ {
+ tmo_ms = RS485_BYTE_TMO_MIN;
+ }
+ else if (tmo_ms > RS485_BYTE_TMO_MAX)
+ {
+ tmo_ms = RS485_BYTE_TMO_MAX;
+ }
+
+ hinst->byte_tmo = tmo_ms;
+
+ LOG_D("rs485 set byte timeout success. the value is %d.", tmo_ms);
+
+ return(RT_EOK);
+}
+
+/*
+ * @brief open rs485 connect
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_connect(rs485_inst_t * hinst)
+{
+ if (hinst == RT_NULL)
+ {
+ LOG_E("rs485 connect fail. hinst is NULL.");
+ return(-RT_ERROR);
+ }
+
+ if (hinst->status == 1)//is connected
+ {
+ LOG_D("rs485 is connected.");
+ return(RT_EOK);
+ }
+
+ if ( rs485_dev_open(hinst) != RT_EOK)
+ {
+ LOG_E("rs485 instance connect error. serial open fail.");
+ return(-RT_ERROR);
+ }
+
+ if (hinst->pin >= 0)
+ {
+ rt_pin_mode(hinst->pin, PIN_MODE_OUTPUT);
+ rt_pin_write(hinst->pin, ! hinst->level);
+ }
+
+
+ hinst->serial->user_data = hinst;
+ hinst->serial->rx_indicate = rs485_recv_ind_hook;
+#ifdef RS485_USING_DMA_TX
+ hinst->serial->tx_complete = rs485_send_comp_hook;
+#endif
+ hinst->status = 1;
+
+ LOG_D("rs485 connect success.");
+
+ return(RT_EOK);
+}
+
+/*
+ * @brief close rs485 connect
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_disconn(rs485_inst_t * hinst)
+{
+ if (hinst == RT_NULL)
+ {
+ LOG_E("rs485 disconnect fail. hinst is NULL.");
+ return(-RT_ERROR);
+ }
+
+ if (hinst->status == 0)//is not connected
+ {
+ LOG_D("rs485 is not connected.");
+ return(RT_EOK);
+ }
+
+ rt_mutex_take(hinst->lock, RT_WAITING_FOREVER);
+
+ if (hinst->serial)
+ {
+ hinst->serial->rx_indicate = RT_NULL;
+#ifdef RS485_USING_DMA_TX
+ hinst->serial->tx_complete = RT_NULL;
+#endif
+ rt_device_close(hinst->serial);
+ }
+
+ if (hinst->pin >= 0)
+ {
+ rt_pin_mode(hinst->pin, PIN_MODE_INPUT);
+ }
+
+ hinst->status = 0;
+
+ rt_mutex_release(hinst->lock);
+
+ LOG_D("rs485 disconnect success.");
+
+ return(RT_EOK);
+}
+
+/*
+ * @brief receive datas from rs485
+ * @param hinst - instance handle
+ * @param buf - buffer addr
+ * @param size - maximum length of received datas
+ * @retval >=0 - length of received datas, <0 - error
+ */
+int rs485_recv(rs485_inst_t * hinst, void *buf, int size)
+{
+ int recv_len = 0;
+ rt_uint32_t recved = 0;
+
+ if (hinst == RT_NULL || buf == RT_NULL || size == 0)
+ {
+ LOG_E("rs485 receive fail. param error.");
+ return(-RT_ERROR);
+ }
+
+ if (hinst->status == 0)
+ {
+ LOG_E("rs485 receive fail. it is not connected.");
+ return(-RT_ERROR);
+ }
+
+ if (rt_mutex_take(hinst->lock, RT_WAITING_FOREVER) != RT_EOK)
+ {
+ LOG_E("rs485 receive fail. it is destoried.");
+ return(-RT_ERROR);
+ }
+
+ while(size)
+ {
+ int len = rt_device_read(hinst->serial, 0, (char *)buf + recv_len, size);
+ if (len)
+ {
+ recv_len += len;
+ size -= len;
+ continue;
+ }
+ rt_event_control(hinst->evt, RT_IPC_CMD_RESET, RT_NULL);
+ if (recv_len)
+ {
+ if (rt_event_recv(hinst->evt, RS485_EVT_RX_IND,
+ (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), hinst->byte_tmo, &recved) != RT_EOK)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if (rt_event_recv(hinst->evt, (RS485_EVT_RX_IND | RS485_EVT_RX_BREAK),
+ (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), hinst->timeout, &recved) != RT_EOK)
+ {
+ break;
+ }
+ if ((recved & RS485_EVT_RX_BREAK) != 0)
+ {
+ rt_mutex_release(hinst->lock);
+ rt_thread_delay(2);
+ return(0);
+ }
+ }
+ }
+
+ rt_mutex_release(hinst->lock);
+
+ return(recv_len);
+}
+
+/*
+ * @brief send datas to rs485
+ * @param hinst - instance handle
+ * @param buf - buffer addr
+ * @param size - length of send datas
+ * @retval >=0 - length of sent datas, <0 - error
+ */
+int rs485_send(rs485_inst_t * hinst, void *buf, int size)
+{
+ int send_len = 0;
+
+ if (hinst == RT_NULL || buf == RT_NULL || size == 0)
+ {
+ LOG_E("rs485 send fail. param is error.");
+ return(-RT_ERROR);
+ }
+
+ if (hinst->status == 0)
+ {
+ LOG_E("rs485 send fail. it is not connected.");
+ return(-RT_ERROR);
+ }
+
+ if (rt_mutex_take(hinst->lock, RT_WAITING_FOREVER) != RT_EOK)
+ {
+ LOG_E("rs485 send fail. it is destoried.");
+ return(-RT_ERROR);
+ }
+
+ rs485_mode_set(hinst, 1);//set to send mode
+
+ send_len = rt_device_write(hinst->serial, 0, buf, size);
+
+ rs485_mode_set(hinst, 0);//set to receive mode
+
+ rt_mutex_release(hinst->lock);
+
+ return(send_len);
+}
+
+/*
+ * @brief break rs485 receive wait
+ * @param hinst - instance handle
+ * @retval 0 - success, other - error
+ */
+int rs485_break_recv(rs485_inst_t * hinst)
+{
+ if ((hinst == RT_NULL) || (hinst->evt == RT_NULL))
+ {
+ return(-RT_ERROR);
+ }
+
+ rt_event_send(hinst->evt, RS485_EVT_RX_BREAK);
+
+ return (RT_EOK);
+}
+
+/*
+ * @brief send data to rs485 and then receive response data from rs485
+ * @param hinst - instance handle
+ * @param send_buf - send buffer addr
+ * @param send_len - length of send datas
+ * @param recv_buf - recv buffer addr
+ * @param recv_size - maximum length of received datas
+ * @retval >=0 - length of received datas, <0 - error
+ */
+int rs485_send_then_recv(rs485_inst_t * hinst, void *send_buf, int send_len, void *recv_buf, int recv_size)
+{
+ int recv_len = 0;
+ rt_uint32_t recved = 0;
+
+ if (hinst == RT_NULL || send_buf == RT_NULL || send_len == 0 || recv_buf == RT_NULL || recv_size == 0)
+ {
+ LOG_E("rs485 send then recv fail. param is error.");
+ return(-RT_ERROR);
+ }
+
+ if (hinst->status == 0)
+ {
+ LOG_E("rs485 send_then_recv fail. it is not connected.");
+ return(-RT_ERROR);
+ }
+
+ if (rt_mutex_take(hinst->lock, RT_WAITING_FOREVER) != RT_EOK)
+ {
+ LOG_E("rs485 send_then_recv fail. it is destoried.");
+ return(-RT_ERROR);
+ }
+
+ rs485_mode_set(hinst, 1);//set to send mode
+ send_len = rt_device_write(hinst->serial, 0, send_buf, send_len);
+ rs485_mode_set(hinst, 0);//set to receive mode
+ if (send_len < 0)
+ {
+ rt_mutex_release(hinst->lock);
+ LOG_E("rs485 send_then_recv fail. send datas error.");
+ return(-RT_ERROR);
+ }
+
+ while(recv_size)
+ {
+ int len = rt_device_read(hinst->serial, 0, (char *)recv_buf + recv_len, recv_size);
+ if (len)
+ {
+ recv_len += len;
+ recv_size -= len;
+ continue;
+ }
+ rt_event_control(hinst->evt, RT_IPC_CMD_RESET, RT_NULL);
+ if (recv_len)
+ {
+ if (rt_event_recv(hinst->evt, RS485_EVT_RX_IND,
+ (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), hinst->byte_tmo, &recved) != RT_EOK)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if (rt_event_recv(hinst->evt, RS485_EVT_RX_IND,
+ (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), hinst->timeout, &recved) != RT_EOK)
+ {
+ break;
+ }
+ }
+ }
+
+ rt_mutex_release(hinst->lock);
+
+ return(recv_len);
+}
+
diff --git a/packages/rs485-v1.06/src/rs485_sample_master.c b/packages/rs485-v1.06/src/rs485_sample_master.c
new file mode 100644
index 0000000..a51b8bc
--- /dev/null
+++ b/packages/rs485-v1.06/src/rs485_sample_master.c
@@ -0,0 +1,97 @@
+/*
+ * rs485_sample_master.c
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-12-17 qiyongzhong first version
+ * 2020-12-18 qiyongzhong fix to rs485_send_then_recv
+ */
+
+#include
+#include
+#include
+#include
+
+#define DBG_TAG "rs485.sample.master"
+#define DBG_LVL DBG_LOG
+#include
+
+#ifdef RS485_USING_SAMPLE_MASTER
+
+#ifndef RS485_SAMPLE_MASTER_SERIAL
+#define RS485_SAMPLE_MASTER_SERIAL "uart2" //serial device name
+#endif
+
+#ifndef RS485_SAMPLE_MASTER_BAUDRATE
+#define RS485_SAMPLE_MASTER_BAUDRATE 9600
+#endif
+
+#ifndef RS485_SAMPLE_MASTER_PARITY
+#define RS485_SAMPLE_MASTER_PARITY 0 //0 -- none parity
+#endif
+
+#ifndef RS485_SAMPLE_MASTER_PIN
+#define RS485_SAMPLE_MASTER_PIN -1 //-1 -- nonuse rs485 mode control
+#endif
+
+#ifndef RS485_SAMPLE_MASTER_LVL
+#define RS485_SAMPLE_MASTER_LVL 1
+#endif
+
+static void rs485_sample_master(void *args)
+{
+ const char read_cmd[] = "read datas test\r\n";
+ static rt_uint8_t buf[256];
+ rs485_inst_t *hinst = rs485_create(RS485_SAMPLE_MASTER_SERIAL, RS485_SAMPLE_MASTER_BAUDRATE,
+ RS485_SAMPLE_MASTER_PARITY, RS485_SAMPLE_MASTER_PIN, RS485_SAMPLE_MASTER_LVL);
+
+ if (hinst == RT_NULL)
+ {
+ LOG_E("create rs485 instance fail.");
+ return;
+ }
+
+ rs485_set_recv_tmo(hinst, 1000);
+ if (rs485_connect(hinst) != RT_EOK)
+ {
+ rs485_destory(hinst);
+ LOG_E("rs485 connect fail.");
+ return;
+ }
+
+ while(1)
+ {
+ int len = strlen(read_cmd);
+ len = rs485_send_then_recv(hinst, (void *)read_cmd, len, buf, sizeof(buf));
+ if (len < 0)
+ {
+ LOG_E("rs485 send datas error.");
+ break;
+ }
+
+ if (len == 0)
+ {
+ LOG_D("rs485 recv timeout.");
+ continue;
+ }
+
+ buf[len] = 0;
+ LOG_D("rs485 recv %d datas : %s", len, buf);
+ }
+
+ rs485_destory(hinst);
+ LOG_D("rs485 test end.");
+}
+
+static int rs485_sample_master_init(void)
+{
+ rt_thread_t tid = rt_thread_create("rs485master", rs485_sample_master, RT_NULL, 1024, 8, 20);
+ RT_ASSERT(tid != RT_NULL);
+ rt_thread_startup(tid);
+ LOG_I("rs485 sample master thread startup...");
+ return(RT_EOK);
+}
+INIT_APP_EXPORT(rs485_sample_master_init);
+
+#endif
+
diff --git a/packages/rs485-v1.06/src/rs485_sample_slave.c b/packages/rs485-v1.06/src/rs485_sample_slave.c
new file mode 100644
index 0000000..1eb517e
--- /dev/null
+++ b/packages/rs485-v1.06/src/rs485_sample_slave.c
@@ -0,0 +1,80 @@
+/*
+ * rs485_sample_slave.c
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-12-17 qiyongzhong first version
+ */
+
+#include
+#include
+#include
+
+#define DBG_TAG "rs485.sample.slave"
+#define DBG_LVL DBG_LOG
+#include
+
+#ifdef RS485_USING_SAMPLE_SLAVE
+
+#ifndef RS485_SAMPLE_SLAVE_SERIAL
+#define RS485_SAMPLE_SLAVE_SERIAL "uart2"
+#endif
+
+#ifndef RS485_SAMPLE_SLAVE_BAUDRATE
+#define RS485_SAMPLE_SLAVE_BAUDRATE 9600
+#endif
+
+#ifndef RS485_SAMPLE_MASTER_PARITY
+#define RS485_SAMPLE_MASTER_PARITY 0 //0 -- none parity
+#endif
+
+#ifndef RS485_SAMPLE_SLAVE_PIN
+#define RS485_SAMPLE_SLAVE_PIN -1 //-1 -- nonuse rs485 mode control
+#endif
+
+#ifndef RS485_SAMPLE_SLAVE_LVL
+#define RS485_SAMPLE_SLAVE_LVL 1
+#endif
+
+static void rs485_sample_slave_loopback_test(void *args)
+{
+ static rt_uint8_t buf[256];
+ rs485_inst_t *hinst = rs485_create(RS485_SAMPLE_SLAVE_SERIAL, RS485_SAMPLE_SLAVE_BAUDRATE,
+ RS485_SAMPLE_MASTER_PARITY, RS485_SAMPLE_SLAVE_PIN, RS485_SAMPLE_SLAVE_LVL);
+
+ if (hinst == RT_NULL)
+ {
+ LOG_E("create rs485 instance fail.");
+ return;
+ }
+
+ rs485_set_recv_tmo(hinst, RT_WAITING_FOREVER);
+ if (rs485_connect(hinst) != RT_EOK)
+ {
+ rs485_destory(hinst);
+ LOG_E("rs485 connect fail.");
+ return;
+ }
+
+ while(1)
+ {
+ int len = rs485_recv(hinst, buf, sizeof(buf));
+ if (len > 0)
+ {
+ rs485_send(hinst, buf, len);
+ }
+ }
+}
+
+static int rs485_sample_slave_init(void)
+{
+ rt_thread_t tid = rt_thread_create("rs485slave", rs485_sample_slave_loopback_test, RT_NULL, 1024, 8, 20);
+ RT_ASSERT(tid != RT_NULL);
+ rt_thread_startup(tid);
+ LOG_I("rs485 sample slave thread startup...");
+ return(RT_EOK);
+}
+INIT_APP_EXPORT(rs485_sample_slave_init);
+
+#endif
+
diff --git a/packages/rs485-v1.06/src/rs485_test.c b/packages/rs485-v1.06/src/rs485_test.c
new file mode 100644
index 0000000..2c3731d
--- /dev/null
+++ b/packages/rs485-v1.06/src/rs485_test.c
@@ -0,0 +1,317 @@
+/*
+ * rs485_test.c
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2020-06-08 qiyongzhong first version
+ * 2020-12-17 qiyongzhong add config function
+ * 2020-12-18 qiyongzhong add send_then_recv
+ */
+
+#include
+#include
+#include
+#include
+
+#ifdef RS485_USING_TEST
+
+#ifndef RS485_TEST_SERIAL
+#define RS485_TEST_SERIAL "uart1" //default test serial
+#endif
+
+#ifndef RS485_TEST_BAUDRATE
+#define RS485_TEST_BAUDRATE 9600 //defalut test baudrate
+#endif
+
+#ifndef RS485_TEST_PARITY
+#define RS485_TEST_PARITY 0 //defalut test parity
+#endif
+
+#ifndef RS485_TEST_PIN
+#define RS485_TEST_PIN GET_PIN(A, 0) //default test ctrl pin
+#endif
+
+#ifndef RS485_TEST_LEVEL
+#define RS485_TEST_LEVEL 1 //default test send mode level
+#endif
+
+#ifndef RS485_TEST_BUF_SIZE
+#define RS485_TEST_BUF_SIZE 1024 //default test buffer size
+#endif
+
+#ifndef RS485_TEST_RECV_TMO
+#define RS485_TEST_RECV_TMO 30000 //default test recicve timeout
+#endif
+
+static rs485_inst_t * test_hinst = RT_NULL;
+static char test_buf[RS485_TEST_BUF_SIZE];
+
+static const char *cmd_info[] =
+{
+ "Usage: \n",
+ "rs485 create [serial] [baudrate] [parity] [pin] [level] - create rs485 instance.\n",
+ "rs485 destory - destory rs485 instance.\n",
+ "rs485 set_recv_tmo [tmo_ms] - set recieve timeout.\n",
+ "rs485 set_byte_tmo [tmo_ms] - set byte timeout.\n",
+ "rs485 connect - open rs485 connect.\n",
+ "rs485 disconn - close rs485 connect.\n",
+ "rs485 recv [size] - receive from rs485.\n",
+ "rs485 send [size] - send to rs485.\n",
+ "rs485 cfg [baudrate] [databits] [parity] [stopbits] - config rs485.\n",
+ "rs485 send_then_recv [send_size] [recv_size] - send to rs485 and then receive from rs485.\n",
+ "\n"
+};
+
+static void show_cmd_info(void)
+{
+ for(int i=0; i= 3)
+ {
+ serial = argv[2];
+ }
+ if ( argc >= 4)
+ {
+ baudrate = atoi(argv[3]);
+ }
+ if (argc >= 5)
+ {
+ parity = atoi(argv[4]);
+ }
+ if (argc >= 6)
+ {
+ pin = atoi(argv[5]);
+ }
+ if (argc >= 7)
+ {
+ level = atoi(argv[6]);
+ }
+ test_hinst = rs485_create(serial, baudrate, parity, pin, level);
+ if (test_hinst != NULL)
+ {
+ rt_kprintf("rs485 instance create success.\n");
+ rt_kprintf("rs485 serial : %s \n", serial);
+ rt_kprintf("rs485 baudrate : %d \n", baudrate);
+ rt_kprintf("rs485 parity : %d \n", parity);
+ rt_kprintf("rs485 control pin : %d \n", pin);
+ rt_kprintf("rs485 send mode level : %d \n", level);
+
+ rs485_set_recv_tmo(test_hinst, RS485_TEST_RECV_TMO);
+ rt_kprintf("rs485 receive timeout : %d \n", RS485_TEST_RECV_TMO);
+ }
+ return;
+ }
+
+ if (strcmp(argv[1], "destory") == 0)
+ {
+ rs485_destory(test_hinst);
+ test_hinst = NULL;
+ return;
+ }
+
+ if (strcmp(argv[1], "set_recv_tmo") == 0)
+ {
+ int tmo_ms = RS485_TEST_RECV_TMO;
+ if (argc >= 3)
+ {
+ tmo_ms = atoi(argv[2]);
+ }
+ rs485_set_recv_tmo(test_hinst, tmo_ms);
+ return;
+ }
+
+ if (strcmp(argv[1], "set_byte_tmo") == 0)
+ {
+ int tmo_ms = 0;
+ if (argc >= 3)
+ {
+ tmo_ms = atoi(argv[2]);
+ }
+ rs485_set_byte_tmo(test_hinst, tmo_ms);
+ return;
+ }
+
+ if (strcmp(argv[1], "connect") == 0)
+ {
+ if (test_hinst == NULL)
+ {
+ rt_kprintf("the test instance is NULL, please create first.\n");
+ return;
+ }
+ if (rs485_connect(test_hinst) == RT_EOK)
+ {
+ rt_kprintf("rs485 instance connect success.\n");
+ }
+ else
+ {
+ rt_kprintf("rs485 instance connect fail.\n");
+ }
+ return;
+ }
+
+ if (strcmp(argv[1], "disconn") == 0)
+ {
+ rs485_disconn(test_hinst);
+ return;
+ }
+
+ if (strcmp(argv[1], "recv") == 0)
+ {
+ int size = RS485_TEST_BUF_SIZE;
+ int len = 0;
+
+ if (test_hinst == NULL)
+ {
+ rt_kprintf("the test instance is NULL, please create first.\n");
+ return;
+ }
+ if (argc >= 3)
+ {
+ size = atoi(argv[2]);
+ if (size > RS485_TEST_BUF_SIZE)
+ {
+ size = RS485_TEST_BUF_SIZE;
+ }
+ }
+ rt_kprintf("rs485 start receiving, max length : %d .\n", size);
+ len = rs485_recv(test_hinst, test_buf, size);
+ if (len == 0)
+ {
+ rt_kprintf("rs485 receive timeout.\n");
+ return;
+ }
+ rt_kprintf("rs485 received %d datas (hex) : ", len);
+ for (int i=0; i= 3)
+ {
+ size = atoi(argv[2]);
+ if (size > RS485_TEST_BUF_SIZE)
+ {
+ size = RS485_TEST_BUF_SIZE;
+ }
+ }
+ for (int i=0; i= 3)
+ {
+ baudrate = atoi(argv[2]);
+ }
+ if ( argc >= 4)
+ {
+ databits = atoi(argv[3]);
+ }
+ if (argc >= 5)
+ {
+ parity = atoi(argv[4]);
+ }
+ if (argc >= 6)
+ {
+ stopbits = atoi(argv[5]);
+ }
+ rs485_config(test_hinst, baudrate, databits, parity, stopbits);
+ return;
+ }
+
+ if (strcmp(argv[1], "send_then_recv") == 0)
+ {
+ int send_size = RS485_TEST_BUF_SIZE;
+ int recv_size = RS485_TEST_BUF_SIZE;
+ int len = 0;
+
+ if (test_hinst == NULL)
+ {
+ rt_kprintf("the test instance is NULL, please create first.\n");
+ return;
+ }
+ if (argc >= 3)
+ {
+ send_size = atoi(argv[2]);
+ }
+ if (argc >= 4)
+ {
+ recv_size = atoi(argv[3]);
+ }
+ for (int i=0; i