diff --git a/APP_Framework/Applications/control_app/plc_demo/Makefile b/APP_Framework/Applications/control_app/plc_demo/Makefile index 3fba029fa..097c9f7d4 100755 --- a/APP_Framework/Applications/control_app/plc_demo/Makefile +++ b/APP_Framework/Applications/control_app/plc_demo/Makefile @@ -1,3 +1,3 @@ -SRC_DIR := advantech beckhoff br delta mitsubishi omron schneider siemens ge xinje inovance keyence ab abb +SRC_DIR := advantech beckhoff br delta mitsubishi omron schneider siemens ge xinje inovance keyence panasonic fatek ab abb include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/control_app/plc_demo/br/image/Br PPC2100 PLC.jpg b/APP_Framework/Applications/control_app/plc_demo/br/image/Br PPC2100 PLC.jpg new file mode 100644 index 000000000..24d312116 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/br/image/Br PPC2100 PLC.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/br/test_recipe_br_ppc2100.json b/APP_Framework/Applications/control_app/plc_demo/br/json/test_recipe_br_ppc2100.json similarity index 100% rename from APP_Framework/Applications/control_app/plc_demo/br/test_recipe_br_ppc2100.json rename to APP_Framework/Applications/control_app/plc_demo/br/json/test_recipe_br_ppc2100.json diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/README.md b/APP_Framework/Applications/control_app/plc_demo/delta/README.md index 16ba6225c..6d0dec6b6 100644 --- a/APP_Framework/Applications/control_app/plc_demo/delta/README.md +++ b/APP_Framework/Applications/control_app/plc_demo/delta/README.md @@ -1,22 +1,48 @@ -# 台达 DVP通信测试 +# 台达 PLC与矽达通ARM通信测试 [TOC] -## 通信接线及参数设置 +## 台达DVP与矽达通ARM通信处测试 + +### 通信接线及参数设置 * 网口 * 通过自带 RJ45 网口连接 * 网口参数:IP:192.168.250.27 Port:502 * 测试的协议:Modbus TCP -## 存储区 +### 存储区 - 含M,D,X,Y。台达PLC中 各存储区地址和Modbus地址有明确的对应表,详见台达DVP协议解析测试文档。 -## 通信测试 +### 通信测试 - 共测试BOOL,INT16,INT32,FLOAT 共四种类型数据。 - 测试D区,M区和Y区。 +## 台达AS332T与矽达通ARM通信处测试 + +### 通信接线及参数设置 + +* 网口 + * 通过自带 RJ45 网口连接 + * 网口参数:IP:192.168.250.5 Port:502 + * 测试的协议:Modbus TCP + +### 存储区 + +- 含M,D,X,Y。台达PLC中 各存储区地址和Modbus地址有明确的对应表,详见台达AS332T协议解析测试文档。 + +### 通信测试结果 + +- 共测试BOOL,INT16,INT32,FLOAT 共四种类型数据。 +- 测试D区,M区和Y区。 + +![](./image/recipe.png) + +![](./image/test_result1.png) + +![](./image/test_result2.png) + diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/delta_as332t.c b/APP_Framework/Applications/control_app/plc_demo/delta/delta_as332t.c index 1b329319a..c60de8b64 100644 --- a/APP_Framework/Applications/control_app/plc_demo/delta/delta_as332t.c +++ b/APP_Framework/Applications/control_app/plc_demo/delta/delta_as332t.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2022 AIIT XUOS Lab + /* * Copyright (c) 2022 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -15,9 +17,53 @@ * @brief PLC DELTA AS332T app * @version 3.0 * @author AIIT XUOS Lab - * @date 2022.9.27 + * @date 2022.10.10 */ +#include + +extern int Adapter4GActive(void); + +void ControlDeltaas332tTest(void) +{ + int i, j = 0; + int read_data_length = 0; + uint8_t read_data[128] = {0}; + +#ifdef CONNECTION_ADAPTER_4G + Adapter4GActive(); +#endif + + ControlProtocolType modbus_tcp_protocol = ControlProtocolFind(); + if (NULL == modbus_tcp_protocol) { + printf("%s get modbus tcp protocol %p failed\n", __func__, modbus_tcp_protocol); + return; + } + + printf("%s get modbus tcp protocol %p successfull\n", __func__, modbus_tcp_protocol); + + if (CONTROL_REGISTERED == modbus_tcp_protocol->protocol_status) { + ControlProtocolOpen(modbus_tcp_protocol); + + for (;;) { + read_data_length = ControlProtocolRead(modbus_tcp_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] modbus tcp data %d using receipe file\n", __func__, i, read_data_length); + if (read_data_length) { + for (j = 0; j < read_data_length; j ++) { + printf("j %d data 0x%x\n", j, read_data[j]); + } + } + i++; + memset(read_data, 0, sizeof(read_data)); + PrivTaskDelay(10000); + } + + //ControlProtocolClose(modbus_tcp_protocol); + } +} +PRIV_SHELL_CMD_FUNCTION(ControlDeltaas332tTest, Delta as332t Demo, PRIV_SHELL_CMD_MAIN_ATTR); + + diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/image/delta_as332t.jpg b/APP_Framework/Applications/control_app/plc_demo/delta/image/delta_as332t.jpg new file mode 100644 index 000000000..a648395ad Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/delta/image/delta_as332t.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/image/delta_dvp.jpg b/APP_Framework/Applications/control_app/plc_demo/delta/image/delta_dvp.jpg new file mode 100644 index 000000000..c4d93ddf6 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/delta/image/delta_dvp.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/image/recipe.png b/APP_Framework/Applications/control_app/plc_demo/delta/image/recipe.png new file mode 100644 index 000000000..14fc4505e Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/delta/image/recipe.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/image/test_result1.png b/APP_Framework/Applications/control_app/plc_demo/delta/image/test_result1.png new file mode 100644 index 000000000..fc304c2dd Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/delta/image/test_result1.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/image/test_result2.png b/APP_Framework/Applications/control_app/plc_demo/delta/image/test_result2.png new file mode 100644 index 000000000..bdca3c1e6 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/delta/image/test_result2.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/json/test_recipe_delta_as332t_tcp.json b/APP_Framework/Applications/control_app/plc_demo/delta/json/test_recipe_delta_as332t_tcp.json new file mode 100644 index 000000000..8f80bf790 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/delta/json/test_recipe_delta_as332t_tcp.json @@ -0,0 +1,79 @@ +{ + "device_id": 1, + "device_name": "DELTA_AS332T_TCP", + "communication_type": 0, + "socket_config": { + "plc_ip": "192.168.250.5", + "local_ip": "192.168.250.233", + "gateway": "192.168.250.1", + "netmask": "255.255.254.0", + "port": 502 + }, + "protocol_type": 2, + "read_period": 1000, + "read_item_list": [ + { + "value_name": "M16", + "value_type": 1, + "function_code": 1, + "start_address": 16, + "quantity": 1 + }, + { + "value_name": "M17", + "value_type": 1, + "function_code": 1, + "start_address": 17, + "quantity": 1 + }, + { + "value_name": "M18", + "value_type": 1, + "function_code": 1, + "start_address": 30, + "quantity": 1 + }, + { + "value_name": "D300", + "value_type": 3, + "function_code": 3, + "start_address": 300, + "quantity": 1 + }, + { + "value_name": "D301", + "value_type": 3, + "function_code": 3, + "start_address": 302, + "quantity": 1 + }, + { + "value_name": "D302", + "value_type": 4, + "function_code": 3, + "start_address": 302, + "quantity": 2 + }, + { + "value_name": "D304", + "value_type": 9, + "function_code": 3, + "start_address": 304, + "quantity": 2 + }, + { + "value_name": "Y1.0", + "value_type": 1, + "function_code": 1, + "start_address": 40976, + "quantity": 1 + }, + { + "value_name": "Y10", + "value_type": 3, + "function_code": 3, + "start_address": 40970, + "quantity": 1 + } + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/delta/test_recipe_delta_dvp.json b/APP_Framework/Applications/control_app/plc_demo/delta/json/test_recipe_delta_dvp.json similarity index 100% rename from APP_Framework/Applications/control_app/plc_demo/delta/test_recipe_delta_dvp.json rename to APP_Framework/Applications/control_app/plc_demo/delta/json/test_recipe_delta_dvp.json diff --git a/APP_Framework/Applications/control_app/plc_demo/fatek/Makefile b/APP_Framework/Applications/control_app/plc_demo/fatek/Makefile new file mode 100644 index 000000000..f260dec57 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/fatek/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fatek_fbs_24mc_uart.c + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/fatek/Readme.md b/APP_Framework/Applications/control_app/plc_demo/fatek/Readme.md new file mode 100644 index 000000000..0e06ddcb9 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/fatek/Readme.md @@ -0,0 +1,42 @@ +# 永宏通信测试 + +[TOC] + +## 永宏FBs-24MCT2-AC通信测试 + +### 通信接线及参数设置 + +* 网口和串口 + * FBS-24MCT2自带圆口232,用于程序的下载。 + * 可本体拓展FBs-CBES用于Modbus TCP,永宏私有协议永宏协议等通信。板卡默认IP:192.168.2.3.端口号500,永宏协议 + * 通过本体拓展FBs-CM22通信模板,可用于Modbus RTU及永宏协议通信。串口接线:+接485A;-接485B。 + * 串口模块MODBUS RTU通信参数配置:通信速率:9600;数据位:8bit;停止位:1bit;校验:偶校验 + * 串口模块永宏协议通信参数配置:通信速率:9600;数据位:8bit;停止位:1bit;校验:偶校验 + * 终端与PLC通信测试,PC编程软件与PLC不能处于联机状态。 + + +### 存储区 + +- 存储区 X,Y,R,D区等。 + +### 通信测试 + +- 共测试BOOL,INT16等类型数据。 + + +- 测试Y区,R区及D区数据。 + + +- 测试截图: + + 测试PLC环境搭建: + + ![](./image/FATEK.jpg) + + 解析完成的配方为: + + ![](./image/panasonic_fpxh_recipe.png) + + 测试结果: + + ![](./image/panasonic_fpxh_communication_test.png) \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/fatek/fatek_fbs_24mc_uart.c b/APP_Framework/Applications/control_app/plc_demo/fatek/fatek_fbs_24mc_uart.c new file mode 100644 index 000000000..412044d4f --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/fatek/fatek_fbs_24mc_uart.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file fatek_fbs_24mc_uart.c + * @brief PLC fatek fbs app + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.11.28 + */ + +#include + +extern int Adapter4GActive(void); + +void ControlFatekFBsUartTest(void) +{ + int i, j = 0; + int read_data_length = 0; + uint8_t read_data[128] = {0}; + +#ifdef CONNECTION_ADAPTER_4G + Adapter4GActive(); +#endif + + ControlProtocolType modbus_rtu_protocol = ControlProtocolFind(); + if (NULL == modbus_rtu_protocol) { + printf("%s get modbus rtu protocol %p failed\n", __func__, modbus_rtu_protocol); + return; + } + + printf("%s get modbus rtu protocol %p successfull\n", __func__, modbus_rtu_protocol); + + if (CONTROL_REGISTERED == modbus_rtu_protocol->protocol_status) { + ControlProtocolOpen(modbus_rtu_protocol); + + for (;;) { + read_data_length = ControlProtocolRead(modbus_rtu_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] modbus rtu data %d using receipe file\n", __func__, i, read_data_length); + if (read_data_length) { + for (j = 0; j < read_data_length; j ++) { + printf("j %d data 0x%x\n", j, read_data[j]); + } + } + i++; + memset(read_data, 0, sizeof(read_data)); + PrivTaskDelay(10000); + } + + //ControlProtocolClose(modbus_rtu_protocol); + } +} +PRIV_SHELL_CMD_FUNCTION(ControlFatekFBsUartTest, fatek fbs uart Demo, PRIV_SHELL_CMD_MAIN_ATTR); + + diff --git a/APP_Framework/Applications/control_app/plc_demo/fatek/image/FATEK.jpg b/APP_Framework/Applications/control_app/plc_demo/fatek/image/FATEK.jpg new file mode 100644 index 000000000..a201d9a6e Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/fatek/image/FATEK.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/fatek/json/test_recipe_fatek_fbs24mc_uart.json b/APP_Framework/Applications/control_app/plc_demo/fatek/json/test_recipe_fatek_fbs24mc_uart.json new file mode 100644 index 000000000..b01773890 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/fatek/json/test_recipe_fatek_fbs24mc_uart.json @@ -0,0 +1,37 @@ +{ + "device_id": 1, + "device_name": "FATEK_FBSMC24T_RTU", + "communication_type": 1, + "serial_config": { + "station": 1, + "baud_rate": 9600, + "data_bits": 8, + "stop_bits": 1, + "check_mode":3 + }, + "protocol_type": 3, + "read_period": 2000, + "read_item_list": [ + { + "value_name": "Y0", + "value_type": 1, + "function_code": 1, + "start_address": 0, + "quantity": 1 + }, + { + "value_name": "D0", + "value_type": 3, + "function_code": 3, + "start_address": 6000, + "quantity": 1 + }, + { + "value_name": "R10", + "value_type": 3, + "function_code": 3, + "start_address": 10, + "quantity": 1 + } + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/ge/img/GE CPE100.jpg b/APP_Framework/Applications/control_app/plc_demo/ge/img/GE CPE100.jpg new file mode 100644 index 000000000..52b954f82 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/ge/img/GE CPE100.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/ge/img/GE versamax CPU001.jpg b/APP_Framework/Applications/control_app/plc_demo/ge/img/GE versamax CPU001.jpg new file mode 100644 index 000000000..0ffd18130 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/ge/img/GE versamax CPU001.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/ge/test_recipe_ge_cpe_tcp.json b/APP_Framework/Applications/control_app/plc_demo/ge/json/test_recipe_ge_cpe_tcp.json similarity index 100% rename from APP_Framework/Applications/control_app/plc_demo/ge/test_recipe_ge_cpe_tcp.json rename to APP_Framework/Applications/control_app/plc_demo/ge/json/test_recipe_ge_cpe_tcp.json diff --git a/APP_Framework/Applications/control_app/plc_demo/ge/test_recipe_ge_versamax_rtu.json b/APP_Framework/Applications/control_app/plc_demo/ge/json/test_recipe_ge_versamax_rtu.json similarity index 100% rename from APP_Framework/Applications/control_app/plc_demo/ge/test_recipe_ge_versamax_rtu.json rename to APP_Framework/Applications/control_app/plc_demo/ge/json/test_recipe_ge_versamax_rtu.json diff --git a/APP_Framework/Applications/control_app/plc_demo/inovance/image/inovance_1608TN.jpg b/APP_Framework/Applications/control_app/plc_demo/inovance/image/inovance_1608TN.jpg new file mode 100644 index 000000000..a541548d9 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/inovance/image/inovance_1608TN.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/inovance/test_recipe_inovance_am401_tcp.json b/APP_Framework/Applications/control_app/plc_demo/inovance/json/test_recipe_inovance_am401_tcp.json similarity index 100% rename from APP_Framework/Applications/control_app/plc_demo/inovance/test_recipe_inovance_am401_tcp.json rename to APP_Framework/Applications/control_app/plc_demo/inovance/json/test_recipe_inovance_am401_tcp.json diff --git a/APP_Framework/Applications/control_app/plc_demo/inovance/test_recipe_inovance_am401_uart.json b/APP_Framework/Applications/control_app/plc_demo/inovance/json/test_recipe_inovance_am401_uart.json similarity index 100% rename from APP_Framework/Applications/control_app/plc_demo/inovance/test_recipe_inovance_am401_uart.json rename to APP_Framework/Applications/control_app/plc_demo/inovance/json/test_recipe_inovance_am401_uart.json diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/Makefile b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/Makefile index 72090f4f1..845e91dc0 100755 --- a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/Makefile +++ b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/Makefile @@ -1,3 +1,3 @@ -SRC_FILES := mitsubishi_fx3u.c mitsubishi_fx5u.c mitsubishi_fx2n.c mitsubishi_q02u.c +SRC_FILES := mitsubishi_fx3u.c mitsubishi_fx5u.c mitsubishi_fx2n.c mitsubishi_q02u.c mitsubishi_q06h.c mitsubishi_q03udv.c include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/README.md b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/README.md index a5fa32bb6..7fd213d9b 100644 --- a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/README.md +++ b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/README.md @@ -1,24 +1,88 @@ -# 三菱 FX2N通信测试 +# 三菱通信测试 [TOC] -## 通信接线及参数设置 +## 三菱FX2N通信测试 + +### 通信接线及参数设置 * 串口 * FX2N自带8针圆口422,用于程序的下载。全系列不支持网口,且需购买串口拓展模块FX2N-485-BD用于通信测试。 * 接线:RDA和SDA短接,引出A;RDB与SDB短接,引出B。 * 串口模块支持MC-1C协议,通信速率:9600;数据位:7bit;停止位:1bit;校验:偶校验 -## 存储区 +### 存储区 - 存储区 I,Q,M,D区。 -## 通信测试 +### 通信测试 - 共测试BOOL,INT16,FLOAT共三种类型数据。 - 测试M区及D区数据。 +## 三菱Q06H通信测试 + +### 通信接线及参数设置 + +* 接口 + * 首次连接时,可通过CPU自带的串口(打印机方口线)进行程序的下载。 + * 本次测试通过Q06H拓展的模块QJ71E71_100模块的网口模块进行MC—3E通信测试。 + * PLC网口模块IP:192.168.250.21 端口号:4000 + +### 存储区 + +- 存储区 I,Q,M,D区。 + +### 通信测试 + +- 共测试BOOL,INT16,FLOAT共三种类型数据。 +- 测试M区及D区数据。 + +- 测试截图: + + 解析完成的配方为 + + ![](./image/q06h_recipe.png) + + 测试结果: + + ![](./image/q06h_communication_test.png) + + + +## 三菱Q03UDV通信测试 + +### 通信接线及参数设置 + +* 接口 + * 本次测试通过Q03UDV拓展的模块QJ71E71_100模块的网口模块进行MC—3E通信测试。网口模块IP:192.168.250.21 端口号:4000 + * 本次测试还可通过Q03UDV自身网口进行MC—3E通信测试。网口模块IP:192.168.250.22 端口号:6000 + +### 存储区 + +- 存储区 I,Q,M,D区。 + +### 通信测试 + +- 共测试BOOL,INT16,FLOAT共三种类型数据。 + + +- 测试M区及D区数据。 + +- 测试截图: + + 扩展模块解析完成的配方为 + + ![](./image/q03udv_recipe.png) + + CPU自带网口解析完成的配方为 + + ![](image/Q03udv_recipe_1.png) + + 测试结果: + + ![](./image/q03udv_communication_test.png) diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/FX2NPLC.jpg b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/FX2NPLC.jpg new file mode 100644 index 000000000..f7cc1e5f1 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/FX2NPLC.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Fx3UPLC.jpg b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Fx3UPLC.jpg new file mode 100644 index 000000000..adcd82cf3 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Fx3UPLC.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q02UPLC.jpg b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q02UPLC.jpg new file mode 100644 index 000000000..1ea129440 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q02UPLC.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q03udvPLC.jpg b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q03udvPLC.jpg new file mode 100644 index 000000000..757b8c004 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q03udvPLC.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q03udv_recipe_1.png b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q03udv_recipe_1.png new file mode 100644 index 000000000..4087d421f Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q03udv_recipe_1.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q06HPLC.jpg b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q06HPLC.jpg new file mode 100644 index 000000000..e86a13c74 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/Q06HPLC.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q03udv_communication_test.png b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q03udv_communication_test.png new file mode 100644 index 000000000..e32d3ed89 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q03udv_communication_test.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q03udv_recipe.png b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q03udv_recipe.png new file mode 100644 index 000000000..341ed3972 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q03udv_recipe.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q06h_communication_test.png b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q06h_communication_test.png new file mode 100644 index 000000000..380205847 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q06h_communication_test.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q06h_recipe.png b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q06h_recipe.png new file mode 100644 index 000000000..970a4c41d Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/image/q06h_recipe.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/test_recipe_mc_1c.json b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_1c.json similarity index 100% rename from APP_Framework/Applications/control_app/plc_demo/mitsubishi/test_recipe_mc_1c.json rename to APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_1c.json diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_1e.json b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_1e.json new file mode 100644 index 000000000..d44caa6b6 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_1e.json @@ -0,0 +1,368 @@ +{ + "device_id": 1, + "device_name": "FX3U_MC_1E", + "communication_type": 0, + "socket_config": { + "plc_ip": "192.168.250.25", + "local_ip": "192.168.250.233", + "gateway": "192.168.250.1", + "netmask": "255.255.254.0", + "port": 2000 + }, + "protocol_type": 6, + "read_period": 2000, + "read_item_list": [ + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "0", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ֹͣ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ʹ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "3", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ͣ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "4", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "5", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "6", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Զ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "20", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "21", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "22", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ֶģʽ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "23", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Զģʽ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "24", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "з", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "25", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "26", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "27", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "0", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "2", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "3", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "3", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "4", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "4", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "5", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "5", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "6", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "50", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "7", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "51", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "8", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "52", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "9", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "53", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "200", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "202", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "204", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ʼλ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "206", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "յλ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "208", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ֵ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "300", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "302", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "2", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "304", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "3", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "306", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "4", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "308", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "Y001", + "value_type": 1, + "device_code": "Y", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Y002", + "value_type": 1, + "device_code": "Y", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Y010", + "value_type": 1, + "device_code": "Y", + "head_device_number_string": "10", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "D400", + "value_type": 4, + "device_code": "D", + "head_device_number_string": "400", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + } + + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_3c.json b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_3c.json new file mode 100644 index 000000000..185fc7708 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_3c.json @@ -0,0 +1,331 @@ +{ + "device_id": 769, + "device_name": "Q02UCPU", + "communication_type": 1, + "serial_config": { + "station": 0, + "baud_rate": 19200, + "data_bits": 7, + "stop_bits": 1, + "check_mode": 3 + }, + "protocol_type": 10, + "read_period": 1000, + "read_item_list": [ + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "0", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ֹͣ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ʹ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "3", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ͣ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "4", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "5", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "6", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Զ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "20", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "21", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "22", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ֶģʽ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "23", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Զģʽ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "24", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "з", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "25", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "26", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "27", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "0", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "2", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "3", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "3", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "4", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "4", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "5", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "5", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "6", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "50", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "7", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "51", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "8", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "52", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "9", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "53", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "200", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "202", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "204", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ʼλ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "206", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "յλ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "208", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ֵ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "300", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "302", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "2", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "304", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "3", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "306", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "4", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "308", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + } + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_3e.json b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_3e.json new file mode 100644 index 000000000..6c99230a4 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/json/test_recipe_mc_3e.json @@ -0,0 +1,494 @@ +{ + "device_id": 1, + "device_name": "Q02UCPU_MC_3E", + "communication_type": 0, + "socket_config": { + "plc_ip": "192.168.250.21", + "local_ip": "192.168.250.233", + "gateway": "192.168.250.1", + "netmask": "255.255.254.0", + "port": 4000 + }, + "protocol_type": 7, + "read_period": 2000, + "read_item_list": [ + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "0", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ֹͣ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ʹ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "3", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ͣ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "4", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "5", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "6", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Զ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "20", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "21", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "22", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "ֶģʽ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "23", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Զģʽ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "24", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "з", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "25", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "λ", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "26", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 1, + "device_code": "M", + "head_device_number_string": "27", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "0", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "2", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "3", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "3", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "4", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "4", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "5", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "5", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "6", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "50", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "7", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "51", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "8", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "52", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "9", + "value_type": 3, + "device_code": "D", + "head_device_number_string": "53", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "200", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "202", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ٶ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "204", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ʼλ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "206", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "յλ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "208", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "ֵ", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "300", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "1", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "302", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "2", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "304", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "3", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "306", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "4", + "value_type": 9, + "device_code": "D", + "head_device_number_string": "308", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "Y001", + "value_type": 1, + "device_code": "Y", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Y002", + "value_type": 1, + "device_code": "Y", + "head_device_number_string": "2", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "Y010", + "value_type": 1, + "device_code": "Y", + "head_device_number_string": "10", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "D400", + "value_type": 4, + "device_code": "D", + "head_device_number_string": "400", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "D402", + "value_type": 8, + "device_code": "D", + "head_device_number_string": "402", + "device_points_count": 4, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "D406", + "value_type": 8, + "device_code": "D", + "head_device_number_string": "406", + "device_points_count": 4, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "B1", + "value_type": 1, + "device_code": "B", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "B10", + "value_type": 1, + "device_code": "B", + "head_device_number_string": "10", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "B20", + "value_type": 1, + "device_code": "B", + "head_device_number_string": "20", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 100 + }, + { + "value_name": "W1", + "value_type": 3, + "device_code": "W", + "head_device_number_string": "1", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "W2", + "value_type": 4, + "device_code": "W", + "head_device_number_string": "2", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "W4", + "value_type": 9, + "device_code": "W", + "head_device_number_string": "4", + "device_points_count": 2, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "W6", + "value_type": 8, + "device_code": "W", + "head_device_number_string": "6", + "device_points_count": 4, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "W22", + "value_type": 3, + "device_code": "W", + "head_device_number_string": "22", + "device_points_count": 1, + "command_type": 1, + "monitoring_timer": 100 + }, + { + "value_name": "B44", + "value_type": 1, + "device_code": "B", + "head_device_number_string": "44", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 500 + }, + { + "value_name": "B200", + "value_type": 1, + "device_code": "B", + "head_device_number_string": "200", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 500 + }, + { + "value_name": "Y100", + "value_type": 1, + "device_code": "Y", + "head_device_number_string": "100", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 500 + }, + { + "value_name": "X150", + "value_type": 1, + "device_code": "X", + "head_device_number_string": "150", + "device_points_count": 1, + "command_type": 0, + "monitoring_timer": 500 + } + + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/mitsubishi_q03udv.c b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/mitsubishi_q03udv.c new file mode 100644 index 000000000..9c374c946 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/mitsubishi_q03udv.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file mitsubishi_q03udv.c + * @brief PLC MITSUBISHI Q03udv app + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.10.30 + */ + +#include + +extern int Adapter4GActive(void); + +void ControlQ03udvTest(void) +{ + int i, j = 0; + int read_data_length = 0; + uint8_t read_data[128] = {0}; + +#ifdef CONNECTION_ADAPTER_4G + Adapter4GActive(); +#endif + + ControlProtocolType melsec_3e_protocol = ControlProtocolFind(); + if (NULL == melsec_3e_protocol) { + printf("%s get melsec 3e protocol %p failed\n", __func__, melsec_3e_protocol); + return; + } + + printf("%s get melsec 3e protocol %p successfull\n", __func__, melsec_3e_protocol); + + if (CONTROL_REGISTERED == melsec_3e_protocol->protocol_status) { + ControlProtocolOpen(melsec_3e_protocol); + + for (;;) { + read_data_length = ControlProtocolRead(melsec_3e_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] melsec 3c data %d using receipe file\n", __func__, i, read_data_length); + if (read_data_length) { + for (j = 0; j < read_data_length; j ++) { + printf("j %d data 0x%x\n", j, read_data[j]); + } + } + i++; + memset(read_data, 0, sizeof(read_data)); + PrivTaskDelay(10000); + } + + //ControlProtocolClose(melsec_3c_protocol); + } +} +PRIV_SHELL_CMD_FUNCTION(ControlQ03udvTest, Mitsubishi Q03udv Demo, PRIV_SHELL_CMD_MAIN_ATTR); + + diff --git a/APP_Framework/Applications/control_app/plc_demo/mitsubishi/mitsubishi_q06h.c b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/mitsubishi_q06h.c new file mode 100644 index 000000000..a65e26722 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/mitsubishi/mitsubishi_q06h.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file mitsubishi_q06h.c + * @brief PLC MITSUBISHI Q06H app + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.10.30 + */ + +#include + +extern int Adapter4GActive(void); + +void ControlQ06hTest(void) +{ + int i, j = 0; + int read_data_length = 0; + uint8_t read_data[128] = {0}; + +#ifdef CONNECTION_ADAPTER_4G + Adapter4GActive(); +#endif + + ControlProtocolType melsec_3e_protocol = ControlProtocolFind(); + if (NULL == melsec_3e_protocol) { + printf("%s get melsec 3e protocol %p failed\n", __func__, melsec_3e_protocol); + return; + } + + printf("%s get melsec 3e protocol %p successfull\n", __func__, melsec_3e_protocol); + + if (CONTROL_REGISTERED == melsec_3e_protocol->protocol_status) { + ControlProtocolOpen(melsec_3e_protocol); + + for (;;) { + read_data_length = ControlProtocolRead(melsec_3e_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] melsec 3c data %d using receipe file\n", __func__, i, read_data_length); + if (read_data_length) { + for (j = 0; j < read_data_length; j ++) { + printf("j %d data 0x%x\n", j, read_data[j]); + } + } + i++; + memset(read_data, 0, sizeof(read_data)); + PrivTaskDelay(10000); + } + + //ControlProtocolClose(melsec_3c_protocol); + } +} +PRIV_SHELL_CMD_FUNCTION(ControlQ06hTest, Mitsubishi Q06H Demo, PRIV_SHELL_CMD_MAIN_ATTR); + + diff --git a/APP_Framework/Applications/control_app/plc_demo/omron/json/test_recipe_nj501_fins.json b/APP_Framework/Applications/control_app/plc_demo/omron/json/test_recipe_nj501_fins.json new file mode 100644 index 000000000..28c128e42 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/omron/json/test_recipe_nj501_fins.json @@ -0,0 +1,26 @@ +{ + "device_id": 1, + "device_name": "NJ501", + "communication_type": 0, + "socket_config": { + "plc_ip": "192.168.250.22", + "local_ip": "192.168.250.233", + "gateway": "192.168.250.1", + "netmask": "255.255.255.0", + "port": 9600 + }, + "protocol_type": 5, + "read_period": 100, + "read_item_list": [ + + { + "value_name": "整型1", + "value_type": 3, + "area_char": "D", + "data_type": 1, + "start_address": 100, + "bit_address": 0, + "data_length": 1 + } + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/omron/omron_nj501.c b/APP_Framework/Applications/control_app/plc_demo/omron/omron_nj501.c index d265aa953..cc57e6961 100644 --- a/APP_Framework/Applications/control_app/plc_demo/omron/omron_nj501.c +++ b/APP_Framework/Applications/control_app/plc_demo/omron/omron_nj501.c @@ -18,6 +18,34 @@ * @date 2022.9.27 */ - +#include + +void ControlNj501Test(void) +{ + int i = 0; + uint16_t read_data_length = 0; + uint8_t read_data[1024] = {0}; + ControlProtocolType fins_protocol = ControlProtocolFind(); + if (NULL == fins_protocol) { + printf("%s get fins protocol %p failed\n", __func__, fins_protocol); + return; + } + + printf("%s get fins protocol %p successfull\n", __func__, fins_protocol); + + if (CONTROL_REGISTERED == fins_protocol->protocol_status) { + ControlProtocolOpen(fins_protocol); + + for (;;) { + read_data_length = ControlProtocolRead(fins_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] fins data %d using receipe file\n", __func__, i, read_data_length); + i++; + PrivTaskDelay(100000); + } + + //ControlProtocolClose(fins_protocol); + } +} +PRIV_SHELL_CMD_FUNCTION(ControlNj501Test, Omron Plc FINS Demo, PRIV_SHELL_CMD_MAIN_ATTR); diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/Makefile b/APP_Framework/Applications/control_app/plc_demo/panasonic/Makefile new file mode 100644 index 000000000..796e6874a --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/panasonic/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := panasonic_fpxh_tcp.c panasonic_fpxh_uart.c + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/Readme.md b/APP_Framework/Applications/control_app/plc_demo/panasonic/Readme.md new file mode 100644 index 000000000..c27a7ed43 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/panasonic/Readme.md @@ -0,0 +1,39 @@ +# 松下通信测试 + +[TOC] + +## 松下FPXHC40ET通信测试 + +### 通信接线及参数设置 + +* 网口和串口 + * FPXHC40ET自带miniUSB,用于程序的下载。本体自带的串口为RS232。 + * 本体自带的网口可用于Modbus TCP,Ethernet/IP等通信。目前用于Modbus TCP通信测试,网口IP:192.168.250.51 Port:502 + * 通过本体拓展FPXH-COM3通信模板,可用于Modbus RTU通信。串口接线:S+接485A;S-接485B。 + * 串口模块通信参数配置:通信速率:115200;数据位:8bit;停止位:1bit;校验:偶校验 + +### 存储区 + +- 存储区 X,Y,R,D,L区等。 + +### 通信测试 + +- 共测试BOOL,INT16等类型数据。 + + +- 测试Y区,R区及DT区数据。 + + +- 测试截图: + + 测试PLC环境搭建: + + ![](./image/PLC_xidatong.jpg) + + 解析完成的配方为: + + ![](./image/panasonic_fpxh_recipe.png) + + 测试结果: + + ![](./image/panasonic_fpxh_communication_test.png) \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/image/PLC_xidatong.jpg b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/PLC_xidatong.jpg new file mode 100644 index 000000000..703290392 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/PLC_xidatong.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic-fpxh.jpg b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic-fpxh.jpg new file mode 100644 index 000000000..5bf2b9103 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic-fpxh.jpg differ diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic_fpxh_communication_test.png b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic_fpxh_communication_test.png new file mode 100644 index 000000000..c3765e56b Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic_fpxh_communication_test.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic_fpxh_recipe.png b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic_fpxh_recipe.png new file mode 100644 index 000000000..3f0c45778 Binary files /dev/null and b/APP_Framework/Applications/control_app/plc_demo/panasonic/image/panasonic_fpxh_recipe.png differ diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/json/test_recipe_panasonic_fpxh_tcp.json b/APP_Framework/Applications/control_app/plc_demo/panasonic/json/test_recipe_panasonic_fpxh_tcp.json new file mode 100644 index 000000000..3ee81bdea --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/panasonic/json/test_recipe_panasonic_fpxh_tcp.json @@ -0,0 +1,65 @@ +{ + "device_id": 1, + "device_name": "PANASONIC_FPXH_TCP", + "communication_type": 0, + "socket_config": { + "plc_ip": "192.168.250.51", + "local_ip": "192.168.250.233", + "gateway": "192.168.250.1", + "netmask": "255.255.254.0", + "port": 502 + }, + "protocol_type": 2, + "read_period": 1000, + "read_item_list": [ + { + "value_name": "Y0", + "value_type": 1, + "function_code": 1, + "start_address": 0, + "quantity": 1 + }, + { + "value_name": "R0", + "value_type": 1, + "function_code": 1, + "start_address":2048, + "quantity": 1 + }, + { + "value_name": "R100", + "value_type": 1, + "function_code": 1, + "start_address": 2208, + "quantity": 1 + }, + { + "value_name": "R101", + "value_type": 1, + "function_code": 1, + "start_address": 2209, + "quantity": 1 + }, + { + "value_name": "DT0", + "value_type": 3, + "function_code": 3, + "start_address": 0, + "quantity": 1 + }, + { + "value_name": "DT1", + "value_type": 3, + "function_code": 3, + "start_address": 1, + "quantity": 1 + }, + { + "value_name": "DT200", + "value_type": 3, + "function_code": 3, + "start_address": 200, + "quantity": 1 + } + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/json/test_recipe_panasonic_fpxh_uart.json b/APP_Framework/Applications/control_app/plc_demo/panasonic/json/test_recipe_panasonic_fpxh_uart.json new file mode 100644 index 000000000..13d81a7b7 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/panasonic/json/test_recipe_panasonic_fpxh_uart.json @@ -0,0 +1,66 @@ +{ + "device_id": 1, + "device_name": "PANASONIC_FPXH_RTU", + "communication_type": 1, + "serial_config": { + "station": 1, + "baud_rate": 9600, + "data_bits": 8, + "stop_bits": 1, + "check_mode":3 + }, + "protocol_type": 3, + "read_period": 2000, + "read_item_list": [ + { + "value_name": "Y0", + "value_type": 1, + "function_code": 1, + "start_address": 0, + "quantity": 1 + }, + { + "value_name": "R0", + "value_type": 1, + "function_code": 1, + "start_address":2048, + "quantity": 1 + }, + { + "value_name": "R100", + "value_type": 1, + "function_code": 1, + "start_address": 2208, + "quantity": 1 + }, + { + "value_name": "R101", + "value_type": 1, + "function_code": 1, + "start_address": 2209, + "quantity": 1 + }, + { + "value_name": "DT0", + "value_type": 3, + "function_code": 3, + "start_address": 0, + "quantity": 1 + }, + { + "value_name": "DT1", + "value_type": 3, + "function_code": 3, + "start_address": 1, + "quantity": 1 + }, + { + "value_name": "DT200", + "value_type": 3, + "function_code": 3, + "start_address": 200, + "quantity": 1 + } + + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/panasonic_fpxh_tcp.c b/APP_Framework/Applications/control_app/plc_demo/panasonic/panasonic_fpxh_tcp.c new file mode 100644 index 000000000..cbd779c02 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/panasonic/panasonic_fpxh_tcp.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file panasonic_fpxh_ethernet.c + * @brief PLC panasonic fpxh app + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.11.22 + */ + +#include + +extern int Adapter4GActive(void); + +void ControlPanasonicFpxhTCPTest(void) +{ + int i, j = 0; + int read_data_length = 0; + uint8_t read_data[128] = {0}; + +#ifdef CONNECTION_ADAPTER_4G + Adapter4GActive(); +#endif + + ControlProtocolType modbus_tcp_protocol = ControlProtocolFind(); + if (NULL == modbus_tcp_protocol) { + printf("%s get modbus tcp protocol %p failed\n", __func__, modbus_tcp_protocol); + return; + } + + printf("%s get modbus tcp protocol %p successfull\n", __func__, modbus_tcp_protocol); + + if (CONTROL_REGISTERED == modbus_tcp_protocol->protocol_status) { + ControlProtocolOpen(modbus_tcp_protocol); + + for (;;) { + read_data_length = ControlProtocolRead(modbus_tcp_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] modbus tcp data %d using receipe file\n", __func__, i, read_data_length); + if (read_data_length) { + for (j = 0; j < read_data_length; j ++) { + printf("j %d data 0x%x\n", j, read_data[j]); + } + } + i++; + memset(read_data, 0, sizeof(read_data)); + PrivTaskDelay(10000); + } + + //ControlProtocolClose(modbus_tcp_protocol); + } +} +PRIV_SHELL_CMD_FUNCTION(ControlPanasonicFpxhTCPTest, panasonic Fpxh TCP Demo, PRIV_SHELL_CMD_MAIN_ATTR); + + diff --git a/APP_Framework/Applications/control_app/plc_demo/panasonic/panasonic_fpxh_uart.c b/APP_Framework/Applications/control_app/plc_demo/panasonic/panasonic_fpxh_uart.c new file mode 100644 index 000000000..8f75ec9a0 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/panasonic/panasonic_fpxh_uart.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file panasonic_fpxh_uart.c + * @brief PLC panasonic fpxh app + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.11.22 + */ + +#include + +extern int Adapter4GActive(void); + +void ControlPanasonicFpxhUartTest(void) +{ + int i, j = 0; + int read_data_length = 0; + uint8_t read_data[128] = {0}; + +#ifdef CONNECTION_ADAPTER_4G + Adapter4GActive(); +#endif + + ControlProtocolType modbus_rtu_protocol = ControlProtocolFind(); + if (NULL == modbus_rtu_protocol) { + printf("%s get modbus rtu protocol %p failed\n", __func__, modbus_rtu_protocol); + return; + } + + printf("%s get modbus rtu protocol %p successfull\n", __func__, modbus_rtu_protocol); + + if (CONTROL_REGISTERED == modbus_rtu_protocol->protocol_status) { + ControlProtocolOpen(modbus_rtu_protocol); + + for (;;) { + read_data_length = ControlProtocolRead(modbus_rtu_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] modbus rtu data %d using receipe file\n", __func__, i, read_data_length); + if (read_data_length) { + for (j = 0; j < read_data_length; j ++) { + printf("j %d data 0x%x\n", j, read_data[j]); + } + } + i++; + memset(read_data, 0, sizeof(read_data)); + PrivTaskDelay(10000); + } + + //ControlProtocolClose(modbus_rtu_protocol); + } +} +PRIV_SHELL_CMD_FUNCTION(ControlPanasonicFpxhUartTest, panasonic fpxh uart Demo, PRIV_SHELL_CMD_MAIN_ATTR); + + diff --git a/APP_Framework/Applications/control_app/plc_demo/siemens/Makefile b/APP_Framework/Applications/control_app/plc_demo/siemens/Makefile index 54fb32baa..815382667 100755 --- a/APP_Framework/Applications/control_app/plc_demo/siemens/Makefile +++ b/APP_Framework/Applications/control_app/plc_demo/siemens/Makefile @@ -1,3 +1,3 @@ -SRC_FILES := siemens_s7_200_cn.c siemens_s7_200_smart.c siemens_s7_300.c siemens_s7_1200.c siemens_s7_1500.c +SRC_FILES := siemens_s7_200_cn.c siemens_s7_200_smart.c siemens_s7_1200.c siemens_s7_1500.c include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/control_app/plc_demo/siemens/json/test_recipe_simens_s71200.json b/APP_Framework/Applications/control_app/plc_demo/siemens/json/test_recipe_simens_s71200.json new file mode 100644 index 000000000..408eff339 --- /dev/null +++ b/APP_Framework/Applications/control_app/plc_demo/siemens/json/test_recipe_simens_s71200.json @@ -0,0 +1,25 @@ +{ + "device_id": 1, + "device_name": "S7-1215", + "communication_type": 0, + "socket_config": { + "plc_ip": "192.168.250.5", + "local_ip": "192.168.250.233", + "gateway": "192.168.250.252", + "netmask": "255.255.255.0", + "port": 102 + }, + "protocol_type": 1, + "read_period": 100, + "read_item_list": [ + { + "value_name": "浮点数", + "value_type": 9, + "area": "DB", + "wordlen": "Real", + "db_number": 10, + "start": 32, + "amount": 1 + } + ] +} \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/siemens/siemens_s7_1200.c b/APP_Framework/Applications/control_app/plc_demo/siemens/siemens_s7_1200.c index 9cbbeae1a..f2a35f4cf 100644 --- a/APP_Framework/Applications/control_app/plc_demo/siemens/siemens_s7_1200.c +++ b/APP_Framework/Applications/control_app/plc_demo/siemens/siemens_s7_1200.c @@ -18,3 +18,28 @@ * @date 2023.3.27 */ +#include +void ControlS71200Test(void) +{ + int i = 0; + uint16_t read_data_length = 0; + uint8_t read_data[1024] = {0}; + ControlProtocolType s7_protocol = ControlProtocolFind(); + if (NULL == s7_protocol) { + printf("%s get s7 protocol %p failed\n", __func__, s7_protocol); + return; + } + printf("%s get s7 protocol %p successfull\n", __func__, s7_protocol); + if (CONTROL_REGISTERED == s7_protocol->protocol_status) { + ControlProtocolOpen(s7_protocol); + for (;;) { + read_data_length = ControlProtocolRead(s7_protocol, read_data, sizeof(read_data)); + printf("%s read [%d] s7 data %d using receipe file\n", __func__, i, read_data_length); + i++; + memset(read_data, 0, sizeof(read_data)); + PrivTaskDelay(10000); + } + } +} + +PRIV_SHELL_CMD_FUNCTION(ControlS71200Test, Siemens Plc S7_1215 Demo, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/APP_Framework/Applications/control_app/plc_demo/siemens/siemens_s7_300.c b/APP_Framework/Applications/control_app/plc_demo/siemens/siemens_s7_300.c deleted file mode 100644 index 88d09209e..000000000 --- a/APP_Framework/Applications/control_app/plc_demo/siemens/siemens_s7_300.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -/** - * @file siemens_s7_300.c - * @brief PLC SIEMENS S7-300 app - * @version 3.0 - * @author AIIT XUOS Lab - * @date 2023.3.27 - */ - diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/context_switch.S b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/context_switch.S index ae0620e2f..9e52ccda4 100755 --- a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/context_switch.S +++ b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/context_switch.S @@ -31,32 +31,14 @@ Modification: context_switch: # store original context to stack - str lr, [r13, #-4]! - str r12, [r13, #-4]! - str r11, [r13, #-4]! - str r10, [r13, #-4]! - str r9, [r13, #-4]! - str r8, [r13, #-4]! - str r7, [r13, #-4]! - str r6, [r13, #-4]! - str r5, [r13, #-4]! - str r4, [r13, #-4]! + stmfd r13!, {r4-r12, lr} # switch the stack str r13, [r0] // save current sp to the old PCB (**old) mov r13, r1 // load the next stack # restore context from stack - ldr r4, [r13], #4 - ldr r5, [r13], #4 - ldr r6, [r13], #4 - ldr r7, [r13], #4 - ldr r8, [r13], #4 - ldr r9, [r13], #4 - ldr r10, [r13], #4 - ldr r11, [r13], #4 - ldr r12, [r13], #4 - ldr lr, [r13], #4 + ldmfd r13!, {r4-r12, lr} # return to the caller bx lr diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h index 11043cb7c..01c5623bf 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/core.h @@ -76,7 +76,7 @@ Modification: #define NR_CPU 4 -__attribute__((always_inline)) static inline uint32_t user_mode() +__attribute__((always_inline, optimize("O0"))) static inline uint32_t user_mode() { uint32_t val; @@ -92,6 +92,16 @@ __attribute__((always_inline)) static inline uint32_t user_mode() return val; } +__attribute__((always_inline, optimize("O0"))) static inline void cpu_into_low_power() +{ + WFE(); +} + +__attribute__((always_inline, optimize("O0"))) static inline void cpu_leave_low_power() +{ + SEV(); +} + struct context { uint32_t r4; uint32_t r5; @@ -103,12 +113,12 @@ struct context { uint32_t r11; uint32_t r12; uint32_t lr; -}; +} __attribute__((packed)); /// @brief init task context, set return address to trap return /// @param extern void task_prepare_enter(); -__attribute__((__always_inline__)) static inline void arch_init_context(struct context* ctx) +__attribute__((always_inline, optimize("O0"))) static inline void arch_init_context(struct context* ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->lr = (uint32_t)(task_prepare_enter + 4); @@ -133,13 +143,13 @@ struct trapframe { uint32_t r11; uint32_t r12; uint32_t pc; -}; +} __attribute__((packed)); /// @brief init task trapframe (*especially the user mode cpsr) /// @param tf /// @param sp /// @param pc -__attribute__((__always_inline__)) static inline void arch_init_trapframe(struct trapframe* tf, uintptr_t sp, uintptr_t pc) +__attribute__((always_inline, optimize("O0"))) static inline void arch_init_trapframe(struct trapframe* tf, uintptr_t sp, uintptr_t pc) { memset(tf, 0, sizeof(*tf)); tf->spsr = user_mode(); @@ -153,7 +163,7 @@ __attribute__((__always_inline__)) static inline void arch_init_trapframe(struct /// @param tf /// @param sp /// @param pc -__attribute__((__always_inline__)) static inline void arch_trapframe_set_sp_pc(struct trapframe* tf, uintptr_t sp, uintptr_t pc) +__attribute__((always_inline, optimize("O0"))) static inline void arch_trapframe_set_sp_pc(struct trapframe* tf, uintptr_t sp, uintptr_t pc) { tf->sp_usr = sp; tf->pc = pc; @@ -163,7 +173,7 @@ __attribute__((__always_inline__)) static inline void arch_trapframe_set_sp_pc(s /// @param tf /// @param argc /// @param argv -__attribute__((__always_inline__)) static inline void arch_set_main_params(struct trapframe* tf, int argc, uintptr_t argv) +__attribute__((always_inline, optimize("O0"))) static inline void arch_set_main_params(struct trapframe* tf, int argc, uintptr_t argv) { tf->r0 = (uint32_t)argc; tf->r1 = (uint32_t)argv; @@ -178,7 +188,7 @@ __attribute__((__always_inline__)) static inline void arch_set_main_params(struc /// @param param5 /// @return extern int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4); -__attribute__((__always_inline__)) static inline int arch_syscall(struct trapframe* tf, int* syscall_num) +__attribute__((always_inline, optimize("O0"))) static inline int arch_syscall(struct trapframe* tf, int* syscall_num) { // call syscall *syscall_num = tf->r0; @@ -188,7 +198,7 @@ __attribute__((__always_inline__)) static inline int arch_syscall(struct trapfra /// @brief set return reg to trapframe /// @param tf /// @param ret -__attribute__((__always_inline__)) static inline void arch_set_return(struct trapframe* tf, int ret) +__attribute__((always_inline, optimize("O0"))) static inline void arch_set_return(struct trapframe* tf, int ret) { tf->r0 = (uint32_t)ret; } diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/config.mk b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/config.mk index 9f7d2a2df..e1bd49d00 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/config.mk +++ b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/config.mk @@ -1,6 +1,6 @@ export CROSS_COMPILE ?= arm-none-eabi- export DEVICE = -march=armv7-a -mtune=cortex-a9 -mfpu=vfpv3-d16 -ftree-vectorize -ffast-math -mfloat-abi=softfp -export CFLAGS := $(DEVICE) -Wall -O0 -g -gdwarf-2 +export CFLAGS := $(DEVICE) -Wall -O2 -g -gdwarf-2 -Wnull-dereference -Waddress -Warray-bounds -Wchar-subscripts -Wimplicit-int -Wimplicit-function-declaration -Wcomment -Wformat -Wmissing-braces -Wnonnull -Wparentheses -Wpointer-sign -Wreturn-type -Wsequence-point -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-value -Wunused-variable -Wunused-function export AFLAGS := -c $(DEVICE) -x assembler-with-cpp -D__ASSEMBLY__ -gdwarf-2 # export LFLAGS := $(DEVICE) -Wl,-Map=XiZi-imx6q-sabrelite.map,-cref,-u,_boot_start -T $(KERNEL_ROOT)/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds export LFLAGS := $(DEVICE) --specs=nosys.specs -Wl,-Map=XiZi-imx6q-sabrelite.map,-cref,-u,_boot_start -T $(KERNEL_ROOT)/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds index 7a23ca569..ed1525396 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds +++ b/Ubiquitous/XiZi_AIoT/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds @@ -77,6 +77,10 @@ BOOT_STACK_SIZE = 0x4000; RAM_VECTORS_SIZE = 72; /* Specify the memory areas */ +/* + ddr3: physical area: [0x10000000, 0x50000000); + virt_ddr3: virt area exclude boot(start_sec), that will be [0x90000000 + 0x11000, 0xD0000000) +*/ MEMORY { ocram (rwx) : ORIGIN = 0x00900000, LENGTH = 256K @@ -154,7 +158,7 @@ SECTIONS PROVIDE(boot_end_addr = .); } > ddr3 - /* Other Kernel code is placed over 0x80000000 + 128KB. */ + /* Other Kernel code is placed over 0x10011000(phy) and 0x90011000(virt). */ .text : AT(0x10011000) { *(.vectors) . = ALIGN(0x1000); diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/clock/arm/armv7-a/cortex-a9/imx6q-sabrelite/clock.c b/Ubiquitous/XiZi_AIoT/hardkernel/clock/arm/armv7-a/cortex-a9/imx6q-sabrelite/clock.c index 123093c1d..cd144a057 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/clock/arm/armv7-a/cortex-a9/imx6q-sabrelite/clock.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/clock/arm/armv7-a/cortex-a9/imx6q-sabrelite/clock.c @@ -40,24 +40,8 @@ static void _sys_clock_init() { uint32_t freq = get_main_clock(IPG_CLK); gpt_init(CLKSRC_IPG_CLK, freq / 1000000, RESTART_MODE, WAIT_MODE_EN | STOP_MODE_EN); - switch (cur_cpuid()) { - case 0: - gpt_set_compare_event(kGPTOutputCompare1, OUTPUT_CMP_DISABLE, 1000); - gpt_counter_enable(kGPTOutputCompare1); - break; - case 1: - gpt_set_compare_event(kGPTOutputCompare2, OUTPUT_CMP_DISABLE, 1000); - gpt_counter_enable(kGPTOutputCompare2); - break; - case 2: - gpt_set_compare_event(kGPTOutputCompare3, OUTPUT_CMP_DISABLE, 1000); - gpt_counter_enable(kGPTOutputCompare3); - break; - case 3: - gpt_set_compare_event(kGPTOutputCompare1, OUTPUT_CMP_DISABLE, 1000); - gpt_counter_enable(kGPTOutputCompare1); - break; - } + gpt_set_compare_event(kGPTOutputCompare1, OUTPUT_CMP_DISABLE, 1000); + gpt_counter_enable(kGPTOutputCompare1); } static uint32_t _get_clock_int() diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c b/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c index 660b883f9..351a1266f 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/hardkernel_init.c @@ -218,10 +218,7 @@ bool secondary_cpu_hardkernel_init(int cpu_id, struct TraceTag* _hardkernel_tag) // cache p_icache_driver->enable(); p_dcache_driver->enable(); - // p_icache_driver->disable(); - // p_dcache_driver->disable(); // clock - // p_clock_driver->sys_clock_init(); p_intr_driver->single_irq_enable(p_clock_driver->get_clock_int(), cpu_id, 0); // mmu secondary_cpu_load_kern_pgdir(&init_mmu_tag, &init_intr_tag); diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/error_debug.c b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/error_debug.c index 7d18f0156..a96d80440 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/error_debug.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/error_debug.c @@ -41,32 +41,18 @@ Modification: *************************************************/ #include "core.h" #include "memlayout.h" - -#include "log.h" -#include "multicores.h" #include "spinlock.h" -#include "syscall.h" +#include "trap_common.h" -__attribute__((always_inline)) static inline void _abort_reason(uint32_t fault_status) -{ - if ((fault_status & 0xd) == 0x1) // Alignment failure - KPrintf("reason: alignment\n"); - else if ((fault_status & 0xd) == 0x5) // External abort "on translation" - KPrintf("reason: ext. abort on trnslt.\n"); - else if ((fault_status & 0xd) == 0x5) // Translation - KPrintf("reason: sect. translation\n"); - else if ((fault_status & 0xd) == 0x9) // Domain - KPrintf("reason: sect. domain\n"); - else if ((fault_status & 0xd) == 0xd) // Permission - KPrintf("reason: sect. permission\n"); - else if ((fault_status & 0xd) == 0x8) // External abort - KPrintf("reason: ext. abort\n"); - else - KPrintf("reason: unknown???\n"); -} +#include "assert.h" +#include "multicores.h" +#include "syscall.h" +#include "task.h" void dump_tf(struct trapframe* tf) { + KPrintf("sp_usr: 0x%x\n", tf->sp_usr); + KPrintf("lr_usr: 0x%x\n", tf->lr_usr); KPrintf("lr_svc: 0x%x\n", tf->lr_svc); KPrintf(" spsr: 0x%x\n", tf->spsr); KPrintf(" r0: 0x%x\n", tf->r0); @@ -85,64 +71,76 @@ void dump_tf(struct trapframe* tf) KPrintf(" pc: 0x%x\n", tf->pc); } +void dabort_reason(struct trapframe* r) +{ + uint32_t fault_status, dfa; + __asm__ __volatile__("mrc p15, 0, %0, c5, c0, 0" : "=r"(fault_status)::); + __asm__ __volatile__("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfa)::); + LOG("program counter: 0x%x caused\n", r->pc); + LOG("data abort at 0x%x, status 0x%x\n", dfa, fault_status); + + if ((fault_status & 0xd) == 0x1) // Alignment failure + KPrintf("reason: alignment\n"); + else if ((fault_status & 0xd) == 0x5) // External abort "on translation" + KPrintf("reason: ext. abort on trnslt.\n"); + else if ((fault_status & 0xd) == 0x5) // Translation + KPrintf("reason: sect. translation\n"); + else if ((fault_status & 0xd) == 0x9) // Domain + KPrintf("reason: sect. domain\n"); + else if ((fault_status & 0xd) == 0xd) // Permission + KPrintf("reason: sect. permission\n"); + else if ((fault_status & 0xd) == 0x8) // External abort + KPrintf("reason: ext. abort\n"); + else + KPrintf("reason: unknown???\n"); + + dump_tf(r); +} + +void iabort_reason(struct trapframe* r) +{ + uint32_t fault_status, ifa; + __asm__ __volatile__("mrc p15, 0, %0, c5, c0, 1" : "=r"(fault_status)::); + __asm__ __volatile__("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifa)::); + LOG("prefetch abort at 0x%x, status 0x%x\n", ifa, fault_status); + + if ((fault_status & 0xd) == 0x1) // Alignment failure + KPrintf("reason: alignment\n"); + else if ((fault_status & 0xd) == 0x5) // External abort "on translation" + KPrintf("reason: ext. abort on trnslt.\n"); + else if ((fault_status & 0xd) == 0x5) // Translation + KPrintf("reason: sect. translation\n"); + else if ((fault_status & 0xd) == 0x9) // Domain + KPrintf("reason: sect. domain\n"); + else if ((fault_status & 0xd) == 0xd) // Permission + KPrintf("reason: sect. permission\n"); + else if ((fault_status & 0xd) == 0x8) // External abort + KPrintf("reason: ext. abort\n"); + else + KPrintf("reason: unknown???\n"); + + dump_tf(r); +} + void handle_undefined_instruction(struct trapframe* tf) { // unimplemented trap handler - KPrintf("undefined instruction at %x\n", tf->pc); + ERROR("undefined instruction at %x\n", tf->pc); + xizi_enter_kernel(); panic(""); } -extern void context_switch(struct context**, struct context*); -void dabort_handler(struct trapframe* r) +void handle_reserved(void) { - if (!is_spinlock_locked(&whole_kernel_lock) || whole_kernel_lock.owner_cpu != cur_cpuid()) { - spinlock_lock(&whole_kernel_lock); - } - uint32_t dfs, dfa; - - __asm__ __volatile__("mrc p15, 0, %0, c5, c0, 0" : "=r"(dfs)::); - __asm__ __volatile__("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfa)::); - - if (r->pc < KERN_MEM_BASE) { // Exception occured in User space: exit - ERROR("dabort in user space: %s\n", cur_cpu()->task->name); - LOG("program counter: 0x%x caused\n", r->pc); - LOG("data abort at 0x%x, status 0x%x\n", dfa, dfs); - _abort_reason(dfs); - dump_tf(r); - sys_exit(cur_cpu()->task); - context_switch(&cur_cpu()->task->main_thread.context, cur_cpu()->scheduler); - } else { // Exception occured in Kernel space: panic - LOG("program counter: 0x%x caused\n", r->pc); - LOG("data abort at 0x%x, status 0x%x\n", dfa, dfs); - _abort_reason(dfs); - dump_tf(r); - panic("data abort exception\n"); - } + // unimplemented trap handler + ERROR("Unimplemented Reserved\n"); + xizi_enter_kernel(); + panic(""); } -void iabort_handler(struct trapframe* r) +void handle_fiq(void) { - if (!is_spinlock_locked(&whole_kernel_lock) || whole_kernel_lock.owner_cpu != cur_cpuid()) { - spinlock_lock(&whole_kernel_lock); - } - uint32_t ifs, ifa; - - __asm__ __volatile__("mrc p15, 0, %0, c5, c0, 1" : "=r"(ifs)::); - __asm__ __volatile__("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifa)::); - - if (r->pc < KERN_MEM_BASE) { // Exception occured in User space: exit - ERROR("iabort in user space: %s\n", cur_cpu()->task->name); - LOG("program counter: 0x%x(%s) caused\n", r->pc, cur_cpu()->task); - LOG("prefetch abort at 0x%x, status 0x%x\n", ifa, ifs); - _abort_reason(ifs); - dump_tf(r); - sys_exit(cur_cpu()->task); - context_switch(&cur_cpu()->task->main_thread.context, cur_cpu()->scheduler); - } else { // Exception occured in Kernel space: panic - LOG("program counter: 0x%x(%s) caused\n", r->pc, cur_cpu()->task); - LOG("prefetch abort at 0x%x, status 0x%x\n", ifa, ifs); - _abort_reason(ifs); - dump_tf(r); - panic("prefetch abort exception\n"); - } -} + ERROR("Unimplemented FIQ\n"); + xizi_enter_kernel(); + panic(""); +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/gicv2/gicv2_distributer_to_device.c b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/gicv2/gicv2_distributer_to_device.c index 94c4b12f0..95b9d8f09 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/gicv2/gicv2_distributer_to_device.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/gicv2/gicv2_distributer_to_device.c @@ -45,6 +45,8 @@ Author: AIIT XUOS Lab Modification: 1. take only gicd part of functions *************************************************/ +#include "string.h" + #include "gicv2_common_opa.h" #include "gicv2_registers.h" @@ -139,7 +141,7 @@ void gic_send_sgi(uint32_t irqID, uint32_t target_list, uint32_t filter_list) void gic_init(void) { - gicd_t* gicd = gic_get_gicd(); + volatile gicd_t* gicd = gic_get_gicd(); // First disable the distributor. gic_enable(false); @@ -150,7 +152,9 @@ void gic_init(void) for (uint32_t i = 0; i < 255; i++) { *(uint32_t*)(&gicd->IPRIORITYRn[i * sizeof(uint32_t)]) = (uint32_t)0x80808080; + // memset((void*)&gicd->IPRIORITYRn[i * sizeof(uint32_t)], 0x80, sizeof(uint32_t)); *(uint32_t*)(&gicd->ITARGETSRn[i * sizeof(uint32_t)]) = (uint32_t)0x01010101; + // memset((void*)&gicd->IPRIORITYRn[i * sizeof(uint32_t)], 0x01, sizeof(uint32_t)); } // Init the GIC CPU interface. diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/imx6q-sabrelite/trap_common.c b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/imx6q-sabrelite/trap_common.c index bbc62cc7e..47dede1b9 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/imx6q-sabrelite/trap_common.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/imx6q-sabrelite/trap_common.c @@ -42,13 +42,13 @@ extern void trap_iabort(void); extern void trap_dabort(void); extern void trap_irq_enter(void); extern void trap_undefined_instruction(void); +extern void handle_reserved(void); +extern void handle_fiq(void); static struct XiziTrapDriver xizi_trap_driver; void panic(char* s) { - xizi_trap_driver.cpu_irq_disable(); - spinlock_unlock(&whole_kernel_lock); KPrintf("panic: %s\n", s); for (;;) ; @@ -56,7 +56,6 @@ void panic(char* s) /* stack for different mode*/ static char mode_stack_pages[NR_CPU][NR_MODE_STACKS][MODE_STACK_SIZE]; - extern uint32_t _vector_jumper; extern uint32_t _vector_start; extern uint32_t _vector_end; @@ -71,19 +70,6 @@ void init_cpu_mode_stacks(int cpu_id) } } -void handle_reserved(void) -{ - // unimplemented trap handler - LOG("Unimplemented Reserved\n"); - panic(""); -} - -void handle_fiq(void) -{ - LOG("Unimplemented FIQ\n"); - panic(""); -} - static void _sys_irq_init(int cpu_id) { /* load exception vectors */ @@ -99,9 +85,10 @@ static void _sys_irq_init(int cpu_id) vector_base[5] = (uint32_t)handle_reserved; // Reserved vector_base[6] = (uint32_t)trap_irq_enter; // IRQ vector_base[7] = (uint32_t)handle_fiq; // FIQ + + gic_init(); } /* active hardware irq responser */ - gic_init(); xizi_trap_driver.switch_hw_irqtbl((uint32_t*)&_vector_jumper); } @@ -153,29 +140,6 @@ static void _bind_irq_handler(int irq, irq_handler_t handler) xizi_trap_driver.sw_irqtbl[irq].handler = handler; } -static bool _send_sgi(uint32_t irq, uint32_t bitmask, enum SgiFilterType type) -{ - if (bitmask > (1 << NR_CPU) - 1) { - return false; - } - - enum _gicd_sgi_filter sgi_filter; - switch (type) { - case SgiFilter_TargetList: - sgi_filter = kGicSgiFilter_UseTargetList; - break; - case SgiFilter_AllOtherCPUs: - sgi_filter = kGicSgiFilter_AllOtherCPUs; - break; - default: - sgi_filter = kGicSgiFilter_OnlyThisCPU; - break; - } - gic_send_sgi(irq, bitmask, sgi_filter); - - return true; -} - static uint32_t _hw_before_irq() { @@ -192,29 +156,11 @@ static uint32_t _hw_cur_int_num(uint32_t int_info) return int_info & 0x1FF; } -static uint32_t _hw_cur_int_cpu(uint32_t int_info) -{ - return (int_info >> 10) & 0x7; -} - static void _hw_after_irq(uint32_t int_info) { gic_write_end_of_irq(int_info); } -static int _is_interruptable(void) -{ - uint32_t val; - - __asm__ __volatile__( - "mrs %0, cpsr" - : "=r"(val) - : - :); - - return !(val & DIS_INT); -} - int _cur_cpu_id() { return cpu_get_current(); @@ -231,12 +177,9 @@ static struct XiziTrapDriver xizi_trap_driver = { .switch_hw_irqtbl = _switch_hw_irqtbl, .bind_irq_handler = _bind_irq_handler, - .send_sgi = _send_sgi, - .is_interruptable = _is_interruptable, .hw_before_irq = _hw_before_irq, .hw_cur_int_num = _hw_cur_int_num, - .hw_cur_int_cpu = _hw_cur_int_cpu, .hw_after_irq = _hw_after_irq, }; diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/trampoline.S b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/trampoline.S index 6ee8ba751..da7018964 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/trampoline.S +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/trampoline.S @@ -47,43 +47,17 @@ trap_return: ldmfd r13!, {r14} ldmfd r13!, {r2} msr spsr_cxsf, r2 - ldr r0, [r13], #4 - ldr r1, [r13], #4 - ldr r2, [r13], #4 - ldr r3, [r13], #4 - ldr r4, [r13], #4 - ldr r5, [r13], #4 - ldr r6, [r13], #4 - ldr r7, [r13], #4 - ldr r8, [r13], #4 - ldr r9, [r13], #4 - ldr r10, [r13], #4 - ldr r11, [r13], #4 - ldr r12, [r13], #4 - ldm r13!, {pc}^ + ldmfd r13!, {r0-r12, pc}^ // restore context and return user_trap_swi_enter: - # save trapframe to swi stack - sub sp, sp, #56 - str r14, [sp, #52] - str r12, [sp, #48] - str r11, [sp, #44] - str r10, [sp, #40] - str r9, [sp, #36] - str r8, [sp, #32] - str r7, [sp, #28] - str r6, [sp, #24] - str r5, [sp, #20] - str r4, [sp, #16] - str r3, [sp, #12] - str r2, [sp, #8] - str r1, [sp, #4] - str r0, [sp] + # save trapframe to swi stack + cpsid i + stmfd sp!, {r0-r12, r14} // save context + mrs r2, spsr // copy spsr to r2 + stmfd r13!, {r2} // save r2(spsr) to the stack - mrs r2, spsr - stmfd r13!, {r2} - stmfd r13!, {r14} - stmfd r13, {sp, lr}^ + stmfd r13!, {r14} // save r14 again to have one uniform trapframe + stmfd r13, {sp, lr}^ // save user mode sp and lr sub r13, r13, #8 # call syscall handler @@ -92,17 +66,13 @@ user_trap_swi_enter: b trap_return trap_irq_enter: - # save context in irq stack - sub r14, r14, #4 - sub sp, sp, #16 - str r14, [sp, #12] - str r2, [sp, #8] - str r1, [sp, #4] - str r0, [sp] - - mrs r1, spsr - mov r0, r13 // irq stack stop - add r13, r13, #16 // reset IRQ stack + # save it on the stack as r14 is banked + cpsid i + sub r14, r14, #4 // r14 (lr) contains the interrupted PC + stmfd r13!, {r0-r2, r14} // + mrs r1, spsr // save spsr_irq + mov r0, r13 // save stack stop (r13_irq) + add r13, r13, #16 // reset the IRQ stack # switch to the SVC mode mrs r2, cpsr @@ -111,134 +81,110 @@ trap_irq_enter: msr cpsr_cxsf, r2 # build the trap frame - ldr r2, [r0, #12] + ldr r2, [r0, #12] // read the r14_irq, then save it stmfd r13!, {r2} - sub r13, r13, #40 - str r12, [r13, #36] - str r11, [r13, #32] - str r10, [r13, #28] - str r9, [r13, #24] - str r8, [r13, #20] - str r7, [r13, #16] - str r6, [r13, #12] - str r5, [r13, #8] - str r4, [r13, #4] - str r3, [r13] - - ldmfd r0, {r3-r5} + stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked) + ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack stmfd r13!, {r3-r5} - stmfd r13!, {r1} - stmfd r13!, {lr} - stmfd r13, {sp, lr}^ + stmfd r13!, {r1} // save spsr + stmfd r13!, {lr} // save lr_svc + + stmfd r13, {sp, lr}^ // save user mode sp and lr sub r13, r13, #8 mov r0, r13 // trapframe as parameters bl intr_irq_dispatch b trap_return -trap_reset_enter: - mov r14, #0 - sub r13, r13, #56 - str r14, [r13, #52] - str r12, [r13, #48] - str r11, [r13, #44] - str r10, [r13, #40] - str r9, [r13, #36] - str r8, [r13, #32] - str r7, [r13, #28] - str r6, [r13, #24] - str r5, [r13, #20] - str r4, [r13, #16] - str r3, [r13, #12] - str r2, [r13, #8] - str r1, [r13, #4] - str r0, [r13] - - mrs r2, spsr - stmfd r13!, {r2} - stmfd r13!, {r14} - stmfd r13, {sp, lr}^ - sub r13, r13, #8 - mov r0, r13 - bl _vector_jumper - trap_dabort: - sub r14, r14, #8 - sub r13, r13, #56 - str r14, [r13, #52] - str r12, [r13, #48] - str r11, [r13, #44] - str r10, [r13, #40] - str r9, [r13, #36] - str r8, [r13, #32] - str r7, [r13, #28] - str r6, [r13, #24] - str r5, [r13, #20] - str r4, [r13, #16] - str r3, [r13, #12] - str r2, [r13, #8] - str r1, [r13, #4] - str r0, [r13] + # save it on the stack as r14 is banked + cpsid i + sub r14, r14, #8 // r14 (lr) contains the interrupted PC + stmfd r13!, {r0-r2, r14} // + mrs r1, spsr // save spsr_irq + mov r0, r13 // save stack stop (r13_irq) + add r13, r13, #16 // reset the IRQ stack - mrs r2, spsr - stmfd r13!, {r2} - stmfd r13!, {r14} - stmfd r13, {sp, lr}^ + # switch to the SVC mode + mrs r2, cpsr + bic r2, r2, #ARM_CPSR_MODE_MASK + orr r2, r2, #ARM_MODE_SVC + msr cpsr_cxsf, r2 + + # build the trap frame + ldr r2, [r0, #12] // read the r14_irq, then save it + stmfd r13!, {r2} + stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked) + ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack + stmfd r13!, {r3-r5} + stmfd r13!, {r1} // save spsr + stmfd r13!, {lr} // save lr_svc + + stmfd r13, {sp, lr}^ // save user mode sp and lr sub r13, r13, #8 - mov r0, r13 + + mov r0, r13 // trapframe as parameters bl dabort_handler trap_iabort: - sub r14, r14, #4 - sub r13, r13, #56 - str r14, [r13, #52] - str r12, [r13, #48] - str r11, [r13, #44] - str r10, [r13, #40] - str r9, [r13, #36] - str r8, [r13, #32] - str r7, [r13, #28] - str r6, [r13, #24] - str r5, [r13, #20] - str r4, [r13, #16] - str r3, [r13, #12] - str r2, [r13, #8] - str r1, [r13, #4] - str r0, [r13] +# save it on the stack as r14 is banked + cpsid i + sub r14, r14, #4 // r14 (lr) contains the interrupted PC + stmfd r13!, {r0-r2, r14} // + mrs r1, spsr // save spsr_irq + mov r0, r13 // save stack stop (r13_irq) + add r13, r13, #16 // reset the IRQ stack - mrs r2, spsr + # switch to the SVC mode + mrs r2, cpsr + bic r2, r2, #ARM_CPSR_MODE_MASK + orr r2, r2, #ARM_MODE_SVC + msr cpsr_cxsf, r2 + + # build the trap frame + ldr r2, [r0, #12] // read the r14_irq, then save it stmfd r13!, {r2} - stmfd r13!, {r14} - stmfd r13, {sp, lr}^ + stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked) + ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack + stmfd r13!, {r3-r5} + stmfd r13!, {r1} // save spsr + stmfd r13!, {lr} // save lr_svc + + stmfd r13, {sp, lr}^ // save user mode sp and lr sub r13, r13, #8 - mov r0, r13 + + mov r0, r13 // trapframe as parameters bl iabort_handler trap_undefined_instruction: - sub r13, r13, #56 - str r14, [r13, #52] - str r12, [r13, #48] - str r11, [r13, #44] - str r10, [r13, #40] - str r9, [r13, #36] - str r8, [r13, #32] - str r7, [r13, #28] - str r6, [r13, #24] - str r5, [r13, #20] - str r4, [r13, #16] - str r3, [r13, #12] - str r2, [r13, #8] - str r1, [r13, #4] - str r0, [r13] + # save it on the stack as r14 is banked + cpsid i + sub r14, r14, #4 // r14 (lr) contains the interrupted PC + stmfd r13!, {r0-r2, r14} // + mrs r1, spsr // save spsr_irq + mov r0, r13 // save stack stop (r13_irq) + add r13, r13, #16 // reset the IRQ stack - mrs r2, spsr + # switch to the SVC mode + mrs r2, cpsr + bic r2, r2, #ARM_CPSR_MODE_MASK + orr r2, r2, #ARM_MODE_SVC + msr cpsr_cxsf, r2 + + # build the trap frame + ldr r2, [r0, #12] // read the r14_irq, then save it stmfd r13!, {r2} - stmfd r13!, {r14} - stmfd r13, {sp, lr}^ - sub r13, r13, #8 - mov r0, r13 - bl handle_undefined_instruction + stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked) + ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack + stmfd r13!, {r3-r5} + stmfd r13!, {r1} // save spsr + stmfd r13!, {lr} // save lr_svc + stmfd r13, {sp, lr}^ // save user mode sp and lr + sub r13, r13, #8 + + mov r0, r13 // trapframe as parameters + bl handle_undefined_instruction init_stack: # set the stack for Other mode diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/zynq7000-zc702/trap_common.c b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/zynq7000-zc702/trap_common.c index eed662bd2..f706f58dd 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/zynq7000-zc702/trap_common.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/arm/armv7-a/cortex-a9/zynq7000-zc702/trap_common.c @@ -42,12 +42,13 @@ extern void trap_iabort(void); extern void trap_dabort(void); extern void trap_irq_enter(void); extern void trap_undefined_instruction(void); +extern void handle_reserved(void); +extern void handle_fiq(void); static struct XiziTrapDriver xizi_trap_driver; void panic(char* s) { - xizi_trap_driver.cpu_irq_disable(); KPrintf("panic: %s\n", s); for (;;) ; @@ -55,7 +56,6 @@ void panic(char* s) /* stack for different mode*/ static char mode_stack_pages[NR_CPU][NR_MODE_STACKS][MODE_STACK_SIZE]; - extern uint32_t _vector_jumper; extern uint32_t _vector_start; extern uint32_t _vector_end; @@ -72,19 +72,6 @@ void init_cpu_mode_stacks(int cpu_id) } } -void handle_reserved(void) -{ - // unimplemented trap handler - LOG("Unimplemented Reserved\n"); - panic(""); -} - -void handle_fiq(void) -{ - LOG("Unimplemented FIQ\n"); - panic(""); -} - static void _sys_irq_init(int cpu_id) { @@ -101,18 +88,18 @@ static void _sys_irq_init(int cpu_id) vector_base[5] = (uint32_t)handle_reserved; // Reserved vector_base[6] = (uint32_t)trap_irq_enter; // IRQ vector_base[7] = (uint32_t)handle_fiq; // FIQ - } - /* active hardware irq responser */ - XScuGic_Config* gic_config = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID); - if (NULL == gic_config) { - ERROR("Error while looking up gic config\n"); - return; - } - int gic_init_status = XScuGic_CfgInitialize(&IntcInstance, gic_config, gic_config->CpuBaseAddress); - if (gic_init_status != XST_SUCCESS) { - ERROR("Error initializing gic\n"); - return; + /* active hardware irq responser */ + XScuGic_Config* gic_config = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID); + if (NULL == gic_config) { + ERROR("Error while looking up gic config\n"); + return; + } + int gic_init_status = XScuGic_CfgInitialize(&IntcInstance, gic_config, gic_config->CpuBaseAddress); + if (gic_init_status != XST_SUCCESS) { + ERROR("Error initializing gic\n"); + return; + } } xizi_trap_driver.switch_hw_irqtbl((uint32_t*)&_vector_jumper); @@ -164,24 +151,6 @@ static void _bind_irq_handler(int irq, irq_handler_t handler) xizi_trap_driver.sw_irqtbl[irq].handler = handler; } -static bool _send_sgi(uint32_t irq, uint32_t bitmask, enum SgiFilterType type) -{ - if (bitmask > (1 << NR_CPU) - 1) { - return false; - } - - int cpu_id = 0; - while (bitmask != 0) { - if ((bitmask & 0x1) != 0) { - XScuGic_SoftwareIntr(&IntcInstance, irq, cpu_id); - } - cpu_id++; - bitmask >>= 1; - } - - return true; -} - static uint32_t _hw_before_irq() { @@ -194,29 +163,11 @@ static uint32_t _hw_cur_int_num(uint32_t int_info) return int_info & XSCUGIC_ACK_INTID_MASK; } -static uint32_t _hw_cur_int_cpu(uint32_t int_info) -{ - return (int_info >> 5) & 0x3; -} - static void _hw_after_irq(uint32_t int_info) { XScuGic_CPUWriteReg(&IntcInstance, XSCUGIC_EOI_OFFSET, int_info); } -static int _is_interruptable(void) -{ - uint32_t val; - - __asm__ __volatile__( - "mrs %0, cpsr" - : "=r"(val) - : - :); - - return !(val & DIS_INT); -} - int _cur_cpu_id() { return cpu_get_current(); @@ -233,18 +184,15 @@ static struct XiziTrapDriver xizi_trap_driver = { .switch_hw_irqtbl = _switch_hw_irqtbl, .bind_irq_handler = _bind_irq_handler, - .send_sgi = _send_sgi, - .is_interruptable = _is_interruptable, .hw_before_irq = _hw_before_irq, .hw_cur_int_num = _hw_cur_int_num, - .hw_cur_int_cpu = _hw_cur_int_cpu, .hw_after_irq = _hw_after_irq, }; struct XiziTrapDriver* hardkernel_intr_init(struct TraceTag* hardkernel_tag) { xizi_trap_driver.sys_irq_init(0); - xizi_trap_driver.cpu_irq_enable(); + xizi_trap_driver.cpu_irq_disable(); return &xizi_trap_driver; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.c b/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.c index 210edfabd..245a44fca 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.c @@ -27,8 +27,8 @@ #include "multicores.h" struct lock_node { - int cpu_id; struct double_list_node node; + int cpu_id; }; static struct double_list_node lock_request_guard; @@ -52,7 +52,7 @@ enum { SPINLOCK_LOCK_WAITFOREVER = 0xFFFFFFFF, }; -void spinlock_init(struct spinlock* lock, char* name) +__attribute__((optimize("O0"))) void spinlock_init(struct spinlock* lock, char* name) { lock->owner_cpu = SPINLOCK_STATE_UNLOCK; strncpy(lock->name, name, 24); @@ -61,33 +61,59 @@ void spinlock_init(struct spinlock* lock, char* name) extern int _spinlock_lock(struct spinlock* lock, uint32_t timeout); void _spinlock_unlock(struct spinlock* lock); -void spinlock_lock(struct spinlock* lock) +__attribute__((optimize("O0"))) void spinlock_lock(struct spinlock* lock) { - if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpuid()) { + int cur_cpu_id = cur_cpuid(); + if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpu_id) { ERROR("spinlock %s lock double locked by core %d\n", lock->name, lock->owner_cpu); panic(""); } + + struct double_list_node* p_lock_node = &core_lock_request[cur_cpu_id].node; _spinlock_lock(&request_lock, SPINLOCK_LOCK_WAITFOREVER); - doubleListAddOnBack(&core_lock_request[cur_cpuid()].node, &lock_request_guard); + doubleListAddOnBack(p_lock_node, &lock_request_guard); _spinlock_unlock(&request_lock); - while (lock_request_guard.next != &core_lock_request[cur_cpuid()].node) + while (lock_request_guard.next != p_lock_node) ; _spinlock_lock(lock, SPINLOCK_LOCK_WAITFOREVER); } -void spinlock_unlock(struct spinlock* lock) +__attribute__((optimize("O0"))) void spinlock_unlock(struct spinlock* lock) { - assert(lock_request_guard.next == &core_lock_request[cur_cpuid()].node); + struct double_list_node* p_lock_node = &core_lock_request[cur_cpuid()].node; + assert(lock_request_guard.next == p_lock_node); _spinlock_lock(&request_lock, SPINLOCK_LOCK_WAITFOREVER); - _double_list_del(core_lock_request[cur_cpuid()].node.prev, core_lock_request[cur_cpuid()].node.next); + _double_list_del(p_lock_node->prev, p_lock_node->next); _spinlock_unlock(&request_lock); _spinlock_unlock(lock); } -bool is_spinlock_locked(struct spinlock* lock) +__attribute__((optimize("O0"))) bool spinlock_try_lock(struct spinlock* lock) { - return lock->owner_cpu != SPINLOCK_STATE_UNLOCK; + int cur_cpu_id = cur_cpuid(); + if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpu_id) { + ERROR("spinlock %s lock double locked by core %d\n", lock->name, lock->owner_cpu); + panic(""); + } + + struct double_list_node* p_lock_node = &core_lock_request[cur_cpu_id].node; + _spinlock_lock(&request_lock, SPINLOCK_LOCK_WAITFOREVER); + doubleListAddOnBack(p_lock_node, &lock_request_guard); + if (lock_request_guard.next != p_lock_node) { + _double_list_del(p_lock_node->prev, p_lock_node->next); + _spinlock_unlock(&request_lock); + return false; + } + _spinlock_unlock(&request_lock); + _spinlock_lock(lock, SPINLOCK_LOCK_WAITFOREVER); + + return true; +} + +bool is_spinlock_hold_by_current_cpu(struct spinlock* lock) +{ + return lock->owner_cpu; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.h b/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.h index e1e08bb86..d082cc67f 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/spinlock.h @@ -34,7 +34,7 @@ Modification: #define STACK_DEPTH 32 struct spinlock { // Mutex. - uint32_t owner_cpu; // 1 for locked, 0 for unlocked + volatile uint32_t owner_cpu; // 1 for locked, 0 for unlocked char name[28]; // The call stack (an array of program counters) } __attribute__((aligned(32))); @@ -42,4 +42,5 @@ bool module_spinlock_use_intr_init(void); void spinlock_init(struct spinlock* lock, char* name); void spinlock_lock(struct spinlock* lock); void spinlock_unlock(struct spinlock* lock); -bool is_spinlock_locked(struct spinlock* lock); \ No newline at end of file +bool spinlock_try_lock(struct spinlock* lock); +bool is_spinlock_hold_by_current_cpu(struct spinlock* lock); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/intr/trap_common.h b/Ubiquitous/XiZi_AIoT/hardkernel/intr/trap_common.h index 06a64ca7d..232cb6b7b 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/intr/trap_common.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/intr/trap_common.h @@ -56,8 +56,6 @@ struct irq_table_entry { struct XiziTrapDriver { /* irq number table*/ struct irq_table_entry sw_irqtbl[NR_IRQS]; - /* current irq number happening in cpu*/ - uint32_t curr_int[NR_CPU]; void (*sys_irq_init)(int); int (*cur_cpu_id)(); @@ -66,17 +64,14 @@ struct XiziTrapDriver { void (*cpu_irq_disable)(); void (*single_irq_enable)(int irq, int cpu, int prio); void (*single_irq_disable)(int irq, int cpu); - uint32_t* (*switch_hw_irqtbl)(uint32_t*); - bool (*send_sgi)(uint32_t, uint32_t, enum SgiFilterType); + uint32_t* (*switch_hw_irqtbl)(uint32_t*); void (*bind_irq_handler)(int, irq_handler_t); /* check if no if interruptable */ - int (*is_interruptable)(); /* code runs before irq handling */ uint32_t (*hw_before_irq)(); uint32_t (*hw_cur_int_num)(uint32_t int_info); - uint32_t (*hw_cur_int_cpu)(uint32_t int_info); /* code runs after irq handling */ void (*hw_after_irq)(uint32_t int_info); }; @@ -101,4 +96,7 @@ void panic(char* s); bool intr_distributer_init(struct IrqDispatcherRightGroup*); void intr_irq_dispatch(struct trapframe* tf); bool swi_distributer_init(struct SwiDispatcherRightGroup*); -void software_irq_dispatch(struct trapframe* tf); \ No newline at end of file +void software_irq_dispatch(struct trapframe* tf); + +void dabort_reason(struct trapframe* r); +void iabort_reason(struct trapframe* r); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h index eef60ffe4..26957c7bb 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/imx6q-sabrelite/memlayout.h @@ -56,10 +56,11 @@ Modification: #define MAX_NR_FREE_PAGES ((PHY_MEM_STOP - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT) /* User memory layout */ -#define USER_STACK_SIZE PAGE_SIZE +#define USER_STACK_SIZE MODE_STACK_SIZE #define USER_MEM_BASE (0x00000000) #define USER_MEM_TOP DEV_VRTMEM_BASE #define USER_IPC_SPACE_BASE (0x70000000) +#define USER_IPC_USE_ALLOCATOR_WATERMARK (0x70010000) #define USER_IPC_SPACE_TOP (USER_MEM_TOP - USER_STACK_SIZE) /* Deivce memory layout */ diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/mmu.c b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/mmu.c index 50d783b90..16d78663d 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/mmu.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/mmu.c @@ -38,24 +38,6 @@ Modification: // extern struct MmuCommonDone mmu_common_done; static struct MmuDriverRightGroup right_group; -void load_pgdir_critical(uintptr_t pgdir_paddr, struct TraceTag* intr_driver_tag) -{ - - /* get cache driver */ - struct ICacheDone* p_icache_done = AchieveResource(&right_group.icache_driver_tag); - struct DCacheDone* p_dcache_done = AchieveResource(&right_group.dcache_driver_tag); - - /* get intr driver */ - struct XiziTrapDriver* p_intr_driver = AchieveResource(intr_driver_tag); - - p_intr_driver->cpu_irq_disable(); - TTBR0_W((uint32_t)pgdir_paddr); - CLEARTLB(0); - p_icache_done->invalidateall(); - p_dcache_done->flushall(); - p_intr_driver->cpu_irq_enable(); -} - void load_pgdir(uintptr_t pgdir_paddr) { /* get cache driver */ @@ -94,7 +76,6 @@ static struct MmuCommonDone mmu_common_done = { .MmuUsrDevPteAttr = GetUsrDevPteAttr, .MmuKernPteAttr = GetKernPteAttr, - .LoadPgdirCrit = load_pgdir_critical, .LoadPgdir = load_pgdir, .TlbFlushAll = tlb_flush_all, .TlbFlush = tlb_flush_range, diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/zynq7000-zc702/memlayout.h b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/zynq7000-zc702/memlayout.h index f68861da0..cf480c399 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/zynq7000-zc702/memlayout.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/arm/armv7-a/cortex-a9/zynq7000-zc702/memlayout.h @@ -53,13 +53,14 @@ Modification: #define NUM_TOPLEVEL_PDE NUM_LEVEL3_PDE #define PAGE_SIZE LEVEL4_PTE_SIZE -#define MAX_NR_FREE_PAGES ((PHY_MEM_STOP - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT) +#define MAX_NR_FREE_PAGES ((PHY_USER_FREEMEM_BASE - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT) /* User memory layout */ -#define USER_STACK_SIZE PAGE_SIZE +#define USER_STACK_SIZE MODE_STACK_SIZE #define USER_MEM_BASE (0x00000000) #define USER_MEM_TOP DEV_VRTMEM_BASE #define USER_IPC_SPACE_BASE (0x70000000) +#define USER_IPC_USE_ALLOCATOR_WATERMARK (0x70010000) #define USER_IPC_SPACE_TOP (USER_MEM_TOP - USER_STACK_SIZE) /* Deivce memory layout */ diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/mmu_common.h b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/mmu_common.h index b979f80e8..4170afc0a 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/mmu/mmu_common.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/mmu/mmu_common.h @@ -27,7 +27,6 @@ struct MmuCommonDone void (*MmuUsrDevPteAttr)(uintptr_t* attr); void (*MmuKernPteAttr)(uintptr_t* attr); - void (*LoadPgdirCrit)(uintptr_t pgdir_paddr, struct TraceTag*); void (*LoadPgdir)(uintptr_t pgdir_paddr); void (*TlbFlushAll)(); void (*TlbFlush)(uintptr_t vaddr, int len); diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/uart/printf.h b/Ubiquitous/XiZi_AIoT/hardkernel/uart/printf.h new file mode 100644 index 000000000..85c030650 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/hardkernel/uart/printf.h @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro defines + * and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ +#define KPrintf printf_ +#define printf printf_ +int printf_(const char* format, ...); + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define sprintf sprintf_ +int sprintf_(char* buffer, const char* format, ...); + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +#define snprintf snprintf_ +#define vsnprintf vsnprintf_ +int snprintf_(char* buffer, size_t count, const char* format, ...); +int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); + +/** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define vprintf vprintf_ +int vprintf_(const char* format, va_list va); + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); + +#ifdef __cplusplus +} +#endif + +#endif // _PRINTF_H_ \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.c b/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.c index 13d067207..d4a09dfa4 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.c @@ -1,15 +1,34 @@ -/* - * Copyright (c) 2020 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// /** * @file uart_common_ope.c * @brief support uart common operation @@ -17,8 +36,10 @@ * @author AIIT XUOS Lab * @date 2023.11.20 */ +#include +#include + #include "uart_common_ope.h" -#include "assert.h" struct PrintProxy { struct TraceTag uart_driver_tag; @@ -38,85 +59,840 @@ int serial_init(struct TraceTag* uart_driver_tag) return 0; } -static void PrintInt(int xx, int base, int sign) +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#define PRINTF_NTOA_BUFFER_SIZE 32U + +#define PRINTF_FTOA_BUFFER_SIZE 32U + +// support for the floating point type (%f) +// default: activated +#define PRINTF_SUPPORT_FLOAT + +// support for exponential floating point notation (%e/%g) +// default: activated +#define PRINTF_SUPPORT_EXPONENTIAL + +// define the default floating point precision +// default: 6 digits +#define PRINTF_DEFAULT_FLOAT_PRECISION 6U + +// define the largest float suitable to print with %f +// default: 1e9 +#define PRINTF_MAX_FLOAT 1e9 + +// support for the long long types (%llu or %p) +// default: activated +#define PRINTF_SUPPORT_LONG_LONG + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#define PRINTF_SUPPORT_PTRDIFF_T + +#define _putchar proxy()->serial->putc + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + +// import float.h for DBL_MAX +#if defined(PRINTF_SUPPORT_FLOAT) +#include +#endif + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + +// internal buffer output +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) { - static char digits[] = "0123456789ABCDEF"; - char buf[16]; - int i; - uint32_t x; - - if (sign && (sign = xx < 0)) { - x = -xx; - } else { - x = xx; + if (idx < maxlen) { + ((char*)buffer)[idx] = character; } - - i = 0; - - do { - buf[i++] = digits[x % base]; - } while ((x /= base) != 0); - - if (sign) - buf[i++] = '-'; - - while (--i >= 0) - proxy()->serial->putc(buf[i]); } -void KPrintf(char* fmt, ...) +// internal null output +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) { - int i, c; - uint32_t* argp; - char* s; + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; +} - if (fmt == 0) { - KPrintf("null fmt"); - return; +// internal _putchar wrapper +static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)buffer; + (void)idx; + (void)maxlen; + if (character) { + _putchar(character); + } +} + +// internal output function wrapper +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; + (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); + } +} + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int _strnlen_s(const char* str, size_t maxsize) +{ + const char* s; + for (s = str; *s && maxsize--; ++s) + ; + return (unsigned int)(s - str); +} + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +// internal ASCII string to unsigned int conversion +static unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + +// output the specified string in reverse, taking care of any zero-padding +static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } } - argp = (uint32_t*)(void*)(&fmt + 1); + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } - for (i = 0; (c = fmt[i] & 0xff) != 0; i++) { - if (c != '%') { - proxy()->serial->putc(c); + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + +#if defined(PRINTF_SUPPORT_FLOAT) + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + +// internal ftoa for fixed decimal floating point +static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } else if (diff < 0.5) { + } else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { + value = -value; + } + + // default precision + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) + out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; continue; + } else { + // yes, evaluate it + format++; } - c = fmt[++i] & 0xff; + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': + flags |= FLAGS_ZEROPAD; + format++; + n = 1U; + break; + case '-': + flags |= FLAGS_LEFT; + format++; + n = 1U; + break; + case '+': + flags |= FLAGS_PLUS; + format++; + n = 1U; + break; + case ' ': + flags |= FLAGS_SPACE; + format++; + n = 1U; + break; + case '#': + flags |= FLAGS_HASH; + format++; + n = 1U; + break; + default: + n = 0U; + break; + } + } while (n); - if (!c) + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l': + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } break; + case 'h': + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j': + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z': + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default: + break; + } - switch (c) { + // evaluate specifier + switch (*format) { case 'd': - PrintInt(*argp++, 10, 1); - break; - + case 'i': + case 'u': case 'x': - case 'p': - PrintInt(*argp++, 16, 0); - break; - - case 's': - if ((s = (char*)*argp++) == 0) { - s = "(null)"; + case 'X': + case 'o': + case 'b': { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } else if (*format == 'o') { + base = 8U; + } else if (*format == 'b') { + base = 2U; + } else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; } - for (; *s; s++) { - proxy()->serial->putc(*s); + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) + : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) + : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f': + case 'F': + if (*format == 'F') + flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g') || (*format == 'G')) + flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E') || (*format == 'G')) + flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + case 'c': { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's': { + const char* p = va_arg(va, char*); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p': { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } case '%': - proxy()->serial->putc('%'); + out('%', buffer, idx++, maxlen); + format++; break; default: - // Print unknown % sequence to draw attention. - proxy()->serial->putc('%'); - proxy()->serial->putc(c); + out(*format, buffer, idx++, maxlen); + format++; break; } } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; } + +/////////////////////////////////////////////////////////////////////////////// + +int printf_(const char* format, ...) +{ + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int sprintf_(char* buffer, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int snprintf_(char* buffer, size_t count, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + +int vprintf_(const char* format, va_list va) +{ + char buffer[1]; + return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); +} + +int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) +{ + va_list va; + va_start(va, format); + const out_fct_wrap_type out_fct_wrap = { out, arg }; + const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.h b/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.h index 9b71764b4..3e3d27ac0 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.h +++ b/Ubiquitous/XiZi_AIoT/hardkernel/uart/uart_common_ope.h @@ -24,6 +24,7 @@ #include #include "actracer.h" +#include "printf.h" struct XiziSerialDriver { void (*sys_serial_init)(); @@ -33,8 +34,6 @@ struct XiziSerialDriver { void (*putc)(uint8_t); }; -void KPrintf(char* fmt, ...); - struct XiziSerialDriver* hardkernel_uart_init(struct TraceTag* hardkernel_tag); int serial_init(struct TraceTag* uart_driver_tag); diff --git a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c index c0a259dee..d790e0344 100644 --- a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c +++ b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer.c @@ -101,7 +101,7 @@ static bool dealloc_trace_meta(struct TraceMeta* meta) static tracer_mem_chunk_idx_t trace_meta_map_mem_chunk(struct TraceMeta* const p_trace_meta, tracer_mem_chunk_idx_t mem_chunk_num) { - tracer_mem_chunk_idx_t addr; + tracer_mem_chunk_idx_t addr = 0; /* direct mapping */ if (mem_chunk_num < TRACEMETA_NR_DIRECT) { if ((addr = p_trace_meta->addr[mem_chunk_num]) == 0) { @@ -367,8 +367,9 @@ static void trace_locate_inner(struct TraceTag* target, struct TraceTag* const p // p_trace_meta: TRACER_OWNER, VT_FS or other. // TRACER_OWNER: path: "", name: "dir name" // other: path: "", name: "file name" - if (!p_trace_meta) { + if (p_trace_meta == NULL) { DEBUG("trace_locate, not found\n"); + return; } target->type = p_trace_meta->type; target->meta = p_trace_meta; diff --git a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer_mem_chunk.c b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer_mem_chunk.c index 44909c21e..01d64fa4a 100644 --- a/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer_mem_chunk.c +++ b/Ubiquitous/XiZi_AIoT/kernel_actracer/actracer_mem_chunk.c @@ -105,6 +105,9 @@ static struct tracer_mem_chunk* tracer_get_mem_chunk_cache(uint32_t chunk_id) struct tracer_mem_chunk* tracer_mem_chunk_read(uint32_t chunk_id) { struct tracer_mem_chunk* b = tracer_get_mem_chunk_cache(chunk_id); + if (b == NULL) { + return NULL; + } if (!(b->flag & TRACER_MEM_CHUNK_VALID)) { tracer_mem_chunk_sync(b); b->flag |= TRACER_MEM_CHUNK_VALID; @@ -137,6 +140,9 @@ static void tracer_mem_chunk_zero(uint32_t chunk_id) assert(chunk_id >= 0 && chunk_id < tracer_mem_chunk_syner.nr_mem_chunks); struct tracer_mem_chunk* tracer_mem_chunk = NULL; tracer_mem_chunk = tracer_mem_chunk_read(chunk_id); + if (tracer_mem_chunk == NULL) { + return; + } memset(tracer_mem_chunk->data, 0, tracer_mem_chunk_syner.mem_chunk_size); tracer_mem_chunk_write(tracer_mem_chunk); tracer_mem_chunk_release(tracer_mem_chunk); diff --git a/Ubiquitous/XiZi_AIoT/services/app/Makefile b/Ubiquitous/XiZi_AIoT/services/app/Makefile index 288a23c1b..ac07d2f9f 100644 --- a/Ubiquitous/XiZi_AIoT/services/app/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/app/Makefile @@ -1,12 +1,12 @@ ifeq ($(BOARD), imx6q-sabrelite) toolchain ?= arm-none-eabi- user_ldflags = --specs=nosys.specs -Wl,-Map=user.map,-cref -N -cflags = -std=c11 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie -no-pie +cflags = -std=c11 -O2 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie -no-pie endif ifeq ($(BOARD), zynq7000-zc702) toolchain ?= arm-xilinx-eabi- user_ldflags = -Wl,--start-group,-lgcc,-lc,--end-group -N -cflags = -std=c11 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie +cflags = -std=c11 -O2 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie board_specs = stub.o #cflags = -Wall -g -std=c11 endif @@ -19,11 +19,17 @@ c_useropts = -O0 INC_DIR = -I$(KERNEL_ROOT)/services/shell/letter-shell \ -I$(KERNEL_ROOT)/services/lib/ipc \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/fs/libfs \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ -I$(KERNEL_ROOT)/services/app -all: init test_fs simple_client simple_server shell fs_server test_priority readme.txt | bin +ifeq ($(BOARD), imx6q-sabrelite) +all: init test_fs simple_client simple_server shell fs_server test_irq_hdlr test_irq_block test_irq_send readme.txt | bin +else +all: init test_fs simple_client simple_server shell fs_server test_irq_hdlr readme.txt | bin +endif ../tools/mkfs/mkfs ./fs.img $^ @mv $(filter-out readme.txt, $^) bin @mv *.o bin @@ -32,31 +38,45 @@ all: init test_fs simple_client simple_server shell fs_server test_priority read bin: @mkdir -p bin -shell: shell_port.o libserial.o shell_cmd_list.o shell.o shell_ext.o libfs_to_client.o libipc.o session.o usyscall.o libmem.o +ifeq ($(BOARD), imx6q-sabrelite) +test_irq_send: test_irq_sender.o usyscall.o arch_usyscall.o libserial.o + @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} + @${objdump} -S $@ > $@.asm +endif + +test_irq_block: test_irq_block.o libserial.o libipc.o session.o usyscall.o arch_usyscall.o libmem.o + @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} + @${objdump} -S $@ > $@.asm + +test_irq_hdlr: test_irq_handler.o libserial.o libipc.o session.o usyscall.o arch_usyscall.o libmem.o + @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} + @${objdump} -S $@ > $@.asm + +shell: shell_port.o libserial.o shell_cmd_list.o shell.o shell_ext.o libfs_to_client.o libipc.o session.o usyscall.o arch_usyscall.o libmem.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm -init: init.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o libmem.o +init: init.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o arch_usyscall.o libmem.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm -test_fs: test_fs.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o libmem.o +test_fs: test_fs.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o arch_usyscall.o libmem.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm -simple_client: simple_client.o libserial.o libipc.o session.o simple_service.o libfs_to_client.o usyscall.o libmem.o +simple_client: simple_client.o libserial.o libipc.o session.o simple_service.o libfs_to_client.o usyscall.o arch_usyscall.o libmem.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm -simple_server: simple_server.o libserial.o libipc.o session.o simple_service.o usyscall.o libmem.o +simple_server: simple_server.o libserial.o libipc.o session.o simple_service.o usyscall.o arch_usyscall.o libmem.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm -fs_server: fs_server.o libfs_to_client.o fs.o libserial.o libipc.o session.o block_io.o usyscall.o libmem.o +fs_server: fs_server.o libfs_to_client.o fs.o libserial.o libipc.o session.o block_io.o usyscall.o arch_usyscall.o libmem.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm -test_priority: test_priority.o libserial.o usyscall.o libmem.o +test_priority: test_priority.o libserial.o usyscall.o arch_usyscall.o libmem.o @${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs} @${objdump} -S $@ > $@.asm diff --git a/Ubiquitous/XiZi_AIoT/services/app/shell_port.c b/Ubiquitous/XiZi_AIoT/services/app/shell_port.c index cb1459168..ce2453519 100644 --- a/Ubiquitous/XiZi_AIoT/services/app/shell_port.c +++ b/Ubiquitous/XiZi_AIoT/services/app/shell_port.c @@ -35,7 +35,7 @@ signed short userShellRead(char* data, unsigned short len) while (length--) { cur_read = getc(); if (cur_read == 0xff) { - yield(); + yield(SYS_TASK_YIELD_NO_REASON); } // *data++ = getc(); *data++ = cur_read; diff --git a/Ubiquitous/XiZi_AIoT/services/app/simple_client.c b/Ubiquitous/XiZi_AIoT/services/app/simple_client.c index 232916067..0462bce7d 100755 --- a/Ubiquitous/XiZi_AIoT/services/app/simple_client.c +++ b/Ubiquitous/XiZi_AIoT/services/app/simple_client.c @@ -84,7 +84,7 @@ int main(int argc, char** argv) if (argc >= 2) { id = string_to_integer(argv[1]); } - printf("This is Simple Client %d, size is 0x%x\n", id, task_heap_base()); + // printf("This is Simple Client %d, size is 0x%x\n", id, task_heap_base()); struct Session session_wait; struct Session session_nowait; diff --git a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/libserial.h b/Ubiquitous/XiZi_AIoT/services/app/test_irq.h similarity index 76% rename from Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/libserial.h rename to Ubiquitous/XiZi_AIoT/services/app/test_irq.h index 02d3e18af..f060ef947 100644 --- a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/libserial.h +++ b/Ubiquitous/XiZi_AIoT/services/app/test_irq.h @@ -9,10 +9,12 @@ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ +#include "libipc.h" +#include "libserial.h" +#include "usyscall.h" -/// this file is only used for debug -#pragma once +IPC_SERVICES(IpcSwIntrHandler, Ipc_intr_3, Ipc_wait_intr_3); -void printf(char* fmt, ...); - -char getc(); \ No newline at end of file +enum { + SW_INTERRUPT_3 = 3, +}; diff --git a/Ubiquitous/XiZi_AIoT/services/app/test_irq_block.c b/Ubiquitous/XiZi_AIoT/services/app/test_irq_block.c new file mode 100644 index 000000000..32d5103e7 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/services/app/test_irq_block.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "test_irq.h" + +IPC_INTERFACE(Ipc_wait_intr_3, 1, ignore, 0); +int wait_intr(struct Session* session, void* ignore_param) +{ + return IPC_CALL(Ipc_wait_intr_3)(session, NULL); +} + +static char prog_name[] = "TEST_IRQ_BLOCK"; +int main(int argc, char* argv[]) +{ + struct Session session; + if (connect_session(&session, "TestIRQ", 4096) < 0) { + printf("connect session failed\n"); + exit(); + } + + printf("%s start waiting for IRQ.\n", prog_name); + wait_intr(&session, NULL); + printf("%s return from waiting for IRQ.\n", prog_name); + + exit(); +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/app/test_irq_handler.c b/Ubiquitous/XiZi_AIoT/services/app/test_irq_handler.c new file mode 100644 index 000000000..c1f49fb0c --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/services/app/test_irq_handler.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "test_irq.h" + +static bool has_one_interrupt = false; +int IPC_DO_SERVE_FUNC(Ipc_intr_3)(void* ignore) +{ + printf("TEST_SW_HDLR: In %s()\n", __func__); + has_one_interrupt = true; + return 0; +} + +int IPC_DO_SERVE_FUNC(Ipc_wait_intr_3)(void* ignore) +{ + // delay the this handle + if (!has_one_interrupt) { + delay_session(); + return -1; + } + + // serve can be done by now + has_one_interrupt = false; + return 0; +} + +IPC_SERVER_INTERFACE(Ipc_intr_3, 1); +IPC_SERVER_INTERFACE(Ipc_wait_intr_3, 1); +IPC_SERVER_REGISTER_INTERFACES(IpcSwIntrHandler, 2, Ipc_intr_3, Ipc_wait_intr_3); +int main() +{ + if (register_irq(SW_INTERRUPT_3, Ipc_intr_3) < 0) { + printf("TEST_SW_HDLR: bind failed"); + exit(); + } + + static char prog_name[] = "TestIRQ"; + if (register_server("TestIRQ") < 0) { + printf("register server name: %s failed.\n", prog_name); + exit(); + } + + ipc_server_loop(&IpcSwIntrHandler); + + exit(); +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/Makefile b/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/Makefile index 1a44e7a85..122fb6ef6 100644 --- a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/Makefile @@ -15,10 +15,12 @@ c_useropts = -O0 INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \ -I$(KERNEL_ROOT)/services/lib/ipc \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ -I$(KERNEL_ROOT)/services/app -board: libserial.o usyscall.o +board: libserial.o arch_usyscall.o test_irq_sender.o @mv $^ ../../app %.o: %.c diff --git a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/arch_usyscall.c b/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/arch_usyscall.c new file mode 100644 index 000000000..76125fa0e --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/arch_usyscall.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "usyscall.h" + +int syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4) +{ + int ret = -1; + + __asm__ volatile( + "mov r0, %1;\ + mov r1, %2;\ + mov r2, %3;\ + mov r3, %4;\ + mov r4, %5;\ + swi 0;\ + dsb;\ + isb;\ + mov %0, r0" + : "=r"(ret) + : "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4) + : "memory", "r0", "r1", "r2", "r3", "r4"); + + return ret; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/test_irq_sender.c b/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/test_irq_sender.c new file mode 100644 index 000000000..c3eb4328f --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/test_irq_sender.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "libserial.h" +#include "usyscall.h" + +enum { + SW_INTERRUPT_3 = 3, +}; + +enum { + ARM_PERIPHERAL_BASE = 0x00A00000, + MX6Q_GICD_BASE_OFFSET = 0x1000, + MX6Q_GICC_BASE_OFFSET = 0x100, + + ARM_PERIPHERAL_VIRT_BASE = 0x50000000, +}; + +enum _gicd_sgi_filter { + //! Forward the interrupt to the CPU interfaces specified in the @a target_list parameter. + kGicSgiFilter_UseTargetList = 0, + + //! Forward the interrupt to all CPU interfaces except that of the processor that requested + //! the interrupt. + kGicSgiFilter_AllOtherCPUs = 1, + + //! Forward the interrupt only to the CPU interface of the processor that requested the + //! interrupt. + kGicSgiFilter_OnlyThisCPU = 2 +}; + +struct _gicd_registers { + uint32_t CTLR; //!< Distributor Control Register. + uint32_t TYPER; //!< Interrupt Controller Type Register. + uint32_t IIDR; //!< Distributor Implementer Identification Register. + uint32_t _reserved0[29]; + uint32_t IGROUPRn[8]; //!< Interrupt Group Registers. + uint32_t _reserved1[24]; + uint32_t ISENABLERn[32]; //!< Interrupt Set-Enable Registers. + uint32_t ICENABLERn[32]; //!< Interrupt Clear-Enable Registers. + uint32_t ISPENDRn[32]; //!< Interrupt Set-Pending Registers. + uint32_t ICPENDRn[32]; //!< Interrupt Clear-Pending Registers. + uint32_t ICDABRn[32]; //!< Active Bit Registers. + uint32_t _reserved2[32]; + uint8_t IPRIORITYRn[255 * sizeof(uint32_t)]; //!< Interrupt Priority Registers. (Byte accessible) + uint32_t _reserved3; + uint8_t ITARGETSRn[255 * sizeof(uint32_t)]; //!< Interrupt Processor Targets Registers. (Byte accessible) + uint32_t _reserved4; + uint32_t ICFGRn[64]; //!< Interrupt Configuration Registers. + uint32_t _reserved5[128]; + uint32_t SGIR; //!< Software Generated Interrupt Register +}; +typedef volatile struct _gicd_registers gicd_t; + +enum _gicd_sgir_fields { + kBP_GICD_SGIR_TargetListFilter = 24, + kBM_GICD_SGIR_TargetListFilter = (0x3 << kBP_GICD_SGIR_TargetListFilter), + + kBP_GICD_SGIR_CPUTargetList = 16, + kBM_GICD_SGIR_CPUTargetList = (0xff << kBP_GICD_SGIR_CPUTargetList), + + kBP_GICD_SGIR_NSATT = 15, + kBM_GICD_SGIR_NSATT = (1 << kBP_GICD_SGIR_NSATT), + + kBP_GICD_SGIR_SGIINTID = 0, + kBM_GICD_SGIR_SGIINTID = 0xf +}; + +void gic_send_sgi(uint32_t irqID, uint32_t target_list, uint32_t filter_list) +{ + gicd_t* gicd = (gicd_t*)(ARM_PERIPHERAL_VIRT_BASE + MX6Q_GICD_BASE_OFFSET); + gicd->SGIR = (filter_list << kBP_GICD_SGIR_TargetListFilter) // + | (target_list << kBP_GICD_SGIR_CPUTargetList) // + | (irqID & 0xf); +} + +int main() +{ + static char prog_name[] = "TEST_IRQ_SEND"; + printf("%s: Mapping GIC\n", prog_name); + mmap(ARM_PERIPHERAL_VIRT_BASE, ARM_PERIPHERAL_BASE, 0x2000, true); + + // int send_time = 1000; + int send_time = 1; + printf("%s: Sending soft interrupt for %d times\n", prog_name, send_time); + for (int i = 0; i < send_time; i++) { + gic_send_sgi(SW_INTERRUPT_3, 0xF, kGicSgiFilter_UseTargetList); + printf("%s: Soft interrupt send 1 time\n", prog_name); + } + printf("%s: Soft interrupt send done\n", prog_name); + exit(); +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/usyscall.c b/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/usyscall.c deleted file mode 100644 index 86a92e24e..000000000 --- a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/usyscall.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2020 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ -#include "usyscall.h" -#include "libmem.h" - -static int -syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4) -{ - int ret = -1; - - __asm__ volatile( - "mov r0, %1;\ - mov r1, %2;\ - mov r2, %3;\ - mov r3, %4;\ - mov r4, %5;\ - swi 0;\ - dsb;\ - isb;\ - mov %0, r0" - : "=r"(ret) - : "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4) - : "memory", "r0", "r1", "r2", "r3", "r4"); - - return ret; -} - -int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv) -{ - int file_size = ipc_fsize(session, fd); - void* img = malloc(file_size); - int read_len = 0, cur_read_len = 0; - while (read_len < file_size) { - cur_read_len = file_size - read_len < 4096 ? file_size - read_len : 4096; - read_len += ipc_read(session, fd, img + read_len, read_len, cur_read_len); - } - int ret = syscall(SYSCALL_SPAWN, (intptr_t)img, (intptr_t)name, (intptr_t)argv, 0); - free(img); - return ret; -} - -int exit() -{ - return syscall(SYSCALL_EXIT, 0, 0, 0, 0); -} - -int yield() -{ - return syscall(SYSCALL_YIELD, 0, 0, 0, 0); -} - -int kill(int pid) -{ - return syscall(SYSCALL_KILL, (intptr_t)pid, 0, 0, 0); -} - -int register_server(char* name) -{ - return syscall(SYSCALL_SERVER, (intptr_t)name, 0, 0, 0); -} - -int session(char* path, int capacity, struct Session* user_session) -{ - return syscall(SYSCALL_SESSION, (intptr_t)path, (intptr_t)capacity, (intptr_t)user_session, 0); -} - -int poll_session(struct Session* userland_session_arr, int arr_capacity) -{ - return syscall(SYSCALL_POLL_SESSION, (intptr_t)userland_session_arr, (intptr_t)arr_capacity, 0, 0); -} - -int close_session(struct Session* session) -{ - return syscall(SYSCALL_CLOSE_SESSION, (intptr_t)session, 0, 0, 0); -} - -int get_memblock_info(sys_state_info* info) -{ - return syscall(SYSCALL_SYS_STATE, SYS_STATE_MEMBLOCK_INFO, (intptr_t)info, 0, 0); -} - -int set_priority(sys_state_info* info) -{ - return syscall(SYSCALL_SYS_STATE, SYS_STATE_SET_TASK_PRIORITY, (intptr_t)info, 0, 0); -} - -int task_heap_base() -{ - return syscall(SYSCALL_SYS_STATE, SYS_STATE_GET_HEAP_BASE, 0, 0, 0); -} - -int show_task() -{ - return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_TASKS, 0, 0, 0); -} - -int show_mem() -{ - return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_MEM_INFO, 0, 0, 0); -} - -int show_cpu() -{ - return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_CPU_INFO, 0, 0, 0); -} - -int mmap(uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev) -{ - return syscall(SYSCALL_MMAP, vaddr, paddr, (intptr_t)len, (intptr_t)is_dev); -} - -int register_irq(int irq, int opcode) -{ - return syscall(SYSCALL_REGISTER_IRQ, (intptr_t)irq, (intptr_t)opcode, 0, 0); -} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/Makefile b/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/Makefile index aa1013cfa..b5ada4070 100644 --- a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/Makefile @@ -19,10 +19,12 @@ INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \ -I$(KERNEL_ROOT)/services/fs/fs_server/include \ -I$(KERNEL_ROOT)/services/lib/ipc \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ -I$(KERNEL_ROOT)/services/app -board: libserial.o stub.o usyscall.o +board: libserial.o stub.o arch_usyscall.o @mv $^ ../../app %.o: %.c diff --git a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/arch_usyscall.c b/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/arch_usyscall.c new file mode 100644 index 000000000..b3c79aafc --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/arch_usyscall.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "usyscall.h" + +int syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4) +{ + int ret = -1; + + __asm__ volatile( + "mov r0, %1;\ + mov r1, %2;\ + mov r2, %3;\ + mov r3, %4;\ + mov r4, %5;\ + swi 0;\ + dsb;\ + isb;\ + mov %0, r0" + : "=r"(ret) + : "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4) + : "memory", "r0", "r1", "r2", "r3", "r4"); + + return ret; +} diff --git a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/usyscall.h b/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/usyscall.h deleted file mode 100644 index 326739a37..000000000 --- a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/usyscall.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2020 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ -#pragma once -#include - -#include "libserial.h" -#include "session.h" - -// clang-format off -#define SYSCALL_TEST 0 -#define SYSCALL_SPAWN 1 // generate a brand new task to run elf -#define SYSCALL_EXIT 2 // exit task, delete the task cb -#define SYSCALL_YIELD 3 // yield task, go to scheduler - -#define SYSCALL_MMAP 4 // map a virt page to phy page -#define SYSCALL_SERVER 5 // register current task as a server -#define SYSCALL_SESSION 6 // create a session to a server -#define SYSCALL_POLL_SESSION 7 // server poll for it's server sessions -#define SYSCALL_CLOSE_SESSION 8 // client close it's client sessions - -#define SYSCALL_EXEC 9 // run elf using current task -#define SYSCALL_SYS_STATE 10 // run system state -#define SYSCALL_REGISTER_IRQ 11 // - -#define SYSCALL_KILL 12 // kill the task by id -// clang-format on - -typedef enum { - SYS_STATE_TEST = 0, - SYS_STATE_SET_TASK_PRIORITY, - SYS_STATE_GET_HEAP_BASE, - SYS_STATE_MEMBLOCK_INFO, - SYS_STATE_SHOW_TASKS, - SYS_STATE_SHOW_MEM_INFO, - SYS_STATE_SHOW_CPU_INFO, -} sys_state_option; - -typedef union { - struct { - uintptr_t memblock_start; - uintptr_t memblock_end; - } memblock_info; - int priority; -} sys_state_info; - -typedef int (*ipc_read_fn)(struct Session* session, int fd, char* dst, int offset, int len); -typedef int (*ipc_fsize_fn)(struct Session* session, int fd); -typedef int (*ipc_write_fn)(struct Session* session, int fd, char* src, int offset, int len); - -int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv); -int exit(); -int yield(); -int kill(int pid); -int register_server(char* name); -int session(char* path, int capacity, struct Session* user_session); -int poll_session(struct Session* userland_session_arr, int arr_capacity); -int close_session(struct Session* session); -int task_heap_base(); -int get_memblock_info(sys_state_info* info); -int set_priority(sys_state_info* info); -int show_task(); -int show_mem(); -int show_cpu(); -int mmap(uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev); -int register_irq(int irq, int opcode); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/fs/fs_server/Makefile b/Ubiquitous/XiZi_AIoT/services/fs/fs_server/Makefile index e93df4cb0..5b550eb1a 100644 --- a/Ubiquitous/XiZi_AIoT/services/fs/fs_server/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/fs/fs_server/Makefile @@ -19,6 +19,8 @@ INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \ -I$(KERNEL_ROOT)/services/fs/fs_server/include \ -I$(KERNEL_ROOT)/services/lib/ipc \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ -I$(KERNEL_ROOT)/services/app diff --git a/Ubiquitous/XiZi_AIoT/services/fs/fs_server/include/fs.h b/Ubiquitous/XiZi_AIoT/services/fs/fs_server/include/fs.h index 42a3d7ffd..72911f2d2 100644 --- a/Ubiquitous/XiZi_AIoT/services/fs/fs_server/include/fs.h +++ b/Ubiquitous/XiZi_AIoT/services/fs/fs_server/include/fs.h @@ -88,7 +88,7 @@ struct Inode { }; // directory entry -#define DIR_NAME_SIZE 14 +#define DIR_NAME_SIZE 30 struct DirectEntry { uint16_t inum; char name[DIR_NAME_SIZE]; diff --git a/Ubiquitous/XiZi_AIoT/services/fs/libfs/Makefile b/Ubiquitous/XiZi_AIoT/services/fs/libfs/Makefile index 336120483..46aad9a4c 100644 --- a/Ubiquitous/XiZi_AIoT/services/fs/libfs/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/fs/libfs/Makefile @@ -18,6 +18,8 @@ c_useropts = -O0 INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \ -I$(KERNEL_ROOT)/services/lib/ipc \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ -I$(KERNEL_ROOT)/services/app diff --git a/Ubiquitous/XiZi_AIoT/services/lib/Makefile b/Ubiquitous/XiZi_AIoT/services/lib/Makefile index c242de34a..db124194e 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/lib/Makefile @@ -1,4 +1,4 @@ -SRC_DIR := ipc memory +SRC_DIR := ipc memory usyscall include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/Makefile b/Ubiquitous/XiZi_AIoT/services/lib/ipc/Makefile index 48b6ef330..0ecba7c2e 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/Makefile @@ -17,6 +17,8 @@ c_useropts = -O0 INC_DIR = -I$(KERNEL_ROOT)/services/lib/ipc \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ -I$(KERNEL_ROOT)/services/app diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c index 0d9582aae..7c3e22302 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.c @@ -121,7 +121,7 @@ void ipc_msg_send_wait(struct IpcMsg* msg) msg->header.done = 0; while (msg->header.done == 0) { /// @todo syscall yield with prio decrease - yield(); + yield(SYS_TASK_YIELD_BLOCK_IPC); } assert(msg->header.done == 1); } @@ -138,7 +138,7 @@ int ipc_session_wait(struct Session* session) struct IpcMsg* msg = IPCSESSION_MSG(session); while (msg->header.done == 0) { /// @todo syscall yield with prio decrease - yield(); + yield(SYS_TASK_YIELD_BLOCK_IPC); } assert(msg->header.done == 1); return msg->header.ret_val; @@ -156,9 +156,15 @@ void delay_session(void) session_delayed = true; } +bool is_cur_session_delayed(void) +{ + return session_delayed; +} + void ipc_server_loop(struct IpcNode* ipc_node) { struct Session session_list[NR_MAX_SESSION]; + memset(session_list, 0, sizeof(session_list)); for (;;) { /* if connect sessions are greater than NR_MAX_SESSION, a full round will require multiple polls. @@ -167,40 +173,49 @@ void ipc_server_loop(struct IpcNode* ipc_node) */ poll_session(session_list, NR_MAX_SESSION); /* handle each session */ - for (int i = 0; i < NR_MAX_SESSION; i++) { - if (session_list[i].buf == NULL) { - yield(); - break; - } - cur_sess_id = session_list[i].id; - struct IpcMsg* msg = IPCSESSION_MSG(&session_list[i]); - /* handle every message in current session - a session could be delay in case one of its message(current message) needs to wait for an interrupt message's arrival - interfaces[opcode] should explicitly call delay_session() and return to delay this session - */ - while (msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done != 1) { - // printf("session %d [%d, %d]\n", session_list[i].id, session_list[i].head, session_list[i].tail); - if (session_used_size(&session_list[i]) == 0 && session_forward_tail(&session_list[i], msg->header.len) < 0) { + bool has_delayed = true; + for (int repeat = 0; repeat <= 1 && has_delayed; repeat++) { + has_delayed = false; + for (int i = 0; i < NR_MAX_SESSION; i++) { + session_delayed = false; + if (session_list[i].buf == NULL) { + yield(SYS_TASK_YIELD_NO_REASON); break; } - if (ipc_node->interfaces[msg->header.opcode]) { - ipc_node->interfaces[msg->header.opcode](msg); - // check if this session is delayed by op handler, all messages after the delayed message in current session is blocked. - if (session_delayed) { - session_delayed = false; + cur_sess_id = session_list[i].id; + struct IpcMsg* msg = IPCSESSION_MSG(&session_list[i]); + /* handle every message in current session + a session could be delay in case one of its message(current message) needs to wait for an interrupt message's arrival + interfaces[opcode] should explicitly call delay_session() and return to delay this session + */ + while (msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done == 0) { + // printf("session %d [%d, %d]\n", session_list[i].id, session_list[i].head, session_list[i].tail); + if (session_used_size(&session_list[i]) == 0 && session_forward_tail(&session_list[i], msg->header.len) < 0) { break; } - } else { - printf("Unsupport opcode(%d) for server: %s\n", msg->header.opcode, ipc_node->name); + + // this is a message needs to handle + if (ipc_node->interfaces[msg->header.opcode]) { + ipc_node->interfaces[msg->header.opcode](msg); + // check if this session is delayed by op handler, all messages after the delayed message in current session is blocked. + if (is_cur_session_delayed()) { + msg->header.delayed = 1; + has_delayed = true; + break; + } + } else { + printf("Unsupport opcode(%d) for server: %s\n", msg->header.opcode, ipc_node->name); + } + // current msg is a message that needs to ignore + // finish this message in server's perspective + if (session_forward_head(&session_list[i], msg->header.len) < 0) { + break; + } + msg = IPCSESSION_MSG(&session_list[i]); } - // finish this message in server's perspective - while (session_forward_head(&session_list[i], msg->header.len) < 0) { - yield(); - } - msg = IPCSESSION_MSG(&session_list[i]); + // stop handle this session + cur_sess_id = -1; } - // stop handle this session - cur_sess_id = -1; } } } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h index 86148a9a6..cee3c0343 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/libipc.h @@ -37,7 +37,7 @@ Modification: #include "ipcargs.h" #include "session.h" -#define NR_MAX_SESSION 16 +#define NR_MAX_SESSION 32 #define IPC_MSG_MAGIC 0xABCDDCBA typedef struct { @@ -47,7 +47,7 @@ typedef struct { uint64_t valid : 1; // for server to peek new msg uint64_t done : 1; // for client to check request done uint64_t init : 1; // for client to check request done - uint64_t reserved : 1; + uint64_t delayed : 1; uint64_t nr_args : 4; uint64_t opcode : 8; uint64_t len : 16; @@ -225,6 +225,7 @@ void ipc_server_loop(struct IpcNode* ipc_node); return res; \ } +bool is_cur_session_delayed(void); #define IPC_SERVER_INTERFACE(ipc_name, argc) \ static int IPC_SERVE(ipc_name)(struct IpcMsg * msg) \ { \ @@ -233,8 +234,10 @@ void ipc_server_loop(struct IpcNode* ipc_node); argv[i] = ipc_msg_get_nth_arg_buf(msg, i); \ } \ int32_t _ret = IPC_DO_SERVE##argc(ipc_name); \ - ipc_msg_set_return(msg, &_ret); \ - msg->header.done = 1; \ + if (!is_cur_session_delayed()) { \ + ipc_msg_set_return(msg, &_ret); \ + msg->header.done = 1; \ + } \ return 0; \ } diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.c b/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.c index 27e88c706..a399dec18 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.c +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.c @@ -61,6 +61,6 @@ bool session_free_buf(struct Session* session, int len) if (len > session_used_size(session)) { return false; } - assert(session_forward_head(session, len) != 1); + assert(session_forward_head(session, len) != -1); return true; } diff --git a/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h b/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h index 24952db0c..196c6bf5b 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h +++ b/Ubiquitous/XiZi_AIoT/services/lib/ipc/session.h @@ -55,8 +55,8 @@ __attribute__((__always_inline__)) static inline int session_remain_capacity(str __attribute__((__always_inline__)) static inline int session_forward_head(struct Session* session, int len) { - if (((session->head + len) % session->capacity) > session->tail) { - printf("forward head with too much size\n"); + if (len > session_used_size(session)) { + printf("forward head with too much size, session used size: %d\n", session_used_size(session)); return -1; } session->head = (session->head + len) % session->capacity; diff --git a/Ubiquitous/XiZi_AIoT/services/lib/memory/Makefile b/Ubiquitous/XiZi_AIoT/services/lib/memory/Makefile index 54139e413..ceaccc4ca 100644 --- a/Ubiquitous/XiZi_AIoT/services/lib/memory/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/lib/memory/Makefile @@ -16,6 +16,8 @@ INC_DIR = -I$(KERNEL_ROOT)/services/app \ -I$(KERNEL_ROOT)/services/fs/libfs \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/lib/ipc all: libmem.o diff --git a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/libserial.h b/Ubiquitous/XiZi_AIoT/services/lib/serial/libserial.h similarity index 100% rename from Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/libserial.h rename to Ubiquitous/XiZi_AIoT/services/lib/serial/libserial.h diff --git a/Ubiquitous/XiZi_AIoT/services/lib/usyscall/Makefile b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/Makefile new file mode 100644 index 000000000..d8e0c7ab5 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/Makefile @@ -0,0 +1,28 @@ +ifeq ($(BOARD), imx6q-sabrelite) +toolchain ?= arm-none-eabi- +endif +ifeq ($(BOARD), zynq7000-zc702) +toolchain ?= arm-xilinx-eabi- +endif +cc = ${toolchain}gcc +ld = ${toolchain}g++ +objdump = ${toolchain}objdump +user_ldflags = -N -Ttext 0 + +cflags = -std=c11 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie +c_useropts = -O0 + +INC_DIR = -I$(KERNEL_ROOT)/services/app \ + -I$(KERNEL_ROOT)/services/fs/libfs \ + -I$(KERNEL_ROOT)/services/boards/$(BOARD) \ + -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ + -I$(KERNEL_ROOT)/services/lib/ipc + +all: usyscall.o + @mv $^ ../../app + +%.o: %.c + @echo "cc $^" + @${cc} ${cflags} ${c_useropts} ${INC_DIR} -o $@ -c $^ \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/usyscall.c b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.c similarity index 84% rename from Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/usyscall.c rename to Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.c index 86a92e24e..8570c0f98 100644 --- a/Ubiquitous/XiZi_AIoT/services/boards/zynq7000-zc702/usyscall.c +++ b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.c @@ -12,28 +12,6 @@ #include "usyscall.h" #include "libmem.h" -static int -syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4) -{ - int ret = -1; - - __asm__ volatile( - "mov r0, %1;\ - mov r1, %2;\ - mov r2, %3;\ - mov r3, %4;\ - mov r4, %5;\ - swi 0;\ - dsb;\ - isb;\ - mov %0, r0" - : "=r"(ret) - : "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4) - : "memory", "r0", "r1", "r2", "r3", "r4"); - - return ret; -} - int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv) { int file_size = ipc_fsize(session, fd); @@ -53,9 +31,9 @@ int exit() return syscall(SYSCALL_EXIT, 0, 0, 0, 0); } -int yield() +int yield(task_yield_reason reason) { - return syscall(SYSCALL_YIELD, 0, 0, 0, 0); + return syscall(SYSCALL_YIELD, (uintptr_t)reason, 0, 0, 0); } int kill(int pid) diff --git a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/usyscall.h b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h similarity index 91% rename from Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/usyscall.h rename to Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h index 326739a37..822831942 100644 --- a/Ubiquitous/XiZi_AIoT/services/boards/imx6q-sabrelite/usyscall.h +++ b/Ubiquitous/XiZi_AIoT/services/lib/usyscall/usyscall.h @@ -44,6 +44,12 @@ typedef enum { SYS_STATE_SHOW_CPU_INFO, } sys_state_option; +typedef enum { + SYS_TASK_YIELD_NO_REASON = 0x0, + SYS_TASK_YIELD_FOREVER = 0x1, + SYS_TASK_YIELD_BLOCK_IPC = 0x2, +} task_yield_reason; + typedef union { struct { uintptr_t memblock_start; @@ -56,9 +62,11 @@ typedef int (*ipc_read_fn)(struct Session* session, int fd, char* dst, int offse typedef int (*ipc_fsize_fn)(struct Session* session, int fd); typedef int (*ipc_write_fn)(struct Session* session, int fd, char* src, int offset, int len); +int syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4); + int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv); int exit(); -int yield(); +int yield(task_yield_reason reason); int kill(int pid); int register_server(char* name); int session(char* path, int capacity, struct Session* user_session); diff --git a/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/Makefile b/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/Makefile index e2bdb095e..3caddc340 100644 --- a/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/Makefile +++ b/Ubiquitous/XiZi_AIoT/services/shell/letter-shell/Makefile @@ -18,6 +18,8 @@ c_useropts = -O0 INC_DIR = -I$(KERNEL_ROOT)/services/app \ -I$(KERNEL_ROOT)/services/fs/libfs \ -I$(KERNEL_ROOT)/services/lib/memory \ + -I$(KERNEL_ROOT)/services/lib/serial \ + -I$(KERNEL_ROOT)/services/lib/usyscall \ -I$(KERNEL_ROOT)/services/lib/ipc \ -I$(KERNEL_ROOT)/services/boards/$(BOARD) diff --git a/Ubiquitous/XiZi_AIoT/services/tools/mkfs/mkfs.h b/Ubiquitous/XiZi_AIoT/services/tools/mkfs/mkfs.h index 328f7f086..a61af5517 100755 --- a/Ubiquitous/XiZi_AIoT/services/tools/mkfs/mkfs.h +++ b/Ubiquitous/XiZi_AIoT/services/tools/mkfs/mkfs.h @@ -80,7 +80,7 @@ struct Inode { }; // Directory is a file containing a sequence of DirEntry structures. -#define DIR_NAME_SIZE 14 +#define DIR_NAME_SIZE 30 struct DirEntry { ushort inum; char name[DIR_NAME_SIZE]; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h b/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h index 6c890c840..d8a0354ca 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/buddy.h @@ -68,7 +68,6 @@ struct KFreeList { struct double_list_node list_head; }; -#define MAX_NR_PAGES MAX_NR_FREE_PAGES struct KBuddy { uint32_t n_pages; uint32_t use_lock; @@ -77,7 +76,7 @@ struct KBuddy { struct KPage* first_page; uint32_t mem_start; uint32_t mem_end; - struct KPage pages[MAX_NR_PAGES]; + struct KPage* pages; }; /********************************************* @@ -89,6 +88,7 @@ struct KBuddy { * @param mem_end free memory region end * @return void */ +bool KBuddyInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end); void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end); /* @@ -105,6 +105,8 @@ char* KBuddyAlloc(struct KBuddy* pbuddy, uint32_t size); */ bool KBuddyFree(struct KBuddy* pbuddy, char* vaddr); +void KBuddyDestory(struct KBuddy* pbuddy); + /* * Print current free pages for debug. */ diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/ipc.h b/Ubiquitous/XiZi_AIoT/softkernel/include/ipc.h index 924ded3d5..775ee2bcb 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/ipc.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/ipc.h @@ -41,7 +41,7 @@ typedef struct { uint64_t valid : 1; // for server to peek new msg uint64_t done : 1; // for client to check request done uint64_t init : 1; // for client to check request done - uint64_t reserved : 1; + uint64_t delayed : 1; uint64_t nr_args : 4; uint64_t opcode : 8; uint64_t len : 16; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/log.h b/Ubiquitous/XiZi_AIoT/softkernel/include/log.h index 22640817c..a56c0e84c 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/log.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/log.h @@ -29,13 +29,14 @@ Modification: *************************************************/ #pragma once +#include "uart_common_ope.h" + #define OUTPUT_LEVLE_LOG 0 #define OUTPUT_LEVLE_DEBUG 1 #define OUTPUT_LEVLE_ERROR 2 #define OUTPUT_LEVLE OUTPUT_LEVLE_DEBUG - -extern void KPrintf(char* fmt, ...); +// #define OUTPUT_LEVLE OUTPUT_LEVLE_LOG #if (OUTPUT_LEVLE >= OUTPUT_LEVLE_LOG) #define LOG_PRINTF(f, args...) \ diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/multicores.h b/Ubiquitous/XiZi_AIoT/softkernel/include/multicores.h index fad604925..2bf28ceb0 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/multicores.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/multicores.h @@ -47,4 +47,9 @@ static inline struct CPU* cur_cpu(void) return &global_cpus[cur_cpuid()]; } -struct spinlock whole_kernel_lock; \ No newline at end of file +extern struct spinlock whole_kernel_lock; + +void xizi_enter_kernel(); +bool xizi_try_enter_kernel(); +void xizi_leave_kernel(); +bool xizi_is_in_kernel(); \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/pagetable.h b/Ubiquitous/XiZi_AIoT/softkernel/include/pagetable.h index 691430773..0668ad5ae 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/pagetable.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/pagetable.h @@ -69,6 +69,7 @@ struct XiziPageManager { extern struct MmuCommonDone* _p_pgtbl_mmu_access; uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc); +void _free_user_pgdir(struct TopLevelPageDirectory* pgdir); extern struct TopLevelPageDirectory kern_pgdir; void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h b/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h index aa78cbf39..4e99da1a8 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/syscall.h @@ -64,6 +64,12 @@ typedef enum { SYS_STATE_SHOW_CPU_INFO, } sys_state_option; +typedef enum { + SYS_TASK_YIELD_NO_REASON = 0x0, + SYS_TASK_YIELD_FOREVER = 0x1, + SYS_TASK_YIELD_BLOCK_IPC = 0x2, +} task_yield_reason; + typedef union { struct { uintptr_t memblock_start; @@ -80,17 +86,19 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u int sys_spawn(char* img_start, char* name, char** argv); int sys_exit(struct TaskMicroDescriptor* ptask); -int sys_yield(); +int sys_yield(task_yield_reason reason); int sys_kill(int id); int sys_register_as_server(char* name); int sys_connect_session(char* path, int capacity, struct Session* user_session); int sys_poll_session(struct Session* userland_session_arr, int arr_capacity); -int sys_close_session(struct Session* session); +int sys_close_session(struct TaskMicroDescriptor* task, struct Session* session); int sys_exec(char* img_start, char* name, char** argv); int sys_state(sys_state_option option, sys_state_info* info); int sys_mmap(uintptr_t vaddr, uintptr_t paddr, int len, int is_dev); int sys_register_irq(int irq_num, int irq_opcode); +int sys_unbind_irq_all(struct TaskMicroDescriptor* task); +int sys_unbind_irq(struct TaskMicroDescriptor* task, int irq_num); #endif diff --git a/Ubiquitous/XiZi_AIoT/softkernel/include/task.h b/Ubiquitous/XiZi_AIoT/softkernel/include/task.h index adc872da6..ff48dbc83 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/include/task.h +++ b/Ubiquitous/XiZi_AIoT/softkernel/include/task.h @@ -31,6 +31,7 @@ Modification: #include "core.h" +#include "buddy.h" #include "list.h" #include "object_allocator.h" #include "pagetable.h" @@ -47,6 +48,8 @@ enum ProcState { READY, RUNNING, DEAD, + BLOCKED, + NEVER_RUN, }; /* Thread Control Block */ @@ -59,33 +62,39 @@ struct Thread { /* Process Control Block */ struct TaskMicroDescriptor { - struct double_list_node node; - - struct spinlock lock; - /* task->lock needed */ + /* task debug resources */ int pid; + bool bind_irq; + bool dead; + char name[TASK_NAME_MAX_LEN]; + + /// @todo support return value + int ret; // state val that be returned to parent /// @todo support parent struct TaskMicroDescriptor* parent; - enum ProcState state; - /// @todo support ret value - int ret; // state val that be returned to parent + + /* task context resources */ + struct Thread main_thread; // will only access by task itself + + /* task memory resources */ struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address + uintptr_t heap_base; // mem size of proc used(allocated by kernel) + /// @todo support heap_base + uintptr_t mem_size; + + /* task communication resources */ struct double_list_node cli_sess_listhead; struct double_list_node svr_sess_listhead; + bool current_ipc_handled; + struct KBuddy* massive_ipc_allocator; struct TraceTag server_identifier; - /* task->lock not necessary */ - struct Thread main_thread; // will only access by task itself + /* task schedule attributes */ + struct double_list_node node; + enum ProcState state; + int priority; // priority int remain_tick; int maxium_tick; - - struct TraceTag cwd; // current directory - - int priority; // priority - - /// @todo support mem_size - uintptr_t mem_size; // mem size of proc used(allocated by kernel) - char name[TASK_NAME_MAX_LEN]; }; struct SchedulerRightGroup { @@ -94,17 +103,13 @@ struct SchedulerRightGroup { }; struct XiziTaskManager { - struct spinlock lock; // lock to organize free and used task list struct double_list_node task_list_head[TASK_MAX_PRIORITY]; /* list of task control blocks that are allocated */ - int nr_pcb_used; // for debug + struct double_list_node task_running_list_head; + struct double_list_node task_blocked_list_head; struct slab_allocator task_allocator; - - /// @todo Add pid to task + struct slab_allocator task_buddy_allocator; uint32_t next_pid; - /* number of tcbs in which one page contains */ - int nr_tcb_per_page; - /* init task manager */ void (*init)(); /* new a task control block, checkout #sys_spawn for usage */ @@ -112,14 +117,19 @@ struct XiziTaskManager { /* free a task control block, this calls #free_user_pgdir to free all vitual spaces */ void (*free_pcb)(struct TaskMicroDescriptor*); /* init a task control block, set name, remain_tick, state, cwd, priority, etc. */ - void (*task_set_default_schedule_attr)(struct TaskMicroDescriptor*, struct TraceTag* cwd); + void (*task_set_default_schedule_attr)(struct TaskMicroDescriptor*); /* use by task_scheduler, find next READY task, should be in locked */ struct TaskMicroDescriptor* (*next_runnable_task)(void); /* function that's runing by kernel thread context, schedule use tasks */ void (*task_scheduler)(struct SchedulerRightGroup); + + /* handle task state */ /* call to yield current use task */ - void (*cur_task_yield_noschedule)(void); + void (*task_yield_noschedule)(struct TaskMicroDescriptor* task, bool is_blocking); + /* block and unblock task */ + void (*task_block)(struct TaskMicroDescriptor* task); + void (*task_unblock)(struct TaskMicroDescriptor* task); /* set task priority */ void (*set_cur_task_priority)(int priority); }; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/main.c b/Ubiquitous/XiZi_AIoT/softkernel/main.c index 5bf2df67a..a3512a53a 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/main.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/main.c @@ -35,24 +35,25 @@ Modification: #include "assert.h" #include "task.h" -extern uint32_t _binary_init_start[], _binary_default_fs_start[]; -static struct TraceTag hardkernel_tag, softkernel_tag; +struct spinlock whole_kernel_lock; -static int core_init_done = 0; -int main(void) +extern uint32_t _binary_init_start[], _binary_default_fs_start[]; +extern int sys_spawn(char* img_start, char* name, char** argv); + +static struct TraceTag hardkernel_tag, softkernel_tag; +static volatile int core_init_done = 0; +__attribute__((optimize("O0"))) int main(void) { /* init tracer */ uint32_t cpu_id = cur_cpuid(); if (cpu_id == 0) { tracer_init(); // init tracer system - // clang-format off - if (!CreateResourceTag(&hardkernel_tag, RequireRootTag(), "hardkernel", TRACER_OWNER, NULL) || + if (!CreateResourceTag(&hardkernel_tag, RequireRootTag(), "hardkernel", TRACER_OWNER, NULL) || // !CreateResourceTag(&softkernel_tag, RequireRootTag(), "softkernel", TRACER_OWNER, NULL)) { ERROR("Failed to create hardkernel owner and softkernel owner.\n"); return -1; } - // clang-format on /* init hardkernel */ if (!hardkernel_init(&hardkernel_tag)) { return -1; @@ -80,23 +81,24 @@ int main(void) /* start first task */ char* init_task_param[2] = { "/app/init", 0 }; - spawn_embedded_task((char*)_binary_init_start, "init", init_task_param); + sys_spawn((char*)_binary_init_start, "init", init_task_param); char* fs_server_task_param[2] = { "/app/fs_server", 0 }; - spawn_embedded_task((char*)_binary_default_fs_start, "memfs", fs_server_task_param); + sys_spawn((char*)_binary_default_fs_start, "memfs", fs_server_task_param); } /* start scheduler */ struct SchedulerRightGroup scheduler_rights; assert(AchieveResourceTag(&scheduler_rights.mmu_driver_tag, &hardkernel_tag, "mmu-ac-resource")); assert(AchieveResourceTag(&scheduler_rights.intr_driver_tag, &hardkernel_tag, "intr-ac-resource")); - core_init_done |= (1 << cpu_id); LOG_PRINTF("CPU %d init done\n", cpu_id); spinlock_unlock(&whole_kernel_lock); - while (core_init_done != (1 << NR_CPU) - 1) - ; + // sync memory + __sync_synchronize(); start_smp_cache_broadcast(cpu_id); + // enter kernel seriously + xizi_enter_kernel(); xizi_task_manager.task_scheduler(scheduler_rights); // never reached diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c index 7b263a625..702c0409e 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/buddy.c @@ -29,6 +29,7 @@ Modification: *************************************************/ #include "buddy.h" +#include "kalloc.h" #include "log.h" static void _buddy_split_page(struct KPage* page, uint32_t low_order, uint32_t high_order, struct KFreeList* list) @@ -138,8 +139,15 @@ static void KBuddyPagesFree(struct KBuddy* pbuddy, struct KPage* page) return; } -void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end) +bool KBuddyInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end) { + if (pbuddy->pages == NULL) { + if ((pbuddy->pages = (struct KPage*)kalloc(((mem_end - mem_start) >> LEVEL4_PTE_SHIFT) * sizeof(struct KPage))) == NULL) { + ERROR("Not space to init a buddy object.\n"); + return false; + } + } + uint32_t i = 0; struct KPage* page = NULL; struct KFreeList* free_list = NULL; @@ -173,6 +181,16 @@ void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end) doubleListNodeInit(&page->node); KBuddyPagesFree(pbuddy, page); } + + return true; +} + +void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end) +{ +#define MAX_NR_PAGES MAX_NR_FREE_PAGES + static struct KPage kern_free_pages[MAX_NR_PAGES]; + pbuddy->pages = kern_free_pages; + KBuddyInit(pbuddy, mem_start, mem_end); } char* KBuddyAlloc(struct KBuddy* pbuddy, uint32_t size) @@ -211,6 +229,13 @@ bool KBuddyFree(struct KBuddy* pbuddy, char* vaddr) return true; } +void KBuddyDestory(struct KBuddy* pbuddy) +{ + if (pbuddy->pages) { + kfree((void*)pbuddy->pages); + } +} + void KFreePagesInfo(struct KBuddy* pbuddy) { DEBUG("Buddy structure:"); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c index 9ce64eaa3..1d7f272bc 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/kalloc.c @@ -45,7 +45,7 @@ bool module_phymem_init() uint32_t user_freemem_start = PHY_USER_FREEMEM_BASE; uint32_t user_freemem_end = PHY_MEM_STOP; KBuddySysInit(&kern_virtmem_buddy, kern_freemem_start, kern_freemem_end); - KBuddySysInit(&user_phy_freemem_buddy, user_freemem_start, user_freemem_end); + KBuddyInit(&user_phy_freemem_buddy, user_freemem_start, user_freemem_end); LOG_PRINTF("Free memory organized done.\n"); return true; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c index 75d33414d..360803c77 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/object_allocator.c @@ -84,9 +84,14 @@ void* slab_alloc(struct slab_allocator* const allocator) allocator->full->prev = full_head; } allocator->full = full_head; - return allocator->full->data + slot * allocator->element_size; + + void* return_addr = allocator->full->data + slot * allocator->element_size; + memset(return_addr, 0, allocator->element_size); + return return_addr; } else { - return allocator->partial->data + slot * allocator->element_size; + void* return_addr = allocator->partial->data + slot * allocator->element_size; + memset(return_addr, 0, allocator->element_size); + return return_addr; } } @@ -109,6 +114,8 @@ void* slab_alloc(struct slab_allocator* const allocator) allocator->partial->refcount = 1; } allocator->partial->bitmap = allocator->bitmap_empty ^ BITMAP_FIRST_BIT; + assert(allocator->partial->data != NULL); + memset(allocator->partial->data, 0, allocator->element_size); return allocator->partial->data; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c index a2a054119..f5d08dfe5 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable.c @@ -62,7 +62,8 @@ static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, uintp uintptr_t* pte; while (true) { - if ((pte = _page_walk(pgdir, vaddr, true)) == 0) { + if ((pte = _page_walk(pgdir, vaddr, true)) == NULL) { + ERROR("pte not found for vaddr %x.\n", vaddr); return false; } @@ -81,6 +82,7 @@ static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, uintp paddr += PAGE_SIZE; } + assert(vaddr == vaddr_last); return true; } @@ -94,7 +96,8 @@ static bool _unmap_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t len) uintptr_t* pte; while (true) { - if ((pte = _page_walk(pgdir, vaddr, true)) == 0) { + if ((pte = _page_walk(pgdir, vaddr, false)) == NULL) { + ERROR("pte not found for vaddr %x.\n", vaddr); return false; } @@ -112,6 +115,7 @@ static bool _unmap_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t len) vaddr += PAGE_SIZE; } + assert(vaddr == vaddr_last); return true; } @@ -140,33 +144,6 @@ static bool _map_user_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, return _map_pages(pgdir, vaddr, paddr, len, mem_attr); } -static void _free_user_pgdir(struct TopLevelPageDirectory* pgdir) -{ - uintptr_t low_bound = kern_virtmem_buddy.mem_start, high_bound = kern_virtmem_buddy.mem_end; - uintptr_t user_low_bound = user_phy_freemem_buddy.mem_start, user_high_bound = user_phy_freemem_buddy.mem_end; - uintptr_t end_idx = USER_MEM_TOP >> LEVEL3_PDE_SHIFT; - - for (uintptr_t i = 0; i < end_idx; i++) { - // free each page table - uintptr_t* pgtbl_paddr = (uintptr_t*)LEVEL4_PTE_ADDR(pgdir->pd_addr[i]); - if (pgtbl_paddr != 0) { - // free each page - for (uintptr_t j = 0; j < NUM_LEVEL4_PTE; j++) { - uintptr_t* page_paddr = (uintptr_t*)ALIGNDOWN(((uintptr_t*)P2V(pgtbl_paddr))[j], PAGE_SIZE); - if (page_paddr != NULL) { - if (LIKELY((uintptr_t)page_paddr >= low_bound && (uintptr_t)page_paddr < high_bound)) { - kfree(P2V(page_paddr)); - } else if (LIKELY((uintptr_t)page_paddr >= user_low_bound && (uintptr_t)page_paddr < user_high_bound)) { - raw_free((char*)page_paddr); - } - } - } - kfree(P2V(pgtbl_paddr)); - } - } - kfree((char*)pgdir->pd_addr); -} - /// assume that a user pagedir is allocated from [0, size) /// if new_size > old_size, allocate more space, /// if old_size > new_size, free extra space, to avoid unnecessary alloc/free. @@ -191,7 +168,9 @@ static uintptr_t _resize_user_pgdir(struct TopLevelPageDirectory* pgdir, uintptr } memset(new_page, 0, PAGE_SIZE); - xizi_pager.map_pages(pgdir->pd_addr, cur_size, V2P(new_page), PAGE_SIZE, false); + if (!xizi_pager.map_pages(pgdir->pd_addr, cur_size, V2P(new_page), PAGE_SIZE, false)) { + return cur_size; + } cur_size += PAGE_SIZE; } @@ -294,11 +273,9 @@ void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driv _map_pages((uintptr_t*)kern_pgdir.pd_addr, DEV_VRTMEM_BASE, DEV_PHYMEM_BASE, DEV_MEM_SZ, dev_attr); _p_pgtbl_mmu_access->LoadPgdir((uintptr_t)V2P(kern_pgdir.pd_addr)); - // _p_pgtbl_mmu_access->LoadPgdirCrit((uintptr_t)V2P(kern_pgdir.pd_addr), intr_driver_tag); } void secondary_cpu_load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag) { _p_pgtbl_mmu_access->LoadPgdir((uintptr_t)V2P(kern_pgdir.pd_addr)); - // _p_pgtbl_mmu_access->LoadPgdirCrit((uintptr_t)V2P(kern_pgdir.pd_addr), intr_driver_tag); } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable_level2.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable_level2.c index 7dad9b1b1..b25155749 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable_level2.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/pagetable_level2.c @@ -29,6 +29,11 @@ Modification: *************************************************/ #include +#include "core.h" +#include "memlayout.h" + +#include "assert.h" +#include "buddy.h" #include "kalloc.h" #include "pagetable.h" @@ -36,6 +41,7 @@ uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc) { // get page table addr + assert(pgdir != NULL); uintptr_t pde_attr = 0; _p_pgtbl_mmu_access->MmuPdeAttr(&pde_attr); @@ -55,4 +61,37 @@ uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc) } return &pgtbl_vaddr[LEVEL4_PTE_IDX(vaddr)]; +} + +void _free_user_pgdir(struct TopLevelPageDirectory* pgdir) +{ + uintptr_t low_bound = kern_virtmem_buddy.mem_start, high_bound = kern_virtmem_buddy.mem_end; + uintptr_t user_low_bound = user_phy_freemem_buddy.mem_start, user_high_bound = user_phy_freemem_buddy.mem_end; + uintptr_t end_idx = USER_MEM_TOP >> LEVEL3_PDE_SHIFT; + + for (uintptr_t level4_entry_idx = 0; level4_entry_idx < end_idx; level4_entry_idx++) { + // free each level4 page table + uintptr_t* pgtbl_paddr = (uintptr_t*)LEVEL4_PTE_ADDR(pgdir->pd_addr[level4_entry_idx]); + if (pgtbl_paddr != NULL) { + // free each page + for (uintptr_t page_entry_idx = 0; page_entry_idx < NUM_LEVEL4_PTE; page_entry_idx++) { + uintptr_t vaddr = (level4_entry_idx << LEVEL3_PDE_SHIFT) | (page_entry_idx << LEVEL4_PTE_SHIFT); + + // get page paddr + uintptr_t* page_paddr = (uintptr_t*)ALIGNDOWN(((uintptr_t*)P2V(pgtbl_paddr))[page_entry_idx], PAGE_SIZE); + if (page_paddr != NULL) { + // IPC vaddr should not be addressed here. + assert(vaddr < USER_IPC_SPACE_BASE || vaddr >= USER_IPC_SPACE_TOP); + + if (LIKELY((uintptr_t)page_paddr >= low_bound && (uintptr_t)page_paddr < high_bound)) { + kfree(P2V(page_paddr)); + } else if (LIKELY((uintptr_t)page_paddr >= user_low_bound && (uintptr_t)page_paddr < user_high_bound)) { + raw_free((char*)page_paddr); + } + } + } + kfree(P2V(pgtbl_paddr)); + } + } + kfree((char*)pgdir->pd_addr); } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c index 335c28879..ba57b8d3c 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/share_page.c @@ -92,8 +92,24 @@ static uintptr_t map_task_share_page(struct TaskMicroDescriptor* task, const uin struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag); // map double vaddr page to support uniform ring buffer r/w - uintptr_t vaddr = alloc_share_page_addr(task, nr_pages * 2); - if (UNLIKELY(vaddr == 0)) { + uintptr_t vaddr = (uintptr_t)NULL; + if (task->massive_ipc_allocator != NULL) { + vaddr = (uintptr_t)KBuddyAlloc(task->massive_ipc_allocator, PAGE_SIZE * nr_pages * 2); + assert(xizi_pager.address_translate(&task->pgdir, vaddr) == (uintptr_t)NULL); + } else { + vaddr = alloc_share_page_addr(task, nr_pages * 2); + if (vaddr >= USER_IPC_USE_ALLOCATOR_WATERMARK) { + task->massive_ipc_allocator = (struct KBuddy*)slab_alloc(&xizi_task_manager.task_buddy_allocator); + KBuddyInit(task->massive_ipc_allocator, USER_IPC_USE_ALLOCATOR_WATERMARK, USER_IPC_SPACE_TOP); + if (!task->massive_ipc_allocator) { + ERROR("Alloc task buddy failed.\n"); + return (uintptr_t)NULL; + } + return map_task_share_page(task, paddr, nr_pages); + } + } + + if (UNLIKELY(vaddr == (uintptr_t)NULL)) { return (uintptr_t)NULL; } if (!xizi_pager.map_pages(task->pgdir.pd_addr, vaddr, paddr, nr_pages * PAGE_SIZE, false)) { @@ -107,9 +123,7 @@ static uintptr_t map_task_share_page(struct TaskMicroDescriptor* task, const uin p_mmu_driver->TlbFlush(vaddr, 2 * nr_pages * PAGE_SIZE); /// @todo clean range rather than all - // p_dcache_done->flushall(); p_dcache_done->invalidateall(); - // p_dcache_done->flush(vaddr, vaddr + 2 * nr_pages * PAGE_SIZE); } return vaddr; } @@ -133,9 +147,7 @@ uintptr_t task_map_pages(struct TaskMicroDescriptor* task, const uintptr_t vaddr p_mmu_driver->TlbFlush(vaddr, nr_pages * PAGE_SIZE); /// @todo clean range rather than all - // p_dcache_done->flushall(); p_dcache_done->invalidateall(); - // p_dcache_done->flush(vaddr, vaddr + nr_pages * PAGE_SIZE); } return vaddr; @@ -149,13 +161,14 @@ void unmap_task_share_pages(struct TaskMicroDescriptor* task, const uintptr_t ta xizi_pager.unmap_pages(task->pgdir.pd_addr, task_vaddr, nr_pages * PAGE_SIZE); xizi_pager.unmap_pages(task->pgdir.pd_addr, task_vaddr + (nr_pages * PAGE_SIZE), nr_pages * PAGE_SIZE); + if (task_vaddr >= USER_IPC_USE_ALLOCATOR_WATERMARK) { + KBuddyFree(task->massive_ipc_allocator, (void*)task_vaddr); + } if (task == cur_cpu()->task) { p_mmu_driver->TlbFlush(task_vaddr, 2 * nr_pages * PAGE_SIZE); /// @todo clean range rather than all - // p_dcache_done->flushall(); p_dcache_done->invalidateall(); - // p_dcache_done->flush(task_vaddr, task_vaddr + 2 * nr_pages * PAGE_SIZE); } } @@ -178,12 +191,14 @@ struct session_backend* create_share_pages(struct TaskMicroDescriptor* client, s uintptr_t client_vaddr = map_task_share_page(client, V2P_WO(kern_vaddr), nr_pages); if (UNLIKELY(client_vaddr == 0)) { kfree((char*)kern_vaddr); + slab_free(SessionAllocator(), session_backend); return NULL; } uintptr_t server_vaddr = map_task_share_page(server, V2P_WO(kern_vaddr), nr_pages); if (UNLIKELY(server_vaddr == 0)) { unmap_task_share_pages(client, client_vaddr, nr_pages); kfree((char*)kern_vaddr); + slab_free(SessionAllocator(), session_backend); return NULL; } @@ -208,6 +223,9 @@ struct session_backend* create_share_pages(struct TaskMicroDescriptor* client, s doubleListNodeInit(&session_backend->server_side.node); doubleListAddOnBack(&session_backend->server_side.node, &server->svr_sess_listhead); + server->mem_size += true_capacity; + client->mem_size += true_capacity; + return session_backend; } @@ -223,18 +241,31 @@ int delete_share_pages(struct session_backend* session_backend) return -1; } + assert(session_backend->server_side.closed || session_backend->client_side.closed); + /* unmap share pages */ - if (session_backend->client) { - doubleListDel(&session_backend->client_side.node); + // close ssesion in server's perspective + if (session_backend->server_side.closed && session_backend->server != NULL) { + xizi_share_page_manager.unmap_task_share_pages(session_backend->server, session_backend->server_side.buf_addr, session_backend->nr_pages); + doubleListDel(&session_backend->server_side.node); + session_backend->server->mem_size -= session_backend->nr_pages * PAGE_SIZE; + session_backend->server = NULL; } - if (session_backend->server) { - doubleListDel(&session_backend->server_side.node); + // close ssesion in client's perspective + if (session_backend->client_side.closed && session_backend->client != NULL) { + xizi_share_page_manager.unmap_task_share_pages(session_backend->client, session_backend->client_side.buf_addr, session_backend->nr_pages); + doubleListDel(&session_backend->client_side.node); + session_backend->client->mem_size -= session_backend->nr_pages * PAGE_SIZE; + session_backend->client = NULL; } /* free seesion backend */ - kfree((void*)session_backend->buf_kernel_addr); - slab_free(SessionAllocator(), (void*)session_backend); + if (session_backend->server_side.closed && session_backend->client_side.closed) { + assert(session_backend->client == NULL && session_backend->server == NULL); + kfree((void*)session_backend->buf_kernel_addr); + slab_free(SessionAllocator(), (void*)session_backend); + } return 0; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c index e87f1bcfd..33a7425f0 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_close_session.c @@ -33,9 +33,13 @@ Modification: #include "syscall.h" #include "task.h" -int sys_close_session(struct Session* session) +/// @brief close a session syscall +/// @warning best to be called by a client +/// @param cur_task +/// @param session +/// @return +int sys_close_session(struct TaskMicroDescriptor* cur_task, struct Session* session) { - struct TaskMicroDescriptor* cur_task = cur_cpu()->task; assert(cur_task != NULL); /* check if session is available */ if (session->buf == NULL || (uintptr_t)session->buf < USER_IPC_SPACE_BASE || (uintptr_t)session->buf > USER_IPC_SPACE_TOP) { @@ -44,18 +48,16 @@ int sys_close_session(struct Session* session) /* check if session is a client one or a server one */ struct session_backend* session_backend = NULL; - bool session_valid = false; struct client_session* client_session = NULL; DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node) { if ((uintptr_t)session->buf == client_session->buf_addr) { - session_valid = true; session_backend = CLIENT_SESSION_BACKEND(client_session); - if (!client_session->closed) { - client_session->closed = true; - xizi_share_page_manager.unmap_task_share_pages(cur_task, session_backend->client_side.buf_addr, session_backend->nr_pages); - } + assert(session_backend->client == cur_task); + assert(client_session->closed == false); + client_session->closed = true; + xizi_share_page_manager.delete_share_pages(session_backend); break; } } @@ -64,20 +66,19 @@ int sys_close_session(struct Session* session) DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node) { if ((uintptr_t)session->buf == server_session->buf_addr) { - session_valid = true; session_backend = SERVER_SESSION_BACKEND(server_session); - if (!server_session->closed) { - server_session->closed = true; - xizi_share_page_manager.unmap_task_share_pages(cur_task, session_backend->server_side.buf_addr, session_backend->nr_pages); - } + assert(session_backend->server == cur_task); + assert(server_session->closed == false); + server_session->closed = true; + xizi_share_page_manager.delete_share_pages(session_backend); break; } } } /* close this session */ - if (UNLIKELY(session_backend->client_side.closed && session_backend->server_side.closed) && LIKELY(session_valid)) { - xizi_share_page_manager.delete_share_pages(session_backend); + if (session_backend == NULL) { + return -1; } return 0; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c index 84fc74109..86db16c5a 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_connect_session.c @@ -35,13 +35,14 @@ Modification: #include "syscall.h" #include "task.h" -int create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session) +struct session_backend* create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session) { // create share pages + assert(server != NULL && client != NULL); struct session_backend* session_backend = xizi_share_page_manager.create_share_pages(client, server, capacity); if (UNLIKELY(session_backend == NULL)) { - DEBUG("create_share_pages failed\n"); - return -1; + DEBUG("create_share_pages to server: %s failed\n", server->name); + return NULL; } // init user_session @@ -51,7 +52,7 @@ int create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDes user_session->tail = 0; user_session->id = session_backend->session_id; - return 0; + return session_backend; } int sys_connect_session(char* path, int capacity, struct Session* user_session) @@ -76,5 +77,8 @@ int sys_connect_session(char* path, int capacity, struct Session* user_session) struct TaskMicroDescriptor* server = AchieveResource(&server_tag); assert(server != NULL); - return create_session_inner(client, server, capacity, user_session); + if (create_session_inner(client, server, capacity, user_session) == NULL) { + return -1; + } + return 0; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exec.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exec.c index 185f21da6..b24f9552b 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exec.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exec.c @@ -69,9 +69,15 @@ Modification: int task_exec(struct TaskMicroDescriptor* task, char* img_start, char* name, char** argv) { /* load img to task */ + if (img_start == NULL) { + return -1; + } /* 1. load elf header */ struct elfhdr elf; memcpy((void*)&elf, img_start, sizeof(elf)); + if (elf.magic != ELF_MAGIC) { + return -1; + } // pgdir for new task struct TopLevelPageDirectory pgdir; pgdir.pd_addr = NULL; @@ -106,7 +112,7 @@ int task_exec(struct TaskMicroDescriptor* task, char* img_start, char* name, cha for (int addr_offset = 0; addr_offset < ph.filesz; addr_offset += PAGE_SIZE) { uintptr_t page_paddr = xizi_pager.address_translate(&pgdir, ph.vaddr + addr_offset); if (page_paddr == 0) { - ERROR("copy elf file to unmapped addr\n"); + ERROR("copy elf file to unmapped addr: %x(pgdir: %x)\n", ph.vaddr + addr_offset, pgdir.pd_addr); goto error_exec; } uintptr_t read_size = (ph.filesz - addr_offset < PAGE_SIZE ? ph.filesz - addr_offset : PAGE_SIZE); @@ -169,13 +175,12 @@ int task_exec(struct TaskMicroDescriptor* task, char* img_start, char* name, cha } strncpy(task->name, last, sizeof(task->name)); - struct TopLevelPageDirectory old_pgdir = task->pgdir; + if (task->pgdir.pd_addr != NULL) { + xizi_pager.free_user_pgdir(&task->pgdir); + } task->pgdir = pgdir; - - /// @todo record mem size used b task - task->mem_size = ALIGNUP(load_size, PAGE_SIZE); - - xizi_pager.free_user_pgdir(&old_pgdir); + task->heap_base = ALIGNUP(load_size, PAGE_SIZE); + task->mem_size = task->heap_base + USER_STACK_SIZE; return 0; error_exec: diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c index bd5a99612..1f270af54 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_exit.c @@ -39,51 +39,12 @@ Modification: int sys_exit(struct TaskMicroDescriptor* ptask) { assert(ptask != NULL); - - /* handle sessions for condition 1, ref. delete_share_pages() */ - // close all server_sessions - struct server_session* server_session = NULL; - while (!IS_DOUBLE_LIST_EMPTY(&ptask->svr_sess_listhead)) { - server_session = CONTAINER_OF(ptask->svr_sess_listhead.next, struct server_session, node); - // cut the connection from task to session - if (!server_session->closed) { - xizi_share_page_manager.unmap_task_share_pages(ptask, server_session->buf_addr, CLIENT_SESSION_BACKEND(server_session)->nr_pages); - server_session->closed = true; - } - doubleListDel(&server_session->node); - SERVER_SESSION_BACKEND(server_session)->server = NULL; - // delete session (also cut connection from session to task) - if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) { - xizi_share_page_manager.delete_share_pages(SERVER_SESSION_BACKEND(server_session)); - } + ptask->dead = true; + // free that task straightly if it's a blocked task + if (ptask->state == BLOCKED) { + xizi_task_manager.free_pcb(ptask); } - // close all client_sessions - struct client_session* client_session = NULL; - while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) { - client_session = CONTAINER_OF(ptask->cli_sess_listhead.next, struct client_session, node); - // cut the connection from task to session - if (!client_session->closed) { - xizi_share_page_manager.unmap_task_share_pages(ptask, client_session->buf_addr, CLIENT_SESSION_BACKEND(client_session)->nr_pages); - client_session->closed = true; - } - doubleListDel(&client_session->node); - CLIENT_SESSION_BACKEND(client_session)->client = NULL; - // delete session (also cut connection from session to task) - if (CLIENT_SESSION_BACKEND(client_session)->server_side.closed) { - xizi_share_page_manager.delete_share_pages(CLIENT_SESSION_BACKEND(client_session)); - } - } - - if (ptask->server_identifier.meta != NULL) { - struct TraceTag server_identifier_owner; - AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier"); - assert(server_identifier_owner.meta != NULL); - DeleteResource(&ptask->server_identifier, &server_identifier_owner); - } - - // delete task for pcb_list - xizi_task_manager.cur_task_yield_noschedule(); - ptask->state = DEAD; - + // yield current task in case it wants to exit itself + xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false); return 0; -} \ No newline at end of file +} diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_kill.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_kill.c index 5d9bef5c8..acfe6ffa1 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_kill.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_kill.c @@ -35,7 +35,25 @@ extern int sys_exit(struct TaskMicroDescriptor* task); int sys_kill(int id) { struct TaskMicroDescriptor* task = NULL; + // check if task is a running one + DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_running_list_head, node) + { + if (task->pid == id) { + sys_exit(task); + return 0; + } + } + // check if task is a blocking one + DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_blocked_list_head, node) + { + if (task->pid == id) { + sys_exit(task); + return 0; + } + } + + // check if task is a ready one for (int prio = 0; prio < TASK_MAX_PRIORITY; prio++) { DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[prio], node) { diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c index 0b11adc62..3b2f7e727 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_mmap.c @@ -63,5 +63,7 @@ int sys_mmap(uintptr_t vaddr, uintptr_t paddr, int len, int is_dev) load_len += PAGE_SIZE; } } + + cur_task->mem_size += true_len; return vaddr + true_len; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c index 8a3e7b9e4..7116add5d 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_poll_session.c @@ -28,11 +28,20 @@ Modification: 1. first version *************************************************/ #include "assert.h" +#include "ipc.h" #include "multicores.h" #include "share_page.h" #include "syscall.h" #include "task.h" +#define IPCSESSION_MSG(session) ((struct IpcMsg*)((char*)((session)->buf) + (session)->head)) + +static inline bool is_msg_needed(struct IpcMsg* msg) +{ + assert(msg != NULL); + return msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done == 0 && msg->header.delayed == 0; +} + int sys_poll_session(struct Session* userland_session_arr, int arr_capacity) { struct TaskMicroDescriptor* cur_task = cur_cpu()->task; @@ -55,51 +64,65 @@ int sys_poll_session(struct Session* userland_session_arr, int arr_capacity) return -1; } // update session_backend + // if current session is handled + if (server_session->head != userland_session_arr[i].head) { + struct TaskMicroDescriptor* client = SERVER_SESSION_BACKEND(server_session)->client; + if (client->state == BLOCKED) { + xizi_task_manager.task_unblock(client); + } else { + client->current_ipc_handled = true; + } + } server_session->head = userland_session_arr[i].head; server_session->tail = userland_session_arr[i].tail; doubleListDel(cur_node); doubleListAddOnBack(cur_node, &cur_task->svr_sess_listhead); } - /* handle sessions for condition 2, ref. delete_share_pages() */ - bool has_delete = true; - while (has_delete) { - has_delete = false; - - DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node) - { - if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) { - // client had closed it, then server will close it too - struct session_backend* session_backend = SERVER_SESSION_BACKEND(server_session); - - if (!session_backend->server_side.closed) { - session_backend->server_side.closed = true; - xizi_share_page_manager.unmap_task_share_pages(cur_task, session_backend->server_side.buf_addr, session_backend->nr_pages); - } - xizi_share_page_manager.delete_share_pages(session_backend); - has_delete = true; - break; - } - } - } - /* poll with new sessions */ - int i = 0; + int nr_sessions_need_to_handle = 0; + bool has_middle_delete = false; + int session_idx = 0; DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node) { - if (i >= arr_capacity) { + if (session_idx >= arr_capacity) { break; } - userland_session_arr[i++] = (struct Session) { + + if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) { + // client had closed it, then server will close it too + struct session_backend* session_backend = SERVER_SESSION_BACKEND(server_session); + assert(session_backend->server == cur_task); + assert(session_backend->client == NULL); + assert(server_session->closed == false); + server_session->closed = true; + xizi_share_page_manager.delete_share_pages(session_backend); + // signal that there is a middle deletion of session + has_middle_delete = true; + break; + } + + userland_session_arr[session_idx] = (struct Session) { .buf = (void*)server_session->buf_addr, .capacity = server_session->capacity, .head = server_session->head, .tail = server_session->tail, .id = SERVER_SESSION_BACKEND(server_session)->session_id, }; + + struct IpcMsg* msg = IPCSESSION_MSG(&userland_session_arr[session_idx]); + if (is_msg_needed(msg)) { + nr_sessions_need_to_handle++; + } + + session_idx++; } - if (LIKELY(i < arr_capacity)) { - userland_session_arr[i].buf = 0; + if (session_idx < arr_capacity) { + userland_session_arr[session_idx].buf = NULL; + if (!has_middle_delete && nr_sessions_need_to_handle == 0) { + xizi_task_manager.task_yield_noschedule(cur_task, false); + xizi_task_manager.task_block(cur_task); + } } return 0; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c index 1ed2965b5..d0b63502c 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_register_irq.c @@ -34,65 +34,126 @@ Modification: #include "actracer.h" #include "assert.h" #include "ipc.h" +#include "kalloc.h" #include "multicores.h" #include "share_page.h" #include "syscall.h" #include "task.h" -static struct TaskMicroDescriptor kernel_irq_proxy; +static struct TaskMicroDescriptor* kernel_irq_proxy; static struct { struct TaskMicroDescriptor* handle_task; - struct Session* session; + struct Session session; + struct session_backend* p_kernel_session; int opcode; } irq_forward_table[NR_IRQS]; static void send_irq_to_user(int irq_num) { - int len = IPC_ARG_INFO_BASE_OFFSET; - /* add session tail */ - struct IpcMsg* buf = irq_forward_table[irq_num].session->buf + irq_forward_table[irq_num].session->tail; - irq_forward_table[irq_num].session->tail += len; - memset((void*)buf, 0, len); - /* construct message */ - buf->header.len = len; - buf->header.nr_args = 0; - buf->header.init = 1; - buf->header.opcode = irq_forward_table[irq_num].opcode; - buf->header.done = 0; - buf->header.magic = IPC_MSG_MAGIC; - buf->header.valid = 1; - /* add session head */ - irq_forward_table[irq_num].session->head += len; + if (irq_forward_table[irq_num].handle_task != NULL) { + struct Session* session = &irq_forward_table[irq_num].session; + int len = IPC_ARG_INFO_BASE_OFFSET; + len += sizeof(struct IpcArgInfo); + + /* get message space and add session tail */ + void* session_kern_vaddr = P2V(xizi_pager.address_translate(&kernel_irq_proxy->pgdir, (uintptr_t)session->buf)); + struct IpcMsg* buf = session_kern_vaddr + session->tail; + + /* check if server session is full */ + if (buf->header.magic == IPC_MSG_MAGIC && buf->header.done == 0) { + DEBUG("irq server cannot handle new interrupt by now.\n"); + return; + } + memset((void*)buf, 0, len); + session->tail = (session->tail + len) % session->capacity; + + /* construct message */ + buf->header.len = len; + buf->header.nr_args = 1; + buf->header.init = 1; + buf->header.opcode = irq_forward_table[irq_num].opcode; + buf->header.done = 0; + buf->header.magic = IPC_MSG_MAGIC; + buf->header.valid = 1; + + if (irq_forward_table[irq_num].handle_task->state == BLOCKED) { + xizi_task_manager.task_unblock(irq_forward_table[irq_num].handle_task); + } + + /* add session head */ + session->head = (session->head + len) % session->capacity; + } } int user_irq_handler(int irq, void* tf, void* arg) { - send_irq_to_user(irq); - next_task_emergency = irq_forward_table[irq].handle_task; - xizi_task_manager.cur_task_yield_noschedule(); + if (irq_forward_table[irq].handle_task != NULL) { + send_irq_to_user(irq); + + next_task_emergency = irq_forward_table[irq].handle_task; + if (cur_cpu()->task != NULL) { + xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false); + } + } return 0; } -extern int create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session); +extern struct session_backend* create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session); /// @warning no tested. + +static struct XiziTrapDriver* p_intr_driver = NULL; int sys_register_irq(int irq_num, int irq_opcode) { - static struct TraceTag intr_ac_tag; - if (!AchieveResourceTag(&intr_ac_tag, RequireRootTag(), "hardkernel/intr-ac-resource")) { - ERROR("intr not initialized.\n"); - return -1; + // init intr resource; + if (p_intr_driver == NULL) { + struct TraceTag intr_ac_tag; + if (!AchieveResourceTag(&intr_ac_tag, RequireRootTag(), "hardkernel/intr-ac-resource")) { + ERROR("intr not initialized.\n"); + return -1; + } + p_intr_driver = (struct XiziTrapDriver*)AchieveResource(&intr_ac_tag); } - struct XiziTrapDriver* p_intr_driver = AchieveResource(&intr_ac_tag); - if (p_intr_driver->sw_irqtbl[irq_num].handler != NULL) { + // init kerenl sender proxy + if (kernel_irq_proxy == NULL) { + kernel_irq_proxy = xizi_task_manager.new_task_cb(); + kernel_irq_proxy->state = NEVER_RUN; + xizi_pager.new_pgdir(&kernel_irq_proxy->pgdir); + memcpy(kernel_irq_proxy->pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE); + } + + // bind irq to session + if (irq_forward_table[irq_num].handle_task != NULL) { ERROR("irq %d is occupied.\n", irq_num); return -1; } struct TaskMicroDescriptor* cur_task = cur_cpu()->task; irq_forward_table[irq_num].handle_task = cur_task; irq_forward_table[irq_num].opcode = irq_opcode; - create_session_inner(&kernel_irq_proxy, cur_task, PAGE_SIZE, irq_forward_table[irq_num].session); + irq_forward_table[irq_num].p_kernel_session = create_session_inner(kernel_irq_proxy, cur_task, PAGE_SIZE, &irq_forward_table[irq_num].session); p_intr_driver->bind_irq_handler(irq_num, user_irq_handler); + cur_task->bind_irq = true; + return 0; +} + +int sys_unbind_irq(struct TaskMicroDescriptor* task, int irq_num) +{ + if (irq_forward_table[irq_num].handle_task != task) { + return -1; + } + + irq_forward_table[irq_num].handle_task = NULL; + return 0; +} + +int sys_unbind_irq_all(struct TaskMicroDescriptor* task) +{ + for (int idx = 0; idx < NR_IRQS; idx++) { + if (irq_forward_table[idx].handle_task == task) { + sys_unbind_irq(task, idx); + } + } + task->bind_irq = false; return 0; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c index c4a587aaa..3d473e61b 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_spawn.c @@ -49,7 +49,7 @@ int sys_spawn(char* img_start, char* name, char** argv) return -1; } // init pcb - xizi_task_manager.task_set_default_schedule_attr(new_task_cb, RequireRootTag()); + xizi_task_manager.task_set_default_schedule_attr(new_task_cb); return 0; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c index c37fb65fb..fba8121ee 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_state.c @@ -40,52 +40,58 @@ Modification: extern uint8_t _binary_fs_img_start[], _binary_fs_img_end[]; -/// @brief Padding task name length to TASK_NAME_MAX_LEN -static inline void _padding(char* name) -{ - int i; - size_t length = strlen(name); - for (i = length; i < TASK_NAME_MAX_LEN - 1; i++) { - name[i] = ' '; - } - name[i] = '\0'; - return; -} +#define SHOWINFO_BORDER_LINE() LOG_PRINTF("******************************************************\n"); +#define SHOWTASK_TASK_BASE_INFO(task) LOG_PRINTF(" %-4d %-16s %-4d 0x%x(%-d)\n", task->pid, task->name, task->priority, task->mem_size >> 10, task->mem_size >> 10) void show_tasks(void) { struct TaskMicroDescriptor* task = NULL; - LOG_PRINTF("******************************************************\n"); + SHOWINFO_BORDER_LINE(); for (int i = 0; i < NR_CPU; i++) { - LOG_PRINTF("CPU %d: ", i); - if (global_cpus[i].task != NULL) { - LOG_PRINTF("%s\n", global_cpus[i].task->name); - } else { - LOG_PRINTF("NULL\n"); - } + LOG_PRINTF("CPU %-2d: %s\n", i, (global_cpus[i].task == NULL ? "NULL" : global_cpus[i].task->name)); } - LOG_PRINTF("******************************************************\n"); - LOG_PRINTF("STAT ID TASK PRI LEFT_TICKS\n"); + SHOWINFO_BORDER_LINE(); + LOG_PRINTF("%-8s %-4s %-16s %-4s %-8s\n", "STAT", "ID", "TASK", "PRI", "MEM(KB)"); + DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_running_list_head, node) + { + LOG_PRINTF("%-8s", "RUNNING"); + SHOWTASK_TASK_BASE_INFO(task); + } + for (int i = 0; i < TASK_MAX_PRIORITY; i++) { if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[i])) { continue; } DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[i], node) { - if (task->state == INIT) - LOG_PRINTF(" INIT "); - else if (task->state == READY) - LOG_PRINTF(" READY "); - else if (task->state == RUNNING) - LOG_PRINTF("RUNNING "); - else if (task->state == DEAD) - LOG_PRINTF(" DEAD "); + switch (task->state) { + case INIT: + LOG_PRINTF("%-8s", "INIT"); + break; + case READY: + LOG_PRINTF("%-8s", "READY"); + break; + case RUNNING: + LOG_PRINTF("%-8s", "RUNNING"); + break; + case DEAD: + LOG_PRINTF("%-8s", "DEAD"); + break; + default: + break; + } - _padding(task->name); - LOG_PRINTF(" %d %s %d %d\n", task->pid, task->name, task->priority, task->remain_tick); + SHOWTASK_TASK_BASE_INFO(task); } } - LOG_PRINTF("******************************************************\n"); + + DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_blocked_list_head, node) + { + LOG_PRINTF("%-8s", "BLOCK"); + SHOWTASK_TASK_BASE_INFO(task); + } + + SHOWINFO_BORDER_LINE(); return; } @@ -94,19 +100,21 @@ extern struct KBuddy kern_virtmem_buddy; extern uint32_t kernel_data_end[]; void show_mem(void) { - LOG_PRINTF("*********************************************************\n"); - LOG_PRINTF(" TOTAL(KB) USED(KB) FREE(KB) \n"); + SHOWINFO_BORDER_LINE(); - uint32_t total = (PHY_MEM_STOP - V2P(kernel_data_end)) >> 10; - uint32_t used = 0; + uint64_t total = (PHY_MEM_STOP - V2P(kernel_data_end)); + uint64_t user_dynamic_free = 0; + uint64_t kernel_free = 0; for (int j = 0; j < MAX_BUDDY_ORDER; j++) { - used += user_phy_freemem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE; - used += kern_virtmem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE; + user_dynamic_free += user_phy_freemem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE; + kernel_free += kern_virtmem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE; } - used = used >> 10; + LOG_PRINTF("%-16s 0x%064lx\n", "TOTAL(B)", total); + LOG_PRINTF("%-16s 0x%064lx\n", "KERNEL USED(B)", (kern_virtmem_buddy.mem_end - kern_virtmem_buddy.mem_start - kernel_free)); + LOG_PRINTF("%-16s 0x%064lx\n", "LIBMEM USED(B)", (user_phy_freemem_buddy.mem_end - user_phy_freemem_buddy.mem_start - user_dynamic_free)); + LOG_PRINTF("%-16s 0x%064lx\n", "FREE(B)", user_dynamic_free + kernel_free); - LOG_PRINTF(" %d %d %d\n", total, total - used, used); - LOG_PRINTF("*********************************************************\n"); + SHOWINFO_BORDER_LINE(); return; } @@ -123,8 +131,6 @@ void show_cpu(void) struct TaskMicroDescriptor* current_task = cur_cpu()->task; assert(current_task != NULL); - _padding(current_task->name); - LOG_PRINTF(" ID COMMAND USED_TICKS FREE_TICKS \n"); LOG_PRINTF(" %d %s %d %d\n", cpu_id, current_task->name, TASK_CLOCK_TICK - current_task->remain_tick, current_task->remain_tick); @@ -138,7 +144,7 @@ int sys_state(sys_state_option option, sys_state_info* info) info->memblock_info.memblock_start = (uintptr_t)V2P(_binary_fs_img_start); info->memblock_info.memblock_end = (uintptr_t)V2P(_binary_fs_img_end); } else if (option == SYS_STATE_GET_HEAP_BASE) { - return cur_cpu()->task->mem_size; + return cur_cpu()->task->heap_base; } else if (option == SYS_STATE_SET_TASK_PRIORITY) { xizi_task_manager.set_cur_task_priority(info->priority); } else if (option == SYS_STATE_SHOW_TASKS) { diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c index 6aa426047..758c486d3 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/sys_yield.c @@ -31,10 +31,32 @@ Modification: #include "syscall.h" #include "task.h" -#include "log.h" +#include "assert.h" -int sys_yield() +int sys_yield(task_yield_reason reason) { - xizi_task_manager.cur_task_yield_noschedule(); + struct TaskMicroDescriptor* cur_task = cur_cpu()->task; + xizi_task_manager.task_yield_noschedule(cur_task, false); + + // handle ipc block + if ((reason & SYS_TASK_YIELD_BLOCK_IPC) != 0) { + if (cur_task->current_ipc_handled) { + cur_task->current_ipc_handled = false; + } else { + xizi_task_manager.task_block(cur_task); + } + } + + // wake up all possible server + struct client_session* client_session = NULL; + DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node) + { + assert(client_session != NULL); + struct session_backend* session_backend = CLIENT_SESSION_BACKEND(client_session); + if (session_backend->server->state == BLOCKED) { + xizi_task_manager.task_unblock(session_backend->server); + } + } + return 0; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c b/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c index 5e3de560c..c93532d77 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/syscall/syscall.c @@ -48,7 +48,7 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u ret = sys_exit(cur_cpu()->task); break; case SYSCALL_YIELD: - ret = sys_yield(); + ret = sys_yield((task_yield_reason)param1); break; case SYSCALL_SERVER: ret = sys_register_as_server((char*)param1); @@ -60,7 +60,7 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u ret = sys_poll_session((struct Session*)param1, (int)param2); break; case SYSCALL_CLOSE_SESSION: - ret = sys_close_session((struct Session*)param1); + ret = sys_close_session(cur_cpu()->task, (struct Session*)param1); break; case SYSCALL_EXEC: ret = sys_exec((char*)param1, (char*)param2, (char**)param3); diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/Makefile b/Ubiquitous/XiZi_AIoT/softkernel/task/Makefile index 94bd1ecf3..a0f5db6ae 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/Makefile +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/Makefile @@ -1,3 +1,3 @@ -SRC_FILES := task.c scheduler.c spawn_default_task.c +SRC_FILES := task.c schedule.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/scheduler.c b/Ubiquitous/XiZi_AIoT/softkernel/task/schedule.c similarity index 80% rename from Ubiquitous/XiZi_AIoT/softkernel/task/scheduler.c rename to Ubiquitous/XiZi_AIoT/softkernel/task/schedule.c index a8d8048dd..080828839 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/scheduler.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/schedule.c @@ -27,24 +27,25 @@ Author: AIIT XUOS Lab Modification: 1. first version *************************************************/ +#include "log.h" #include "scheduler.h" struct TaskMicroDescriptor* max_priority_runnable_task(void) { - struct TaskMicroDescriptor* task = NULL; - uint32_t priority = 0; + static struct TaskMicroDescriptor* task = NULL; + static int priority = 0; priority = __builtin_ffs(ready_task_priority) - 1; + if (priority > 31 || priority < 0) { + return NULL; + } DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[priority], node) { - if (task->state == READY) { + if (task->state == READY && !task->dead) { // found a runnable task, stop this look up - task->state = RUNNING; return task; - } else if (task->state == DEAD) { - // found a killed task, stop this loop - // change in pcb_list may break this loop, so find a runnable in next look up + } else if (task->dead && task->state != RUNNING) { xizi_task_manager.free_pcb(task); return NULL; } @@ -58,14 +59,10 @@ struct TaskMicroDescriptor* round_robin_runnable_task(uint32_t priority) DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[priority], node) { - - if (task->state == READY) { + if (task->state == READY && !task->dead) { // found a runnable task, stop this look up - task->state = RUNNING; return task; - } else if (task->state == DEAD) { - // found a killed task, stop this loop - // change in pcb_list may break this loop, so find a runnable in next look up + } else if (task->dead && task->state != RUNNING) { xizi_task_manager.free_pcb(task); return NULL; } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/spawn_default_task.c b/Ubiquitous/XiZi_AIoT/softkernel/task/spawn_default_task.c deleted file mode 100644 index 8e1cd6e42..000000000 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/spawn_default_task.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2020 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ -/** - * @file spawn_default_task.c - * @brief spawn task that embeded in kernel image - * @version 3.0 - * @author AIIT XUOS Lab - * @date 2023.08.25 - */ - -/************************************************* -File name: spawn_default_task.c -Description: spawn task that embeded in kernel image -Others: -History: -1. Date: 2023-08-28 -Author: AIIT XUOS Lab -Modification: -1. first version -*************************************************/ -#include "actracer.h" -#include "assert.h" -#include "kalloc.h" -#include "task.h" - -#include "execelf.h" - -int spawn_embedded_task(char* img_start, char* name, char** argv) -{ - struct TaskMicroDescriptor* new_task_cb = xizi_task_manager.new_task_cb(); - if (UNLIKELY(!new_task_cb)) { - ERROR("Unable to new task control block.\n"); - return -1; - } - // init trapframe - arch_init_trapframe(new_task_cb->main_thread.trapframe, 0, 0); - - /* load img to task */ - /* 1. load elf header */ - struct elfhdr* elf = (struct elfhdr*)img_start; - // pgdir for new task - struct TopLevelPageDirectory pgdir; - if (UNLIKELY(!xizi_pager.new_pgdir(&pgdir))) { - ERROR("create new pgdir failed.\n"); - goto error_exec; - } - memcpy(pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE); - - /* 2. load elf content */ - uint32_t load_size = 0; - struct proghdr ph; - for (int sec_idx = 0, off = elf->phoff; sec_idx < elf->phnum; sec_idx++, off += sizeof(ph)) { - // load proghdr - memcpy((char*)&ph, img_start + off, sizeof(ph)); - - if (ph.type != ELF_PROG_LOAD) - continue; - if (ph.memsz < ph.filesz) { - ERROR("elf header mem size less than file size\n"); - goto error_exec; - } - - // read section - // 1. alloc space - if ((load_size = xizi_pager.resize_user_pgdir(&pgdir, load_size, ph.vaddr + ph.memsz)) - != ph.vaddr + ph.memsz) { - goto error_exec; - } - // 2. copy inode to space - assert(ph.vaddr % PAGE_SIZE == 0); - for (int addr_offset = 0; addr_offset < ph.filesz; addr_offset += PAGE_SIZE) { - uintptr_t page_paddr = xizi_pager.address_translate(&pgdir, ph.vaddr + addr_offset); - if (page_paddr == 0) { - panic("copy elf file to unmapped addr"); - } - uintptr_t read_size = (ph.filesz - addr_offset < PAGE_SIZE ? ph.filesz - addr_offset : PAGE_SIZE); - memcpy(P2V(page_paddr), img_start + (ph.off + addr_offset), read_size); - } - } - - /// elf file content now in memory - // alloc stack page and map to TOP of user vspace - uintptr_t* stack_bottom = (uintptr_t*)kalloc(USER_STACK_SIZE); - if (UNLIKELY(stack_bottom == NULL)) { - ERROR("No memory.\n"); - goto error_exec; - } - xizi_pager.map_pages(pgdir.pd_addr, USER_MEM_TOP - USER_STACK_SIZE, V2P(stack_bottom), USER_STACK_SIZE, false); - - uintptr_t user_vspace_sp = USER_MEM_TOP; - /// @todo change 32 to some macro - uintptr_t user_stack_init[32]; - uintptr_t argc = 0; - uintptr_t copy_len = 0; - for (argc = 0; argv != NULL && argv[argc] != NULL; argc++) { - /// @todo handle with large number of parameters - - // copy param to user stack - copy_len = strlen(argv[argc]) + 1; - user_vspace_sp = (user_vspace_sp - copy_len) & ~3; - uintptr_t copied_len = xizi_pager.cross_vspace_data_copy(&pgdir, user_vspace_sp, (uintptr_t)argv[argc], copy_len); - if (UNLIKELY(copied_len != copy_len)) { - ERROR("Something went wrong when copying params.\n"); - goto error_exec; - } - user_stack_init[argc] = user_vspace_sp; - } - user_stack_init[argc] = 0; - copy_len = (argc + 1) * sizeof(uintptr_t); - user_vspace_sp -= copy_len; - uintptr_t copied_len = xizi_pager.cross_vspace_data_copy(&pgdir, user_vspace_sp, (uintptr_t)user_stack_init, copy_len); - if (UNLIKELY(copied_len != copy_len)) { - ERROR("Something went wrong when copying params.\n"); - goto error_exec; - } - - // init task trapframe, which stores in svc stack - // do not go tp error_exec once we change trapframe! - assert(copied_len == (argc + 1) * sizeof(uintptr_t)); - arch_trapframe_set_sp_pc(new_task_cb->main_thread.trapframe, user_vspace_sp, elf->entry); - arch_set_main_params(new_task_cb->main_thread.trapframe, argc, user_vspace_sp); - - // save program name - strncpy(new_task_cb->name, name, sizeof(new_task_cb->name)); - - struct TopLevelPageDirectory old_pgdir = new_task_cb->pgdir; - new_task_cb->pgdir = pgdir; - - /// @todo record mem size used b task - new_task_cb->mem_size = ALIGNUP(load_size, PAGE_SIZE); - - xizi_pager.free_user_pgdir(&old_pgdir); - - xizi_task_manager.task_set_default_schedule_attr(new_task_cb, RequireRootTag()); - return 0; - -error_exec: - if (pgdir.pd_addr != NULL) { - xizi_pager.free_user_pgdir(&pgdir); - } - return -1; -} \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/softkernel/task/task.c b/Ubiquitous/XiZi_AIoT/softkernel/task/task.c index 277422fae..ea9ee6b5e 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/task/task.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/task/task.c @@ -32,23 +32,47 @@ Modification: #include "core.h" #include "assert.h" +#include "kalloc.h" #include "log.h" #include "multicores.h" -#include "kalloc.h" #include "scheduler.h" +#include "syscall.h" #include "task.h" struct CPU global_cpus[NR_CPU]; uint32_t ready_task_priority; +static inline void task_node_leave_list(struct TaskMicroDescriptor* task) +{ + doubleListDel(&task->node); + if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[task->priority])) { + ready_task_priority &= ~((uint32_t)1 << task->priority); + } +} + +static inline void task_node_add_to_ready_list_head(struct TaskMicroDescriptor* task) +{ + doubleListAddOnHead(&task->node, &xizi_task_manager.task_list_head[task->priority]); + ready_task_priority |= ((uint32_t)1 << task->priority); +} + +static inline void task_node_add_to_ready_list_back(struct TaskMicroDescriptor* task) +{ + doubleListAddOnBack(&task->node, &xizi_task_manager.task_list_head[task->priority]); + ready_task_priority |= ((uint32_t)1 << task->priority); +} + static void _task_manager_init() { // init task list to NULL for (int i = 0; i < TASK_MAX_PRIORITY; i++) { doubleListNodeInit(&xizi_task_manager.task_list_head[i]); } + doubleListNodeInit(&xizi_task_manager.task_blocked_list_head); + doubleListNodeInit(&xizi_task_manager.task_running_list_head); // init task (slab) allocator slab_init(&xizi_task_manager.task_allocator, sizeof(struct TaskMicroDescriptor)); + slab_init(&xizi_task_manager.task_buddy_allocator, sizeof(struct KBuddy)); // pid pool xizi_task_manager.next_pid = 0; @@ -69,12 +93,54 @@ static struct TaskMicroDescriptor* _alloc_task_cb() // set pid once task is allocated memset(task, 0, sizeof(*task)); task->pid = xizi_task_manager.next_pid++; - // update pcb used - xizi_task_manager.nr_pcb_used += 1; return task; } +int _task_retrieve_sys_resources(struct TaskMicroDescriptor* ptask) +{ + assert(ptask != NULL); + + /* handle sessions for condition 1, ref. delete_share_pages() */ + struct session_backend* session_backend = NULL; + // close all server_sessions + struct server_session* server_session = NULL; + while (!IS_DOUBLE_LIST_EMPTY(&ptask->svr_sess_listhead)) { + server_session = CONTAINER_OF(ptask->svr_sess_listhead.next, struct server_session, node); + assert(server_session != NULL); + session_backend = SERVER_SESSION_BACKEND(server_session); + assert(session_backend->server == ptask); + // cut the connection from task to session + server_session->closed = true; + xizi_share_page_manager.delete_share_pages(session_backend); + } + // close all client_sessions + struct client_session* client_session = NULL; + while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) { + client_session = CONTAINER_OF(ptask->cli_sess_listhead.next, struct client_session, node); + assert(client_session != NULL); + session_backend = CLIENT_SESSION_BACKEND(client_session); + assert(session_backend->client == ptask); + // cut the connection from task to session + client_session->closed = true; + xizi_share_page_manager.delete_share_pages(session_backend); + } + + if (ptask->server_identifier.meta != NULL) { + struct TraceTag server_identifier_owner; + AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier"); + assert(server_identifier_owner.meta != NULL); + DeleteResource(&ptask->server_identifier, &server_identifier_owner); + } + + // delete registered irq if there is one + if (ptask->bind_irq) { + sys_unbind_irq_all(ptask); + } + + return 0; +} + /// @brief this function changes task list without locking, so it must be called inside a lock critical area /// @param task static void _dealloc_task_cb(struct TaskMicroDescriptor* task) @@ -84,6 +150,8 @@ static void _dealloc_task_cb(struct TaskMicroDescriptor* task) return; } + _task_retrieve_sys_resources(task); + // stack is mapped in vspace, so it should be free by pgdir if (task->pgdir.pd_addr) { xizi_pager.free_user_pgdir(&task->pgdir); @@ -92,25 +160,22 @@ static void _dealloc_task_cb(struct TaskMicroDescriptor* task) kfree((char*)task->main_thread.stack_addr); } - struct double_list_node* cur_node = &task->node; // remove it from used task list - doubleListDel(cur_node); + task_node_leave_list(task); // free task back to allocator - slab_free(&xizi_task_manager.task_allocator, (void*)task); - xizi_task_manager.nr_pcb_used -= 1; - - // remove priority - if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[task->priority])) { - ready_task_priority &= ~(1 << task->priority); + if (task->massive_ipc_allocator != NULL) { + KBuddyDestory(task->massive_ipc_allocator); + slab_free(&xizi_task_manager.task_buddy_allocator, (void*)task->massive_ipc_allocator); } + slab_free(&xizi_task_manager.task_allocator, (void*)task); } /* alloc a new task with init */ extern void trap_return(void); -void task_prepare_enter() +__attribute__((optimize("O0"))) void task_prepare_enter() { - spinlock_unlock(&whole_kernel_lock); + xizi_leave_kernel(); trap_return(); } @@ -122,10 +187,7 @@ static struct TaskMicroDescriptor* _new_task_cb() return NULL; } // init vm - if (!xizi_pager.new_pgdir(&task->pgdir)) { - _dealloc_task_cb(task); - return NULL; - } + task->pgdir.pd_addr = NULL; /* init basic task member */ doubleListNodeInit(&task->cli_sess_listhead); doubleListNodeInit(&task->svr_sess_listhead); @@ -155,15 +217,21 @@ static struct TaskMicroDescriptor* _new_task_cb() return task; } -static void _task_set_default_schedule_attr(struct TaskMicroDescriptor* task, struct TraceTag* cwd) +static void _task_set_default_schedule_attr(struct TaskMicroDescriptor* task) { task->remain_tick = TASK_CLOCK_TICK; task->maxium_tick = TASK_CLOCK_TICK * 10; task->state = READY; - task->cwd = *cwd; task->priority = TASK_DEFAULT_PRIORITY; - doubleListAddOnHead(&task->node, &xizi_task_manager.task_list_head[task->priority]); - ready_task_priority |= (1 << task->priority); + task_node_add_to_ready_list_head(task); +} + +static void task_state_set_running(struct TaskMicroDescriptor* task) +{ + assert(task != NULL && task->state == READY); + task->state = RUNNING; + task_node_leave_list(task); + doubleListAddOnHead(&task->node, &xizi_task_manager.task_running_list_head); } struct TaskMicroDescriptor* next_task_emergency = NULL; @@ -172,66 +240,77 @@ static void _scheduler(struct SchedulerRightGroup right_group) { struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag); struct TaskMicroDescriptor* next_task; + struct CPU* cpu = cur_cpu(); - spinlock_lock(&whole_kernel_lock); while (1) { next_task = NULL; /* find next runnable task */ assert(cur_cpu()->task == NULL); - if (next_task_emergency != NULL) { + if (next_task_emergency != NULL && next_task_emergency->state == READY) { next_task = next_task_emergency; - next_task->state = RUNNING; - next_task_emergency = NULL; } else { next_task = xizi_task_manager.next_runnable_task(); } - spinlock_unlock(&whole_kernel_lock); + next_task_emergency = NULL; - /* not a runnable task */ - if (UNLIKELY(next_task == NULL) || UNLIKELY(next_task->state != RUNNING)) { - spinlock_lock(&whole_kernel_lock); + /* if there's not a runnable task, wait for one */ + if (next_task == NULL) { + xizi_leave_kernel(); + // there is no task to run, into low power mode + cpu_into_low_power(); + + /* leave kernel for other cores, so they may create a runnable task */ + xizi_enter_kernel(); + // activate cpu + cpu_leave_low_power(); continue; } - /* a runnable task */ - spinlock_lock(&whole_kernel_lock); - struct CPU* cpu = cur_cpu(); + /* run the chosen task */ + task_state_set_running(next_task); cpu->task = next_task; p_mmu_driver->LoadPgdir((uintptr_t)V2P(next_task->pgdir.pd_addr)); context_switch(&cpu->scheduler, next_task->main_thread.context); + assert(next_task->state != RUNNING); } } -static uint32_t yield_cnt = 0; -static void _cur_task_yield_noschedule(void) +static void _task_yield_noschedule(struct TaskMicroDescriptor* task, bool blocking) { - yield_cnt++; - - struct TaskMicroDescriptor* current_task = cur_cpu()->task; - assert(current_task != NULL); + assert(task != NULL); + /// @warning only support current task yield now + assert(task == cur_cpu()->task && task->state == RUNNING); // rearrage current task position - doubleListDel(¤t_task->node); - // DEBUG("%s,%d\n", current_task->name, strcmp(current_task->name, name1)); - if (current_task->maxium_tick <= 0) { - if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[current_task->priority])) { - ready_task_priority &= ~(1 << current_task->priority); - } - current_task->priority += 1; - current_task->maxium_tick = TASK_CLOCK_TICK * 10; + task_node_leave_list(task); + if (task->state == RUNNING) { + task->state = READY; } - doubleListAddOnBack(¤t_task->node, &xizi_task_manager.task_list_head[current_task->priority]); - ready_task_priority |= (1 << current_task->priority); - // set current task state - current_task->state = READY; - current_task->remain_tick = TASK_CLOCK_TICK; + task->remain_tick = TASK_CLOCK_TICK; cur_cpu()->task = NULL; - if (yield_cnt == 50) { - recover_priority(); - yield_cnt = 0; - } + task_node_add_to_ready_list_back(task); } +static void _task_block(struct TaskMicroDescriptor* task) +{ + assert(task != NULL); + assert(task->state != RUNNING); + task_node_leave_list(task); + task->state = BLOCKED; + doubleListAddOnHead(&task->node, &xizi_task_manager.task_blocked_list_head); +} + +static void _task_unblock(struct TaskMicroDescriptor* task) +{ + assert(task != NULL); + assert(task->state == BLOCKED); + task_node_leave_list(task); + task->state = READY; + task_node_add_to_ready_list_head(task); +} + +/// @brief @warning not tested function +/// @param priority static void _set_cur_task_priority(int priority) { if (priority < 0 || priority >= TASK_MAX_PRIORITY) { @@ -240,14 +319,13 @@ static void _set_cur_task_priority(int priority) } struct TaskMicroDescriptor* current_task = cur_cpu()->task; - assert(current_task != NULL); + assert(current_task != NULL && current_task->state == RUNNING); + + task_node_leave_list(current_task); current_task->priority = priority; - doubleListDel(¤t_task->node); - doubleListAddOnBack(¤t_task->node, &xizi_task_manager.task_list_head[current_task->priority]); - - ready_task_priority |= (1 << current_task->priority); + task_node_add_to_ready_list_back(current_task); return; } @@ -260,7 +338,10 @@ struct XiziTaskManager xizi_task_manager = { .next_runnable_task = max_priority_runnable_task, .task_scheduler = _scheduler, - .cur_task_yield_noschedule = _cur_task_yield_noschedule, + + .task_block = _task_block, + .task_unblock = _task_unblock, + .task_yield_noschedule = _task_yield_noschedule, .set_cur_task_priority = _set_cur_task_priority }; diff --git a/Ubiquitous/XiZi_AIoT/softkernel/trap/Makefile b/Ubiquitous/XiZi_AIoT/softkernel/trap/Makefile index 9fef57c16..0a795948d 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/trap/Makefile +++ b/Ubiquitous/XiZi_AIoT/softkernel/trap/Makefile @@ -1,6 +1,7 @@ SRC_FILES := default_irq_handler.c \ clock_irq_handler.c \ - software_irq_handler.c + software_irq_handler.c \ + abort_handler.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/softkernel/trap/abort_handler.c b/Ubiquitous/XiZi_AIoT/softkernel/trap/abort_handler.c new file mode 100644 index 000000000..af806507a --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/softkernel/trap/abort_handler.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2006-2018 Frans Kaashoek, Robert Morris, Russ Cox, + * Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +/** + * @file abort_handler.c + * @brief handle program abort + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2023.11.23 + */ + +/************************************************* +File name: abort_handler.c +Description: handle program abort +Others: +History: +1. Date: 2023-11-23 +Author: AIIT XUOS Lab +Modification: +1. Modify iabort and dabort handler(in dabort_handler() and iabort_handler()) +*************************************************/ +#include "core.h" +#include "memlayout.h" +#include "spinlock.h" +#include "trap_common.h" + +#include "assert.h" +#include "multicores.h" +#include "syscall.h" +#include "task.h" + +extern void context_switch(struct context**, struct context*); +__attribute__((optimize("O0"))) void dabort_handler(struct trapframe* r) +{ + if (r->pc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) { + assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock)); + ERROR("dabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name); + dabort_reason(r); + panic("data abort exception\n"); + } + + struct TaskMicroDescriptor* cur_task = cur_cpu()->task; + ERROR("dabort in user space: %s\n", cur_task->name); + dabort_reason(r); + + xizi_enter_kernel(); + sys_exit(cur_task); + assert(cur_cpu()->task == NULL); + context_switch(&cur_task->main_thread.context, cur_cpu()->scheduler); + panic("dabort end should never be reashed.\n"); +} + +__attribute__((optimize("O0"))) void iabort_handler(struct trapframe* r) +{ + if (r->pc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) { + assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock)); + ERROR("iabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name); + iabort_reason(r); + panic("kernel prefetch abort exception\n"); + } + + struct TaskMicroDescriptor* cur_task = cur_cpu()->task; + ERROR("iabort in user space: %s\n", cur_task->name); + iabort_reason(r); + + xizi_enter_kernel(); + sys_exit(cur_task); + assert(cur_cpu()->task == NULL); + context_switch(&cur_task->main_thread.context, cur_cpu()->scheduler); + panic("iabort end should never be reashed.\n"); +} diff --git a/Ubiquitous/XiZi_AIoT/softkernel/trap/clock_irq_handler.c b/Ubiquitous/XiZi_AIoT/softkernel/trap/clock_irq_handler.c index b3453dd2c..6c4c92915 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/trap/clock_irq_handler.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/trap/clock_irq_handler.c @@ -58,7 +58,7 @@ int xizi_clock_handler(int irq, void* tf, void* arg) current_task->remain_tick--; current_task->maxium_tick--; if (current_task->remain_tick == 0) { - xizi_task_manager.cur_task_yield_noschedule(); + xizi_task_manager.task_yield_noschedule(current_task, false); } } } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/trap/default_irq_handler.c b/Ubiquitous/XiZi_AIoT/softkernel/trap/default_irq_handler.c index ad0aa6d40..a475c0810 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/trap/default_irq_handler.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/trap/default_irq_handler.c @@ -46,54 +46,72 @@ bool intr_distributer_init(struct IrqDispatcherRightGroup* _right_group) return p_intr_driver != NULL; } -void default_interrupt_routine(void) +void default_interrupt_routine(int irq) { /* default handler borrow the rights of dispatcher */ ///@todo Support other cores. (currently assume that CPU_0 is used) - ERROR("Interrupt %d has been asserted\n", p_intr_driver->curr_int[0]); + ERROR("Interrupt %d has been asserted\n", irq); } extern void context_switch(struct context**, struct context*); void intr_irq_dispatch(struct trapframe* tf) { - assert(p_intr_driver != NULL); - - p_intr_driver->cpu_irq_disable(); + xizi_enter_kernel(); // enter irq + assert(p_intr_driver != NULL); uintptr_t int_info = 0; if ((int_info = p_intr_driver->hw_before_irq()) == 0) { - return; + goto intr_leave_interrupt; } - spinlock_lock(&whole_kernel_lock); struct TaskMicroDescriptor* current_task = cur_cpu()->task; - if (LIKELY(current_task != NULL)) { - current_task->main_thread.trapframe = tf; - } + assert(current_task != NULL); + current_task->main_thread.trapframe = tf; - unsigned cpu = p_intr_driver->hw_cur_int_cpu(int_info); + int cpu = cur_cpuid(); + assert(cpu >= 0 && cpu < NR_CPU); unsigned irq = p_intr_driver->hw_cur_int_num(int_info); - p_intr_driver->curr_int[cpu] = irq; // distribute irq irq_handler_t isr = p_intr_driver->sw_irqtbl[irq].handler; - if (isr) { + if (isr != NULL) { isr(irq, tf, NULL); } else { - default_interrupt_routine(); + default_interrupt_routine(irq); } // finish irq. - p_intr_driver->curr_int[cpu] = 0; p_intr_driver->hw_after_irq(int_info); - if ((cur_cpu()->task == NULL && current_task != NULL) || current_task->state != RUNNING) { + if (cur_cpu()->task == NULL || current_task->state != RUNNING) { cur_cpu()->task = NULL; context_switch(¤t_task->main_thread.context, cur_cpu()->scheduler); } assert(current_task == cur_cpu()->task); - spinlock_unlock(&whole_kernel_lock); - p_intr_driver->cpu_irq_enable(); +intr_leave_interrupt: + xizi_leave_kernel(); +} + +__attribute__((always_inline)) inline void xizi_enter_kernel() +{ + /// @warning trampoline is responsible for closing interrupt + spinlock_lock(&whole_kernel_lock); +} + +__attribute__((always_inline)) inline bool xizi_try_enter_kernel() +{ + /// @warning trampoline is responsible for closing interrupt + if (spinlock_try_lock(&whole_kernel_lock)) { + return true; + } + + return false; +} + +__attribute__((always_inline)) inline void xizi_leave_kernel() +{ + /// @warning trampoline is responsible for eabling interrupt by using user's state register + spinlock_unlock(&whole_kernel_lock); } diff --git a/Ubiquitous/XiZi_AIoT/softkernel/trap/software_irq_handler.c b/Ubiquitous/XiZi_AIoT/softkernel/trap/software_irq_handler.c index f462c44e0..dce844139 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/trap/software_irq_handler.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/trap/software_irq_handler.c @@ -48,12 +48,9 @@ bool swi_distributer_init(struct SwiDispatcherRightGroup* _right_group) extern void context_switch(struct context**, struct context*); void software_irq_dispatch(struct trapframe* tf) { - + xizi_enter_kernel(); assert(p_intr_driver != NULL); - p_intr_driver->cpu_irq_disable(); - spinlock_lock(&whole_kernel_lock); - // get current task struct TaskMicroDescriptor* cur_task = cur_cpu()->task; /// @todo: Handle dead task @@ -74,11 +71,10 @@ void software_irq_dispatch(struct trapframe* tf) cur_cpu()->task = NULL; context_switch(&cur_task->main_thread.context, cur_cpu()->scheduler); } - assert(cur_task == cur_cpu()->task); if (syscall_num == SYSCALL_EXIT) { panic("Exit reaches"); } - spinlock_unlock(&whole_kernel_lock); - p_intr_driver->cpu_irq_enable(); + assert(cur_task == cur_cpu()->task); + xizi_leave_kernel(); } \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c index 1f36ec74a..56a17b24a 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c @@ -28,6 +28,7 @@ * @date 2022-08-08 */ #include "ch32v30x.h" +#include "connect_can.h" #include "connect_ether.h" #include "connect_uart.h" #include "core_riscv.h" @@ -57,24 +58,27 @@ static uint32_t _SysTick_Config(uint32_t ticks) /** * This function will initial your board. */ + void InitBoardHardware() { - USART_Printf_Init(115200); - /* System Tick Configuration */ _SysTick_Config(SystemCoreClock / TICK_PER_SECOND); /* initialize memory system */ InitBoardMemory(MEMORY_START_ADDRESS, (void*)MEMORY_END_ADDRESS); InitHwUart(); - InstallConsole("uart1", "uart1_drv", "uart1_dev1"); +#ifdef BSP_USING_UART4 + InstallConsole("uart4", "uart4_drv", "uart4_dev4"); +#endif #ifdef BSP_USING_ETH InitHwEth(); #endif +#ifdef BSP_USING_CAN + InitHwCan(); +#endif + KPrintf("consle init completed.\n"); KPrintf("board initialization......\n"); - // KPrintf("memory address range: [0x%08x - 0x%08x], size: %d\n", (x_ubase) MEMORY_START_ADDRESS, (x_ubase) MEMORY_END_ADDRESS, gd32vf103_SRAM_SIZE); - /* initialize memory system */ KPrintf("board init done.\n"); KPrintf("start okernel...\n"); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig index 64a20aaa9..2d37f65b0 100755 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig @@ -19,4 +19,23 @@ menuconfig BSP_USING_ETH bool "Using Ethernet" default y - \ No newline at end of file +menuconfig BSP_USING_CAN + bool "Using CAN device" + default y + select RESOURCES_CAN + if BSP_USING_CAN + source "$BSP_DIR/third_party_driver/can/Kconfig" + endif + + +menuconfig BSP_USING_USB + bool "Using USB device" + default y + select BSP_USING_USBH + select RESOURCES_USB + select RESOURCES_USB_HOST + select USBH_MSTORAGE + select RESOURCES_USB_DEVICE + if BSP_USING_USB + source "$BSP_DIR/third_party_driver/usb/Kconfig" + endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile index 7167d1e93..df748c38d 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile @@ -13,4 +13,12 @@ ifeq ($(CONFIG_BSP_USING_ETH),y) SRC_DIR += ethernet endif +ifeq ($(CONFIG_BSP_USING_CAN),y) + SRC_DIR += can +endif + +ifeq ($(CONFIG_BSP_USING_USB),y) + SRC_DIR += usb +endif + include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Kconfig new file mode 100755 index 000000000..34fb7d247 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Kconfig @@ -0,0 +1,11 @@ +config CAN_BUS_NAME_1 + string "can bus name" + default "can1" + +config CAN_DRIVER_NAME + string "can driver name" + default "can1_drv" + +config CAN_1_DEVICE_NAME_1 + string "can bus 1 device 1 name" + default "can1_dev1" \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Makefile new file mode 100755 index 000000000..f3fd6ea31 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Makefile @@ -0,0 +1,4 @@ +SRC_FILES := connect_can.c +SRC_DIR := test + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/connect_can.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/connect_can.c new file mode 100644 index 000000000..403eb42df --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/connect_can.c @@ -0,0 +1,249 @@ + +#include +#include +#include +#include + +static struct CanSendConfigure can_send_deconfig = +{ + .stdid = 0x12, + .exdid = 0x12, + .ide = 0 , + .rtr = 0, + .data_lenth = 8 +}; + +static void CanGPIOInit(void) +{ + CAN_FilterInitTypeDef can1_filter; + GPIO_InitTypeDef gpio_initstructure; + CAN_InitTypeDef can_initstruction; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOB, ENABLE); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); + + GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE); + + gpio_initstructure.GPIO_Pin = GPIO_Pin_9; + gpio_initstructure.GPIO_Mode = GPIO_Mode_AF_PP; + gpio_initstructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init( GPIOB, &gpio_initstructure); + + gpio_initstructure.GPIO_Pin = GPIO_Pin_8; + gpio_initstructure.GPIO_Mode = GPIO_Mode_IPU; + GPIO_Init( GPIOB, &gpio_initstructure); +} + +static void Can1NvicConfig(void) +{ + NVIC_InitTypeDef can_nvic_config; + + can_nvic_config.NVIC_IRQChannel = CAN1_RX1_IRQn; + can_nvic_config.NVIC_IRQChannelPreemptionPriority = 2; + can_nvic_config.NVIC_IRQChannelSubPriority = 2; + can_nvic_config.NVIC_IRQChannelCmd = ENABLE; + CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); + NVIC_Init(&can_nvic_config); +} + +static uint32 CanModeInit(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + CAN_FilterInitTypeDef can1_filter; + CAN_InitTypeDef can_initstruction; + + struct CanDriverConfigure *config = ( struct CanDriverConfigure *)configure_info->private_data; + + can_initstruction.CAN_TTCM = DISABLE; + can_initstruction.CAN_ABOM = DISABLE; + can_initstruction.CAN_AWUM = DISABLE; + can_initstruction.CAN_NART = ENABLE; + can_initstruction.CAN_TXFP = DISABLE; + can_initstruction.CAN_Mode = config->mode; + can_initstruction.CAN_RFLM = DISABLE; + can_initstruction.CAN_SJW = config->tsjw; + can_initstruction.CAN_BS1 = config->tbs1; + can_initstruction.CAN_BS2 = config->tbs2; + can_initstruction.CAN_Prescaler = config->brp; + + CAN_Init(CAN1, &can_initstruction); + + can1_filter.CAN_FilterNumber=0; + can1_filter.CAN_FilterMode=CAN_FilterMode_IdMask; + can1_filter.CAN_FilterScale=CAN_FilterScale_32bit; + can1_filter.CAN_FilterIdHigh=0x0000; + can1_filter.CAN_FilterIdLow=0x0000; + can1_filter.CAN_FilterMaskIdHigh=0x0000; + can1_filter.CAN_FilterMaskIdLow=0x0006; + can1_filter.CAN_FilterFIFOAssignment=CAN_Filter_FIFO1; + can1_filter.CAN_FilterActivation=ENABLE; + CAN_FilterInit(&can1_filter); + + #ifdef CAN_USING_INTERRUPT + Can1NvicConfig(); + #endif + + return 0; +} + +static uint32 CanSendMsg(void * dev , struct BusBlockWriteParam *write_param ) +{ + NULL_PARAM_CHECK(write_param); + + uint8 *data = (uint8 * ) write_param->buffer; + u8 messege_box; + u16 i = 0; + u16 timer_count = 1000; + CanTxMsg tx_data; + tx_data.StdId = 0x55; + tx_data.ExtId = 0x00; + tx_data.IDE = 0; + tx_data.RTR = 0; + tx_data.DLC = write_param->size; + + for(i = 0;i < tx_data.DLC;i ++) { + tx_data.Data[i] = data[i]; + } + + messege_box = CAN_Transmit(CAN1,&tx_data); + + while (CAN_TransmitStatus(CAN1,messege_box)== CAN_TxStatus_Failed &&timer_count) { + timer_count--; + } + + if (timer_count<=0) { + return ERROR; + } + return EOK; +} + +static uint32 CanRecvMsg(void *dev , struct BusBlockReadParam *databuf) +{ + NULL_PARAM_CHECK(dev); + int i; + uint8 * buf = (uint8 *)databuf->buffer; + CanRxMsg msg; + if (CAN_MessagePending(CAN1, CAN_FIFO0) == 0) + return 0; + CAN_Receive(CAN1, CAN_FIFO0, &msg); + for(i = 0 ;i < msg.DLC;i ++) + buf[i] = msg.Data[i]; + databuf->size = msg.DLC ; + + return msg.DLC; +} + +static struct CanDevDone dev_done = +{ + .open = NONE, + .close = NONE, + .write = CanSendMsg, + .read = CanRecvMsg +}; + +static struct CanHardwareDevice dev; + +#ifdef CAN_USING_INTERRUPT +void CAN1_RX0_IRQHandler(void) +{ + CanRxMsg rxmsg; + int i = 0; + CAN_Receive(CAN1, 0, &rxmsg); + for (i = 0;i < 8;i ++) + KPrintf("rxbuf [%d] = :%d",i,rxmsg.Data[i]); +} +DECLARE_HW_IRQ(CAN1_RX0_IRQn, CAN1_RX0_IRQHandler, NONE); +#endif + +static int BoardCanBusInit(struct CanDev *CanDev_bus, struct CanDriver *can_driver) +{ + x_err_t ret = EOK; + + /*Init the can bus */ + ret = CanBusInit(&CanDev_bus->can_bus, CanDev_bus->bus_name); + if (EOK != ret) { + KPrintf("Board_can_init canBusInit error %d\n", ret); + return ERROR; + } + + /*Init the can driver*/ + ret = CanDriverInit(can_driver, CAN_DRIVER_NAME); + if (EOK != ret) { + KPrintf("Board_can_init canDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the can driver to the can bus*/ + ret = CanDriverAttachToBus(CAN_DRIVER_NAME, CanDev_bus->bus_name); + if (EOK != ret) { + KPrintf("Board_can_init CanDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +static x_err_t HwCanDeviceAttach(const char *bus_name, const char *device_name) +{ + NULL_PARAM_CHECK(bus_name); + NULL_PARAM_CHECK(device_name); + + x_err_t result; + struct CanHardwareDevice *can_device; + + /* attach the device to can bus*/ + can_device = (struct CanHardwareDevice *)x_malloc(sizeof(struct CanHardwareDevice)); + CHECK(can_device); + memset(can_device, 0, sizeof(struct CanHardwareDevice)); + can_device->dev_done = &dev_done; + + result = CanDeviceRegister(can_device, NONE, device_name); + if (EOK != result) { + KPrintf("board_can_init canDeviceInit device %s error %d\n", "can1", result); + return ERROR; + } + + result = CanDeviceAttachToBus(device_name, bus_name); + if (result != EOK) { + SYS_ERR("%s attach to %s faild, %d\n", device_name, bus_name, result); + } + + CHECK(result == EOK); + + KPrintf("%s attach to %s done\n", device_name, bus_name); + + return result; +} + +struct CanDev can1; + +int InitHwCan(void) +{ + x_err_t ret = EOK; + struct CanDev *can_bus; + + static struct CanDriver can_driver; + memset(&can_driver, 0, sizeof(struct CanDriver)); + can_driver.configure = CanModeInit; + + CanGPIOInit(); + can_bus = &can1; + can_bus->instance = CAN1; + can_bus->bus_name = CAN_BUS_NAME_1; + can_bus->can_bus.private_data = &can1; + + ret = BoardCanBusInit(can_bus, &can_driver); + + if (EOK != ret) { + KPrintf(" can_bus_init %s error ret %u\n", can_bus->bus_name, ret); + return ERROR; + } + + ret = HwCanDeviceAttach(CAN_BUS_NAME_1,CAN_1_DEVICE_NAME_1); + if (EOK != ret) { + KPrintf(" HwCanDeviceAttach %s error ret %u\n", can_bus->bus_name, ret); + return ERROR; + } + return EOK; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/Makefile new file mode 100755 index 000000000..44c989594 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/Makefile @@ -0,0 +1,4 @@ +SRC_FILES := can_test.c + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/can_test.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/can_test.c new file mode 100644 index 000000000..bc06a10a8 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/can_test.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file can_test.c + * @brief test ch32v307 can + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2024-03-14 + */ +#include "shell.h" +#include "ch32v30x.h" +#include "connect_can.h" +#include +#include +#include + +static int init_can() +{ + KPrintf("init can\r\n"); + + CAN_FilterInitTypeDef can1_filter; + CAN_InitTypeDef can_initstruction; + + can_initstruction.CAN_TTCM = DISABLE; + can_initstruction.CAN_ABOM = DISABLE; + can_initstruction.CAN_AWUM = DISABLE; + can_initstruction.CAN_NART = ENABLE; + can_initstruction.CAN_TXFP = DISABLE; + can_initstruction.CAN_Mode = CAN_Mode_Silent_LoopBack; + can_initstruction.CAN_RFLM = DISABLE; + can_initstruction.CAN_SJW = CAN_SJW_1tq; + can_initstruction.CAN_BS1 = CAN_BS1_6tq; + can_initstruction.CAN_BS2 = CAN_BS2_5tq; + can_initstruction.CAN_Prescaler = 12; + CAN_Init(CAN1, &can_initstruction); + + can1_filter.CAN_FilterNumber = 0; + can1_filter.CAN_FilterMode = CAN_FilterMode_IdMask; + can1_filter.CAN_FilterScale = CAN_FilterScale_32bit; + can1_filter.CAN_FilterIdHigh = 0x0000; + can1_filter.CAN_FilterIdLow = 0x0000; + can1_filter.CAN_FilterMaskIdHigh = 0x0000; + can1_filter.CAN_FilterMaskIdLow = 0x0006; + can1_filter.CAN_FilterFIFOAssignment = CAN_Filter_FIFO1; + can1_filter.CAN_FilterActivation = ENABLE; + CAN_FilterInit(&can1_filter); + + return 0; +} + +static u8 CAN_Send_Msg(u8 *msg, u8 len) +{ + u8 mbox; + u16 i = 0; + + CanTxMsg CanTxStructure; + + CanTxStructure.StdId = 0x317; + CanTxStructure.IDE = CAN_Id_Standard; + CanTxStructure.RTR = CAN_RTR_Data; + CanTxStructure.DLC = len; + + for (i = 0; i < len; i++) + { + CanTxStructure.Data[i] = msg[i]; + } + + mbox = CAN_Transmit(CAN1, &CanTxStructure); + + i = 0; + + while ((CAN_TransmitStatus(CAN1, mbox) != CAN_TxStatus_Ok) && (i < 0xFFF)) + { + i++; + } + + if (i == 0xFFF) + { + return 1; + } + else + { + return 0; + } +} + +static u8 CAN_Receive_Msg(u8 *buf) +{ + u8 i; + + CanRxMsg CanRxStructure; + + if (CAN_MessagePending(CAN1, CAN_FIFO1) == 0) + { + return 0; + } + + CAN_Receive(CAN1, CAN_FIFO1, &CanRxStructure); + + for (i = 0; i < 8; i++) + { + buf[i] = CanRxStructure.Data[i]; + } + + return CanRxStructure.DLC; +} + +int test_can(int argc, char *argv[]) +{ + u8 i; + u8 cnt = 0; + u8 tx, rx; + u8 txbuf[8]; + u8 rxbuf[8]; + init_can(); + + for (i = 0; i < 8; i++) + { + txbuf[i] = cnt + i; + } + tx = CAN_Send_Msg(txbuf, 8); + + if (tx) + { + KPrintf("CAN1 Send Failed\r\n"); + } + else + { + KPrintf("CAN1 Send Success\r\n"); + KPrintf("CAN1 Send Data:\r\n"); + + for (i = 0; i < 8; i++) + { + KPrintf("%02x\r\n", txbuf[i]); + } + } + + rx = CAN_Receive_Msg(rxbuf); + + if (rx) + { + KPrintf("CAN1 Receive Data:\r\n"); + + for (i = 0; i < 8; i++) + { + KPrintf("%02x\r\n", txbuf[i]); + } + } + else + { + KPrintf("CAN1 No Receive Data\r\n"); + } + + cnt++; + if (cnt == 0xFF) + { + cnt = 0; + } + + return 0; +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + test_can, test_can, test CAN); \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/readme.md b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/readme.md new file mode 100644 index 000000000..6f7d829d3 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/test/readme.md @@ -0,0 +1,55 @@ + +0.该测试在Ubiquitous中测试通过(将驱动中静态的收发初始化操作在测试文件中实现),在APP_Framework的测试中BusFind,BusFindDriver,BusFindDevice可找到相应的设备,但无法通过其进行读写等操作 + +``` +// APP_Framework/Applications/main.c + +#include +#include +#include +#include +#define CAN_BUS "can1" + +#define CAN_DRIVER "can1_drv" + +#define CAN_DEVICE "can1_dev1" + +void TestCAN(void) +{ + KPrintf("Test can start\n"); + struct Bus *bus; + struct HardwareDev *dev; + struct Driver *drv; + char test_str[] = "Hello AIIT!\r\n"; + /* find the serial bus pointer */ + bus = BusFind(CAN_BUS); + if (NONE == bus) + { + KPrintf("BusFind %s failed\n", CAN_BUS); + return; + } + /* find the serial driver pointer */ + drv = BusFindDriver(bus, CAN_DRIVER); + if (NONE == drv) + { + KPrintf("BusFindDriver %s failed\n", CAN_DRIVER); + return; + } + /* find the serial device pointer */ + dev = BusFindDevice(bus, CAN_DEVICE); + if (NONE == dev) + { + KPrintf("BusFindDevice %s failed\n", CAN_DEVICE); + return; + } +} + +PRIV_SHELL_CMD_FUNCTION(TestCAN, a can test sample, PRIV_SHELL_CMD_MAIN_ATTR); +``` + +1.make BOARD=ch32v307vct6 menuconfig中配置can相关参数 ch32v307vct6 feature ---> Using CAN device ---> + +2.在can_test.c中can_initstruction.CAN_Mode表示can的收发模式,修改该参数可实现不同的收发方式,有CAN_Mode_Normal,CAN_Mode_LoopBack,CAN_Mode_Silent,CAN_Mode_Silent_LoopBack四种模式,此处用CAN_Mode_Silent_LoopBack该模式,实现自收自发,如果需要通过主机收发可修改为CAN_Mode_Normal + +3.编译后将其烧录至开发板上,执行test_can命令,运行can测试。 + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_can.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_can.h new file mode 100644 index 000000000..0c5d64a12 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_can.h @@ -0,0 +1,33 @@ + + + + + + +#ifndef CONNECT_CAN_H +#define CONNECT_CAN_H + + +#include +#include + + +#include +#include + + +struct CanDev +{ + CAN_TypeDef *instance; + + char *bus_name; + + // CAN_InitTypeDef init; + + uint8 can_flag; + struct CanBus can_bus; +}; + +int InitHwCan(void); + +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_usb.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_usb.h new file mode 100644 index 000000000..fba9fffa3 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_usb.h @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_usb.h +* @brief define aiit-arm32-board usb function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_USB_H +#define CONNECT_USB_H + + +#include +#include +#ifdef RESOURCES_USB_HOST +#ifdef BSP_USING_USBH +#include +#endif +#endif + + + + +#ifdef __cplusplus +extern "C" { +#endif + +int InitHwUsb(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Kconfig index 54c333882..6ddc3f577 100755 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Kconfig @@ -1,6 +1,6 @@ menuconfig BSP_USING_UART1 bool "Enable UART1" - default y + default n if BSP_USING_UART1 config SERIAL_BUS_NAME_1 string "serial bus name" @@ -12,3 +12,48 @@ menuconfig BSP_USING_UART1 string "serial bus device name" default "uart1_dev1" endif + +menuconfig BSP_USING_UART2 + bool "Enable UART2" + default n + if BSP_USING_UART2 + config SERIAL_BUS_NAME_2 + string "serial bus name" + default "uart2" + config SERIAL_DRV_NAME_2 + string "serial bus driver name" + default "uart2_drv" + config SERIAL_2_DEVICE_NAME_0 + string "serial bus device name" + default "uart2_dev2" + endif + +menuconfig BSP_USING_UART4 + bool "Enable UART4" + default y + if BSP_USING_UART4 + config SERIAL_BUS_NAME_4 + string "serial bus name" + default "uart4" + config SERIAL_DRV_NAME_4 + string "serial bus driver name" + default "uart4_drv" + config SERIAL_4_DEVICE_NAME_0 + string "serial bus device name" + default "uart4_dev4" + endif + +menuconfig BSP_USING_UART5 + bool "Enable UART5" + default y + if BSP_USING_UART5 + config SERIAL_BUS_NAME_5 + string "serial bus name" + default "uart5" + config SERIAL_DRV_NAME_5 + string "serial bus driver name" + default "uart5_drv" + config SERIAL_5_DEVICE_NAME_0 + string "serial bus device name" + default "uart5_dev5" + endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Makefile index d75c1d8bc..7f668b11e 100755 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/Makefile @@ -1,4 +1,4 @@ -SRC_FILES := connect_uart.c +SRC_FILES := connect_uart.c test_uart.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c index f36a7722d..7ed1fbf42 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c @@ -76,6 +76,7 @@ static void UartIsr(struct SerialDriver* serial_drv, struct SerialHardwareDevice static uint32 SerialInit(struct SerialDriver* serial_drv, struct BusConfigureInfo* configure_info) { + KPrintf("Serial init\n"); NULL_PARAM_CHECK(serial_drv); struct SerialCfgParam* serial_cfg = (struct SerialCfgParam*)serial_drv->private_data; // struct UsartHwCfg *serial_hw_cfg = (struct UsartHwCfg *)serial_cfg->hw_cfg.private_data; @@ -95,67 +96,6 @@ static uint32 SerialInit(struct SerialDriver* serial_drv, struct BusConfigureInf // config serial receive sem timeout dev_param->serial_timeout = serial_cfg->data_cfg.serial_timeout; - // init usart type def - GPIO_InitTypeDef GPIO_InitStructure; - - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); - - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_Init(GPIOA, &GPIO_InitStructure); - - USART_InitTypeDef USART_InitStructure; - USART_InitStructure.USART_BaudRate = serial_cfg->data_cfg.serial_baud_rate; - - switch (serial_cfg->data_cfg.serial_data_bits) { - case DATA_BITS_8: - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - break; - - case DATA_BITS_9: - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - break; - default: - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - break; - } - - switch (serial_cfg->data_cfg.serial_stop_bits) { - case STOP_BITS_1: - USART_InitStructure.USART_StopBits = USART_StopBits_1; - break; - case STOP_BITS_2: - USART_InitStructure.USART_StopBits = USART_StopBits_2; - break; - default: - USART_InitStructure.USART_StopBits = USART_StopBits_1; - break; - } - - switch (serial_cfg->data_cfg.serial_parity_mode) { - case PARITY_NONE: - USART_InitStructure.USART_Parity = USART_Parity_No; - break; - case PARITY_ODD: - USART_InitStructure.USART_Parity = USART_Parity_Odd; - break; - case PARITY_EVEN: - USART_InitStructure.USART_Parity = USART_Parity_Even; - break; - default: - USART_InitStructure.USART_Parity = USART_Parity_No; - break; - } - - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - - USART_Init(USART1, &USART_InitStructure); - USART_Cmd(USART1, ENABLE); - // usart_hardware_flow_rts_config(serial_cfg->hw_cfg.serial_register_base, USART_RTS_DISABLE); - // usart_hardware_flow_cts_config(serial_cfg->hw_cfg.serial_register_base, USART_CTS_DISABLE); - return EOK; } @@ -227,6 +167,17 @@ static int SerialGetChar(struct SerialHardwareDevice* serial_dev) } static const struct SerialDataCfg data_cfg_init = { + .serial_baud_rate = BAUD_RATE_9600, + .serial_data_bits = DATA_BITS_8, + .serial_stop_bits = STOP_BITS_1, + .serial_parity_mode = PARITY_NONE, + .serial_bit_order = BIT_ORDER_LSB, + .serial_invert_mode = NRZ_NORMAL, + .serial_buffer_size = SERIAL_RB_BUFSZ, + .serial_timeout = WAITING_FOREVER, +}; + +static const struct SerialDataCfg data_cfg_init_uart3 = { .serial_baud_rate = BAUD_RATE_115200, .serial_data_bits = DATA_BITS_8, .serial_stop_bits = STOP_BITS_1, @@ -317,10 +268,90 @@ void USART1_IRQHandler(void) } #endif +uint16_t UART_ReceiveData(USART_TypeDef* USARTx) +{ + return (uint16_t)(USARTx->DATAR & (uint16_t)0x01FF); +} + +void UART_SendData(USART_TypeDef* USARTx, uint16_t Data) +{ + USARTx->DATAR = (Data & (uint16_t)0x01FF); +} + +#ifdef BSP_USING_UART2 +struct SerialDriver serial_driver_2; +struct SerialHardwareDevice serial_device_2; + +#define TxSize2 100 +uint16_t RxBuffer2[TxSize2] = { 0 }; +uint16_t TxCnt2 = 0, RxCnt2 = 0; + +void USART3_IRQHandler(void) __attribute__((interrupt())); + +void USART3_IRQHandler(void) +{ + if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) { + RxBuffer2[RxCnt2++] = UART_ReceiveData(USART3); + + if (RxCnt2 == 100) { + USART_ITConfig(USART3, USART_IT_RXNE, DISABLE); + } + } +} +#endif + +#ifdef BSP_USING_UART4 +struct SerialDriver serial_driver_4; +struct SerialHardwareDevice serial_device_4; + +#define TxSize2 100 +uint16_t RxBuffer4[TxSize2] = { 0 }; +uint16_t TxCnt4 = 0, RxCnt4 = 0; + +void UART4_IRQHandler(void) __attribute__((interrupt())); + +void UART4_IRQHandler(void) +{ + GET_INT_SP(); + x_base level; + level = DisableLocalInterrupt(); + isrManager.done->incCounter(); + EnableLocalInterrupt(level); + UartIsr(&serial_driver_4, &serial_device_4); + level = DisableLocalInterrupt(); + isrManager.done->decCounter(); + EnableLocalInterrupt(level); + FREE_INT_SP(); +} +#endif + +#ifdef BSP_USING_UART5 +struct SerialDriver serial_driver_5; +struct SerialHardwareDevice serial_device_5; + +#define TxSize5 100 +uint16_t RxBuffer5[TxSize5] = { 0 }; +uint16_t TxCnt5 = 0, RxCnt5 = 0; + +void USART5_IRQHandler(void) __attribute__((interrupt())); + +void USART5_IRQHandler(void) +{ + if (USART_GetITStatus(UART5, USART_IT_RXNE) != RESET) { + RxBuffer5[RxCnt5++] = UART_ReceiveData(UART5); + if (RxCnt5 == 100) { + USART_ITConfig(UART5, USART_IT_RXNE, DISABLE); + } + } +} +#endif + + int InitHwUart(void) { x_err_t ret = EOK; +#ifdef BSP_USING_UART1 static struct SerialBus serial_bus; memset(&serial_bus, 0, sizeof(struct SerialBus)); @@ -340,10 +371,8 @@ int InitHwUart(void) serial_cfg.data_cfg = data_cfg_init; -#ifdef BSP_USING_UART1 serial_cfg.hw_cfg.serial_register_base = (uint32)USART1; serial_cfg.hw_cfg.serial_irq_interrupt = USART1_IRQn; -#endif serial_driver_1.private_data = (void*)&serial_cfg; @@ -374,7 +403,7 @@ int InitHwUart(void) GPIO_Init(GPIOA, &gpio_init_struct); USART_InitTypeDef usart_init_struct; - usart_init_struct.USART_BaudRate = 115200; + usart_init_struct.USART_BaudRate = 9600; usart_init_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; usart_init_struct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; usart_init_struct.USART_WordLength = USART_WordLength_8b; @@ -382,6 +411,199 @@ int InitHwUart(void) usart_init_struct.USART_Parity = USART_Parity_No; USART_Init((USART_TypeDef*)serial_cfg.hw_cfg.serial_register_base, &usart_init_struct); USART_Cmd((USART_TypeDef*)serial_cfg.hw_cfg.serial_register_base, ENABLE); +#endif + +#ifdef BSP_USING_UART2 + static struct SerialBus serial_bus_2; + memset(&serial_bus_2, 0, sizeof(struct SerialBus)); + + memset(&serial_driver_2, 0, sizeof(struct SerialDriver)); + + memset(&serial_device_2, 0, sizeof(struct SerialHardwareDevice)); + + static struct SerialCfgParam serial_cfg_2; + memset(&serial_cfg_2, 0, sizeof(struct SerialCfgParam)); + + static struct SerialDevParam serial_dev_param_2; + memset(&serial_dev_param_2, 0, sizeof(struct SerialDevParam)); + + serial_driver_2.drv_done = &drv_done; + serial_driver_2.configure = &SerialDrvConfigure; + serial_device_2.hwdev_done = &hwdev_done; + + serial_cfg_2.data_cfg = data_cfg_init; + + serial_cfg_2.hw_cfg.serial_register_base = (uint32)USART3; + serial_cfg_2.hw_cfg.serial_irq_interrupt = USART3_IRQn; + + serial_driver_2.private_data = (void*)&serial_cfg_2; + + serial_dev_param_2.serial_work_mode = SIGN_OPER_INT_RX; + serial_device_2.haldev.private_data = (void*)&serial_dev_param_2; + + ret = BoardSerialBusInit(&serial_bus_2, &serial_driver_2, SERIAL_BUS_NAME_2, SERIAL_DRV_NAME_2); + if (EOK != ret) { + KPrintf("InitHwUart 2 uarths error ret %u\n", ret); + return ERROR; + } + + ret = BoardSerialDevBend(&serial_device_2, (void*)&serial_cfg_2, SERIAL_BUS_NAME_2, SERIAL_2_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("InitHwUart 2 uarths error ret %u\n", ret); + return ERROR; + } + + GPIO_InitTypeDef gpio_init_struct_2; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); + // RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART3 | RCC_APB2Periph_GPIOB, ENABLE); + gpio_init_struct_2.GPIO_Pin = GPIO_Pin_10; + gpio_init_struct_2.GPIO_Speed = GPIO_Speed_50MHz; + gpio_init_struct_2.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_Init(GPIOB, &gpio_init_struct_2); + gpio_init_struct_2.GPIO_Pin = GPIO_Pin_11; + gpio_init_struct_2.GPIO_Speed = GPIO_Speed_50MHz; + gpio_init_struct_2.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(GPIOB, &gpio_init_struct_2); + + USART_InitTypeDef usart_init_struct_2; + usart_init_struct_2.USART_BaudRate = 9600; + usart_init_struct_2.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + usart_init_struct_2.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; + usart_init_struct_2.USART_WordLength = USART_WordLength_8b; + usart_init_struct_2.USART_StopBits = USART_StopBits_1; + usart_init_struct_2.USART_Parity = USART_Parity_No; + USART_Init((USART_TypeDef*)serial_cfg_2.hw_cfg.serial_register_base, &usart_init_struct_2); + USART_Cmd((USART_TypeDef*)serial_cfg_2.hw_cfg.serial_register_base, ENABLE); +#endif + +#ifdef BSP_USING_UART4 + static struct SerialBus serial_bus_4; + memset(&serial_bus_4, 0, sizeof(struct SerialBus)); + + memset(&serial_driver_4, 0, sizeof(struct SerialDriver)); + + memset(&serial_device_4, 0, sizeof(struct SerialHardwareDevice)); + + static struct SerialCfgParam serial_cfg_4; + memset(&serial_cfg_4, 0, sizeof(struct SerialCfgParam)); + + static struct SerialDevParam serial_dev_param_4; + memset(&serial_dev_param_4, 0, sizeof(struct SerialDevParam)); + + serial_driver_4.drv_done = &drv_done; + serial_driver_4.configure = &SerialDrvConfigure; + serial_device_4.hwdev_done = &hwdev_done; + + serial_cfg_4.data_cfg = data_cfg_init; + + serial_cfg_4.hw_cfg.serial_register_base = (uint32)UART4; + serial_cfg_4.hw_cfg.serial_irq_interrupt = UART4_IRQn; + + serial_driver_4.private_data = (void*)&serial_cfg_4; + + serial_dev_param_4.serial_work_mode = SIGN_OPER_INT_RX; + serial_device_4.haldev.private_data = (void*)&serial_dev_param_4; + + ret = BoardSerialBusInit(&serial_bus_4, &serial_driver_4, SERIAL_BUS_NAME_4, SERIAL_DRV_NAME_4); + if (EOK != ret) { + KPrintf("InitHwUart 4 uarths error ret %u\n", ret); + return ERROR; + } + + ret = BoardSerialDevBend(&serial_device_4, (void*)&serial_cfg_4, SERIAL_BUS_NAME_4, SERIAL_4_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("InitHwUart 4 uarths error ret %u\n", ret); + return ERROR; + } + + GPIO_InitTypeDef gpio_init_struct_4; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + + gpio_init_struct_4.GPIO_Pin = GPIO_Pin_10; + gpio_init_struct_4.GPIO_Speed = GPIO_Speed_50MHz; + gpio_init_struct_4.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_Init(GPIOC, &gpio_init_struct_4); + gpio_init_struct_4.GPIO_Pin = GPIO_Pin_11; + gpio_init_struct_4.GPIO_Speed = GPIO_Speed_50MHz; + gpio_init_struct_4.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(GPIOC, &gpio_init_struct_4); + + USART_InitTypeDef usart_init_struct_4; + usart_init_struct_4.USART_BaudRate = 9600; + usart_init_struct_4.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + usart_init_struct_4.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; + usart_init_struct_4.USART_WordLength = USART_WordLength_8b; + usart_init_struct_4.USART_StopBits = USART_StopBits_1; + usart_init_struct_4.USART_Parity = USART_Parity_No; + USART_Init((USART_TypeDef*)serial_cfg_4.hw_cfg.serial_register_base, &usart_init_struct_4); + USART_Cmd((USART_TypeDef*)serial_cfg_4.hw_cfg.serial_register_base, ENABLE); +#endif + +#ifdef BSP_USING_UART5 + static struct SerialBus serial_bus_5; + memset(&serial_bus_5, 0, sizeof(struct SerialBus)); + + memset(&serial_driver_5, 0, sizeof(struct SerialDriver)); + + memset(&serial_device_5, 0, sizeof(struct SerialHardwareDevice)); + + static struct SerialCfgParam serial_cfg_5; + memset(&serial_cfg_5, 0, sizeof(struct SerialCfgParam)); + + static struct SerialDevParam serial_dev_param_5; + memset(&serial_dev_param_5, 0, sizeof(struct SerialDevParam)); + + serial_driver_5.drv_done = &drv_done; + serial_driver_5.configure = &SerialDrvConfigure; + serial_device_5.hwdev_done = &hwdev_done; + + serial_cfg_5.data_cfg = data_cfg_init; + + serial_cfg_5.hw_cfg.serial_register_base = (uint32)UART5; + serial_cfg_5.hw_cfg.serial_irq_interrupt = UART5_IRQn; + + serial_driver_5.private_data = (void*)&serial_cfg_5; + + serial_dev_param_5.serial_work_mode = SIGN_OPER_INT_RX; + serial_device_5.haldev.private_data = (void*)&serial_dev_param_5; + + ret = BoardSerialBusInit(&serial_bus_5, &serial_driver_5, SERIAL_BUS_NAME_5, SERIAL_DRV_NAME_5); + if (EOK != ret) { + KPrintf("InitHwUart 5 uarths error ret %u\n", ret); + return ERROR; + } + + ret = BoardSerialDevBend(&serial_device_5, (void*)&serial_cfg_5, SERIAL_BUS_NAME_5, SERIAL_5_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("InitHwUart 5 uarths error ret %u\n", ret); + return ERROR; + } + + GPIO_InitTypeDef gpio_init_struct_5; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); + + gpio_init_struct_5.GPIO_Pin = GPIO_Pin_12; + gpio_init_struct_5.GPIO_Speed = GPIO_Speed_50MHz; + gpio_init_struct_5.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_Init(GPIOC, &gpio_init_struct_5); + gpio_init_struct_5.GPIO_Pin = GPIO_Pin_2; + gpio_init_struct_5.GPIO_Speed = GPIO_Speed_50MHz; + gpio_init_struct_5.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(GPIOD, &gpio_init_struct_5); + + USART_InitTypeDef usart_init_struct_5; + usart_init_struct_5.USART_BaudRate = 9600; + usart_init_struct_5.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + usart_init_struct_5.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; + usart_init_struct_5.USART_WordLength = USART_WordLength_8b; + usart_init_struct_5.USART_StopBits = USART_StopBits_1; + usart_init_struct_5.USART_Parity = USART_Parity_No; + USART_Init((USART_TypeDef*)serial_cfg_5.hw_cfg.serial_register_base, &usart_init_struct_5); + USART_Cmd((USART_TypeDef*)serial_cfg_5.hw_cfg.serial_register_base, ENABLE); +#endif return ret; -} \ No newline at end of file +} diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/linux_uart.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/linux_uart.c new file mode 100644 index 000000000..76b5540a6 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/linux_uart.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include + +int main() +{ + int fd; + struct termios tty; + char buffer[256]; + + // 打开串口设备 + fd = open("/dev/ttySC3", O_RDWR | O_NOCTTY); + if (fd == -1) { + perror("打开串口失败"); + return -1; + } + + // 获取当前串口配置 + if (tcgetattr(fd, &tty) != 0) { + perror("获取串口配置失败"); + close(fd); + return -1; + } + + // 设置波特率为9600 + cfsetispeed(&tty, B9600); + cfsetospeed(&tty, B9600); + + // 8位数据位,无校验位,1位停止位 + tty.c_cflag &= ~PARENB; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; + + // 非规范模式,禁止软件流控制 + tty.c_iflag &= ~(IXON | IXOFF | IXANY); + tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + + // 禁止输出回车换行和换行符的映射 + tty.c_oflag &= ~OPOST; + tty.c_oflag &= ~ONLCR; + + // 设置新的串口配置 + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + perror("设置串口配置失败"); + close(fd); + return -1; + } + + // 获取待读取数据的字节数 + int bytes_available; + printf("读取中\n"); + while (1) { + int res = ioctl(fd, TIOCINQ, &bytes_available); + + if (res != -1) { + if (bytes_available > 0) { + // 读取串口数据 + printf("read\n"); + int bytes_read = read(fd, buffer, sizeof(buffer)); + if (bytes_read > 0) { + // 在这里处理读取到的数据 + printf("读取到的数据: %s\n", buffer); + } + } + } + } + + // 关闭串口设备 + close(fd); + + return 0; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/Makefile new file mode 100755 index 000000000..7b33f7977 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/Makefile @@ -0,0 +1,4 @@ +SRC_FILES := rs485_test.c + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/readme.md b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/readme.md new file mode 100644 index 000000000..641ffc85f --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/readme.md @@ -0,0 +1,84 @@ +0.该测试在Ubiquitous中测试通过(将驱动中静态的收发操作在测试文件中实现),在APP_Framework的测试中BusFind,BusFindDriver,BusFindDevice可找到相应的设备,但无法通过其进行读写等操作 + +``` +// APP_Framework/Applications/main.c + +#include +#include +#include +#include +#define RS485_UART_BUS "uart5" +#define RS485_UART_DRV "uart5_drv" +#define RS485_UART_DEV "uart5_dev5" + +void Test485(void) +{ + /* + 485的驱动,使用UART5,在connect_uart.c中添加UART5的初始化,添加UART5的Kconfig,borad.c中使用InstallConsole用uart5串口正常输出控制台信息;在app_famework中加入app_test的485测试用例后出现 + + HardFault_Handler. + mepc :000f448 + mcause:0000007 + mtval :200100d4 + + 报错,控制台停止运行,最后将Test485用例摘出放置main.c中,发现将PrivOpen编译进bin就会报错(没有实际执行) + + 试了试busfind,bus,bus_drv,bus_dev都能找到,但是BusDevWriteData(dev, &write_param)编译进去后无法运行(OS无法起来/没有实际执行);Busdevclose导致程序崩溃 + + Test 485 start + [ERR][x_free] Freeing a unallocated address. + HardFault_Handler. + mepc :0000012 + mcause:0000002 + mtval :0000000 + + 在Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test测试中 + 可以通过485串口正常输出接收 + + */ + + KPrintf("Test 485 start\n"); + struct Bus *bus; + struct HardwareDev *dev; + struct Driver *drv; + char test_str[] = "Hello AIIT!\r\n"; + /* find the serial bus pointer */ + bus = BusFind(RS485_UART_BUS); + if (NONE == bus) + { + KPrintf("BusFind %s failed\n", RS485_UART_BUS); + return; + } + /* find the serial driver pointer */ + drv = BusFindDriver(bus, RS485_UART_DRV); + if (NONE == drv) + { + KPrintf("BusFindDriver %s failed\n", RS485_UART_DRV); + return; + } + /* find the serial device pointer */ + dev = BusFindDevice(bus, RS485_UART_DEV); + if (NONE == dev) + { + KPrintf("BusFindDevice %s failed\n", RS485_UART_DEV); + return; + } + struct BusBlockWriteParam write_param; + write_param.pos = 0; + write_param.buffer = (void *)test_str; + write_param.size = sizeof(test_str) - 1; + + // BusDevWriteData(dev, &write_param); + // BusDevClose(dev); + + return; +} + +PRIV_SHELL_CMD_FUNCTION(Test485, a 485 test sample, PRIV_SHELL_CMD_MAIN_ATTR); +``` + + +1.make BOARD=ch32v307vct6 menuconfig中配置UART相关参数 ch32v307vct6 feature ---> Enable UART5 ---> + +2.编译后将其烧录至开发板上,连接485转USB硬件至主机,主机使用串口工具打开执行test_rs485命令,运行485收发测试。 + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/rs485_test.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/rs485_test.c new file mode 100644 index 000000000..875e2ea8b --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test/rs485_test.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file rs485_test.c + * @brief test ch32v307 485 + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2024-03-14 + */ +#include "shell.h" +#include "ch32v30x.h" +#include "ch32v30x_usart.h" +#include "connect_uart.h" + +// UART5发送数据 +static void UART5_SendData(uint8_t data) +{ + // 等待发送缓冲区为空 + while (USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET) + { + } + + // 发送数据 + USART_SendData(UART5, data); +} + +// UART5接收数据 +static uint8_t UART5_ReceiveData(void) +{ + // 等待接收缓冲区非空 + while (USART_GetFlagStatus(UART5, USART_FLAG_RXNE) == RESET) + { + } + + // 读取接收数据 + return USART_ReceiveData(UART5); +} + +static void UART5_SendString(const char *buffer) +{ + size_t len = strlen(buffer); + for (size_t i = 0; i < len; i++) + { + if (buffer[i] != '\r' || buffer[i] != '\n') + { + UART5_SendData(buffer[i]); + } + } +} + +static void UART5_ReceiveString(char *buffer, size_t bufferSize) +{ + size_t i = 0; + + while (i < bufferSize - 1) + { + char receivedChar = UART5_ReceiveData(); + + if (receivedChar == '\n') + { + // 收到回车或换行符,表示字符串接收完毕 + break; + } + + buffer[i] = receivedChar; + i++; + } + + buffer[i] = '\0'; // 在字符串末尾添加空字符,表示字符串结束 + + while (USART_GetFlagStatus(UART5, USART_FLAG_RXNE) != RESET) + { + char dummy = USART_ReceiveData(UART5); + (void)dummy; // 避免编译器警告 + } +} + +int test_rs485(int argc, char *argv[]) +{ + KPrintf("485 Test\r\n"); + char receiveBuffer[100]; + char *sendString = " hello aiit 485\r\n"; + int n = 10; + UART5_SendString(sendString); + while (n--) + { + // 接收字符串 + UART5_ReceiveString(receiveBuffer, sizeof(receiveBuffer)); + KPrintf("%s\r\n", receiveBuffer); + if (receiveBuffer[0] == 0xfd) + { + UART5_SendString(sendString); + } + else + { + USART_ClearFlag(UART5, USART_FLAG_TC); + UART5_SendString(receiveBuffer); + } + } + + return 0; +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + test_rs485, test_rs485, test rs485); \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test_uart.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test_uart.c new file mode 100644 index 000000000..268c1eb2e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/test_uart.c @@ -0,0 +1,34 @@ +#include "ch32v30x.h" +#include "connect_uart.h" + +extern RxBuffer2; +extern uint16_t UART_ReceiveData(USART_TypeDef* USARTx); +extern void UART_SendData(USART_TypeDef* USARTx, uint16_t Data); + +void send_rensa() +{ + char* s = "ch uart"; + while (*s) { + UART_SendData(USART3, (uint16_t)*s++); + KPrintf("%c", *s); + } +} + +void recv_rensa() +{ + uint16_t ans = 0; + char recv_data = ' '; + + int cnt = 0; + while (recv_data != '\n') { + recv_data = (char)UART_ReceiveData(USART3); + KPrintf("%c", recv_data); + } + recv_data = ' '; +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + recv_rensa, recv_rensa, test receive renesa); + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + send_rensa, send_rensa, test send renesa); \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/Kconfig new file mode 100755 index 000000000..eab1bac92 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/Kconfig @@ -0,0 +1,26 @@ + +menuconfig BSP_USING_USBH + bool "Using usb host" + default y + if BSP_USING_USBH + config USB_BUS_NAME + string "usb bus name" + default "usb" + config USB_DRIVER_NAME + string "usb bus driver name" + default "usb_drv" + config USB_DEVICE_NAME + string "usb bus device name" + default "usb_dev" + config MOUNT_USB_FS + bool "mount usb file system" + default y + select MOUNT_USB + + if MOUNT_USB_FS + config MOUNT_USB_FS_TYPE + int "choose file system type : FATFS(0) LWEXT4(3)" + default 0 + endif + endif + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/Makefile new file mode 100644 index 000000000..a748aa85f --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/Makefile @@ -0,0 +1,9 @@ +SRC_FILES := connect_usb.c +SRC_DIR += usb_drv/src + +include $(KERNEL_ROOT)/compiler.mk + + + + + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/connect_usb.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/connect_usb.c new file mode 100644 index 000000000..e31332174 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/connect_usb.c @@ -0,0 +1,134 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_usb.c +* @brief support aiit-arm32-board usb function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include + +uint32 UdiskRead_new_api(void *dev, struct BusBlockReadParam *read_param); +uint32 UdiskWirte_new_api(void *dev, struct BusBlockWriteParam *write_param); + +#ifdef MOUNT_USB +#define DISABLE 0 +#define ENABLE 1 + +int MountUsb(void) +{ + Udisk_USBH_Initialization(); + return 0; +} +#endif + +static uint32 UdiskOpenNewApi(void *dev) +{ + return EOK; +} + +static uint32 UdiskCloseNewApi(void *dev) +{ + return EOK; +} + +/*manage the usb device operations*/ +static const struct UsbDevDone dev_done = +{ + .open = UdiskOpenNewApi, + .close = UdiskCloseNewApi, + .write = UdiskWirte_new_api, + .read = UdiskRead_new_api, +}; + +/*Init usb bus*/ +static int BoardUsbBusInit(struct UsbBus *usb_bus, struct UsbDriver *usb_driver) +{ + x_err_t ret = EOK; + + /*Init the usb bus */ + ret = UsbBusInit(usb_bus, USB_BUS_NAME); + if (EOK != ret) { + KPrintf("board_usb_init UsbBusInit error %d\n", ret); + return ERROR; + } + + /*Init the usb driver*/ + ret = UsbDriverInit(usb_driver, USB_DRIVER_NAME); + if (EOK != ret){ + KPrintf("board_usb_init UsbDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the usb driver to the usb bus*/ + ret = UsbDriverAttachToBus(USB_DRIVER_NAME, USB_BUS_NAME); + if (EOK != ret) { + KPrintf("board_usb_init USEDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the usb device to the usb bus*/ +static int BoardUsbDevBend(void) +{ + x_err_t ret = EOK; + static struct UsbHardwareDevice usb_device1; + memset(&usb_device1, 0, sizeof(struct UsbHardwareDevice)); + + usb_device1.dev_done = &dev_done; + + ret = USBDeviceRegister(&usb_device1, NONE, USB_DEVICE_NAME); + if (EOK != ret) { + KPrintf("board_usb_init USBDeviceInit device %s error %d\n", USB_DEVICE_NAME, ret); + return ERROR; + } + + ret = USBDeviceAttachToBus(USB_DEVICE_NAME, USB_BUS_NAME); + if (EOK != ret) { + KPrintf("board_usb_init USBDeviceAttachToBus device %s error %d\n", USB_DEVICE_NAME, ret); + return ERROR; + } + + return ret; +} + +/*BOARD USB INIT*/ +int InitHwUsb(void) +{ + x_err_t ret = EOK; + static struct UsbBus usb_bus; + memset(&usb_bus, 0, sizeof(struct UsbBus)); + + static struct UsbDriver usb_driver; + memset(&usb_driver, 0, sizeof(struct UsbDriver)); + + ret = BoardUsbBusInit(&usb_bus, &usb_driver); + if (EOK != ret) { + KPrintf("board_usb_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardUsbDevBend(); + if (EOK != ret) { + KPrintf("board_usb_Init error ret %u\n", ret); + return ERROR; + } + + return ret; +} diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/CHRV3UFI.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/CHRV3UFI.h new file mode 100644 index 000000000..a84044b7a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/CHRV3UFI.h @@ -0,0 +1,366 @@ +/* 2014.09.09 +***************************************** +** Copyright (C) W.ch 1999-2019 ** +** Web: http://wch.cn ** +***************************************** +** USB-flash File Interface for CHRV3 ** +** KEIL423, gcc 8.20 ** +***************************************** +*/ +/* CHRV3 U盘主机文件系统接口, 支持: FAT12/FAT16/FAT32 */ + +//#include "CHRV3BAS.H" + +#ifndef __CHRV3UFI_H__ +#define __CHRV3UFI_H__ + + + +#define CHRV3_LIB_VER 0x10 + +//#define DISK_BASE_BUF_LEN 512 /* 默认的磁盘数据缓冲区大小为512字节(可以选择为2048甚至4096以支持某些大扇区的U盘),为0则禁止在本文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */ +/* 如果需要复用磁盘数据缓冲区以节约RAM,那么可将DISK_BASE_BUF_LEN定义为0以禁止在本文件中定义缓冲区,而由应用程序在调用CHRV3LibInit之前将与其它程序合用的缓冲区起始地址置入pDISK_BASE_BUF变量 */ + +//#define NO_DEFAULT_ACCESS_SECTOR 1 /* 禁止默认的磁盘扇区读写子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_DISK_CONNECT 1 /* 禁止默认的检查磁盘连接子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_FILE_ENUMER 1 /* 禁止默认的文件名枚举回调程序,下面用自行编写的程序代替它 */ +#define FOR_ROOT_UDISK_ONLY 1 +#ifdef __cplusplus +extern "C" { +#endif + +/* ********************************************************************************************************************* */ + +/* FILE: CHRV3UF.H */ + +/* 错误码 */ +#ifndef ERR_SUCCESS +#define ERR_SUCCESS 0x00 /* 操作成功 */ +#endif +#ifndef ERR_DISK_DISCON +#define ERR_CHRV3_ERROR 0x81 /* CHRV3硬件错误,可能需要复位CHRV3 */ +//#define ERR_DISK_DISCON 0x82 /* 磁盘尚未连接,可能磁盘已经断开 */ +#define ERR_STATUS_ERR 0x83 /* 磁盘状态错误,可能正在连接或者断开磁盘 */ +#define ERR_HUB_PORT_FREE 0x84 /* USB-HUB已经连接但是HUB端口尚未连接磁盘,可能磁盘已经断开 */ +#define ERR_MBR_ERROR 0x91 /* 磁盘的主引导记录无效,可能磁盘尚未分区或者尚未格式化 */ +#define ERR_TYPE_ERROR 0x92 /* 磁盘分区类型不支持,只支持FAT12/FAT16/BigDOS/FAT32,需要由磁盘管理工具重新分区 */ +#define ERR_BPB_ERROR 0xA1 /* 磁盘尚未格式化,或者参数错误,需要由WINDOWS采用默认参数重新格式化 */ +#define ERR_TOO_LARGE 0xA2 /* 磁盘非正常格式化并且容量大于4GB,或者容量大于250GB,需要由WINDOWS采用默认参数重新格式化 */ +#define ERR_FAT_ERROR 0xA3 /* 磁盘的文件系统不支持,只支持FAT12/FAT16/FAT32,需要由WINDOWS采用默认参数重新格式化 */ +#define ERR_DISK_FULL 0xB1 /* 磁盘文件太满,剩余空间太少或者已经没有,需要磁盘整理 */ +#define ERR_FDT_OVER 0xB2 /* 目录内文件太多,没有空闲的目录项,FAT12/FAT16根目录下的文件数应该少于500个,需要磁盘整理 */ +#define ERR_MISS_DIR 0xB3 /* 指定路径的某个子目录没有找到,可能是目录名称错误 */ +#define ERR_FILE_CLOSE 0xB4 /* 文件已经关闭,如果需要使用,应该重新打开文件 */ +#define ERR_OPEN_DIR 0x41 /* 指定路径的目录被打开 */ +#define ERR_MISS_FILE 0x42 /* 指定路径的文件没有找到,可能是文件名称错误 */ +#define ERR_FOUND_NAME 0x43 /* 搜索到与通配符相匹配的文件名,文件名及其完整路径在命令缓冲区中,如果需要使用,应该打开该文件 */ +#endif +/* 代码2XH-3XH用于USB主机方式的通讯失败代码,由CHRV3子程序模仿CH375的返回 */ +/* 代码1XH用于USB主机方式的操作状态代码,由CHRV3子程序模仿CH375的返回 */ +#ifndef ERR_USB_CONNECT +#define ERR_USB_CONNECT_LS 0x13 /* 检测到低速USB设备连接事件 */ +#define ERR_USB_CONNECT 0x15 /* 检测到USB设备连接事件,磁盘已经连接 */ +#define ERR_USB_DISCON 0x16 /* 检测到USB设备断开事件,磁盘已经断开 */ +#define ERR_USB_BUF_OVER 0x17 /* USB传输的数据有误或者数据太多缓冲区溢出 */ +#define ERR_USB_DISK_ERR 0x1F /* USB存储器操作失败,在初始化时可能是USB存储器不支持,在读写操作中可能是磁盘损坏或者已经断开 */ +#define ERR_USB_TRANSFER 0x20 /* NAK/STALL等更多错误码在0x20~0x2F */ +#endif + +/* 磁盘及文件状态 */ +#define DISK_UNKNOWN 0x00 /* 尚未初始化,未知状态 */ +#define DISK_DISCONNECT 0x01 /* 磁盘没有连接或者已经断开 */ +#define DISK_CONNECT 0x02 /* 磁盘已经连接,但是尚未初始化或者无法识别该磁盘 */ +#define DISK_USB_ADDR 0x04 /* 磁盘已经分配USB设备地址,但是尚未配置USB和初始化磁盘 */ +#define DISK_MOUNTED 0x05 /* 磁盘已经初始化成功,但是尚未分析文件系统或者文件系统不支持 */ +#define DISK_READY 0x10 /* 已经分析磁盘的文件系统并且能够支持 */ +#define DISK_OPEN_ROOT 0x12 /* 已经打开根目录,扇区模式,只能以扇区为单位读写目录的内容,使用后必须关闭,注意FAT12/FAT16根目录是固定长度 */ +#define DISK_OPEN_DIR 0x13 /* 已经打开子目录,扇区模式,只能以扇区为单位读写目录的内容 */ +#define DISK_OPEN_FILE 0x14 /* 已经打开文件,扇区模式,可以以扇区为单位进行数据读写 */ +#define DISK_OPEN_FILE_B 0x15 /* 已经打开文件,字节模式,可以以字节为单位进行数据读写 */ + +/* FAT类型标志 */ +#ifndef DISK_FAT16 +#define DISK_FS_UNKNOWN 0 /* 未知的文件系统 */ +#define DISK_FAT12 1 /* FAT12文件系统 */ +#define DISK_FAT16 2 /* FAT16文件系统 */ +#define DISK_FAT32 3 /* FAT32文件系统 */ +#endif + +/* FAT数据区中文件目录信息 */ +typedef struct _FAT_DIR_INFO { + uint8_t DIR_Name[11]; /* 00H,文件名,共11字节,不足处填空格 */ + uint8_t DIR_Attr; /* 0BH,文件属性,参考下面的说明 */ + uint8_t DIR_NTRes; /* 0CH */ + uint8_t DIR_CrtTimeTenth; /* 0DH,文件创建的时间,以0.1秒单位计数 */ + uint16_t DIR_CrtTime; /* 0EH,文件创建的时间 */ + uint16_t DIR_CrtDate; /* 10H,文件创建的日期 */ + uint16_t DIR_LstAccDate; /* 12H,最近一次存取操作的日期 */ + uint16_t DIR_FstClusHI; /* 14H */ + uint16_t DIR_WrtTime; /* 16H,文件修改时间,参考宏MAKE_FILE_TIME */ + uint16_t DIR_WrtDate; /* 18H,文件修改日期,参考宏MAKE_FILE_DATA */ + uint16_t DIR_FstClusLO; /* 1AH */ + uint32_t DIR_FileSize; /* 1CH,文件长度 */ +} FAT_DIR_INFO; /* 20H */ + +typedef FAT_DIR_INFO *PX_FAT_DIR_INFO; + +/* 文件属性 */ +#define ATTR_READ_ONLY 0x01 /* 文件为只读属性 */ +#define ATTR_HIDDEN 0x02 /* 文件为隐含属性 */ +#define ATTR_SYSTEM 0x04 /* 文件为系统属性 */ +#define ATTR_VOLUME_ID 0x08 /* 卷标 */ +#define ATTR_DIRECTORY 0x10 /* 子目录 */ +#define ATTR_ARCHIVE 0x20 /* 文件为存档属性 */ +#define ATTR_LONG_NAME ( ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID ) +/* 文件属性 uint8_t */ +/* bit0 bit1 bit2 bit3 bit4 bit5 bit6 bit7 */ +/* 只 隐 系 卷 目 存 未定义 */ +/* 读 藏 统 标 录 档 */ +/* 文件时间 uint16_t */ +/* Time = (Hour<<11) + (Minute<<5) + (Second>>1) */ +#define MAKE_FILE_TIME( h, m, s ) ( (h<<11) + (m<<5) + (s>>1) ) /* 生成指定时分秒的文件时间数据 */ +/* 文件日期 uint16_t */ +/* Date = ((Year-1980)<<9) + (Month<<5) + Day */ +#define MAKE_FILE_DATE( y, m, d ) ( ((y-1980)<<9) + (m<<5) + d ) /* 生成指定年月日的文件日期数据 */ + +/* 文件名 */ +#define PATH_WILDCARD_CHAR 0x2A /* 路径名的通配符 '*' */ +#define PATH_SEPAR_CHAR1 0x5C /* 路径名的分隔符 '\' */ +#define PATH_SEPAR_CHAR2 0x2F /* 路径名的分隔符 '/' */ +#ifndef MAX_PATH_LEN +#define MAX_PATH_LEN 64 /* 最大路径长度,含所有斜杠分隔符和小数点间隔符以及路径结束符00H */ +#endif + +/* 外部命令参数 */ +typedef union _CMD_PARAM +{ + struct + { + uint8_t mBuffer[ MAX_PATH_LEN ]; + } Other; + struct + { + uint32_t mTotalSector; /* 返回: 当前逻辑盘的总扇区数 */ + uint32_t mFreeSector; /* 返回: 当前逻辑盘的剩余扇区数 */ + uint32_t mSaveValue; + } Query; /* CMD_DiskQuery, 查询磁盘信息 */ + struct + { + uint8_t mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILENAME.EXT",00H */ + } Open; /* CMD_FileOpen, 打开文件 */ +// struct +// { +// uint8_t mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名(含通配符*)...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILE*",00H */ +// } Open; /* CMD_FileOpen, 枚举文件, CHRV3vFileSize最高位为1则各调用xFileNameEnumer,为0则返回指定序号的文件名 */ + struct + { + uint8_t mUpdateLen; /* 输入参数: 是否允许更新长度: 0禁止,1允许 */ + } Close; /* CMD_FileClose, 关闭当前文件 */ + struct + { + uint8_t mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILENAME.EXT",00H */ + } Create; /* CMD_FileCreate, 新建文件并打开,如果文件已经存在则先删除后再新建 */ + struct + { + uint8_t mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILENAME.EXT",00H */ + } Erase; /* CMD_FileErase, 删除文件并关闭 */ + struct + { + uint32_t mFileSize; /* 输入参数: 新的文件长度,为0FFFFFFFFH则不修改, 返回: 原长度 */ + uint16_t mFileDate; /* 输入参数: 新的文件日期,为0FFFFH则不修改, 返回: 原日期 */ + uint16_t mFileTime; /* 输入参数: 新的文件时间,为0FFFFH则不修改, 返回: 原时间 */ + uint8_t mFileAttr; /* 输入参数: 新的文件属性,为0FFH则不修改, 返回: 原属性 */ + } Modify; /* CMD_FileQuery, 查询当前文件的信息; CMD_FileModify, 查询或者修改当前文件的信息 */ + struct + { + uint32_t mSaveCurrClus; + uint32_t mSaveLastClus; + } Alloc; /* CMD_FileAlloc, 根据文件长度调整为文件分配的磁盘空间 */ + struct + { + uint32_t mSectorOffset; /* 输入参数: 扇区偏移,0则移动到文件头,0FFFFFFFFH则移动到文件尾, 返回: 当前文件指针对应的绝对线性扇区号, 0FFFFFFFFH则已到文件尾 */ + uint32_t mLastOffset; + } Locate; /* CMD_FileLocate, 移动当前文件指针 */ + struct + { + uint8_t mSectorCount; /* 输入参数: 读取扇区数, 返回: 实际读取扇区数 */ + uint8_t mActCnt; + uint8_t mLbaCount; + uint8_t mRemainCnt; + uint8_t *mDataBuffer; /* 输入参数: 缓冲区起始地址, 返回: 缓冲区当前地址 */ + uint32_t mLbaStart; + } Read; /* CMD_FileRead, 从当前文件读取数据 */ + struct + { + uint8_t mSectorCount; /* 输入参数: 写入扇区数, 返回: 实际写入扇区数 */ + uint8_t mActCnt; + uint8_t mLbaCount; + uint8_t mAllocCnt; + uint8_t *mDataBuffer; /* 输入参数: 缓冲区起始地址, 返回: 缓冲区当前地址 */ + uint32_t mLbaStart; + uint32_t mSaveValue; + } Write; /* CMD_FileWrite, 向当前文件写入数据 */ + struct + { + uint32_t mDiskSizeSec; /* 返回: 整个物理磁盘的总扇区数, 仅首次调用时返回 */ + } DiskReady; /* CMD_DiskReady, 查询磁盘就绪 */ + struct + { + uint32_t mByteOffset; /* 输入参数: 以字节为单位的偏移量, 以字节为单位的文件指针, 返回: 当前文件指针对应的绝对线性扇区号, 0FFFFFFFFH则已到文件尾 */ + uint32_t mLastOffset; + } ByteLocate; /* CMD_ByteLocate, 以字节为单位移动当前文件指针 */ + struct + { + uint16_t mByteCount; /* 输入参数: 准备读取的字节数, 返回: 实际读出的字节数 */ + uint8_t *mByteBuffer; /* 输入参数: 指向存放读出数据块的缓冲区 */ + uint16_t mActCnt; + } ByteRead; /* CMD_ByteRead, 以字节为单位从当前文件读取数据块 */ + struct + { + uint16_t mByteCount; /* 输入参数: 准备写入的字节数, 返回: 实际写入的字节数 */ + uint8_t *mByteBuffer; /* 输入参数: 指向存放读出数据块的缓冲区 */ + uint16_t mActCnt; + } ByteWrite; /* CMD_ByteWrite, 以字节为单位向当前文件写入数据块 */ + struct + { + uint8_t mSaveVariable; /* 输入参数: 为0则恢复单个U盘的变量,为0x80则恢复多个U盘的变量,其它值则备份/保存变量 */ + uint8_t mReserved[3]; + uint8_t *mBuffer; /* 输入参数: 指向子程序库的变量的备份缓冲区,长度不小于80个字节 */ + } SaveVariable; /* CMD_SaveVariable, 备份/保存/恢复子程序库的变量 */ +} CMD_PARAM; + +typedef CMD_PARAM CMD_PARAM_I; +//typedef CMD_PARAM *P_CMD_PARAM; + +/* SCSI命令码 */ +#ifndef SPC_CMD_INQUIRY +#define SPC_CMD_INQUIRY 0x12 +#define SPC_CMD_READ_CAPACITY 0x25 +#define SPC_CMD_READ10 0x28 +#define SPC_CMD_WRITE10 0x2A +#define SPC_CMD_TEST_READY 0x00 +#define SPC_CMD_REQUEST_SENSE 0x03 +#define SPC_CMD_MODESENSE6 0x1A +#define SPC_CMD_MODESENSE10 0x5A +#define SPC_CMD_START_STOP 0x1B +#endif + +/* FILE: CHRV3UFI.C */ +#define EN_DISK_WRITE 1 + +#ifndef DISK_BASE_BUF_LEN +#define DISK_BASE_BUF_LEN 512 /* 默认的磁盘数据缓冲区大小为512字节,建议选择为2048甚至4096以支持某些大扇区的U盘,为0则禁止在.H文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */ +#endif + +/* 子程序库中提供的变量 */ +extern volatile uint8_t CHRV3IntStatus; /* CHRV3操作的中断状态 */ +extern volatile uint8_t CHRV3DiskStatus; /* 磁盘及文件状态 */ +extern uint8_t CHRV3vDiskFat; /* 逻辑盘的FAT标志:1=FAT12,2=FAT16,3=FAT32 */ +extern uint8_t CHRV3vSecPerClus; /* 逻辑盘的每簇扇区数 */ +extern uint8_t CHRV3vSectorSizeB; /* log2(CHRV3vSectorSize) */ +extern uint32_t CHRV3vStartLba; /* 逻辑盘的起始绝对扇区号LBA */ +extern uint32_t CHRV3vDiskRoot; /* 对于FAT16盘为根目录占用扇区数,对于FAT32盘为根目录起始簇号 */ +extern uint32_t CHRV3vDataStart; /* 逻辑盘的数据区域的起始LBA */ +extern uint32_t CHRV3vStartCluster; /* 当前文件或者目录的起始簇号 */ +extern uint32_t CHRV3vFileSize; /* 当前文件的长度 */ +extern uint32_t CHRV3vCurrentOffset; /* 当前文件指针,当前读写位置的字节偏移 */ +extern uint32_t CHRV3vFdtLba; /* 当前FDT所在的LBA地址 */ +extern uint32_t CHRV3vLbaCurrent; /* 当前读写的磁盘起始LBA地址 */ +extern uint16_t CHRV3vFdtOffset; /* 当前FDT在扇区内的偏移地址 */ +extern uint16_t CHRV3vSectorSize; /* 磁盘的扇区大小 */ +extern uint8_t CHRV3vCurrentLun; /* 磁盘当前操作逻辑单元号 */ +extern uint8_t CHRV3vSubClassIs6; /* USB存储类设备的子类为6,0则非6 */ +extern uint8_t *pDISK_BASE_BUF; /* 指向外部RAM的磁盘数据缓冲区,缓冲区长度不小于CHRV3vSectorSize,由应用程序初始化 */ +extern uint8_t *pDISK_FAT_BUF; /* 指向外部RAM的磁盘FAT数据缓冲区,缓冲区长度不小于CHRV3vSectorSize,由应用程序初始化 */ +extern uint16_t CHRV3vPacketSize; /* USB存储类设备的最大包长度:64@FS,512@HS/SS,由应用程序初始化 */ +extern uint32_t *pTX_DMA_A_REG; /* 指向发送DMA地址寄存器,由应用程序初始化 */ +extern uint32_t *pRX_DMA_A_REG; /* 指向接收DMA地址寄存器,由应用程序初始化 */ +extern uint16_t *pTX_LEN_REG; /* 指向发送长度寄存器,由应用程序初始化 */ +extern uint16_t *pRX_LEN_REG; /* 指向接收长度寄存器,由应用程序初始化 */ + +extern CMD_PARAM_I mCmdParam; /* 命令参数 */ + +extern __attribute__ ((aligned(4))) uint8_t RxBuffer[ ]; // IN, must even address +extern __attribute__ ((aligned(4))) uint8_t TxBuffer[ ]; // OUT, must even address + +//#define PXUDISK_BOC_CBW PUDISK_BOC_CBW +//#define PXUDISK_BOC_CSW PUDISK_BOC_CSW + +#ifndef pSetupReq +#define pSetupReq ((PUSB_SETUP_REQ)TxBuffer) +#endif + +#ifndef pCBW +#define pCBW ((PXUDISK_BOC_CBW)TxBuffer) +#define pCSW ((PXUDISK_BOC_CSW)RxBuffer) +#endif +#ifndef pBOC_buf +#define pBOC_buf (TxBuffer+((USB_BO_CBW_SIZE+4)&0xFE)) +#endif + +#if DISK_BASE_BUF_LEN > 0 +extern uint8_t DISK_BASE_BUF[ DISK_BASE_BUF_LEN ]; /* 外部RAM的磁盘数据缓冲区,缓冲区长度为一个扇区的长度 */ +#endif +extern uint8_t CHRV3ReadSector( uint8_t SectCount, uint8_t * DataBuf ); /* 从磁盘读取多个扇区的数据到缓冲区中 */ +#ifdef EN_DISK_WRITE +extern uint8_t CHRV3WriteSector( uint8_t SectCount, uint8_t * DataBuf ); /* 将缓冲区中的多个扇区的数据块写入磁盘 */ +#endif + +extern uint8_t CHRV3DiskConnect( void ); /* 检查磁盘是否连接并更新磁盘状态 */ +extern void xFileNameEnumer( void ); /* 调用外部定义的子程序,文件名枚举回调子程序 */ + +extern uint8_t CHRV3LibInit( void ); /* 初始化CHRV3程序库,操作成功返回0 */ + +/* 子程序库中提供的子程序 */ +/* 下述子程序中, 文件操作子程序CHRV3File*和磁盘查询子程序CHRV3DiskQuery都可能会用到磁盘数据缓冲区pDISK_BASE_BUF, + 并且有可能在pDISK_BASE_BUF中保存了磁盘信息, 所以必须保证pDISK_BASE_BUF不被用于其它用途, + 如果RAM较少, 要将pDISK_BASE_BUF临时用于其它用途, 那么在临时用完后必须调用CHRV3DirtyBuffer清除磁盘缓冲区 */ +extern uint8_t CHRV3GetVer( void ); /* 获取当前子程序库的版本号 */ +extern void CHRV3DirtyBuffer( void ); /* 清除磁盘缓冲区 */ +extern uint8_t CHRV3BulkOnlyCmd( uint8_t * DataBuf ); /* 执行基于BulkOnly协议的命令 */ +extern uint8_t CHRV3DiskReady( void ); /* 查询磁盘是否准备好 */ +extern uint8_t CHRV3AnalyzeError( uint8_t iMode ); /* USB操作失败分析CHRV3IntStatus返回错误状态 */ +extern uint8_t CHRV3FileOpen( void ); /* 打开文件或者枚举文件 */ +extern uint8_t CHRV3FileClose( void ); /* 关闭当前文件 */ +#ifdef EN_DISK_WRITE +extern uint8_t CHRV3FileErase( void ); /* 删除文件并关闭 */ +extern uint8_t CHRV3FileCreate( void ); /* 新建文件并打开,如果文件已经存在则先删除后再新建 */ +extern uint8_t CHRV3FileAlloc( void ); /* 根据文件长度调整为文件分配的磁盘空间 */ +#endif +extern uint8_t CHRV3FileModify( void ); /* 查询或者修改当前文件的信息 */ +extern uint8_t CHRV3FileQuery( void ); /* 查询当前文件的信息 */ +extern uint8_t CHRV3FileLocate( void ); /* 移动当前文件指针 */ +extern uint8_t CHRV3FileRead( void ); /* 从当前文件读取数据到指定缓冲区 */ +#ifdef EN_DISK_WRITE +extern uint8_t CHRV3FileWrite( void ); /* 向当前文件写入指定缓冲区的数据 */ +#endif +extern uint8_t CHRV3ByteLocate( void ); /* 以字节为单位移动当前文件指针 */ +extern uint8_t CHRV3ByteRead( void ); /* 以字节为单位从当前位置读取数据块 */ +#ifdef EN_DISK_WRITE +extern uint8_t CHRV3ByteWrite( void ); /* 以字节为单位向当前位置写入数据块 */ +#endif +extern uint8_t CHRV3DiskQuery( void ); /* 查询磁盘信息 */ +extern void CHRV3SaveVariable( void ); /* 备份/保存/恢复子程序库的变量,用于子程序库在多个芯片或者U盘之间进行切换 */ + +extern void mDelayuS( uint16_t n ); // 以uS为单位延时 +extern void mDelaymS( uint16_t n ); // 以mS为单位延时 +extern uint8_t USBHostTransact( uint8_t endp_pid, uint8_t tog, uint32_t timeout ); // CHRV3传输事务,输入目的端点地址/PID令牌,同步标志,NAK重试时间,返回0成功,超时/出错重试 +extern uint8_t HostCtrlTransfer( uint8_t * DataBuf, uint8_t * RetLen ); // 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区,实际收发长度返回在ReqLen指向的变量中 +extern void CopySetupReqPkg( const char * pReqPkt ); // 复制控制传输的请求包 +extern uint8_t CtrlGetDeviceDescrTB( void ); // 获取设备描述符,返回在TxBuffer中 +extern uint8_t CtrlGetConfigDescrTB( void ); // 获取配置描述符,返回在TxBuffer中 +extern uint8_t CtrlSetUsbAddress( uint8_t addr ); // 设置USB设备地址 +extern uint8_t CtrlSetUsbConfig( uint8_t cfg ); // 设置USB设备配置 +extern uint8_t CtrlClearEndpStall( uint8_t endp ); // 清除端点STALL +#ifndef FOR_ROOT_UDISK_ONLY +//extern uint8_t CtrlGetHubDescr( void ); // 获取HUB描述符,返回在TxBuffer中 +extern uint8_t HubGetPortStatus( uint8_t HubPortIndex ); // 查询HUB端口状态,返回在TxBuffer中 +//extern uint8_t HubSetPortFeature( uint8_t HubPortIndex, uint8_t FeatureSelt ); // 设置HUB端口特性 +extern uint8_t HubClearPortFeature( uint8_t HubPortIndex, uint8_t FeatureSelt ); // 清除HUB端口特性 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/Udisk_Operation.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/Udisk_Operation.h new file mode 100644 index 000000000..9fc77dfac --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/Udisk_Operation.h @@ -0,0 +1,78 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : UDisk_Operation.h +* Author : WCH +* Version : V1.0.0 +* Date : 2022/11/20 +* Description : This file contains all the functions prototypes for the Udisk + host operation. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#ifndef USER_UDISK_OPERATION_H_ +#define USER_UDISK_OPERATION_H_ + +#include "debug.h" +#include "string.h" +#include "CHRV3UFI.h" +#include "ch32v30x_usbhs_host.h" +#include "usb_host_config.h" + +/*******************************************************************************/ +/* Public Extern Variables */ +extern volatile uint8_t UDisk_Opeation_Flag; +extern struct _ROOT_HUB_DEVICE RootHubDev[ DEF_TOTAL_ROOT_HUB ]; +extern struct __HOST_CTL HostCtl[ DEF_TOTAL_ROOT_HUB * DEF_ONE_USB_SUP_DEV_TOTAL ]; +extern volatile uint8_t UDisk_Opeation_Flag; +extern uint8_t *pCodeStr; + +extern __attribute__((aligned(4))) uint8_t Com_Buffer[ DEF_COM_BUF_LEN ]; // even address , used for host enumcation and udisk operation +extern __attribute__((aligned(4))) uint8_t DevDesc_Buf[ 18 ]; // Device Descriptor Buffer + +/*******************************************************************************/ +/* 长文件名相关的宏定义极其全局变量 */ +// 长文件名缓冲区从(0到20)*26 +#define LONG_NAME_BUF_LEN (20*26) +#define UNICODE_ENDIAN 0 // 1为UNICDOE大端编码 0为小端 +// 长文件名存放缓冲区(Unicode编码) +extern uint8_t LongNameBuf[ ]; +// 长文件名(Unicode编码) +extern uint8_t LongName[ ]; +#define LongName_Len 124 +#define TRUE 1 +#define FALSE 0 + +// 函数返回 +#define ERR_NO_NAME 0X44 // 此短文件名没有长文件名或错误的长文件 +#define ERR_BUF_OVER 0X45 // 长文件缓冲区溢出 +#define ERR_LONG_NAME 0X46 // 错误的长文件名 +#define ERR_NAME_EXIST 0X47 // 此短文件名存在 + +/*******************************************************************************/ +/* Extern UDisk Operation Functions */ +extern void mStopIfError( uint8_t iError ); +extern void Udisk_USBH_Initialization( void ); +extern uint8_t Udisk_USBH_EnumRootDevice( uint8_t usb_port ); +extern uint8_t UDisk_USBH_PreDeal( void ); +extern uint8_t UDisk_USBH_DiskReady( void ); + +/* Extern Long-name Operation Functions */ +extern void UDisk_USBH_Longname( void ); +extern uint8_t CHRV3GetLongName( void ); +extern uint8_t GetUpSectorData( uint32_t *NowSector ); +extern uint8_t CHRV3CreateLongName( void ); +extern uint8_t AnalyzeLongName( void ); +extern uint8_t CheckNameSum( uint8_t *p ); + +/* Extern Creating Directory Functions */ +extern void UDisk_USBH_CreatDirectory( void ); +extern uint8_t CreateDirectory( void ); + +/* Extern Byte/Sector Open/Read/Modify/Delete and File-Enumeration Functions */ +extern void UDisk_USBH_ByteOperation( void ); +extern void UDisk_USBH_SectorOperation( void ); +extern void UDisk_USBH_EnumFiles( void ); + +#endif /* USER_UDISK_OPERATION_H_ */ diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/ch32v30x_usb.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/ch32v30x_usb.h new file mode 100644 index 000000000..f1f6da6f6 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/ch32v30x_usb.h @@ -0,0 +1,833 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : system_ch32v30x.h +* Author : WCH +* Version : V1.0.0 +* Date : 2022/08/20 +* Description : CH32V30x Device Peripheral Access Layer System Header File. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#ifndef __CH32V30x_USB_H +#define __CH32V30x_USB_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*******************************************************************************/ +/* Header File */ +#include "stdint.h" + +/*******************************************************************************/ +/* USB Communication Related Macro Definition */ +/* USB Endpoint0 Size */ +#ifndef DEFAULT_ENDP0_SIZE +#define DEFAULT_ENDP0_SIZE 8 // default maximum packet size for endpoint 0 +#endif +#ifndef MAX_PACKET_SIZE +#define MAX_PACKET_SIZE 64 // maximum packet size +#endif + +/* USB PID */ +#ifndef USB_PID_SETUP +#define USB_PID_NULL 0x00 +#define USB_PID_SOF 0x05 +#define USB_PID_SETUP 0x0D +#define USB_PID_IN 0x09 +#define USB_PID_OUT 0x01 +#define USB_PID_NYET 0x06 +#define USB_PID_ACK 0x02 +#define USB_PID_NAK 0x0A +#define USB_PID_STALL 0x0E +#define USB_PID_DATA0 0x03 +#define USB_PID_DATA1 0x0B +#define USB_PID_DATA2 0x07 +#define USB_PID_MDATA 0x0F +#define USB_PID_PRE 0x0C +#endif + +/* USB standard device request code */ +#ifndef USB_GET_DESCRIPTOR +#define USB_GET_STATUS 0x00 +#define USB_CLEAR_FEATURE 0x01 +#define USB_SET_FEATURE 0x03 +#define USB_SET_ADDRESS 0x05 +#define USB_GET_DESCRIPTOR 0x06 +#define USB_SET_DESCRIPTOR 0x07 +#define USB_GET_CONFIGURATION 0x08 +#define USB_SET_CONFIGURATION 0x09 +#define USB_GET_INTERFACE 0x0A +#define USB_SET_INTERFACE 0x0B +#define USB_SYNCH_FRAME 0x0C +#endif + +#define DEF_STRING_DESC_LANG 0x00 +#define DEF_STRING_DESC_MANU 0x01 +#define DEF_STRING_DESC_PROD 0x02 +#define DEF_STRING_DESC_SERN 0x03 + +/* USB hub class request code */ +#ifndef HUB_GET_DESCRIPTOR +#define HUB_GET_STATUS 0x00 +#define HUB_CLEAR_FEATURE 0x01 +#define HUB_GET_STATE 0x02 +#define HUB_SET_FEATURE 0x03 +#define HUB_GET_DESCRIPTOR 0x06 +#define HUB_SET_DESCRIPTOR 0x07 +#endif + +/* USB HID class request code */ +#ifndef HID_GET_REPORT +#define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 +#define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0A +#define HID_SET_PROTOCOL 0x0B +#endif + +/* USB CDC Class request code */ +#ifndef CDC_GET_LINE_CODING +#define CDC_GET_LINE_CODING 0x21 /* This request allows the host to find out the currently configured line coding */ +#define CDC_SET_LINE_CODING 0x20 /* Configures DTE rate, stop-bits, parity, and number-of-character */ +#define CDC_SET_LINE_CTLSTE 0x22 /* This request generates RS-232/V.24 style control signals */ +#define CDC_SEND_BREAK 0x23 /* Sends special carrier modulation used to specify RS-232 style break */ +#endif + +/* Bit Define for USB Request Type */ +#ifndef USB_REQ_TYP_MASK +#define USB_REQ_TYP_IN 0x80 +#define USB_REQ_TYP_OUT 0x00 +#define USB_REQ_TYP_READ 0x80 +#define USB_REQ_TYP_WRITE 0x00 +#define USB_REQ_TYP_MASK 0x60 +#define USB_REQ_TYP_STANDARD 0x00 +#define USB_REQ_TYP_CLASS 0x20 +#define USB_REQ_TYP_VENDOR 0x40 +#define USB_REQ_TYP_RESERVED 0x60 +#define USB_REQ_RECIP_MASK 0x1F +#define USB_REQ_RECIP_DEVICE 0x00 +#define USB_REQ_RECIP_INTERF 0x01 +#define USB_REQ_RECIP_ENDP 0x02 +#define USB_REQ_RECIP_OTHER 0x03 +#define USB_REQ_FEAT_REMOTE_WAKEUP 0x01 +#define USB_REQ_FEAT_ENDP_HALT 0x00 +#endif + +/* USB Descriptor Type */ +#ifndef USB_DESCR_TYP_DEVICE +#define USB_DESCR_TYP_DEVICE 0x01 +#define USB_DESCR_TYP_CONFIG 0x02 +#define USB_DESCR_TYP_STRING 0x03 +#define USB_DESCR_TYP_INTERF 0x04 +#define USB_DESCR_TYP_ENDP 0x05 +#define USB_DESCR_TYP_QUALIF 0x06 +#define USB_DESCR_TYP_SPEED 0x07 +#define USB_DESCR_TYP_OTG 0x09 +#define USB_DESCR_TYP_BOS 0X0F +#define USB_DESCR_TYP_HID 0x21 +#define USB_DESCR_TYP_REPORT 0x22 +#define USB_DESCR_TYP_PHYSIC 0x23 +#define USB_DESCR_TYP_CS_INTF 0x24 +#define USB_DESCR_TYP_CS_ENDP 0x25 +#define USB_DESCR_TYP_HUB 0x29 +#endif + +/* USB Device Class */ +#ifndef USB_DEV_CLASS_HUB +#define USB_DEV_CLASS_RESERVED 0x00 +#define USB_DEV_CLASS_AUDIO 0x01 +#define USB_DEV_CLASS_COMMUNIC 0x02 +#define USB_DEV_CLASS_HID 0x03 +#define USB_DEV_CLASS_MONITOR 0x04 +#define USB_DEV_CLASS_PHYSIC_IF 0x05 +#define USB_DEV_CLASS_POWER 0x06 +#define USB_DEV_CLASS_IMAGE 0x06 +#define USB_DEV_CLASS_PRINTER 0x07 +#define USB_DEV_CLASS_STORAGE 0x08 +#define USB_DEV_CLASS_HUB 0x09 +#define USB_DEV_CLASS_VEN_SPEC 0xFF +#endif + +/* USB Hub Class Request */ +#ifndef HUB_GET_HUB_DESCRIPTOR +#define HUB_CLEAR_HUB_FEATURE 0x20 +#define HUB_CLEAR_PORT_FEATURE 0x23 +#define HUB_GET_BUS_STATE 0xA3 +#define HUB_GET_HUB_DESCRIPTOR 0xA0 +#define HUB_GET_HUB_STATUS 0xA0 +#define HUB_GET_PORT_STATUS 0xA3 +#define HUB_SET_HUB_DESCRIPTOR 0x20 +#define HUB_SET_HUB_FEATURE 0x20 +#define HUB_SET_PORT_FEATURE 0x23 +#endif + +/* Hub Class Feature Selectors */ +#ifndef HUB_PORT_RESET +#define HUB_C_HUB_LOCAL_POWER 0 +#define HUB_C_HUB_OVER_CURRENT 1 +#define HUB_PORT_CONNECTION 0 +#define HUB_PORT_ENABLE 1 +#define HUB_PORT_SUSPEND 2 +#define HUB_PORT_OVER_CURRENT 3 +#define HUB_PORT_RESET 4 +#define HUB_PORT_POWER 8 +#define HUB_PORT_LOW_SPEED 9 +#define HUB_C_PORT_CONNECTION 16 +#define HUB_C_PORT_ENABLE 17 +#define HUB_C_PORT_SUSPEND 18 +#define HUB_C_PORT_OVER_CURRENT 19 +#define HUB_C_PORT_RESET 20 +#endif + +/* USB UDisk */ +#ifndef USB_BO_CBW_SIZE +#define USB_BO_CBW_SIZE 0x1F +#define USB_BO_CSW_SIZE 0x0D +#endif +#ifndef USB_BO_CBW_SIG0 +#define USB_BO_CBW_SIG0 0x55 +#define USB_BO_CBW_SIG1 0x53 +#define USB_BO_CBW_SIG2 0x42 +#define USB_BO_CBW_SIG3 0x43 +#define USB_BO_CSW_SIG0 0x55 +#define USB_BO_CSW_SIG1 0x53 +#define USB_BO_CSW_SIG2 0x42 +#define USB_BO_CSW_SIG3 0x53 +#endif + + +/******************************************************************************/ +/* USBHS Clock Configuration Related Macro Definition */ +#define USB_CLK_SRC 0x80000000 +#define USBHS_PLL_ALIVE 0x40000000 +#define USBHS_PLL_CKREF_MASK 0x30000000 +#define USBHS_PLL_CKREF_3M 0x00000000 +#define USBHS_PLL_CKREF_4M 0x10000000 +#define USBHS_PLL_CKREF_8M 0x20000000 +#define USBHS_PLL_CKREF_5M 0x30000000 +#define USBHS_PLL_SRC 0x08000000 +#define USBHS_PLL_SRC_PRE_MASK 0x07000000 +#define USBHS_PLL_SRC_PRE_DIV1 0x00000000 +#define USBHS_PLL_SRC_PRE_DIV2 0x01000000 +#define USBHS_PLL_SRC_PRE_DIV3 0x02000000 +#define USBHS_PLL_SRC_PRE_DIV4 0x03000000 +#define USBHS_PLL_SRC_PRE_DIV5 0x04000000 +#define USBHS_PLL_SRC_PRE_DIV6 0x05000000 +#define USBHS_PLL_SRC_PRE_DIV7 0x06000000 +#define USBHS_PLL_SRC_PRE_DIV8 0x07000000 + + +/*******************************************************************************/ +/* USBHS Related Register Macro Definition */ + +/* R8_USB_CTRL */ +#define USBHS_UC_HOST_MODE 0x80 +#define USBHS_UC_SPEED_TYPE 0x60 +#define USBHS_UC_SPEED_LOW 0x40 +#define USBHS_UC_SPEED_FULL 0x00 +#define USBHS_UC_SPEED_HIGH 0x20 +#define USBHS_UC_DEV_PU_EN 0x10 +#define USBHS_UC_INT_BUSY 0x08 +#define USBHS_UC_RESET_SIE 0x04 +#define USBHS_UC_CLR_ALL 0x02 +#define USBHS_UC_DMA_EN 0x01 + +/* R8_USB_INT_EN */ +#define USBHS_UIE_DEV_NAK 0x80 +#define USBHS_UIE_ISO_ACT 0x40 +#define USBHS_UIE_SETUP_ACT 0x20 +#define USBHS_UIE_FIFO_OV 0x10 +#define USBHS_UIE_SOF_ACT 0x08 +#define USBHS_UIE_SUSPEND 0x04 +#define USBHS_UIE_TRANSFER 0x02 +#define USBHS_UIE_DETECT 0x01 +#define USBHS_UIE_BUS_RST 0x01 + +/* R16_USB_DEV_AD */ +#define USBHS_MASK_USB_ADDR 0x7F + +/* R16_USB_FRAME_NO */ +#define USBHS_MICRO_FRAME_NUM 0xE000 +#define USBHS_SOF_FRAME_NUM 0x07FF + +/* R8_USB_SUSPEND */ +#define USBHS_USB_LINESTATE 0x30 +#define USBHS_USB_WAKEUP_ST 0x04 +#define USBHS_USB_SYS_MOD 0x03 + +/* R8_USB_SPEED_TYPE */ +#define USBHS_USB_SPEED_TYPE 0x03 +#define USBHS_USB_SPEED_LOW 0x02 +#define USBHS_USB_SPEED_FULL 0x00 +#define USBHS_USB_SPEED_HIGH 0x01 + +/* R8_USB_MIS_ST */ +#define USBHS_UMS_SOF_PRES 0x80 +#define USBHS_UMS_SOF_ACT 0x40 +#define USBHS_UMS_SIE_FREE 0x20 +#define USBHS_UMS_R_FIFO_RDY 0x10 +#define USBHS_UMS_BUS_RESET 0x08 +#define USBHS_UMS_SUSPEND 0x04 +#define USBHS_UMS_DEV_ATTACH 0x02 +#define USBHS_UMS_SPLIT_CAN 0x01 + +/* R8_USB_INT_FG */ +#define USBHS_UIF_ISO_ACT 0x40 +#define USBHS_UIF_SETUP_ACT 0x20 +#define USBHS_UIF_FIFO_OV 0x10 +#define USBHS_UIF_HST_SOF 0x08 +#define USBHS_UIF_SUSPEND 0x04 +#define USBHS_UIF_TRANSFER 0x02 +#define USBHS_UIF_DETECT 0x01 +#define USBHS_UIF_BUS_RST 0x01 + +/* R8_USB_INT_ST */ +#define USBHS_UIS_IS_NAK 0x80 +#define USBHS_UIS_TOG_OK 0x40 +#define USBHS_UIS_TOKEN_MASK 0x30 +#define USBHS_UIS_TOKEN_OUT 0x00 +#define USBHS_UIS_TOKEN_SOF 0x10 +#define USBHS_UIS_TOKEN_IN 0x20 +#define USBHS_UIS_TOKEN_SETUP 0x30 +#define USBHS_UIS_ENDP_MASK 0x0F +#define USBHS_UIS_H_RES_MASK 0x0F + +/* R16_USB_RX_LEN */ +#define USBHS_USB_RX_LEN 0xFFFF + +/* R32_UEP_CONFIG */ +#define USBHS_UEP15_R_EN 0x80000000 +#define USBHS_UEP14_R_EN 0x40000000 +#define USBHS_UEP13_R_EN 0x20000000 +#define USBHS_UEP12_R_EN 0x10000000 +#define USBHS_UEP11_R_EN 0x08000000 +#define USBHS_UEP10_R_EN 0x04000000 +#define USBHS_UEP9_R_EN 0x02000000 +#define USBHS_UEP8_R_EN 0x01000000 +#define USBHS_UEP7_R_EN 0x00800000 +#define USBHS_UEP6_R_EN 0x00400000 +#define USBHS_UEP5_R_EN 0x00200000 +#define USBHS_UEP4_R_EN 0x00100000 +#define USBHS_UEP3_R_EN 0x00080000 +#define USBHS_UEP2_R_EN 0x00040000 +#define USBHS_UEP1_R_EN 0x00020000 +#define USBHS_UEP0_R_EN 0x00010000 +#define USBHS_UEP15_T_EN 0x00008000 +#define USBHS_UEP14_T_EN 0x00004000 +#define USBHS_UEP13_T_EN 0x00002000 +#define USBHS_UEP12_T_EN 0x00001000 +#define USBHS_UEP11_T_EN 0x00000800 +#define USBHS_UEP10_T_EN 0x00000400 +#define USBHS_UEP9_T_EN 0x00000200 +#define USBHS_UEP8_T_EN 0x00000100 +#define USBHS_UEP7_T_EN 0x00000080 +#define USBHS_UEP6_T_EN 0x00000040 +#define USBHS_UEP5_T_EN 0x00000020 +#define USBHS_UEP4_T_EN 0x00000010 +#define USBHS_UEP3_T_EN 0x00000008 +#define USBHS_UEP2_T_EN 0x00000004 +#define USBHS_UEP1_T_EN 0x00000002 +#define USBHS_UEP0_T_EN 0x00000001 + +/* R32_UEP_TYPE */ +#define USBHS_UEP15_R_TYPE 0x80000000 +#define USBHS_UEP14_R_TYPE 0x40000000 +#define USBHS_UEP13_R_TYPE 0x20000000 +#define USBHS_UEP12_R_TYPE 0x10000000 +#define USBHS_UEP11_R_TYPE 0x08000000 +#define USBHS_UEP10_R_TYPE 0x04000000 +#define USBHS_UEP9_R_TYPE 0x02000000 +#define USBHS_UEP8_R_TYPE 0x01000000 +#define USBHS_UEP7_R_TYPE 0x00800000 +#define USBHS_UEP6_R_TYPE 0x00400000 +#define USBHS_UEP5_R_TYPE 0x00200000 +#define USBHS_UEP4_R_TYPE 0x00100000 +#define USBHS_UEP3_R_TYPE 0x00080000 +#define USBHS_UEP2_R_TYPE 0x00040000 +#define USBHS_UEP1_R_TYPE 0x00020000 +#define USBHS_UEP0_R_TYPE 0x00010000 +#define USBHS_UEP15_T_TYPE 0x00008000 +#define USBHS_UEP14_T_TYPE 0x00004000 +#define USBHS_UEP13_T_TYPE 0x00002000 +#define USBHS_UEP12_T_TYPE 0x00001000 +#define USBHS_UEP11_T_TYPE 0x00000800 +#define USBHS_UEP10_T_TYPE 0x00000400 +#define USBHS_UEP9_T_TYPE 0x00000200 +#define USBHS_UEP8_T_TYPE 0x00000100 +#define USBHS_UEP7_T_TYPE 0x00000080 +#define USBHS_UEP6_T_TYPE 0x00000040 +#define USBHS_UEP5_T_TYPE 0x00000020 +#define USBHS_UEP4_T_TYPE 0x00000010 +#define USBHS_UEP3_T_TYPE 0x00000008 +#define USBHS_UEP2_T_TYPE 0x00000004 +#define USBHS_UEP1_T_TYPE 0x00000002 +#define USBHS_UEP0_T_TYPE 0x00000001 + +/* R32_UEP_BUF_MOD */ +#define USBHS_UEP15_ISO_BUF_MOD 0x80000000 +#define USBHS_UEP14_ISO_BUF_MOD 0x40000000 +#define USBHS_UEP13_ISO_BUF_MOD 0x20000000 +#define USBHS_UEP12_ISO_BUF_MOD 0x10000000 +#define USBHS_UEP11_ISO_BUF_MOD 0x08000000 +#define USBHS_UEP10_ISO_BUF_MOD 0x04000000 +#define USBHS_UEP9_ISO_BUF_MOD 0x02000000 +#define USBHS_UEP8_ISO_BUF_MOD 0x01000000 +#define USBHS_UEP7_ISO_BUF_MOD 0x00800000 +#define USBHS_UEP6_ISO_BUF_MOD 0x00400000 +#define USBHS_UEP5_ISO_BUF_MOD 0x00200000 +#define USBHS_UEP4_ISO_BUF_MOD 0x00100000 +#define USBHS_UEP3_ISO_BUF_MOD 0x00080000 +#define USBHS_UEP2_ISO_BUF_MOD 0x00040000 +#define USBHS_UEP1_ISO_BUF_MOD 0x00020000 +#define USBHS_UEP0_ISO_BUF_MOD 0x00010000 +#define USBHS_UEP15_BUF_MOD 0x00008000 +#define USBHS_UEP14_BUF_MOD 0x00004000 +#define USBHS_UEP13_BUF_MOD 0x00002000 +#define USBHS_UEP12_BUF_MOD 0x00001000 +#define USBHS_UEP11_BUF_MOD 0x00000800 +#define USBHS_UEP10_BUF_MOD 0x00000400 +#define USBHS_UEP9_BUF_MOD 0x00000200 +#define USBHS_UEP8_BUF_MOD 0x00000100 +#define USBHS_UEP7_BUF_MOD 0x00000080 +#define USBHS_UEP6_BUF_MOD 0x00000040 +#define USBHS_UEP5_BUF_MOD 0x00000020 +#define USBHS_UEP4_BUF_MOD 0x00000010 +#define USBHS_UEP3_BUF_MOD 0x00000008 +#define USBHS_UEP2_BUF_MOD 0x00000004 +#define USBHS_UEP1_BUF_MOD 0x00000002 +#define USBHS_UEP0_BUF_MOD 0x00000001 + +/* R32_UEP0_DMA */ +#define USBHS_UEP0_DMA 0x0000FFFF + +/* R32_UEPn_TX_DMA, n=1-15 */ +#define USBHS_UEPn_TX_DMA 0x0000FFFF + +/* R32_UEPn_RX_DMA, n=1-15 */ +#define USBHS_UEPn_RX_DMA 0x0000FFFF + +/* R16_UEPn_MAX_LEN, n=0-15 */ +#define USBHS_UEPn_MAX_LEN 0x07FF + +/* R16_UEPn_T_LEN, n=0-15 */ +#define USBHS_UEPn_T_LEN 0x07FF + +/* R8_UEPn_TX_CTRL, n=0-15 */ +#define USBHS_UEP_T_TOG_AUTO 0x20 +#define USBHS_UEP_T_TOG_MASK 0x18 +#define USBHS_UEP_T_TOG_DATA0 0x00 +#define USBHS_UEP_T_TOG_DATA1 0x08 +#define USBHS_UEP_T_TOG_DATA2 0x10 +#define USBHS_UEP_T_TOG_MDATA 0x18 +#define USBHS_UEP_T_RES_MASK 0x03 +#define USBHS_UEP_T_RES_ACK 0x00 +#define USBHS_UEP_T_RES_NYET 0x01 +#define USBHS_UEP_T_RES_NAK 0x02 +#define USBHS_UEP_T_RES_STALL 0x03 + +/* R8_UEPn_TX_CTRL, n=0-15 */ +#define USBHS_UEP_R_TOG_AUTO 0x20 +#define USBHS_UEP_R_TOG_MASK 0x18 +#define USBHS_UEP_R_TOG_DATA0 0x00 +#define USBHS_UEP_R_TOG_DATA1 0x08 +#define USBHS_UEP_R_TOG_DATA2 0x10 +#define USBHS_UEP_R_TOG_MDATA 0x18 +#define USBHS_UEP_R_RES_MASK 0x03 +#define USBHS_UEP_R_RES_ACK 0x00 +#define USBHS_UEP_R_RES_NYET 0x01 +#define USBHS_UEP_R_RES_NAK 0x02 +#define USBHS_UEP_R_RES_STALL 0x03 + +/* R8_UHOST_CTRL */ +#define USBHS_UH_SOF_EN 0x80 +#define USBHS_UH_SOF_FREE 0x40 +#define USBHS_UH_PHY_SUSPENDM 0x10 +#define USBHS_UH_REMOTE_WKUP 0x08 +#define USBHS_UH_TX_BUS_RESUME 0x04 +#define USBHS_UH_TX_BUS_SUSPEND 0x02 +#define USBHS_UH_TX_BUS_RESET 0x01 + +/* R32_UH_CONFIG */ +#define USBHS_UH_EP_RX_EN 0x00040000 +#define USBHS_UH_EP_TX_EN 0x00000008 + +/* R32_UH_EP_TYPE */ +#define USBHS_UH_EP_RX_TYPE 0x00040000 +#define USBHS_UH_EP_TX_TYPE 0x00000008 + +/* R32_UH_RX_DMA */ +#define USBHS_UH_RX_DMA 0x0000FFFC + +/* R32_UH_TX_DMA */ +#define USBHS_UH_TX_DMA 0x0000FFFF + +/* R16_UH_RX_MAX_LEN */ +#define USBHS_UH_RX_MAX_LEN 0x07FF + +/* R8_UH_EP_PID */ +#define USBHS_UH_TOKEN_MASK 0xF0 +#define USBHS_UH_ENDP_MASK 0x0F + +/* R8_UH_RX_CTRL */ +#define USBHS_UH_R_DATA_NO 0x40 +#define USBHS_UH_R_TOG_AUTO 0x20 +#define USBHS_UH_R_TOG_MASK 0x18 +#define USBHS_UH_R_TOG_DATA0 0x00 +#define USBHS_UH_R_TOG_DATA1 0x08 +#define USBHS_UH_R_TOG_DATA2 0x10 +#define USBHS_UH_R_TOG_MDATA 0x18 +#define USBHS_UH_R_RES_NO 0x04 +#define USBHS_UH_R_RES_MASK 0x03 +#define USBHS_UH_R_RES_ACK 0x00 +#define USBHS_UH_R_RES_NYET 0x01 +#define USBHS_UH_R_RES_NAK 0x02 +#define USBHS_UH_R_RES_STALL 0x03 + +/* R16_UH_TX_LEN */ +#define USBHS_UH_TX_LEN 0x07FF + +/* R8_UH_TX_CTRL */ +#define USBHS_UH_T_DATA_NO 0x40 +#define USBHS_UH_T_AUTO_TOG 0x20 +#define USBHS_UH_T_TOG_MASK 0x18 +#define USBHS_UH_T_TOG_DATA0 0x00 +#define USBHS_UH_T_TOG_DATA1 0x08 +#define USBHS_UH_T_TOG_DATA2 0x10 +#define USBHS_UH_T_TOG_MDATA 0x18 +#define USBHS_UH_T_RES_NO 0x04 +#define USBHS_UH_T_RES_MASK 0x03 +#define USBHS_UH_T_RES_ACK 0x00 +#define USBHS_UH_T_RES_NYET 0x01 +#define USBHS_UH_T_RES_NAK 0x02 +#define USBHS_UH_T_RES_STALL 0x03 + +/* R16_UH_SPLIT_DATA */ +#define USBHS_UH_SPLIT_DATA 0x0FFF + + +/*******************************************************************************/ +/* USBFS Related Register Macro Definition */ + +/* R8_USB_CTRL */ +#define USBFS_UC_HOST_MODE 0x80 +#define USBFS_UC_LOW_SPEED 0x40 +#define USBFS_UC_DEV_PU_EN 0x20 +#define USBFS_UC_SYS_CTRL_MASK 0x30 +#define USBFS_UC_SYS_CTRL0 0x00 +#define USBFS_UC_SYS_CTRL1 0x10 +#define USBFS_UC_SYS_CTRL2 0x20 +#define USBFS_UC_SYS_CTRL3 0x30 +#define USBFS_UC_INT_BUSY 0x08 +#define USBFS_UC_RESET_SIE 0x04 +#define USBFS_UC_CLR_ALL 0x02 +#define USBFS_UC_DMA_EN 0x01 + +/* R8_USB_INT_EN */ +#define USBFS_UIE_DEV_SOF 0x80 +#define USBFS_UIE_DEV_NAK 0x40 +#define USBFS_UIE_FIFO_OV 0x10 +#define USBFS_UIE_HST_SOF 0x08 +#define USBFS_UIE_SUSPEND 0x04 +#define USBFS_UIE_TRANSFER 0x02 +#define USBFS_UIE_DETECT 0x01 +#define USBFS_UIE_BUS_RST 0x01 + +/* R8_USB_DEV_AD */ +#define USBFS_UDA_GP_BIT 0x80 +#define USBFS_USB_ADDR_MASK 0x7F + +/* R8_USB_MIS_ST */ +#define USBFS_UMS_SOF_PRES 0x80 +#define USBFS_UMS_SOF_ACT 0x40 +#define USBFS_UMS_SIE_FREE 0x20 +#define USBFS_UMS_R_FIFO_RDY 0x10 +#define USBFS_UMS_BUS_RESET 0x08 +#define USBFS_UMS_SUSPEND 0x04 +#define USBFS_UMS_DM_LEVEL 0x02 +#define USBFS_UMS_DEV_ATTACH 0x01 + +/* R8_USB_INT_FG */ +#define USBFS_U_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received +#define USBFS_U_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK +#define USBFS_U_SIE_FREE 0x20 // RO, indicate USB SIE free status +#define USBFS_UIF_FIFO_OV 0x10 // FIFO overflow interrupt flag for USB, direct bit address clear or write 1 to clear +#define USBFS_UIF_HST_SOF 0x08 // host SOF timer interrupt flag for USB host, direct bit address clear or write 1 to clear +#define USBFS_UIF_SUSPEND 0x04 // USB suspend or resume event interrupt flag, direct bit address clear or write 1 to clear +#define USBFS_UIF_TRANSFER 0x02 // USB transfer completion interrupt flag, direct bit address clear or write 1 to clear +#define USBFS_UIF_DETECT 0x01 // device detected event interrupt flag for USB host mode, direct bit address clear or write 1 to clear +#define USBFS_UIF_BUS_RST 0x01 // bus reset event interrupt flag for USB device mode, direct bit address clear or write 1 to clear + +/* R8_USB_INT_ST */ +#define USBFS_UIS_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received for USB device mode +#define USBFS_UIS_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK +#define USBFS_UIS_TOKEN_MASK 0x30 // RO, bit mask of current token PID code received for USB device mode +#define USBFS_UIS_TOKEN_OUT 0x00 +#define USBFS_UIS_TOKEN_SOF 0x10 +#define USBFS_UIS_TOKEN_IN 0x20 +#define USBFS_UIS_TOKEN_SETUP 0x30 +// bUIS_TOKEN1 & bUIS_TOKEN0: current token PID code received for USB device mode +// 00: OUT token PID received +// 01: SOF token PID received +// 10: IN token PID received +// 11: SETUP token PID received +#define USBFS_UIS_ENDP_MASK 0x0F // RO, bit mask of current transfer endpoint number for USB device mode +#define USBFS_UIS_H_RES_MASK 0x0F // RO, bit mask of current transfer handshake response for USB host mode: 0000=no response, time out from device, others=handshake response PID received + +/* R32_USB_OTG_CR */ +#define USBFS_CR_SESS_VTH 0x20 +#define USBFS_CR_VBUS_VTH 0x10 +#define USBFS_CR_OTG_EN 0x08 +#define USBFS_CR_IDPU 0x04 +#define USBFS_CR_CHARGE_VBUS 0x02 +#define USBFS_CR_DISCHAR_VBUS 0x01 + +/* R32_USB_OTG_SR */ +#define USBFS_SR_ID_DIG 0x08 +#define USBFS_SR_SESS_END 0x04 +#define USBFS_SR_SESS_VLD 0x02 +#define USBFS_SR_VBUS_VLD 0x01 + +/* R8_UDEV_CTRL */ +#define USBFS_UD_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable +#define USBFS_UD_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level +#define USBFS_UD_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level +#define USBFS_UD_LOW_SPEED 0x04 // enable USB physical port low speed: 0=full speed, 1=low speed +#define USBFS_UD_GP_BIT 0x02 // general purpose bit +#define USBFS_UD_PORT_EN 0x01 // enable USB physical port I/O: 0=disable, 1=enable + +/* R8_UEP4_1_MOD */ +#define USBFS_UEP1_RX_EN 0x80 // enable USB endpoint 1 receiving (OUT) +#define USBFS_UEP1_TX_EN 0x40 // enable USB endpoint 1 transmittal (IN) +#define USBFS_UEP1_BUF_MOD 0x10 // buffer mode of USB endpoint 1 +#define USBFS_UEP4_RX_EN 0x08 // enable USB endpoint 4 receiving (OUT) +#define USBFS_UEP4_TX_EN 0x04 // enable USB endpoint 4 transmittal (IN) +#define USBFS_UEP4_BUF_MOD 0x01 + +/* R8_UEP2_3_MOD */ +#define USBFS_UEP3_RX_EN 0x80 // enable USB endpoint 3 receiving (OUT) +#define USBFS_UEP3_TX_EN 0x40 // enable USB endpoint 3 transmittal (IN) +#define USBFS_UEP3_BUF_MOD 0x10 // buffer mode of USB endpoint 3 +#define USBFS_UEP2_RX_EN 0x08 // enable USB endpoint 2 receiving (OUT) +#define USBFS_UEP2_TX_EN 0x04 // enable USB endpoint 2 transmittal (IN) +#define USBFS_UEP2_BUF_MOD 0x01 // buffer mode of USB endpoint 2 + +/* R8_UEP5_6_MOD */ +#define USBFS_UEP6_RX_EN 0x80 // enable USB endpoint 6 receiving (OUT) +#define USBFS_UEP6_TX_EN 0x40 // enable USB endpoint 6 transmittal (IN) +#define USBFS_UEP6_BUF_MOD 0x10 // buffer mode of USB endpoint 6 +#define USBFS_UEP5_RX_EN 0x08 // enable USB endpoint 5 receiving (OUT) +#define USBFS_UEP5_TX_EN 0x04 // enable USB endpoint 5 transmittal (IN) +#define USBFS_UEP5_BUF_MOD 0x01 // buffer mode of USB endpoint 5 + +/* R8_UEP7_MOD */ +#define USBFS_UEP7_RX_EN 0x08 // enable USB endpoint 7 receiving (OUT) +#define USBFS_UEP7_TX_EN 0x04 // enable USB endpoint 7 transmittal (IN) +#define USBFS_UEP7_BUF_MOD 0x01 // buffer mode of USB endpoint 7 + +/* R8_UEPn_TX_CTRL */ +#define USBFS_UEP_T_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle +#define USBFS_UEP_T_TOG 0x04 // prepared data toggle flag of USB endpoint X transmittal (IN): 0=DATA0, 1=DATA1 +#define USBFS_UEP_T_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X transmittal (IN) +#define USBFS_UEP_T_RES_ACK 0x00 +#define USBFS_UEP_T_RES_NONE 0x01 +#define USBFS_UEP_T_RES_NAK 0x02 +#define USBFS_UEP_T_RES_STALL 0x03 +// bUEP_T_RES1 & bUEP_T_RES0: handshake response type for USB endpoint X transmittal (IN) +// 00: DATA0 or DATA1 then expecting ACK (ready) +// 01: DATA0 or DATA1 then expecting no response, time out from host, for non-zero endpoint isochronous transactions +// 10: NAK (busy) +// 11: STALL (error) +// host aux setup + +/* R8_UEPn_RX_CTRL, n=0-7 */ +#define USBFS_UEP_R_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle +#define USBFS_UEP_R_TOG 0x04 // expected data toggle flag of USB endpoint X receiving (OUT): 0=DATA0, 1=DATA1 +#define USBFS_UEP_R_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X receiving (OUT) +#define USBFS_UEP_R_RES_ACK 0x00 +#define USBFS_UEP_R_RES_NONE 0x01 +#define USBFS_UEP_R_RES_NAK 0x02 +#define USBFS_UEP_R_RES_STALL 0x03 +// RB_UEP_R_RES1 & RB_UEP_R_RES0: handshake response type for USB endpoint X receiving (OUT) +// 00: ACK (ready) +// 01: no response, time out to host, for non-zero endpoint isochronous transactions +// 10: NAK (busy) +// 11: STALL (error) + +/* R8_UHOST_CTRL */ +#define USBFS_UH_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable +#define USBFS_UH_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level +#define USBFS_UH_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level +#define USBFS_UH_LOW_SPEED 0x04 // enable USB port low speed: 0=full speed, 1=low speed +#define USBFS_UH_BUS_RESET 0x02 // control USB bus reset: 0=normal, 1=force bus reset +#define USBFS_UH_PORT_EN 0x01 // enable USB port: 0=disable, 1=enable port, automatic disabled if USB device detached + +/* R32_UH_EP_MOD */ +#define USBFS_UH_EP_TX_EN 0x40 // enable USB host OUT endpoint transmittal +#define USBFS_UH_EP_TBUF_MOD 0x10 // buffer mode of USB host OUT endpoint +// bUH_EP_TX_EN & bUH_EP_TBUF_MOD: USB host OUT endpoint buffer mode, buffer start address is UH_TX_DMA +// 0 x: disable endpoint and disable buffer +// 1 0: 64 bytes buffer for transmittal (OUT endpoint) +// 1 1: dual 64 bytes buffer by toggle bit bUH_T_TOG selection for transmittal (OUT endpoint), total=128bytes +#define USBFS_UH_EP_RX_EN 0x08 // enable USB host IN endpoint receiving +#define USBFS_UH_EP_RBUF_MOD 0x01 // buffer mode of USB host IN endpoint +// bUH_EP_RX_EN & bUH_EP_RBUF_MOD: USB host IN endpoint buffer mode, buffer start address is UH_RX_DMA +// 0 x: disable endpoint and disable buffer +// 1 0: 64 bytes buffer for receiving (IN endpoint) +// 1 1: dual 64 bytes buffer by toggle bit bUH_R_TOG selection for receiving (IN endpoint), total=128bytes + +/* R16_UH_SETUP */ +#define USBFS_UH_PRE_PID_EN 0x0400 // USB host PRE PID enable for low speed device via hub +#define USBFS_UH_SOF_EN 0x0004 // USB host automatic SOF enable + +/* R8_UH_EP_PID */ +#define USBFS_UH_TOKEN_MASK 0xF0 // bit mask of token PID for USB host transfer +#define USBFS_UH_ENDP_MASK 0x0F // bit mask of endpoint number for USB host transfer + +/* R8_UH_RX_CTRL */ +#define USBFS_UH_R_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle +#define USBFS_UH_R_TOG 0x04 // expected data toggle flag of host receiving (IN): 0=DATA0, 1=DATA1 +#define USBFS_UH_R_RES 0x01 // prepared handshake response type for host receiving (IN): 0=ACK (ready), 1=no response, time out to device, for isochronous transactions + +/* R8_UH_TX_CTRL */ +#define USBFS_UH_T_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle +#define USBFS_UH_T_TOG 0x04 // prepared data toggle flag of host transmittal (SETUP/OUT): 0=DATA0, 1=DATA1 +#define USBFS_UH_T_RES 0x01 // expected handshake response type for host transmittal (SETUP/OUT): 0=ACK (ready), 1=no response, time out from device, for isochronous transactions + + +/*******************************************************************************/ +/* Struct Definition */ + +/* USB Setup Request */ +typedef struct __attribute__((packed)) _USB_SETUP_REQ +{ + uint8_t bRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} USB_SETUP_REQ, *PUSB_SETUP_REQ; + +/* USB Device Descriptor */ +typedef struct __attribute__((packed)) _USB_DEVICE_DESCR +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} USB_DEV_DESCR, *PUSB_DEV_DESCR; + +/* USB Configuration Descriptor */ +typedef struct __attribute__((packed)) _USB_CONFIG_DESCR +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t MaxPower; +} USB_CFG_DESCR, *PUSB_CFG_DESCR; + +/* USB Interface Descriptor */ +typedef struct __attribute__((packed)) _USB_INTERF_DESCR +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} USB_ITF_DESCR, *PUSB_ITF_DESCR; + +/* USB Endpoint Descriptor */ +typedef struct __attribute__((packed)) _USB_ENDPOINT_DESCR +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint8_t wMaxPacketSizeL; + uint8_t wMaxPacketSizeH; + uint8_t bInterval; +} USB_ENDP_DESCR, *PUSB_ENDP_DESCR; + +/* USB Configuration Descriptor Set */ +typedef struct __attribute__((packed)) _USB_CONFIG_DESCR_LONG +{ + USB_CFG_DESCR cfg_descr; + USB_ITF_DESCR itf_descr; + USB_ENDP_DESCR endp_descr[ 1 ]; +} USB_CFG_DESCR_LONG, *PUSB_CFG_DESCR_LONG; + +/* USB HUB Descriptor */ +typedef struct __attribute__((packed)) _USB_HUB_DESCR +{ + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint8_t wHubCharacteristicsL; + uint8_t wHubCharacteristicsH; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable; + uint8_t PortPwrCtrlMask; +} USB_HUB_DESCR, *PUSB_HUB_DESCR; + +/* USB HID Descriptor */ +typedef struct __attribute__((packed)) _USB_HID_DESCR +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescriptorTypeX; + uint8_t wDescriptorLengthL; + uint8_t wDescriptorLengthH; +} USB_HID_DESCR, *PUSB_HID_DESCR; + +/* USB UDisk */ +typedef struct __attribute__((packed)) _UDISK_BOC_CBW +{ + uint32_t mCBW_Sig; + uint32_t mCBW_Tag; + uint32_t mCBW_DataLen; + uint8_t mCBW_Flag; + uint8_t mCBW_LUN; + uint8_t mCBW_CB_Len; + uint8_t mCBW_CB_Buf[ 16 ]; +} UDISK_BOC_CBW, *PXUDISK_BOC_CBW; + +/* USB UDisk */ +typedef struct __attribute__((packed)) _UDISK_BOC_CSW +{ + uint32_t mCBW_Sig; + uint32_t mCBW_Tag; + uint32_t mCSW_Residue; + uint8_t mCSW_Status; +} UDISK_BOC_CSW, *PXUDISK_BOC_CSW; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CH32V30x_USB_H */ diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/ch32v30x_usbhs_host.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/ch32v30x_usbhs_host.h new file mode 100644 index 000000000..f7060ba9a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/ch32v30x_usbhs_host.h @@ -0,0 +1,114 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : ch32v30x_usbhs_host.h +* Author : WCH +* Version : V1.0.0 +* Date : 2021/06/06 +* Description : This file contains all the functions prototypes for the USB +* Host firmware library. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + + +#ifndef __CH32V30x_USBHS_HOST_H +#define __CH32V30x_USBHS_HOST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*******************************************************************************/ +/* Header Files */ +#include "ch32v30x.h" +#include "ch32v30x_usb.h" + +/*******************************************************************************/ +/* USB Setup Request Macro Definition */ +#define pUSBHS_SetupRequest ( (PUSB_SETUP_REQ)USBHS_TX_Buf ) + +/*******************************************************************************/ +/* Constant Definition */ +#ifndef DEF_GET_USB_DEV_DESC +#define DEF_GET_USB_DEV_DESC +/* Get Device Descriptor Command Packet */ +__attribute__((aligned(4))) static const uint8_t SetupGetDevDesc[ ] = +{ + USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_DEVICE, 0x00, 0x00, sizeof( USB_DEV_DESCR ), 0x00 +}; + +/* Get Configuration Descriptor Command Packet */ +__attribute__((aligned(4))) static const uint8_t SetupGetCfgDesc[ ] = +{ + USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_CONFIG, 0x00, 0x00, 0x04, 0x00 +}; + +/* Get String Descriptor Command Packet */ +__attribute__((aligned(4))) static const uint8_t SetupGetStrDesc[ ] = +{ + USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_STRING, 0x09, 0x04, 0x04, 0x00 +}; + +/* Set USB Address Command Packet */ +__attribute__((aligned(4))) static const uint8_t SetupSetAddr[ ] = +{ + USB_REQ_TYP_OUT, USB_SET_ADDRESS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Set USB Configuration Command Packet */ +__attribute__((aligned(4))) static const uint8_t SetupSetConfig[ ] = +{ + USB_REQ_TYP_OUT, USB_SET_CONFIGURATION, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Clear Endpoint STALL Command Packet */ +__attribute__((aligned(4))) static const uint8_t SetupClearEndpStall[ ] = +{ + USB_REQ_TYP_OUT | USB_REQ_RECIP_ENDP, USB_CLEAR_FEATURE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Set Device Interface Command Packet */ +__attribute__((aligned(4))) static const uint8_t SetupSetInterface[ ] = +{ + USB_REQ_RECIP_INTERF, USB_SET_INTERFACE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif + +/*******************************************************************************/ +/* Variable Declaration */ +extern __attribute__((aligned(4))) uint8_t RxBuffer[ MAX_PACKET_SIZE ]; +extern __attribute__((aligned(4))) uint8_t TxBuffer[ MAX_PACKET_SIZE ]; + +#define USBHS_RX_Buf RxBuffer +#define USBHS_TX_Buf TxBuffer + +/*******************************************************************************/ +/* Function Declaration */ +extern void USBHS_RCC_Init( void ); +extern void USBHS_Host_Init( FunctionalState sta ); +extern uint8_t USBHSH_CheckRootHubPortStatus( uint8_t status ); +extern uint8_t USBHSH_CheckRootHubPortEnable( void ); +extern uint8_t USBHSH_CheckRootHubPortSpeed( void ); +extern void USBHSH_SetSelfAddr( uint8_t addr ); +extern void USBHSH_SetSelfSpeed( uint8_t speed ); +extern void USBHSH_ResetRootHubPort( uint8_t mode ); +extern uint8_t USBHSH_EnableRootHubPort( uint8_t *pspeed ); +extern uint8_t USBHSH_Transact( uint8_t endp_pid, uint8_t endp_tog, uint32_t timeout ); +extern uint8_t USBHSH_CtrlTransfer( uint8_t ep0_size, uint8_t *pbuf, uint16_t *plen ); +extern uint8_t USBHSH_GetDeviceDescr( uint8_t *pep0_size, uint8_t *pbuf ); +extern uint8_t USBHSH_GetConfigDescr( uint8_t ep0_size, uint8_t *pbuf, uint16_t buf_len, uint16_t *pcfg_len ); +extern uint8_t USBHSH_GetStrDescr( uint8_t ep0_size, uint8_t str_num, uint8_t *pbuf ); +extern uint8_t USBHSH_SetUsbAddress( uint8_t ep0_size, uint8_t addr ); +extern uint8_t USBHSH_SetUsbConfig( uint8_t ep0_size, uint8_t cfg_val ); +extern uint8_t USBHSH_ClearEndpStall( uint8_t ep0_size, uint8_t endp_num ); +extern uint8_t USBHSH_GetEndpData( uint8_t endp_num, uint8_t *pendp_tog, uint8_t *pbuf, uint16_t *plen ); +extern uint8_t USBHSH_SendEndpData( uint8_t endp_num, uint8_t *pendp_tog, uint8_t *pbuf, uint16_t len ); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/usb_host_config.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/usb_host_config.h new file mode 100644 index 000000000..6e99c702a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/inc/usb_host_config.h @@ -0,0 +1,174 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : usb_host_config.h + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/29 + * Description : +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#ifndef __USB_HOST_CONFIG_H +#define __USB_HOST_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************/ +/* Header File */ +#include "string.h" +#include "debug.h" +#include "ch32v30x_usb.h" +#include "ch32v30x_usbhs_host.h" + +/******************************************************************************/ +/* USB Host Communication Related Macro Definition */ + +/* USB Host Port General Control */ +/* CH32V303x, Support USBFS Host/Slave Only */ +/* CH32V305FB, Support USBHS Host/Slave Only */ +/* CH32V305RB, CH32V307, Support USBHS/USBFS Host/Slave */ +#define DEF_TOTAL_ROOT_HUB 2 +#define DEF_USB_PORT_FS_EN 0 +#define DEF_USB_PORT_HS_EN 1 +#define DEF_USB_PORT_FS 0x00 +#define DEF_USB_PORT_HS 0x01 + +/* USB Root Device Status */ +#define ROOT_DEV_DISCONNECT 0 +#define ROOT_DEV_CONNECTED 1 +#define ROOT_DEV_FAILED 2 +#define ROOT_DEV_SUCCESS 3 + +/* USB Device Address */ +#define USB_DEVICE_ADDR 0x02 + +/* USB Speed */ +#define USB_LOW_SPEED 0x00 +#define USB_FULL_SPEED 0x01 +#define USB_HIGH_SPEED 0x02 +#define USB_SPEED_CHECK_ERR 0xFF + +/* Configuration Descriptor Type */ +#define DEF_DECR_CONFIG 0x02 +#define DEF_DECR_INTERFACE 0x04 +#define DEF_DECR_ENDPOINT 0x05 +#define DEF_DECR_HID 0x21 + +/* USB Communication Status Code */ +#define ERR_SUCCESS 0x00 +#define ERR_USB_CONNECT 0x15 +#define ERR_USB_DISCON 0x16 +#define ERR_USB_BUF_OVER 0x17 +#define ERR_USB_DISK_ERR 0x1F +#define ERR_USB_TRANSFER 0x20 +#define ERR_USB_UNSUPPORT 0xFB +#define ERR_USB_UNAVAILABLE 0xFC +#define ERR_USB_UNKNOWN 0xFE + +/* USB Device Enumeration Status Code */ +#define DEF_DEV_DESCR_GETFAIL 0x45 +#define DEF_DEV_ADDR_SETFAIL 0x46 +#define DEF_CFG_DESCR_GETFAIL 0x47 +#define DEF_REP_DESCR_GETFAIL 0x48 +#define DEF_DEV_TYPE_UNKNOWN 0xFF + +/* USB Communication Time */ +#define DEF_BUS_RESET_TIME 11 // USB bus reset time +#define DEF_RE_ATTACH_TIMEOUT 100 // Wait for the USB device to reconnect after reset, 100mS timeout +#define DEF_WAIT_USB_TOUT_200US 1000 +#define DEF_CTRL_TRANS_TIMEOVER_CNT 60000 // Control transmission delay timing + +/* General */ +#define DEF_ONE_USB_SUP_DEV_TOTAL 1 +#define DEF_NEXT_HUB_PORT_NUM_MAX 4 +#define DEF_INTERFACE_NUM_MAX 4 +#define DEF_COM_BUF_LEN 255 + +/* Debug */ +#define DEF_DEBUG_PRINTF 1 +#if ( DEF_DEBUG_PRINTF == 1 ) +#define DUG_PRINTF( format, arg... ) printf( format, ##arg ) +#else +#define DUG_PRINTF( format, arg... ) do{ if( 0 )printf( format, ##arg ); }while( 0 ); +#endif + +/* HUB Port Device */ +typedef struct _HUB_DEVICE +{ + uint8_t bStatus; + uint8_t bType; + uint8_t bAddress; + uint8_t bSpeed; + uint8_t bEp0MaxPks; + uint8_t DeviceIndex; +}HUB_DEVICE, *PHUB_DEVICE; + +/* Root HUB Device Structure, Physical Interface */ +typedef struct _ROOT_HUB_DEVICE +{ + uint8_t bStatus; + uint8_t bType; + uint8_t bAddress; + uint8_t bSpeed; + uint8_t bEp0MaxPks; + uint8_t DeviceIndex; + uint8_t bPortNum; + HUB_DEVICE Device[ DEF_NEXT_HUB_PORT_NUM_MAX ]; +} ROOT_HUB_DEVICE, *PROOT_HUB_DEVICE; + +/* USB Host Control Structure */ +struct __HOST_CTL +{ + uint8_t InterfaceNum; + uint8_t ErrorCount; + + struct interface + { + uint8_t Type; + uint16_t HidDescLen; + uint8_t HidReportID; + uint8_t Full_KB_Flag; + + uint8_t InEndpNum; + uint8_t InEndpAddr[ 4 ]; + uint8_t InEndpType[ 4 ]; + uint16_t InEndpSize[ 4 ]; + uint8_t InEndpTog[ 4 ]; + uint8_t InEndpInterval[ 4 ]; + uint8_t InEndpTimeCount[ 4 ]; + + uint8_t OutEndpNum; + uint8_t OutEndpAddr[ 4 ]; + uint8_t OutEndpType[ 4 ]; + uint16_t OutEndpSize[ 4 ]; + uint8_t OutEndpTog[ 4 ]; + + uint8_t IDFlag; + uint8_t ReportID; + + uint8_t LED_Usage_Min; + uint8_t LED_Usage_Max; + + uint8_t SetReport_Swi; + uint8_t SetReport_Value; + uint8_t SetReport_Flag; + + }Interface[ DEF_INTERFACE_NUM_MAX ]; +}; + +/*******************************************************************************/ +/* Variable Declaration */ +extern uint8_t DevDesc_Buf[ ]; +extern uint8_t Com_Buf[ ]; +extern struct _ROOT_HUB_DEVICE RootHubDev[ ]; +extern struct __HOST_CTL HostCtl[ ]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/CH32V103UFI.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/CH32V103UFI.c new file mode 100644 index 000000000..b806a4466 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/CH32V103UFI.c @@ -0,0 +1,528 @@ +/* 2014.09.09 +***************************************** +** Copyright (C) W.ch 1999-2019 ** +** Web: http://wch.cn ** +***************************************** +** USB-flash File Interface for CHRV3 ** +** KEIL423, gcc 8.20 ** +***************************************** +*/ +/* CHRV3 U盘主机文件系统接口, 支持: FAT12/FAT16/FAT32 */ + +//#define DISK_BASE_BUF_LEN 512 /* 默认的磁盘数据缓冲区大小为512字节(可以选择为2048甚至4096以支持某些大扇区的U盘),为0则禁止在本文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */ +/* 如果需要复用磁盘数据缓冲区以节约RAM,那么可将DISK_BASE_BUF_LEN定义为0以禁止在本文件中定义缓冲区,而由应用程序在调用CHRV3LibInit之前将与其它程序合用的缓冲区起始地址置入pDISK_BASE_BUF变量 */ + +//#define NO_DEFAULT_ACCESS_SECTOR 1 /* 禁止默认的磁盘扇区读写子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_DISK_CONNECT 1 /* 禁止默认的检查磁盘连接子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_FILE_ENUMER 1 /* 禁止默认的文件名枚举回调程序,下面用自行编写的程序代替它 */ +//#include "CHRV3SFR.H" + +#include "debug.h" +#include "ch32v30x.h" +#include "usb_host_config.h" +#include "CHRV3UFI.h" + +uint8_t USBHostTransact( uint8_t endp_pid, uint8_t tog, uint32_t timeout ) +{ +#if DEF_USB_PORT_FS_EN + uint8_t r, trans_rerty; + uint16_t i; + USBOTG_H_FS->HOST_TX_CTRL = USBOTG_H_FS->HOST_RX_CTRL = 0; + if( tog & 0x80 ) + { + USBOTG_H_FS->HOST_RX_CTRL = 1<<2; + } + if( tog & 0x40 ) + { + USBOTG_H_FS->HOST_TX_CTRL = 1<<2; + } + trans_rerty = 0; + do + { + USBOTG_H_FS->HOST_EP_PID = endp_pid; // Specify token PID and endpoint number + USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; // Allow transmission + for( i = DEF_WAIT_USB_TOUT_200US; ( i != 0 ) && ( ( USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER ) == 0 ); i-- ) + { + Delay_Us( 1 ); + } + USBOTG_H_FS->HOST_EP_PID = 0x00; // Stop USB transfer + if( ( USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER ) == 0 ) + { + return ERR_USB_UNKNOWN; + } + else + { + /* Complete transfer */ + if( USBOTG_H_FS->INT_ST & USBFS_UIS_TOG_OK ) + { + return ERR_SUCCESS; + } + r = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; // USB device answer status + if( r == USB_PID_STALL ) + { + return ( r | ERR_USB_TRANSFER ); + } + if( r == USB_PID_NAK ) + { + if( timeout == 0 ) + { + return ( r | ERR_USB_TRANSFER ); + } + if( timeout < 0xFFFF ) + { + timeout--; + } + --trans_rerty; + } + else switch ( endp_pid >> 4 ) + { + case USB_PID_SETUP: + case USB_PID_OUT: + if( r ) + { + return ( r | ERR_USB_TRANSFER ); + } + break; + case USB_PID_IN: + if( ( r == USB_PID_DATA0 ) && ( r == USB_PID_DATA1 ) ) + { + ; + } + else if( r ) + { + return ( r | ERR_USB_TRANSFER ); + } + break; + default: + return ERR_USB_UNKNOWN; + } + } + Delay_Us( 15 ); + if( USBOTG_H_FS->INT_FG & USBFS_UIF_DETECT ) + { + Delay_Us( 200 ); + if( USBFSH_CheckRootHubPortEnable( ) == 0 ) + { + return ERR_USB_DISCON; // USB device disconnect event + } + } + }while( ++trans_rerty < 10 ); + + return ERR_USB_TRANSFER; // Reply timeout +#elif DEF_USB_PORT_HS_EN + uint8_t r, trans_retry; + uint16_t i; + USBHSH->HOST_TX_CTRL = USBHSH->HOST_RX_CTRL = 0; + if( tog & 0x80 ) + { + USBHSH->HOST_RX_CTRL = 1<<3; + } + if( tog & 0x40 ) + { + USBHSH->HOST_TX_CTRL = 1<<3; + } + trans_retry = 0; + do + { + USBHSH->HOST_EP_PID = endp_pid; // Set the token for the host to send the packet + USBHSH->INT_FG = USBHS_UIF_TRANSFER; + for( i = DEF_WAIT_USB_TOUT_200US; ( i != 0 ) && ( ( USBHSH->INT_FG & USBHS_UIF_TRANSFER ) == 0 ); i-- ) + { + Delay_Us( 1 ); + } + USBHSH->HOST_EP_PID = 0x00; + if( ( USBHSH->INT_FG & USBHS_UIF_TRANSFER ) == 0 ) + { + return ERR_USB_UNKNOWN; + } + + if( USBHSH->INT_FG & USBHS_UIF_DETECT ) + { + USBHSH->INT_FG = USBHS_UIF_DETECT; + Delay_Us( 200 ); + if( USBHSH->MIS_ST & USBHS_UIF_TRANSFER ) + { + if( USBHSH->HOST_CTRL & USBHS_UH_SOF_EN ) + { + return ERR_USB_CONNECT; + } + } + else + { + return ERR_USB_DISCON; + } + } + else if( USBHSH->INT_FG & USBHS_UIF_TRANSFER ) // The packet transmission was successful + { + r = USBHSH->INT_ST & USBHS_UIS_H_RES_MASK; + if( ( endp_pid >> 4 ) == USB_PID_IN ) + { + if( USBHSH->INT_ST & USBHS_UIS_TOG_OK ) + { + return ERR_SUCCESS; // Packet token match + } + } + else + { + if( ( r == USB_PID_ACK ) || ( r == USB_PID_NYET ) ) + { + return ERR_SUCCESS; + } + } + if( r == USB_PID_STALL ) + { + return ( r | ERR_USB_TRANSFER ); + } + + if( r == USB_PID_NAK ) + { + if( timeout == 0 ) + { + return ( r | ERR_USB_TRANSFER ); + } + if( timeout < 0xFFFF ) + { + timeout--; + } + --trans_retry; + } + else switch( endp_pid >> 4 ) + { + case USB_PID_SETUP: + + case USB_PID_OUT: + if( r ) + { + return ( r | ERR_USB_TRANSFER ); + } + break; + case USB_PID_IN: + if( ( r == USB_PID_DATA0 ) || ( r == USB_PID_DATA1 ) ) + { + ; + } + else if( r ) + { + return ( r | ERR_USB_TRANSFER ); + } + break; + default: + return ERR_USB_UNKNOWN; + } + } + else + { + USBHSH->INT_FG = USBHS_UIF_DETECT | USBHS_UIF_TRANSFER | USBHS_UIF_SUSPEND | USBHS_UIF_HST_SOF | USBHS_UIF_FIFO_OV | USBHS_UIF_SETUP_ACT; + } + Delay_Us( 15 ); + } while( ++trans_retry < 10 ); + + return ERR_USB_TRANSFER; +#endif +} + +uint8_t HostCtrlTransfer( uint8_t *DataBuf, uint8_t *RetLen ) +{ + uint8_t ret; + uint16_t retlen; + retlen = (uint16_t)(*RetLen); +#if DEF_USB_PORT_FS_EN + ret = USBFSH_CtrlTransfer( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, DataBuf, &retlen ); +#elif DEF_USB_PORT_HS_EN + ret = USBHSH_CtrlTransfer( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, DataBuf, &retlen ); +#endif + return ret; +} + +void CopySetupReqPkg( const char * pReqPkt ) +{ + uint8_t i; + for(i = 0; i != sizeof(USB_SETUP_REQ); i++) + { +#if DEF_USB_PORT_FS_EN + ((char *)pUSBFS_SetupRequest)[i] = *pReqPkt; +#elif DEF_USB_PORT_HS_EN + ((char *)pUSBHS_SetupRequest)[i] = *pReqPkt; +#endif + pReqPkt++; + } +} + +uint8_t CtrlGetDeviceDescrTB( void ) +{ + uint8_t ret; +#if DEF_USB_PORT_FS_EN + ret = USBFSH_GetDeviceDescr( &RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, TxBuffer ); +#elif DEF_USB_PORT_HS_EN + ret = USBHSH_GetDeviceDescr( &RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, TxBuffer ); +#endif + return ret; +} + +uint8_t CtrlGetConfigDescrTB( void ) +{ + uint16_t len; + uint8_t ret; +#if DEF_USB_PORT_FS_EN + ret = USBFSH_GetConfigDescr( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, TxBuffer, 256, &len ); +#elif DEF_USB_PORT_HS_EN + ret = USBHSH_GetConfigDescr( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, TxBuffer, 256, &len ); +#endif + return ret; +} + +uint8_t CtrlSetUsbConfig( uint8_t cfg ) +{ + uint8_t ret; +#if DEF_USB_PORT_FS_EN + ret = USBFSH_SetUsbConfig( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, cfg ); +#elif DEF_USB_PORT_HS_EN + ret = USBHSH_SetUsbConfig( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, cfg ); +#endif + return ret; +} + +uint8_t CtrlSetUsbAddress( uint8_t addr ) +{ + uint8_t ret; +#if DEF_USB_PORT_FS_EN + ret = USBFSH_SetUsbAddress( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, addr ); +#elif DEF_USB_PORT_HS_EN + ret = USBHSH_SetUsbAddress( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, addr ); +#endif + return ret; +} + +uint8_t CtrlClearEndpStall( uint8_t endp ) +{ + uint8_t ret; +#if DEF_USB_PORT_FS_EN + ret = USBFSH_ClearEndpStall( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, endp ); +#elif DEF_USB_PORT_HS_EN + ret = USBHSH_ClearEndpStall( RootHubDev[ DEF_USB_PORT_HS ].bEp0MaxPks, endp ); +#endif + return ret; +} + +#ifndef FOR_ROOT_UDISK_ONLY +uint8_t CtrlGetHubDescr( void ) +{ + +} + +uint8_t HubGetPortStatus( uint8_t HubPortIndex ) +{ + +} + +uint8_t HubSetPortFeature( uint8_t HubPortIndex, uint8_t FeatureSelt ) +{ + +} + +uint8_t HubClearPortFeature( uint8_t HubPortIndex, uint8_t FeatureSelt ) +{ + +} +#endif + +CMD_PARAM_I mCmdParam; /* 命令参数 */ +#if DISK_BASE_BUF_LEN > 0 +//uint8_t DISK_BASE_BUF[ DISK_BASE_BUF_LEN ] __attribute__((at(BA_RAM+SZ_RAM/2))); /* 外部RAM的磁盘数据缓冲区,缓冲区长度为一个扇区的长度 */ +uint8_t DISK_BASE_BUF[ DISK_BASE_BUF_LEN ] __attribute__((aligned (4))); /* 外部RAM的磁盘数据缓冲区,缓冲区长度为一个扇区的长度 */ +//UINT8 DISK_FAT_BUF[ DISK_BASE_BUF_LEN ] __attribute__((aligned (4))); /* 外部RAM的磁盘FAT数据缓冲区,缓冲区长度为一个扇区的长度 */ +#endif + +/* 以下程序可以根据需要修改 */ + +#ifndef NO_DEFAULT_ACCESS_SECTOR /* 在应用程序中定义NO_DEFAULT_ACCESS_SECTOR可以禁止默认的磁盘扇区读写子程序,然后用自行编写的程序代替它 */ +//if ( use_external_interface ) { // 替换U盘扇区底层读写子程序 +// CHRV3vSectorSize=512; // 设置实际的扇区大小,必须是512的倍数,该值是磁盘的扇区大小 +// CHRV3vSectorSizeB=9; // 设置实际的扇区大小的位移数,512则对应9,1024对应10,2048对应11 +// CHRV3DiskStatus=DISK_MOUNTED; // 强制块设备连接成功(只差分析文件系统) +//} + +uint8_t CHRV3ReadSector( uint8_t SectCount, uint8_t *DataBuf ) /* 从磁盘读取多个扇区的数据到缓冲区中 */ +{ + uint8_t retry; +// if ( use_external_interface ) return( extReadSector( CHRV3vLbaCurrent, SectCount, DataBuf ) ); /* 外部接口 */ + for( retry = 0; retry < 3; retry ++ ) { /* 错误重试 */ + pCBW -> mCBW_DataLen = (uint32_t)SectCount << CHRV3vSectorSizeB; /* 数据传输长度 */ + pCBW -> mCBW_Flag = 0x80; + pCBW -> mCBW_LUN = CHRV3vCurrentLun; + pCBW -> mCBW_CB_Len = 10; + pCBW -> mCBW_CB_Buf[ 0 ] = SPC_CMD_READ10; + pCBW -> mCBW_CB_Buf[ 1 ] = 0x00; + pCBW -> mCBW_CB_Buf[ 2 ] = (uint8_t)( CHRV3vLbaCurrent >> 24 ); + pCBW -> mCBW_CB_Buf[ 3 ] = (uint8_t)( CHRV3vLbaCurrent >> 16 ); + pCBW -> mCBW_CB_Buf[ 4 ] = (uint8_t)( CHRV3vLbaCurrent >> 8 ); + pCBW -> mCBW_CB_Buf[ 5 ] = (uint8_t)( CHRV3vLbaCurrent ); + pCBW -> mCBW_CB_Buf[ 6 ] = 0x00; + pCBW -> mCBW_CB_Buf[ 7 ] = 0x00; + pCBW -> mCBW_CB_Buf[ 8 ] = SectCount; + pCBW -> mCBW_CB_Buf[ 9 ] = 0x00; + CHRV3BulkOnlyCmd( DataBuf ); /* 执行基于BulkOnly协议的命令 */ + if ( CHRV3IntStatus == ERR_SUCCESS ) { + return( ERR_SUCCESS ); + } + CHRV3IntStatus = CHRV3AnalyzeError( retry ); + if ( CHRV3IntStatus != ERR_SUCCESS ) { + return( CHRV3IntStatus ); + } + } + return( CHRV3IntStatus = ERR_USB_DISK_ERR ); /* 磁盘操作错误 */ +} + +#ifdef EN_DISK_WRITE +uint8_t CHRV3WriteSector( uint8_t SectCount, uint8_t *DataBuf ) /* 将缓冲区中的多个扇区的数据块写入磁盘 */ +{ + uint8_t retry; +// if ( use_external_interface ) return( extWriteSector( CHRV3vLbaCurrent, SectCount, DataBuf ) ); /* 外部接口 */ + for( retry = 0; retry < 3; retry ++ ) { /* 错误重试 */ + pCBW -> mCBW_DataLen = (uint32_t)SectCount << CHRV3vSectorSizeB; /* 数据传输长度 */ + pCBW -> mCBW_Flag = 0x00; + pCBW -> mCBW_LUN = CHRV3vCurrentLun; + pCBW -> mCBW_CB_Len = 10; + pCBW -> mCBW_CB_Buf[ 0 ] = SPC_CMD_WRITE10; + pCBW -> mCBW_CB_Buf[ 1 ] = 0x00; + pCBW -> mCBW_CB_Buf[ 2 ] = (uint8_t)( CHRV3vLbaCurrent >> 24 ); + pCBW -> mCBW_CB_Buf[ 3 ] = (uint8_t)( CHRV3vLbaCurrent >> 16 ); + pCBW -> mCBW_CB_Buf[ 4 ] = (uint8_t)( CHRV3vLbaCurrent >> 8 ); + pCBW -> mCBW_CB_Buf[ 5 ] = (uint8_t)( CHRV3vLbaCurrent ); + pCBW -> mCBW_CB_Buf[ 6 ] = 0x00; + pCBW -> mCBW_CB_Buf[ 7 ] = 0x00; + pCBW -> mCBW_CB_Buf[ 8 ] = SectCount; + pCBW -> mCBW_CB_Buf[ 9 ] = 0x00; + CHRV3BulkOnlyCmd( DataBuf ); /* 执行基于BulkOnly协议的命令 */ + if ( CHRV3IntStatus == ERR_SUCCESS ) { + Delay_Us( 200 ); /* 写操作后延时 */ + return( ERR_SUCCESS ); + } + CHRV3IntStatus = CHRV3AnalyzeError( retry ); + if ( CHRV3IntStatus != ERR_SUCCESS ) { + return( CHRV3IntStatus ); + } + } + return( CHRV3IntStatus = ERR_USB_DISK_ERR ); /* 磁盘操作错误 */ +} +#endif +#endif // NO_DEFAULT_ACCESS_SECTOR + +#ifndef NO_DEFAULT_DISK_CONNECT /* 在应用程序中定义NO_DEFAULT_DISK_CONNECT可以禁止默认的检查磁盘连接子程序,然后用自行编写的程序代替它 */ + +/* +约定: USB设备地址分配规则(参考USB_DEVICE_ADDR) +地址值 设备位置 +0x02 内置Root-HUB0下的USB设备或外部HUB +0x03 内置Root-HUB1下的USB设备或外部HUB +0x1x 内置Root-HUB0下的外部HUB的端口x下的USB设备,x为1~n +0x2x 内置Root-HUB1下的外部HUB的端口x下的USB设备,x为1~n +*/ + +#define UHUB_DEV_ADDR (USBHSH->DEV_AD) +#define UHUB_MIS_STAT (USBHSH->MIS_ST) +#define UHUB_HOST_CTRL (USBHSH->HOST_CTRL) +#define UHUB_INT_FLAG (USBHSH->INT_FG) +#define bUMS_ATTACH USBHS_UMS_DEV_ATTACH +#define bUMS_SUSPEND USBHS_UMS_SUSPEND + +/* 检查磁盘是否连接 */ +uint8_t CHRV3DiskConnect( void ) +{ + uint8_t ums, devaddr; + UHUB_DEV_ADDR = UHUB_DEV_ADDR & 0x7F; + ums = UHUB_MIS_STAT; + devaddr = UHUB_DEV_ADDR; + if ( devaddr == USB_DEVICE_ADDR+1 ) + { + /* 内置Root-HUB下的USB设备 */ + if ( ums & bUMS_ATTACH ) + { + /* 内置Root-HUB下的USB设备存在 */ + if ( ( ums & bUMS_SUSPEND ) == 0 ) + { + /* 内置Root-HUB下的USB设备存在且未插拔 */ + return( ERR_SUCCESS ); /* USB设备已经连接且未插拔 */ + } + else + { + /* 内置Root-HUB下的USB设备存在 */ + CHRV3DiskStatus = DISK_CONNECT; /* 曾经断开过 */ + return( ERR_SUCCESS ); /* 外部HUB或USB设备已经连接或者断开后重新连接 */ + } + } + else + { + /* USB设备断开 */ +mDiskDisconn: + CHRV3DiskStatus = DISK_DISCONNECT; + return( ERR_USB_DISCON ); + } + } + else + { + goto mDiskDisconn; + } +} +#endif // NO_DEFAULT_DISK_CONNECT + +#ifndef NO_DEFAULT_FILE_ENUMER /* 在应用程序中定义NO_DEFAULT_FILE_ENUMER可以禁止默认的文件名枚举回调程序,然后用自行编写的程序代替它 */ +void xFileNameEnumer( void ) /* 文件名枚举回调子程序 */ +{ +/* 如果指定枚举序号CHRV3vFileSize为0xFFFFFFFF后调用FileOpen,那么每搜索到一个文件FileOpen都会调用本回调程序, + 回调程序xFileNameEnumer返回后,FileOpen递减CHRV3vFileSize并继续枚举直到搜索不到文件或者目录。建议做法是, + 在调用FileOpen之前定义一个全局变量为0,当FileOpen回调本程序后,本程序由CHRV3vFdtOffset得到结构FAT_DIR_INFO, + 分析结构中的DIR_Attr以及DIR_Name判断是否为所需文件名或者目录名,记录相关信息,并将全局变量计数增量, + 当FileOpen返回后,判断返回值如果是ERR_MISS_FILE或ERR_FOUND_NAME都视为操作成功,全局变量为搜索到的有效文件数。 + 如果在本回调程序xFileNameEnumer中将CHRV3vFileSize置为1,那么可以通知FileOpen提前结束搜索。以下是回调程序例子 */ +#if 0 + uint8_t i; + uint16_t FileCount; + PX_FAT_DIR_INFO pFileDir; + uint8_t *NameBuf; + pFileDir = (PX_FAT_DIR_INFO)( pDISK_BASE_BUF + CHRV3vFdtOffset ); /* 当前FDT的起始地址 */ + FileCount = (UINT16)( 0xFFFFFFFF - CHRV3vFileSize ); /* 当前文件名的枚举序号,CHRV3vFileSize初值是0xFFFFFFFF,找到文件名后递减 */ + if ( FileCount < sizeof( FILE_DATA_BUF ) / 12 ) { /* 检查缓冲区是否足够存放,假定每个文件名需占用12个字节存放 */ + NameBuf = & FILE_DATA_BUF[ FileCount * 12 ]; /* 计算保存当前文件名的缓冲区地址 */ + for ( i = 0; i < 11; i ++ ) NameBuf[ i ] = pFileDir -> DIR_Name[ i ]; /* 复制文件名,长度为11个字符,未处理空格 */ +// if ( pFileDir -> DIR_Attr & ATTR_DIRECTORY ) NameBuf[ i ] = 1; /* 判断是目录名 */ + NameBuf[ i ] = 0; /* 文件名结束符 */ + } +#endif +} +#endif // NO_DEFAULT_FILE_ENUMER + +uint8_t CHRV3LibInit( void ) /* 初始化CHRV3程序库,操作成功返回0 */ +{ + uint8_t s; + s = CHRV3GetVer( ); + if( s < CHRV3_LIB_VER ) + { + return( 0xFF ); /* 获取当前子程序库的版本号,版本太低则返回错误 */ + } + printf( "lib vision:%02x\r\n",s ); +#if DISK_BASE_BUF_LEN > 0 + pDISK_BASE_BUF = & DISK_BASE_BUF[0]; /* 指向外部RAM的磁盘数据缓冲区 */ + pDISK_FAT_BUF = & DISK_BASE_BUF[0]; /* 指向外部RAM的磁盘FAT数据缓冲区,可以与pDISK_BASE_BUF合用以节约RAM */ +// pDISK_FAT_BUF = & DISK_FAT_BUF[0]; /* 指向外部RAM的磁盘FAT数据缓冲区,独立于pDISK_BASE_BUF以提高速度 */ +/* 如果希望提高文件存取速度,那么可以在主程序中调用CHRV3LibInit之后,将pDISK_FAT_BUF重新指向另一个独立分配的与pDISK_BASE_BUF同样大小的缓冲区 */ +#endif + CHRV3DiskStatus = DISK_UNKNOWN; /* 未知状态 */ + CHRV3vSectorSizeB = 9; /* 默认的物理磁盘的扇区是512B */ + CHRV3vSectorSize = 512; /* 默认的物理磁盘的扇区是512B,该值是磁盘的扇区大小 */ + CHRV3vStartLba = 0; /* 默认为自动分析FDD和HDD */ + CHRV3vPacketSize = 512; /* USB存储类设备的最大包长度:64@FS,512@HS/SS,由应用程序初始化,枚举U盘后如果是高速或者超速那么及时更新为512 */ + + pTX_DMA_A_REG = (uint32_t *)&(USBHSH->HOST_TX_DMA); /* 指向发送DMA地址寄存器,由应用程序初始化 */ + pRX_DMA_A_REG = (uint32_t *)&(USBHSH->HOST_RX_DMA); /* 指向接收DMA地址寄存器,由应用程序初始化 */ + pTX_LEN_REG = (uint16_t *)&(USBHSH->HOST_TX_LEN); /* 指向发送长度寄存器,由应用程序初始化 */ + pRX_LEN_REG = (uint16_t *)&(USBHSH->RX_LEN); /* 指向接收长度寄存器,由应用程序初始化 */ + + return( ERR_SUCCESS ); +} + +void mDelaymS( uint16_t n ) +{ + Delay_Ms(n); +} + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/Makefile new file mode 100644 index 000000000..d6d19a6b4 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/Makefile @@ -0,0 +1,8 @@ +SRC_FILES := ch32v30x_usbhs_host.c Udisk_Func_BasicOp.c UDisk_Func_CreatDir.c UDisk_Func_LongName.c UDisk_HW.c CH32V103UFI.c + +include $(KERNEL_ROOT)/compiler.mk + + + + + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_Func_CreatDir.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_Func_CreatDir.c new file mode 100644 index 000000000..d906b9e02 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_Func_CreatDir.c @@ -0,0 +1,195 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : UDisk_Func_CreatDir.c +* Author : WCH +* Version : V1.0.0 +* Date : 2022/11/22 +* Description : USB full-speed port host operation functions. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +/*******************************************************************************/ +/* Header File */ +#include "Udisk_Operation.h" + +/******************************************************************************* +* Function Name : CreateDirectory +* Description : 新建目录并打开,如果目录已经存在则直接打开,目录名在mCmdParam.Create.mPathName中,与文件名规则相同 +* Input : +* Output : None +* Return : ERR_SUCCESS = 打开目录成功或者创建目录成功, + ERR_FOUND_NAME = 已经存在同名文件, + ERR_MISS_DIR = 路径名无效或者上级目录不存在 +*******************************************************************************/ +uint8_t CreateDirectory( void ) +{ + uint8_t i, j; + uint32_t UpDirCluster; + uint8_t * DirXramBuf; + uint8_t *DirConstData; + j = 0xFF; + for ( i = 0; i != sizeof( mCmdParam.Create.mPathName ); i ++ ) //检查目录路径 + { + if ( mCmdParam.Create.mPathName[ i ] == 0 ) + { + break; + } + if ( mCmdParam.Create.mPathName[ i ] == PATH_SEPAR_CHAR1 || mCmdParam.Create.mPathName[ i ] == PATH_SEPAR_CHAR2 ) + { + j = i; //记录上级目录 + } + } + i = ERR_SUCCESS; + if ( j == 0 || (j == 2 && mCmdParam.Create.mPathName[1] == ':') ) + { + UpDirCluster = 0; //在根目录下创建子目录 + } + else + { + if ( j != 0xFF ) //对于绝对路径应该获取上级目录的起始簇号 + { + mCmdParam.Create.mPathName[ j ] = 0; + i = CHRV3FileOpen( ); //打开上级目录 + if ( i == ERR_SUCCESS ) + { + i = ERR_MISS_DIR; //是文件而非目录 + } + else if ( i == ERR_OPEN_DIR ) + { + i = ERR_SUCCESS; //成功打开上级目录 + } + mCmdParam.Create.mPathName[ j ] = PATH_SEPAR_CHAR1; //恢复目录分隔符 + } + UpDirCluster = CHRV3vStartCluster; //保存上级目录的起始簇号 + } + if ( i == ERR_SUCCESS ) //成功获取上级目录的起始簇号 + { + i = CHRV3FileOpen( ); //打开本级子目录 + if ( i == ERR_SUCCESS ) + { + i = ERR_FOUND_NAME; //是文件而非目录 + } + else if ( i == ERR_OPEN_DIR ) + { + i = ERR_SUCCESS; //目录已经存在 + } + else if ( i == ERR_MISS_FILE ) //目录不存在,可以新建 + { + i = CHRV3FileCreate( ); //以创建文件的方法创建目录 + if ( i == ERR_SUCCESS ) + { + if ( pDISK_FAT_BUF == pDISK_BASE_BUF ) + { + memset(pDISK_FAT_BUF,0,CHRV3vSectorSize); //如果FILE_DATA_BUF与DISK_BASE_BUF合用则必须清除磁盘缓冲区 + } + DirXramBuf = pDISK_FAT_BUF; //文件数据缓冲区 + DirConstData = ". \x10\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x21\x30\x0\x0\x0\x0\x0\x0.. \x10\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x21\x30\x0\x0\x0\x0\x0\x0"; + for ( i = 0x40; i != 0; i -- ) //目录的保留单元,分别指向自身和上级目录 + { + *DirXramBuf = *DirConstData; + DirXramBuf ++; + DirConstData ++; + } + *(pDISK_FAT_BUF+0x1A) = ( (uint8_t *)&CHRV3vStartCluster )[3];//自身的起始簇号 + *(pDISK_FAT_BUF+0x1B) = ( (uint8_t *)&CHRV3vStartCluster )[2]; + *(pDISK_FAT_BUF+0x14) = ( (uint8_t *)&CHRV3vStartCluster )[1]; + *(pDISK_FAT_BUF+0x15) = ( (uint8_t *)&CHRV3vStartCluster )[0]; + *(pDISK_FAT_BUF+0x20+0x1A) = ( (uint8_t *)&UpDirCluster )[3];//上级目录的起始簇号 + *(pDISK_FAT_BUF+0x20+0x1B) = ( (uint8_t *)&UpDirCluster )[2]; + *(pDISK_FAT_BUF+0x20+0x14) = ( (uint8_t *)&UpDirCluster )[1]; + *(pDISK_FAT_BUF+0x20+0x15) = ( (uint8_t *)&UpDirCluster )[0]; +// for ( count = 0x40; count != CHRV3vSectorSizeH*256; count ++ ) { /* 清空目录区剩余部分 */ +// *DirXramBuf = 0; +// DirXramBuf ++; +// } + mCmdParam.Write.mSectorCount = 1; + mCmdParam.Write.mDataBuffer = pDISK_FAT_BUF; //指向文件数据缓冲区的起始地址 + i = CHRV3FileWrite( ); //向文件写入数据 + if ( i == ERR_SUCCESS ) + { + DirXramBuf = pDISK_FAT_BUF; + for ( i = 0x40; i != 0; i -- ) //清空目录区 + { + *DirXramBuf = 0; + DirXramBuf ++; + } + for ( j = 1; j != CHRV3vSecPerClus; j ++ ) + { + if ( pDISK_FAT_BUF == pDISK_BASE_BUF ) + { + memset(pDISK_FAT_BUF,0,CHRV3vSectorSize); //如果FILE_DATA_BUF与DISK_BASE_BUF合用则必须清除磁盘缓冲区 + } + mCmdParam.Write.mSectorCount = 1; + mCmdParam.Write.mDataBuffer = pDISK_FAT_BUF; //指向文件数据缓冲区的起始地址 + i = CHRV3FileWrite( ); //清空目录的剩余扇区 + if ( i != ERR_SUCCESS ) + { + break; + } + } + if ( j == CHRV3vSecPerClus ) //成功清空目录 + { + mCmdParam.Modify.mFileSize = 0; //目录的长度总是0 + mCmdParam.Modify.mFileDate = 0xFFFF; + mCmdParam.Modify.mFileTime = 0xFFFF; + mCmdParam.Modify.mFileAttr = 0x10; //置目录属性 + i = CHRV3FileModify( ); //将文件信息修改为目录 + } + } + } + } + } + return( i ); +} + +/********************************************************************* + * @fn UDisk_USBH_CreatDirectory + * + * @brief Demo Function For UDisk Create Directory (EXAM9) + * + * @return none + */ +void UDisk_USBH_CreatDirectory( void ) +{ + uint8_t i; + uint8_t ret; + + ret = UDisk_USBH_DiskReady( ); + if( ( ret == DISK_READY )&&( UDisk_Opeation_Flag == 1 ) ) + { + UDisk_Opeation_Flag = 0; + printf("CHRV3DiskStatus:%02x\r\n",CHRV3DiskStatus); + printf( "Create Level 1 Directory /YEAR2004 \r\n" ); + strcpy( mCmdParam.Create.mPathName, "/YEAR2004" ); //目录名,该目录建在根目录下 + ret = CreateDirectory( ); //新建或者打开目录 + mStopIfError( ret ); + /* 目录新建或者打开成功,下面在这个子目录中新建一个演示文件 */ + printf( "Create New File /YEAR2004/DEMO2004.TXT \r\n" ); + strcpy( mCmdParam.Create.mPathName, "/YEAR2004/DEMO2004.TXT" );//文件名 + ret = CHRV3FileCreate( ); //新建文件并打开,如果文件已经存在则先删除后再新建 + mStopIfError( ret ); + printf( "Write some data to file DEMO2004.TXT \r\n" ); + i = sprintf( Com_Buffer, "演示文件\xd\xa" ); + mCmdParam.ByteWrite.mByteCount = i; //指定本次写入的字节数,单次读写的长度不能超过MAX_BYTE_IO + mCmdParam.ByteWrite.mByteBuffer = Com_Buffer; //指向缓冲区 + ret = CHRV3ByteWrite( ); //以字节为单位向文件写入数据,单次读写的长度不能超过MAX_BYTE_IO + mStopIfError( ret ); + printf( "Close file DEMO2004.TXT \r\n" ); + mCmdParam.Close.mUpdateLen = 1; //自动计算文件长度,以字节为单位写文件,建议让程序库关闭文件以便自动更新文件长度 + ret = CHRV3FileClose( ); + mStopIfError( ret ); + /* 下面新建二级子目录,方法与前面的一级子目录完全相同 */ + printf( "Create Level 2 Directory /YEAR2004/MONTH05 \r\n" ); + strcpy( mCmdParam.Create.mPathName, "/YEAR2004/MONTH05" ); //目录名,该目录建在YEAR2004子目录下,YEAR2004目录必须事先存在 + ret = CreateDirectory( ); //新建或者打开目录 + mStopIfError( ret ); + printf( "Close\r\n" ); + mCmdParam.Close.mUpdateLen = 0; //对于目录不需要自动更新文件长度 + ret = CHRV3FileClose( ); //关闭目录,目录不需要关闭,关闭只是为了防止下面误操作 + mStopIfError( ret ); + } +} + + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_Func_LongName.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_Func_LongName.c new file mode 100644 index 000000000..bd9eb1673 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_Func_LongName.c @@ -0,0 +1,596 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : Udisk_Func_longname.c +* Author : WCH +* Version : V1.0.0 +* Date : 2022/11/22 +* Description : USB full-speed port host operation functions. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +/*******************************************************************************/ +/* Header File */ +#include "Udisk_Operation.h" + +/*******************************************************************************/ +/* Variable Definition */ +uint8_t LongNameBuf[ LONG_NAME_BUF_LEN ]; +/* +长文件名示例(UNICODE编码的大小端 必须与UNICODE_ENDIAN定义相同) +以下是LongName里编码内容: +建立长文件名,输入两个参数: 1.采用(unicode 大端),字符串末尾用两个0表示结束;2.ANSI编码短文件名.TXT +*/ +uint8_t LongName[ ] = +#if UNICODE_ENDIAN == 1 +{ + 0x5E, 0xFA, 0x7A, 0xCB, 0x95, 0x7F, 0x65, 0x87, 0x4E, 0xF6, 0x54, 0x0D, 0xFF, 0x0C, 0x8F, 0x93, + 0x51, 0x65, 0x4E, 0x24, 0x4E, 0x2A, 0x53, 0xC2, 0x65, 0x70, 0xFF, 0x1A, 0x00, 0x20, 0x00, 0x31, + 0x00, 0x2E, 0x91, 0xC7, 0x75, 0x28, 0x00, 0x28, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x63, + 0x00, 0x6F, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x59, 0x27, 0x7A, 0xEF, 0x00, 0x29, 0xFF, 0x0C, + 0x5B, 0x57, 0x7B, 0x26, 0x4E, 0x32, 0x67, 0x2B, 0x5C, 0x3E, 0x75, 0x28, 0x4E, 0x24, 0x4E, 0x2A, + 0x00, 0x30, 0x88, 0x68, 0x79, 0x3A, 0x7E, 0xD3, 0x67, 0x5F, 0x00, 0x3B, 0x00, 0x32, 0x00, 0x2E, + 0x00, 0x41, 0x00, 0x4E, 0x00, 0x53, 0x00, 0x49, 0x7F, 0x16, 0x78, 0x01, 0x77, 0xED, 0x65, 0x87, + 0x4E, 0xF6, 0x54, 0x0D, 0x00, 0x2E, 0x00, 0x54, 0x00, 0x58, 0x00, 0x54 +}; +#else +{ + 0xFA, 0x5E, 0xCB, 0x7A, 0x7F, 0x95, 0x87, 0x65, 0xF6, 0x4E, 0x0D, 0x54, 0x0C, 0xFF, 0x93, 0x8F, + 0x65, 0x51, 0x24, 0x4E, 0x2A, 0x4E, 0xC2, 0x53, 0x70, 0x65, 0x1A, 0xFF, 0x20, 0x00, 0x31, 0x00, + 0x2E, 0x00, 0xC7, 0x91, 0x28, 0x75, 0x28, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x63, 0x00, + 0x6F, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x00, 0x27, 0x59, 0xEF, 0x7A, 0x29, 0x00, 0x0C, 0xFF, + 0x57, 0x5B, 0x26, 0x7B, 0x32, 0x4E, 0x2B, 0x67, 0x3E, 0x5C, 0x28, 0x75, 0x24, 0x4E, 0x2A, 0x4E, + 0x30, 0x00, 0x68, 0x88, 0x3A, 0x79, 0xD3, 0x7E, 0x5F, 0x67, 0x3B, 0x00, 0x32, 0x00, 0x2E, 0x00, + 0x41, 0x00, 0x4E, 0x00, 0x53, 0x00, 0x49, 0x00, 0x16, 0x7F, 0x01, 0x78, 0xED, 0x77, 0x87, 0x65, + 0xF6, 0x4E, 0x0D, 0x54, 0x2E, 0x00, 0x54, 0x00, 0x58, 0x00, 0x54, 0x00 +}; +#endif + +/********************************************************************* + * @fn UDisk_USBH_Longname + * + * @brief Demo Function For UDisk long-name Operation(EXAM 13) + * + * @return none + */ +void UDisk_USBH_Longname( void ) +{ + uint8_t ret, i, len; + uint16_t j; + + ret = UDisk_USBH_DiskReady( ); + if( ( ret == DISK_READY )&&( UDisk_Opeation_Flag == 1 ) ) + { + UDisk_Opeation_Flag = 0; + /*==================== 以下演示创建及读取长文件名 ============================*/ + // 复制长文件名(UNICODE 大端)到LongNameBuf里 + len = LongName_Len; + memcpy( LongNameBuf, LongName, len ); + // 末尾用两个0表示结束 + LongNameBuf[len] = 0x00; + LongNameBuf[len + 1] = 0x00; + // 该长文件名的ANSI编码短文件名(8+3格式) + strcpy( mCmdParam.Create.mPathName, "\\长文件名.TXT" ); + i = CHRV3CreateLongName( ); + if( i == ERR_SUCCESS ) + { + DUG_PRINTF( "Created Long Name OK!\r\n" ); + } + else + { + /* Error code defined in "udisk_operaion.h" */ + DUG_PRINTF( "Error Code: %02X\r\n", (uint16_t)i ); + } + + DUG_PRINTF( "Get long Name#\r\n" ); + strcpy( mCmdParam.Open.mPathName, "\\长文件名.TXT" ); + // 以上需要输入文件名的完整路径 + i = CHRV3GetLongName( ); + if( i == ERR_SUCCESS ) + { + // 长文件名收集完成,以UNICODE编码方式(按UNICODE_ENDIAN定义) + // 存放在LongNameBuf缓冲里,长文件名最后用两个0结束. + // 以下显示缓冲区里所有数据 + DUG_PRINTF( "LongNameBuf: " ); + for( j=0; j!=LONG_NAME_BUF_LEN; j++ ) + { + DUG_PRINTF( "%02X ", (uint16_t)LongNameBuf[j] ); + } + DUG_PRINTF( "\r\n" ); + } + else + { + /* Error code defined in "udisk_operaion.h" */ + DUG_PRINTF( "Error Code: %02X\r\n", (uint16_t)i ); + } + } +} + +/********************************************************************* + * @fn CheckNameSum + * + * @brief 检查长文件名的短文件名检验和 + * + * @return 计算后的校验和 + */ +uint8_t CheckNameSum( uint8_t *p ) +{ +uint8_t FcbNameLen; +uint8_t Sum; + + Sum = 0; + for (FcbNameLen=0; FcbNameLen!=11; FcbNameLen++) + Sum = ((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *p++; + return Sum; +} + +/********************************************************************* + * @fn AnalyzeLongName + * + * @brief 整理长文件名 返回有几个的26长度 + * + * @return 返回有多少个26的长度 + */ +uint8_t AnalyzeLongName( void ) +{ +uint8_t i, j; +uint16_t index; + + i = FALSE; + for( index=0; index!=LONG_NAME_BUF_LEN; index = index + 2 ) + { + if( ( LongNameBuf[index] == 0 ) && ( LongNameBuf[index+1] == 0 ) ) + { + i = TRUE; + break; + } + } + if( ( i == FALSE ) || ( index == 0) ) + return 0; // 返回0表示错误的长文件名 + + i = index % 26; + if( i != 0 ) + { + index += 2; + if( index % 26 != 0 ) // 加0刚好结束 + { + for( j=i+2; j!=26; j++ )// 把剩余数据填为0XFF + LongNameBuf[index++] = 0xff; + } + } + return (index / 26); +} + +/********************************************************************* + * @fn CHRV3CreateLongName + * + * @brief 创建长文件名,需要输入短文件名的完整路径 + * + * @return 操作状态 + */ +uint8_t CHRV3CreateLongName( void ) +{ +// 分析 保留文件路径 创建一个空文件 得到FDT偏移和其所在扇区 删除文件 +// 向后偏移扇区 可能失败 如FAT12/16处在根目录处 填充完毕后再次创建文件 +uint8_t i; +uint8_t len; // 存放路径的长度 +uint16_t index; // 长文件偏移索引 +uint16_t indexBak; // 长文件偏移索引备份 +uint32_t Secoffset; // 扇区偏移 + +uint8_t Fbit; // 第一次进入写扇区 +uint8_t Mult; // 长文件名长度26的倍数 +uint8_t MultBak; // 长文件名长度26的倍数备份 + +uint16_t Backoffset; // 保存文件偏移备份 +uint16_t BackoffsetBak; // 保存偏移备份的备份 +uint32_t BackFdtSector; // 保寸偏移上一个扇区 +uint8_t sum; // 保存长文件名的校验和 + +uint8_t BackPathBuf[MAX_PATH_LEN]; // 保存文件路径 + + Mult = AnalyzeLongName( ); // 保存长文件名是26的倍数 + if( Mult == 0 ) + return ERR_LONG_NAME; + MultBak = Mult; + + i = CHRV3FileOpen(); // 短文件名存在则返回错误 + if( i == ERR_SUCCESS ) + return ERR_NAME_EXIST; + + i = CHRV3FileCreate( ); + if( i == ERR_SUCCESS ) + { + Backoffset = CHRV3vFdtOffset; + BackoffsetBak = Backoffset; + BackFdtSector = CHRV3vFdtLba; + sum = CheckNameSum( &DISK_BASE_BUF[Backoffset ] ); + for( i=0; i!=MAX_PATH_LEN; i++ ) // 对文件路径进行备份 + BackPathBuf[i] = mCmdParam.Open.mPathName[i]; + CHRV3FileErase( ); // 删除此文件 + + Secoffset = 0; // 从0开始偏移 + index = Mult*26; // 得到长文件名的长度 + indexBak = index; + Fbit = FALSE; // 默认没有进入 + // 打开上级 进行数据填充数据 + P_RETRY: + for(len=0; len!=MAX_PATH_LEN; len++) + { + if(mCmdParam.Open.mPathName[len] == 0) + break; // 得到字符串长度 + } + + for(i=len-1; i!=0xff; i--) // 得到上级目录位置 + { + if((mCmdParam.Open.mPathName[i] == '\\') || (mCmdParam.Open.mPathName[i] == '/')) + break; + } + mCmdParam.Open.mPathName[i] = 0x00; + + if( i==0 ) // 打开一级目录注意:处在根目录开始的特殊情况 + { + mCmdParam.Open.mPathName[0] = '/'; + mCmdParam.Open.mPathName[1] = 0; + } + + i = CHRV3FileOpen(); // 打开上级目录 + if( i == ERR_OPEN_DIR ) + { + while( 1 ) // 循环填写 直到完成 + { + mCmdParam.Locate.mSectorOffset = Secoffset; + i = CHRV3FileLocate( ); + if( i == ERR_SUCCESS ) + { + if( Fbit ) // 第二次进入次写扇区 + { + if( mCmdParam.Locate.mSectorOffset != 0x0FFFFFFFF ) + { + BackFdtSector = mCmdParam.Locate.mSectorOffset; + Backoffset = 0; + } + else + { + for( i=0; i!=MAX_PATH_LEN; i++ )// 还原文件路径 + mCmdParam.Open.mPathName[i] = BackPathBuf[i]; + i = CHRV3FileCreate( ); // 进行空间扩展 + if( i != ERR_SUCCESS ) + return i; + CHRV3FileErase( ); + goto P_RETRY; // 重新打开上级目录 + } + } + + if( BackFdtSector == mCmdParam.Locate.mSectorOffset ) + { + mCmdParam.Read.mSectorCount = 1; // 读一个扇区到磁盘缓冲区 + mCmdParam.Read.mDataBuffer = &DISK_BASE_BUF[0]; + i = CHRV3FileRead( ); + CHRV3DirtyBuffer( ); // 清除磁盘缓冲区 + if( i!= ERR_SUCCESS ) + return i; + + i = ( CHRV3vSectorSize - Backoffset ) / 32; + if( Mult > i ) + Mult = Mult - i; // 剩余的倍数 + else + { + i = Mult; + Mult = 0; + } + + for( len=i; len!=0; len-- ) + { + indexBak -= 26; + index = indexBak; + for( i=0; i!=5; i++) // 长文件名的1-5个字符 + { // 在磁盘上UNICODE用小端方式存放 + #if UNICODE_ENDIAN == 1 + DISK_BASE_BUF[Backoffset + i*2 + 2 ] = + LongNameBuf[index++]; + DISK_BASE_BUF[Backoffset + i*2 + 1 ] = + LongNameBuf[index++]; + #else + DISK_BASE_BUF[Backoffset + i*2 + 1 ] = + LongNameBuf[index++]; + DISK_BASE_BUF[Backoffset + i*2 + 2 ] = + LongNameBuf[index++]; + #endif + } + + for( i =0; i!=6; i++) // 长文件名的6-11个字符 + { + #if UNICODE_ENDIAN == 1 + DISK_BASE_BUF[Backoffset + 14 + i*2 + 1 ] = + LongNameBuf[index++]; + DISK_BASE_BUF[Backoffset + 14 + i*2 ] = + LongNameBuf[index++]; + #else + DISK_BASE_BUF[Backoffset + 14 + i*2 ] = + LongNameBuf[index++]; + DISK_BASE_BUF[Backoffset + 14 + i*2 + 1 ] = + LongNameBuf[index++]; + #endif + } + + for( i=0; i!=2; i++) // 长文件名的12-13个字符 + { + #if UNICODE_ENDIAN == 1 + DISK_BASE_BUF[Backoffset + 28 + i*2 + 1 ] = + LongNameBuf[index++]; + DISK_BASE_BUF[Backoffset + 28 + i*2 ] = + LongNameBuf[index++]; + #else + DISK_BASE_BUF[Backoffset + 28 + i*2 ] = + LongNameBuf[index++]; + DISK_BASE_BUF[Backoffset + 28 + i*2 + 1 ] = + LongNameBuf[index++]; + #endif + } + + DISK_BASE_BUF[Backoffset + 0x0b] = 0x0f; + DISK_BASE_BUF[Backoffset + 0x0c] = 0x00; + DISK_BASE_BUF[Backoffset + 0x0d] = sum; + DISK_BASE_BUF[Backoffset + 0x1a] = 0x00; + DISK_BASE_BUF[Backoffset + 0x1b] = 0x00; + DISK_BASE_BUF[Backoffset] = MultBak--; + Backoffset += 32; + } + + if( !Fbit ) + { + Fbit = TRUE; + DISK_BASE_BUF[ BackoffsetBak ] |= 0x40; + } + CHRV3vLbaCurrent = BackFdtSector; + i = CHRV3WriteSector( 1, DISK_BASE_BUF ); + if( i!= ERR_SUCCESS ) + return i; + + if( Mult==0 ) + { // 还原文件路径 + CHRV3FileClose( ); + for( i=0; i!=MAX_PATH_LEN; i++ ) + mCmdParam.Open.mPathName[i] = BackPathBuf[i]; + i = CHRV3FileCreate( ); + return i; + } + } + } + else + return i; + Secoffset++; + } + } + } + return i; +} + +/********************************************************************* + * @fn GetUpSectorData + * + * @brief 由当前扇区得到上一个扇区的数据,放在磁盘缓冲区 + * + * @return 操作状态 + */ +uint8_t GetUpSectorData( uint32_t *NowSector ) +{ +uint8_t i; +uint8_t len; // 存放路径的长度 +uint32_t index; // 目录扇区偏移扇区数 + + index = 0; + for(len=0; len!=MAX_PATH_LEN; len++) + { + if(mCmdParam.Open.mPathName[len] == 0) // 得到字符串长度 + break; + } + + for(i=len-1; i!=0xff; i--) // 得到上级目录位置 + { + if((mCmdParam.Open.mPathName[i] == '\\') || (mCmdParam.Open.mPathName[i] == '/')) + break; + } + mCmdParam.Open.mPathName[i] = 0x00; + + if( i==0 ) // 打开一级目录注意:处在根目录开始的特殊情况 + { + mCmdParam.Open.mPathName[0] = '/'; + mCmdParam.Open.mPathName[1] = 0; + i = CHRV3FileOpen(); + if ( i == ERR_OPEN_DIR ) + goto P_NEXT0; + } + else + { + i = CHRV3FileOpen(); + if ( i == ERR_OPEN_DIR ) + { + while( 1 ) + { + P_NEXT0: + mCmdParam.Locate.mSectorOffset = index; + i = CHRV3FileLocate( ); + if( i == ERR_SUCCESS ) + { + if( *NowSector == mCmdParam.Locate.mSectorOffset ) + { + if( index==0 ) // 处于根目录扇区的开始 + return ERR_NO_NAME; + mCmdParam.Locate.mSectorOffset = --index; + i = CHRV3FileLocate( ); // 读上一个扇区的数据 + if( i == ERR_SUCCESS ) + { // 以下保存当前所在扇区数 + *NowSector = mCmdParam.Locate.mSectorOffset; + mCmdParam.Read.mSectorCount = 1; // 读一个扇区到磁盘缓冲区 + mCmdParam.Read.mDataBuffer = &DISK_BASE_BUF[0]; + i = CHRV3FileRead( ); + CHRV3DirtyBuffer( ); // 清除磁盘缓冲区 + return i; + } + else + return i; + } + } + else + return i; + index++; + } + } + } + return i; +} + +/********************************************************************* + * @fn CHRV3GetLongName + * + * @brief 由完整短文件名路径(可以是文件或文件夹)得到相应的长文件名 + * + * @return 操作状态 + */ +uint8_t CHRV3GetLongName( void ) +{ +// 需要变量扇区大小 +// 第一步:打开文件是否找到文件,分析文件是否存在,并得到FDT在此扇区的偏移和所在扇区 +// 第二步:分析上面的信息看是否有长文件名存在,是否处于目录的第一个扇区的开始 +// 第三步:实现向后偏移一个扇区?读取长文件名(扇区512字节的U盘) +uint8_t i; +uint16_t index; // 在长文件名缓冲区内的索引 +uint32_t BackFdtSector; // 保寸偏移上一个扇区 +uint8_t sum; // 保存长文件名的校验和 +//uint16_t Backoffset; // 保存文件偏移备份 +uint16_t offset; // 扇区内文件偏移32倍数 +uint8_t FirstBit; // 长文件名跨越两个扇区标志位 +uint8_t BackPathBuf[MAX_PATH_LEN]; // 保存文件路径 + + i = CHRV3FileOpen( ); + if( ( i == ERR_SUCCESS ) || ( i == ERR_OPEN_DIR ) ) + { + for( i=0; i!=MAX_PATH_LEN; i++ ) + BackPathBuf[i] = mCmdParam.Open.mPathName[i]; + // 以上完成对路径的备份 + + sum = CheckNameSum( &DISK_BASE_BUF[CHRV3vFdtOffset] ); + index = 0; + FirstBit = FALSE; +// Backoffset = CHRV3vFdtOffset; + BackFdtSector = CHRV3vFdtLba; + if( CHRV3vFdtOffset == 0 ) + { + // 先判断是否处于一个扇区开始 是否处于根目录开始 ,否则向后偏移 + if( FirstBit == FALSE ) + FirstBit = TRUE; + i = GetUpSectorData( &BackFdtSector ); + if( i == ERR_SUCCESS ) + { + CHRV3vFdtOffset = CHRV3vSectorSize; + goto P_NEXT1; + } + } + else + { + // 读取偏移后的数据,直到结束。如果不够则向后偏移 + P_NEXT1: + offset = CHRV3vFdtOffset; + while( 1 ) + { + if( offset != 0 ) + { + offset = offset - 32; + if( ( DISK_BASE_BUF[offset + 11] == ATTR_LONG_NAME ) + && ( DISK_BASE_BUF[offset + 13] == sum ) ) + { + if( (index + 26) > LONG_NAME_BUF_LEN ) + return ERR_BUF_OVER; + + for( i=0; i!=5; i++) // 长文件名的1-5个字符 + { // 在磁盘上UNICODE用小端方式存放 + #if UNICODE_ENDIAN == 1 + LongNameBuf[index++] = + DISK_BASE_BUF[offset + i*2 + 2]; + LongNameBuf[index++] = + DISK_BASE_BUF[offset + i*2 + 1]; + #else + LongNameBuf[index++] = + DISK_BASE_BUF[offset + i*2 + 1]; + LongNameBuf[index++] = + DISK_BASE_BUF[offset + i*2 + 2]; + #endif + } + + for( i =0; i!=6; i++) // 长文件名的6-11个字符 + { + #if UNICODE_ENDIAN == 1 + LongNameBuf[index++] = + DISK_BASE_BUF[offset + 14 + i*2 + 1]; + LongNameBuf[index++] = + DISK_BASE_BUF[offset + + 14 + i*2 ]; + #else + LongNameBuf[index++] = + DISK_BASE_BUF[offset + + 14 + i*2 ]; + LongNameBuf[index++] = + DISK_BASE_BUF[offset + 14 + i*2 + 1]; + #endif + + } + + for( i=0; i!=2; i++) // 长文件名的12-13个字符 + { + #if UNICODE_ENDIAN == 1 + LongNameBuf[index++] = + DISK_BASE_BUF[offset + 28 + i*2 + 1]; + LongNameBuf[index++] = + DISK_BASE_BUF[offset + 28 + i*2 ]; + #else + LongNameBuf[index++] = + DISK_BASE_BUF[offset + 28 + i*2 ]; + LongNameBuf[index++] = + DISK_BASE_BUF[offset + 28 + i*2 + 1]; + #endif + } + + if( DISK_BASE_BUF[offset] & 0X40 ) + { + if( ! (((LongNameBuf[index -1] ==0x00) + && (LongNameBuf[index -2] ==0x00)) + || ((LongNameBuf[index -1] ==0xFF) + && (LongNameBuf[index -2 ] ==0xFF)))) + { // 处理刚好为26字节长倍数的文件名 + if(index + 52 >LONG_NAME_BUF_LEN ) + return ERR_BUF_OVER; + LongNameBuf[ index ] = 0x00; + LongNameBuf[ index + 1] = 0x00; + } + return ERR_SUCCESS; // 成功完成长文件名收集完成 + } + } + else + return ERR_NO_NAME; // 错误的长文件名,程序返回 + } + else + { + if( FirstBit == FALSE ) + FirstBit = TRUE; + else // 否则第二次进入 + { + for( i=0; i!=MAX_PATH_LEN; i++ )// 还原路径 + mCmdParam.Open.mPathName[i] = BackPathBuf[i]; + } + i = GetUpSectorData( &BackFdtSector ); + if( i == ERR_SUCCESS ) + { + CHRV3vFdtOffset = CHRV3vSectorSize; + goto P_NEXT1; + } + else + return i; + // 向后偏移扇区 + } + } + } + } + return i; // 返回错误 +} + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_HW.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_HW.c new file mode 100644 index 000000000..84db4cc22 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/UDisk_HW.c @@ -0,0 +1,572 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : UDisk_HW.c +* Author : WCH +* Version : V1.0.0 +* Date : 2022/09/01 +* Description : USB full-speed port host operation functions. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +/*******************************************************************************/ +/* Header File */ +#include "Udisk_Operation.h" + +/*******************************************************************************/ +/* Variable Definition */ +__attribute__((aligned(4))) uint8_t Com_Buffer[ DEF_COM_BUF_LEN ]; // even address , used for host enumcation and udisk operation +__attribute__((aligned(4))) uint8_t DevDesc_Buf[ 18 ]; // Device Descriptor Buffer +struct _ROOT_HUB_DEVICE RootHubDev[ DEF_TOTAL_ROOT_HUB ]; +struct __HOST_CTL HostCtl[ DEF_TOTAL_ROOT_HUB * DEF_ONE_USB_SUP_DEV_TOTAL ]; +volatile uint8_t UDisk_Opeation_Flag = 0; + +/* For Udisk Lib */ +uint8_t *pHOST_RX_RAM_Addr; +uint8_t *pHOST_TX_RAM_Addr; + +/********************************************************************* + * @fn mStopIfError + * + * @brief Checking the operation status, displaying the error code and stopping if there is an error + * input : iError - Error code input + * + * @return none + */ +// void mStopIfError( uint8_t iError ) +// { +// if ( iError == ERR_SUCCESS ) +// { +// /* operation success, return */ +// return; +// } +// /* Display the errors */ +// DUG_PRINTF( "Error:%02x\r\n", iError ); +// /* After encountering an error, you should analyze the error code and CH103DiskReday status, for example, +// * call CH103DiskReday to check whether the current USB disk is connected or not, +// * if the disk is disconnected then wait for the disk to be plugged in again and operate again, +// * Suggested steps to follow after an error: +// * 1,call CH103DiskReday once, if successful, then continue the operation, such as Open, Read/Write, etc. +// * 2,If CH103DiskReday is not successful, then the operation will be forced to start from the beginning. +// */ +// while(1) +// { } +// } + +/********************************************************************* + * @fn Udisk_USBH_Initialization + * + * @brief USB Host Udisk process Initialization, include usb-host initialization + * usb libs initialization, udisk-related values Initialization + and the others + * + * @para none + * + * @return none + */ +void Udisk_USBH_Initialization( void ) +{ + /* USB Host Initialization */ + printf( "USB Host & UDisk Lib Initialization. \r\n" ); + /* Initialize USBHS host */ + /* Note: Only CH32F205/CH32F207 support USB high-speed port. */ +#if DEF_USB_PORT_HS_EN + DUG_PRINTF( "USBHS Host Init\r\n" ); + USBHS_RCC_Init( ); + USBHS_Host_Init( ENABLE ); + /* For Udisk Lib */ + pHOST_TX_RAM_Addr = USBHS_TX_Buf; + pHOST_RX_RAM_Addr = USBHS_RX_Buf; + /* Clear Struct */ + memset( &RootHubDev[ DEF_USB_PORT_HS ].bStatus, 0, sizeof( struct _ROOT_HUB_DEVICE ) ); + memset( &HostCtl[ DEF_USB_PORT_HS ].InterfaceNum, 0, sizeof( struct __HOST_CTL ) ); +#endif + + /* Initialize USBFS host */ +#if DEF_USB_PORT_FS_EN + DUG_PRINTF( "USBFS Host Init\r\n" ); + USBFS_RCC_Init( ); + USBFS_Host_Init( ENABLE ); + /* For Udisk Lib */ + pHOST_TX_RAM_Addr = USBFS_TX_Buf; + pHOST_RX_RAM_Addr = USBFS_RX_Buf; + /* Clear Struct */ + memset( &RootHubDev[ DEF_USB_PORT_FS ].bStatus, 0, sizeof( struct _ROOT_HUB_DEVICE ) ); + memset( &HostCtl[ DEF_USB_PORT_FS ].InterfaceNum, 0, sizeof( struct __HOST_CTL ) ); +#endif + + /* USB Libs Initialization */ + printf( "UDisk library Initialization. \r\n" ); + CHRV3LibInit( ); +} + +/********************************************************************* + * @fn USBH_CheckRootHubPortStatus + * + * @brief Check status of USB port. + * + * @para index: USB host port + * + * @return The current status of the port. + */ +uint8_t USBH_CheckRootHubPortStatus( uint8_t usb_port ) +{ + uint8_t s = ERR_USB_UNSUPPORT; + + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + s = USBFSH_CheckRootHubPortStatus( RootHubDev[ usb_port ].bStatus ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + s = USBHSH_CheckRootHubPortStatus( RootHubDev[ usb_port ].bStatus ); +#endif + } + + return s; +} + +/********************************************************************* + * @fn USBH_ResetRootHubPort + * + * @brief Reset USB port. + * + * @para index: USB host port + * mod: Reset host port operating mode. + * 0 -> reset and wait end + * 1 -> begin reset + * 2 -> end reset + * + * @return none + */ +void USBH_ResetRootHubPort( uint8_t usb_port, uint8_t mode ) +{ + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + USBFSH_ResetRootHubPort( mode ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + USBHSH_ResetRootHubPort( mode ); +#endif + } +} + +/********************************************************************* + * @fn USBH_EnableRootHubPort + * + * @brief Enable USB host port. + * + * @para index: USB host port + * + * @return none + */ +uint8_t USBH_EnableRootHubPort( uint8_t usb_port ) +{ + uint8_t s = ERR_USB_UNSUPPORT; + + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + s = USBFSH_EnableRootHubPort( &RootHubDev[ usb_port ].bSpeed ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + s = USBHSH_EnableRootHubPort( &RootHubDev[ usb_port ].bSpeed ); +#endif + } + + return s; +} + +/********************************************************************* + * @fn USBH_SetSelfSpeed + * + * @brief Set USB speed. + * + * @para index: USB host port + * + * @return none + */ +void USBH_SetSelfSpeed( uint8_t usb_port ) +{ + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + USBFSH_SetSelfSpeed( RootHubDev[ usb_port].bSpeed ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + USBHSH_SetSelfSpeed( RootHubDev[ usb_port ].bSpeed ); +#endif + } +} + +/********************************************************************* + * @fn USBH_GetDeviceDescr + * + * @brief Get the device descriptor of the USB device. + * + * @para index: USB host port + * + * @return none + */ +uint8_t USBH_GetDeviceDescr( uint8_t usb_port ) +{ + uint8_t s = ERR_USB_UNSUPPORT; + + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + s = USBFSH_GetDeviceDescr( &RootHubDev[ usb_port ].bEp0MaxPks, DevDesc_Buf ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + s = USBHSH_GetDeviceDescr( &RootHubDev[ usb_port ].bEp0MaxPks, DevDesc_Buf ); +#endif + } + + return s; +} + +/********************************************************************* + * @fn USBH_SetUsbAddress + * + * @brief Set USB device address. + * + * @para index: USB host port + * + * @return none + */ +uint8_t USBH_SetUsbAddress( uint8_t usb_port ) +{ + uint8_t s = ERR_USB_UNSUPPORT; + + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + RootHubDev[ usb_port ].bAddress = (uint8_t)( DEF_USB_PORT_FS + USB_DEVICE_ADDR ); + s = USBFSH_SetUsbAddress( RootHubDev[ usb_port ].bEp0MaxPks, RootHubDev[ usb_port ].bAddress ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + RootHubDev[ usb_port ].bAddress = (uint8_t)( DEF_USB_PORT_HS + USB_DEVICE_ADDR ); + s = USBHSH_SetUsbAddress( RootHubDev[ usb_port ].bEp0MaxPks, RootHubDev[ usb_port ].bAddress ); +#endif + } + + return s; +} + +/********************************************************************* + * @fn USBH_GetConfigDescr + * + * @brief Get the configuration descriptor of the USB device. + * + * @para index: USB host port + * + * @return none + */ +uint8_t USBH_GetConfigDescr( uint8_t usb_port, uint16_t *pcfg_len ) +{ + uint8_t s = ERR_USB_UNSUPPORT; + + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + s = USBFSH_GetConfigDescr( RootHubDev[ usb_port ].bEp0MaxPks, Com_Buffer, DEF_COM_BUF_LEN, pcfg_len ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + s = USBHSH_GetConfigDescr( RootHubDev[ usb_port ].bEp0MaxPks, Com_Buffer, DEF_COM_BUF_LEN, pcfg_len ); +#endif + } + return s; +} + +/********************************************************************* + * @fn USBFSH_SetUsbConfig + * + * @brief Set USB configuration. + * + * @para index: USB host port + * + * @return none + */ +uint8_t USBH_SetUsbConfig( uint8_t usb_port, uint8_t cfg_val ) +{ + uint8_t s = ERR_USB_UNSUPPORT; + + if( usb_port == DEF_USB_PORT_FS ) + { +#if DEF_USB_PORT_FS_EN + s = USBFSH_SetUsbConfig( RootHubDev[ usb_port ].bEp0MaxPks, cfg_val ); +#endif + } + else if( usb_port == DEF_USB_PORT_HS ) + { +#if DEF_USB_PORT_HS_EN + s = USBHSH_SetUsbConfig( RootHubDev[ usb_port ].bEp0MaxPks, cfg_val ); +#endif + } + + return s; +} + +/********************************************************************* + * @fn Udisk_USBH_EnumRootDevice + * + * @brief Generally enumerate a device connected to host port. + * + * @para index: USB host port + * + * @return Enumeration result + */ +uint8_t Udisk_USBH_EnumRootDevice( uint8_t usb_port ) +{ + uint8_t s; + uint8_t enum_cnt; + uint8_t cfg_val; + uint16_t i; + uint16_t len; + + DUG_PRINTF( "Enum:\r\n" ); + + enum_cnt = 0; +ENUM_START: + /* Delay and wait for the device to stabilize */ + Delay_Ms( 100 ); + enum_cnt++; + Delay_Ms( 8 << enum_cnt ); + + /* Reset the USB device and wait for the USB device to reconnect */ + USBH_ResetRootHubPort( usb_port, 0 ); + for( i = 0, s = 0; i < DEF_RE_ATTACH_TIMEOUT; i++ ) + { + if( USBH_EnableRootHubPort( usb_port ) == ERR_SUCCESS ) + { + i = 0; + s++; + if( s > 6 ) + { + break; + } + } + Delay_Ms( 1 ); + } + if( i ) + { + /* Determine whether the maximum number of retries has been reached, and retry if not reached */ + if( enum_cnt <= 5 ) + { + goto ENUM_START; + } + return ERR_USB_DISCON; + } + + /* Select USB speed */ + USBH_SetSelfSpeed( usb_port ); + + /* Get USB device device descriptor */ + DUG_PRINTF("Get DevDesc: "); + s = USBH_GetDeviceDescr( usb_port ); + if( s == ERR_SUCCESS ) + { + /* Print USB device device descriptor */ +#if DEF_DEBUG_PRINTF + for( i = 0; i < 18; i++ ) + { + DUG_PRINTF( "%02x ", DevDesc_Buf[ i ] ); + } + DUG_PRINTF("\n"); +#endif + } + else + { + /* Determine whether the maximum number of retries has been reached, and retry if not reached */ + DUG_PRINTF( "Err(%02x)\n", s ); + if( enum_cnt <= 5 ) + { + goto ENUM_START; + } + return DEF_DEV_DESCR_GETFAIL; + } + + /* Set the USB device address */ + DUG_PRINTF("Set DevAddr: "); + s = USBH_SetUsbAddress( usb_port ); + if( s == ERR_SUCCESS ) + { + DUG_PRINTF( "OK\n" ); + } + else + { + /* Determine whether the maximum number of retries has been reached, and retry if not reached */ + DUG_PRINTF( "Err(%02x)\n", s ); + if( enum_cnt <= 5 ) + { + goto ENUM_START; + } + return DEF_DEV_ADDR_SETFAIL; + } + Delay_Ms( 5 ); + + /* Get the USB device configuration descriptor */ + DUG_PRINTF("Get CfgDesc: "); + s = USBH_GetConfigDescr( usb_port, &len ); + if( s == ERR_SUCCESS ) + { + cfg_val = ( (PUSB_CFG_DESCR)Com_Buffer )->bConfigurationValue; + + /* Print USB device configuration descriptor */ +#if DEF_DEBUG_PRINTF + for( i = 0; i < len; i++ ) + { + DUG_PRINTF( "%02x ", Com_Buffer[ i ] ); + } + DUG_PRINTF("\n"); +#endif + } + else + { + /* Determine whether the maximum number of retries has been reached, and retry if not reached */ + DUG_PRINTF( "Err(%02x)\n", s ); + if( enum_cnt <= 5 ) + { + goto ENUM_START; + } + return DEF_CFG_DESCR_GETFAIL; + } + + /* Set USB device configuration value */ + DUG_PRINTF("Set Cfg: "); + s = USBH_SetUsbConfig( usb_port, cfg_val ); + if( s == ERR_SUCCESS ) + { + DUG_PRINTF( "OK\n" ); + } + else + { + /* Determine whether the maximum number of retries has been reached, and retry if not reached */ + DUG_PRINTF( "Err(%02x)\n", s ); + if( enum_cnt <= 5 ) + { + goto ENUM_START; + } + return ERR_USB_UNSUPPORT; + } + + return ERR_SUCCESS; +} + +/********************************************************************* + * @fn IAP_USBH_PreDeal + * + * @brief usb host preemption operations, + * including detecting device insertion and enumerating device information + * + * @return none + */ +uint8_t UDisk_USBH_PreDeal( void ) +{ + uint8_t usb_port; + uint8_t index; + uint8_t ret; +#if DEF_USB_PORT_FS_EN + usb_port = DEF_USB_PORT_FS; +#elif DEF_USB_PORT_HS_EN + usb_port = DEF_USB_PORT_HS; +#endif + ret = USBH_CheckRootHubPortStatus( usb_port ); + if( ret == ROOT_DEV_CONNECTED ) + { + DUG_PRINTF("USB Dev In.\n"); + USBH_CheckRootHubPortStatus( usb_port ); + RootHubDev[ usb_port ].bStatus = ROOT_DEV_CONNECTED; // Set connection status_ + RootHubDev[ usb_port ].DeviceIndex = usb_port * DEF_ONE_USB_SUP_DEV_TOTAL; + + /* Enumerate root device */ + ret = Udisk_USBH_EnumRootDevice( usb_port ); + if( ret == ERR_SUCCESS ) + { + DUG_PRINTF( "USB Port %02x Device Enumeration Succeed\r\n", usb_port ); + RootHubDev[ usb_port ].bStatus = ROOT_DEV_SUCCESS; + return ERR_SUCCESS; + } + else + { + DUG_PRINTF( "USB Port %02x Device Enumeration ERR %02x.\r\n", usb_port, ret ); + RootHubDev[ usb_port ].bStatus = ROOT_DEV_FAILED; + return ERR_USB_UNAVAILABLE; + } + } + else if( ret == ROOT_DEV_DISCONNECT ) + { + DUG_PRINTF("USB Port %02x Device Out.\r\n", usb_port ); + /* Clear parameters */ + index = RootHubDev[ usb_port ].DeviceIndex; + memset( &RootHubDev[ usb_port ].bStatus, 0, sizeof( struct _ROOT_HUB_DEVICE ) ); + memset( &HostCtl[ index ].InterfaceNum, 0, sizeof( struct __HOST_CTL ) ); + CHRV3DiskStatus = DISK_UNKNOWN; + return ERR_USB_DISCON; + } + return ERR_USB_UNKNOWN; +} + +/********************************************************************* + * @fn UDisk_USBH_DiskReady + * + * @brief Check if UDisk is Ready and update status in 'CHRV3DiskStatus' + * + * @return none + */ +uint8_t UDisk_USBH_DiskReady( void ) +{ + uint8_t ret, i; + + /* Detect USB Device & Enumeration processing */ + ret = UDisk_USBH_PreDeal( ); + if( ret == ERR_SUCCESS ) + { + /* Wait for uDisk Ready */ + CHRV3DiskStatus = DISK_USB_ADDR; + for ( i = 0; i != 10; i ++ ) + { + DUG_PRINTF( "Wait Disk Ready...\r\n" ); + ret = CHRV3DiskReady( ); + if ( ret == ERR_SUCCESS ) + { + /* Disk Ready */ + DUG_PRINTF( "Disk Ready Code:%02x.\r\n", ret ); + DUG_PRINTF( "CH103DiskStatus:%02x\n", CHRV3DiskStatus); + UDisk_Opeation_Flag = 1; + return DISK_READY; + } + else + { + DUG_PRINTF("Not Ready Code :%02x.\r\n", ret); + DUG_PRINTF("CH103DiskStatus:%02x.\n", CHRV3DiskStatus); + } + Delay_Ms( 50 ); + } + } + return CHRV3DiskStatus; +} + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/Udisk_Func_BasicOp.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/Udisk_Func_BasicOp.c new file mode 100644 index 000000000..6dd079165 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/usb/usb_drv/src/Udisk_Func_BasicOp.c @@ -0,0 +1,345 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : Udisk_Func_BasicOp.c +* Author : WCH +* Version : V1.0.0 +* Date : 2022/11/22 +* Description : USB full-speed port host operation functions. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +/*******************************************************************************/ +/* Header File */ +#include "Udisk_Operation.h" +uint8_t *pCodeStr; +/*******************************************************************************/ +/* Variable Definition */ +__attribute__((aligned(4))) uint8_t MY_DATA_BUF[ DISK_BASE_BUF_LEN ]; /* MY_DATA_BUF指向外部RAM的磁盘数据缓冲区,缓冲区长度为至少一个扇区的长度,用于用户数据缓存 */ +uint8_t *pCodeStr; + +/********************************************************************* + * @fn UDisk_USBH_ByteOperation + * + * @brief Demo Function For UDisk File Byte-operation + * including Create\Modify\Read\Erase (EXAM1) + * + * @return none + */ +void UDisk_USBH_ByteOperation( void ) +{ + uint8_t ret; + uint8_t i,t; + uint16_t TotalCount = 0; + + UDisk_USBH_DiskReady( ); + if( (CHRV3DiskStatus >= DISK_MOUNTED)&&( UDisk_Opeation_Flag == 1 ) ) + { + UDisk_Opeation_Flag = 0; + printf("CHRV3DiskStatus:%02x\r\n",CHRV3DiskStatus); + /* 读文件 */ + strcpy( (char *)mCmdParam.Open.mPathName, "/C51/NEWFILE.C" ); //设置将要操作的文件路径和文件名/C51/NEWFILE.C + ret = CHRV3FileOpen( ); //打开文件 + if ( ret == ERR_MISS_DIR || ret == ERR_MISS_FILE ) //没有找到文件 + { + //创建文件演示 + printf( "Find No File And Create\r\n" ); + strcpy( (char *)mCmdParam.Create.mPathName, "/C51/NEWFILE.C" ); //新文件名,在根目录下,中文文件名 + ret = CHRV3FileCreate( ); //新建文件并打开,如果文件已经存在则先删除后再新建 + mStopIfError( ret ); + printf( "ByteWrite\r\n" ); + //实际应该判断写数据长度和定义缓冲区长度是否相符,如果大于缓冲区长度则需要多次写入 + i = sprintf( (char *)Com_Buffer,"Note: \xd\xa这个程序是以字节为单位进行U盘文件读写,简单演示功能。\xd\xa"); + for(t=0; t<10; t++) + { + mCmdParam.ByteWrite.mByteCount = i; //指定本次写入的字节数 + mCmdParam.ByteWrite.mByteBuffer = Com_Buffer; //指向缓冲区 + ret = CHRV3ByteWrite( ); //以字节为单位向文件写入数据 + mStopIfError( ret ); + printf("成功写入 %02X次\r\n",(uint16_t)t); + } + //演示修改文件属性 + printf( "Modify\r\n" ); + mCmdParam.Modify.mFileAttr = 0xff; //输入参数: 新的文件属性,为0FFH则不修改 + mCmdParam.Modify.mFileTime = 0xffff; //输入参数: 新的文件时间,为0FFFFH则不修改,使用新建文件产生的默认时间 + mCmdParam.Modify.mFileDate = MAKE_FILE_DATE( 2015, 5, 18 ); //输入参数: 新的文件日期: 2015.05.18 + mCmdParam.Modify.mFileSize = 0xffffffff; // 输入参数: 新的文件长度,以字节为单位写文件应该由程序库关闭文件时自动更新长度,所以此处不修改 + i = CHRV3FileModify( ); //修改当前文件的信息,修改日期 + mStopIfError( i ); + printf( "Close\r\n" ); + mCmdParam.Close.mUpdateLen = 1; //自动计算文件长度,以字节为单位写文件,建议让程序库关闭文件以便自动更新文件长度 + i = CHRV3FileClose( ); + mStopIfError( i ); + + /* 删除某文件 */ +// printf( "Erase\n" ); +// strcpy( (char *)mCmdParam.Create.mPathName, "/OLD" ); //将被删除的文件名,在根目录下 +// i = CHRV3FileErase( ); //删除文件并关闭 +// if ( i != ERR_SUCCESS ) printf( "Error: %02X\n", (uint16_t)i ); //显示错误 + } + else + { + /* 一、写入文件 */ + printf( "ByteWrite\r\n" ); //如果希望将新数据添加到原文件的尾部,可以移动文件指针 + mCmdParam.ByteLocate.mByteOffset = 0xffffffff; //移到文件的尾部 + CHRV3ByteLocate( ); //实际应该判断写数据长度和定义缓冲区长度是否相符,如果大于缓冲区长度则需要多次写入 + i = sprintf( (char *)Com_Buffer,"Note: \xd\xa这个程序是以字节为单位进行U盘文件读写,简单演示功能。\xd\xa"); //演示文字 + for(t=0; t<10; t++) + { + mCmdParam.ByteWrite.mByteCount = i; //指定本次写入的字节数 + mCmdParam.ByteWrite.mByteBuffer = Com_Buffer; // 指向缓冲区 + ret = CHRV3ByteWrite( ); // 以字节为单位向文件写入数据 + mStopIfError( ret ); + printf("成功写入 %02X次\r\n",(uint16_t)t); + } + /* 二、读取文件前N字节 */ + TotalCount = 60; //设置准备读取总长度100字节 + strcpy( (char *)mCmdParam.Open.mPathName, "/C51/NEWFILE.C" ); //设置将要操作的文件路径和文件名/C51/NEWFILE.C + CHRV3FileOpen( ); //打开文件 + printf( "读出的前%d个字符是:\r\n",TotalCount ); + while ( TotalCount ) + { + //如果文件比较大,一次读不完,可以再调用CH103ByteRead继续读取,文件指针自动向后移动 + if ( TotalCount > (MAX_PATH_LEN-1) ) + { + t = MAX_PATH_LEN-1; // 剩余数据较多,限制单次读写的长度不能超过 sizeof( mCmdParam.Other.mBuffer ) + } + else + { + t = TotalCount; //最后剩余的字节数 + } + mCmdParam.ByteRead.mByteCount = t; //请求读出几十字节数据 + mCmdParam.ByteRead.mByteBuffer= &Com_Buffer[0]; + ret = CHRV3ByteRead( ); //以字节为单位读取数据块,单次读写的长度不能超过MAX_BYTE_IO,第二次调用时接着刚才的向后读 + TotalCount -= mCmdParam.ByteRead.mByteCount; //计数,减去当前实际已经读出的字符数 + for ( i=0; i!=mCmdParam.ByteRead.mByteCount; i++ ) + { + printf( "%c", mCmdParam.ByteRead.mByteBuffer[i] ); //显示读出的字符 + } + printf( "\r\n" ); + + if ( mCmdParam.ByteRead.mByteCount < t ) //实际读出的字符数少于要求读出的字符数,说明已经到文件的结尾 + { + printf( "\r\n" ); + printf( "文件已经结束\r\n" ); + break; + } + } + i = CHRV3FileClose( ); //关闭文件 + mStopIfError( i ); + } + } +} + +/********************************************************************* + * @fn UDisk_USBH_SectorOperation + * + * @brief Demo Function For UDisk File Sector-operation + * including Create\Modify\Read\Erase (EXAM6) + * + * @return none + */ +void UDisk_USBH_SectorOperation( void ) +{ + uint8_t ret, SecCount, s; + uint8_t i; + uint16_t tmp; + uint8_t tmpbuf[64]; + + ret = UDisk_USBH_DiskReady( ); + if( ( ret == DISK_READY )&&( UDisk_Opeation_Flag == 1 ) ) + { + UDisk_Opeation_Flag = 0; + /* 查询磁盘物理容量 */ + printf( "DiskSize\r\n" ); + i = CHRV3DiskQuery( ); + mStopIfError( i ); + printf( "TotalSize = %u MB \n", (unsigned int)( mCmdParam.Query.mTotalSector * CHRV3vSectorSizeB / 2 ) ); //显示为以MB为单位的容量 + + /* 读取原文件 */ + printf( "Open\r\n" ); + strcpy( mCmdParam.Open.mPathName, "/NEWFILE.TXT" );//文件名,该文件在C51子目录下 + s = CHRV3FileOpen( ); //打开文件 + if ( s == ERR_MISS_DIR || s == ERR_MISS_FILE )//没有找到文件 + { + printf( "没有找到文件\r\n" ); + } + else //找到文件或者出错 + { + printf( "Query\r\n" ); + i = CHRV3FileQuery( ); //查询当前文件的信息 + mStopIfError( i ); + printf( "Read\r\n" ); + CHRV3vFileSize = CHRV3vFileSize+(sizeof( MY_DATA_BUF )-1); //原文件的长度 + SecCount = CHRV3vFileSize/ sizeof( MY_DATA_BUF ) ;//计算文件的扇区数,因为读写是以扇区为单位的,先加CHRV3vSectorSize-1是为了读出文件尾部不足1个扇区的部分 + printf( "Size=%ld, Sec=%d\r\n", CHRV3vFileSize, (uint16_t)SecCount ); + while(SecCount--) + { + mCmdParam.Read.mSectorCount = sizeof( MY_DATA_BUF )/512; //读取全部数据,如果超过2个扇区则只读取2个扇区 + mCmdParam.Read.mDataBuffer = &MY_DATA_BUF[0];//指向文件数据缓冲区的起始地址 + i = CHRV3FileRead( ); //从文件读取数据 + mStopIfError( i ); + if(SecCount == 0) break; + /* + for(tmp=0; tmpCONTROL = USBHS_UC_INT_BUSY | USBHS_UC_DMA_EN | USBHS_UC_SPEED_HIGH | USBHS_UC_HOST_MODE; + USBHSH->HOST_CTRL = USBHS_UH_PHY_SUSPENDM | USBHS_UH_SOF_EN; + USBHSH->HOST_EP_CONFIG = USBHS_UH_EP_TX_EN | USBHS_UH_EP_RX_EN; + USBHSH->HOST_RX_MAX_LEN = 512; + USBHSH->HOST_RX_DMA = (uint32_t)USBHS_RX_Buf; + USBHSH->HOST_TX_DMA = (uint32_t)USBHS_TX_Buf; + } + else + { + USBHSH->CONTROL = USBHS_UC_RESET_SIE | USBHS_UC_CLR_ALL; + } +} + +/********************************************************************* + * @fn USBHSH_CheckRootHubPortStatus + * + * @brief Check status of USB port. + * + * @para dev_sta: The status of the root device connected to this port. + * + * @return The current status of the port. + */ +uint8_t USBHSH_CheckRootHubPortStatus( uint8_t status ) +{ + /* Detect USB devices plugged or unplugged */ + if( USBHSH->INT_FG & USBHS_UIF_DETECT ) + { + USBHSH->INT_FG = USBHS_UIF_DETECT; // Clear flag + if( USBHSH->MIS_ST & USBHS_UMS_DEV_ATTACH ) // Detect that the USB device has been connected to the port + { + if( ( status == ROOT_DEV_DISCONNECT ) || ( ( status != ROOT_DEV_FAILED ) && ( USBHSH_CheckRootHubPortEnable( ) == 0x00 ) ) ) + { + return ROOT_DEV_CONNECTED; + } + else + { + return ROOT_DEV_FAILED; + } + } + else + { + return ROOT_DEV_DISCONNECT; + } + } + else + { + return ROOT_DEV_FAILED; + } +} + +/********************************************************************* + * @fn USBHSH_CheckRootHubPortEnable + * + * @brief Check the enable status of the USB port. + * + * @return The current enable status of the port. + */ +uint8_t USBHSH_CheckRootHubPortEnable( void ) +{ + return ( USBHSH->MIS_ST & USBHS_UMS_DEV_ATTACH ); +} + +/********************************************************************* + * @fn USBHSH_CheckRootHubPortSpeed + * + * @brief Check the speed of the USB port. + * + * @return The current speed of the port. + */ +uint8_t USBHSH_CheckRootHubPortSpeed( void ) +{ + uint8_t speed; + + speed = USBHSH->SPEED_TYPE & USBHS_USB_SPEED_TYPE; + + if( speed == USBHS_USB_SPEED_LOW ) + { + return USB_LOW_SPEED; + } + else if( speed == USBHS_USB_SPEED_FULL ) + { + return USB_FULL_SPEED; + } + else if( speed == USBHS_USB_SPEED_HIGH ) + { + return USB_HIGH_SPEED; + } + + return USB_SPEED_CHECK_ERR; +} + +/********************************************************************* + * @fn USBHSH_SetSelfAddr + * + * @brief Set the USB device address. + * + * @para addr: USB device address. + * + * @return none + */ +void USBHSH_SetSelfAddr( uint8_t addr ) +{ + USBHSH->DEV_AD = addr & USBHS_MASK_USB_ADDR; +} + +/********************************************************************* + * @fn USBHSH_SetSelfSpeed + * + * @brief Set USB speed. + * + * @para speed: USB speed. + * + * @return none + */ +void USBHSH_SetSelfSpeed( uint8_t speed ) +{ + if( speed == USB_HIGH_SPEED ) + { + USBHSH->CONTROL = ( USBHSH->CONTROL & ~USBHS_UC_SPEED_TYPE ) | USBHS_UC_SPEED_HIGH; + } + else if( speed == USB_FULL_SPEED ) + { + USBHSH->CONTROL = ( USBHSH->CONTROL & ~USBHS_UC_SPEED_TYPE ) | USBHS_UC_SPEED_FULL; + } + else + { + USBHSH->CONTROL = ( USBHSH->CONTROL & ~USBHS_UC_SPEED_TYPE ) | USBHS_UC_SPEED_LOW; + } +} + +/********************************************************************* + * @fn USBHSH_ResetRootHubPort + * + * @brief Reset USB port. + * + * @para mod: Reset host port operating mode. + * 0 -> reset and wait end + * 1 -> begin reset + * 2 -> end reset + * + * @return none + */ +void USBHSH_ResetRootHubPort( uint8_t mode ) +{ + USBHSH_SetSelfAddr( 0x00 ); + USBHSH_SetSelfSpeed( USB_HIGH_SPEED ); + if( mode <= 1 ) + { + USBHSH->HOST_CTRL |= USBHS_UH_TX_BUS_RESET; + } + if( mode == 0 ) + { + Delay_Ms( DEF_BUS_RESET_TIME ); + } + if( mode != 1 ) + { + USBHSH->HOST_CTRL &= ~USBHS_UH_TX_BUS_RESET; + } + Delay_Ms( 2 ); +} + +/********************************************************************* + * @fn USBHSH_EnableRootHubPort + * + * @brief Enable USB host port. + * + * @para *pspeed: USB speed. + * + * @return Operation result of the enabled port. + */ +uint8_t USBHSH_EnableRootHubPort( uint8_t *pspeed ) +{ + if( USBHSH->MIS_ST & USBHS_UMS_DEV_ATTACH ) + { + *pspeed = USBHSH_CheckRootHubPortSpeed( ); + USBHSH->HOST_CTRL |= USBHS_UH_SOF_EN; + + return ERR_SUCCESS; + } + + return ERR_USB_DISCON; +} + +/********************************************************************* + * @fn USBHSH_Transact + * + * @brief Perform USB transaction. + * + * @para endp_pid: Token PID. + * endp_tog: Toggle + * timeout: Timeout time. + * + * @return USB transfer result. + */ +uint8_t USBHSH_Transact( uint8_t endp_pid, uint8_t endp_tog, uint32_t timeout ) +{ + uint8_t r, trans_retry; + uint16_t i; + USBHSH->HOST_TX_CTRL = USBHSH->HOST_RX_CTRL = endp_tog; + trans_retry = 0; + do + { + USBHSH->HOST_EP_PID = endp_pid; // Set the token for the host to send the packet + USBHSH->INT_FG = USBHS_UIF_TRANSFER; + for( i = DEF_WAIT_USB_TOUT_200US; ( i != 0 ) && ( ( USBHSH->INT_FG & USBHS_UIF_TRANSFER ) == 0 ); i-- ) + { + Delay_Us( 1 ); + } + USBHSH->HOST_EP_PID = 0x00; + if( ( USBHSH->INT_FG & USBHS_UIF_TRANSFER ) == 0 ) + { + return ERR_USB_UNKNOWN; + } + + if( USBHSH->INT_FG & USBHS_UIF_DETECT ) + { + USBHSH->INT_FG = USBHS_UIF_DETECT; + Delay_Us( 200 ); + if( USBHSH->MIS_ST & USBHS_UIF_TRANSFER ) + { + if( USBHSH->HOST_CTRL & USBHS_UH_SOF_EN ) + { + return ERR_USB_CONNECT; + } + } + else + { + return ERR_USB_DISCON; + } + } + else if( USBHSH->INT_FG & USBHS_UIF_TRANSFER ) // The packet transmission was successful + { + r = USBHSH->INT_ST & USBHS_UIS_H_RES_MASK; + if( ( endp_pid >> 4 ) == USB_PID_IN ) + { + if( USBHSH->INT_ST & USBHS_UIS_TOG_OK ) + { + return ERR_SUCCESS; // Packet token match + } + } + else + { + if( ( r == USB_PID_ACK ) || ( r == USB_PID_NYET ) ) + { + return ERR_SUCCESS; + } + } + if( r == USB_PID_STALL ) + { + return ( r | ERR_USB_TRANSFER ); + } + + if( r == USB_PID_NAK ) + { + if( timeout == 0 ) + { + return ( r | ERR_USB_TRANSFER ); + } + if( timeout < 0xFFFF ) + { + timeout--; + } + --trans_retry; + } + else switch( endp_pid >> 4 ) + { + case USB_PID_SETUP: + + case USB_PID_OUT: + if( r ) + { + return ( r | ERR_USB_TRANSFER ); + } + break; + case USB_PID_IN: + if( ( r == USB_PID_DATA0 ) || ( r == USB_PID_DATA1 ) ) + { + ; + } + else if( r ) + { + return ( r | ERR_USB_TRANSFER ); + } + break; + default: + return ERR_USB_UNKNOWN; + } + } + else + { + USBHSH->INT_FG = USBHS_UIF_DETECT | USBHS_UIF_TRANSFER | USBHS_UIF_SUSPEND | USBHS_UIF_HST_SOF | USBHS_UIF_FIFO_OV | USBHS_UIF_SETUP_ACT; + } + Delay_Us( 15 ); + } while( ++trans_retry < 10 ); + + return ERR_USB_TRANSFER; +} + +/********************************************************************* + * @fn USBHSH_CtrlTransfer + * + * @brief Host control transfer. + * + * @brief USB host control transfer. + * + * @para ep0_size: Device endpoint 0 size + * pbuf: Data buffer + * plen: Data length + * + * @return USB control transfer result. + */ +uint8_t USBHSH_CtrlTransfer( uint8_t ep0_size, uint8_t *pbuf, uint16_t *plen ) +{ + uint8_t s, tog = 1; + uint16_t rem_len, rx_len, rx_cnt, tx_cnt; + + if( plen ) + { + *plen = 0; + } + USBHSH->HOST_TX_LEN = 8; + s = USBHSH_Transact( ( USB_PID_SETUP << 4 ) | 0x00, 0, 200000 ); + if( s != ERR_SUCCESS ) + { + return s; + } + + rem_len = pUSBHS_SetupRequest->wLength; + if( rem_len && pbuf ) //data stage + { + if( pUSBHS_SetupRequest->bRequestType & USB_REQ_TYP_IN ) //device to host + { + while( rem_len ) + { + s = USBHSH_Transact( ( USB_PID_IN << 4 ) | 0x00, tog << 3, 20000 ); + if( s != ERR_SUCCESS ) + { + return s; + } + tog ^=1; + rx_len = ( USBHSH->RX_LEN < rem_len )? USBHSH->RX_LEN : rem_len; + rem_len -= rx_len; + if( plen ) + { + *plen += rx_len; + } + for( rx_cnt = 0; rx_cnt != rx_len; rx_cnt++ ) + { + *pbuf = USBHS_RX_Buf[ rx_cnt ]; + pbuf++; + } + if( ( USBHSH->RX_LEN == 0 ) || ( USBHSH->RX_LEN & ( ep0_size - 1 ) ) ) + { + break; + } + } + USBHSH->HOST_TX_LEN = 0; + } + else + { // host to device + while( rem_len ) + { + USBHSH->HOST_TX_LEN = ( rem_len >= ep0_size )? ep0_size : rem_len; + for( tx_cnt = 0; tx_cnt != USBHSH->HOST_TX_LEN; tx_cnt++ ) + { + USBHS_TX_Buf[ tx_cnt ] = *pbuf; + pbuf++; + } + s = USBHSH_Transact( ( USB_PID_OUT << 4 ) | 0x00, tog << 3, 20000 ); + if( s != ERR_SUCCESS ) + { + return s; + } + tog ^=1; + rem_len -= USBHSH->HOST_TX_LEN; + if( plen ) + { + *plen += USBHSH->HOST_TX_LEN; + } + } + } + } + + s = USBHSH_Transact( ( USBHSH->HOST_TX_LEN )? ( USB_PID_IN << 4 | 0x00 ) : ( USB_PID_OUT << 4 | 0x00 ), USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_T_TOG_DATA1, 20000 ); + if( s != ERR_SUCCESS ) + { + return s; + } + + if( USBHSH->HOST_TX_LEN == 0 ) + { + return ERR_SUCCESS; //status stage is out, send a zero-length packet. + } + + if( USBHSH->RX_LEN == 0 ) + { + return ERR_SUCCESS; //status stage is in, a zero-length packet is returned indicating success. + } + + return ERR_USB_BUF_OVER; +} + +/********************************************************************* + * @fn USBHSH_GetDeviceDescr + * + * @brief Get the device descriptor of the USB device. + * + * @para pep0_size: Device endpoint 0 size + * pbuf: Data buffer + * + * @return The result of getting the device descriptor. + */ +uint8_t USBHSH_GetDeviceDescr( uint8_t *pep0_size, uint8_t *pbuf ) +{ + uint8_t s; + uint16_t len; + + *pep0_size = DEFAULT_ENDP0_SIZE; + memcpy( pUSBHS_SetupRequest, SetupGetDevDesc, sizeof( USB_SETUP_REQ ) ); + s = USBHSH_CtrlTransfer( *pep0_size, pbuf, &len ); + if( s != ERR_SUCCESS ) + { + return s; + } + + *pep0_size = ( (PUSB_DEV_DESCR)pbuf )->bMaxPacketSize0; + if( len < ( (PUSB_SETUP_REQ)SetupGetDevDesc )->wLength ) + { + return ERR_USB_BUF_OVER; + } + return ERR_SUCCESS; +} + +/********************************************************************* + * @fn USBHSH_GetConfigDescr + * + * @brief Get the configuration descriptor of the USB device. + * + * @para ep0_size: Device endpoint 0 size + * pbuf: Data buffer + * buf_len: Data buffer length + * pcfg_len: The length of the device configuration descriptor + * + * @return The result of getting the configuration descriptor. + */ +uint8_t USBHSH_GetConfigDescr( uint8_t ep0_size, uint8_t *pbuf, uint16_t buf_len, uint16_t *pcfg_len ) +{ + uint8_t s; + + /* Get the string descriptor of the first 4 bytes */ + memcpy( pUSBHS_SetupRequest, SetupGetCfgDesc, sizeof( USB_SETUP_REQ ) ); + s = USBHSH_CtrlTransfer( ep0_size, pbuf, pcfg_len ); + if( s != ERR_SUCCESS ) + { + return s; + } + if( *pcfg_len < ( (PUSB_SETUP_REQ)SetupGetCfgDesc )->wLength ) + { + return ERR_USB_BUF_OVER; + } + + /* Get the complete string descriptor */ + *pcfg_len = ((PUSB_CFG_DESCR)pbuf)->wTotalLength; + if( *pcfg_len > buf_len ) + { + *pcfg_len = buf_len; + } + memcpy( pUSBHS_SetupRequest, SetupGetCfgDesc, sizeof( USB_SETUP_REQ ) ); + pUSBHS_SetupRequest->wLength = *pcfg_len; + s = USBHSH_CtrlTransfer( ep0_size, pbuf, pcfg_len ); + return s; +} + +/********************************************************************* + * @fn USBH_GetStrDescr + * + * @brief Get the string descriptor of the USB device. + * + * @para ep0_size: Device endpoint 0 size + * str_num: Index of string descriptor + * pbuf: Data buffer + * + * @return The result of getting the string descriptor. + */ +uint8_t USBHSH_GetStrDescr( uint8_t ep0_size, uint8_t str_num, uint8_t *pbuf ) +{ + uint8_t s; + uint16_t len; + + /* Get the string descriptor of the first 4 bytes */ + memcpy( pUSBHS_SetupRequest, SetupGetStrDesc, sizeof( USB_SETUP_REQ ) ); + pUSBHS_SetupRequest->wValue = ( (uint16_t)USB_DESCR_TYP_STRING << 8 ) | str_num; + s = USBHSH_CtrlTransfer( ep0_size, pbuf, &len ); + if( s != ERR_SUCCESS ) + { + return s; + } + + /* Get the complete string descriptor */ + len = pbuf[ 0 ]; + memcpy( pUSBHS_SetupRequest, SetupGetStrDesc, sizeof( USB_SETUP_REQ ) ); + pUSBHS_SetupRequest->wValue = ( (uint16_t)USB_DESCR_TYP_STRING << 8 ) | str_num; + pUSBHS_SetupRequest->wLength = len; + s = USBHSH_CtrlTransfer( ep0_size, pbuf, &len ); + if( s != ERR_SUCCESS ) + { + return s; + } + return ERR_SUCCESS; +} + +/********************************************************************* + * @fn USBH_SetUsbAddress + * + * @brief Set USB device address. + * + * @para ep0_size: Device endpoint 0 size + * addr: Device address + * + * @return The result of setting device address. + */ +uint8_t USBHSH_SetUsbAddress( uint8_t ep0_size, uint8_t addr ) +{ + uint8_t s; + + memcpy( pUSBHS_SetupRequest, SetupSetAddr, sizeof( USB_SETUP_REQ ) ); + pUSBHS_SetupRequest->wValue = (uint16_t)addr; + s = USBHSH_CtrlTransfer( ep0_size, NULL, NULL ); + if( s != ERR_SUCCESS ) + { + return s; + } + USBHSH_SetSelfAddr( addr ); + Delay_Ms( DEF_BUS_RESET_TIME >> 1 ); // Wait for the USB device to complete its operation. + return ERR_SUCCESS; +} + +/********************************************************************* + * @fn USBH_SetUsbConfig + * + * @brief Set USB configuration. + * + * @para ep0_size: Device endpoint 0 size + * cfg: Device configuration value + * + * @return The result of setting device configuration. + */ +uint8_t USBHSH_SetUsbConfig( uint8_t ep0_size, uint8_t cfg_val ) +{ + memcpy( pUSBHS_SetupRequest, SetupSetConfig, sizeof( USB_SETUP_REQ ) ); + pUSBHS_SetupRequest->wValue = (uint16_t)cfg_val; + return USBHSH_CtrlTransfer( ep0_size, NULL, NULL ); +} + +/********************************************************************* + * @fn USBH_ClearEndpStall + * + * @brief Clear endpoint stall. + * + * @para ep0_size: Device endpoint 0 size + * endp_num: Endpoint number. + * + * @return The result of clearing endpoint stall. + */ +uint8_t USBHSH_ClearEndpStall( uint8_t ep0_size, uint8_t endp_num ) +{ + memcpy( pUSBHS_SetupRequest, SetupClearEndpStall, sizeof( USB_SETUP_REQ ) ); + pUSBHS_SetupRequest->wIndex = (uint16_t)endp_num; + return ( USBHSH_CtrlTransfer( ep0_size, NULL, NULL ) ); +} + +/********************************************************************* + * @fn USBHSH_GetEndpData + * + * @brief Get data from USB device input endpoint. + * + * @para endp_num: Endpoint number + * pendp_tog: Endpoint toggle + * pbuf: Data Buffer + * plen: Data length + * + * @return The result of getting data. + */ +uint8_t USBHSH_GetEndpData( uint8_t endp_num, uint8_t *pendp_tog, uint8_t *pbuf, uint16_t *plen ) +{ + uint8_t s; + + s = USBHSH_Transact( ( USB_PID_IN << 4 ) | endp_num, *pendp_tog, 0 ); + if( s == ERR_SUCCESS ) + { + *pendp_tog ^= USBHS_UH_T_TOG_DATA1 | USBHS_UH_R_TOG_DATA1; + *plen = USBHSH->RX_LEN; + memcpy( pbuf, USBHS_RX_Buf, *plen ); + } + + return s; +} + +/********************************************************************* + * @fn USBHSH_SendEndpData + * + * @brief Send data to the USB device output endpoint. + * + * @para endp_num: Endpoint number + * pendp_tog: Endpoint toggle + * pbuf: Data Buffer + * plen: Data length + * + * @return The result of sending data. + */ +uint8_t USBHSH_SendEndpData( uint8_t endp_num, uint8_t *pendp_tog, uint8_t *pbuf, uint16_t len ) +{ + uint8_t s; + + memcpy( USBHS_TX_Buf, pbuf, len ); + USBHSH->HOST_TX_LEN = len; + + s = USBHSH_Transact( ( USB_PID_OUT << 4 ) | endp_num, *pendp_tog, 0 ); + if( s == ERR_SUCCESS ) + { + *pendp_tog ^= USBHS_UH_T_TOG_DATA1 | USBHS_UH_R_TOG_DATA1; + } + + return s; +} diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/can/connect_can.c b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/can/connect_can.c index df7842f50..0414fd3ee 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/can/connect_can.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/can/connect_can.c @@ -182,7 +182,7 @@ static uint32 CanReadData(void *dev , struct BusBlockReadParam *databuf) ret = CAN_GetRxFrame(CAN_X, &frame_received); if(EOK != ret){ - // KPrintf("CAN recv frame failed(CODE:%d)!\n",ret); + // KPrintf("CAN recv frame failed(CODE:%d)!\n",ret); p_can_config->data_lenth = 0; return ERROR; } diff --git a/Ubiquitous/XiZi_IIoT/path_kernel.mk b/Ubiquitous/XiZi_IIoT/path_kernel.mk index 36ebeb926..07ed18cbc 100755 --- a/Ubiquitous/XiZi_IIoT/path_kernel.mk +++ b/Ubiquitous/XiZi_IIoT/path_kernel.mk @@ -285,6 +285,7 @@ KERNELPATHS += \ -I$(KERNEL_ROOT)/arch/risc-v/ch32v307vct6/User \ -I$(KERNEL_ROOT)/arch/risc-v/ch32v307vct6 \ -I$(BSP_ROOT)/third_party_driver/include \ + -I$(BSP_ROOT)/third_party_driver/usb/usb_drv/inc \ -I$(BSP_ROOT)/third_party_driver/Peripheral/inc \ -I$(BSP_ROOT)/include \ -I$(KERNEL_ROOT)/include #