From 0735772f8afd1daad4b9b4625dedbdfb82a2083c Mon Sep 17 00:00:00 2001 From: sc <2401809606@qq.com> Date: Sat, 29 Nov 2025 02:03:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B2=E5=8F=A31=EF=BC=8C485=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=82=20=E6=95=B0=E6=8D=AE=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=8F=8A=E6=95=B0=E6=8D=AE=E5=BA=93=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .config | 24 +- .cproject | 6 +- .settings/language.settings.xml | 2 +- applications/DATA_uart.c | 174 ++--- applications/data/DATA_comm.c | 18 +- applications/main.c | 13 +- applications/sql/DB_SQLite.c | 147 ++-- applications/sql/DB_SQLite.h | 4 +- packages/packages.dbsqlite | Bin 274432 -> 274432 bytes packages/pkgs.json | 5 + packages/rs485-v1.06/LICENSE | 504 ++++++++++++++ packages/rs485-v1.06/SConscript | 9 + packages/rs485-v1.06/inc/rs485.h | 135 ++++ packages/rs485-v1.06/readme.md | 136 ++++ packages/rs485-v1.06/src/rs485.c | 625 ++++++++++++++++++ .../rs485-v1.06/src/rs485_sample_master.c | 97 +++ packages/rs485-v1.06/src/rs485_sample_slave.c | 80 +++ packages/rs485-v1.06/src/rs485_test.c | 317 +++++++++ rtconfig.h | 6 + 19 files changed, 2070 insertions(+), 232 deletions(-) create mode 100644 packages/rs485-v1.06/LICENSE create mode 100644 packages/rs485-v1.06/SConscript create mode 100644 packages/rs485-v1.06/inc/rs485.h create mode 100644 packages/rs485-v1.06/readme.md create mode 100644 packages/rs485-v1.06/src/rs485.c create mode 100644 packages/rs485-v1.06/src/rs485_sample_master.c create mode 100644 packages/rs485-v1.06/src/rs485_sample_slave.c create mode 100644 packages/rs485-v1.06/src/rs485_test.c 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 844513c0cc9e8d68c7a7502b4f0d43b8c5bd26ec..fc48dd6757b4fc9dc14469a4fe3a7e04ad319d9f 100644 GIT binary patch delta 795 zcmaixJ!=#}7{|T1Rqidlf?%t+%=-&sbzC86L=Vv-kezvEh8*NBm)$jm5cWd2R+O#m z^#cfs-z1GqzJXn8=RBJ;SuE$7hu{C@SzPWcE_XiMXAT4sVMmE{n6N;VAV_IRF;EM}a_TY8>N0uN zgf7fLL1(0Zd&aum7VlHAU(3n>DIc5P^^q z-Usa@_d;{es51aa$9zJA8P|F8s6pgr?7AKe4g?_vTPZN3OnVjEp&`V%GcW4nL{^*F zRm)SKPF+*yLU1C4bW%{yjRJ!ZwJJCgsfq_TuIK++oy`88Gd;LYt=6X`L@SPjcFe_c zr3tZijxA!Ga;*crtdA1CX>~k2niY^w=H+$j8fvi?j8Gf1V{Y)uB4ONGq__3;1GQiTq#qFn4SfI)r4L08?+%#` WIStzlmr+0iEU|z*4Yz$Q1cL(NoD~rO 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