diff --git a/vendor/DFRobot_Beetle_WS63/build_config.json b/vendor/DFRobot_Beetle_WS63/build_config.json new file mode 100644 index 0000000000000000000000000000000000000000..5b2f33e7c7a4dc14ecf69164aca37e3aada6c3ec --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/build_config.json @@ -0,0 +1,112 @@ +[ + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_ble_uart", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"1", + "name":"beetle_ble_uart", + "description":"BLE串口" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_sle_uart", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"2", + "name":"beetle_sle_uart", + "description":"SLE串口" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_mqtt", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"3", + "name":"beetle_mqtt", + "description":"MQTT发布、接收消息" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_urm37", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"4", + "name":"beetle_urm37", + "description":"URM37超声波传感器测距" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_button", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"5", + "name":"beetle_button", + "description":"板载按钮中断" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_ds18b20", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"6", + "name":"beetle_ds18b20", + "description":"DS18B20温度传感器" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_df9gms", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"7", + "name":"beetle_df9gms", + "description":"DF9GMS舵机控制" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_c4001", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"8", + "name":"beetle_c4001", + "description":"C4001雷达传感器" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_lis2dh12", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"9", + "name":"beetle_lis2dh12", + "description":"LIS2DH12加速度传感器" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_ssd1306", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"10", + "name":"beetle_ssd1306", + "description":"SSD1306 OLED显示屏" + }, + { + "buildTarget": "ws63-liteos-app", + "relativePath": "demo/beetle_bme680", + "chip": "WS63", + "buildDef": "", + "needSmoke": "false", + "key":"11", + "name":"beetle_bme680", + "description":"BME680环境传感器" + } +] diff --git a/vendor/DFRobot_Beetle_WS63/demo/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..86761b43dc75be1b71f5ce29c5a01f5ae60d1224 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/CMakeLists.txt @@ -0,0 +1,52 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== + +if(DEFINED CONFIG_SAMPLE_SUPPORT_BLE_UART) + add_subdirectory_if_exist(beetle_ble_uart) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_SLE_UART) + add_subdirectory_if_exist(beetle_sle_uart) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_MQTT) + add_subdirectory_if_exist(beetle_mqtt) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_URM37) + add_subdirectory_if_exist(beetle_urm37) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_BUTTON) + add_subdirectory_if_exist(beetle_button) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_DS18B20) + add_subdirectory_if_exist(beetle_ds18b20) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_DF9GMS) + add_subdirectory_if_exist(beetle_df9gms) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_C4001) + add_subdirectory_if_exist(beetle_c4001) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_LIS2DH12) + add_subdirectory_if_exist(beetle_lis2dh12) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_SSD1306) + add_subdirectory_if_exist(beetle_ssd1306) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_BME680) + add_subdirectory_if_exist(beetle_bme680) +endif() + +set(SOURCES "${SOURCES}" PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" PARENT_SCOPE) + diff --git a/vendor/DFRobot_Beetle_WS63/demo/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3e31de795d2a4ffb60e79b793a42d4b3f34619a1 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/Kconfig @@ -0,0 +1,140 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== + +config SAMPLE_SUPPORT_BLE_UART + bool + prompt "Enable the Sample of BLE_UART." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of BLE_UART. + +if SAMPLE_SUPPORT_BLE_UART +menu "BLE UART Sample Configuration" + osource "application/samples/beetle_demo/beetle_ble_uart/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_SLE_UART + bool + prompt "Enable the Sample of SLE_UART." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of SLE_UART. + +if SAMPLE_SUPPORT_SLE_UART +menu "SLE UART Sample Configuration" + osource "application/samples/beetle_demo/beetle_sle_uart/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_MQTT + bool + prompt "Enable the Sample of MQTT." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of MQTT. +if SAMPLE_SUPPORT_MQTT +menu "MQTT Sample Configuration" + osource "application/samples/beetle_demo/beetle_mqtt/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_URM37 + bool + prompt "Enable the Sample of URM37." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of URM37. +if SAMPLE_SUPPORT_URM37 +menu "URM37 Sample Configuration" + osource "application/samples/beetle_demo/beetle_urm37/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_BUTTON + bool + prompt "Enable the Sample of Button." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of Button. + +config SAMPLE_SUPPORT_DS18B20 + bool + prompt "Enable the Sample of DS18B20." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of beetle_DS18B20. +if SAMPLE_SUPPORT_DS18B20 +menu "DS18B20 Sample Configuration" + osource "application/samples/beetle_demo/beetle_ds18b20/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_DF9GMS + bool + prompt "Enable the Sample of DF9GMS." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of DF9GMS. +if SAMPLE_SUPPORT_DF9GMS +menu "DF9GMS Sample Configuration" + osource "application/samples/beetle_demo/beetle_df9gms/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_C4001 + bool + prompt "Enable the Sample of C4001." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of C4001. +if SAMPLE_SUPPORT_C4001 +menu "C4001 Sample Configuration" + osource "application/samples/beetle_demo/beetle_c4001/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_LIS2DH12 + bool + prompt "Enable the Sample of LIS2DH12." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of LIS2DH12. +if SAMPLE_SUPPORT_LIS2DH12 +menu "LIS2DH12 Sample Configuration" + osource "application/samples/beetle_demo/beetle_lis2dh12/Kconfig" +endmenu +endif + +config SAMPLE_SUPPORT_SSD1306 + bool + prompt "Enable the Sample of SSD1306." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of SSD1306. + + +config SAMPLE_SUPPORT_BME680 + bool + prompt "Enable the Sample of BME680." + default n + depends on ENABLE_BEETLE_DEMO + help + This option means enable the sample of BME680. +if SAMPLE_SUPPORT_BME680 +menu "BME680 Sample Configuration" + osource "application/samples/beetle_demo/beetle_bme680/Kconfig" +endmenu +endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a024849ba856ca890054854ae36aa001fba915f4 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/CMakeLists.txt @@ -0,0 +1,22 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +if(DEFINED CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER) +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_server/ble_uart_server.c + ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_server/ble_uart_server_adv.c + ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_sample.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_server) +elseif(DEFINED CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT) +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_client/ble_uart_client.c + ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_client/ble_uart_client_scan.c + ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_sample.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/ble_uart_client) +endif() + +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" ${HEADER_LIST} PARENT_SCOPE) \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..efbcc3de97c3d2898776d99831e6d71c951fd0de --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/Kconfig @@ -0,0 +1,21 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved. +#=============================================================================== + +config BLE_UART_BUS + int + prompt "Set the UART BUS of the currrent sample." + default 0 + depends on SAMPLE_SUPPORT_BLE_UART + help + This option means the UART BUS of the currrent sample. + +choice + prompt "Select ble uart type" + default SAMPLE_SUPPORT_BLE_UART_SERVER + config SAMPLE_SUPPORT_BLE_UART_SERVER + bool "Enable BLE UART Server sample." + config SAMPLE_SUPPORT_BLE_UART_CLIENT + bool "Enable BLE UART Client sample." +endchoice diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client.c new file mode 100644 index 0000000000000000000000000000000000000000..a06eb068098c6fe46d8c86245c0aabc2d129f9d0 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client.c @@ -0,0 +1,409 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE uart sample of client. \n + * + * History: \n + * 2023-04-03, Create file. \n + */ +#include "securec.h" +#include "product.h" +#include "soc_osal.h" +#include "osal_debug.h" +#include "osal_addr.h" +#include "uart.h" +#include "bts_le_gap.h" +#include "bts_gatt_client.h" +#include "ble_uart_client_scan.h" +#include "ble_uart_client.h" + +#define UUID16_LEN 2 +/* Characteristic UUID */ +#define BLE_UART_CHARACTER_CLIENT_UUID_TX 0xEFEF +#define BLE_UART_CLIENT_LOG "[ble uart client]" +#define BLE_UART_CLIENT_ERROR "[ble uart client error]" +#define DELAY_MS 500 + +/* client id, invalid client id is "0" */ +static uint8_t g_uart_client_id = 0; +/* connection id, invalid client id is "0" */ +static uint16_t g_uart_conn_id = 0; +/* max transport unit, default is 100 */ +static uint16_t g_uart_mtu = 100; +/* characteristic handle */ +static uint16_t g_ble_uart_chara_handle_write_value = 0; + +/* uart client app uuid for test */ +static bt_uuid_t g_client_app_uuid = {UUID16_LEN, {0}}; + +/* server address for client connect */ +static uint8_t g_ble_server_addr_connect[] = {0x66, 0x55, 0x44, 0x33, 0x22, 0x11}; + +static uint8_t g_ble_uart_name_value[] = {'b', 'l', 'e', '_', 'u', 'a', 'r', 't', '\0'}; +static uint8_t g_ble_uart_client_addr[] = {0x12, 0x22, 0x33, 0x44, 0x55, 0x66}; + +static void bts_data_to_uuid_len2(uint16_t uuid_data, bt_uuid_t *out_uuid) +{ + out_uuid->uuid_len = UUID16_LEN; + out_uuid->uuid[0] = (uint8_t)(uuid_data >> 8); /* 8: octet bit num */ + out_uuid->uuid[1] = (uint8_t)(uuid_data); +} + +/* ble client discover all service */ +errcode_t ble_uart_client_discover_all_service(uint16_t conn_id) +{ + bt_uuid_t service_uuid = {0}; /* uuid length is zero, discover all service */ + return gattc_discovery_service(g_uart_client_id, conn_id, &service_uuid); +} + +/* ble client write data to server */ +errcode_t ble_uart_client_write_cmd(uint8_t *data, uint16_t len, uint16_t handle) +{ + gattc_handle_value_t uart_handle_value = {0}; + uart_handle_value.handle = handle; + uart_handle_value.data_len = len; + uart_handle_value.data = data; + osal_printk("%s ble_uart_client_write_cmd len: %d, g_uart_client_id: %x\n", BLE_UART_CLIENT_LOG, len, + g_uart_client_id); + for (uint16_t i = 0; i < len; i++) { + osal_printk("%02x", data[i]); + } + osal_printk("\n"); + errcode_t ret = gattc_write_cmd(g_uart_client_id, g_uart_conn_id, &uart_handle_value); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s gattc_write_cmd failed\n", BLE_UART_CLIENT_LOG); + return ERRCODE_BT_FAIL; + } + return ERRCODE_BT_SUCCESS; +} + +/* ble client set scan param callback */ +void ble_uart_client_set_scan_param_cbk(errcode_t status) +{ + osal_printk("%s set scan param status: %d\n", BLE_UART_CLIENT_LOG, status); + gap_ble_remove_all_pairs(); + ble_uart_start_scan(); +} + +/* ble client scan result callback */ +void ble_uart_client_scan_result_cbk(gap_scan_result_data_t *scan_result_data) +{ + if (memcmp(g_ble_server_addr_connect, scan_result_data->addr.addr, sizeof(g_ble_server_addr_connect)) == 0) { + gap_ble_stop_scan(); + osal_printk("\naddr:"); + for (uint8_t i = 0; i < BD_ADDR_LEN; i++) { + osal_printk(" %02x: ", scan_result_data->addr.addr[i]); + } + bd_addr_t bt_uart_client_addr = {0}; + bt_uart_client_addr.type = scan_result_data->addr.type; + if (memcpy_s(bt_uart_client_addr.addr, BD_ADDR_LEN, scan_result_data->addr.addr, BD_ADDR_LEN) != EOK) { + osal_printk("%s add server app addr memcpy failed\r\n", BLE_UART_CLIENT_ERROR); + return; + } + gap_ble_connect_remote_device(&bt_uart_client_addr); + } +} + +/* ble client connect state change callback */ +void ble_uart_client_connect_change_cbk(uint16_t conn_id, + bd_addr_t *addr, + gap_ble_conn_state_t conn_state, + gap_ble_pair_state_t pair_state, + gap_ble_disc_reason_t disc_reason) +{ + bd_addr_t bt_uart_client_addr = {0}; + bt_uart_client_addr.type = addr->type; + g_uart_conn_id = conn_id; + if (memcpy_s(bt_uart_client_addr.addr, BD_ADDR_LEN, addr->addr, BD_ADDR_LEN) != EOK) { + osal_printk("%s add server app addr memcpy failed\r\n", BLE_UART_CLIENT_ERROR); + return; + } + osal_printk("%s connect state change conn_id: %d, status: %d, pair_status:%d, disc_reason %x\n", + BLE_UART_CLIENT_LOG, conn_id, conn_state, pair_state, disc_reason); + + if (conn_state == GAP_BLE_STATE_CONNECTED && pair_state == GAP_BLE_PAIR_NONE) { + osal_printk("%s connect change cbk conn_id =%d \n", BLE_UART_CLIENT_LOG, conn_id); + gattc_exchange_mtu_req(g_uart_client_id, g_uart_conn_id, g_uart_mtu); + } else if (conn_state == GAP_BLE_STATE_DISCONNECTED) { + osal_printk("%s connect change cbk conn disconnected \n", BLE_UART_CLIENT_LOG); + ble_uart_start_scan(); + return; + } +} + +/* ble client pair result callback */ +void ble_uart_client_pair_result_cb(uint16_t conn_id, const bd_addr_t *addr, errcode_t status) +{ + osal_printk("%s pair result conn_id: %d,status: %d \n", BLE_UART_CLIENT_LOG, conn_id, status); + osal_printk("addr:\n"); + for (uint8_t i = 0; i < BD_ADDR_LEN; i++) { + osal_printk("%2x", addr->addr[i]); + } + osal_printk("\n"); + gattc_exchange_mtu_req(g_uart_client_id, g_uart_conn_id, g_uart_mtu); +} + +/* ble client bt stack enable callback */ +void ble_uart_client_enable_cbk(errcode_t status) +{ + osal_printk("ble enable: %d\n", status); + errcode_t ret = 0; + bd_addr_t ble_addr = {0}; + ble_addr.type = BLE_PUBLIC_DEVICE_ADDRESS; + osal_msleep(DELAY_MS); /* 延时500ms,等待SLE初始化完毕 */ + if (memcpy_s(ble_addr.addr, BD_ADDR_LEN, g_ble_uart_client_addr, sizeof(g_ble_uart_client_addr)) != EOK) { + osal_printk("%s add server app addr memcpy failed\n", BLE_UART_CLIENT_ERROR); + return; + } + ret = gap_ble_set_local_name(g_ble_uart_name_value, sizeof(g_ble_uart_name_value)); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s gap_ble_set_local_name ret = %x\n", BLE_UART_CLIENT_ERROR, ret); + } + ret = gap_ble_set_local_addr(&ble_addr); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s gap_ble_set_local_addr ret = %x\n", BLE_UART_CLIENT_ERROR, ret); + } + ret = gattc_register_client(&g_client_app_uuid, &g_uart_client_id); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s gattc_register_client ret = %x\n", BLE_UART_CLIENT_ERROR, ret); + } + + ble_uart_set_scan_parameters(); + osal_printk("ble enable end: %d\n", status); +} + +/* ble client service discovery callback */ +static void ble_uart_client_discover_service_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_discovery_service_result_t *service, + errcode_t status) +{ + gattc_discovery_character_param_t param = {0}; + osal_printk("%s Discovery service callback client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id); + osal_printk("%s start handle:%d end handle:%d uuid_len:%d uuid:\n", BLE_UART_CLIENT_LOG, service->start_hdl, + service->end_hdl, service->uuid.uuid_len); + for (uint8_t i = 0; i < service->uuid.uuid_len; i++) { + osal_printk("%02x", service->uuid.uuid[i]); + } + osal_printk("\n %s status:%d\n", BLE_UART_CLIENT_LOG, status); + param.service_handle = service->start_hdl; + param.uuid.uuid_len = service->uuid.uuid_len; /* uuid length is zero, discover all character */ + if (memcpy_s(param.uuid.uuid, param.uuid.uuid_len, service->uuid.uuid, service->uuid.uuid_len) != 0) { + osal_printk("%s memcpy error\n", BLE_UART_CLIENT_ERROR); + } + gattc_discovery_character(g_uart_client_id, conn_id, ¶m); +} + +/* ble client character discovery callback */ +static void ble_uart_client_discover_character_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_discovery_character_result_t *character, + errcode_t status) +{ + for (uint8_t i = 0; i < character->uuid.uuid_len; i++) { + osal_printk("%02x", character->uuid.uuid[i]); + } + osal_printk("\n%s discover character declare_handle:%d, value_handle:%d, properties:%2x\n", BLE_UART_CLIENT_LOG, + character->declare_handle, character->value_handle, character->properties); + osal_printk("%s client_id:%d, conn_id = %d, status:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id, status); + bt_uuid_t write_uuid = {0}; + bts_data_to_uuid_len2(BLE_UART_CHARACTER_CLIENT_UUID_TX, &write_uuid); + write_uuid.uuid_len = BT_UUID_MAX_LEN; + if (memcmp(character->uuid.uuid, write_uuid.uuid, character->uuid.uuid_len) == 0) { + g_ble_uart_chara_handle_write_value = character->value_handle; + osal_printk("%s write declare_handle:%d, value_handle:%d, properties:%2x\n", BLE_UART_CLIENT_LOG, + character->declare_handle, character->value_handle, character->properties); + } + gattc_discovery_descriptor(g_uart_client_id, conn_id, character->declare_handle); +} + +/* ble client descriptor discovery callback */ +static void ble_uart_client_discover_descriptor_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_discovery_descriptor_result_t *descriptor, + errcode_t status) +{ + osal_printk("%s Discovery descriptor----client:%d conn_id:%d uuid len:%d, uuid:\n", BLE_UART_CLIENT_LOG, client_id, + conn_id, descriptor->uuid.uuid_len); + for (uint8_t i = 0; i < descriptor->uuid.uuid_len; i++) { + osal_printk("%02x", descriptor->uuid.uuid[i]); + } + osal_printk("\n%s descriptor handle:%d, status:%d\n", BLE_UART_CLIENT_LOG, descriptor->descriptor_hdl, status); + + gattc_read_req_by_uuid_param_t paramsss = {0}; + paramsss.uuid = descriptor->uuid; + paramsss.start_hdl = descriptor->descriptor_hdl; + paramsss.end_hdl = descriptor->descriptor_hdl; + gattc_read_req_by_uuid(client_id, conn_id, ¶msss); +} + +/* ble client compare service uuid */ +static void ble_uart_client_discover_service_compl_cbk(uint8_t client_id, + uint16_t conn_id, + bt_uuid_t *uuid, + errcode_t status) +{ + osal_printk("%s Discovery service complete----client:%d conn_id:%d uuid len:%d uuid:\n", BLE_UART_CLIENT_LOG, + client_id, conn_id, uuid->uuid_len); + for (uint8_t i = 0; i < uuid->uuid_len; i++) { + osal_printk("%02x", uuid->uuid[i]); + } + osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status); +} + +/* ble client character discovery complete callback */ +static void ble_uart_client_discover_character_compl_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_discovery_character_param_t *param, + errcode_t status) +{ + osal_printk("%s Discovery character complete----client:%d conn_id:%d uuid len:%d uuid: \n", BLE_UART_CLIENT_LOG, + client_id, conn_id, param->uuid.uuid_len); + for (uint8_t i = 0; i < param->uuid.uuid_len; i++) { + osal_printk("%02x", param->uuid.uuid[i]); + } + osal_printk("\n%s service handle:%d status:%d\n", BLE_UART_CLIENT_LOG, param->service_handle, status); +} + +/* ble client descriptor discovery complete callback */ +static void ble_uart_client_discover_descriptor_compl_cbk(uint8_t client_id, + uint16_t conn_id, + uint16_t character_handle, + errcode_t status) +{ + osal_printk("%s Discovery descriptor complete----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id); + osal_printk("%s character handle:%d, status:%d\n", BLE_UART_CLIENT_LOG, character_handle, status); +} + +/* Callback invoked when receive read response */ +static void ble_uart_client_read_cfm_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_handle_value_t *read_result, + gatt_status_t status) +{ + osal_printk("%s Read result client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id); + osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, read_result->handle, read_result->data_len); + for (uint8_t i = 0; i < read_result->data_len; i++) { + osal_printk("%02x", read_result->data[i]); + } + osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status); +} + +/* Callback invoked when read complete */ +static void ble_uart_client_read_compl_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_read_req_by_uuid_param_t *param, + errcode_t status) +{ + osal_printk("%s Read by uuid complete----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id); + osal_printk("%s start handle:%d end handle:%d uuid len:%d uuid:\n", BLE_UART_CLIENT_LOG, param->start_hdl, + param->end_hdl, param->uuid.uuid_len); + for (uint8_t i = 0; i < param->uuid.uuid_len; i++) { + osal_printk("%02x", param->uuid.uuid[i]); + } + osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status); +} + +/* Callback invoked when receive write response */ +static void ble_uart_client_write_cfm_cbk(uint8_t client_id, uint16_t conn_id, uint16_t handle, gatt_status_t status) +{ + osal_printk("%s Write result----client:%d conn_id:%d handle:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id, handle); + osal_printk("%s status:%d\n", BLE_UART_CLIENT_LOG, status); +} + +/* Callback invoked when change MTU complete */ +static void ble_uart_client_mtu_changed_cbk(uint8_t client_id, uint16_t conn_id, uint16_t mtu_size, errcode_t status) +{ + osal_printk("%s Mtu changed----client:%d conn_id:%d, mtu size:%d, status:%d\n", BLE_UART_CLIENT_LOG, client_id, + conn_id, mtu_size, status); + ble_uart_client_discover_all_service(conn_id); +} + +/* Callback invoked when receive server notification */ +static void ble_uart_client_notification_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_handle_value_t *data, + errcode_t status) +{ + osal_printk("%s Receive notification----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id); + osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, data->handle, data->data_len); + osal_printk("%s ble_uart_client_notification_cbk %s", BLE_UART_CLIENT_LOG, data->data); + osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status); + uapi_uart_write(CONFIG_BLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0); +} + +/* Callback invoked when receive server indication */ +static void ble_uart_client_indication_cbk(uint8_t client_id, + uint16_t conn_id, + gattc_handle_value_t *data, + errcode_t status) +{ + osal_printk("%s Receive indication----client:%d conn_id:%d\n", BLE_UART_CLIENT_LOG, client_id, conn_id); + osal_printk("%s handle:%d data_len:%d\ndata:", BLE_UART_CLIENT_LOG, data->handle, data->data_len); + for (uint8_t i = 0; i < data->data_len; i++) { + osal_printk("%02x", data->data[i]); + } + osal_printk("\n%s status:%d\n", BLE_UART_CLIENT_LOG, status); +} + +/* register gatt and gap callback */ +errcode_t ble_uart_client_callback_register(void) +{ + errcode_t ret = 0; + + gattc_callbacks_t cb = {0}; + gap_ble_callbacks_t gap_cb = {0}; + gap_cb.ble_enable_cb = ble_uart_client_enable_cbk; + gap_cb.set_scan_param_cb = ble_uart_client_set_scan_param_cbk; + gap_cb.scan_result_cb = ble_uart_client_scan_result_cbk; + gap_cb.conn_state_change_cb = ble_uart_client_connect_change_cbk; + gap_cb.pair_result_cb = ble_uart_client_pair_result_cb; + ret |= gap_ble_register_callbacks(&gap_cb); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s reg gap cbk failed ret = %d\n", BLE_UART_CLIENT_ERROR, ret); + } + + cb.discovery_svc_cb = ble_uart_client_discover_service_cbk; + cb.discovery_svc_cmp_cb = ble_uart_client_discover_service_compl_cbk; + cb.discovery_chara_cb = ble_uart_client_discover_character_cbk; + cb.discovery_chara_cmp_cb = ble_uart_client_discover_character_compl_cbk; + cb.discovery_desc_cb = ble_uart_client_discover_descriptor_cbk; + cb.discovery_desc_cmp_cb = ble_uart_client_discover_descriptor_compl_cbk; + cb.read_cb = ble_uart_client_read_cfm_cbk; + cb.read_cmp_cb = ble_uart_client_read_compl_cbk; + cb.write_cb = ble_uart_client_write_cfm_cbk; + cb.mtu_changed_cb = ble_uart_client_mtu_changed_cbk; + cb.notification_cb = ble_uart_client_notification_cbk; + cb.indication_cb = ble_uart_client_indication_cbk; + ret = gattc_register_callbacks(&cb); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s reg gatt cbk failed ret = %d\n", BLE_UART_CLIENT_ERROR, ret); + } +#if (CORE_NUMS < 2) + enable_ble(); +#endif + return ret; +} + +/* ble uart client init */ +errcode_t ble_uart_client_init(void) +{ + errcode_t ret = ERRCODE_BT_SUCCESS; + + ret |= ble_uart_client_callback_register(); + osal_printk("[SLE Client] try enable1.\r\n"); + + ret |= enable_ble(); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s enable_ble ret = %x\n", BLE_UART_CLIENT_ERROR, ret); + } + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s init failed ret = %x\n", BLE_UART_CLIENT_ERROR, ret); + } + return ret; +} + +uint16_t ble_uart_get_write_value_handle(void) +{ + return g_ble_uart_chara_handle_write_value; +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client.h new file mode 100644 index 0000000000000000000000000000000000000000..d701f84f7bf42c5c0c338c4b3c842001ada3b059 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE uart client Config. \n + * + * History: \n + * 2023-07-26, Create file. \n + */ + +#ifndef BLE_UART_CLIENT_H +#define BLE_UART_CLIENT_H + +#include +#include "common_def.h" +#include "errcode.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef enum { + BLE_PUBLIC_DEVICE_ADDRESS, + BLE_RANDOM_DEVICE_ADDRESS, + BLE_PUBLIC_IDENTITY_ADDRESS, + BLE_RANDOM_STATIC_IDENTITY_ADDRESS +} ble_address_t; + +errcode_t ble_uart_client_discover_all_service(uint16_t conn_id); +errcode_t ble_uart_client_write_cmd(uint8_t *data, uint16_t len, uint16_t hand); +errcode_t ble_uart_client_init(void); +uint16_t ble_uart_get_write_value_handle(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client_scan.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client_scan.c new file mode 100644 index 0000000000000000000000000000000000000000..333ad9c23315f0dadbd2d9cf28dc8c4e0942f764 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client_scan.c @@ -0,0 +1,40 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE uart client scan source. \n + * + * History: \n + * 2023-07-26, Create file. \n + */ +#include "errcode.h" +#include "bts_def.h" +#include "bts_le_gap.h" +#include "ble_uart_client_scan.h" +#include "osal_debug.h" + +static uint16_t g_uart_scan_interval = 0x48; +static uint16_t g_uart_scan_window = 0x48; +static uint8_t g_uart_scan_type = 0x00; +static uint8_t g_uart_scan_phy = 0x01; +static uint8_t g_uart_scan_filter_policy = 0x00; + +errcode_t ble_uart_set_scan_parameters(void) +{ + errcode_t ret = ERRCODE_BT_SUCCESS; + gap_ble_scan_params_t ble_uart_scan_params = {0}; + ble_uart_scan_params.scan_interval = g_uart_scan_interval; + ble_uart_scan_params.scan_window = g_uart_scan_window; + ble_uart_scan_params.scan_type = g_uart_scan_type; + ble_uart_scan_params.scan_phy = g_uart_scan_phy; + ble_uart_scan_params.scan_filter_policy = g_uart_scan_filter_policy; + ret = gap_ble_set_scan_parameters(&ble_uart_scan_params); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("gap_ble_set_scan_parameters ret = %x\n", ret); + } + return ret; +} + +errcode_t ble_uart_start_scan(void) +{ + return gap_ble_start_scan(); +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client_scan.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client_scan.h new file mode 100644 index 0000000000000000000000000000000000000000..b5451b1ed34b5cef33a7eb6b87878652ed054cdf --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_client/ble_uart_client_scan.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE uart client scan \n + * + * History: \n + * 2023-07-26, Create file. \n + */ +#ifndef BLE_UART_CLIENT_SCAN_H +#define BLE_UART_CLIENT_SCAN_H + +#include "errcode.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +errcode_t ble_uart_start_scan(void); +errcode_t ble_uart_set_scan_parameters(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..7f89b959f535717357758f05b7a95a6c94c69612 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_sample.c @@ -0,0 +1,150 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE UART Sample Source. \n + * + * History: \n + * 2023-07-20, Create file. \n + */ +#include "securec.h" +#include "common_def.h" +#include "soc_osal.h" +#include "app_init.h" +#include "uart.h" + +#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER) +#define BLE_UART_TASK_STACK_SIZE 0x1200 +#include "bts_gatt_server.h" +#include "ble_uart_server.h" +#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT) +#define BLE_UART_TASK_STACK_SIZE 0x1200 +#include "bts_gatt_client.h" +#include "ble_uart_client.h" +#endif /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */ + +#define BLE_UART_TASK_PRIO 28 +#define BLE_UART_BT_STACK_POWER_MS 10000 + +typedef struct { + uint8_t *value; + uint16_t value_len; +} msg_data_t; +unsigned long g_mouse_msg_queue = 0; +unsigned int g_msg_rev_size = sizeof(msg_data_t); + +#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER) +static void ble_uart_read_int_handler(const void *buffer, uint16_t length, bool error) +{ + osal_printk("ble_uart_read_int_handler server.\r\n"); + unused(error); + if (ble_uart_get_connection_state() != 0) { + msg_data_t msg_data = {0}; + void *buffer_cpy = osal_vmalloc(length); + if (memcpy_s(buffer_cpy, length, buffer, length) != EOK) { + osal_vfree(buffer_cpy); + return; + } + msg_data.value = (uint8_t *)buffer_cpy; + msg_data.value_len = length; + osal_msg_queue_write_copy(g_mouse_msg_queue, (void *)&msg_data, g_msg_rev_size, 0); + } +} + +static void *ble_uart_server_task(const char *arg) +{ + unused(arg); + ble_uart_server_init(); + errcode_t ret = uapi_uart_register_rx_callback( + CONFIG_BLE_UART_BUS, UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE, 1, ble_uart_read_int_handler); + if (ret != ERRCODE_SUCC) { + osal_printk("Register uart callback fail."); + return NULL; + } + while (1) { + msg_data_t msg_data = {0}; + int msg_ret = osal_msg_queue_read_copy(g_mouse_msg_queue, &msg_data, &g_msg_rev_size, OSAL_WAIT_FOREVER); + if (msg_ret != OSAL_SUCCESS) { + osal_printk("msg queue read copy fail."); + if (msg_data.value != NULL) { + osal_vfree(msg_data.value); + } + continue; + } + if (msg_data.value != NULL) { + ble_uart_server_send_input_report(msg_data.value, msg_data.value_len); + osal_vfree(msg_data.value); + } + } + return NULL; +} +#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT) +static void ble_uart_read_int_handler(const void *buffer, uint16_t length, bool error) +{ + osal_printk("ble_uart_read_int_handler client.\r\n"); + unused(error); + msg_data_t msg_data = {0}; + void *buffer_cpy = osal_vmalloc(length); + if (memcpy_s(buffer_cpy, length, buffer, length) != EOK) { + osal_vfree(buffer_cpy); + return; + } + msg_data.value = (uint8_t *)buffer_cpy; + msg_data.value_len = length; + osal_msg_queue_write_copy(g_mouse_msg_queue, (void *)&msg_data, g_msg_rev_size, 0); +} + +static void *ble_uart_client_task(const char *arg) +{ + unused(arg); + osal_printk("ble_uart_client_task entry."); + ble_uart_client_init(); + errcode_t ret = uapi_uart_register_rx_callback( + CONFIG_BLE_UART_BUS, UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE, 1, ble_uart_read_int_handler); + if (ret != ERRCODE_SUCC) { + osal_printk("Register uart callback fail."); + return NULL; + } + while (1) { + msg_data_t msg_data = {0}; + int msg_ret = osal_msg_queue_read_copy(g_mouse_msg_queue, &msg_data, &g_msg_rev_size, OSAL_WAIT_FOREVER); + if (msg_ret != OSAL_SUCCESS) { + osal_printk("msg queue read copy fail."); + if (msg_data.value != NULL) { + osal_vfree(msg_data.value); + } + continue; + } + if (msg_data.value != NULL) { + uint16_t write_handle = ble_uart_get_write_value_handle(); + ble_uart_client_write_cmd(msg_data.value, msg_data.value_len, write_handle); + osal_vfree(msg_data.value); + } + } + return NULL; +} +#endif /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */ + +static void ble_uart_entry(void) +{ + int msg_ret = osal_msg_queue_create("task_msg", g_msg_rev_size, &g_mouse_msg_queue, 0, g_msg_rev_size); + if (msg_ret != OSAL_SUCCESS) { + osal_printk("msg queue create fail."); + return; + } + osal_task *task_handle = NULL; + osal_kthread_lock(); +#if defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_SERVER) + task_handle = osal_kthread_create((osal_kthread_handler)ble_uart_server_task, 0, "BLEUartServerTask", + BLE_UART_TASK_STACK_SIZE); +#elif defined(CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT) + task_handle = osal_kthread_create((osal_kthread_handler)ble_uart_client_task, 0, "BLEUartClientTask", + BLE_UART_TASK_STACK_SIZE); +#endif /* CONFIG_SAMPLE_SUPPORT_BLE_UART_CLIENT */ + if (task_handle != NULL) { + osal_kthread_set_priority(task_handle, BLE_UART_TASK_PRIO); + } + osal_kthread_unlock(); +} + +/* Run the ble_uart_entry. */ +app_run(ble_uart_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server.c new file mode 100644 index 0000000000000000000000000000000000000000..7e356f7a08db8ec186276ec5948f42cf53a4fada --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server.c @@ -0,0 +1,347 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE UART Server Source. \n + * + * History: \n + * 2023-07-26, Create file. \n + */ +#include "osal_addr.h" +#include "osal_debug.h" +#include "soc_osal.h" +#include "product.h" +#include "securec.h" +#include "errcode.h" +#include "uart.h" +#include "bts_def.h" +#include "bts_gatt_stru.h" +#include "bts_gatt_server.h" +#include "bts_le_gap.h" +#include "ble_uart_server_adv.h" +#include "ble_uart_server.h" + +/* uart gatt server id */ +#define BLE_UART_SERVER_ID 1 +/* uart ble connect id */ +#define BLE_SINGLE_LINK_CONNECT_ID 1 +/* octets of 16 bits uart */ +#define UART16_LEN 2 +/* invalid attribute handle */ +#define INVALID_ATT_HDL 0 +/* invalid server ID */ +#define INVALID_SERVER_ID 0 + +#define BLE_UART_SERVER_LOG "[ble uart server]" +#define BLE_UART_SERVER_ERROR "[ble uart server error]" +#define BLE_UART_SERVICE_NUM 3 +#define DELAY_MS 5000 + +static uint16_t g_ble_uart_conn_id; +static uint8_t g_ble_uart_name_value[] = {'b', 'l', 'e', '_', 'u', 'a', 'r', 't', '\0'}; +static uint8_t g_uart_server_app_uuid[] = {0x00, 0x00}; +static uint8_t g_ble_uart_server_addr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; +static uint8_t g_server_id = INVALID_SERVER_ID; +static uint8_t g_connection_state = 0; +static uint16_t g_notify_indicate_handle = 0; +static uint8_t g_service_num = 0; + +/* 将uint16的uuid数字转化为bt_uuid_t */ +static void bts_data_to_uuid_len2(uint16_t uuid_data, bt_uuid_t *out_uuid) +{ + out_uuid->uuid_len = UART16_LEN; + out_uuid->uuid[0] = (uint8_t)(uuid_data >> 8); /* 8: octet bit num */ + out_uuid->uuid[1] = (uint8_t)(uuid_data); +} + +/* 设置注册服务时的name */ +void ble_uart_set_device_name_value(const uint8_t *name, const uint8_t len) +{ + size_t len_name = sizeof(g_ble_uart_name_value); + if (memcpy_s(g_ble_uart_name_value, len_name, name, len) != EOK) { + osal_printk("%s memcpy name fail\n", BLE_UART_SERVER_ERROR); + } +} + +/* 创建服务 */ +static void ble_uart_add_service(void) +{ + bt_uuid_t uart_service_uuid = {0}; + bts_data_to_uuid_len2(BLE_UART_UUID_SERVER_SERVICE, &uart_service_uuid); + gatts_add_service(BLE_UART_SERVER_ID, &uart_service_uuid, true); +} + +/* 添加uart发送服务的所有特征和描述符 */ +static void ble_uart_add_tx_characters_and_descriptors(uint8_t server_id, uint16_t srvc_handle) +{ + osal_printk("%s TX characters:%d srv_handle:%d \n", BLE_UART_SERVER_LOG, server_id, srvc_handle); + bt_uuid_t characters_uuid = {0}; + uint8_t characters_value[] = {0x12, 0x34}; + bts_data_to_uuid_len2(BLE_UART_CHARACTERISTIC_UUID_TX, &characters_uuid); + gatts_add_chara_info_t character; + character.chara_uuid = characters_uuid; + character.properties = GATT_CHARACTER_PROPERTY_BIT_NOTIFY | GATT_CHARACTER_PROPERTY_BIT_READ; + character.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE; + character.value_len = sizeof(characters_value); + character.value = characters_value; + gatts_add_characteristic(server_id, srvc_handle, &character); + osal_printk("%s characters_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]); + + static uint8_t ccc_val[] = {0x01, 0x00}; // notify + bt_uuid_t ccc_uuid = {0}; + bts_data_to_uuid_len2(BLE_UART_CLIENT_CHARACTERISTIC_CONFIGURATION, &ccc_uuid); + gatts_add_desc_info_t descriptor; + descriptor.desc_uuid = ccc_uuid; + descriptor.permissions = + GATT_ATTRIBUTE_PERMISSION_READ | GATT_CHARACTER_PROPERTY_BIT_WRITE | GATT_ATTRIBUTE_PERMISSION_WRITE; + descriptor.value_len = sizeof(ccc_val); + descriptor.value = ccc_val; + gatts_add_descriptor(server_id, srvc_handle, &descriptor); + osal_printk("%s ccc_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]); +} + +/* 添加uart接收服务的所有特征和描述符 */ +static void ble_uart_add_rx_characters_and_descriptors(uint8_t server_id, uint16_t srvc_handle) +{ + osal_printk("%s RX characters:%d srv_handle: %d \n", BLE_UART_SERVER_LOG, server_id, srvc_handle); + bt_uuid_t characters_uuid = {0}; + uint8_t characters_value[] = {0x12, 0x34}; + bts_data_to_uuid_len2(BLE_UART_CHARACTERISTIC_UUID_RX, &characters_uuid); + gatts_add_chara_info_t character; + character.chara_uuid = characters_uuid; + character.properties = GATT_CHARACTER_PROPERTY_BIT_READ | GATT_CHARACTER_PROPERTY_BIT_WRITE_NO_RSP; + character.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE; + character.value_len = sizeof(characters_value); + character.value = characters_value; + gatts_add_characteristic(server_id, srvc_handle, &character); + osal_printk("%s characters_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]); + + bt_uuid_t ccc_uuid = {0}; + /* uart client characteristic configuration value for test */ + static uint8_t ccc_val[] = {0x00, 0x00}; + bts_data_to_uuid_len2(BLE_UART_CLIENT_CHARACTERISTIC_CONFIGURATION, &ccc_uuid); + gatts_add_desc_info_t descriptor; + descriptor.desc_uuid = ccc_uuid; + descriptor.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE; + descriptor.value_len = sizeof(ccc_val); + descriptor.value = ccc_val; + gatts_add_descriptor(server_id, srvc_handle, &descriptor); + osal_printk("%s ccc_uuid:%2x %2x\n", BLE_UART_SERVER_LOG, characters_uuid.uuid[0], characters_uuid.uuid[1]); +} + +bool bts_uart_compare_uuid(bt_uuid_t *uuid1, bt_uuid_t *uuid2) +{ + if (uuid1->uuid_len != uuid2->uuid_len) { + return false; + } + if (memcmp(uuid1->uuid, uuid2->uuid, uuid1->uuid_len) != 0) { + return false; + } + return true; +} + +/* 服务添加回调 */ +static void ble_uart_server_service_add_cbk(uint8_t server_id, bt_uuid_t *uuid, uint16_t handle, errcode_t status) +{ + osal_printk("%s add characters_and_descriptors cbk service:%d, srv_handle:%d, uuid_len:%d, status:%d, uuid:", + BLE_UART_SERVER_LOG, server_id, handle, uuid->uuid_len, status); + for (int8_t i = 0; i < uuid->uuid_len; i++) { + osal_printk("%02x ", uuid->uuid[i]); + } + osal_printk("\n"); + ble_uart_add_tx_characters_and_descriptors(server_id, handle); + ble_uart_add_rx_characters_and_descriptors(server_id, handle); + gatts_start_service(server_id, handle); +} + +/* 特征添加回调 */ +static void ble_uart_server_characteristic_add_cbk(uint8_t server_id, + bt_uuid_t *uuid, + uint16_t service_handle, + gatts_add_character_result_t *result, + errcode_t status) +{ + osal_printk("%s add character cbk service:%d service_hdl: %d char_hdl: %d char_val_hdl: %d uuid_len: %d \n", + BLE_UART_SERVER_LOG, server_id, service_handle, result->handle, result->value_handle, uuid->uuid_len); + osal_printk("uuid:"); + for (int8_t i = 0; i < uuid->uuid_len; i++) { + osal_printk("%02x ", uuid->uuid[i]); + } + bt_uuid_t characters_cbk_uuid = {0}; + bts_data_to_uuid_len2(BLE_UART_CHARACTERISTIC_UUID_TX, &characters_cbk_uuid); + characters_cbk_uuid.uuid_len = uuid->uuid_len; + if (bts_uart_compare_uuid(uuid, &characters_cbk_uuid)) { + g_notify_indicate_handle = result->value_handle; + } + osal_printk("%s status:%d indicate_handle:%d\n", BLE_UART_SERVER_LOG, status, g_notify_indicate_handle); +} + +/* 描述符添加回调 */ +static void ble_uart_server_descriptor_add_cbk(uint8_t server_id, + bt_uuid_t *uuid, + uint16_t service_handle, + uint16_t handle, + errcode_t status) +{ + osal_printk("%s service:%d service_hdl: %d desc_hdl: %d uuid_len: %d \n", BLE_UART_SERVER_LOG, server_id, + service_handle, handle, uuid->uuid_len); + osal_printk("uuid:"); + for (int8_t i = 0; i < uuid->uuid_len; i++) { + osal_printk("%02x ", (uint8_t)uuid->uuid[i]); + } + osal_printk("%s status:%d\n", BLE_UART_SERVER_LOG, status); +} + +/* 开始服务回调 */ +static void ble_uart_server_service_start_cbk(uint8_t server_id, uint16_t handle, errcode_t status) +{ + g_service_num++; + if ((g_service_num == BLE_UART_SERVICE_NUM) && (status == 0)) { + osal_printk("%s start service cbk , start adv\n", BLE_UART_SERVER_LOG); + ble_uart_set_adv_data(); + ble_uart_start_adv(); + } + osal_printk("%s start service:%2d service_hdl: %d status: %d\n", BLE_UART_SERVER_LOG, server_id, handle, status); +} + +static void ble_uart_receive_write_req_cbk(uint8_t server_id, + uint16_t conn_id, + gatts_req_write_cb_t *write_cb_para, + errcode_t status) +{ + osal_printk("%s ble uart write cbk server_id:%d, conn_id:%d, status%d\n", BLE_UART_SERVER_LOG, server_id, conn_id, + status); + osal_printk("%s ble uart write cbk len:%d, data:%s\n", BLE_UART_SERVER_LOG, write_cb_para->length, + write_cb_para->value); + if ((write_cb_para->length > 0) && write_cb_para->value) { + uapi_uart_write(CONFIG_BLE_UART_BUS, (uint8_t *)(write_cb_para->value), write_cb_para->length, 0); + } +} + +static void ble_uart_receive_read_req_cbk(uint8_t server_id, + uint16_t conn_id, + gatts_req_read_cb_t *read_cb_para, + errcode_t status) +{ + osal_printk("%s ReceiveReadReq--server_id:%d conn_id:%d\n", BLE_UART_SERVER_LOG, server_id, conn_id); + osal_printk("%s request_id:%d, att_handle:%d offset:%d, need_rsp:%d, is_long:%d\n", BLE_UART_SERVER_LOG, + read_cb_para->request_id, read_cb_para->handle, read_cb_para->offset, read_cb_para->need_rsp, + read_cb_para->is_long); + osal_printk("%s status:%d\n", BLE_UART_SERVER_LOG, status); +} + +static void ble_uart_mtu_changed_cbk(uint8_t server_id, uint16_t conn_id, uint16_t mtu_size, errcode_t status) +{ + osal_printk("%s MtuChanged--server_id:%d conn_id:%d\n", BLE_UART_SERVER_LOG, server_id, conn_id); + osal_printk("%s mtusize:%d, status:%d\n", BLE_UART_SERVER_LOG, mtu_size, status); +} + +static void ble_uart_server_adv_enable_cbk(uint8_t adv_id, adv_status_t status) +{ + osal_printk("%s adv enable cbk adv_id:%d status:%d\n", BLE_UART_SERVER_LOG, adv_id, status); +} + +static void ble_uart_server_adv_disable_cbk(uint8_t adv_id, adv_status_t status) +{ + osal_printk("%s adv disable adv_id: %d, status:%d\n", BLE_UART_SERVER_LOG, adv_id, status); +} + +void ble_uart_server_connect_change_cbk(uint16_t conn_id, + bd_addr_t *addr, + gap_ble_conn_state_t conn_state, + gap_ble_pair_state_t pair_state, + gap_ble_disc_reason_t disc_reason) +{ + g_ble_uart_conn_id = conn_id; + g_connection_state = (uint8_t)conn_state; + osal_printk("%s connect state change conn_id: %d, status: %d, pair_status:%d, addr %x disc_reason %x\n", + BLE_UART_SERVER_LOG, conn_id, conn_state, pair_state, addr[0], disc_reason); + if (conn_state == GAP_BLE_STATE_CONNECTED) { + return; + } else if (conn_state == GAP_BLE_STATE_DISCONNECTED) { + ble_uart_set_adv_data(); + ble_uart_start_adv(); + } +} +void ble_uart_server_pair_result_cb(uint16_t conn_id, const bd_addr_t *addr, errcode_t status) +{ + osal_printk("%s pair result conn_id: %d, status: %d, addr %x \n", BLE_UART_SERVER_LOG, conn_id, status, addr[0]); +} + +static errcode_t ble_uart_server_register_callbacks(void) +{ + gap_ble_callbacks_t gap_cb = {0}; + gatts_callbacks_t service_cb = {0}; + + gap_cb.start_adv_cb = ble_uart_server_adv_enable_cbk; + gap_cb.conn_state_change_cb = ble_uart_server_connect_change_cbk; + gap_cb.stop_adv_cb = ble_uart_server_adv_disable_cbk; + gap_cb.pair_result_cb = ble_uart_server_pair_result_cb; + errcode_t ret = gap_ble_register_callbacks(&gap_cb); + + service_cb.add_service_cb = ble_uart_server_service_add_cbk; + service_cb.add_characteristic_cb = ble_uart_server_characteristic_add_cbk; + service_cb.add_descriptor_cb = ble_uart_server_descriptor_add_cbk; + service_cb.start_service_cb = ble_uart_server_service_start_cbk; + service_cb.read_request_cb = ble_uart_receive_read_req_cbk; + service_cb.write_request_cb = ble_uart_receive_write_req_cbk; + service_cb.mtu_changed_cb = ble_uart_mtu_changed_cbk; + ret = gatts_register_callbacks(&service_cb); + if (ret != ERRCODE_BT_SUCCESS) { + osal_printk("%s reg service cbk failed ret = %d\n", BLE_UART_SERVER_ERROR, ret); + return ret; + } +#if (CORE_NUMS < 2) + enable_ble(); +#endif + return ret; +} + +void ble_uart_server_init(void) +{ + (void)osal_msleep(DELAY_MS); /* 延时5000ms,等待BLE初始化完毕 */ + + ble_uart_server_register_callbacks(); + enable_ble(); + + errcode_t ret = 0; + bt_uuid_t app_uuid = {0}; + bd_addr_t ble_addr = {0}; + app_uuid.uuid_len = sizeof(g_uart_server_app_uuid); + if (memcpy_s(app_uuid.uuid, app_uuid.uuid_len, g_uart_server_app_uuid, sizeof(g_uart_server_app_uuid)) != EOK) { + osal_printk("%s add server app uuid memcpy failed\n", BLE_UART_SERVER_ERROR); + return; + } + ble_addr.type = BLE_PUBLIC_DEVICE_ADDRESS; + if (memcpy_s(ble_addr.addr, BD_ADDR_LEN, g_ble_uart_server_addr, sizeof(g_ble_uart_server_addr)) != EOK) { + osal_printk("%s add server app addr memcpy failed\n", BLE_UART_SERVER_ERROR); + return; + } + gap_ble_set_local_name(g_ble_uart_name_value, sizeof(g_ble_uart_name_value)); + gap_ble_set_local_addr(&ble_addr); + ret = gatts_register_server(&app_uuid, &g_server_id); + if ((ret != ERRCODE_BT_SUCCESS) || (g_server_id == INVALID_SERVER_ID)) { + osal_printk("%s add server failed\r\n", BLE_UART_SERVER_ERROR); + return; + } + ble_uart_add_service(); /* 添加uart服务 */ + osal_printk("%s beginning add service\r\n", BLE_UART_SERVER_LOG); + bth_ota_init(); +} + +/* device向host发送数据:input report */ +errcode_t ble_uart_server_send_input_report(uint8_t *data, uint16_t len) +{ + gatts_ntf_ind_t param = {0}; + uint16_t conn_id = g_ble_uart_conn_id; + param.attr_handle = g_notify_indicate_handle; + param.value_len = len; + param.value = data; + osal_printk("%s send input report indicate_handle:%d\n", BLE_UART_SERVER_LOG, g_notify_indicate_handle); + gatts_notify_indicate(BLE_UART_SERVER_ID, conn_id, ¶m); + return ERRCODE_BT_SUCCESS; +} + +uint8_t ble_uart_get_connection_state(void) +{ + return g_connection_state; +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server.h new file mode 100644 index 0000000000000000000000000000000000000000..11b7fbd1437388f59b90643c304cb11f6fa86b5b --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE uart server Config. \n + * + * History: \n + * 2023-07-26, Create file. \n + */ +#ifndef BLE_UART_SERVER_H +#define BLE_UART_SERVER_H + +#include +#include "errcode.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/* Service UUID */ +#define BLE_UART_UUID_SERVER_SERVICE 0xABCD +/* Characteristic UUID */ +#define BLE_UART_CHARACTERISTIC_UUID_TX 0xCDEF +/* Characteristic UUID */ +#define BLE_UART_CHARACTERISTIC_UUID_RX 0xEFEF +/* Client Characteristic Configuration UUID */ +#define BLE_UART_CLIENT_CHARACTERISTIC_CONFIGURATION 0x2902 + +void ble_uart_set_device_name_value(const uint8_t *name, const uint8_t len); +void ble_uart_set_device_appearance_value(uint16_t appearance); +void ble_uart_server_init(void); +errcode_t ble_uart_server_send_input_report(uint8_t *data, uint16_t len); +uint8_t ble_uart_get_connection_state(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server_adv.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server_adv.c new file mode 100644 index 0000000000000000000000000000000000000000..b627676fc8e8f31ff4ad3b7f31599a6852307915 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server_adv.c @@ -0,0 +1,257 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE UART Server adv Source. \n + * + * History: \n + * 2023-07-26, Create file. \n + */ +#include "osal_addr.h" +#include "securec.h" +#include "errcode.h" +#include "osal_debug.h" +#include "bts_def.h" +#include "bts_le_gap.h" +#include "ble_uart_server_adv.h" + +/* Ble Adv type Flag length */ +#define BLE_ADV_FLAG_LEN 0x03 +/* Ble Adv data length */ +#define BLE_GENERAL_BYTE_1 1 +/* Ble Adv appearance length */ +#define BLE_ADV_APPEARANCE_LENGTH 4 +/* Ble Adv appearance type */ +#define BLE_ADV_APPEARANCE_DATA_TYPE 0x19 +/* Ble uart appearance type */ +#define BLE_ADV_CATEGORY_UART_VALUE 0x0080 +/* Ble uart categorylength */ +#define BLE_ADV_CATEGORY_LEN 2 +/* Ble name adv param type length */ +#define BLE_ADV_PARAM_DATATYPE_LENGTH 1 +/* Ble name adv name type */ +#define BLE_ADV_LOCAL_NAME_DATA_TYPE 0x09 +/* Ble name adv tx power type */ +#define BLE_ADV_TX_POWER_LEVEL 0x0A +/* Ble name adv tx power response type */ +#define BLE_SCAN_RSP_TX_POWER_LEVEL_LEN 0x03 +/* Ble adv flag data */ +#define BLE_ADV_FLAG_DATA 0x05 + +/* Ble adv min interval */ +#define BLE_ADV_MIN_INTERVAL 0x30 +/* Ble adv max interval */ +#define BLE_ADV_MAX_INTERVAL 0x60 +/* Ble adv handle */ +#define BTH_GAP_BLE_ADV_HANDLE_DEFAULT 0x01 +/* Ble adv duration */ +#define BTH_GAP_BLE_ADV_FOREVER_DURATION 0 + +#define MAX_NAME_LENGTH 15 +#define EXT_ADV_OR_SCAN_RSP_DATA_LEN 251 +#define ADV_APPEA_CATOGORY_HIGH 8 + +#define BLE_UART_ADV_LOG "[ble uart adv]" + +typedef enum ble_adv_filter_policy { + BLE_ADV_FILTER_POLICY_SCAN_ANY_CONNECT_ANY = 0x00, + BLE_ADV_FILTER_POLICY_SCAN_WHITE_LIST_CONNECT_ANY = 0x01, + BLE_ADV_FILTER_POLICY_SCAN_ANY_CONNECT_WHITE_LIST = 0x02, + BLE_ADV_FILTER_POLICY_SCAN_WHITE_LIST_CONNECT_WHITE_LIST = 0x03 +} ble_adv_filter_policy_t; + +typedef enum ble_adverting_type { + BLE_ADV_TYPE_CONNECTABLE_UNDIRECTED = 0x00, + BLE_ADV_TYPE_CONNECTABLE_HIGH_DUTY_CYCLE_DIRECTED = 0x01, + BLE_ADV_TYPE_SCANNABLE_UNDIRECTED = 0x02, + BLE_ADV_TYPE_NON_CONNECTABLE_UNDIRECTED = 0x03, + BLE_ADV_TYPE_CONNECTABLE_LOW_DUTY_CYCLE_DIRECTED = 0x04 +} ble_adverting_type_t; + +typedef enum ble_adv_channel_map { + BLE_ADV_CHANNEL_MAP_CH_37 = 0x01, + BLE_ADV_CHANNEL_MAP_CH_38 = 0x02, + BLE_ADV_CHANNEL_MAP_CH_39 = 0x04, + BLE_ADV_CHANNEL_MAP_CH_37_CH_38 = 0x03, + BLE_ADV_CHANNEL_MAP_CH_37_CH_39 = 0x05, + BLE_ADV_CHANNEL_MAP_CH_38_CH_39 = 0x06, + BLE_ADV_CHANNEL_MAP_CH_DEFAULT = 0x07 +} ble_adv_channel_map_t; + +typedef struct { + uint8_t length; /* 广播数据类型长度 */ + uint8_t adv_data_type; /* 广播数据类型 */ + uint8_t flags; /* 广播数据标志 */ +} ble_adv_flag; + +typedef struct { + uint8_t length; /* 设备外观数据类型长度 */ + uint8_t adv_data_type; /* 设备外观数据类型 */ + uint8_t catogory_id[BLE_ADV_CATEGORY_LEN]; /* 设备外观数据 */ +} ble_appearance_t; + +typedef struct { + uint8_t length; /* 广播设备名称类型长度 */ + uint8_t adv_data_type; /* 设备名称类型 */ + int8_t *name; /* 设备名称数据指针 */ +} ble_local_name_t; + +typedef struct { + uint8_t length; /* 广播发送功率长度 */ + uint8_t adv_data_type; /* 广播发送数据类型 */ + uint8_t tx_power_value; /* 广播发送数据 */ +} ble_tx_power_level_t; + +uint8_t g_uart_local_name[MAX_NAME_LENGTH] = {'b', 'l', 'e', '_', 'u', 'a', 'r', 't', + '_', 's', 'e', 'r', 'v', 'e', 'r'}; + +static inline uint8_t u16_low_u8(uint16_t val) +{ + return (uint8_t)((uint16_t)(val) & 0xff); +} + +static inline uint8_t u16_high_u8(uint16_t val) +{ + return (uint8_t)(((uint16_t)(val) >> ADV_APPEA_CATOGORY_HIGH) & 0xff); +} + +static uint8_t ble_set_adv_flag_data(uint8_t *set_adv_data_position, uint8_t max_len) +{ + ble_adv_flag adv_flags = { + .length = BLE_ADV_FLAG_LEN - BLE_GENERAL_BYTE_1, .adv_data_type = 1, .flags = BLE_ADV_FLAG_DATA}; + if (memcpy_s(set_adv_data_position, max_len, &adv_flags, BLE_ADV_FLAG_LEN) != EOK) { + return 0; + } + return BLE_ADV_FLAG_LEN; +} + +static uint8_t ble_set_adv_appearance(uint8_t *set_adv_data_position, uint8_t max_len) +{ + ble_appearance_t adv_appearance_data = { + .length = BLE_ADV_APPEARANCE_LENGTH - BLE_GENERAL_BYTE_1, + .adv_data_type = BLE_ADV_APPEARANCE_DATA_TYPE, + .catogory_id = {u16_low_u8(BLE_ADV_CATEGORY_UART_VALUE), u16_high_u8(BLE_ADV_CATEGORY_UART_VALUE)}}; + if (memcpy_s(set_adv_data_position, max_len, &adv_appearance_data, BLE_ADV_APPEARANCE_LENGTH) != EOK) { + return 0; + } + return BLE_ADV_APPEARANCE_LENGTH; +} + +static uint8_t ble_set_adv_name(uint8_t *set_adv_data_position, uint8_t max_len) +{ + uint8_t len = BLE_ADV_PARAM_DATATYPE_LENGTH + BLE_ADV_PARAM_DATATYPE_LENGTH; + ble_local_name_t adv_local_name_data = {.length = + (uint8_t)(BLE_ADV_PARAM_DATATYPE_LENGTH + sizeof(g_uart_local_name)), + .adv_data_type = BLE_ADV_LOCAL_NAME_DATA_TYPE}; + + if (memcpy_s(set_adv_data_position, max_len, &adv_local_name_data, len) != EOK) { + return 0; + } + if (memcpy_s((set_adv_data_position + len), (size_t)(max_len - len), g_uart_local_name, + sizeof(g_uart_local_name)) != EOK) { + return 0; + } + len = (uint8_t)(len + sizeof(g_uart_local_name)); + return len; +} + +static uint8_t ble_set_adv_appearance_data(uint8_t *set_adv_data_position, uint8_t max_len) +{ + uint8_t idx = 0; + + idx += ble_set_adv_appearance(set_adv_data_position, max_len); + idx += ble_set_adv_name(set_adv_data_position + idx, (max_len - idx)); + return idx; +} + +static uint16_t ble_uart_server_set_adv_data(uint8_t *set_adv_data, uint8_t adv_data_max_len) +{ + uint8_t idx = 0; + + if ((set_adv_data == NULL) || (adv_data_max_len == 0)) { + return 0; + } + + idx += ble_set_adv_flag_data(set_adv_data, adv_data_max_len); + idx += ble_set_adv_appearance_data(&set_adv_data[idx], adv_data_max_len - idx); + return idx; +} + +static uint16_t ble_set_scan_response_data(uint8_t *scan_rsp_data, uint8_t scan_rsp_data_max_len) +{ + uint8_t idx = 0; + + if (scan_rsp_data == NULL || scan_rsp_data_max_len == 0) { + return 0; + } + + /* tx power level */ + ble_tx_power_level_t tx_power_level = {.length = BLE_SCAN_RSP_TX_POWER_LEVEL_LEN - BLE_GENERAL_BYTE_1, + .adv_data_type = BLE_ADV_TX_POWER_LEVEL, + .tx_power_value = 0}; + + if (memcpy_s(scan_rsp_data, scan_rsp_data_max_len, &tx_power_level, sizeof(ble_tx_power_level_t)) != EOK) { + return 0; + } + + idx += BLE_SCAN_RSP_TX_POWER_LEVEL_LEN; + + /* set local name */ + scan_rsp_data[idx++] = sizeof(g_uart_local_name) + BLE_GENERAL_BYTE_1; + scan_rsp_data[idx++] = BLE_ADV_LOCAL_NAME_DATA_TYPE; + if ((idx + sizeof(g_uart_local_name)) > scan_rsp_data_max_len) { + return 0; + } + if (memcpy_s(&scan_rsp_data[idx], scan_rsp_data_max_len - idx, g_uart_local_name, sizeof(g_uart_local_name)) != + EOK) { + return 0; + } + idx += sizeof(g_uart_local_name); + return idx; +} + +uint8_t ble_uart_set_adv_data(void) +{ + uint8_t set_adv_data[EXT_ADV_OR_SCAN_RSP_DATA_LEN] = {0}; + uint8_t set_scan_rsp_data[EXT_ADV_OR_SCAN_RSP_DATA_LEN] = {0}; + gap_ble_config_adv_data_t cfg_adv_data; + + /* set adv data */ + uint16_t adv_data_len = ble_uart_server_set_adv_data(set_adv_data, EXT_ADV_OR_SCAN_RSP_DATA_LEN); + if ((adv_data_len > EXT_ADV_OR_SCAN_RSP_DATA_LEN) || (adv_data_len == 0)) { + return 0; + } + /* set scan response data */ + uint16_t scan_rsp_data_len = ble_set_scan_response_data(set_scan_rsp_data, EXT_ADV_OR_SCAN_RSP_DATA_LEN); + if ((scan_rsp_data_len > EXT_ADV_OR_SCAN_RSP_DATA_LEN) || (scan_rsp_data_len == 0)) { + return 0; + } + cfg_adv_data.adv_data = set_adv_data; + cfg_adv_data.adv_length = adv_data_len; + + cfg_adv_data.scan_rsp_data = set_scan_rsp_data; + cfg_adv_data.scan_rsp_length = scan_rsp_data_len; + osal_printk("%s ble_uart_set_adv_data adv_handle %d, len:%d, data:%s\n", BLE_UART_ADV_LOG, + BTH_GAP_BLE_ADV_HANDLE_DEFAULT, adv_data_len, set_adv_data); + return gap_ble_set_adv_data(BTH_GAP_BLE_ADV_HANDLE_DEFAULT, &cfg_adv_data); +} + +uint8_t ble_uart_start_adv(void) +{ + errcode_t ret = ERRCODE_BT_SUCCESS; + int adv_id = BTH_GAP_BLE_ADV_HANDLE_DEFAULT; + + gap_ble_adv_params_t adv_para = {.min_interval = BLE_ADV_MIN_INTERVAL, + .max_interval = BLE_ADV_MAX_INTERVAL, + .duration = BTH_GAP_BLE_ADV_FOREVER_DURATION, + .peer_addr.type = BLE_PUBLIC_DEVICE_ADDRESS, + /* 广播通道选择bitMap, 可参考BleAdvChannelMap */ + .channel_map = BLE_ADV_CHANNEL_MAP_CH_DEFAULT, + .adv_type = BLE_ADV_TYPE_CONNECTABLE_UNDIRECTED, + .adv_filter_policy = BLE_ADV_FILTER_POLICY_SCAN_ANY_CONNECT_ANY}; + + (void)memset_s(&adv_para.peer_addr.addr, BD_ADDR_LEN, 0, BD_ADDR_LEN); + osal_printk("%s ble_uart_start_adv adv_id %d\n", BLE_UART_ADV_LOG, adv_id); + ret |= gap_ble_set_adv_param(adv_id, &adv_para); + ret |= gap_ble_start_adv(adv_id); + return ret; +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server_adv.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server_adv.h new file mode 100644 index 0000000000000000000000000000000000000000..6d993993568e558fa31002fbb04e46ce3e6e1c53 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/ble_uart_server/ble_uart_server_adv.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: BLE UART Server adv config. \n + * + * History: \n + * 2023-07-26, Create file. \n + */ + +#ifndef BLE_UART_SERVER_ADV_H +#define BLE_UART_SERVER_ADV_H + +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef enum { + BLE_PUBLIC_DEVICE_ADDRESS, + BLE_RANDOM_DEVICE_ADDRESS, + BLE_PUBLIC_IDENTITY_ADDRESS, + BLE_RANDOM_STATIC_IDENTITY_ADDRESS +} ble_address_t; + +uint8_t ble_uart_set_adv_data(void); +uint8_t ble_uart_start_adv(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/images/bleuart_img1.PNG b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/images/bleuart_img1.PNG new file mode 100644 index 0000000000000000000000000000000000000000..47c7a9a591f7eca729c24ee81a981385a6fd1e2b Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/images/bleuart_img1.PNG differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/images/bleuart_img2.PNG b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/images/bleuart_img2.PNG new file mode 100644 index 0000000000000000000000000000000000000000..b006bb030ce968bdc8d8d6aaa9c8b0d024dd3ae3 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/images/bleuart_img2.PNG differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..d9d375ac425b67f35d5e360bbf64f797563e1972 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ble_uart/readme.md @@ -0,0 +1,21 @@ +# beetle_ble_uart + +## 一、介绍 + +本例程演示了如何使用两块开发板通过BLE进行双向数据传输: + +- 开发板A(Server端)和开发板B(Client端)配对连接 +- A板:串口接收数据 → BLE发送 → B板:BLE接收 → 串口打印 +- B板:串口接收数据 → BLE发送 → A板:BLE接收 → 串口打印 + +## 二、实验流程 + +打开kconfig勾选beetle_demo例程中的BLE_UART示例,准备两块WS63开发板A和B,A烧录BLE_Server示例,B烧录BLE_Client示例: + +![img](.\images\bleuart_img1.PNG) + +烧录完成后,启动两个串口助手分别连接到A和B,测试AB互发消息: + +![img](.\images\bleuart_img2.PNG) + +然后交换AB固件烧录,再次观察打印。 diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d1b17bc39683d300d88355779791d2faf0910ef8 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/CMakeLists.txt @@ -0,0 +1,17 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_bme680/bme680.c + ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_bme680/dfrobot_bme680.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_bme680) + + +if(DEFINED CONFIG_SAMPLE_SUPPORT_BME680_I2C_SAMPLE) + add_subdirectory_if_exist(bme680_i2c_sample) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_BME680_SPI_SAMPLE) + add_subdirectory_if_exist(bme680_spi_sample) +endif() + +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" ${HEADER_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..45ee379d1c0b44451282b1d739885725f8d08673 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/Kconfig @@ -0,0 +1,70 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +choice + prompt "Select BME680_I2C or BME680_SPI Sample" + default SAMPLE_SUPPORT_BME680_I2C_SAMPLE + config SAMPLE_SUPPORT_BME680_I2C_SAMPLE + bool "Support BME680_I2C Sample." + + config SAMPLE_SUPPORT_BME680_SPI_SAMPLE + bool "Support BME680_SPI Sample." + +endchoice + +config I2C_MASTER_BUS_ID + int "Choose I2C bus id." + default 1 + depends on SAMPLE_SUPPORT_BME680_I2C_SAMPLE + +config I2C_SCL_MASTER_PIN + int "Choose I2C SCL pin" + default 16 + depends on SAMPLE_SUPPORT_BME680_I2C_SAMPLE + +config I2C_SDA_MASTER_PIN + int "Choose I2C SDA pin" + default 15 + depends on SAMPLE_SUPPORT_BME680_I2C_SAMPLE + +config I2C_SLAVE_ADDR + int "Choose I2C ADDR" + default 0x77 + depends on SAMPLE_SUPPORT_BME680_I2C_SAMPLE + +config CALIBRATE_PRESSURE + bool "enable CALIBRATE_PRESSURE." + default y + depends on SAMPLE_SUPPORT_BME680_I2C_SAMPLE + + +config SPI_MASTER_BUS_ID + int "Choose SPI bus id." + default 0 + depends on SAMPLE_SUPPORT_BME680_SPI_SAMPLE + +config SPI_CLK_MASTER_PIN + int "Choose SPI CLK pin." + default 7 + depends on SAMPLE_SUPPORT_BME680_SPI_SAMPLE + +config SPI_DO_MASTER_PIN + int "Choose SPI MOSI pin." + default 9 + depends on SAMPLE_SUPPORT_BME680_SPI_SAMPLE + +config SPI_DI_MASTER_PIN + int "Choose SPI MISO pin." + default 11 + depends on SAMPLE_SUPPORT_BME680_SPI_SAMPLE + +config SPI_CS_MASTER_PIN + int "Choose SPI CS pin." + default 10 + depends on SAMPLE_SUPPORT_BME680_SPI_SAMPLE + +config CALIBRATE_PRESSURE + bool "enable CALIBRATE_PRESSURE." + default y + depends on SAMPLE_SUPPORT_BME680_SPI_SAMPLE \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5781e38926667f9523c61b989b9b14e4e2709e36 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/CMakeLists.txt @@ -0,0 +1,6 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_bme680_i2c.c + ${CMAKE_CURRENT_SOURCE_DIR}/bme680_i2c_sample.c +) +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/bme680_i2c_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/bme680_i2c_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..77e3a3b0cb2893c905c54a762ee4cebda6a4b22c --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/bme680_i2c_sample.c @@ -0,0 +1,86 @@ +/*! + * @file bme680_i2c_sample.c + * @brief connect bme680 I2C interface with your board (please reference board compatibility) + * @n Temprature, Humidity, pressure, altitude, calibrate altitude and gas resistance data will print on serial window. + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#include "dfrobot_bme680_i2c.h" + +#define I2C_TASK_PRIO 24 +#define I2C_TASK_STACK_SIZE 0x1000 +#define DELAY_S 1000 +#define TEMP_RAW_TO_CELSIUS 100 +#define HUMIDITY_RAW_TO_PERCENT 1000 +#define BME680_BEGIN_DELAY_MS (DELAY_S * 2) + +float g_sea_level; + +void bme680_task(void) +{ + dfrobot_bme680_i2c_init(CONFIG_I2C_SLAVE_ADDR, CONFIG_I2C_SCL_MASTER_PIN, CONFIG_I2C_SDA_MASTER_PIN, + CONFIG_I2C_MASTER_BUS_ID); + + while (bme680_bme680_begin() != 0) { + uapi_watchdog_kick(); + printf("bme begin failure\r\n"); + uapi_systick_delay_ms(BME680_BEGIN_DELAY_MS); + } + printf("bme begin successful\r\n"); + static char templine[64] = {0}; +#ifdef CONFIG_CALIBRATE_PRESSURE + start_convert(); + uapi_systick_delay_ms(DELAY_S); + bme680_bme680_update(); + /* You can use an accurate altitude to calibrate sea level air pressure. + * And then use this calibrated sea level pressure as a reference to obtain the calibrated altitude. + * In this case,525.0m is chendu accurate altitude. + */ + g_sea_level = read_sea_level(525.0); + sprintf(templine, "seaLevel: %.2f\r\n", g_sea_level); + printf(templine); +#endif + + while (1) { + uapi_watchdog_kick(); + start_convert(); + uapi_systick_delay_ms(DELAY_S); + bme680_bme680_update(); + sprintf(templine, "temperature(C) : %.2f\r\n", read_temperature() / TEMP_RAW_TO_CELSIUS); + printf(templine); + sprintf(templine, "pressure(Pa) : %.2f\r\n", read_pressure()); + printf(templine); + sprintf(templine, "humidity(rh) : %.2f\r\n", read_humidity() / HUMIDITY_RAW_TO_PERCENT); + printf(templine); + sprintf(templine, "gas resistance(ohm) : %.2f\r\n", read_gas_resistance()); + printf(templine); + sprintf(templine, "altitude(m) : %.2f\r\n", read_altitude()); + printf(templine); +#ifdef CONFIG_CALIBRATE_PRESSURE + sprintf(templine, "calibrated altitude(m) : %.2f\r\n", read_calibrated_altitude(g_sea_level)); + printf(templine); +#endif + } +} + +void bme680_entry(void) +{ + uint32_t ret; + osal_task *taskid; + // 创建任务调度 + osal_kthread_lock(); + // 创建任务1 + taskid = osal_kthread_create((osal_kthread_handler)bme680_task, NULL, "bme680_task", I2C_TASK_STACK_SIZE); + ret = osal_kthread_set_priority(taskid, I2C_TASK_PRIO); + if (ret != OSAL_SUCCESS) { + printf("create task1 failed .\n"); + } + osal_kthread_unlock(); +} +app_run(bme680_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/dfrobot_bme680_i2c.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/dfrobot_bme680_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..9372fd508176f4435949aab218946cc978c530de --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/dfrobot_bme680_i2c.c @@ -0,0 +1,86 @@ +/** + * @file dfrobot_bme680_i2c.c + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#include "dfrobot_bme680_i2c.h" + +#define I2C_MASTER_ADDR 0x0 +#define I2C_SET_BAUDRATE 400000 +#define I2C_MASTER_PIN_MODE 2 + +uint8_t g_iic_bus_id; + +static int8_t bme680_i2c_read(uint8_t dev_id, uint8_t reg, uint8_t *p_buf, uint16_t size) +{ + UNUSED(dev_id); + + if (p_buf == NULL) { + osal_printk("p_buf ERROR!! : null pointer\n"); + return 0; + } + + i2c_data_t data = {0}; + data.send_buf = ® + data.send_len = 1; // 先发寄存器地址 + data.receive_buf = p_buf; + data.receive_len = size; // 再收数据 + + if (uapi_i2c_master_write(g_iic_bus_id, g_bme680_i2c_addr, &data) != ERRCODE_SUCC) { + osal_printk("I2C readReg send error!\n"); + return 0; + } + + if (uapi_i2c_master_read(g_iic_bus_id, g_bme680_i2c_addr, &data) != ERRCODE_SUCC) { + osal_printk("I2C readReg recv error!\n"); + return 0; + } + + return 0; +} + +static int8_t bme680_i2c_write(uint8_t dev_id, uint8_t reg, uint8_t *p_buf, uint16_t size) +{ + UNUSED(dev_id); + + if (p_buf == NULL) { + osal_printk("p_buf ERROR!! : null pointer\n"); + return 0; + } + + // 拼接寄存器地址 + 数据 + uint8_t buf[1 + size]; + buf[0] = reg; + memcpy(&buf[1], p_buf, size); + + i2c_data_t data = {0}; + data.send_buf = buf; + data.send_len = 1 + size; + data.receive_buf = NULL; + data.receive_len = 0; + + if (uapi_i2c_master_write(g_iic_bus_id, g_bme680_i2c_addr, &data) != ERRCODE_SUCC) { + osal_printk("I2C writeReg error!\n"); + } + + return 0; +} + +void dfrobot_bme680_i2c_init(uint8_t I2CAddr_, + uint8_t iic_scl_master_pin, + uint8_t iic_sda_master_pin, + uint8_t iic_bus_id) +{ + dfrobot_bme680(bme680_i2c_read, bme680_i2c_write, bme680_delay_ms, BME680_INTERFACE_I2C); + g_bme680_i2c_addr = I2CAddr_; + g_iic_bus_id = iic_bus_id; + uapi_pin_set_mode(iic_scl_master_pin, I2C_MASTER_PIN_MODE); + uapi_pin_set_mode(iic_sda_master_pin, I2C_MASTER_PIN_MODE); + uapi_i2c_master_init(g_iic_bus_id, I2C_SET_BAUDRATE, I2C_MASTER_ADDR); +} diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/dfrobot_bme680_i2c.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/dfrobot_bme680_i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..18a2f14de7fbe0bf63afbb2f43e5cb71076033a1 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_i2c_sample/dfrobot_bme680_i2c.h @@ -0,0 +1,23 @@ +/** + * @file dfrobot_bme680_i2c.h + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#ifndef DFROBOT_BME680_I2C_H +#define DFROBOT_BME680_I2C_H + +#include "dfrobot_bme680.h" +#include "i2c.h" + +void dfrobot_bme680_i2c_init(uint8_t I2CAddr, + uint8_t iic_scl_master_pin, + uint8_t iic_sda_master_pin, + uint8_t iic_bus_id); + +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4374d65e321cebc3d6aa891195d51ab9bbf9daef --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/CMakeLists.txt @@ -0,0 +1,6 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_bme680_spi.c + ${CMAKE_CURRENT_SOURCE_DIR}/bme680_spi_sample.c +) +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/bme680_spi_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/bme680_spi_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..83af90bab329ccd22c59c095ae20a42bc24e8368 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/bme680_spi_sample.c @@ -0,0 +1,88 @@ +/*! + * @file bme680_spi_sample.c + * @brief Connect bme680 4 wires SPI interface with your board (please reference board compatibility). + * @n Temprature, Humidity, pressure, altitude, calibrate altitude and gas resistance data will print on serial window. + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#include "dfrobot_bme680_spi.h" + +#define SPI_TASK_PRIO 24 +#define SPI_TASK_STACK_SIZE 0x1000 +#define DELAY_S 1000 +#define TEMP_RAW_TO_CELSIUS 100 +#define HUMIDITY_RAW_TO_PERCENT 1000 +#define BME680_BEGIN_DELAY_MS (DELAY_S * 2) + +float g_sea_level; + +void bme680_task(void) +{ + dfrobot_bme680_spi_init(CONFIG_SPI_CS_MASTER_PIN, CONFIG_SPI_DI_MASTER_PIN, CONFIG_SPI_DO_MASTER_PIN, + CONFIG_SPI_CLK_MASTER_PIN, CONFIG_SPI_MASTER_BUS_ID); + + int16_t ret = bme680_bme680_begin(); + while (ret != 0) { + uapi_watchdog_kick(); + printf("bme begin failure ret = %d\r\n", ret); + uapi_systick_delay_ms(BME680_BEGIN_DELAY_MS); + ret = bme680_bme680_begin(); + } + printf("bme begin successful\r\n"); + static char templine[64] = {0}; +#ifdef CONFIG_CALIBRATE_PRESSURE + start_convert(); + uapi_systick_delay_ms(DELAY_S); + bme680_bme680_update(); + /* You can use an accurate altitude to calibrate sea level air pressure. + * And then use this calibrated sea level pressure as a reference to obtain the calibrated altitude. + * In this case,525.0m is chendu accurate altitude. + */ + g_sea_level = read_sea_level(525.0); + sprintf(templine, "seaLevel: %.2f\r\n", g_sea_level); + printf(templine); +#endif + + while (1) { + uapi_watchdog_kick(); + start_convert(); + uapi_systick_delay_ms(DELAY_S); + bme680_bme680_update(); + sprintf(templine, "temperature(C) : %.2f\r\n", read_temperature() / TEMP_RAW_TO_CELSIUS); + printf(templine); + sprintf(templine, "pressure(Pa) : %.2f\r\n", read_pressure()); + printf(templine); + sprintf(templine, "humidity(rh) : %.2f\r\n", read_humidity() / HUMIDITY_RAW_TO_PERCENT); + printf(templine); + sprintf(templine, "gas resistance(ohm) : %.2f\r\n", read_gas_resistance()); + printf(templine); + sprintf(templine, "altitude(m) : %.2f\r\n", read_altitude()); + printf(templine); +#ifdef CONFIG_CALIBRATE_PRESSURE + sprintf(templine, "calibrated altitude(m) : %.2f\r\n", read_calibrated_altitude(g_sea_level)); + printf(templine); +#endif + } +} + +void bme680_entry(void) +{ + uint32_t ret; + osal_task *taskid; + // 创建任务调度 + osal_kthread_lock(); + // 创建任务1 + taskid = osal_kthread_create((osal_kthread_handler)bme680_task, NULL, "bme680_task", SPI_TASK_STACK_SIZE); + ret = osal_kthread_set_priority(taskid, SPI_TASK_PRIO); + if (ret != OSAL_SUCCESS) { + printf("create task1 failed .\n"); + } + osal_kthread_unlock(); +} +app_run(bme680_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/dfrobot_bme680_spi.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/dfrobot_bme680_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..86a27dfec6f8ea64245c16f471d5f384611f8d7e --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/dfrobot_bme680_spi.c @@ -0,0 +1,155 @@ +/** + * @file dfrobot_bme680_spi.c + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ +#include "dfrobot_bme680_spi.h" + +#define SPI_SLAVE_NUM 1 +#define SPI_FREQUENCY 1 +#define SPI_CLK_POLARITY 0 +#define SPI_CLK_PHASE 0 +#define SPI_FRAME_FORMAT 0 +#define SPI_FRAME_FORMAT_STANDARD 0 +#define SPI_FRAME_SIZE_8 HAL_SPI_FRAME_SIZE_8 +#define SPI_TMOD 0 +#define SPI_WAIT_CYCLES 0x10 + +#define BME680_SPI_TIMEOUT 0xFFFFFFFF +#define BME680_MAX_TRANSFER_LEN 1 +#define SPI_MASTER_PIN_MODE 3 + +uint8_t g_spi_bus_id; +static uint8_t g_bme680_cs_pin; + +static void bme680_cs_low(void) +{ + uapi_gpio_set_val(g_bme680_cs_pin, GPIO_LEVEL_LOW); // CS低电平有效 +} + +static void bme680_cs_high(void) +{ + uapi_gpio_set_val(g_bme680_cs_pin, GPIO_LEVEL_HIGH); +} + +static int8_t bme680_spi_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) +{ + UNUSED(dev_id); + errcode_t ret; + uint8_t tx; + uint8_t rx; + + /* 相当于 SPI.beginTransaction */ + bme680_cs_low(); + + /* 先发寄存器地址(读操作最高位=1) */ + tx = reg_addr | 0x80; + rx = 0; + spi_xfer_data_t xfer_addr = { + .tx_buff = &tx, .tx_bytes = BME680_MAX_TRANSFER_LEN, .rx_buff = &rx, .rx_bytes = BME680_MAX_TRANSFER_LEN}; + ret = uapi_spi_master_writeread(g_spi_bus_id, &xfer_addr, BME680_SPI_TIMEOUT); + if (ret != ERRCODE_SUCC) { + bme680_cs_high(); + return -1; + } + + /* 循环逐字节读取数据 */ + while (len--) { + tx = 0x00; /* dummy data */ + rx = 0; + spi_xfer_data_t xfer_data = { + .tx_buff = &tx, .tx_bytes = BME680_MAX_TRANSFER_LEN, .rx_buff = &rx, .rx_bytes = BME680_MAX_TRANSFER_LEN}; + ret = uapi_spi_master_writeread(g_spi_bus_id, &xfer_data, BME680_SPI_TIMEOUT); + if (ret != ERRCODE_SUCC) { + bme680_cs_high(); + return -1; + } + *data++ = rx; + } + + bme680_cs_high(); + /* 相当于 SPI.endTransaction */ + return BME680_OK; +} + +static int8_t bme680_spi_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) +{ + UNUSED(dev_id); + errcode_t ret; + uint8_t tx; + uint8_t rx; + + bme680_cs_low(); + + /* 先发寄存器地址(写操作最高位=0) */ + tx = reg_addr & 0x7F; + rx = 0; + spi_xfer_data_t xfer_addr = { + .tx_buff = &tx, .tx_bytes = BME680_MAX_TRANSFER_LEN, .rx_buff = &rx, .rx_bytes = BME680_MAX_TRANSFER_LEN}; + ret = uapi_spi_master_writeread(g_spi_bus_id, &xfer_addr, BME680_SPI_TIMEOUT); + if (ret != ERRCODE_SUCC) { + bme680_cs_high(); + return -1; + } + + /* 循环逐字节写数据 */ + while (len--) { + tx = *data++; + rx = 0; + spi_xfer_data_t xfer_data = { + .tx_buff = &tx, .tx_bytes = BME680_MAX_TRANSFER_LEN, .rx_buff = &rx, .rx_bytes = BME680_MAX_TRANSFER_LEN}; + ret = uapi_spi_master_writeread(g_spi_bus_id, &xfer_data, BME680_SPI_TIMEOUT); + if (ret != ERRCODE_SUCC) { + bme680_cs_high(); + return -1; + } + } + + bme680_cs_high(); + return BME680_OK; +} + +/* ---------------- BME680 SPI 初始化 ---------------- */ +void dfrobot_bme680_spi_init(uint8_t pin_cs, uint8_t pin_miso, uint8_t pin_mosi, uint8_t pin_clk, uint8_t spi_bus_id) +{ + g_bme680_cs_pin = pin_cs; + + g_spi_bus_id = spi_bus_id; + + uapi_pin_set_mode(pin_miso, SPI_MASTER_PIN_MODE); + uapi_pin_set_mode(pin_mosi, SPI_MASTER_PIN_MODE); + uapi_pin_set_mode(pin_clk, SPI_MASTER_PIN_MODE); + + uapi_pin_set_mode(pin_cs, HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(pin_cs, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(pin_cs, GPIO_LEVEL_HIGH); + + spi_attr_t config = {0}; + spi_extra_attr_t ext_config = {0}; + + config.is_slave = false; + config.slave_num = SPI_SLAVE_NUM; + config.bus_clk = SPI_CLK_FREQ; + config.freq_mhz = SPI_FREQUENCY; + config.clk_polarity = SPI_CLK_POLARITY; + config.clk_phase = SPI_CLK_PHASE; + config.frame_format = SPI_FRAME_FORMAT; + config.spi_frame_format = HAL_SPI_FRAME_FORMAT_STANDARD; + config.frame_size = SPI_FRAME_SIZE_8; + config.tmod = SPI_TMOD; + config.sste = 1; + + ext_config.qspi_param.wait_cycles = SPI_WAIT_CYCLES; + + int ret = uapi_spi_init(g_spi_bus_id, &config, &ext_config); + if (ret != 0) { + printf("spi init fail %0x\r\n", ret); + } + + dfrobot_bme680(bme680_spi_read, bme680_spi_write, bme680_delay_ms, BME680_INTERFACE_SPI); +} diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/dfrobot_bme680_spi.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/dfrobot_bme680_spi.h new file mode 100644 index 0000000000000000000000000000000000000000..9539a84ccf277ec853af5c724653d95593e02fea --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/bme680_spi_sample/dfrobot_bme680_spi.h @@ -0,0 +1,20 @@ +/** + * @file dfrobot_bme680_spi.h + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#ifndef DFROBOT_BME680_SPI_H +#define DFROBOT_BME680_SPI_H + +#include "dfrobot_bme680.h" +#include "spi.h" + +void dfrobot_bme680_spi_init(uint8_t pin_cs, uint8_t pin_miso, uint8_t pin_mosi, uint8_t pin_clk, uint8_t spi_bus_id); + +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680.c new file mode 100644 index 0000000000000000000000000000000000000000..b81ea56e831d088515fab85f2dde12b88200370b --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680.c @@ -0,0 +1,1314 @@ +/** + * @file bme680.c + * @brief Sensor driver for BME680 sensor. + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#include "bme680.h" + +/** Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t get_calib_data(struct bme680_dev *dev); +static void parse_temp_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev); +static void parse_pressure_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev); +static void parse_humidity_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev); +static void parse_gas_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev); +static int8_t parse_other_coefficients(struct bme680_dev *dev); +static int8_t interleave_reg_data(const uint8_t *reg_addr, + const uint8_t *reg_data, + uint8_t len, + uint8_t *tmp_buff, + struct bme680_dev *dev); + +/** + * @fn set_gas_config + * @brief This internal API is used to set the gas configuration of the sensor. + * + * @param dev :Structure instance of bme680_dev. + * + * @return Result of API execution status. + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t set_gas_config(struct bme680_dev *dev); + +/** + * @fn get_gas_config + * @brief This internal API is used to get the gas configuration of the sensor. + * @param dev :Structure instance of bme680_dev. + * @return Result of API execution status. + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t get_gas_config(struct bme680_dev *dev); + +/** + * @fn calc_heater_dur + * @brief This internal API is used to calculate the Heat duration value. + * @param dur :Value of the duration to be shared. + * @return uint8_t threshold duration after calculation. + */ +static uint8_t calc_heater_dur(uint16_t dur); + +/** + * @fn calc_temperature + * @brief This internal API is used to calculate the temperature value. + * @param temp_adc :Contains the temperature ADC value . + * @param dev :Structure instance of bme680_dev. + * @return uint32_t calculated temperature. + */ +static int16_t calc_temperature(uint32_t temp_adc, struct bme680_dev *dev); + +/** + * @fn calc_pressure + * @brief This internal API is used to calculate the pressure value. + * @param pres_adc :Contains the pressure ADC value . + * @param dev :Structure instance of bme680_dev. + * @return uint32_t calculated pressure. + */ +static uint32_t calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev); + +/** + * @fn calc_humidity + * @brief This internal API is used to calculate the humidity value. + * @param hum_adc :Contains the humidity ADC value. + * @param dev :Structure instance of bme680_dev. + * + * @return uint32_t calculated humidity. + */ +static uint32_t calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev); + +/** + * @fn calc_heater_res + * @brief This internal API is used to calculate the Heat Resistance value. + * @param temp :Contains the temporary value. + * @param dev :Structure instance of bme680_dev. + * @return uint8_t calculated heater resistance. + */ +static uint8_t calc_heater_res(uint16_t temp, const struct bme680_dev *dev); + +/** + * @fn read_field_data + * @brief This internal API is used to calculate the field data of sensor. + * + * @param data :Structure instance to hold the data + * @param dev :Structure instance of bme680_dev. + * + * @return int8_t result of the field data from sensor. + */ +static int8_t read_field_data(struct bme680_field_data *data, struct bme680_dev *dev); + +/** + * @fn set_mem_page + * @brief This internal API is used to set the memory page based on register address. + * + * @n The value of memory page + * @n value | Description + * @n --------|-------------- + * @n 0 | BME680_PAGE0_SPI + * @n 1 | BME680_PAGE1_SPI + * + * @param reg_addr :Contains the register address array. + * @param dev :Structure instance of bme680_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t set_mem_page(uint8_t reg_addr, struct bme680_dev *dev); + +/** + * @fn get_mem_page + * @brief This internal API is used to get the memory page based on register address. + * @n The value of memory page + * @n value | Description + * @n --------|-------------- + * @n 0 | BME680_PAGE0_SPI + * @n 1 | BME680_PAGE1_SPI + * + * @param dev :Structure instance of bme680_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t get_mem_page(struct bme680_dev *dev); + +/** + * @fn null_ptr_check + * @brief This internal API is used to validate the device pointer for null conditions. + * + * @param dev :Structure instance of bme680_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t null_ptr_check(const struct bme680_dev *dev); + +/** + * @fn boundary_check + * @brief This internal API is used to check the boundary conditions. + * + * @param value :pointer to the value. + * @param min :minimum value. + * @param max :maximum value. + * @param dev :Structure instance of bme680_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev); + +/** + * @fn configure_filter_settings + * @brief Configure filter settings for the sensor. + * @param desired_settings : Desired settings mask. + * @param reg_array : Register address array. + * @param data_array : Register data array. + * @param count : Current count in arrays. + * @param dev : Structure instance of bme680_dev. + * @return Result of API execution status. + */ +static int8_t configure_filter_settings(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev); + +/** + * @fn configure_heater_control + * @brief Configure heater control settings for the sensor. + * @param desired_settings : Desired settings mask. + * @param reg_array : Register address array. + * @param data_array : Register data array. + * @param count : Current count in arrays. + * @param dev : Structure instance of bme680_dev. + * @return Result of API execution status. + */ +static int8_t configure_heater_control(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev); + +/** + * @fn configure_tph_oversampling + * @brief Configure temperature and pressure oversampling settings. + * @param desired_settings : Desired settings mask. + * @param reg_array : Register address array. + * @param data_array : Register data array. + * @param count : Current count in arrays. + * @param dev : Structure instance of bme680_dev. + * @return Result of API execution status. + */ +static int8_t configure_tph_oversampling(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev); + +/** + * @fn configure_humidity_oversampling + * @brief Configure humidity oversampling settings. + * @param desired_settings : Desired settings mask. + * @param reg_array : Register address array. + * @param data_array : Register data array. + * @param count : Current count in arrays. + * @param dev : Structure instance of bme680_dev. + * @return Result of API execution status. + */ +static int8_t configure_humidity_oversampling(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev); + +/** + * @fn configure_gas_settings + * @brief Configure gas measurement settings. + * @param desired_settings : Desired settings mask. + * @param reg_array : Register address array. + * @param data_array : Register data array. + * @param count : Current count in arrays. + * @param dev : Structure instance of bme680_dev. + * @return Result of API execution status. + */ +static int8_t configure_gas_settings(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev); + +/** + * @fn calculate_tph_duration + * @brief Calculate TPH (Temperature, Pressure, Humidity) measurement duration. + * @param dev : Structure instance of bme680_dev. + * @return Calculated TPH duration in milliseconds. + */ +static uint32_t calculate_tph_duration(const struct bme680_dev *dev); + +/****************** Global Function Definitions *******************************/ +int8_t bme680_init(struct bme680_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + /* Soft reset to restore it to default values */ + rslt = bme680_soft_reset(dev); + if (rslt != BME680_OK) { + return rslt; + } + + rslt = bme680_get_regs(BME680_CHIP_ID_ADDR, &dev->chip_id, 1, dev); + if (rslt != BME680_OK) { + return rslt; + } + + if (dev->chip_id != BME680_CHIP_ID) { + return BME680_E_DEV_NOT_FOUND; + } + + /* Get the Calibration data */ + rslt = get_calib_data(dev); + + return rslt; +} + +int8_t bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt == BME680_OK) { + if (dev->intf == BME680_SPI_INTF) { + /* Set the memory page */ + rslt = set_mem_page(reg_addr, dev); + if (rslt == BME680_OK) { + reg_addr = reg_addr | BME680_SPI_RD_MSK; + } + } + dev->com_rslt = dev->read(dev->dev_id, reg_addr, reg_data, len); + if (dev->com_rslt != 0) { + rslt = BME680_E_COM_FAIL; + } + } + + return rslt; +} + +int8_t bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev) +{ + int8_t rslt; + /* Length of the temporary buffer is 2*(length of register) */ + uint8_t tmp_buff[BME680_TMP_BUFFER_LENGTH] = {0}; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + if ((len == 0) || (len >= BME680_TMP_BUFFER_HALF)) { + return BME680_E_INVALID_LENGTH; + } + + /* Interleave the 2 arrays */ + rslt = interleave_reg_data(reg_addr, reg_data, len, tmp_buff, dev); + if (rslt != BME680_OK) { + return rslt; + } + + /* Write the interleaved array */ + dev->com_rslt = dev->write(dev->dev_id, tmp_buff[BME680_TMP_BUFF_REG_ADDR_INDEX], + &tmp_buff[BME680_TMP_BUFF_REG_DATA_INDEX], (BME680_REG_PAIR_MULTIPLIER * len) - 1); + if (dev->com_rslt != 0) { + return BME680_E_COM_FAIL; + } + + return BME680_OK; +} + +int8_t bme680_soft_reset(struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t reg_addr = BME680_SOFT_RESET_ADDR; + /* 0xb6 is the soft reset command */ + uint8_t soft_rst_cmd = BME680_SOFT_RESET_CMD; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + if (dev->intf == BME680_SPI_INTF) { + rslt = get_mem_page(dev); + if (rslt != BME680_OK) { + return rslt; + } + } + + /* Reset the device */ + rslt = bme680_set_regs(®_addr, &soft_rst_cmd, 1, dev); + /* Wait for 5ms */ + dev->delay_ms(BME680_RESET_PERIOD); + + if (rslt != BME680_OK) { + return rslt; + } + + /* After reset get the memory page */ + if (dev->intf == BME680_SPI_INTF) { + rslt = get_mem_page(dev); + } + + return rslt; +} + +int8_t bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t count = 0; + uint8_t reg_array[BME680_REG_BUFFER_LENGTH] = {0}; + uint8_t data_array[BME680_REG_BUFFER_LENGTH] = {0}; + uint8_t intended_power_mode = dev->power_mode; + + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + if (desired_settings & BME680_GAS_MEAS_SEL) { + rslt = set_gas_config(dev); + if (rslt != BME680_OK) { + return rslt; + } + } + + dev->power_mode = BME680_SLEEP_MODE; + rslt = bme680_set_sensor_mode(dev); + if (rslt != BME680_OK) { + dev->power_mode = intended_power_mode; + return rslt; + } + + rslt = configure_filter_settings(desired_settings, reg_array, data_array, &count, dev); + if (rslt == BME680_OK) { + rslt = configure_heater_control(desired_settings, reg_array, data_array, &count, dev); + } + if (rslt == BME680_OK) { + rslt = configure_tph_oversampling(desired_settings, reg_array, data_array, &count, dev); + } + if (rslt == BME680_OK) { + rslt = configure_humidity_oversampling(desired_settings, reg_array, data_array, &count, dev); + } + if (rslt == BME680_OK) { + rslt = configure_gas_settings(desired_settings, reg_array, data_array, &count, dev); + } + + if (rslt == BME680_OK && count > 0) { + rslt = bme680_set_regs(reg_array, data_array, count, dev); + } + + dev->power_mode = intended_power_mode; + return rslt; +} + +int8_t bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) +{ + int8_t rslt; + /* starting address of the register array for burst read */ + uint8_t reg_addr = BME680_CONF_HEAT_CTRL_ADDR; + uint8_t data_array[BME680_REG_BUFFER_LENGTH] = {0}; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt == BME680_OK) { + rslt = bme680_get_regs(reg_addr, data_array, BME680_REG_BUFFER_LENGTH, dev); + if (rslt == BME680_OK) { + if (desired_settings & BME680_GAS_MEAS_SEL) { + rslt = get_gas_config(dev); + } + + /* get the T,P,H ,Filter,ODR settings here */ + if (desired_settings & BME680_FILTER_SEL) { + dev->tph_sett.filter = + bme680_get_bits(data_array[BME680_REG_FILTER_INDEX], BME680_FILTER_MSK, BME680_FILTER_POS); + } + + if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { + dev->tph_sett.os_temp = + bme680_get_bits(data_array[BME680_REG_TEMP_INDEX], BME680_OST_MSK, BME680_OST_POS); + dev->tph_sett.os_pres = + bme680_get_bits(data_array[BME680_REG_PRES_INDEX], BME680_OSP_MSK, BME680_OSP_POS); + } + + if (desired_settings & BME680_OSH_SEL) { + dev->tph_sett.os_hum = bme680_get_bits_pos_0(data_array[BME680_REG_HUM_INDEX], BME680_OSH_MSK); + } + + /* get the gas related settings */ + if (desired_settings & BME680_HCNTRL_SEL) { + dev->gas_sett.heatr_ctrl = bme680_get_bits_pos_0(data_array[BME680_REG_HCTRL_INDEX], BME680_HCTRL_MSK); + } + + if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { + dev->gas_sett.nb_conv = bme680_get_bits_pos_0(data_array[BME680_REG_NBCONV_INDEX], BME680_NBCONV_MSK); + dev->gas_sett.run_gas = + bme680_get_bits(data_array[BME680_REG_RUN_GAS_INDEX], BME680_RUN_GAS_MSK, BME680_RUN_GAS_POS); + } + } + } else { + rslt = BME680_E_NULL_PTR; + } + + return rslt; +} + +int8_t bme680_set_sensor_mode(struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t tmp_pow_mode; + uint8_t pow_mode = 0; + uint8_t reg_addr = BME680_CONF_T_P_MODE_ADDR; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + /* Call recursively until in sleep */ + do { + rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &tmp_pow_mode, 1, dev); + if (rslt != BME680_OK) { + return rslt; + } + + /* Put to sleep before changing mode */ + pow_mode = (tmp_pow_mode & BME680_MODE_MSK); + if (pow_mode == BME680_SLEEP_MODE) { + break; + } + + tmp_pow_mode = tmp_pow_mode & (~BME680_MODE_MSK); /* Set to sleep */ + rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); + if (rslt != BME680_OK) { + return rslt; + } + dev->delay_ms(BME680_POLL_PERIOD_MS); + } while (pow_mode != BME680_SLEEP_MODE); + + /* Already in sleep */ + if (dev->power_mode == BME680_SLEEP_MODE) { + return rslt; + } + + tmp_pow_mode = (tmp_pow_mode & ~BME680_MODE_MSK) | (dev->power_mode & BME680_MODE_MSK); + if (rslt == BME680_OK) { + rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); + } + + return rslt; +} + +int8_t bme680_get_sensor_mode(struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t mode; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt == BME680_OK) { + rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &mode, 1, dev); + /* Masking the other register bit info */ + dev->power_mode = mode & BME680_MODE_MSK; + } + + return rslt; +} + +void bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev) +{ + uint32_t tph_dur; + + tph_dur = calculate_tph_duration(dev); + dev->gas_sett.heatr_dur = duration - (uint16_t)tph_dur; +} + +void bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev) +{ + uint32_t tph_dur; + + tph_dur = calculate_tph_duration(dev); + *duration = (uint16_t)tph_dur; + + if (dev->gas_sett.run_gas) { + *duration += dev->gas_sett.heatr_dur; + } +} + +int8_t bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt == BME680_OK) { + /* Reading the sensor data in forced mode only */ + rslt = read_field_data(data, dev); + if (rslt == BME680_OK) { + if (data->status & BME680_NEW_DATA_MSK) { + dev->new_fields = 1; + } else { + dev->new_fields = 0; + } + } + } + + return rslt; +} + +static void parse_temp_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev) +{ + dev->calib.par_t1 = (uint16_t)(bme680_concat_bytes(coeff_array[BME680_T1_MSB_REG], coeff_array[BME680_T1_LSB_REG])); + dev->calib.par_t2 = (int16_t)(bme680_concat_bytes(coeff_array[BME680_T2_MSB_REG], coeff_array[BME680_T2_LSB_REG])); + dev->calib.par_t3 = (int8_t)(coeff_array[BME680_T3_REG]); +} + +static void parse_pressure_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev) +{ + dev->calib.par_p1 = (uint16_t)(bme680_concat_bytes(coeff_array[BME680_P1_MSB_REG], coeff_array[BME680_P1_LSB_REG])); + dev->calib.par_p2 = (int16_t)(bme680_concat_bytes(coeff_array[BME680_P2_MSB_REG], coeff_array[BME680_P2_LSB_REG])); + dev->calib.par_p3 = (int8_t)coeff_array[BME680_P3_REG]; + dev->calib.par_p4 = (int16_t)(bme680_concat_bytes(coeff_array[BME680_P4_MSB_REG], coeff_array[BME680_P4_LSB_REG])); + dev->calib.par_p5 = (int16_t)(bme680_concat_bytes(coeff_array[BME680_P5_MSB_REG], coeff_array[BME680_P5_LSB_REG])); + dev->calib.par_p6 = (int8_t)(coeff_array[BME680_P6_REG]); + dev->calib.par_p7 = (int8_t)(coeff_array[BME680_P7_REG]); + dev->calib.par_p8 = (int16_t)(bme680_concat_bytes(coeff_array[BME680_P8_MSB_REG], coeff_array[BME680_P8_LSB_REG])); + dev->calib.par_p9 = (int16_t)(bme680_concat_bytes(coeff_array[BME680_P9_MSB_REG], coeff_array[BME680_P9_LSB_REG])); + dev->calib.par_p10 = (uint8_t)(coeff_array[BME680_P10_REG]); +} + +static void parse_humidity_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev) +{ + dev->calib.par_h1 = (uint16_t)(((uint16_t)coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | + (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK)); + dev->calib.par_h2 = (uint16_t)(((uint16_t)coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | + ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL)); + dev->calib.par_h3 = (int8_t)coeff_array[BME680_H3_REG]; + dev->calib.par_h4 = (int8_t)coeff_array[BME680_H4_REG]; + dev->calib.par_h5 = (int8_t)coeff_array[BME680_H5_REG]; + dev->calib.par_h6 = (uint8_t)coeff_array[BME680_H6_REG]; + dev->calib.par_h7 = (int8_t)coeff_array[BME680_H7_REG]; +} + +static void parse_gas_coefficients(const uint8_t *coeff_array, struct bme680_dev *dev) +{ + dev->calib.par_gh1 = (int8_t)coeff_array[BME680_GH1_REG]; + dev->calib.par_gh2 = + (int16_t)(bme680_concat_bytes(coeff_array[BME680_GH2_MSB_REG], coeff_array[BME680_GH2_LSB_REG])); + dev->calib.par_gh3 = (int8_t)coeff_array[BME680_GH3_REG]; +} + +static int8_t parse_other_coefficients(struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t temp_var = 0; + + rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_RANGE_ADDR, &temp_var, 1, dev); + if (rslt != BME680_OK) { + return rslt; + } + + dev->calib.res_heat_range = ((temp_var & BME680_RHRANGE_MSK) / BME680_RHRANGE_DIVISOR); + rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_VAL_ADDR, &temp_var, 1, dev); + if (rslt != BME680_OK) { + return rslt; + } + + dev->calib.res_heat_val = (int8_t)temp_var; + rslt = bme680_get_regs(BME680_ADDR_RANGE_SW_ERR_ADDR, &temp_var, 1, dev); + if (rslt != BME680_OK) { + return rslt; + } + + dev->calib.range_sw_err = ((int8_t)temp_var & (int8_t)BME680_RSERROR_MSK) / BME680_RSERROR_DIVISOR; + + return rslt; +} + +static int8_t interleave_reg_data(const uint8_t *reg_addr, + const uint8_t *reg_data, + uint8_t len, + uint8_t *tmp_buff, + struct bme680_dev *dev) +{ + int8_t rslt = BME680_OK; + uint16_t index; + + for (index = 0; index < len; index++) { + if (dev->intf == BME680_SPI_INTF) { + /* Set the memory page */ + rslt = set_mem_page(reg_addr[index], dev); + if (rslt != BME680_OK) { + return rslt; + } + tmp_buff[(BME680_REG_PAIR_MULTIPLIER * index)] = reg_addr[index] & BME680_SPI_WR_MSK; + } else { + tmp_buff[(BME680_REG_PAIR_MULTIPLIER * index)] = reg_addr[index]; + } + tmp_buff[(BME680_REG_PAIR_MULTIPLIER * index) + 1] = reg_data[index]; + } + + return rslt; +} + +static int8_t get_calib_data(struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t coeff_array[BME680_COEFF_SIZE] = {0}; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + rslt = bme680_get_regs(BME680_COEFF_ADDR1, coeff_array, BME680_COEFF_ADDR1_LEN, dev); + if (rslt != BME680_OK) { + return rslt; + } + + /* Append the second half in the same array */ + rslt = bme680_get_regs(BME680_COEFF_ADDR2, &coeff_array[BME680_COEFF_ADDR1_LEN], BME680_COEFF_ADDR2_LEN, dev); + if (rslt != BME680_OK) { + return rslt; + } + + /* Parse all coefficients from the array */ + parse_temp_coefficients(coeff_array, dev); + parse_pressure_coefficients(coeff_array, dev); + parse_humidity_coefficients(coeff_array, dev); + parse_gas_coefficients(coeff_array, dev); + + /* Parse other coefficients from additional registers */ + rslt = parse_other_coefficients(dev); + + return rslt; +} + +static int8_t set_gas_config(struct bme680_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt == BME680_OK) { + uint8_t reg_addr[BME680_GAS_CONFIG_REG_COUNT] = {0}; + uint8_t reg_data[BME680_GAS_CONFIG_REG_COUNT] = {0}; + + if (dev->power_mode == BME680_FORCED_MODE) { + reg_addr[0] = BME680_RES_HEAT0_ADDR; + reg_data[0] = calc_heater_res(dev->gas_sett.heatr_temp, dev); + reg_addr[1] = BME680_GAS_WAIT0_ADDR; + reg_data[1] = calc_heater_dur(dev->gas_sett.heatr_dur); + dev->gas_sett.nb_conv = 0; + } else { + rslt = BME680_W_DEFINE_PWR_MODE; + } + if (rslt == BME680_OK) { + rslt = bme680_set_regs(reg_addr, reg_data, BME680_GAS_CONFIG_REG_COUNT, dev); + } + } + + return rslt; +} + +static int8_t get_gas_config(struct bme680_dev *dev) +{ + int8_t rslt; + /* starting address of the register array for burst read */ + uint8_t reg_addr1 = BME680_ADDR_SENS_CONF_START; + uint8_t reg_addr2 = BME680_ADDR_GAS_CONF_START; + uint8_t data_array[BME680_GAS_HEATER_PROF_LEN_MAX] = {0}; + uint8_t index; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + if (dev->intf == BME680_SPI_INTF) { + /* Memory page switch the SPI address */ + rslt = set_mem_page(reg_addr1, dev); + if (rslt != BME680_OK) { + return rslt; + } + } + + rslt = bme680_get_regs(reg_addr1, data_array, BME680_GAS_HEATER_PROF_LEN_MAX, dev); + if (rslt != BME680_OK) { + return rslt; + } + + for (index = 0; index < BME680_GAS_HEATER_PROF_LEN_MAX; index++) { + dev->gas_sett.heatr_temp = data_array[index]; + } + + rslt = bme680_get_regs(reg_addr2, data_array, BME680_GAS_HEATER_PROF_LEN_MAX, dev); + if (rslt != BME680_OK) { + return rslt; + } + + for (index = 0; index < BME680_GAS_HEATER_PROF_LEN_MAX; index++) { + dev->gas_sett.heatr_dur = data_array[index]; + } + + return rslt; +} + +static int16_t calc_temperature(uint32_t temp_adc, struct bme680_dev *dev) +{ + int64_t var1; + int64_t var2; + int64_t var3; + int16_t calc_temp; + + var1 = ((int32_t)temp_adc >> BME680_TEMP_ADC_SHIFT_RIGHT) - + ((int32_t)dev->calib.par_t1 << BME680_TEMP_PAR_T1_SHIFT_LEFT); + var2 = (var1 * (int32_t)dev->calib.par_t2) >> BME680_TEMP_VAR2_SHIFT_RIGHT; + var3 = ((var1 >> 1) * (var1 >> 1)) >> BME680_TEMP_VAR3_SHIFT_RIGHT; + var3 = ((var3) * ((int32_t)dev->calib.par_t3 << BME680_TEMP_PAR_T3_SHIFT_LEFT)) >> BME680_TEMP_VAR3_SHIFT_RIGHT_2; + dev->calib.t_fine = (int32_t)(var2 + var3); + calc_temp = (int16_t)(((dev->calib.t_fine * BME680_TEMP_CALC_MULTIPLIER) + BME680_TEMP_CALC_OFFSET) >> + BME680_TEMP_SHIFT_RIGHT); + + return calc_temp; +} + +static uint32_t calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev) +{ + int32_t var1 = 0; + int32_t var2 = 0; + int32_t var3 = 0; + int32_t var4 = 0; + int32_t pressure_comp = 0; + + var1 = (((int32_t)dev->calib.t_fine) >> BME680_PRES_VAR1_SHIFT_RIGHT) - BME680_PRES_VAR1_SUBTRACT; + var2 = ((((var1 >> BME680_PRES_VAR2_SHIFT_RIGHT) * (var1 >> BME680_PRES_VAR2_SHIFT_RIGHT)) >> + BME680_PRES_VAR2_SHIFT_RIGHT_2) * + (int32_t)dev->calib.par_p6) >> + BME680_PRES_VAR2_SHIFT_RIGHT_3; + var2 = var2 + ((var1 * (int32_t)dev->calib.par_p5) << BME680_PRES_VAR1_SHIFT_RIGHT); + var2 = (var2 >> BME680_PRES_VAR2_SHIFT_RIGHT) + ((int32_t)dev->calib.par_p4 << BME680_PRES_PAR_P4_SHIFT_LEFT); + var1 = (((((var1 >> BME680_PRES_VAR2_SHIFT_RIGHT) * (var1 >> BME680_PRES_VAR2_SHIFT_RIGHT)) >> + BME680_PRES_VAR1_SHIFT_RIGHT_2) * + ((int32_t)dev->calib.par_p3 << BME680_PRES_PAR_P3_SHIFT_LEFT)) >> + BME680_PRES_VAR1_SHIFT_RIGHT_3) + + (((int32_t)dev->calib.par_p2 * var1) >> BME680_PRES_VAR1_SHIFT_RIGHT); + var1 = var1 >> BME680_PRES_VAR1_SHIFT_RIGHT_4; + var1 = ((BME680_PRES_VAR1_ADD + var1) * (int32_t)dev->calib.par_p1) >> BME680_PRES_VAR1_SHIFT_RIGHT_5; + pressure_comp = BME680_PRES_COMP_SUBTRACT - pres_adc; + pressure_comp = + (int32_t)((pressure_comp - (var2 >> BME680_PRES_VAR2_SHIFT_RIGHT_4)) * ((uint32_t)BME680_PRES_COMP_MULTIPLIER)); + var4 = (1 << BME680_PRES_VAR4_SHIFT_LEFT); + if (pressure_comp >= var4) { + pressure_comp = ((pressure_comp / (uint32_t)var1) << BME680_PRES_COMP_SHIFT_LEFT); + } else { + pressure_comp = ((pressure_comp << BME680_PRES_COMP_SHIFT_LEFT) / (uint32_t)var1); + } + var1 = ((int32_t)dev->calib.par_p9 * (int32_t)(((pressure_comp >> BME680_PRES_COMP_SHIFT_RIGHT) * + (pressure_comp >> BME680_PRES_COMP_SHIFT_RIGHT)) >> + BME680_PRES_COMP_SHIFT_RIGHT_2)) >> + BME680_PRES_COMP_SHIFT_RIGHT_3; + var2 = ((int32_t)(pressure_comp >> BME680_PRES_COMP_SHIFT_RIGHT_4) * (int32_t)dev->calib.par_p8) >> + BME680_PRES_PAR_P8_SHIFT_RIGHT; + var3 = ((int32_t)(pressure_comp >> BME680_PRES_COMP_SHIFT_RIGHT_5) * + (int32_t)(pressure_comp >> BME680_PRES_COMP_SHIFT_RIGHT_5) * + (int32_t)(pressure_comp >> BME680_PRES_COMP_SHIFT_RIGHT_5) * (int32_t)dev->calib.par_p10) >> + BME680_PRES_COMP_SHIFT_RIGHT_6; + + pressure_comp = (int32_t)(pressure_comp) + + ((var1 + var2 + var3 + ((int32_t)dev->calib.par_p7 << BME680_PRES_PAR_P7_SHIFT_LEFT)) >> + BME680_PRES_COMP_SHIFT_RIGHT_7); + + return (uint32_t)pressure_comp; +} + +static uint32_t calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev) +{ + int32_t var1; + int32_t var2; + int32_t var3; + int32_t var4; + int32_t var5; + int32_t var6; + int32_t temp_scaled; + int32_t calc_hum; + + temp_scaled = (((int32_t)dev->calib.t_fine * BME680_TEMP_CALC_MULTIPLIER) + BME680_TEMP_CALC_OFFSET) >> + BME680_TEMP_SHIFT_RIGHT; + var1 = (int32_t)(hum_adc - ((int32_t)((int32_t)dev->calib.par_h1 * BME680_HUM_PAR_H1_MULTIPLIER))) - + (((temp_scaled * (int32_t)dev->calib.par_h3) / ((int32_t)BME680_HUM_PERCENT_DIVISOR)) >> + BME680_HUM_VAR1_SHIFT_RIGHT); + var2 = ((int32_t)dev->calib.par_h2 * + (((temp_scaled * (int32_t)dev->calib.par_h4) / ((int32_t)BME680_HUM_PERCENT_DIVISOR)) + + (((temp_scaled * ((temp_scaled * (int32_t)dev->calib.par_h5) / ((int32_t)BME680_HUM_PERCENT_DIVISOR))) >> + BME680_HUM_VAR2_SHIFT_RIGHT) / + ((int32_t)BME680_HUM_PERCENT_DIVISOR)) + + (int32_t)(1 << BME680_HUM_VAR2_SHIFT_LEFT))) >> + BME680_HUM_VAR2_SHIFT_RIGHT_2; + var3 = var1 * var2; + var4 = (int32_t)dev->calib.par_h6 << BME680_HUM_VAR4_SHIFT_LEFT; + var4 = ((var4) + ((temp_scaled * (int32_t)dev->calib.par_h7) / ((int32_t)BME680_HUM_PERCENT_DIVISOR))) >> + BME680_HUM_VAR4_SHIFT_RIGHT; + var5 = ((var3 >> BME680_HUM_VAR5_SHIFT_RIGHT) * (var3 >> BME680_HUM_VAR5_SHIFT_RIGHT)) >> + BME680_HUM_VAR5_SHIFT_RIGHT_2; + var6 = (var4 * var5) >> BME680_HUM_VAR6_SHIFT_RIGHT; + calc_hum = (((var3 + var6) >> BME680_HUM_CALC_SHIFT_RIGHT) * ((int32_t)BME680_HUM_CALC_MULTIPLIER)) >> + BME680_HUM_CALC_SHIFT_RIGHT_2; + + if (calc_hum > BME680_HUM_MAX_VALUE) { /* Cap at 100%rH */ + calc_hum = BME680_HUM_MAX_VALUE; + } else if (calc_hum < BME680_HUM_MIN_VALUE) { + calc_hum = BME680_HUM_MIN_VALUE; + } + + return (uint32_t)calc_hum; +} + +uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, struct bme680_dev *dev) +{ + int64_t var1; + uint64_t var2; + int64_t var3; + uint32_t calc_gas_res; + + var1 = (int64_t)((BME680_GAS_VAR1_BASE + (BME680_GAS_VAR1_MULTIPLIER * (int64_t)dev->calib.range_sw_err)) * + ((int64_t)g_lookup_table1[gas_range])) >> + BME680_GAS_VAR1_SHIFT_RIGHT; + var2 = + (((int64_t)((int64_t)gas_res_adc << BME680_GAS_VAR2_SHIFT_LEFT) - (int64_t)(BME680_GAS_VAR2_SUBTRACT)) + var1); + var3 = (((int64_t)g_lookup_table2[gas_range] * (int64_t)var1) >> BME680_GAS_VAR3_SHIFT_RIGHT); + calc_gas_res = (uint32_t)((var3 + ((int64_t)var2 >> BME680_GAS_VAR2_SHIFT_RIGHT)) / (int64_t)var2); + + return calc_gas_res; +} + +static uint8_t calc_heater_res(uint16_t temp, const struct bme680_dev *dev) +{ + uint8_t heatr_res; + int32_t var1; + int32_t var2; + int32_t var3; + int32_t var4; + int32_t var5; + int32_t heatr_res_x100; + + if (temp < BME680_HEATR_TEMP_MIN) { /* Cap temperature */ + temp = BME680_HEATR_TEMP_MIN; + } else if (temp > BME680_HEATR_TEMP_MAX) { + temp = BME680_HEATR_TEMP_MAX; + } + + var1 = (((int32_t)dev->amb_temp * dev->calib.par_gh3) / BME680_HEATR_AMBIENT_DIVISOR) * + BME680_HEATR_AMBIENT_MULTIPLIER; + var2 = (dev->calib.par_gh1 + BME680_HEATR_PAR_GH1_ADD) * + (((((dev->calib.par_gh2 + BME680_HEATR_PAR_GH2_ADD) * temp * BME680_HEATR_TEMP_MULTIPLIER) / + BME680_HEATR_TEMP_DIVISOR) + + BME680_HEATR_TEMP_ADD) / + BME680_HEATR_TEMP_DIVISOR_2); + var3 = var1 + (var2 / BME680_REG_PAIR_MULTIPLIER); + var4 = (var3 / (dev->calib.res_heat_range + BME680_HEATR_RES_RANGE_ADD)); + var5 = (BME680_HEATR_VAR5_MULTIPLIER * dev->calib.res_heat_val) + BME680_HEATR_VAR5_ADD; + heatr_res_x100 = (int32_t)(((var4 / var5) - BME680_HEATR_VAR5_SUBTRACT) * BME680_HEATR_VAR5_MULTIPLIER_2); + heatr_res = (uint8_t)((heatr_res_x100 + BME680_HEATR_ROUNDING_ADD) / BME680_HEATR_ROUNDING_DIVISOR); + + return heatr_res; +} + +static uint8_t calc_heater_dur(uint16_t dur) +{ + uint8_t factor = 0; + uint8_t durval; + + if (dur >= BME680_HEATR_DUR_MAX_THRESHOLD) { + durval = BME680_HEATR_DUR_MAX_VALUE; /* Max duration */ + } else { + while (dur > BME680_HEATR_DUR_THRESHOLD) { + dur = dur / BME680_HEATR_DUR_DIVISOR; + factor += 1; + } + durval = (uint8_t)(dur + (factor * BME680_HEATR_DUR_FACTOR_MULTIPLIER)); + } + + return durval; +} + +static int8_t read_field_data(struct bme680_field_data *data, struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t buff[BME680_FIELD_LENGTH] = {0}; + uint8_t gas_range; + uint32_t adc_temp; + uint32_t adc_pres; + uint16_t adc_hum; + uint16_t adc_gas_res; + uint8_t tries = BME680_FIELD_READ_TRIES; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + do { + if (rslt == BME680_OK) { + rslt = bme680_get_regs(((uint8_t)(BME680_FIELD0_ADDR)), buff, (uint16_t)BME680_FIELD_LENGTH, dev); + + data->status = buff[BME680_FIELD_STATUS_INDEX] & BME680_NEW_DATA_MSK; + data->gas_index = buff[BME680_FIELD_STATUS_INDEX] & BME680_GAS_INDEX_MSK; + data->meas_index = buff[BME680_FIELD_MEAS_INDEX]; + + /* read the raw data from the sensor */ + adc_pres = (uint32_t)(((uint32_t)buff[BME680_FIELD_PRES_MSB_INDEX] * BME680_ADC_PRES_MULTIPLIER_MSB) | + ((uint32_t)buff[BME680_FIELD_PRES_LSB_INDEX] * BME680_ADC_PRES_MULTIPLIER_MID) | + ((uint32_t)buff[BME680_FIELD_PRES_XLSB_INDEX] / BME680_ADC_PRES_DIVISOR)); + adc_temp = (uint32_t)(((uint32_t)buff[BME680_FIELD_TEMP_MSB_INDEX] * BME680_ADC_TEMP_MULTIPLIER_MSB) | + ((uint32_t)buff[BME680_FIELD_TEMP_LSB_INDEX] * BME680_ADC_TEMP_MULTIPLIER_MID) | + ((uint32_t)buff[BME680_FIELD_TEMP_XLSB_INDEX] / BME680_ADC_TEMP_DIVISOR)); + adc_hum = (uint16_t)(((uint32_t)buff[BME680_FIELD_HUM_MSB_INDEX] * BME680_ADC_HUM_MULTIPLIER) | + (uint32_t)buff[BME680_FIELD_HUM_LSB_INDEX]); + adc_gas_res = (uint16_t)(((uint32_t)buff[BME680_FIELD_GAS_RES_MSB_INDEX] * BME680_ADC_GAS_MULTIPLIER) | + (((uint32_t)buff[BME680_FIELD_GAS_RES_LSB_INDEX]) / BME680_ADC_GAS_DIVISOR)); + gas_range = buff[BME680_FIELD_GAS_RES_LSB_INDEX] & BME680_GAS_RANGE_MSK; + + data->status |= buff[BME680_FIELD_GAS_RES_LSB_INDEX] & BME680_GASM_VALID_MSK; + data->status |= buff[BME680_FIELD_GAS_RES_LSB_INDEX] & BME680_HEAT_STAB_MSK; + + if (data->status & BME680_NEW_DATA_MSK) { + data->temperature = calc_temperature(adc_temp, dev); + data->pressure = calc_pressure(adc_pres, dev); + data->humidity = calc_humidity(adc_hum, dev); + data->gas_resistance = calc_gas_resistance(adc_gas_res, gas_range, dev); + break; + } + /* Delay to poll the data */ + dev->delay_ms(BME680_POLL_PERIOD_MS); + } + tries--; + } while (tries); + + if (!tries) { + rslt = BME680_W_NO_NEW_DATA; + } + + return rslt; +} + +static int8_t set_mem_page(uint8_t reg_addr, struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t reg; + uint8_t mem_page; + + /* Check for null pointers in the device structure */ + rslt = null_ptr_check(dev); + if (rslt != BME680_OK) { + return rslt; + } + + if (reg_addr > 0x7f) { + mem_page = BME680_MEM_PAGE1; + } else { + mem_page = BME680_MEM_PAGE0; + } + + if (mem_page == dev->mem_page) { + return rslt; + } + + dev->mem_page = mem_page; + + dev->com_rslt = dev->read(dev->dev_id, BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); + if (dev->com_rslt != 0) { + return BME680_E_COM_FAIL; + } + + reg = reg & (~BME680_MEM_PAGE_MSK); + reg = reg | (dev->mem_page & BME680_MEM_PAGE_MSK); + + dev->com_rslt = dev->write(dev->dev_id, BME680_MEM_PAGE_ADDR & BME680_SPI_WR_MSK, ®, 1); + if (dev->com_rslt != 0) { + return BME680_E_COM_FAIL; + } + + return rslt; +} + +static int8_t get_mem_page(struct bme680_dev *dev) +{ + int8_t rslt; + uint8_t reg; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + if (rslt == BME680_OK) { + dev->com_rslt = dev->read(dev->dev_id, BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); + if (dev->com_rslt != 0) { + rslt = BME680_E_COM_FAIL; + } else { + dev->mem_page = reg & BME680_MEM_PAGE_MSK; + } + } + + return rslt; +} + +static int8_t boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev) +{ + int8_t rslt = BME680_OK; + + if (value != NULL) { + /* Check if value is below minimum value */ + if (*value < min) { + /* Auto correct the invalid value to minimum value */ + *value = min; + dev->info_msg |= BME680_I_MIN_CORRECTION; + } + /* Check if value is above maximum value */ + if (*value > max) { + /* Auto correct the invalid value to maximum value */ + *value = max; + dev->info_msg |= BME680_I_MAX_CORRECTION; + } + } else { + rslt = BME680_E_NULL_PTR; + } + + return rslt; +} + +static int8_t null_ptr_check(const struct bme680_dev *dev) +{ + int8_t rslt; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) { + /* Device structure pointer is not valid */ + rslt = BME680_E_NULL_PTR; + } else { + /* Device structure is fine */ + rslt = BME680_OK; + } + + return rslt; +} + +static int8_t configure_filter_settings(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev) +{ + int8_t rslt = BME680_OK; + uint8_t reg_addr; + uint8_t data = 0; + + if (desired_settings & BME680_FILTER_SEL) { + rslt = boundary_check(&dev->tph_sett.filter, BME680_FILTER_SIZE_0, BME680_FILTER_SIZE_127, dev); + reg_addr = BME680_CONF_ODR_FILT_ADDR; + + if (rslt == BME680_OK) { + rslt = bme680_get_regs(reg_addr, &data, 1, dev); + } + + if (rslt == BME680_OK) { + if (desired_settings & BME680_FILTER_SEL) { + data = bme680_set_bits(data, BME680_FILTER_MSK, BME680_FILTER_POS, dev->tph_sett.filter); + } + + reg_array[*count] = reg_addr; + data_array[*count] = data; + (*count)++; + } + } + + return rslt; +} + +static int8_t configure_heater_control(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev) +{ + int8_t rslt = BME680_OK; + uint8_t reg_addr; + uint8_t data = 0; + + if (desired_settings & BME680_HCNTRL_SEL) { + rslt = boundary_check(&dev->gas_sett.heatr_ctrl, BME680_ENABLE_HEATER, BME680_DISABLE_HEATER, dev); + reg_addr = BME680_CONF_HEAT_CTRL_ADDR; + + if (rslt == BME680_OK) { + rslt = bme680_get_regs(reg_addr, &data, 1, dev); + } + + if (rslt == BME680_OK) { + data = bme680_set_bits_pos_0(data, BME680_HCTRL_MSK, dev->gas_sett.heatr_ctrl); + + reg_array[*count] = reg_addr; + data_array[*count] = data; + (*count)++; + } + } + + return rslt; +} + +static int8_t configure_tph_oversampling(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev) +{ + int8_t rslt = BME680_OK; + uint8_t reg_addr; + uint8_t data = 0; + + if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { + rslt = boundary_check(&dev->tph_sett.os_temp, BME680_OS_NONE, BME680_OS_16X, dev); + reg_addr = BME680_CONF_T_P_MODE_ADDR; + + if (rslt == BME680_OK) { + rslt = bme680_get_regs(reg_addr, &data, 1, dev); + } + + if (rslt == BME680_OK) { + if (desired_settings & BME680_OST_SEL) { + data = bme680_set_bits(data, BME680_OST_MSK, BME680_OST_POS, dev->tph_sett.os_temp); + } + + if (desired_settings & BME680_OSP_SEL) { + data = bme680_set_bits(data, BME680_OSP_MSK, BME680_OSP_POS, dev->tph_sett.os_pres); + } + + reg_array[*count] = reg_addr; + data_array[*count] = data; + (*count)++; + } + } + + return rslt; +} + +static int8_t configure_humidity_oversampling(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev) +{ + int8_t rslt = BME680_OK; + uint8_t reg_addr; + uint8_t data = 0; + + if (desired_settings & BME680_OSH_SEL) { + rslt = boundary_check(&dev->tph_sett.os_hum, BME680_OS_NONE, BME680_OS_16X, dev); + reg_addr = BME680_CONF_OS_H_ADDR; + + if (rslt == BME680_OK) { + rslt = bme680_get_regs(reg_addr, &data, 1, dev); + } + + if (rslt == BME680_OK) { + data = bme680_set_bits_pos_0(data, BME680_OSH_MSK, dev->tph_sett.os_hum); + + reg_array[*count] = reg_addr; + data_array[*count] = data; + (*count)++; + } + } + + return rslt; +} + +static int8_t configure_gas_settings(uint16_t desired_settings, + uint8_t *reg_array, + uint8_t *data_array, + uint8_t *count, + struct bme680_dev *dev) +{ + int8_t rslt = BME680_OK; + uint8_t reg_addr; + uint8_t data = 0; + + if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { + rslt = boundary_check(&dev->gas_sett.run_gas, BME680_RUN_GAS_DISABLE, BME680_RUN_GAS_ENABLE, dev); + if (rslt == BME680_OK) { + rslt = boundary_check(&dev->gas_sett.nb_conv, BME680_NBCONV_MIN, BME680_NBCONV_MAX, dev); + } + + reg_addr = BME680_CONF_ODR_RUN_GAS_NBC_ADDR; + + if (rslt == BME680_OK) { + rslt = bme680_get_regs(reg_addr, &data, 1, dev); + } + + if (rslt == BME680_OK) { + if (desired_settings & BME680_RUN_GAS_SEL) { + data = bme680_set_bits(data, BME680_RUN_GAS_MSK, BME680_RUN_GAS_POS, dev->gas_sett.run_gas); + } + + if (desired_settings & BME680_NBCONV_SEL) { + data = bme680_set_bits_pos_0(data, BME680_NBCONV_MSK, dev->gas_sett.nb_conv); + } + + reg_array[*count] = reg_addr; + data_array[*count] = data; + (*count)++; + } + } + + return rslt; +} + +static uint32_t calculate_tph_duration(const struct bme680_dev *dev) +{ + uint32_t tph_dur; + + tph_dur = ((uint32_t)(dev->tph_sett.os_temp + dev->tph_sett.os_pres + dev->tph_sett.os_hum) * BME680_TPH_DUR_COEFF); + tph_dur += (BME680_TPH_SWITCH_DUR_BASE * BME680_TPH_SWITCH_MULTIPLIER); + tph_dur += (BME680_TPH_SWITCH_DUR_BASE * BME680_GAS_MEAS_DUR_MULTIPLIER); + tph_dur += BME680_DUR_ROUNDING_FACTOR; + tph_dur /= BME680_MS_PER_SEC; + tph_dur += BME680_WAKE_UP_DUR_MS; + + return tph_dur; +} diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680.h new file mode 100644 index 0000000000000000000000000000000000000000..831abc3be58625c88f41c50e77a9f1c5459be2c9 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680.h @@ -0,0 +1,172 @@ +/*! + * @file bme680.h + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#ifndef BME680_H_ +#define BME680_H_ + +/* Header includes */ +#include "bme680_defs.h" + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @fn bme680_init + * @brief This API is the entry point. + * @n It reads the chip-id and calibration data from the sensor. + * @param dev : Structure instance of bme680_dev + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +int8_t bme680_init(struct bme680_dev *dev); + +/** + * @fn bme680_set_regs + * @brief This API writes the given data to the register address of the sensor. + * @param reg_addr : Register address from where the data to be written. + * @param reg_data : Pointer to data buffer which is to be written in the sensor. + * @param len : No of bytes of data to write.. + * @param dev : Structure instance of bme680_dev. + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +int8_t bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev); + +/** + * @fn bme680_get_regs + * @brief This API reads the data from the given register address of the sensor. + * @param reg_addr : Register address from where the data to be read + * @param reg_data : Pointer to data buffer to store the read data. + * @param len : No of bytes of data to be read. + * @param dev : Structure instance of bme680_dev. + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +int8_t bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev); + +/** + * @fn bme680_soft_reset + * @brief This API performs the soft reset of the sensor. + * @param dev : Structure instance of bme680_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. + */ +int8_t bme680_soft_reset(struct bme680_dev *dev); + +/** + * @fn bme680_set_sensor_mode + * @brief This API is used to set the power mode of the sensor. + * @param dev : Structure instance of bme680_dev + * @note : Pass the value to bme680_dev.power_mode structure variable. + * @n value | mode + * @n ------|------------------ + * @n 0x00 | BME680_SLEEP_MODE + * @n 0x01 | BME680_FORCED_MODE + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +int8_t bme680_set_sensor_mode(struct bme680_dev *dev); + +/** + * @brief This API is used to get the power mode of the sensor. + * @param dev : Structure instance of bme680_dev + * @note : bme680_dev.power_mode structure variable hold the power mode. + * @n + * @n value | mode + * @n ---------|------------------ + * @n 0x00 | BME680_SLEEP_MODE + * @n 0x01 | BME680_FORCED_MODE + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +int8_t bme680_get_sensor_mode(struct bme680_dev *dev); + +/** + * @brief This API is used to set the profile duration of the sensor. + * @param dev : Structure instance of bme680_dev. + * @param duration : Duration of the measurement in ms. + * @return Nothing + */ +void bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev); + +/** + * @fn bme680_get_profile_dur + * @brief This API is used to get the profile duration of the sensor. + * + * @param duration : Duration of the measurement in ms. + * @param dev : Structure instance of bme680_dev. + * @return Nothing + */ +void bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev); + +/** + * @fn bme680_get_sensor_data + * @brief This API reads the pressure, temperature and humidity and gas data + * @n from the sensor, compensates the data and store it in the g_bme680_data + * @n structure instance passed by the user. + * @param data: Structure instance to hold the data. + * @param dev : Structure instance of bme680_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +int8_t bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev); + +/** + * @fn bme680_set_sensor_settings + * @brief This API is used to set the oversampling, filter and T,P,H, gas selection settings in the sensor. + * + * @param desired_settings : Variable used to select the settings which are to be set in the sensor. + * @n + * @n Macros | Functionality + * @n ---------------------------------|---------------------------------------------- + * @n BME680_OST_SEL | To set temperature oversampling. + * @n BME680_OSP_SEL | To set pressure oversampling. + * @n BME680_OSH_SEL | To set humidity oversampling. + * @n BME680_GAS_MEAS_SEL | To set gas measurement setting. + * @n BME680_FILTER_SEL | To set filter setting. + * @n BME680_HCNTRL_SEL | To set humidity control setting. + * @n BME680_RUN_GAS_SEL | To set run gas setting. + * @n BME680_NBCONV_SEL | To set NB conversion setting. + * @n BME680_GAS_SENSOR_SEL | To set all gas sensor related settings + * @param dev : Structure instance of bme680_dev. + * + * @note : Below are the macros to be used by the user for selecting the + * @n desired settings. User can do OR operation of these macros for configuring multiple settings. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. + */ +int8_t bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev); + +/** + * @fn bme680_get_sensor_settings + * @brief This API is used to get the oversampling, filter and T,P,H, gas selection + * @n settings in the sensor. + * + * @param desired_settings : Variable used to select the settings which + * @n are to be get from the sensor. + * @param dev : Structure instance of bme680_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. + */ +int8_t bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev); + +uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, struct bme680_dev *dev); +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680_defs.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..aea5bf80f4c46c99dd3fec4896f5599158cc0bd2 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/bme680_defs.h @@ -0,0 +1,574 @@ +/** + * @file bme680_defs.h + * @brief Sensor driver for BME680 sensor. + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#ifndef BME680_DEFS_H_ +#define BME680_DEFS_H_ + +/********************************************************/ +/* header includes */ +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +/******************************************************************************/ +/*! @name Common macros */ +/******************************************************************************/ + +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) (x) +#define UINT8_C(x) (x) +#endif + +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) (x) +#define UINT16_C(x) (x) +#endif + +#if !defined(INT32_C) && !defined(UINT32_C) +#define INT32_C(x) (x) +#define UINT32_C(x) (x) +#endif + +#if !defined(INT64_C) && !defined(UINT64_C) +#define INT64_C(x) (x) +#define UINT64_C(x) (x) +#endif + +/**@}*/ + +/**\name C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +/** BME680 General config */ +#define BME680_POLL_PERIOD_MS UINT8_C(10) + +/** BME680 I2C addresses */ +#define BME680_I2C_ADDR_PRIMARY UINT8_C(0x76) +#define BME680_I2C_ADDR_SECONDARY UINT8_C(0x77) + +/** BME680 unique chip identifier */ +#define BME680_CHIP_ID UINT8_C(0x61) + +/** BME680 coefficients related defines */ +#define BME680_COEFF_SIZE UINT8_C(0x41) +#define BME680_COEFF_ADDR1_LEN UINT8_C(25) +#define BME680_COEFF_ADDR2_LEN UINT8_C(16) + +/** Common constants */ +#define BME680_BITS_PER_BYTE UINT8_C(8) + +/** BME680 field_x related defines */ +#define BME680_FIELD_LENGTH UINT8_C(15) +#define BME680_FIELD_ADDR_OFFSET UINT8_C(17) + +/** Soft reset command */ +#define BME680_SOFT_RESET_CMD UINT8_C(0xb6) + +/** Error code definitions */ +#define BME680_OK INT8_C(0) +/* Errors */ +#define BME680_E_NULL_PTR INT8_C(-1) +#define BME680_E_COM_FAIL INT8_C(-2) +#define BME680_E_DEV_NOT_FOUND INT8_C(-3) +#define BME680_E_INVALID_LENGTH INT8_C(-4) + +/* Warnings */ +#define BME680_W_DEFINE_PWR_MODE INT8_C(1) +#define BME680_W_NO_NEW_DATA INT8_C(2) + +/* Info's */ +#define BME680_I_MIN_CORRECTION UINT8_C(1) +#define BME680_I_MAX_CORRECTION UINT8_C(2) + +/** Register map */ +/** Other coefficient's address */ +#define BME680_ADDR_RES_HEAT_VAL_ADDR UINT8_C(0x00) +#define BME680_ADDR_RES_HEAT_RANGE_ADDR UINT8_C(0x02) +#define BME680_ADDR_RANGE_SW_ERR_ADDR UINT8_C(0x04) +#define BME680_ADDR_SENS_CONF_START UINT8_C(0x5A) +#define BME680_ADDR_GAS_CONF_START UINT8_C(0x64) + +/** Field settings */ +#define BME680_FIELD0_ADDR UINT8_C(0x1d) + +/** Heater settings */ +#define BME680_RES_HEAT0_ADDR UINT8_C(0x5a) +#define BME680_GAS_WAIT0_ADDR UINT8_C(0x64) + +/** Sensor configuration registers */ +#define BME680_CONF_HEAT_CTRL_ADDR UINT8_C(0x70) +#define BME680_CONF_ODR_RUN_GAS_NBC_ADDR UINT8_C(0x71) +#define BME680_CONF_OS_H_ADDR UINT8_C(0x72) +#define BME680_MEM_PAGE_ADDR UINT8_C(0xf3) +#define BME680_CONF_T_P_MODE_ADDR UINT8_C(0x74) +#define BME680_CONF_ODR_FILT_ADDR UINT8_C(0x75) + +/** Coefficient's address */ +#define BME680_COEFF_ADDR1 UINT8_C(0x89) +#define BME680_COEFF_ADDR2 UINT8_C(0xe1) + +/** Chip identifier */ +#define BME680_CHIP_ID_ADDR UINT8_C(0xd0) + +/** Soft reset register */ +#define BME680_SOFT_RESET_ADDR UINT8_C(0xe0) + +/** Heater control settings */ +#define BME680_ENABLE_HEATER UINT8_C(0x00) +#define BME680_DISABLE_HEATER UINT8_C(0x08) + +/** Gas measurement settings */ +#define BME680_DISABLE_GAS_MEAS UINT8_C(0x00) +#define BME680_ENABLE_GAS_MEAS UINT8_C(0x01) + +/** Over-sampling settings */ +#define BME680_OS_NONE UINT8_C(0) +#define BME680_OS_1X UINT8_C(1) +#define BME680_OS_2X UINT8_C(2) +#define BME680_OS_4X UINT8_C(3) +#define BME680_OS_8X UINT8_C(4) +#define BME680_OS_16X UINT8_C(5) + +/** IIR filter settings */ +#define BME680_FILTER_SIZE_0 UINT8_C(0) +#define BME680_FILTER_SIZE_1 UINT8_C(1) +#define BME680_FILTER_SIZE_3 UINT8_C(2) +#define BME680_FILTER_SIZE_7 UINT8_C(3) +#define BME680_FILTER_SIZE_15 UINT8_C(4) +#define BME680_FILTER_SIZE_31 UINT8_C(5) +#define BME680_FILTER_SIZE_63 UINT8_C(6) +#define BME680_FILTER_SIZE_127 UINT8_C(7) + +/** Power mode settings */ +#define BME680_SLEEP_MODE UINT8_C(0) +#define BME680_FORCED_MODE UINT8_C(1) + +/** Delay related macro declaration */ +#define BME680_RESET_PERIOD UINT32_C(10) + +/** SPI memory page settings */ +#define BME680_MEM_PAGE0 UINT8_C(0x10) +#define BME680_MEM_PAGE1 UINT8_C(0x00) + +/** Ambient humidity shift value for compensation */ +#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4) + +/** Run gas enable and disable settings */ +#define BME680_RUN_GAS_DISABLE UINT8_C(0) +#define BME680_RUN_GAS_ENABLE UINT8_C(1) + +/** Buffer length macro declaration */ +#define BME680_TMP_BUFFER_LENGTH UINT8_C(40) +#define BME680_REG_BUFFER_LENGTH UINT8_C(6) +#define BME680_FIELD_DATA_LENGTH UINT8_C(3) +#define BME680_GAS_REG_BUF_LENGTH UINT8_C(20) +#define BME680_GAS_HEATER_PROF_LEN_MAX UINT8_C(10) + +/** Register pair and buffer calculation macros */ +#define BME680_REG_PAIR_MULTIPLIER UINT8_C(2) +#define BME680_TMP_BUFFER_HALF (BME680_TMP_BUFFER_LENGTH / BME680_REG_PAIR_MULTIPLIER) +#define BME680_GAS_CONFIG_REG_COUNT UINT8_C(2) + +/** Duration calculation constants */ +#define BME680_TPH_DUR_COEFF UINT32_C(1963) +#define BME680_TPH_SWITCH_DUR_BASE UINT32_C(477) +#define BME680_TPH_SWITCH_MULTIPLIER UINT8_C(4) +#define BME680_GAS_MEAS_DUR_MULTIPLIER UINT8_C(5) +#define BME680_DUR_ROUNDING_FACTOR UINT32_C(500) +#define BME680_MS_PER_SEC UINT32_C(1000) +#define BME680_WAKE_UP_DUR_MS UINT32_C(1) + +/** Bit shift and mask constants */ +#define BME680_RHRANGE_SHIFT UINT8_C(4) +#define BME680_RHRANGE_DIVISOR UINT8_C(16) +#define BME680_RSERROR_DIVISOR UINT8_C(16) + +/** ADC data parsing constants */ +#define BME680_ADC_PRES_MULTIPLIER_MSB UINT32_C(4096) +#define BME680_ADC_PRES_MULTIPLIER_MID UINT8_C(16) +#define BME680_ADC_PRES_DIVISOR UINT8_C(16) +#define BME680_ADC_TEMP_MULTIPLIER_MSB UINT32_C(4096) +#define BME680_ADC_TEMP_MULTIPLIER_MID UINT8_C(16) +#define BME680_ADC_TEMP_DIVISOR UINT8_C(16) +#define BME680_ADC_HUM_MULTIPLIER UINT16_C(256) +#define BME680_ADC_GAS_MULTIPLIER UINT8_C(4) +#define BME680_ADC_GAS_DIVISOR UINT8_C(64) + +/** Temperature calculation constants */ +#define BME680_TEMP_CALC_MULTIPLIER UINT8_C(5) +#define BME680_TEMP_CALC_OFFSET UINT8_C(128) +#define BME680_TEMP_SHIFT_RIGHT UINT8_C(8) +#define BME680_TEMP_ADC_SHIFT_RIGHT UINT8_C(3) +#define BME680_TEMP_PAR_T1_SHIFT_LEFT UINT8_C(1) +#define BME680_TEMP_VAR2_SHIFT_RIGHT UINT8_C(11) +#define BME680_TEMP_VAR3_SHIFT_RIGHT UINT8_C(12) +#define BME680_TEMP_VAR3_SHIFT_RIGHT_2 UINT8_C(14) +#define BME680_TEMP_PAR_T3_SHIFT_LEFT UINT8_C(4) + +/** Pressure calculation constants */ +#define BME680_PRES_VAR1_SHIFT_RIGHT UINT8_C(1) +#define BME680_PRES_VAR1_SUBTRACT UINT32_C(64000) +#define BME680_PRES_VAR2_SHIFT_RIGHT UINT8_C(2) +#define BME680_PRES_VAR2_SHIFT_RIGHT_2 UINT8_C(11) +#define BME680_PRES_VAR2_SHIFT_RIGHT_3 UINT8_C(2) +#define BME680_PRES_VAR2_SHIFT_RIGHT_4 UINT8_C(12) +#define BME680_PRES_VAR1_SHIFT_RIGHT_2 UINT8_C(13) +#define BME680_PRES_VAR1_SHIFT_RIGHT_3 UINT8_C(3) +#define BME680_PRES_VAR1_SHIFT_RIGHT_4 UINT8_C(18) +#define BME680_PRES_VAR1_SHIFT_RIGHT_5 UINT8_C(15) +#define BME680_PRES_VAR1_ADD UINT32_C(32768) +#define BME680_PRES_COMP_SUBTRACT UINT32_C(1048576) +#define BME680_PRES_COMP_MULTIPLIER UINT32_C(3125) +#define BME680_PRES_VAR4_SHIFT_LEFT UINT8_C(31) +#define BME680_PRES_COMP_SHIFT_LEFT UINT8_C(1) +#define BME680_PRES_COMP_SHIFT_RIGHT UINT8_C(3) +#define BME680_PRES_COMP_SHIFT_RIGHT_2 UINT8_C(13) +#define BME680_PRES_COMP_SHIFT_RIGHT_3 UINT8_C(12) +#define BME680_PRES_COMP_SHIFT_RIGHT_4 UINT8_C(2) +#define BME680_PRES_COMP_SHIFT_RIGHT_5 UINT8_C(8) +#define BME680_PRES_COMP_SHIFT_RIGHT_6 UINT8_C(17) +#define BME680_PRES_COMP_SHIFT_RIGHT_7 UINT8_C(4) +#define BME680_PRES_PAR_P3_SHIFT_LEFT UINT8_C(5) +#define BME680_PRES_PAR_P4_SHIFT_LEFT UINT8_C(16) +#define BME680_PRES_PAR_P7_SHIFT_LEFT UINT8_C(7) +#define BME680_PRES_PAR_P8_SHIFT_RIGHT UINT8_C(13) + +/** Humidity calculation constants */ +#define BME680_HUM_PAR_H1_MULTIPLIER UINT8_C(16) +#define BME680_HUM_PERCENT_DIVISOR UINT8_C(100) +#define BME680_HUM_VAR1_SHIFT_RIGHT UINT8_C(1) +#define BME680_HUM_VAR2_SHIFT_RIGHT UINT8_C(6) +#define BME680_HUM_VAR2_SHIFT_LEFT UINT8_C(14) +#define BME680_HUM_VAR2_SHIFT_RIGHT_2 UINT8_C(10) +#define BME680_HUM_VAR4_SHIFT_LEFT UINT8_C(7) +#define BME680_HUM_VAR4_SHIFT_RIGHT UINT8_C(4) +#define BME680_HUM_VAR5_SHIFT_RIGHT UINT8_C(14) +#define BME680_HUM_VAR5_SHIFT_RIGHT_2 UINT8_C(10) +#define BME680_HUM_VAR6_SHIFT_RIGHT UINT8_C(1) +#define BME680_HUM_CALC_SHIFT_RIGHT UINT8_C(10) +#define BME680_HUM_CALC_MULTIPLIER UINT32_C(1000) +#define BME680_HUM_CALC_SHIFT_RIGHT_2 UINT8_C(12) +#define BME680_HUM_MAX_VALUE INT32_C(100000) +#define BME680_HUM_MIN_VALUE INT32_C(0) + +/** Gas resistance calculation constants */ +#define BME680_GAS_VAR1_BASE UINT32_C(1340) +#define BME680_GAS_VAR1_MULTIPLIER UINT8_C(5) +#define BME680_GAS_VAR1_SHIFT_RIGHT UINT8_C(16) +#define BME680_GAS_VAR2_SHIFT_LEFT UINT8_C(15) +#define BME680_GAS_VAR2_SUBTRACT UINT32_C(16777216) +#define BME680_GAS_VAR2_SHIFT_RIGHT UINT8_C(1) +#define BME680_GAS_VAR3_SHIFT_RIGHT UINT8_C(9) + +/** Heater resistance calculation constants */ +#define BME680_HEATR_TEMP_MIN UINT16_C(200) +#define BME680_HEATR_TEMP_MAX UINT16_C(400) +#define BME680_HEATR_AMBIENT_DIVISOR UINT16_C(1000) +#define BME680_HEATR_AMBIENT_MULTIPLIER UINT16_C(256) +#define BME680_HEATR_PAR_GH1_ADD UINT16_C(784) +#define BME680_HEATR_PAR_GH2_ADD UINT32_C(154009) +#define BME680_HEATR_TEMP_MULTIPLIER UINT8_C(5) +#define BME680_HEATR_TEMP_DIVISOR UINT8_C(100) +#define BME680_HEATR_TEMP_ADD UINT32_C(3276800) +#define BME680_HEATR_TEMP_DIVISOR_2 UINT8_C(10) +#define BME680_HEATR_VAR3_SHIFT_RIGHT UINT8_C(2) +#define BME680_HEATR_RES_RANGE_ADD UINT8_C(4) +#define BME680_HEATR_VAR5_MULTIPLIER UINT8_C(131) +#define BME680_HEATR_VAR5_ADD UINT32_C(65536) +#define BME680_HEATR_VAR5_SUBTRACT UINT16_C(250) +#define BME680_HEATR_VAR5_MULTIPLIER_2 UINT8_C(34) +#define BME680_HEATR_ROUNDING_ADD UINT8_C(50) +#define BME680_HEATR_ROUNDING_DIVISOR UINT8_C(100) + +/** Heater duration calculation constants */ +#define BME680_HEATR_DUR_MAX_THRESHOLD UINT16_C(0xfc0) +#define BME680_HEATR_DUR_MAX_VALUE UINT8_C(0xff) +#define BME680_HEATR_DUR_DIVISOR UINT8_C(4) +#define BME680_HEATR_DUR_FACTOR_MULTIPLIER UINT8_C(64) +#define BME680_HEATR_DUR_THRESHOLD UINT8_C(0x3F) + +/** Field data reading constants */ +#define BME680_FIELD_READ_TRIES UINT8_C(10) + +/** Field data buffer index definitions */ +#define BME680_FIELD_STATUS_INDEX UINT8_C(0) +#define BME680_FIELD_MEAS_INDEX UINT8_C(1) +#define BME680_FIELD_PRES_MSB_INDEX UINT8_C(2) +#define BME680_FIELD_PRES_LSB_INDEX UINT8_C(3) +#define BME680_FIELD_PRES_XLSB_INDEX UINT8_C(4) +#define BME680_FIELD_TEMP_MSB_INDEX UINT8_C(5) +#define BME680_FIELD_TEMP_LSB_INDEX UINT8_C(6) +#define BME680_FIELD_TEMP_XLSB_INDEX UINT8_C(7) +#define BME680_FIELD_HUM_MSB_INDEX UINT8_C(8) +#define BME680_FIELD_HUM_LSB_INDEX UINT8_C(9) +#define BME680_FIELD_GAS_RES_MSB_INDEX UINT8_C(13) +#define BME680_FIELD_GAS_RES_LSB_INDEX UINT8_C(14) + +/** Temporary buffer index definitions */ +#define BME680_TMP_BUFF_REG_ADDR_INDEX UINT8_C(0) +#define BME680_TMP_BUFF_REG_DATA_INDEX UINT8_C(1) + +/** Settings selector */ +#define BME680_OST_SEL UINT16_C(1) +#define BME680_OSP_SEL UINT16_C(2) +#define BME680_OSH_SEL UINT16_C(4) +#define BME680_GAS_MEAS_SEL UINT16_C(8) +#define BME680_FILTER_SEL UINT16_C(16) +#define BME680_HCNTRL_SEL UINT16_C(32) +#define BME680_RUN_GAS_SEL UINT16_C(64) +#define BME680_NBCONV_SEL UINT16_C(128) +#define BME680_GAS_SENSOR_SEL (BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL) + +/** Number of conversion settings*/ +#define BME680_NBCONV_MIN UINT8_C(0) +#define BME680_NBCONV_MAX UINT8_C(10) + +/** Mask definitions */ +#define BME680_GAS_MEAS_MSK UINT8_C(0x30) +#define BME680_NBCONV_MSK UINT8_C(0X0F) +#define BME680_FILTER_MSK UINT8_C(0X1C) +#define BME680_OST_MSK UINT8_C(0XE0) +#define BME680_OSP_MSK UINT8_C(0X1C) +#define BME680_OSH_MSK UINT8_C(0X07) +#define BME680_HCTRL_MSK UINT8_C(0x08) +#define BME680_RUN_GAS_MSK UINT8_C(0x10) +#define BME680_MODE_MSK UINT8_C(0x03) +#define BME680_RHRANGE_MSK UINT8_C(0x30) +#define BME680_RSERROR_MSK UINT8_C(0xf0) +#define BME680_NEW_DATA_MSK UINT8_C(0x80) +#define BME680_GAS_INDEX_MSK UINT8_C(0x0f) +#define BME680_GAS_RANGE_MSK UINT8_C(0x0f) +#define BME680_GASM_VALID_MSK UINT8_C(0x20) +#define BME680_HEAT_STAB_MSK UINT8_C(0x10) +#define BME680_MEM_PAGE_MSK UINT8_C(0x10) +#define BME680_SPI_RD_MSK UINT8_C(0x80) +#define BME680_SPI_WR_MSK UINT8_C(0x7f) +#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F) + +/** Bit position definitions for sensor settings */ +#define BME680_GAS_MEAS_POS UINT8_C(4) +#define BME680_FILTER_POS UINT8_C(2) +#define BME680_OST_POS UINT8_C(5) +#define BME680_OSP_POS UINT8_C(2) +#define BME680_RUN_GAS_POS UINT8_C(4) + +/** Array Index to Field data mapping for Calibration Data*/ +#define BME680_T2_LSB_REG (1) +#define BME680_T2_MSB_REG (2) +#define BME680_T3_REG (3) +#define BME680_P1_LSB_REG (5) +#define BME680_P1_MSB_REG (6) +#define BME680_P2_LSB_REG (7) +#define BME680_P2_MSB_REG (8) +#define BME680_P3_REG (9) +#define BME680_P4_LSB_REG (11) +#define BME680_P4_MSB_REG (12) +#define BME680_P5_LSB_REG (13) +#define BME680_P5_MSB_REG (14) +#define BME680_P7_REG (15) +#define BME680_P6_REG (16) +#define BME680_P8_LSB_REG (19) +#define BME680_P8_MSB_REG (20) +#define BME680_P9_LSB_REG (21) +#define BME680_P9_MSB_REG (22) +#define BME680_P10_REG (23) +#define BME680_H2_MSB_REG (25) +#define BME680_H2_LSB_REG (26) +#define BME680_H1_LSB_REG (26) +#define BME680_H1_MSB_REG (27) +#define BME680_H3_REG (28) +#define BME680_H4_REG (29) +#define BME680_H5_REG (30) +#define BME680_H6_REG (31) +#define BME680_H7_REG (32) +#define BME680_T1_LSB_REG (33) +#define BME680_T1_MSB_REG (34) +#define BME680_GH2_LSB_REG (35) +#define BME680_GH2_MSB_REG (36) +#define BME680_GH1_REG (37) +#define BME680_GH3_REG (38) + +/** BME680 register buffer index settings*/ +#define BME680_REG_FILTER_INDEX UINT8_C(5) +#define BME680_REG_TEMP_INDEX UINT8_C(4) +#define BME680_REG_PRES_INDEX UINT8_C(4) +#define BME680_REG_HUM_INDEX UINT8_C(2) +#define BME680_REG_NBCONV_INDEX UINT8_C(1) +#define BME680_REG_RUN_GAS_INDEX UINT8_C(1) +#define BME680_REG_HCTRL_INDEX UINT8_C(0) + +/** Inline function to combine two 8 bit data's to form a 16 bit data */ +static inline uint16_t bme680_concat_bytes(uint8_t msb, uint8_t lsb) +{ + return ((uint16_t)msb << BME680_BITS_PER_BYTE) | (uint16_t)lsb; +} + +/** Inline function to SET BITS of a register */ +static inline uint8_t bme680_set_bits(uint8_t reg_data, uint8_t mask, uint8_t pos, uint8_t data) +{ + return (reg_data & ~mask) | ((data << pos) & mask); +} + +/** Inline function to GET BITS of a register */ +static inline uint8_t bme680_get_bits(uint8_t reg_data, uint8_t mask, uint8_t pos) +{ + return (reg_data & mask) >> pos; +} + +/** Inline function variant to handle the bitname position if it is zero */ +static inline uint8_t bme680_set_bits_pos_0(uint8_t reg_data, uint8_t mask, uint8_t data) +{ + return (reg_data & ~mask) | (data & mask); +} + +/** Inline function variant to GET BITS when position is zero */ +static inline uint8_t bme680_get_bits_pos_0(uint8_t reg_data, uint8_t mask) +{ + return reg_data & mask; +} + +/** + * @fn bme680_com_fptr_t + * @brief Generic communication function pointer + * @param dev_id: Place holder to store the id of the device structure + * @n Can be used to store the index of the Chip select or + * @n I2C address of the device. + * @param reg_addr: Used to select the register the where data needs to + * be read from or written to. + * @param data: Data array to read/write + * @param len: Length of the data array + * @return int8_t type + */ +typedef int8_t (*bme680_com_fptr_t)(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len); + +/** + * @fn bme680_delay_fptr_t + * @brief Delay function pointer + * @param[in] period: Time period in milliseconds + */ +typedef void (*bme680_delay_fptr_t)(uint32_t period); + +/** + * @enum bme680_intf + * @brief Interface selection Enumerations + */ +enum bme680_intf { + BME680_SPI_INTF, + BME680_I2C_INTF /**< I2C interface */ +}; + +/** + * @struct bme680_field_data + * @brief Sensor field data structure + */ +struct bme680_field_data { + uint8_t status; /**< Contains new_data, gasm_valid & heat_stab */ + uint8_t gas_index; /**< The index of the heater profile used */ + uint8_t meas_index; /**< Measurement index to track order */ + int16_t temperature; /**< Temperature in degree celsius x100 */ + uint32_t pressure; /**< Pressure in Pascal */ + uint32_t humidity; /**< Humidity in % relative humidity x1000 */ + uint32_t gas_resistance; /**< Gas resistance in Ohms */ +}; + +/** + * @struct bme680_calib_data + * @brief Structure to hold the Calibration data + */ +struct bme680_calib_data { + uint16_t par_h1; /**< Variable to store calibrated humidity data */ + uint16_t par_h2; /**< Variable to store calibrated humidity data */ + int8_t par_h3; /**< Variable to store calibrated humidity data */ + int8_t par_h4; /**< Variable to store calibrated humidity data */ + int8_t par_h5; /**< Variable to store calibrated humidity data */ + uint8_t par_h6; /**< Variable to store calibrated humidity data */ + int8_t par_h7; /**< Variable to store calibrated humidity data */ + int8_t par_gh1; /**< Variable to store calibrated gas data */ + int16_t par_gh2; /**< Variable to store calibrated gas data */ + int8_t par_gh3; /**< Variable to store calibrated gas data */ + uint16_t par_t1; /**< Variable to store calibrated temperature data */ + int16_t par_t2; /**< Variable to store calibrated temperature data */ + int8_t par_t3; /**< Variable to store calibrated temperature data */ + uint16_t par_p1; /**< Variable to store calibrated pressure data */ + int16_t par_p2; /**< Variable to store calibrated pressure data */ + int8_t par_p3; /**< Variable to store calibrated pressure data */ + int16_t par_p4; /**< Variable to store calibrated pressure data */ + int16_t par_p5; /**< Variable to store calibrated pressure data */ + int8_t par_p6; /**< Variable to store calibrated pressure data */ + int8_t par_p7; /**< Variable to store calibrated pressure data */ + int16_t par_p8; /**< Variable to store calibrated pressure data */ + int16_t par_p9; /**< Variable to store calibrated pressure data */ + uint8_t par_p10; /**< Variable to store calibrated pressure data */ + int32_t t_fine; /**< Variable to store t_fine size */ + uint8_t res_heat_range; /**< Variable to store heater resistance range */ + int8_t res_heat_val; /**< Variable to store heater resistance value */ + int8_t range_sw_err; /**< Variable to store error range */ +}; + +/** + * @struct bme680_tph_sett + * @brief BME680 sensor settings structure which comprises of ODR, + * over-sampling and filter settings. + */ +struct bme680_tph_sett { + uint8_t os_hum; /**< Humidity oversampling */ + uint8_t os_temp; /**< Temperature oversampling */ + uint8_t os_pres; /**< Pressure oversampling */ + uint8_t filter; /**< Filter coefficient */ +}; + +/** + * @struct bme680_gas_sett + * @brief BME680 gas sensor which comprises of gas settings + * and status parameters + */ +struct bme680_gas_sett { + uint8_t nb_conv; /**< Variable to store nb conversion */ + uint8_t heatr_ctrl; /**< Variable to store heater control */ + uint8_t run_gas; /**< Run gas enable value */ + uint16_t heatr_temp; /**< Pointer to store heater temperature */ + uint16_t heatr_dur; /**< Pointer to store duration profile */ +}; + +/** + * @struct bme680_dev + * @brief BME680 device structure + */ +struct bme680_dev { + uint8_t chip_id; /**< Chip Id */ + uint8_t dev_id; /**< Device Id */ + enum bme680_intf intf; /**< SPI/I2C interface */ + uint8_t mem_page; /**< Memory page used */ + int8_t amb_temp; /**< Ambient temperature in Degree C*/ + struct bme680_calib_data calib; /**< Sensor calibration data */ + struct bme680_tph_sett tph_sett; /**< Sensor settings */ + struct bme680_gas_sett gas_sett; /**< Gas Sensor settings */ + uint8_t power_mode; /**< Sensor power modes */ + uint8_t new_fields; /**< New sensor fields */ + uint8_t info_msg; /**< Store the info messages */ + bme680_com_fptr_t read; /**< Burst read structure */ + bme680_com_fptr_t write; /**< Burst write structure */ + bme680_delay_fptr_t delay_ms; /**< Delay in ms */ + int8_t com_rslt; /**< Communication function result */ +}; + +#endif diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/dfrobot_bme680.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/dfrobot_bme680.c new file mode 100644 index 0000000000000000000000000000000000000000..dda11a1dbccb8f87b2df8cce4061feb55e092992 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/dfrobot_bme680.c @@ -0,0 +1,187 @@ +/** + * @file dfrobot_bme680.c + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ +#include +#include "dfrobot_bme680.h" + +static struct bme680_dev g_bme680_sensor; +static struct bme680_field_data g_bme680_data; +static uint8_t g_convert_cmd = (BME680_CONVERT_CMD_OS_TEMP_VAL << BME680_CONVERT_CMD_OS_TEMP_SHIFT) | + (BME680_CONVERT_CMD_OS_PRES_VAL << BME680_CONVERT_CMD_OS_PRES_SHIFT) | + BME680_CONVERT_CMD_MODE_VAL; + +uint8_t g_bme680_i2c_addr = BME680_INIT_SUCCESS; + +void bme680_delay_ms(uint32_t period) +{ + uapi_systick_delay_ms(period); +} + +void dfrobot_bme680(bme680_com_fptr_t read_reg, + bme680_com_fptr_t write_reg, + bme680_delay_fptr_t delay_ms, + e_bme680_interface interface) +{ + g_bme680_sensor.read = read_reg; + g_bme680_sensor.write = write_reg; + g_bme680_sensor.delay_ms = delay_ms; + switch (interface) { + case BME680_INTERFACE_I2C: + g_bme680_sensor.intf = BME680_I2C_INTF; + break; + case BME680_INTERFACE_SPI: + g_bme680_sensor.intf = BME680_SPI_INTF; + break; + } +} + +int16_t bme680_bme680_begin(void) +{ + g_bme680_sensor.dev_id = g_bme680_i2c_addr; + if (bme680_init(&g_bme680_sensor) != BME680_OK) { + return BME680_INIT_FAILURE; + } + + printf("bme begin step1\r\n"); + + uint8_t set_required_settings; + + /* Set the temperature, pressure and humidity settings */ + g_bme680_sensor.tph_sett.os_hum = BME680_DEFAULT_OS_HUM; + g_bme680_sensor.tph_sett.os_pres = BME680_DEFAULT_OS_PRES; + g_bme680_sensor.tph_sett.os_temp = BME680_DEFAULT_OS_TEMP; + g_bme680_sensor.tph_sett.filter = BME680_DEFAULT_FILTER; + + /* Set the remaining gas sensor settings and link the heating profile */ + g_bme680_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS; + /* Create a ramp heat waveform in 3 steps */ + g_bme680_sensor.gas_sett.heatr_temp = BME680_DEFAULT_HEATR_TEMP; /* degree Celsius */ + g_bme680_sensor.gas_sett.heatr_dur = BME680_DEFAULT_HEATR_DUR; /* milliseconds */ + + /* Select the power mode */ + /* Must be set before writing the sensor configuration */ + g_bme680_sensor.power_mode = BME680_FORCED_MODE; + + /* Set the required sensor settings needed */ + set_required_settings = + BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL; + + /* Set the desired sensor configuration */ + bme680_set_sensor_settings(set_required_settings, &g_bme680_sensor); + + /* Set the power mode */ + bme680_set_sensor_mode(&g_bme680_sensor); + + /* Get the total measurement duration so as to sleep or wait till the + * measurement is complete */ + uint16_t meas_period; + bme680_get_profile_dur(&meas_period, &g_bme680_sensor); + g_bme680_sensor.delay_ms(meas_period); /* Delay till the measurement is ready */ + return BME680_INIT_SUCCESS; +} + +void start_convert(void) +{ + g_bme680_sensor.write(g_bme680_sensor.dev_id, BME680_REG_CTRL_TEMP_PRES, &g_convert_cmd, BME680_REG_DATA_SIZE); +} + +void bme680_bme680_update(void) +{ + bme680_get_sensor_data(&g_bme680_data, &g_bme680_sensor); +} + +float read_temperature(void) +{ + return g_bme680_data.temperature; +} + +float read_pressure(void) +{ + return g_bme680_data.pressure; +} + +float read_humidity(void) +{ + return g_bme680_data.humidity; +} + +float read_altitude(void) +{ + return (1.0f - pow((float)g_bme680_data.pressure / BME680_PRESSURE_TO_HPA_DIVISOR / BME680_SEALEVEL, + BME680_ALTITUDE_EXPONENT)) * + BME680_ALTITUDE_COEFFICIENT_1 / BME680_ALTITUDE_COEFFICIENT_2; +} + +float read_calibrated_altitude(float sea_level) +{ + return (1.0f - pow((float)g_bme680_data.pressure / sea_level, BME680_ALTITUDE_EXPONENT)) * + BME680_ALTITUDE_COEFFICIENT_1 / BME680_ALTITUDE_COEFFICIENT_2; +} + +float read_gas_resistance(void) +{ + return g_bme680_data.gas_resistance; +} + +float read_sea_level(float altitude) +{ + return (g_bme680_data.pressure / + pow(1.0f - (altitude / BME680_SEA_LEVEL_ALTITUDE_BASE), BME680_SEA_LEVEL_EXPONENT)); +} + +void set_param(e_bme680_param_t e_param, uint8_t dat) +{ + if (dat > BME680_PARAM_MAX_VALUE) { + return; + } + + switch (e_param) { + case BME680_PARAM_TEMPSAMP: + write_param_helper(BME680_REG_CTRL_TEMP_PRES, dat, BME680_PARAM_MASK << BME680_PARAM_TEMP_SHIFT); + break; + case BME680_PARAM_PREESAMP: + write_param_helper(BME680_REG_CTRL_TEMP_PRES, dat, BME680_PARAM_MASK << BME680_PARAM_PRES_SHIFT); + break; + case BME680_PARAM_HUMISAMP: + write_param_helper(BME680_REG_CTRL_HUM, dat, BME680_PARAM_MASK << BME680_PARAM_HUM_SHIFT); + break; + case BME680_PARAM_IIRSIZE: + write_param_helper(BME680_REG_CTRL_FILTER, dat, BME680_PARAM_MASK << BME680_PARAM_FILTER_SHIFT); + break; + } +} + +void set_gas_heater(uint16_t temp, uint16_t t) +{ + UNUSED(temp); + UNUSED(t); + g_bme680_sensor.gas_sett.heatr_temp = BME680_DEFAULT_HEATR_TEMP; /* degree Celsius */ + g_bme680_sensor.gas_sett.heatr_dur = BME680_DEFAULT_HEATR_DUR; /* milliseconds */ + uint8_t set_required_settings = BME680_GAS_SENSOR_SEL; + bme680_set_sensor_settings(set_required_settings, &g_bme680_sensor); +} + +void write_param_helper(uint8_t reg, uint8_t dat, uint8_t addr) +{ + uint8_t var1 = BME680_INIT_SUCCESS; + uint8_t addr_count = BME680_INIT_SUCCESS; + if (g_bme680_sensor.intf == BME680_SPI_INTF) { + uint8_t spi_page_reset = BME680_REG_SPI_PAGE_RESET; + g_bme680_sensor.write(g_bme680_sensor.dev_id, BME680_REG_CTRL_SPI_PAGE, &spi_page_reset, BME680_REG_DATA_SIZE); + } + g_bme680_sensor.read(g_bme680_sensor.dev_id, reg, &var1, BME680_REG_DATA_SIZE); + var1 &= ~addr; + while (!(addr & BME680_BIT_MASK_LSB)) { + addr_count++; + addr >>= 1; + } + var1 |= dat << addr_count; + g_bme680_sensor.write(g_bme680_sensor.dev_id, reg, &var1, BME680_REG_DATA_SIZE); +} diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/dfrobot_bme680.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/dfrobot_bme680.h new file mode 100644 index 0000000000000000000000000000000000000000..9201adc63b1561afc5dd409a4ed1ea3948b3985d --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/dfrobot_bme680.h @@ -0,0 +1,192 @@ +/** + * @file dfrobot_bme680.h + * + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author Martin(Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/dfrobot_bme680 + */ + +#ifndef DFROBOT_BME680_H +#define DFROBOT_BME680_H + +#include "bme680.h" + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "systick.h" +#include "osal_debug.h" +#include "watchdog.h" +#include "app_init.h" + +#define BME680_SEALEVEL 1015 + +/** Default sensor configuration constants */ +#define BME680_DEFAULT_OS_HUM UINT8_C(5) +#define BME680_DEFAULT_OS_PRES UINT8_C(5) +#define BME680_DEFAULT_OS_TEMP UINT8_C(5) +#define BME680_DEFAULT_FILTER UINT8_C(4) +#define BME680_DEFAULT_HEATR_TEMP UINT16_C(320) +#define BME680_DEFAULT_HEATR_DUR UINT16_C(150) + +/** Convert command constants */ +#define BME680_CONVERT_CMD_OS_TEMP_SHIFT 5 +#define BME680_CONVERT_CMD_OS_PRES_SHIFT 2 +#define BME680_CONVERT_CMD_OS_TEMP_VAL 0x05 +#define BME680_CONVERT_CMD_OS_PRES_VAL 0x05 +#define BME680_CONVERT_CMD_MODE_VAL 0x01 + +/** Register address constants */ +#define BME680_REG_CTRL_TEMP_PRES UINT8_C(0x74) +#define BME680_REG_CTRL_HUM UINT8_C(0x72) +#define BME680_REG_CTRL_FILTER UINT8_C(0x75) +#define BME680_REG_CTRL_SPI_PAGE UINT8_C(0x73) + +/** Register value constants */ +#define BME680_REG_DATA_SIZE UINT8_C(1) +#define BME680_REG_SPI_PAGE_RESET UINT8_C(0x00) + +/** Parameter validation constants */ +#define BME680_PARAM_MAX_VALUE UINT8_C(0x05) +#define BME680_PARAM_MASK UINT8_C(0x07) + +/** Bit shift constants */ +#define BME680_PARAM_TEMP_SHIFT 5 +#define BME680_PARAM_PRES_SHIFT 2 +#define BME680_PARAM_HUM_SHIFT 0 +#define BME680_PARAM_FILTER_SHIFT 2 + +/** Bit mask constants */ +#define BME680_BIT_MASK_LSB UINT8_C(0x01) + +/** Return value constants */ +#define BME680_INIT_SUCCESS 0 +#define BME680_INIT_FAILURE (-1) + +/** Altitude calculation constants */ +#define BME680_PRESSURE_TO_HPA_DIVISOR 100.0f +#define BME680_ALTITUDE_EXPONENT 0.190284f +#define BME680_ALTITUDE_COEFFICIENT_1 287.15f +#define BME680_ALTITUDE_COEFFICIENT_2 0.0065f +#define BME680_SEA_LEVEL_ALTITUDE_BASE 44330.0f +#define BME680_SEA_LEVEL_EXPONENT 5.255f + +/**\name C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +typedef enum { BME680_INTERFACE_SPI, BME680_INTERFACE_I2C } e_bme680_interface; + +typedef void (*pf_start_convert_t)(void); +typedef void (*pf_update_t)(void); + +void bme680_delay_ms(uint32_t period); + +typedef enum { + BME680_PARAM_TEMPSAMP, + BME680_PARAM_HUMISAMP, + BME680_PARAM_PREESAMP, + BME680_PARAM_IIRSIZE +} e_bme680_param_t; + +void dfrobot_bme680(bme680_com_fptr_t read_reg, + bme680_com_fptr_t write_reg, + bme680_delay_fptr_t delay_ms, + e_bme680_interface interface); + +extern uint8_t g_bme680_i2c_addr; +/** + * @fn begin + * @brief begin BME680 device + * @return result + * @retval non-zero : failed + * @retval 0 : succussful + */ +int16_t bme680_bme680_begin(void); +/** + * @fn update + * @brief update all data to MCU ram + */ +void bme680_bme680_update(void); + +/** + * @fn start_convert + * @brief start convert to get a accurate values + */ +void start_convert(void); +/** + * @fn read_temperature + * @brief read the temperature value (unit C) + * + * @return temperature valu, this value has two decimal points + */ +float read_temperature(void); +/** + * @fn read_pressure + * @brief read the pressure value (unit pa) + * + * @return pressure value, this value has two decimal points + */ +float read_pressure(void); +/** + * @fn read_humidity + * @brief read the humidity value (unit %rh) + * @return humidity value, this value has two decimal points + */ +float read_humidity(void); +/** + * @fn read_altitude + * @brief read the altitude (unit meter) + * @return altitude value, this value has two decimal points + */ +float read_altitude(void); +/** + * @fn read_calibrated_altitude + * @brief read the Calibrated altitude (unit meter) + * + * @param sea_level normalised atmospheric pressure + * + * @return calibrated altitude value , this value has two decimal points + */ +float read_calibrated_altitude(float sea_level); +/** + * @fn read_gas_resistance + * @brief read the gas resistance(unit ohm) + * @return temperature value, this value has two decimal points + */ +float read_gas_resistance(void); +/** + * @fn read_sea_level + * @brief read normalised atmospheric pressure (unit pa) + * @param altitude accurate altitude for normalising + * @return normalised atmospheric pressure + */ +float read_sea_level(float altitude); +/** + * @fn set_param + * @brief set bme680 parament + * + * @param e_param :which param you want to change + * dat :object data, can't more than 5 + */ +void set_param(e_bme680_param_t e_param, uint8_t dat); +/** + * @fn set_gas_heater + * @brief set bme680 gas heater + * @param temp :your object temp + * @param t :time spend in milliseconds + */ +void set_gas_heater(uint16_t temp, uint16_t t); + +void write_param_helper(uint8_t reg, uint8_t dat, uint8_t addr); + +#endif diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..0ed3dff2c07807a01b1521ada12bc4f377c37fd6 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/readme.md @@ -0,0 +1,114 @@ +# dfrobot_bme680 + +BME680 是专为移动应用和可穿戴设备开发的集成环境传感器其中尺寸和低功耗是关键要求。 BME680 扩展了 Bosch Sensortec
+现有的环境传感器系列,首次集成了用于气体、压力、湿度和温度的单个高线性度和高精度传感器。
+ +![产品效果图](./resources/images/SEN0248.png) + +## 产品链接([https://www.dfrobot.com.cn/goods-1621.html](https://www.dfrobot.com.cn/goods-1621.html)) + SKU: SEN0248 + +## 目录 + + * [概述](#概述) + * [API](#API) + * [历史](#历史) + +## 概述 + +提供一个 WS63 库,用于通过 I2C 通过 SPI 读取和解释 Bosch BME680 数据。读取温度、湿度、气体、压力并计算高度。 + + +## API +```C++ + /** + * @fn begin + * @brief 启动BME680传感器设备 + * @return 结果 + * @retval 非0值 : 失败 + * @retval 0 : 成功 + */ + int16_t bme680_bme680_begin(void); + + /** + * @fn update + * @brief 将所有数据更新到 MCU 内存 + */ + void bme680_bme680_update(void); + + /** + * @fn start_convert + * @brief 开始转换以获得准确的值 + */ + void start_convert(void); + /** + * @fn read_temperature + * @brief 获取温度值 (单位 摄氏度) + * + * @return 温度值, 这个值有两个小数点 + */ + float read_temperature(void); + /** + * @fn read_pressure + * @brief 读取压强值 (单位 帕) + * + * @return 压强值, 这个值有两个小数点 + */ + float read_pressure(void); + /** + * @fn read_humidity + * @brief 读取湿度值 (单位 %rh) + * @return 湿度值, 这个值有两个小数点 + */ + float read_humidity(void); + /** + * @fn read_altitude + * @brief 读取高度(单位米) + * @return 高度值, 这个值有两个小数点 + */ + float read_altitude(void); + /** + * @fn read_calibrated_altitude + * @brief 读取校准高度(单位米) + * + * @param sea_level 正规化大气压 + * + * @return 标定高度值,该值有两位小数 + */ + float read_calibrated_altitude(float sea_level); + /** + * @fn read_gas_resistance + * @brief 读取气体电阻(单位欧姆) + * @return 温度值,这个值有两位小数 + */ + float read_gas_resistance(void); + /** + * @fn read_sea_level + * @brief 读取标准化大气压力(单位帕) + * @param altitude 标准化大气压力 + * @return 标准化大气压力 + */ + float read_sea_level(float altitude); + /** + * @fn set_param + * @brief 设置bme680的参数 + * + * @param e_param : 需要设置的参数 + * dat : 对象数据,不能超过5 + */ + void set_param(e_bme680_param_t e_param, uint8_t dat); + /** + * @fn set_gas_heater + * @brief 设置bme680燃气加热器 + * @param temp :目标温度 + * @param t :以毫秒为单位花费的时间 + */ + void set_gas_heater(uint16_t temp, uint16_t t); +``` + +## 历史 + +- 2025/09/29 - WS63版本 V1.0.0 - Written by Martin(Martin@dfrobot.com), 2025. + +- 2017/12/04 - Arduino版本 V2.0.0 - Written by Frank(jiehan.guo@dfrobot.com), 2017. +- 2017/09/04 - Arduino版本 V1.0.0 - Written by Frank(jiehan.guo@dfrobot.com), 2017. diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/resources/images/SEN0248.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/resources/images/SEN0248.png new file mode 100644 index 0000000000000000000000000000000000000000..97e5ab8328c4f3f3e84331c545a3c68ed7cdaf28 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/dfrobot_bme680/resources/images/SEN0248.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_1.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d4edcc7d1a9df95f480ab245068fa9e6e1b30c2e Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_1.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_2.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_2.png new file mode 100644 index 0000000000000000000000000000000000000000..a3c55971788aa6bd4bdb5a923d74f4c90d47f346 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_2.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_3.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_3.png new file mode 100644 index 0000000000000000000000000000000000000000..7e4890bf42df48add5b0c875345d79a16645aa1f Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_3.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_4.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_4.png new file mode 100644 index 0000000000000000000000000000000000000000..a39af3df6a5f66216270ab9403545aba8c9806c7 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/images/680_4.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..153af2417c8ac047a43ab1996f4927467251d812 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_bme680/readme.md @@ -0,0 +1,31 @@ +# beetle_bme680 + +## 一、介绍 + +dfrobot_bme680传感器驱动库提供了对BME680环境传感器的完整支持,包括温度、湿度、气压、海拔高度和气体电阻的测量功能。该库支持I2C和SPI两种通信接口,提供了灵活的配置选项和校准功能,能够适应不同的应用场景需求。通过简洁的API接口,开发者可以快速集成环境监测功能到嵌入式系统中,并获取准确的环境数据参数。 + +详见:[[dfrobot_bme680] readme.md](./dfrobot_bme680/readme.md) + +## 二、实验流程 + +### 1、获取环境数据 - I2C通信 + +- 执行Clean命令清理资源 +- 打开KConfig配置BME680-IIC相关引脚信息: + +![img](.\images\680_1.png) + +- 编译、烧录后观察环境参数打印: + +![img](.\images\680_2.png) + +### 2、获取环境数据 - SPI通信 + +- 执行Clean命令清理资源 +- 打开KConfig配置BME680-SPI相关引脚信息(此例程所用MOSI引脚与boot相关,烧录示例时请先断开该引脚的连接,等待烧录完成后重新连接;复位时同理): + +![img](.\images\680_3.png) + +- 编译、烧录后观察环境参数打印: + +![img](.\images\680_4.png) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_button/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_button/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..82f09e70ddcb18838f47e675922ff61084613791 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_button/CMakeLists.txt @@ -0,0 +1,4 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/button.c +) +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_button/button.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_button/button.c new file mode 100644 index 0000000000000000000000000000000000000000..a773abc3bea6edd6b5bfb7f8312c05f77874a5f6 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_button/button.c @@ -0,0 +1,75 @@ +/**! + * @file button.c + * @brief Onboard button interrupt example: Pressing the button toggles the onboard LED on or off. + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + */ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "hal_gpio.h" +#include "watchdog.h" +#include "app_init.h" + +#define BSP_LED 2 // BLUE +#define BUTTON_GPIO 12 // 按键 + +#define BUTTON_TASK_STACK_SIZE 0x1000 +#define BUTTON_TASK_PRIO 17 + +static int g_led_state = 0; + +static void gpio_callback_func(pin_t pin, uintptr_t param) +{ + UNUSED(pin); + UNUSED(param); + g_led_state = !g_led_state; + printf("Button pressed.\r\n"); +} + +static void *button_task(const char *arg) +{ + unused(arg); + uapi_pin_set_mode(BSP_LED, HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(BSP_LED, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(BSP_LED, GPIO_LEVEL_LOW); + + uapi_pin_set_mode(BUTTON_GPIO, HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(BUTTON_GPIO, GPIO_DIRECTION_INPUT); + errcode_t ret = uapi_gpio_register_isr_func(BUTTON_GPIO, GPIO_INTERRUPT_FALLING_EDGE, gpio_callback_func); + if (ret != 0) { + uapi_gpio_unregister_isr_func(BUTTON_GPIO); + } + while (1) { + uapi_watchdog_kick(); // 喂狗,防止程序出现异常系统挂死 + if (g_led_state) { + uapi_gpio_set_val(BSP_LED, GPIO_LEVEL_HIGH); + } else { + uapi_gpio_set_val(BSP_LED, GPIO_LEVEL_LOW); + } + } + return NULL; +} + +static void button_entry(void) +{ + uint32_t ret; + osal_task *taskid; + // 创建任务调度 + osal_kthread_lock(); + // 创建任务1 + taskid = osal_kthread_create((osal_kthread_handler)button_task, NULL, "button_task", BUTTON_TASK_STACK_SIZE); + ret = osal_kthread_set_priority(taskid, BUTTON_TASK_PRIO); + if (ret != OSAL_SUCCESS) { + printf("create task1 failed .\n"); + } + osal_kthread_unlock(); +} + +/* Run the blinky_entry. */ +app_run(button_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e536bf887549f976dffef8c1fac3ff7d410bcb26 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/CMakeLists.txt @@ -0,0 +1,16 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_c4001/dfrobot_c4001.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_c4001) + + +if(DEFINED CONFIG_SAMPLE_SUPPORT_MOTION_SAMPLE) + add_subdirectory_if_exist(motion_detection_sample) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_MRANGE_SAMPLE) + add_subdirectory_if_exist(range_velocity_sample) +endif() + +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" ${HEADER_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a128a5026b4501f08e4f2de9a314982215cca8da --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/Kconfig @@ -0,0 +1,31 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +choice + prompt "Select Motion Detection or Range Velocity Sample" + default SAMPLE_SUPPORT_MOTION_SAMPLE + config SAMPLE_SUPPORT_MOTION_SAMPLE + bool "Support Motion Detection Sample." + + config SAMPLE_SUPPORT_MRANGE_SAMPLE + bool "Support Range Velocity Sample." + +endchoice + +config UART_BUS_ID + int "Choose UART BUS id." + default 2 + +config RADAR_UART_BAUD + int "Choose UART baud." + default 9600 + +config RADAR_UART_TX_PIN + int "Choose UART TX pin." + default 8 + +config RADAR_UART_RX_PIN + int "Choose UART RX pin." + default 7 + \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/dfrobot_c4001.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/dfrobot_c4001.c new file mode 100644 index 0000000000000000000000000000000000000000..5630c40cc93df9a84a5830ee20621576d8ff3705 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/dfrobot_c4001.c @@ -0,0 +1,637 @@ +/*! + * @file dfrobot_c4001.c + * @brief Define the basic structure of the DFRobot_C4001 class, the implementation of the basic methods + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-09-29 + * @url https://github.com/DFRobot/DFRobot_C4001 + */ +#include "dfrobot_c4001.h" + +static s_private_data_t g_buffer; + +#define TIME_OUT C4001_TIME_OUT_MS ///< time out +#define SENSOR_UART_ID 2 // 替换成你初始化时使用的 UART ID +#define DELAY_MS C4001_DELAY_MS_BASE + +#define THE_UART_TRANSFER_SIZE C4001_UART_TRANSFER_SIZE +static uint8_t g_app_uart_rx_buff[THE_UART_TRANSFER_SIZE] = {0}; +static uart_buffer_config_t g_app_uart_buffer_config = {.rx_buffer = g_app_uart_rx_buff, + .rx_buffer_size = THE_UART_TRANSFER_SIZE}; + +static void write_reg(uint8_t reg, const uint8_t *data, uint8_t len) +{ + (void)reg; + if (len > sizeof(g_app_uart_rx_buff)) { + osal_printk("UART write error: len too large\r\n"); + return; + } + + // 拷贝数据到全局 buffer + memcpy(g_app_uart_rx_buff, data, len); + + // 调用底层写接口发送 + int ret = uapi_uart_write(SENSOR_UART_ID, g_app_uart_rx_buff, len, 0); + if (ret < 0) { + osal_printk("UART write error: %d\r\n", ret); + } +} + +static int16_t read_reg(uint8_t reg, uint8_t *data, uint8_t len) +{ + (void)reg; + + if (len > sizeof(g_app_uart_rx_buff)) { + osal_printk("UART read error: len too large\r\n"); + return -1; + } + + uint16_t received = 0; + uint32_t start = uapi_systick_get_ms(); + + while (uapi_systick_get_ms() - start < TIME_OUT) { + // 把数据直接读到 g_app_uart_rx_buff + int ret = uapi_uart_read(SENSOR_UART_ID, g_app_uart_rx_buff + received, len - received, 0); + if (ret > 0) { + received += ret; + if (received >= len) { + break; // 收够数据 + } + } + } + + if (received > 0) { + // 拷贝到用户缓冲 + memcpy(data, g_app_uart_rx_buff, received); + } + + return received; +} + +static s_response_data_t analysis_response(uint8_t *data, uint8_t len, uint8_t count) +{ + s_response_data_t response_data; + uint8_t space[C4001_SPACE_ARRAY_SIZE] = {0}; + uint8_t i = 0; + uint8_t j = 0; + for (i = 0; i < len; i++) { + if (data[i] == C4001_STR_CHAR_R && data[i + C4001_ARRAY_INDEX_1] == C4001_STR_CHAR_E && + data[i + C4001_ARRAY_INDEX_2] == C4001_STR_CHAR_S) { + break; + } + } + if (i == len || i == C4001_ARRAY_INDEX_0) { + response_data.status = false; + } else { + response_data.status = true; + for (j = 0; i < len; i++) { + if (data[i] == C4001_STR_CHAR_SPACE) { + space[j++] = i + C4001_ARRAY_INDEX_1; + } + } + if (j != C4001_ARRAY_INDEX_0) { + response_data.response1 = atof((const char *)(data + space[C4001_ARRAY_INDEX_0])); + if (j >= C4001_ARRAY_INDEX_2) { + response_data.response2 = atof((const char *)(data + space[C4001_ARRAY_INDEX_1])); + } + if (count == C4001_ARRAY_INDEX_3) { + response_data.response3 = atof((const char *)(data + space[C4001_ARRAY_INDEX_2])); + } + } else { + response_data.response1 = 0.0; + response_data.response2 = 0.0; + } + } + return response_data; +} + +static s_all_data_t analysis_data(uint8_t *data, uint8_t len) +{ + s_all_data_t all_data; + uint8_t location = 0; + memset(&all_data, 0, sizeof(s_all_data_t)); + for (uint8_t i = 0; i < len; i++) { + if (data[i] == C4001_STR_CHAR_DOLLAR) { + location = i; + break; + } + } + if (location == len) { + return all_data; + } + if (strncmp((const char *)(data + location), "$DFHPD", C4001_STR_DFHPD_LEN) == 0) { + all_data.sta.work_mode = EXITMODE; + all_data.sta.work_status = C4001_ARRAY_INDEX_1; + all_data.sta.init_status = C4001_ARRAY_INDEX_1; + if (data[location + C4001_STR_POS_DFHPD_EXIST_OFFSET] == '1') { + all_data.exist = C4001_ARRAY_INDEX_1; + } else { + all_data.exist = C4001_ARRAY_INDEX_0; + } + } else if (strncmp((const char *)(data + location), "$DFDMD", C4001_STR_DFDMD_LEN) == 0) { + all_data.sta.work_mode = SPEEDMODE; + all_data.sta.work_status = C4001_ARRAY_INDEX_1; + all_data.sta.init_status = C4001_ARRAY_INDEX_1; + char *token; + char *parts[C4001_PARTS_ARRAY_SIZE]; // Let's say there are at most 10 parts + int index = 0; // Used to track the number of parts stored + token = strtok((char *)(data + location), ","); + while (token != NULL) { + parts[index] = token; // Stores partial Pointers in an array + if (index++ > C4001_STR_POS_PARTS_INDEX_MAX) { + break; + } + token = strtok(NULL, ","); // Continue to extract the next section + } + all_data.target.number = atoi(parts[C4001_ARRAY_INDEX_1]); + all_data.target.range = atof(parts[C4001_ARRAY_INDEX_3]) * C4001_RANGE_FROM_METER_MULTIPLIER; + all_data.target.speed = atof(parts[C4001_ARRAY_INDEX_4]) * C4001_RANGE_FROM_METER_MULTIPLIER; + all_data.target.energy = atof(parts[C4001_ARRAY_INDEX_5]); + } else { + } + return all_data; +} + +static bool sensor_stop(void) +{ + uint8_t len = 0; + uint8_t temp[C4001_TEMP_BUFFER_SIZE] = {0}; + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)STOP_SENSOR, strlen(STOP_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_1000_MS); + len = read_reg(C4001_ARRAY_INDEX_0, temp, C4001_TEMP_BUFFER_SIZE); + while (C4001_ARRAY_INDEX_1) { + if (len != C4001_ARRAY_INDEX_0) { + if (strstr((const char *)temp, "sensorStop") != NULL) { + return true; + } + } + memset(temp, 0, C4001_TEMP_BUFFER_SIZE); + uapi_systick_delay_ms(C4001_DELAY_400_MS); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)STOP_SENSOR, strlen(STOP_SENSOR)); + len = read_reg(C4001_ARRAY_INDEX_0, temp, C4001_TEMP_BUFFER_SIZE); + } +} + +static s_response_data_t write_read_cmd(char *cmd1, uint8_t count) +{ + uint8_t len = 0; + uint8_t temp[C4001_TEMP_BUFFER_SIZE] = {0}; + s_response_data_t response_data; + sensor_stop(); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)cmd1, strlen(cmd1)); + uapi_systick_delay_ms(C4001_DELAY_100_MS); + len = read_reg(C4001_ARRAY_INDEX_0, temp, C4001_TEMP_BUFFER_SIZE); + response_data = analysis_response(temp, len, count); + uapi_systick_delay_ms(C4001_DELAY_100_MS); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)START_SENSOR, strlen(START_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_100_MS); + return response_data; +} + +static void write_cmd(char *cmd1, char *cmd2, uint8_t count) +{ + sensor_stop(); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)cmd1, strlen(cmd1)); + uapi_systick_delay_ms(C4001_DELAY_100_MS); + if (count > C4001_ARRAY_INDEX_1) { + uapi_systick_delay_ms(C4001_DELAY_100_MS); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)cmd2, strlen(cmd2)); + uapi_systick_delay_ms(C4001_DELAY_100_MS); + } + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)SAVE_CONFIG, strlen(SAVE_CONFIG)); + uapi_systick_delay_ms(C4001_DELAY_100_MS); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)START_SENSOR, strlen(START_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_100_MS); +} + +void dfrobot_c4001_init(uint32_t baud, uint8_t txpin, uint8_t rxpin, uint8_t uart_id) +{ + // 1. 配置引脚 +#if defined(CONFIG_PINCTRL_SUPPORT_IE) + uapi_pin_set_ie(rxpin, PIN_IE_1); +#endif + uapi_pin_set_mode(txpin, PIN_MODE_2); + uapi_pin_set_mode(rxpin, PIN_MODE_2); + + // 2. 配置 UART 属性 + uart_attr_t attr = { + .baud_rate = baud, .data_bits = UART_DATA_BIT_8, .stop_bits = UART_STOP_BIT_1, .parity = UART_PARITY_NONE}; + + uart_pin_config_t pin_config = {.tx_pin = txpin, .rx_pin = rxpin, .cts_pin = PIN_NONE, .rts_pin = PIN_NONE}; + + uapi_uart_deinit(uart_id); + uapi_uart_init(uart_id, &pin_config, &attr, NULL, &g_app_uart_buffer_config); +} + +s_sensor_status_t get_status(void) +{ + s_sensor_status_t data; + uint8_t temp[C4001_STATUS_BUFFER_SIZE] = {0}; + uint8_t len = 0; + + s_all_data_t all_data; + read_reg(C4001_ARRAY_INDEX_0, temp, C4001_STATUS_BUFFER_SIZE); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)START_SENSOR, strlen(START_SENSOR)); + while (len == C4001_ARRAY_INDEX_0) { + uapi_systick_delay_ms(C4001_DELAY_1000_MS); + len = read_reg(C4001_ARRAY_INDEX_0, temp, C4001_STATUS_BUFFER_SIZE); + all_data = analysis_data(temp, len); + } + data.work_status = all_data.sta.work_status; + data.work_mode = all_data.sta.work_mode; + data.init_status = all_data.sta.init_status; + + return data; +} + +bool motion_detection(void) +{ + static bool old = false; + uint8_t status = C4001_ARRAY_INDEX_0; + uint8_t len = 0; + uint8_t temp[C4001_STATUS_BUFFER_SIZE] = {0}; + s_all_data_t data; + len = read_reg(C4001_ARRAY_INDEX_0, temp, C4001_STATUS_BUFFER_SIZE); + data = analysis_data(temp, len); + if (data.exist) { + old = (bool)status; + return (bool)data.exist; + } else { + return (bool)old; + } +} + +void set_sensor(e_set_mode_t mode) +{ + if (mode == STARTSEN) { + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)START_SENSOR, strlen(START_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_200_MS); // must timer + } else if (mode == STOPSEN) { + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)STOP_SENSOR, strlen(STOP_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_200_MS); // must timer + } else if (mode == RESETSEN) { + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)RESET_SENSOR, strlen(RESET_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_1500_MS); // must timer + } else if (mode == SAVEPARAMS) { + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)STOP_SENSOR, strlen(STOP_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_200_MS); // must timer + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)SAVE_CONFIG, strlen(SAVE_CONFIG)); + uapi_systick_delay_ms(C4001_DELAY_800_MS); // must timer + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)START_SENSOR, strlen(START_SENSOR)); + } else if (mode == RECOVERSEN) { + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)STOP_SENSOR, strlen(STOP_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_200_MS); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)RECOVER_SENSOR, strlen(RECOVER_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_800_MS); // must timer + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)START_SENSOR, strlen(START_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_500_MS); + } +} + +bool set_sensor_mode(e_mode_t mode) +{ + sensor_stop(); + if (mode == EXITMODE) { + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)EXIST_MODE, strlen(EXIST_MODE)); + uapi_systick_delay_ms(C4001_DELAY_50_MS); + } else { + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)SPEED_MODE, strlen(SPEED_MODE)); + uapi_systick_delay_ms(C4001_DELAY_50_MS); + } + uapi_systick_delay_ms(C4001_DELAY_50_MS); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)SAVE_CONFIG, strlen(SAVE_CONFIG)); + uapi_systick_delay_ms(C4001_DELAY_500_MS); + write_reg(C4001_ARRAY_INDEX_0, (uint8_t *)START_SENSOR, strlen(START_SENSOR)); + uapi_systick_delay_ms(C4001_DELAY_100_MS); + return true; +} + +bool set_trig_sensitivity(uint8_t sensitivity) +{ + if (sensitivity > C4001_SENSITIVITY_MAX) { + return false; + } + + char data[] = "setSensitivity 255 1"; // 分配在栈上,可写 + data[C4001_STR_POS_SENSITIVITY_TRIG_OFFSET] = sensitivity + '0'; // 修改有效 + write_cmd(data, data, (uint8_t)C4001_ARRAY_INDEX_1); + return true; +} + +uint8_t get_trig_sensitivity(void) +{ + s_response_data_t response_data; + uint8_t temp[C4001_STATUS_BUFFER_SIZE] = {0}; + read_reg(C4001_ARRAY_INDEX_0, temp, C4001_STATUS_BUFFER_SIZE); + char *data = "getSensitivity"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_1); + if (response_data.status) { + return response_data.response1; + } + return C4001_ARRAY_INDEX_0; +} + +bool set_keep_sensitivity(uint8_t sensitivity) +{ + if (sensitivity > C4001_SENSITIVITY_MAX) { + return false; + } + + char data[] = "setSensitivity 1 255"; + data[C4001_STR_POS_SENSITIVITY_KEEP_OFFSET] = sensitivity + '0'; + write_cmd(data, data, (uint8_t)C4001_ARRAY_INDEX_1); + return true; +} + +uint8_t get_keep_sensitivity(void) +{ + s_response_data_t response_data; + uint8_t temp[C4001_STATUS_BUFFER_SIZE] = {0}; + read_reg(C4001_ARRAY_INDEX_0, temp, C4001_STATUS_BUFFER_SIZE); + char *data = "getSensitivity"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_1); + if (response_data.status) { + return response_data.response2; + } + return C4001_ARRAY_INDEX_0; +} + +bool set_delay(uint8_t trig, uint16_t keep) +{ + if (trig > C4001_TRIG_DELAY_MAX) { + return false; + } + if (keep < C4001_KEEP_DELAY_MIN || keep > C4001_KEEP_DELAY_MAX) { + return false; + } + + // trig: 百分比 -> 秒 (trig * 0.01) + float trig_val = trig * C4001_TRIG_DELAY_TO_SEC_MULTIPLIER; + // keep: 乘0.5 + float keep_val = keep * C4001_KEEP_DELAY_TO_SEC_MULTIPLIER; + + char cmd[C4001_CMD_BUFFER_SIZE] = {0}; + // 格式化命令字符串 + snprintf(cmd, sizeof(cmd), "setLatency %.1f %.1f", trig_val, keep_val); + + // 调用底层写命令函数 + write_cmd(cmd, cmd, C4001_ARRAY_INDEX_1); + + return true; +} + +uint8_t get_trig_delay(void) +{ + s_response_data_t response_data; + char *data = "getLatency"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_1); + if (response_data.status) { + return response_data.response1 * C4001_TRIG_DELAY_FROM_SEC_MULTIPLIER; + } + return C4001_ARRAY_INDEX_0; +} + +uint16_t get_keep_timeout(void) +{ + s_response_data_t response_data; + char *data = "getLatency"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_2); + if (response_data.status) { + return response_data.response2 * C4001_KEEP_DELAY_FROM_SEC_MULTIPLIER; + } + return C4001_ARRAY_INDEX_0; +} + +bool set_detection_range(uint16_t min, uint16_t max, uint16_t trig) +{ + if (max < C4001_RANGE_MAX_MIN || max > C4001_RANGE_MAX_MAX) { + return false; + } + if (min < C4001_RANGE_MIN_MIN || min > max) { + return false; + } + + float min_val = min / C4001_RANGE_TO_METER_DIVISOR; + float max_val = max / C4001_RANGE_TO_METER_DIVISOR; + float trig_val = trig / C4001_RANGE_TO_METER_DIVISOR; + + char data1[C4001_CMD_BUFFER_SIZE] = {0}; + char data2[C4001_CMD_BUFFER_SIZE] = {0}; + + // 拼接命令 + snprintf(data1, sizeof(data1), "setRange %.2f %.2f", min_val, max_val); + snprintf(data2, sizeof(data2), "setTrigRange %.2f", trig_val); + + // 发送命令 + write_cmd(data1, data2, C4001_ARRAY_INDEX_2); + + return true; +} + +uint16_t get_trig_range(void) +{ + s_response_data_t response_data; + char *data = "getTrigRange"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_1); + if (response_data.status) { + return response_data.response1 * C4001_RANGE_FROM_METER_MULTIPLIER; + } + return C4001_ARRAY_INDEX_0; +} + +uint16_t get_max_range(void) +{ + s_response_data_t response_data; + char *data = "getRange"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_2); + if (response_data.status) { + return response_data.response2 * C4001_RANGE_FROM_METER_MULTIPLIER; + } + return C4001_ARRAY_INDEX_0; +} + +uint16_t get_min_range(void) +{ + s_response_data_t response_data; + char *data = "getRange"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_2); + if (response_data.status) { + return response_data.response1 * C4001_RANGE_FROM_METER_MULTIPLIER; + } + return C4001_ARRAY_INDEX_0; +} + +uint8_t get_target_number(void) +{ + static uint8_t flash_number = C4001_ARRAY_INDEX_0; + uint8_t len = 0; + uint8_t temp[C4001_STATUS_BUFFER_SIZE] = {0}; + s_all_data_t data; + len = read_reg(C4001_ARRAY_INDEX_0, temp, C4001_STATUS_BUFFER_SIZE); + data = analysis_data(temp, len); + if (data.target.number != C4001_ARRAY_INDEX_0) { + flash_number = C4001_ARRAY_INDEX_0; + g_buffer.number = data.target.number; + g_buffer.range = data.target.range / C4001_RANGE_TO_METER_DIVISOR; + g_buffer.speed = data.target.speed / C4001_RANGE_TO_METER_DIVISOR; + g_buffer.energy = data.target.energy; + } else { + g_buffer.number = C4001_ARRAY_INDEX_1; + if (flash_number++ > C4001_FLASH_COUNTER_THRESHOLD) { + g_buffer.number = C4001_ARRAY_INDEX_0; + g_buffer.range = 0; + g_buffer.speed = 0; + g_buffer.energy = 0; + } + } + return data.target.number; +} + +float get_target_speed(void) +{ + return g_buffer.speed; +} + +float get_target_range(void) +{ + return g_buffer.range; +} + +uint32_t get_target_energy(void) +{ + return g_buffer.energy; +} + +bool set_detect_thres(uint16_t min, uint16_t max, uint16_t thres) +{ + if (max > C4001_RANGE_MAX_LIMIT) { + return false; + } + if (min > max) { + return false; + } + + float min_val = min / C4001_RANGE_TO_METER_DIVISOR; + float max_val = max / C4001_RANGE_TO_METER_DIVISOR; + + char data1[C4001_CMD_BUFFER_SIZE] = {0}; + char data2[C4001_CMD_BUFFER_SIZE] = {0}; + + // 拼接字符串 + snprintf(data1, sizeof(data1), "setRange %.2f %.2f", min_val, max_val); + snprintf(data2, sizeof(data2), "setThrFactor %u", thres); + + // 发送命令 + write_cmd(data1, data2, C4001_ARRAY_INDEX_2); + + return true; +} + +bool set_io_polarity(uint8_t value) +{ + if (value > C4001_IO_POLARITY_MAX) { + return false; + } + + char data[C4001_IO_BUFFER_SIZE] = {0}; // 可写缓冲 + snprintf(data, sizeof(data), "setGpioMode %d", value); // 拼接字符串 + write_cmd(data, data, (uint8_t)C4001_ARRAY_INDEX_1); + return true; +} + +uint8_t get_io_polarity(void) +{ + s_response_data_t response_data; + char *data = "getGpioMode 1"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_2); + if (response_data.status) { + return response_data.response2; + } + return C4001_ARRAY_INDEX_0; +} + +bool set_pwm(uint8_t pwm1, uint8_t pwm2, uint8_t timer) +{ + if (pwm1 > C4001_PWM_MAX || pwm2 > C4001_PWM_MAX) { + return false; + } + + char data[C4001_CMD_BUFFER_SIZE] = {0}; + + // 拼接成命令字符串,例如:set_pwm 50 75 10 + snprintf(data, sizeof(data), "setPwm %u %u %u", pwm1, pwm2, timer); + + // 发送命令 + write_cmd(data, data, C4001_ARRAY_INDEX_1); + + return true; +} + +s_pwm_data_t get_pwm(void) +{ + s_pwm_data_t pwm_data; + memset(&pwm_data, C4001_ARRAY_INDEX_0, sizeof(s_pwm_data_t)); + + s_response_data_t response_data; + char *data = "getPwm"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_3); + if (response_data.status) { + pwm_data.pwm1 = response_data.response1; + pwm_data.pwm2 = response_data.response2; + pwm_data.timer = response_data.response3; + } + return pwm_data; +} + +uint16_t get_t_min_range(void) +{ + s_response_data_t response_data; + char *data = "getRange"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_1); + if (response_data.status) { + return response_data.response1 * C4001_RANGE_FROM_METER_MULTIPLIER; + } + return C4001_ARRAY_INDEX_0; +} + +uint16_t get_t_max_range(void) +{ + s_response_data_t response_data; + char *data = "getRange"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_2); + if (response_data.status) { + return response_data.response2 * C4001_RANGE_FROM_METER_MULTIPLIER; + } + return C4001_ARRAY_INDEX_0; +} + +uint16_t get_thres_range(void) +{ + s_response_data_t response_data; + char *data = "getThrFactor"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_1); + if (response_data.status) { + return response_data.response1; + } + return C4001_ARRAY_INDEX_0; +} + +void set_fretting_detection(e_switch_t sta) +{ + char data[C4001_IO_BUFFER_SIZE] = {0}; + snprintf(data, sizeof(data), "setMicroMotion %d", sta); + write_cmd(data, data, (uint8_t)C4001_ARRAY_INDEX_1); +} + +e_switch_t get_fretting_detection(void) +{ + s_response_data_t response_data; + char *data = "getMicroMotion"; + response_data = write_read_cmd(data, (uint8_t)C4001_ARRAY_INDEX_1); + if (response_data.status) { + return (e_switch_t)response_data.response1; + } + return (e_switch_t)C4001_ARRAY_INDEX_0; +} diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/dfrobot_c4001.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/dfrobot_c4001.h new file mode 100644 index 0000000000000000000000000000000000000000..77fa23cbb482cdd6f1aeaa073456033317b9d68f --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/dfrobot_c4001.h @@ -0,0 +1,451 @@ +/*! + * @file dfrobot_c4001.h + * @brief Define the basic structure of the DFRobot_C4001 class, the implementation of the basic methods + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-09-29 + * @url https://github.com/DFRobot/DFRobot_C4001 + */ +#ifndef __DFROBOT_C4001_H__ +#define __DFROBOT_C4001_H__ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "systick.h" +#include "osal_debug.h" +#include "watchdog.h" +#include "app_init.h" +#include "uart.h" + +#include +#include +#include +#include + +/** + * @struct s_sensor_status_t + * @brief sensor status + * @note sensor status + */ +typedef struct { + uint8_t work_status; + uint8_t work_mode; + uint8_t init_status; +} s_sensor_status_t; + +/** + * @struct s_private_data_t + * @brief speed mode data + */ +typedef struct { + uint8_t number; + float speed; + float range; + uint32_t energy; +} s_private_data_t; + +/** + * @struct s_response_data_t + * @brief response data + */ +typedef struct { + bool status; + float response1; + float response2; + float response3; +} s_response_data_t; + +/** + * @struct s_pwm_data_t + * @brief config pwm data param + */ +typedef struct { + uint8_t pwm1; + uint8_t pwm2; + uint8_t timer; +} s_pwm_data_t; + +/** + * @struct s_all_data_t + * @brief sensor return data + */ +typedef struct { + uint8_t exist; + s_sensor_status_t sta; + s_private_data_t target; +} s_all_data_t; + +/** + * @enum e_mode_t + * @brief sensor work mode + */ +typedef enum { + EXITMODE = 0x00, + SPEEDMODE = 0x01, +} e_mode_t; + +/** + * @enum e_switch_t + * @brief Micromotion detection switch + */ +typedef enum { + SWITCH_ON = 0x01, + SWITCH_OFF = 0x00, +} e_switch_t; + +/** + * @enum e_set_mode_t + * @brief Set parameters for the sensor working status + */ +typedef enum { + STARTSEN = 0x55, + STOPSEN = 0x33, + RESETSEN = 0xCC, + RECOVERSEN = 0xAA, + SAVEPARAMS = 0x5C, + CHANGEMODE = 0x3B, +} e_set_mode_t; + +#define START_SENSOR "sensorStart" +#define STOP_SENSOR "sensorStop" +#define SAVE_CONFIG "saveConfig" +#define RECOVER_SENSOR "resetCfg" ///< factory data reset +#define RESET_SENSOR "resetSystem" ///< RESET_SENSOR +#define SPEED_MODE "setRunApp 1" +#define EXIST_MODE "setRunApp 0" + +/** Timeout and delay constants */ +#define C4001_TIME_OUT_MS UINT8_C(100) +#define C4001_DELAY_MS_BASE UINT8_C(1) +#define C4001_DELAY_50_MS (50 * C4001_DELAY_MS_BASE) +#define C4001_DELAY_100_MS (100 * C4001_DELAY_MS_BASE) +#define C4001_DELAY_200_MS (200 * C4001_DELAY_MS_BASE) +#define C4001_DELAY_400_MS (400 * C4001_DELAY_MS_BASE) +#define C4001_DELAY_500_MS (500 * C4001_DELAY_MS_BASE) +#define C4001_DELAY_800_MS (800 * C4001_DELAY_MS_BASE) +#define C4001_DELAY_1000_MS (1000 * C4001_DELAY_MS_BASE) +#define C4001_DELAY_1500_MS (1500 * C4001_DELAY_MS_BASE) + +/** Buffer size constants */ +#define C4001_UART_TRANSFER_SIZE UINT16_C(200) +#define C4001_TEMP_BUFFER_SIZE UINT8_C(200) +#define C4001_STATUS_BUFFER_SIZE UINT8_C(100) +#define C4001_CMD_BUFFER_SIZE UINT8_C(64) +#define C4001_IO_BUFFER_SIZE UINT8_C(32) +#define C4001_SPACE_ARRAY_SIZE UINT8_C(5) +#define C4001_PARTS_ARRAY_SIZE UINT8_C(10) + +/** Array index constants */ +#define C4001_ARRAY_INDEX_0 UINT8_C(0) +#define C4001_ARRAY_INDEX_1 UINT8_C(1) +#define C4001_ARRAY_INDEX_2 UINT8_C(2) +#define C4001_ARRAY_INDEX_3 UINT8_C(3) +#define C4001_ARRAY_INDEX_4 UINT8_C(4) +#define C4001_ARRAY_INDEX_5 UINT8_C(5) +#define C4001_ARRAY_INDEX_7 UINT8_C(7) +#define C4001_ARRAY_INDEX_8 UINT8_C(8) +#define C4001_ARRAY_INDEX_9 UINT8_C(9) +#define C4001_ARRAY_INDEX_10 UINT8_C(10) +#define C4001_ARRAY_INDEX_15 UINT8_C(15) +#define C4001_ARRAY_INDEX_19 UINT8_C(19) + +/** String parsing constants */ +#define C4001_STR_CHAR_R 'R' +#define C4001_STR_CHAR_E 'e' +#define C4001_STR_CHAR_S 's' +#define C4001_STR_CHAR_SPACE ' ' +#define C4001_STR_CHAR_DOLLAR '$' +#define C4001_STR_DFHPD_LEN (strlen("$DFHPD")) +#define C4001_STR_DFDMD_LEN (strlen("$DFDMD")) + +/** Sensitivity and range limits */ +#define C4001_SENSITIVITY_MAX UINT8_C(9) +#define C4001_TRIG_DELAY_MAX UINT16_C(200) +#define C4001_KEEP_DELAY_MIN UINT16_C(4) +#define C4001_KEEP_DELAY_MAX UINT16_C(3000) +#define C4001_RANGE_MAX_LIMIT UINT16_C(2500) +#define C4001_RANGE_MAX_MIN UINT16_C(240) +#define C4001_RANGE_MAX_MAX UINT16_C(2000) +#define C4001_RANGE_MIN_MIN UINT16_C(30) +#define C4001_RANGE_MIN_MAX UINT16_C(2000) +#define C4001_PWM_MAX UINT8_C(100) +#define C4001_TIMER_MAX UINT8_C(255) +#define C4001_IO_POLARITY_MAX UINT8_C(1) + +/** Float conversion constants */ +#define C4001_RANGE_TO_METER_DIVISOR 100.0f +#define C4001_TRIG_DELAY_TO_SEC_MULTIPLIER 0.01f +#define C4001_KEEP_DELAY_TO_SEC_MULTIPLIER 0.5f +#define C4001_TRIG_DELAY_FROM_SEC_MULTIPLIER 100.0f +#define C4001_KEEP_DELAY_FROM_SEC_MULTIPLIER 2.0f +#define C4001_RANGE_FROM_METER_MULTIPLIER 100.0f + +/** String position constants */ +#define C4001_STR_POS_DFHPD_EXIST_OFFSET UINT8_C(7) +#define C4001_STR_POS_SENSITIVITY_TRIG_OFFSET UINT8_C(19) +#define C4001_STR_POS_SENSITIVITY_KEEP_OFFSET UINT8_C(15) +#define C4001_STR_POS_PARTS_INDEX_MAX UINT8_C(8) + +/** Flash counter threshold */ +#define C4001_FLASH_COUNTER_THRESHOLD UINT8_C(10) + +/** + * @fn dfrobot_c4001_init + * @brief initialization function + * @param baud UART baud + * @param txpin UART TX pin + * @param rxpin UART RX pin + * @param uart_id UART bus id + */ +void dfrobot_c4001_init(uint32_t baud, uint8_t txpin, uint8_t rxpin, uint8_t uart_id); + +/** + * @fn motion_detection + * @brief motion Detection + * @return true or false + */ +bool motion_detection(void); + +/** + * @fn set_sensor + * @brief Set the Sensor object + * @param mode + * @n STARTSEN start collect + * @n STOPSEN stop collect + * @n RESETSEN reset sensor + * @n RECOVERSEN recover params + * @n SAVEPARAMS save config + * @n CHANGEMODE chagne mode + */ +void set_sensor(e_set_mode_t mode); + +/** + * @fn set_delay + * @brief Set the Delay object + * @param trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * @param keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + * @return true or false + */ +bool set_delay(uint8_t trig, uint16_t keep); + +/** + * @fn get_trig_delay + * @brief Get the Trig Delay object + * @return uint8_t + */ +uint8_t get_trig_delay(void); + +/** + * @fn get_keep_timeout + * @brief get keep timer out + * @return uint16_t + */ +uint16_t get_keep_timeout(void); + +/** + * @fn get_trig_range + * @brief Get the Trig Range object + * @n The triggering distance, in cm, ranges from 2.4 to 20m (240 to 2000). + * @n The actual configuration range does not exceed the maximum and minimum detection distance. + * @return uint16_t + */ +uint16_t get_trig_range(void); + +/** + * @fn get_max_range + * @brief Get the Max Range object + * @return uint16_t + */ +uint16_t get_max_range(void); + +/** + * @fn get_min_range + * @brief Get the Min Range object + * @return uint16_t + */ +uint16_t get_min_range(void); + +/** + * @fn set_detection_range + * @brief Set the Detection Range object + * @param min Detection range Minimum distance, unit cm, range 0.3~20m (30~2000), not exceeding max, otherwise the + * function is abnormal. + * @param max Detection range Maximum distance, unit cm, range 2.4~20m (240~2000) + * @param trig The trigger distance (unit: cm) ranges from 2.4 to 20m (240 to 2000). The actual configuration range does + * not exceed the maximum and minimum detection distance. + * @return true or false + */ +bool set_detection_range(uint16_t min, uint16_t max, uint16_t trig); + +/** + * @fn set_trig_sensitivity + * @brief Set trigger sensitivity, 0~9 + * @param sensitivity + * @return true or false + */ +bool set_trig_sensitivity(uint8_t sensitivity); + +/** + * @fn set_keep_sensitivity + * @brief Set the Keep Sensitivity object,0~9 + * @param sensitivity + * @return true or false + */ +bool set_keep_sensitivity(uint8_t sensitivity); + +/** + * @fn get_trig_sensitivity + * @brief Get the Trig Sensitivity object + * @return uint8_t + */ +uint8_t get_trig_sensitivity(void); + +/** + * @fn get_keep_sensitivity + * @brief Get the Keep Sensitivity object + * @return uint8_t + */ +uint8_t get_keep_sensitivity(void); + +/** + * @fn get_status + * @brief Get the Status object + * @return s_sensor_status_t + * @n work_status + * @n 0 stop + * @n 1 start + * @n work_mode + * @n 0 indicates presence detection + * @n 1 is speed measurement and ranging + * @n init_status + * @n 0 not init + * @n 1 init success + */ +s_sensor_status_t get_status(void); + +/** + * @fn set_io_polarity + * @brief Set the Io Polaity object + * @param value + * @n 0:Output low level when there is a target, output high level when there is no target + * @n 1: Output high level when there is a target, output low level when there is no target (default) + * @return true or false + */ +bool set_io_polarity(uint8_t value); + +/** + * @fn get_io_polarity + * @brief Get the Io Polaity object + * @return uint8_t The level of the signal output by the pin after the configured I/O port detects the target + */ +uint8_t get_io_polarity(void); + +/** + * @fn set_pwm + * @brief Set the Pwm object + * @param pwm1 When no target is detected, the duty cycle of the output signal of the OUT pin ranges from 0 to 100 + * @param pwm2 After the target is detected, the duty cycle of the output signal of the OUT pin ranges from 0 to 100 + * @param timer timer The value ranges from 0 to 255, corresponding to timer x 64ms + * @n For example, timer=20, it takes 20*64ms=1.28s for the duty cycle to change from pwm1 to pwm2. + * @return true or false + */ +bool set_pwm(uint8_t pwm1, uint8_t pwm2, uint8_t timer); + +/** + * @fn get_pwm + * @brief Get the Pwm object + * @return s_pwm_data_t + * @retval pwm1 When no target is detected, the duty cycle of the output signal of the OUT pin ranges from 0 to 100 + * @retval pwm2 After the target is detected, the duty cycle of the output signal of the OUT pin ranges from 0 to 100 + * @retval timer The value ranges from 0 to 255, corresponding to timer x 64ms + * @n For example, timer=20, it takes 20*64ms=1.28s for the duty cycle to change from pwm1 to pwm2. + */ +s_pwm_data_t get_pwm(void); + +/** + * @fn set_sensor_mode + * @brief Set the Sensor Mode object + * @param mode + * @return true or false + */ +bool set_sensor_mode(e_mode_t mode); + +/** + * @fn get_target_number + * @brief Get the Target Number object + * @return uint8_t + */ +uint8_t get_target_number(void); + +/** + * @fn get_target_speed + * @brief Get the Target Speed object + * @return float + */ +float get_target_speed(void); + +/** + * @fn get_target_range + * @brief Get the Target Range object + * @return float + */ +float get_target_range(void); + +/** + * @fn get_target_energy + * @brief Get the Target Energy object + * @return uint32_t + */ +uint32_t get_target_energy(void); + +/** + * @fn set_detect_thres + * @brief Set the Detect Thres object + * @param min Detection range Minimum distance, unit cm, range 0.3~20m (30~2000), not exceeding max, otherwise the + * function is abnormal. + * @param max Detection range Maximum distance, unit cm, range 2.4~20m (240~2000) + * @param thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + * @return true or false + */ +bool set_detect_thres(uint16_t min, uint16_t max, uint16_t thres); + +/** + * @fn get_t_min_range + * @brief get speed Min Range + * @return uint16_t + */ +uint16_t get_t_min_range(void); + +/** + * @fn get_t_max_range + * @brief get speed Max Range + * @return uint16_t + */ +uint16_t get_t_max_range(void); + +/** + * @fn get_thres_range + * @brief Get the Thres Range object + * @return uint16_t + */ +uint16_t get_thres_range(void); + +/** + * @fn set_fretting_detection + * @brief Set the Fretting Detection object + * @param sta + */ +void set_fretting_detection(e_switch_t sta); + +/** + * @fn get_fretting_detection + * @brief Get the Fretting Detection object + * @return e_switch_t + */ +e_switch_t get_fretting_detection(void); + +#endif diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..4c3e3fec344f5442a460a38fec07e9be3707a5a1 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/readme.md @@ -0,0 +1,280 @@ +# dfrobot_c4001 +这是一款人体存在传感器,如PIR传感器、红外传感器和超声波传感器,具有动静都能检测的特点,并且其抗干扰能力相对较强,不易受到温度变化、环境光变化和环境噪声等因素的影响。不论人体是静坐、睡觉还是运动,传感器都能够快速、灵敏地检测到其存在。 +例如,在公共智能厕所项目中,由于公共厕所环境相对复杂,容易受到环境噪声和温湿度变化的影响。然而,该款毫米波人体存在传感器可以在这种复杂的环境下实时监测公共厕所蹲位的使用情况,优化公共厕所的布局和资源分配,提高使用效率和用户体验。 + +![C4001 25m](./resources/images/mmWaveLadar.jpg) + +## 产品链接(https://www.dfrobot.com.cn/goods-3851.html) + + SKU:SEN0609 + +## 目录 + +* [概述](#概述) +* [API](#API) +* [历史](#历史) + +## 概述 + +提供一个WS63库,此库具有以下功能: + +- 判断人体是否存在 +- 获取前方物体的速度,距离
+ +## API + +```C++ + /** + * @fn DFRobot_C4001_INIT + * @brief 初始化函数 + * @param baud UART波特率 + * @param txpin UART TX引脚 + * @param rxpin UART RX引脚 + * @param uart_id UART总线标识符(如:0=UART0, 1=UART1, 2=UART2) + */ + void DFRobot_C4001_INIT(uint32_t baud, uint8_t txpin, uint8_t rxpin, uint8_t uart_id); + + /** + * @fn motionDetection + * @brief 运动检测 + * @return true + * @return false + */ + bool motionDetection(void); + + /** + * @fn setSensor + * @brief 设置传感器模式 + * @param mode + * @n STARTSEN 开始采集 + * @n STOPSEN 停止采集 + * @n RESETSEN 复位传感器 + * @n RECOVERSEN 恢复默认设置 + * @n SAVEPARAMS 保存配置 + * @n CHANGEMODE 切换模式 + */ + void setSensor(e_set_mode_t mode); + + /** + * @fn setDelay + * @brief 设置延时时间 + * @param trig 触发延时,单位0.01s,范围0~2s(0~200) + * @param keep 维持检测超时,单位0.5s,范围2~1500秒(4~3000) + * @return true + * @return false + */ + bool setDelay(uint8_t trig , uint16_t keep); + + /** + * @fn getTrigDelay + * @brief 获取物体的触发延时 + * @return uint8_t + */ + uint8_t getTrigDelay(void); + + /** + * @fn getKeepTimerout + * @brief 获取物体持续超时时间 + * @return uint16_t + */ + uint16_t getKeepTimerout(void); + + /** + * @fn getTrigRange + * @brief 存在模式,获取触发距离,单位cm,范围2.4~20m(240~2000),实际生效的配置范围不超出检测距离的最大距离和最小距离。 + * @return uint16_t + */ + uint16_t getTrigRange(void); + + /** + * @fn getMaxRange + * @brief 存在模式,获取检测范围最大距离,单位cm,范围2.4~20m(240~2000) + * @return uint16_t + */ + uint16_t getMaxRange(void); + + /** + * @fn getMinRange + * @brief 存在模式,获取检测范围最小距离,单位cm,范围0.3~20m(30~2000),不超过MAX_RANGE,否则功能不正常。 + * @return uint16_t + */ + uint16_t getMinRange(void); + + /** + * @fn setDetectionRange + * @brief 设置检测范围 + * @param min 检测范围最小距离,单位cm,范围0.3~20m(30~2000),不超过MAX_RANGE,否则功能不正常。 + * @param max 检测范围最大距离,单位cm,范围2.4~20m(240~2000) + * @param trig 触发距离,单位cm,范围2.4~20m(240~2000),实际生效的配置范围不超出检测距离的最大距离和最小距离。 + * @n 触发距离就是能触发无人到有人的距离, + * @n 例如配置最远检测距离10米,触发距离的值是6米,无人后需要到6米内才显示有人,只处于6-10米间不会出发为有人 + * @return true or false + */ + bool setDetectionRange(uint16_t min, uint16_t max); + + /** + * @fn setTrigSensitivity + * @brief 设置触发灵敏度,0~9 + * @param sensitivity + * @return true or false + */ + bool setTrigSensitivity(uint8_t sensitivity); + + /** + * @fn setKeepSensitivity + * @brief 设置维持灵敏度,0~9 + * @param sensitivity + * @return true or false + */ + bool setKeepSensitivity(uint8_t sensitivity); + + /** + * @fn getTrigSensitivity + * @brief 获取触发灵敏度 + * @return uint8_t + */ + uint8_t getTrigSensitivity(void); + + /** + * @fn getKeepSensitivity + * @brief 获取维持灵敏度 + * @return uint8_t + */ + uint8_t getKeepSensitivity(void); + + /** + * @fn getStatus + * @brief 获取模块当前状态 + * @return s_sensor_status_t + * @n workStatus + * @n 0 stop + * @n 1 start + * @n workMode + * @n 0 为存在检测 + * @n 1 为测速测距 + * @n initStatus + * @n 0 未初始化 + * @n 1 初始化完成 + */ + s_sensor_status_t getStatus(void); + + /** + * @fn setIoPolaity + * @brief 设置io口极性 + * @param value + * @n 0:有目标时输出低电平,无目标时输出高电平 + * @n 1:有目标时输出高电平,无目标时输出低电平(默认状态) + * @return true or false + */ + bool setIoPolaity(uint8_t value); + + /** + * @fn getIoPolaity + * @brief 获取io口极性状态 + * @return uint8_t 配置的I/O 口检测到目标后,引脚输出的信号电平 + */ + uint8_t getIoPolaity(void); + + /** + * @fn setPwm + * @brief 设置 pwm 周期 + * @param pwm1 未检测到目标时,OUT引脚输出信号的占空比,取值范围:0~100 + * @param pwm2 检测到目标后,OUT引脚输出信号的占空比,取值范围:0~100 + * @param timer 从pwm1 占空比渐变为pwm2 占空比的时间,取值范围:0~255,对应时间值 = timer*64ms + * @n 如timer=20,占空比从pwm1渐变为pwm2需要 20*64ms=1.28s。 + * @return true or false + */ + bool setPwm(uint8_t pwm1 , uint8_t pwm2, uint8_t timer); + + /** + * @fn getPwm + * @brief 获取pwm 周期 + * @return s_pwm_data_t + * @retval pwm1 未检测到目标时,OUT引脚输出信号的占空比,取值范围:0~100 + * @retval pwm2 检测到目标后,OUT引脚输出信号的占空比,取值范围:0~100 + * @retval timer 从pwm1 占空比渐变为pwm2 占空比的时间,取值范围:0~255,对应时间值 = timer*64ms + * @n 如timer=20,占空比从pwm1渐变为pwm2需要 20*64ms=1.28s。 + */ + s_pwm_data_t getPwm(void); + + /** + * @fn setSensorMode + * @brief 设置sensor 模式 + * @param mode 存在模式或者运动模式 + * @return true or false + */ + bool setSensorMode(e_mode_t mode); + + /** + * @fn getTargetNumber + * @brief 获取速度模式下的目标数量 + * @return uint8_t + */ + uint8_t getTargetNumber(void); + + /** + * @fn getTargetSpeed + * @brief 获取速度模式下的目标速度 + * @return float + */ + float getTargetSpeed(void); + + /** + * @fn getTargetRange + * @brief 获取速度模式下目标范围 + * @return float + */ + float getTargetRange(void); + + /** + * @fn setDetectThres + * @brief 设置检测的阈值 + * @param min 检测距离最小距离,单位厘米,范围0.3~20m(30~2000),不能超过max,否则功能异常。 + * @param max 最大探测距离,单位厘米,范围2.4~20m (240~2000) + * @param thres 目标检测阈值,无量纲单位0.1,范围0~6553.5 (0~65535) + * @return true or false + */ + bool setDetectThres(uint16_t min, uint16_t max, uint16_t thres); + + /** + * @fn getTMinRange + * @brief 运动模式,获取检测的最小范围 + * @return uint16_t + */ + uint16_t getTMinRange(void); + + /** + * @fn getTMaxRange + * @brief 运动模式,获取检测的最大范围 + * @return uint16_t + */ + uint16_t getTMaxRange(void); + + /** + * @fn getThresRange + * @brief 运动模式,获取阈值配置的范围 + * @return uint16_t + */ + uint16_t getThresRange(void); + + /** + * @fn setFrettingDetection + * @brief 设置微动检测 + * @param sta 枚举类型 + */ + void setFrettingDetection(e_switch_t sta); + + /** + * @fn getFrettingDetection + * @brief 获取微动检测的配置状态 + * @return e_switch_t + */ + e_switch_t getFrettingDetection(void); +``` + +## 历史 + +- 2025/09/29 - WS63版本 V1.0.0 - Written by [Martin](Martin@dfrobot.com), 2025. + +- 2024/02/26 - Arduino版本 V1.0.0 - Written by [ZhixinLiu](zhixin.liu@dfrobot.com), 2024. + diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/resources/images/mmWaveLadar.jpg b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/resources/images/mmWaveLadar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..253177d0abecec5d756800d83c724754ff4ced50 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/dfrobot_c4001/resources/images/mmWaveLadar.jpg differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img1.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img1.png new file mode 100644 index 0000000000000000000000000000000000000000..bcd76d58dce4f6e82e02602326c969ebb0b95088 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img1.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img2.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img2.png new file mode 100644 index 0000000000000000000000000000000000000000..40894d7227c8c5b95457f6f407b74aff1cacc51e Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img2.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img3.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img3.png new file mode 100644 index 0000000000000000000000000000000000000000..9edf34730ae101ce02afbaba30d9b2ab1372e35a Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img3.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img4.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img4.png new file mode 100644 index 0000000000000000000000000000000000000000..73d817d91e4cbe213d7913122328353824d39e89 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/images/c4001_img4.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/motion_detection_sample/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/motion_detection_sample/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..28e56d8e15afe02fbc7fae5011dda39d20557f23 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/motion_detection_sample/CMakeLists.txt @@ -0,0 +1 @@ +set(SOURCES "${SOURCES}" "${CMAKE_CURRENT_SOURCE_DIR}/motion_detection_sample.c" PARENT_SCOPE) \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/motion_detection_sample/motion_detection_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/motion_detection_sample/motion_detection_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..b2ce66ce1c6f1ec1996cf1fcab4aa6660f681c3f --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/motion_detection_sample/motion_detection_sample.c @@ -0,0 +1,130 @@ +/*! + * @file motion_detection_sample.c + * @brief Example of radar detecting whether an object is moving + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-09-29 + * @url https://github.com/dfrobot/DFRobot_C4001 + */ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "systick.h" +#include "osal_debug.h" +#include "watchdog.h" +#include "app_init.h" +#include "uart.h" +#include "dfrobot_c4001.h" + +#define MINRANGE 30 +#define MAXRANGE 1000 +#define TRIGRANGE 1000 +#define TRIG_SENSITIVITY 1 +#define KEEP_SENSITIVITY 2 +#define TRIG_DELAY 100 +#define KEEP_TIME 4 +#define PWM_NO_TARGET_DUTY 50 +#define PWM_TARGET_DUTY 0 +#define DETECTION_TIMER_MS 10 +#define IOPOLAITY 1 +#define DELAY_MS 1 + +/** Delay constants */ +#define MOTION_DETECTION_DELAY_MS (100 * DELAY_MS) + +/** Task configuration constants */ +#define MOTION_DETECTION_TASK_STACK_SIZE 0x2000 +#define MOTION_DETECTION_TASK_PRIO 25 + +static void radar_example(void) +{ + osal_printk("Radar example start!\r\n"); + + dfrobot_c4001_init(CONFIG_RADAR_UART_BAUD, CONFIG_RADAR_UART_TX_PIN, CONFIG_RADAR_UART_RX_PIN, CONFIG_UART_BUS_ID); + + osal_printk("Radar connected!\r\n"); + + // exist Mode + set_sensor_mode(EXITMODE); + + s_sensor_status_t status = get_status(); + osal_printk("work status = %d\r\n", status.work_status); // 0 stop 1 start + osal_printk("work mode = %d\r\n", status.work_mode); // 0 exist 1 speed + osal_printk("init status = %d\r\n", status.init_status); // 0 no init 1 success + + // 设置检测范围 + if (set_detection_range(MINRANGE, MAXRANGE, TRIGRANGE)) { + osal_printk("set detection range successfully!\r\n"); + } + + // 设置触发灵敏度 + if (set_trig_sensitivity(TRIG_SENSITIVITY)) { + osal_printk("set trig sensitivity successfully!\r\n"); + } + + // 设置保持灵敏度 + if (set_keep_sensitivity(KEEP_SENSITIVITY)) { + osal_printk("set keep sensitivity successfully!\r\n"); + } + + // 设置触发延时和保持时间 + if (set_delay(TRIG_DELAY, KEEP_TIME)) { + osal_printk("set delay successfully!\r\n"); + } + + uapi_watchdog_kick(); + + // 设置 PWM 输出 + if (set_pwm(PWM_NO_TARGET_DUTY, PWM_TARGET_DUTY, DETECTION_TIMER_MS)) { + osal_printk("set pwm period successfully!\r\n"); + } + + // 设置 IO 极性 + if (set_io_polarity(IOPOLAITY)) { + osal_printk("set Io Polaity successfully!\r\n"); + } + + // 打印当前参数 + osal_printk("trig sensitivity = %d\r\n", get_trig_sensitivity()); + osal_printk("keep sensitivity = %d\r\n", get_keep_sensitivity()); + osal_printk("min range = %d\r\n", get_min_range()); + osal_printk("max range = %d\r\n", get_max_range()); + uapi_watchdog_kick(); + osal_printk("trig range = %d\r\n", get_trig_range()); + osal_printk("keep time = %d\r\n", get_keep_timeout()); + osal_printk("trig delay = %d\r\n", get_trig_delay()); + osal_printk("polaity = %d\r\n", get_io_polarity()); + uapi_watchdog_kick(); + s_pwm_data_t pwmData = get_pwm(); + osal_printk("pwm1 = %d\r\n", pwmData.pwm1); + osal_printk("pwm2 = %d\r\n", pwmData.pwm2); + osal_printk("pwm timer = %d\r\n", pwmData.timer); + + // 主循环 + while (1) { + uapi_watchdog_kick(); + if (motion_detection()) { + osal_printk("exist motion\r\n"); + } + uapi_systick_delay_ms(MOTION_DETECTION_DELAY_MS); + } +} + +// 示例入口 +static void radar_entry(void) +{ + osal_task *task_handle = NULL; + osal_kthread_lock(); + task_handle = + osal_kthread_create((osal_kthread_handler)radar_example, NULL, "RadarTask", MOTION_DETECTION_TASK_STACK_SIZE); + if (task_handle != NULL) { + osal_kthread_set_priority(task_handle, MOTION_DETECTION_TASK_PRIO); + } + osal_kthread_unlock(); +} + +app_run(radar_entry); diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/range_velocity_sample/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/range_velocity_sample/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..24bf516f759118b3fbd95da86c8e8836819928d4 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/range_velocity_sample/CMakeLists.txt @@ -0,0 +1 @@ +set(SOURCES "${SOURCES}" "${CMAKE_CURRENT_SOURCE_DIR}/range_velocity_sample.c" PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/range_velocity_sample/range_velocity_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/range_velocity_sample/range_velocity_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..e83e82e323d0082a0a95d0506c78c8c6da4612ef --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/range_velocity_sample/range_velocity_sample.c @@ -0,0 +1,103 @@ +/*! + * @file range_velocity_sample.c + * @brief radar measurement demo + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-09-29 + * @url https://github.com/dfrobot/DFRobot_C4001 + */ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "systick.h" +#include "osal_debug.h" +#include "watchdog.h" +#include "app_init.h" +#include "uart.h" + +#include "dfrobot_c4001.h" + +#define DELAY_MS 1 + +/** Task configuration constants */ +#define RANGE_VELOCITY_TASK_STACK_SIZE 0x2000 +#define RANGE_VELOCITY_TASK_PRIO 25 + +/** Detection threshold constants */ +#define RANGE_VELOCITY_DETECT_MIN_CM 11 +#define RANGE_VELOCITY_DETECT_MAX_CM 1200 +#define RANGE_VELOCITY_DETECT_THRES 10 + +/** Delay constants */ +#define RANGE_VELOCITY_DELAY_MS (100 * DELAY_MS) + +/** Buffer size constants */ +#define RANGE_VELOCITY_TEMPLINE_BUFFER_SIZE 32 + +static void m_range_velocity_task(void) +{ + osal_printk("Radar example start!\r\n"); + + dfrobot_c4001_init(CONFIG_RADAR_UART_BAUD, CONFIG_RADAR_UART_TX_PIN, CONFIG_RADAR_UART_RX_PIN, CONFIG_UART_BUS_ID); + + osal_printk("Radar connected!\r\n"); + + // speed Mode + set_sensor_mode(SPEEDMODE); + + s_sensor_status_t status = get_status(); + osal_printk("work status = %d\r\n", status.work_status); // 0 stop 1 start + osal_printk("work mode = %d\r\n", status.work_mode); // 0 exist 1 speed + osal_printk("init status = %d\r\n", status.init_status); // 0 no init 1 success + uapi_watchdog_kick(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2000), not exceeding max, otherwise the function + * is abnormal. max Detection range Maximum distance, unit cm, range 2.4~20m (240~2000) thres Target detection + * threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (set_detect_thres(RANGE_VELOCITY_DETECT_MIN_CM /* min */, RANGE_VELOCITY_DETECT_MAX_CM /* max */, + RANGE_VELOCITY_DETECT_THRES /* thres */)) { + osal_printk("set detect threshold successfully\r\n"); + } + + // set Fretting Detection + set_fretting_detection(SWITCH_ON); + + uapi_watchdog_kick(); + + osal_printk("min range = %d\r\n", get_t_min_range()); + osal_printk("max range = %d\r\n", get_t_max_range()); + osal_printk("threshold range = %d\r\n", get_thres_range()); + osal_printk("fretting detection = %d\r\n", get_fretting_detection()); + + static char templine[RANGE_VELOCITY_TEMPLINE_BUFFER_SIZE] = {0}; + while (1) { + uapi_watchdog_kick(); + osal_printk("target number = %d\r\n", get_target_number()); + sprintf(templine, "target Speed = %.2f m/s\r\n", get_target_speed()); + osal_printk("%s", templine); + sprintf(templine, "target distance = %.2f m\r\n", get_target_range()); + osal_printk("%s", templine); + uapi_systick_delay_ms(RANGE_VELOCITY_DELAY_MS); + } +} + +// 示例入口 +static void m_range_velocity_entry(void) +{ + osal_task *task_handle = NULL; + osal_kthread_lock(); + task_handle = osal_kthread_create((osal_kthread_handler)m_range_velocity_task, NULL, "RadarTask", + RANGE_VELOCITY_TASK_STACK_SIZE); + if (task_handle != NULL) { + osal_kthread_set_priority(task_handle, RANGE_VELOCITY_TASK_PRIO); + } + osal_kthread_unlock(); +} + +app_run(m_range_velocity_entry); diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..d049f2b362f6644d03f38c47924639253abac54d --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_c4001/readme.md @@ -0,0 +1,41 @@ +# beetle_c4001 + +## 一、介绍 + +dfrobot_c4001是一个高性能的C4001毫米波雷达传感器驱动库,支持存在检测和速度测量两种工作模式。 + +详见库:[[dfrobot_c4001] readme.md](./dfrobot_c4001/readme.md) + +## 二、存在检测示例 (motion_detection_sample.c) + +### 1、介绍 + +本例程演示了C4001雷达模块的运动检测功能。程序首先初始化雷达硬件并设置为存在检测模式,然后配置检测范围、灵敏度、延时参数和PWM输出等关键参数。在主循环中,程序持续监测雷达信号,每100ms检测一次物体运动状态,当检测到运动时会实时输出提示信息。 + +### 2、实验流程 + +- 执行Clean命令清理资源 +- 打开KConfig,选择Motion Detection示例,设置UART参数,波特率为9600: + +![img](.\images\c4001_img1.png) + +- 编译、烧录后,在传感器前放置物体,观察是否打印存在检测信息: + +![img](.\images\c4001_img2.png) + +## 三、测速测距示例 (range_velocity_sample.c) + +### 1、介绍 + +本例程演示了C4001雷达模块的距离和速度测量功能。程序首先初始化雷达硬件并设置为测速模式,然后配置检测阈值参数和开启微动检测功能。在主循环中,程序持续获取并实时显示目标数量(仅0和1)、运动速度(m/s)和距离(m)等测量数据,每100ms更新一次。 + +### 2、实验流程 + +- 执行Clean命令清理资源 +- 打开KConfig,选择Range Velocity示例,设置UART参数,波特率为9600: + +![img](.\images\c4001_img3.png) + +- 编译、烧录后,在传感器前移动物体,观察打印相关数据: + +![img](.\images\c4001_img4.png) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..59a5f61a8b9046063389a773787aff2344f242d7 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/CMakeLists.txt @@ -0,0 +1,4 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/beetle_df9gms_sample.c +) +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..bf195a75fb7805a5ab7929e2f24ba694cd55b205 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/Kconfig @@ -0,0 +1,8 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== + +config DF9GMS_PIN + int "Choose DF9GMS pin." + default 2 diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/beetle_df9gms_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/beetle_df9gms_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..673a91b2e7e2f70edf6a881e1aa096a899d6cafe --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_df9gms/beetle_df9gms_sample.c @@ -0,0 +1,174 @@ +/**! + * @file beetle_df9gms_sample.c + * @brief The servo will gradually rotate from 0 degrees to 180 degrees, and then gradually return to 0 degrees. + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + */ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "hal_gpio.h" +#include "systick.h" +#include "watchdog.h" +#include "app_init.h" +#include "timer.h" +#include "tcxo.h" +#include "chip_core_irq.h" +#include + +#define DF9GMS_TASK_STACK_SIZE 0x1000 +#define DF9GMS_TASK_PRIO 17 +#define FREQ_TIME 20000 +#define DF9GMS_PULSE_COUNT 10 +#define DELAY_S 1000 +#define ANGLE_0 0 +#define ANGLE_90 90 +#define ANGLE_180 180 + +// 定时器相关定义 +#define SERVO_TIMER_INDEX 2 +#define SERVO_TIMER_PRIO 2 +#define SERVO_TIMER_IRQ TIMER_2_IRQN +#define SERVO_PWM_PERIOD_US 20000 // 20ms周期 +#define SERVO_MIN_PULSE_US 500 // 0.5ms脉宽 +#define SERVO_MAX_PULSE_US 2500 // 2.5ms脉宽 + +// 全局变量 +static timer_handle_t g_servo_timer = NULL; +static uint32_t g_current_angle = 0; +static uint32_t g_current_pulse_width = 0; +static uint32_t g_pulse_start_time = 0; + +// 定时器回调函数 - 产生持续PWM信号 +static void servo_timer_callback(uintptr_t data) +{ + unused(data); + static uint32_t pulse_phase = 0; // 0: 高电平阶段, 1: 低电平阶段 + + if (pulse_phase == 0) { + // 高电平阶段开始 + uapi_gpio_set_val(CONFIG_DF9GMS_PIN, GPIO_LEVEL_HIGH); + g_pulse_start_time = uapi_tcxo_get_us(); + pulse_phase = 1; + // 设置脉宽定时 + uapi_timer_start(g_servo_timer, g_current_pulse_width, servo_timer_callback, 0); + } else { + // 低电平阶段开始 + uapi_gpio_set_val(CONFIG_DF9GMS_PIN, GPIO_LEVEL_LOW); + pulse_phase = 0; + // 设置剩余周期定时,持续发波 + uapi_timer_start(g_servo_timer, SERVO_PWM_PERIOD_US - g_current_pulse_width, servo_timer_callback, 0); + } +} + +void df9gms_init(void) +{ + uapi_pin_set_mode(CONFIG_DF9GMS_PIN, HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(CONFIG_DF9GMS_PIN, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(CONFIG_DF9GMS_PIN, GPIO_LEVEL_LOW); +} + +// 初始化定时器PWM +void servo_pwm_init(void) +{ + // 初始化定时器 + uapi_timer_init(); + uapi_timer_adapter(SERVO_TIMER_INDEX, SERVO_TIMER_IRQ, SERVO_TIMER_PRIO); + uapi_timer_create(SERVO_TIMER_INDEX, &g_servo_timer); + + // 设置初始角度为0度 + g_current_angle = 0; + g_current_pulse_width = SERVO_MIN_PULSE_US; +} + +// 停止PWM输出 +void servo_pwm_stop(void) +{ + if (g_servo_timer != NULL) { + uapi_timer_stop(g_servo_timer); + uapi_gpio_set_val(CONFIG_DF9GMS_PIN, GPIO_LEVEL_LOW); + } +} + +// 销毁定时器 +void servo_pwm_deinit(void) +{ + if (g_servo_timer != NULL) { + uapi_timer_stop(g_servo_timer); + uapi_timer_delete(g_servo_timer); + g_servo_timer = NULL; + } +} + +// 将角度(0~180)映射为脉宽并启动持续PWM +void servo_set_pos(unsigned int pos) +{ + if (pos > ANGLE_180) { + pos = ANGLE_180; // 限制最大角度 + } + + // 计算对应的脉宽 (us) + unsigned int duty = SERVO_MIN_PULSE_US + (pos * (SERVO_MAX_PULSE_US - SERVO_MIN_PULSE_US)) / 180; + + // 更新全局变量 + g_current_angle = pos; + g_current_pulse_width = duty; + + // 启动定时器开始持续发波 + if (g_servo_timer != NULL) { + uapi_timer_start(g_servo_timer, g_current_pulse_width, servo_timer_callback, 0); + } +} + +void df9gms_task(void) +{ + // 初始化GPIO + df9gms_init(); + + // 初始化定时器PWM + servo_pwm_init(); + + // 舵机运动序列 - 每次调用ServoSetPos都会启动持续PWM + servo_set_pos(ANGLE_0); // 转到0度并保持 + uapi_systick_delay_ms(DELAY_S); + + servo_set_pos(ANGLE_90); // 转到90度并保持 + uapi_systick_delay_ms(DELAY_S); + + servo_set_pos(ANGLE_180); // 转到180度并保持 + uapi_systick_delay_ms(DELAY_S); + + servo_set_pos(ANGLE_90); // 转到90度并保持 + uapi_systick_delay_ms(DELAY_S); + + servo_set_pos(ANGLE_0); // 转到0度并保持 + uapi_systick_delay_ms(DELAY_S); + + // 停止PWM + servo_pwm_stop(); + uapi_systick_delay_ms(DELAY_S); + + // 清理定时器资源 + servo_pwm_deinit(); +} + +void df9gms_entry(void) +{ + uint32_t ret; + osal_task *taskid; + // 创建任务调度 + osal_kthread_lock(); + // 创建任务1 + taskid = osal_kthread_create((osal_kthread_handler)df9gms_task, NULL, "df9gms_task", DF9GMS_TASK_STACK_SIZE); + ret = osal_kthread_set_priority(taskid, DF9GMS_TASK_PRIO); + if (ret != OSAL_SUCCESS) { + printf("create task1 failed .\n"); + } + osal_kthread_unlock(); +} +app_run(df9gms_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e488d1e2ed78ea029ed32f43218b3732f1f92db --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/CMakeLists.txt @@ -0,0 +1,4 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/beetle_ds18b20_sample.c +) +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..dcbf626aef854bcc677367794082ed140c98fa76 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/Kconfig @@ -0,0 +1,8 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== + +config ONEWIRE_PIN + int "Choose DS18B20 pin." + default 2 diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/beetle_ds18b20_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/beetle_ds18b20_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..df1a8a758d66f1604a6c17b59766de138c6122a3 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ds18b20/beetle_ds18b20_sample.c @@ -0,0 +1,211 @@ +/**! + * @file beetle_ds18b20_sample.c + * @brief Implementing the OneWire protocol via GPIO to drive the DS18B20. + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + */ + +#include "pinctrl.h" +#include "gpio.h" +#include "systick.h" +#include "soc_osal.h" +#include "app_init.h" + +#include "tcxo.h" + +/** Task configuration constants */ +#define DS_TASK_PRIO 24 +#define DS_TASK_STACK_SIZE 0x1000 +#define READITV 10 +#define TASKITV 1000 + +/** OneWire timing constants (in microseconds) */ +#define DS18B20_RESET_LOW_TIME_US 480 +#define DS18B20_RESET_RELEASE_TIME_US 70 +#define DS18B20_RESET_WAIT_TIME_US 410 +#define DS18B20_WRITE_BIT_1_LOW_TIME_US 6 +#define DS18B20_WRITE_BIT_1_RELEASE_TIME_US 64 +#define DS18B20_WRITE_BIT_0_LOW_TIME_US 60 +#define DS18B20_WRITE_BIT_0_RELEASE_TIME_US 10 +#define DS18B20_READ_BIT_LOW_TIME_US 6 +#define DS18B20_READ_BIT_SAMPLE_TIME_US 9 +#define DS18B20_READ_BIT_WAIT_TIME_US 55 + +/** OneWire protocol constants */ +#define DS18B20_BITS_PER_BYTE 8 +#define DS18B20_BIT_MASK_LSB 0x01 +#define DS18B20_BIT_MASK_MSB 0x80 + +/** DS18B20 command constants */ +#define DS18B20_CMD_SKIP_ROM 0xCC +#define DS18B20_CMD_CONVERT_T 0x44 +#define DS18B20_CMD_READ_SCRATCHPAD 0xBE + +/** DS18B20 conversion timeout (in microseconds) */ +#define DS18B20_CONVERSION_TIMEOUT_US 800000 + +/** Temperature conversion constants */ +#define DS18B20_TEMP_DIVISOR 16.0f + +/** Buffer size constants */ +#define DS18B20_TEMPLINE_BUFFER_SIZE 32 + +static inline uint32_t get_time_us(void) +{ + return (uint32_t)uapi_tcxo_get_us(); +} + +static void delay_us(uint32_t us) +{ + uapi_tcxo_delay_us(us); +} + +static inline void bus_drive_low(void) +{ + uapi_gpio_set_dir(CONFIG_ONEWIRE_PIN, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(CONFIG_ONEWIRE_PIN, GPIO_LEVEL_LOW); +} + +static inline void bus_release(void) +{ + uapi_gpio_set_dir(CONFIG_ONEWIRE_PIN, GPIO_DIRECTION_INPUT); +} + +static inline uint8_t bus_read_level(void) +{ + return (uint8_t)uapi_gpio_get_val(CONFIG_ONEWIRE_PIN); +} + +static bool ow_reset(void) +{ + bus_drive_low(); + delay_us(DS18B20_RESET_LOW_TIME_US); + bus_release(); + delay_us(DS18B20_RESET_RELEASE_TIME_US); + bool present = (bus_read_level() == 0); + delay_us(DS18B20_RESET_WAIT_TIME_US); + return present; +} + +static void ow_write_bit(uint8_t bit) +{ + if (bit) { + bus_drive_low(); + delay_us(DS18B20_WRITE_BIT_1_LOW_TIME_US); + bus_release(); + delay_us(DS18B20_WRITE_BIT_1_RELEASE_TIME_US); + } else { + bus_drive_low(); + delay_us(DS18B20_WRITE_BIT_0_LOW_TIME_US); + bus_release(); + delay_us(DS18B20_WRITE_BIT_0_RELEASE_TIME_US); + } +} + +static uint8_t ow_read_bit(void) +{ + uint8_t bit; + bus_drive_low(); + delay_us(DS18B20_READ_BIT_LOW_TIME_US); + bus_release(); + delay_us(DS18B20_READ_BIT_SAMPLE_TIME_US); + bit = bus_read_level(); + delay_us(DS18B20_READ_BIT_WAIT_TIME_US); + return bit; +} + +static void ow_write_byte(uint8_t val) +{ + for (int i = 0; i < DS18B20_BITS_PER_BYTE; i++) { + ow_write_bit(val & DS18B20_BIT_MASK_LSB); + val >>= 1; + } +} + +static uint8_t ow_read_byte(void) +{ + uint8_t v = 0; + for (int i = 0; i < DS18B20_BITS_PER_BYTE; i++) { + v >>= 1; + if (ow_read_bit()) { + v |= DS18B20_BIT_MASK_MSB; + } + } + return v; +} + +static bool ds18b20_read_temp_raw(int16_t *temp_raw) +{ + if (!ow_reset()) { + return false; + } + ow_write_byte(DS18B20_CMD_SKIP_ROM); // SKIP ROM + ow_write_byte(DS18B20_CMD_CONVERT_T); // CONVERT T + + uint32_t start = get_time_us(); + while ((uint32_t)(get_time_us() - start) < DS18B20_CONVERSION_TIMEOUT_US) { + if (ow_read_bit()) { + break; + } + osal_msleep(READITV); + } + + if (!ow_reset()) { + return false; + } + ow_write_byte(DS18B20_CMD_SKIP_ROM); + ow_write_byte(DS18B20_CMD_READ_SCRATCHPAD); // READ SCRATCHPAD + + uint8_t temp_l = ow_read_byte(); + uint8_t temp_h = ow_read_byte(); + *temp_raw = (int16_t)((temp_h << DS18B20_BITS_PER_BYTE) | temp_l); + return true; +} + +static float ds18b20_raw_to_celsius(int16_t raw) +{ + return (float)raw / DS18B20_TEMP_DIVISOR; +} + +static int ds18b20_task(const char *arg) +{ + unused(arg); + + uapi_pin_set_mode(CONFIG_ONEWIRE_PIN, HAL_PIO_FUNC_GPIO); + uapi_pin_set_pull(CONFIG_ONEWIRE_PIN, PIN_PULL_TYPE_UP); + uapi_gpio_init(); + uapi_systick_init(); + + static char templine[DS18B20_TEMPLINE_BUFFER_SIZE] = {0}; + while (1) { + int16_t raw = 0; + bool ok = ds18b20_read_temp_raw(&raw); + if (ok) { + float t = ds18b20_raw_to_celsius(raw); + sprintf(templine, "DS18B20: %.2f C\r\n", t); + printf(templine); + } else { + osal_printk("DS18B20: no presence\r\n"); + } + osal_msleep(TASKITV); + } + + return 0; +} + +static void ds18b20_entry(void) +{ + osal_task *task_handle = NULL; + osal_kthread_lock(); + task_handle = osal_kthread_create((osal_kthread_handler)ds18b20_task, 0, "DS18B20Task", DS_TASK_STACK_SIZE); + if (task_handle != NULL) { + osal_kthread_set_priority(task_handle, DS_TASK_PRIO); + osal_kfree(task_handle); + } + osal_kthread_unlock(); +} + +app_run(ds18b20_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..74bc09ef05d98559a6c1f31e4cdb4754290783d7 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/CMakeLists.txt @@ -0,0 +1,16 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_lis2dh12/dfrobot_lis2dh12.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/dfrobot_lis2dh12) + + +if(DEFINED CONFIG_SAMPLE_SUPPORT_ACCELERATION_SAMPLE) + add_subdirectory_if_exist(get_acceleration_sample) +endif() + +if(DEFINED CONFIG_SAMPLE_SUPPORT_INTERRUPT_SAMPLE) + add_subdirectory_if_exist(interrupt_sample) +endif() + +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" ${HEADER_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..ec3523b88e57003538c04c2a6e60df3488486883 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/Kconfig @@ -0,0 +1,35 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +choice + prompt "Select getAcceleration or interrupt Sample" + default SAMPLE_SUPPORT_ACCELERATION_SAMPLE + config SAMPLE_SUPPORT_ACCELERATION_SAMPLE + bool "Support getAcceleration Sample." + + config SAMPLE_SUPPORT_INTERRUPT_SAMPLE + bool "Support interrupt Sample." + +endchoice + +config I2C_MASTER_BUS_ID + int "Choose I2C bus id." + default 1 + +config I2C_SCL_MASTER_PIN + int "Choose I2C SCL pin" + default 16 + +config I2C_SDA_MASTER_PIN + int "Choose I2C SDA pin" + default 15 + +config I2C_SLAVE_ADDR + int "Choose I2C SLAVE ADDR" + default 0x18 + +config INTERRUPT_PIN + int "Choose INTERRUPT pin" + default 2 + depends on SAMPLE_SUPPORT_INTERRUPT_SAMPLE diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/dfrobot_lis2dh12.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/dfrobot_lis2dh12.c new file mode 100644 index 0000000000000000000000000000000000000000..a76bd6cdc28f6b3b3654cb0cb08a8d3c2e861451 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/dfrobot_lis2dh12.c @@ -0,0 +1,330 @@ +/*! + * @file dfrobot_lis2dh12.c + * @brief Define the basic structure of DFRobot_LIS2DH12 + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/DFRobot_LIS + */ + +#include "dfrobot_lis2dh12.h" + +#define I2C_MASTER_ADDR LIS2DH12_I2C_MASTER_ADDR +#define I2C_SET_BAUDRATE LIS2DH12_I2C_SET_BAUDRATE +#define I2C_MASTER_PIN_MODE LIS2DH12_I2C_MASTER_PIN_MODE + +uint8_t g_iic_bus_id; +uint8_t g_device_addr; +uint8_t g_mg_scale_vel = LIS2DH12_DEFAULT_MG_SCALE_VEL; +uint8_t g_reset = LIS2DH12_RESET_DEFAULT; + +bool dfrobot_lis2dh12_init(uint8_t addr, uint8_t iic_scl_master_pin, uint8_t iic_sda_master_pin, uint8_t iic_bus_id) +{ + g_device_addr = addr; + g_iic_bus_id = iic_bus_id; + uapi_pin_set_mode(iic_scl_master_pin, I2C_MASTER_PIN_MODE); + uapi_pin_set_mode(iic_sda_master_pin, I2C_MASTER_PIN_MODE); + uapi_i2c_master_init(g_iic_bus_id, I2C_SET_BAUDRATE, I2C_MASTER_ADDR); + + uint8_t identifier = LIS2DH12_ARRAY_INDEX_0; + bool ret = false; + g_reset = LIS2DH12_RESET_SET; + read_reg(REG_CARD_ID, &identifier, LIS2DH12_REG_ADDR_SIZE); + DBG(identifier); + if (identifier == LIS2DH12_CHIP_ID_VALID) { + ret = true; + } else if (identifier == LIS2DH12_CHIP_ID_INVALID_1 || identifier == LIS2DH12_CHIP_ID_INVALID_2) { + DBG("Communication failure"); + ret = false; + } else { + DBG("the ic is not LIS2DH12"); + ret = false; + } + return ret; +} + +void write_reg(uint8_t reg, const uint8_t *p_buf, size_t size) +{ + if (p_buf == NULL) { + osal_printk("p_buf ERROR!! : null pointer\n"); + return; + } + + // 拼接寄存器地址 + 数据 + uint8_t buf[LIS2DH12_REG_ADDR_SIZE + size]; + buf[LIS2DH12_ARRAY_INDEX_0] = reg; + memcpy(&buf[LIS2DH12_ARRAY_INDEX_1], p_buf, size); + + i2c_data_t data = {0}; + data.send_buf = buf; + data.send_len = LIS2DH12_REG_ADDR_SIZE + size; + data.receive_buf = NULL; + data.receive_len = LIS2DH12_ARRAY_INDEX_0; + + if (uapi_i2c_master_write(g_iic_bus_id, g_device_addr, &data) != ERRCODE_SUCC) { + osal_printk("I2C write_reg error!\n"); + } +} + +uint8_t read_reg(uint8_t reg, uint8_t *p_buf, size_t size) +{ + if (p_buf == NULL) { + osal_printk("p_buf ERROR!! : null pointer\n"); + return 0; + } + + i2c_data_t data = {0}; + data.send_buf = ® + data.send_len = LIS2DH12_REG_ADDR_SIZE; // 先发寄存器地址 + data.receive_buf = p_buf; + data.receive_len = size; // 再收数据 + + if (uapi_i2c_master_write(g_iic_bus_id, g_device_addr, &data) != ERRCODE_SUCC) { + osal_printk("I2C read_reg send error!\n"); + return LIS2DH12_ARRAY_INDEX_0; + } + + if (uapi_i2c_master_read(g_iic_bus_id, g_device_addr, &data) != ERRCODE_SUCC) { + osal_printk("I2C read_reg recv error!\n"); + return LIS2DH12_ARRAY_INDEX_0; + } + + return size; +} + +/** + * @fn limit_acceleration_data + * @brief Limit acceleration data based on measurement range + * @param data Acceleration data to be limited + * @return Limited acceleration data + */ +static int32_t limit_acceleration_data(int32_t data) +{ + // Set appropriate limit values based on measurement range + if (g_mg_scale_vel == LIS2DH12_MG_SCALE_2G) { // 2g range + if (data > LIS2DH12_ACC_LIMIT_2G_POS) { + data = LIS2DH12_ACC_LIMIT_2G_POS; + } else if (data < LIS2DH12_ACC_LIMIT_2G_NEG) { + data = LIS2DH12_ACC_LIMIT_2G_NEG; + } + } else if (g_mg_scale_vel == LIS2DH12_MG_SCALE_4G) { // 4g range + if (data > LIS2DH12_ACC_LIMIT_4G_POS) { + data = LIS2DH12_ACC_LIMIT_4G_POS; + } else if (data < LIS2DH12_ACC_LIMIT_4G_NEG) { + data = LIS2DH12_ACC_LIMIT_4G_NEG; + } + } else if (g_mg_scale_vel == LIS2DH12_MG_SCALE_8G) { // 8g range + if (data > LIS2DH12_ACC_LIMIT_8G_POS) { + data = LIS2DH12_ACC_LIMIT_8G_POS; + } else if (data < LIS2DH12_ACC_LIMIT_8G_NEG) { + data = LIS2DH12_ACC_LIMIT_8G_NEG; + } + } else if (g_mg_scale_vel == LIS2DH12_MG_SCALE_16G) { // 16g range + if (data > LIS2DH12_ACC_LIMIT_16G_POS) { + data = LIS2DH12_ACC_LIMIT_16G_POS; + } else if (data < LIS2DH12_ACC_LIMIT_16G_NEG) { + data = LIS2DH12_ACC_LIMIT_16G_NEG; + } + } + return data; +} + +int32_t read_acc_x(void) +{ + uint8_t sensor_data[LIS2DH12_SENSOR_DATA_SIZE]; + int32_t data; + read_reg(REG_OUT_X_L | LIS2DH12_REG_READ_MASK, sensor_data, LIS2DH12_SENSOR_DATA_SIZE); + data = ((int8_t)sensor_data[LIS2DH12_ARRAY_INDEX_1] * (uint8_t)g_mg_scale_vel); + + return limit_acceleration_data(data); +} + +int32_t read_acc_y(void) +{ + uint8_t sensor_data[LIS2DH12_SENSOR_DATA_SIZE]; + int32_t a; + read_reg(REG_OUT_Y_L | LIS2DH12_REG_READ_MASK, sensor_data, LIS2DH12_SENSOR_DATA_SIZE); + a = ((int8_t)sensor_data[LIS2DH12_ARRAY_INDEX_1] * (uint8_t)g_mg_scale_vel); + + return limit_acceleration_data(a); +} + +int32_t read_acc_z(void) +{ + uint8_t sensor_data[LIS2DH12_SENSOR_DATA_SIZE]; + int32_t a; + read_reg(REG_OUT_Z_L | LIS2DH12_REG_READ_MASK, sensor_data, LIS2DH12_SENSOR_DATA_SIZE); + DBG(sensor_data[LIS2DH12_ARRAY_INDEX_0]); + DBG(sensor_data[LIS2DH12_ARRAY_INDEX_1]); + a = ((int8_t)sensor_data[LIS2DH12_ARRAY_INDEX_1] * (uint8_t)g_mg_scale_vel); + return limit_acceleration_data(a); +} + +void set_range(e_range_t range) +{ + switch (range) { + case E_LIS2DH12_2G: + g_mg_scale_vel = LIS2DH12_MG_SCALE_2G; + break; + case E_LIS2DH12_4G: + g_mg_scale_vel = LIS2DH12_MG_SCALE_4G; + break; + case E_LIS2DH12_8G: + g_mg_scale_vel = LIS2DH12_MG_SCALE_8G; + break; + default: + g_mg_scale_vel = LIS2DH12_MG_SCALE_16G; + break; + } + DBG(range); + write_reg(REG_CTRL_REG4, &range, LIS2DH12_REG_ADDR_SIZE); +} + +void set_acquire_rate(e_power_mode_t rate) +{ + uint8_t reg = LIS2DH12_CTRL_REG1_DEFAULT; + reg = reg | rate; + DBG(reg); + write_reg(REG_CTRL_REG1, ®, LIS2DH12_REG_ADDR_SIZE); +} + +uint8_t get_id(void) +{ + uint8_t identifier; + read_reg(REG_CARD_ID, &identifier, LIS2DH12_REG_ADDR_SIZE); + return identifier; +} + +void set_int1_th(uint8_t threshold) +{ + uint8_t reg = (threshold * LIS2DH12_THRESHOLD_MULTIPLIER) / g_mg_scale_vel; + uint8_t reg1 = LIS2DH12_CTRL_REG5_INT1_DEFAULT; + uint8_t reg2 = LIS2DH12_CTRL_REG2_DEFAULT; + uint8_t data = LIS2DH12_CTRL_REG3_INT1_DEFAULT; + + write_reg(REG_CTRL_REG2, ®2, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_CTRL_REG3, &data, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_CTRL_REG5, ®1, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_CTRL_REG6, ®2, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_INT1_THS, ®, LIS2DH12_REG_ADDR_SIZE); + read_reg(REG_CTRL_REG5, ®2, LIS2DH12_REG_ADDR_SIZE); + DBG(reg2); + read_reg(REG_CTRL_REG3, ®2, LIS2DH12_REG_ADDR_SIZE); + DBG(reg2); +} + +void set_int2_th(uint8_t threshold) +{ + uint8_t reg = (threshold * LIS2DH12_THRESHOLD_MULTIPLIER) / g_mg_scale_vel; + uint8_t reg1 = LIS2DH12_CTRL_REG5_INT2_DEFAULT; + uint8_t reg2 = LIS2DH12_CTRL_REG2_DEFAULT; + uint8_t data = LIS2DH12_CTRL_REG6_INT2_DEFAULT; + + write_reg(REG_CTRL_REG2, ®2, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_CTRL_REG3, ®2, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_CTRL_REG5, ®1, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_CTRL_REG6, &data, LIS2DH12_REG_ADDR_SIZE); + write_reg(REG_INT2_THS, ®, LIS2DH12_REG_ADDR_SIZE); + read_reg(REG_CTRL_REG5, ®2, LIS2DH12_REG_ADDR_SIZE); + DBG(reg2); + read_reg(REG_CTRL_REG6, ®2, LIS2DH12_REG_ADDR_SIZE); + DBG(reg2); +} + +void enable_interrupt_event(e_interrupt_source_t source, e_interrupt_event_t event) +{ + uint8_t data = LIS2DH12_ARRAY_INDEX_0; + data = LIS2DH12_INT_CFG_BASE | event; + DBG(data); + if (source == E_INT1) { + write_reg(REG_INT1_CFG, &data, LIS2DH12_REG_ADDR_SIZE); + } else { + write_reg(REG_INT2_CFG, &data, LIS2DH12_REG_ADDR_SIZE); + } + read_reg(REG_INT1_CFG, &data, LIS2DH12_REG_ADDR_SIZE); + DBG(data); +} + +bool get_int1_event(e_interrupt_event_t event) +{ + uint8_t data = LIS2DH12_ARRAY_INDEX_0; + bool ret = false; + read_reg(REG_INT1_SRC, &data, LIS2DH12_REG_ADDR_SIZE); + DBG(data, HEX); + if (data & LIS2DH12_INT_STATUS_IA_MASK) { + switch (event) { + case E_X_LOWER_THAN_TH: + if (!(data & LIS2DH12_INT_EVENT_XL_MASK)) + ret = true; + break; + case E_X_HIGHER_THAN_TH: + if ((data & LIS2DH12_INT_EVENT_XH_MASK) == LIS2DH12_INT_EVENT_XH_MASK) + ret = true; + break; + case E_Y_LOWER_THAN_TH: + if (!(data & LIS2DH12_INT_EVENT_YL_MASK)) + ret = true; + break; + case E_Y_HIGHER_THAN_TH: + if ((data & LIS2DH12_INT_EVENT_YH_MASK) == LIS2DH12_INT_EVENT_YH_MASK) + ret = true; + break; + case E_Z_LOWER_THAN_TH: + if (!(data & LIS2DH12_INT_EVENT_ZL_MASK)) + ret = true; + break; + case E_Z_HIGHER_THAN_TH: + if ((data & LIS2DH12_INT_EVENT_ZH_MASK) == LIS2DH12_INT_EVENT_ZH_MASK) + ret = true; + break; + default: + ret = false; + } + } else { + ret = false; + } + return ret; +} + +bool get_int2_event(e_interrupt_event_t event) +{ + uint8_t data = LIS2DH12_ARRAY_INDEX_0; + bool ret = false; + read_reg(REG_INT2_SRC, &data, LIS2DH12_REG_ADDR_SIZE); + DBG(data, HEX); + if (data & LIS2DH12_INT_STATUS_IA_MASK) { + switch (event) { + case E_X_LOWER_THAN_TH: + if (!(data & LIS2DH12_INT_EVENT_XL_MASK)) + ret = true; + break; + case E_X_HIGHER_THAN_TH: + if ((data & LIS2DH12_INT_EVENT_XH_MASK) == LIS2DH12_INT_EVENT_XH_MASK) + ret = true; + break; + case E_Y_LOWER_THAN_TH: + if (!(data & LIS2DH12_INT_EVENT_YL_MASK)) + ret = true; + break; + case E_Y_HIGHER_THAN_TH: + if ((data & LIS2DH12_INT_EVENT_YH_MASK) == LIS2DH12_INT_EVENT_YH_MASK) + ret = true; + break; + case E_Z_LOWER_THAN_TH: + if (!(data & LIS2DH12_INT_EVENT_ZL_MASK)) + ret = true; + break; + case E_Z_HIGHER_THAN_TH: + if ((data & LIS2DH12_INT_EVENT_ZH_MASK) == LIS2DH12_INT_EVENT_ZH_MASK) + ret = true; + break; + default: + ret = false; + } + } else { + ret = false; + } + return ret; +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/dfrobot_lis2dh12.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/dfrobot_lis2dh12.h new file mode 100644 index 0000000000000000000000000000000000000000..7aecdb1140459bfa69fdbf63a7df54fd42449529 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/dfrobot_lis2dh12.h @@ -0,0 +1,317 @@ +#ifndef DFROBOT_LIS2DH12_H +#define DFROBOT_LIS2DH12_H + +/*! + * @file dfrobot_lis2dh12.h + * @brief Define the basic structure of DFRobot_LIS2DH12 + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/DFRobot_LIS + */ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "systick.h" +#include "osal_debug.h" +#include "watchdog.h" +#include "app_init.h" +#include "i2c.h" + +#include +#include +#include +#include + +#ifdef ENABLE_DBG +#define DBG(...) \ + do { \ + Serial.print("["); \ + Serial.print(__FUNCTION__); \ + Serial.print("(): "); \ + Serial.print(__LINE__); \ + Serial.print(" ] "); \ + Serial.println(__VA_ARGS__); \ + } while (0) +#else +#define DBG(...) +#endif + +#define REG_CARD_ID 0x0F ///< Chip id +#define REG_CTRL_REG1 0x20 ///< Control register 1 +#define REG_CTRL_REG4 0x23 ///< Control register 4 +#define REG_CTRL_REG2 0x21 ///< Control register 2 +#define REG_CTRL_REG3 0x22 ///< Control register 3 +#define REG_CTRL_REG5 0x24 ///< Control register 5 +#define REG_CTRL_REG6 0x25 ///< Control register 6 +#define REG_STATUS_REG 0x27 ///< Status register +#define REG_OUT_X_L 0x28 ///< The low order of the X-axis acceleration register +#define REG_OUT_X_H 0x29 ///< The high point of the X-axis acceleration register +#define REG_OUT_Y_L 0x2A ///< The low order of the Y-axis acceleration register +#define REG_OUT_Y_H 0x2B ///< The high point of the Y-axis acceleration register +#define REG_OUT_Z_L 0x2C ///< The low order of the Z-axis acceleration register +#define REG_OUT_Z_H 0x2D ///< The high point of the Z-axis acceleration register +#define REG_INT1_THS 0x32 ///< Interrupt source 1 threshold +#define REG_INT2_THS 0x36 ///< Interrupt source 2 threshold +#define REG_INT1_CFG 0x30 ///< Interrupt source 1 configuration register +#define REG_INT2_CFG 0x34 ///< Interrupt source 2 configuration register +#define REG_INT1_SRC 0x31 ///< Interrupt source 1 status register +#define REG_INT2_SRC 0x35 ///< Interrupt source 2 status register + +/** I2C configuration constants */ +#define LIS2DH12_I2C_MASTER_ADDR UINT8_C(0x0) +#define LIS2DH12_I2C_SET_BAUDRATE UINT32_C(400000) +#define LIS2DH12_I2C_MASTER_PIN_MODE UINT8_C(2) + +/** Default scale velocity constants */ +#define LIS2DH12_DEFAULT_MG_SCALE_VEL UINT8_C(16) +#define LIS2DH12_RESET_DEFAULT UINT8_C(0) +#define LIS2DH12_RESET_SET UINT8_C(1) + +/** Chip identification constants */ +#define LIS2DH12_CHIP_ID_VALID UINT8_C(0x33) +#define LIS2DH12_CHIP_ID_INVALID_1 UINT8_C(0x00) +#define LIS2DH12_CHIP_ID_INVALID_2 UINT8_C(0xFF) + +/** Buffer and array size constants */ +#define LIS2DH12_REG_ADDR_SIZE UINT8_C(1) +#define LIS2DH12_SENSOR_DATA_SIZE UINT8_C(2) +#define LIS2DH12_ARRAY_INDEX_0 UINT8_C(0) +#define LIS2DH12_ARRAY_INDEX_1 UINT8_C(1) + +/** Acceleration scale velocity constants */ +#define LIS2DH12_MG_SCALE_2G UINT8_C(16) +#define LIS2DH12_MG_SCALE_4G UINT8_C(32) +#define LIS2DH12_MG_SCALE_8G UINT8_C(64) +#define LIS2DH12_MG_SCALE_16G UINT8_C(192) + +/** Acceleration limit constants (in mg) */ +#define LIS2DH12_ACC_LIMIT_2G_POS UINT16_C(2000) +#define LIS2DH12_ACC_LIMIT_2G_NEG INT16_C(-2000) +#define LIS2DH12_ACC_LIMIT_4G_POS UINT16_C(4000) +#define LIS2DH12_ACC_LIMIT_4G_NEG INT16_C(-4000) +#define LIS2DH12_ACC_LIMIT_8G_POS UINT16_C(8000) +#define LIS2DH12_ACC_LIMIT_8G_NEG INT16_C(-8000) +#define LIS2DH12_ACC_LIMIT_16G_POS UINT16_C(16000) +#define LIS2DH12_ACC_LIMIT_16G_NEG INT16_C(-16000) + +/** Register operation constants */ +#define LIS2DH12_REG_READ_MASK UINT8_C(0x80) +#define LIS2DH12_CTRL_REG1_DEFAULT UINT8_C(0x0F) +#define LIS2DH12_CTRL_REG2_DEFAULT UINT8_C(0x00) +#define LIS2DH12_CTRL_REG3_INT1_DEFAULT UINT8_C(0x40) +#define LIS2DH12_CTRL_REG3_INT2_DEFAULT UINT8_C(0x00) +#define LIS2DH12_CTRL_REG5_INT1_DEFAULT UINT8_C(0x08) +#define LIS2DH12_CTRL_REG5_INT2_DEFAULT UINT8_C(0x02) +#define LIS2DH12_CTRL_REG6_INT2_DEFAULT UINT8_C(0x40) +#define LIS2DH12_INT_CFG_BASE UINT8_C(0x80) + +/** Threshold calculation constants */ +#define LIS2DH12_THRESHOLD_MULTIPLIER UINT16_C(1024) + +/** Interrupt status bit masks */ +#define LIS2DH12_INT_STATUS_IA_MASK UINT8_C(0x40) +#define LIS2DH12_INT_EVENT_XL_MASK UINT8_C(0x01) +#define LIS2DH12_INT_EVENT_XH_MASK UINT8_C(0x02) +#define LIS2DH12_INT_EVENT_YL_MASK UINT8_C(0x04) +#define LIS2DH12_INT_EVENT_YH_MASK UINT8_C(0x08) +#define LIS2DH12_INT_EVENT_ZL_MASK UINT8_C(0x10) +#define LIS2DH12_INT_EVENT_ZH_MASK UINT8_C(0x20) + +/** + * @fn e_power_mode_t + * @brief Power mode selection, determine the frequency of data collection Represents the number of data collected per + * second + */ +typedef enum { + E_POWER_DOWN_0HZ = 0, + E_LOW_POWER_1HZ = 0x10, + E_LOW_POWER_10HZ = 0x20, + E_LOW_POWER_25HZ = 0x30, + E_LOW_POWER_50HZ = 0x40, + E_LOW_POWER_100HZ = 0x50, + E_LOW_POWER_200HZ = 0x60, + E_LOW_POWER_400HZ = 0x70 +} e_power_mode_t; + +/** + * @fn e_range_t + * @brief Sensor range selection + */ +typedef enum { + E_LIS2DH12_2G = 0x00, /**<±2g>*/ + E_LIS2DH12_4G = 0x10, /**<±4g>*/ + E_LIS2DH12_8G = 0x20, /**<±8g>*/ + E_LIS2DH12_16G = 0x30 /**<±16g>*/ +} e_range_t; + +/** + * @fn e_interrupt_event_t + * @brief Interrupt event + */ +typedef enum { + E_X_LOWER_THAN_TH = 0x01, /***/ + E_X_HIGHER_THAN_TH = 0x02, /***/ + E_Y_LOWER_THAN_TH = 0x04, /***/ + E_Y_HIGHER_THAN_TH = 0x08, /***/ + E_Z_LOWER_THAN_TH = 0x10, /***/ + E_Z_HIGHER_THAN_TH = 0x20, /***/ + E_EVENT_ERROR = 0, /**< No event>*/ +} e_interrupt_event_t; + +/** + * @fn e_interrupt_source_t + * @brief Interrupt pin selection + */ +typedef enum { + E_INT1 = 0, /***/ + E_INT2, /***/ +} e_interrupt_source_t; + +/** + * @fn dfrobot_lis2dh12_init + * @brief initialization function + * @param addr I2C slave addr + * @param iic_scl_master_pin SCL pin + * @param iic_sda_master_pin SDA pin + * @param iic_bus_id I2C bus id + * @return true/false + */ +bool dfrobot_lis2dh12_init(uint8_t addr, uint8_t iic_scl_master_pin, uint8_t iic_sda_master_pin, uint8_t iic_bus_id); + +/** + * @fn set_range + * @brief Set the measurement range + * @param range Range(g) + * @n E_LIS2DH12_2G, //2g + * @n E_LIS2DH12_4G, //4g + * @n E_LIS2DH12_8G, //8g + * @n E_LIS2DH12_16G, //16g + */ +void set_range(e_range_t range); + +/** + * @fn set_acquire_rate + * @brief Set data measurement rate + * @param rate rate(HZ) + * @n E_POWER_DOWN_0HZ + * @n E_LOW_POWER_1HZ + * @n E_LOW_POWER_10HZ + * @n E_LOW_POWER_25HZ + * @n E_LOW_POWER_50HZ + * @n E_LOW_POWER_100HZ + * @n E_LOW_POWER_200HZ + * @n E_LOW_POWER_400HZ + */ +void set_acquire_rate(e_power_mode_t rate); + +/** + * @fn get_id + * @brief Get chip id + * @return 8 bit serial number + */ +uint8_t get_id(void); + +/** + * @fn read_acc_x + * @brief Get the acceleration in the x direction + * @return acceleration from x (unit:g), the mearsurement range is ±100g or ±200g, set by set_range() function. + */ +int32_t read_acc_x(void); + +/** + * @fn read_acc_y + * @brief Get the acceleration in the y direction + * @return acceleration from y(unit:g), the mearsurement range is ±100g or ±200g, set by set_range() function. + */ +int32_t read_acc_y(void); + +/** + * @fn read_acc_z + * @brief Get the acceleration in the z direction + * @return acceleration from z(unit:g), the mearsurement range is ±100g or ±200g, set by set_range() function. + */ +int32_t read_acc_z(void); + +/** + * @fn set_int1_th + * @brief Set the threshold of interrupt source 1 interrupt + * @param threshold The threshold is within the measurement range(unit:g) + */ +void set_int1_th(uint8_t threshold); + +/** + * @fn set_int2_th + * @brief Set interrupt source 2 interrupt generation threshold + * @param threshold The threshold is within the measurement range(unit:g) + */ +void set_int2_th(uint8_t threshold); + +/** + * @fn enable_interrupt_event + * @brief Enable interrupt + * @param source Interrupt pin selection + * @n E_INT1 = 0,// + * @n E_INT2,// + * @param event Interrupt event selection + * @n E_X_LOWER_THAN_TH ,// + * @n E_X_HIGHER_THAN_TH ,// + * @n E_Y_LOWER_THAN_TH,// + * @n E_Y_HIGHER_THAN_TH,// + * @n E_Z_LOWER_THAN_TH,// + * @n E_Z_HIGHER_THAN_TH,// + */ +void enable_interrupt_event(e_interrupt_source_t source, e_interrupt_event_t event); + +/** + * @fn get_int1_event + * @brief Check whether the interrupt event'event' is generated in interrupt 1 + * @param event Interrupt event + * @n E_X_LOWER_THAN_TH ,// + * @n E_X_HIGHER_THAN_TH ,// + * @n E_Y_LOWER_THAN_TH,// + * @n E_Y_HIGHER_THAN_TH,// + * @n E_Z_LOWER_THAN_TH,// + * @n E_Z_HIGHER_THAN_TH,// + * @return true Generated/false Not generated + */ +bool get_int1_event(e_interrupt_event_t event); + +/** + * @fn get_int2_event + * @brief Check whether the interrupt event'event' is generated in interrupt 1 + * @param event Interrupt event + * @n E_X_LOWER_THAN_TH ,// + * @n E_X_HIGHER_THAN_TH ,// + * @n E_Y_LOWER_THAN_TH,// + * @n E_Y_HIGHER_THAN_TH,// + * @n E_Z_LOWER_THAN_TH,// + * @n E_Z_HIGHER_THAN_TH,// + * @return true Generated/false Not generated + */ +bool get_int2_event(e_interrupt_event_t event); + +/** + * @fn read_reg + * @brief read data from sensor chip register + * @param reg chip register + * @param p_buf buf for store data to read + * @param size number of data to read + * @return The number of successfully read data + */ +uint8_t read_reg(uint8_t reg, uint8_t *p_buf, size_t size); + +/** + * @fn write_reg + * @brief Write data to sensor register + * @param reg register + * @param p_buf buf for store data to write + * @param size The number of the data in p_buf + */ +void write_reg(uint8_t reg, const uint8_t *p_buf, size_t size); + +#endif diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..02f667d533c21583675a09e7822191d4c8b0f17d --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/readme.md @@ -0,0 +1,151 @@ +# dfrobot_lis2dh12 + +LIS2DH12是一款超低功率高性能三轴线性 +加速度计属于“femto”家族,利用了强大的和 +成熟的制造工艺已用于生产微加工 +加速度计。 +LIS2DH12有用户可选择的±2g/±4g/±8g/±16g的全刻度 +![产品效果图片](./resources/images/SEN0224_TOP.jpg) + +## 产品链接(https://www.dfrobot.com.cn/goods-1372.html) + SKU:SEN0224 + +## 目录 + + * [概述](#概述) + * [API](#API) + * [历史](#历史) + +## 概述 + +提供一个WS63库,通过读取LIS2DH12数据获得三轴加速度。 + +## API +```C++ + /** + * @fn dfrobot_lis2dh12_init + * @brief 初始化函数 + * @param addr 从机I2C地址 + * @param iic_scl_master_pin SCL引脚 + * @param iic_sda_master_pin SDA引脚 + * @param iic_bus_id I2C总线标识符 + * @return true(成功)/false(失败) + */ + bool dfrobot_lis2dh12_init(uint8_t addr, uint8_t iic_scl_master_pin, uint8_t iic_sda_master_pin, uint8_t iic_bus_id); + + /** + * @fn set_range + * @brief 设置测量范围 + * @param range 范围(g) + * @n e_lis2dh12_2g, //±2g + * @n e_lis2dh12_4g, //4g + * @n e_lis2dh12_8g, //8g + * @n e_lis2dh12_16g, //16g + */ + void set_range(e_range_t range); + + /** + * @fn set_acquire_rate + * @brief 设置数据测量速率 + * @param rate 速度(HZ) + * @n e_power_down_0hz + * @n e_low_power_1hz + * @n e_low_power_10hz + * @n e_low_power_25hz + * @n e_low_power_50hz + * @n e_low_power_100hz + * @n e_low_power_200hz + * @n e_low_power_400hz + */ + void set_acquire_rate(e_power_mode_t rate); + + /** + * @fn set_acquire_rate + * @brief 获取芯片ID + * @return 8连续数据 + */ + uint8_t get_id(); + + /** + * @fn read_acc_x + * @brief 获取x方向上的加速度 + * @return 加速度为x(单位:g),测量范围为±100g或±200g,由set_range()函数设定。 + */ + int32_t read_acc_x(); + + /** + * @fn read_acc_y + * @brief 获取y方向的加速度 + * @return 加速度为y(单位:g),测量范围为±100g或±200g,由set_range()函数设定。 + */ + int32_t read_acc_y(); + + /** + * @fn read_acc_z + * @brief 获取z方向的加速度 + * @return 加速度从z开始(单位:g),测量范围为±100g或±200g,由set_range()函数设定。 + */ + int32_t read_acc_z(); + + /** + * @fn set_int1_th + * @brief 设置中断源1中断的阈值 + * @param threshold 告警阈值在测量范围内,单位:g + */ + void set_int1_th(uint8_t threshold); + + /** + * @fn set_int2_th + * @brief 设置“中断源2”的中断产生阈值 + * @param threshold 告警阈值在测量范围内,单位:g + */ + void set_int2_th(uint8_t threshold); + + /** + * @fn enable_interrupt_event + * @brief 启用中断 + * @param source 中断引脚选择 + * @n e_int1 = 0,// + * @n e_int2,// + * @param event 中断事件选择 + * @n e_x_lower_than_th ,// + * @n e_x_higher_than_th ,// + * @n e_y_lower_than_th,// + * @n e_y_higher_than_th,// + * @n e_z_lower_than_th,// + * @n e_z_higher_than_th,// + */ + void enable_interrupt_event(e_interrupt_source_t source, e_interrupt_event_t event); + + /** + * @fn get_int1_event + * @brief 检查中断1中是否产生中断事件'event' + * @param event Interrupt event + * @n e_x_lower_than_th ,// + * @n e_x_higher_than_th ,// + * @n e_y_lower_than_th,// + * @n e_y_higher_than_th,// + * @n e_z_lower_than_th,// + * @n e_z_higher_than_th,// + * @return true 产生/false 没有产生 + */ + bool get_int1_event(e_interrupt_event_t event); + + /** + * @fn get_int2_event + * @brief 检查中断2中是否产生中断事件'event' + * @param event Interrupt event + * @n e_x_lower_than_th ,// + * @n e_x_higher_than_th ,// + * @n e_y_lower_than_th,// + * @n e_y_higher_than_th,// + * @n e_z_lower_than_th,// + * @n e_z_higher_than_th,// + * @return true 产生/false 没有产生 + */ + bool get_int2_event(e_interrupt_event_t event); +``` +## 历史 + +- 2025/9/29 - WS63版本 V1.0.0 - Written by(Martin@dfrobot.com), 2025. +- 2021/2/1 - Arduino版本 V1.0.0 - Written by(li.feng@dfrobot.com,jie.tang@dfrobot.com), 2021. diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/resources/images/SEN0224_TOP.jpg b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/resources/images/SEN0224_TOP.jpg new file mode 100644 index 0000000000000000000000000000000000000000..40fdeae972fd38625cdba56ae6e5f760adf97703 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/dfrobot_lis2dh12/resources/images/SEN0224_TOP.jpg differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/get_acceleration_sample/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/get_acceleration_sample/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..536de15f34941a81c5bb50e7b40fc1351de4b0d3 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/get_acceleration_sample/CMakeLists.txt @@ -0,0 +1 @@ +set(SOURCES "${SOURCES}" "${CMAKE_CURRENT_SOURCE_DIR}/get_acceleration_sample.c" PARENT_SCOPE) \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/get_acceleration_sample/get_acceleration_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/get_acceleration_sample/get_acceleration_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..e4a9157116a0be0040b7ac3b9865a205595ea80f --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/get_acceleration_sample/get_acceleration_sample.c @@ -0,0 +1,87 @@ +/**! + * @file get_acceleration_sample.c + * @brief Get the acceleration in the three directions of xyz, the range can be ±2g、±4g、±8g、±16g + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/DFRobot_LIS + */ + +#include "dfrobot_lis2dh12.h" + +#define I2C_TASK_PRIO 24 +#define I2C_TASK_STACK_SIZE 0x1000 +#define DELAY_S 1000 +#define DELAY_MS 1 +#define ACCELERATION_DELAY_MS (300 * DELAY_MS) + +static void get_acceleration_task(void) +{ + // Chip initialization + while (!dfrobot_lis2dh12_init(CONFIG_I2C_SLAVE_ADDR, CONFIG_I2C_SCL_MASTER_PIN, CONFIG_I2C_SDA_MASTER_PIN, + CONFIG_I2C_MASTER_BUS_ID)) { + uapi_watchdog_kick(); + osal_printk("Initialization failed, please check the connection and I2C address settings\r\n"); + uapi_systick_delay_ms(DELAY_S); + } + + // Get chip id + osal_printk("chip id : %X\r\n", get_id()); + + /** + set range:Range(g) + E_LIS2DH12_2G,/< ±2g>/ + E_LIS2DH12_4G,/< ±4g>/ + E_LIS2DH12_8G,/< ±8g>/ + E_LIS2DH12_16G,/< ±16g>/ + */ + set_range(E_LIS2DH12_16G); + + /** + Set data measurement rate: + E_POWER_DOWN_0HZ + E_LOW_POWER_1HZ + E_LOW_POWER_10HZ + E_LOW_POWER_25HZ + E_LOW_POWER_50HZ + E_LOW_POWER_100HZ + E_LOW_POWER_200HZ + E_LOW_POWER_400HZ + */ + set_acquire_rate(E_LOW_POWER_10HZ); + osal_printk("Acceleration:\r\n"); + uapi_systick_delay_ms(DELAY_S); + + while (1) { + uapi_watchdog_kick(); + // Get the acceleration in the three directions of xyz + long ax; + long ay; + long az; + // The measurement range can be ±100g or ±200g set by the set_range() function + ax = read_acc_x(); // Get the acceleration in the x direction + ay = read_acc_y(); // Get the acceleration in the y direction + az = read_acc_z(); // Get the acceleration in the z direction + // Print acceleration + osal_printk("x: %d mg\t y: %d mg\t z: %d mg\r\n", ax, ay, az); + + uapi_systick_delay_ms(ACCELERATION_DELAY_MS); + } +} + +static void get_acceleration_entry(void) +{ + osal_task *task_handle = NULL; + osal_kthread_lock(); + task_handle = + osal_kthread_create((osal_kthread_handler)get_acceleration_task, 0, "getAccelerationTask", I2C_TASK_STACK_SIZE); + if (task_handle != NULL) { + osal_kthread_set_priority(task_handle, I2C_TASK_PRIO); + osal_kfree(task_handle); + } + osal_kthread_unlock(); +} + +app_run(get_acceleration_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img1.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img1.png new file mode 100644 index 0000000000000000000000000000000000000000..c224bb2648a7ce24bb0d54a33254ac8ca346ea7b Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img1.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img2.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img2.png new file mode 100644 index 0000000000000000000000000000000000000000..b11f35b1845b8170540375962d166d2c31b12e65 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img2.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img3.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img3.png new file mode 100644 index 0000000000000000000000000000000000000000..fffdafdc2055cbf3fbc31e3e590f0ab67385b82a Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img3.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img4.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img4.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc8406ab0112d002425adeff9f167396c042398 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/images/lis_img4.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/interrupt_sample/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/interrupt_sample/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce86711e4a32ebc6d36b3e23b349a8c655656a77 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/interrupt_sample/CMakeLists.txt @@ -0,0 +1 @@ +set(SOURCES "${SOURCES}" "${CMAKE_CURRENT_SOURCE_DIR}/interrupt_sample.c" PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/interrupt_sample/interrupt_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/interrupt_sample/interrupt_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..744b5d2569d6e4f866a0cb4f1d08c97a085b8a22 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/interrupt_sample/interrupt_sample.c @@ -0,0 +1,153 @@ +/**! + * @file interrupt_sample.c + * @brief Interrupt detection + * @n In this example, the enable E_Z_HIGHER_THAN_TH interrupt event means when the acceleration in the Z direction + * exceeds the + * @n threshold set by the program, the interrupt level can be detected on the interrupt pin int1/int2 we set, and the + * level change on the + * @n interrupt pin can be used to determine whether the interrupt occurs. The following are the 6 settable interrupt + * events:E_X_HIGHER_THAN_TH, + * @n E_X_LOWER_THAN_TH, E_Y_HIGHER_THAN_TH, E_Y_LOWER_THAN_TH, E_Z_HIGHER_THAN_TH, E_Z_LOWER_THAN_TH. For a detailed + * explanation of each of them, + * @n please look up the comments of the enable_interrupt_event() function. + * @n This example needs to connect the int2/int1 pin of the module to the interrupt pin of the motherboard. + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + * @url https://github.com/DFRobot/DFRobot_LIS + */ +#include "dfrobot_lis2dh12.h" + +#define I2C_TASK_PRIO 24 +#define I2C_TASK_STACK_SIZE 0x1000 +#define DELAY_S 1000 +#define DELAY_MS 1 +#define THRESHOLD 6 +#define INTERRUPT_DELAY_MS (300 * DELAY_MS) + +// Interrupt generation flag +volatile bool int_flag = false; + +void inter_event(pin_t pin, uintptr_t param) +{ + UNUSED(pin); + UNUSED(param); + int_flag = true; +} + +// from Arduino +#define RISING 0x00000001 +#define FALLING 0x00000002 +#define CHANGE 0x00000003 +#define ONLOW 0x00000004 +#define ONHIGH 0x00000005 + +void attach_interrupt(uint8_t pin, gpio_callback_t callback, uint32_t mode) +{ + uapi_pin_set_mode(pin, HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(pin, GPIO_DIRECTION_INPUT); + errcode_t ret = uapi_gpio_register_isr_func(pin, mode, callback); + if (ret != 0) { + uapi_gpio_unregister_isr_func(pin); + } +} + +static void interrupt_task(void) +{ + // Chip initialization + while (!dfrobot_lis2dh12_init(CONFIG_I2C_SLAVE_ADDR, CONFIG_I2C_SCL_MASTER_PIN, CONFIG_I2C_SDA_MASTER_PIN, + CONFIG_I2C_MASTER_BUS_ID)) { + uapi_watchdog_kick(); + osal_printk("Initialization failed, please check the connection and I2C address settings\r\n"); + uapi_systick_delay_ms(DELAY_S); + } + + // Get chip id + osal_printk("chip id : %X\r\n", get_id()); + + /** + set range:Range(g) + E_LIS2DH12_2G,/< ±2g>/ + E_LIS2DH12_4G,/< ±4g>/ + E_LIS2DH12_8G,/< ±8g>/ + E_LIS2DH12_16G,/< ±16g>/ + */ + set_range(E_LIS2DH12_16G); + + /** + Set data measurement rate: + E_POWER_DOWN_0HZ + E_LOW_POWER_1HZ + E_LOW_POWER_10HZ + E_LOW_POWER_25HZ + E_LOW_POWER_50HZ + E_LOW_POWER_100HZ + E_LOW_POWER_200HZ + E_LOW_POWER_400HZ + */ + set_acquire_rate(E_LOW_POWER_10HZ); + + attach_interrupt(CONFIG_INTERRUPT_PIN, inter_event, CHANGE); + + /** + Set the threshold of interrupt source 1 interrupt + threshold:Threshold(g) + */ + set_int1_th(THRESHOLD); // Unit: g + + /*! + Enable interrupt + Interrupt pin selection: + E_INT1 = 0,// + E_INT2,// + Interrupt event selection: + E_X_LOWER_THAN_TH ,// + E_X_HIGHER_THAN_TH ,// + E_Y_LOWER_THAN_TH,// + E_Y_HIGHER_THAN_TH,// + E_Z_LOWER_THAN_TH,// + E_Z_HIGHER_THAN_TH,// + */ + enable_interrupt_event(E_INT1 /* int pin */, E_Z_HIGHER_THAN_TH /* interrupt event */); + + uapi_systick_delay_ms(DELAY_S); + + while (1) { + uapi_watchdog_kick(); + // Get the acceleration in the three directions of xyz + long ax; + long ay; + long az; + // The measurement range can be ±100g or ±200g set by the set_range() function + ax = read_acc_x(); // Get the acceleration in the x direction + ay = read_acc_y(); // Get the acceleration in the y direction + az = read_acc_z(); // Get the acceleration in the z direction + // Print acceleration + osal_printk("x: %d mg\t y: %d mg\t z: %d mg\r\n", ax, ay, az); + uapi_systick_delay_ms(INTERRUPT_DELAY_MS); + // The interrupt flag is set + if (int_flag == true) { + // Check whether the interrupt event is generated in interrupt 1 + if (get_int1_event(E_Z_HIGHER_THAN_TH)) { + osal_printk("The acceleration in the z direction is greater than the threshold\r\n"); + } + int_flag = false; + } + } +} + +static void interrupt_entry(void) +{ + osal_task *task_handle = NULL; + osal_kthread_lock(); + task_handle = osal_kthread_create((osal_kthread_handler)interrupt_task, 0, "interruptTask", I2C_TASK_STACK_SIZE); + if (task_handle != NULL) { + osal_kthread_set_priority(task_handle, I2C_TASK_PRIO); + osal_kfree(task_handle); + } + osal_kthread_unlock(); +} + +app_run(interrupt_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..22945d59f0fb56abf4dc48b7f8ce3b75043894a3 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_lis2dh12/readme.md @@ -0,0 +1,42 @@ +# beetle_lis2dh12 + +## 一、介绍 + +dfrobot_lis2dh12是一个高性能的三轴加速度计传感器驱动库,基于 STMicroelectronics 的 LIS2DH12 传感器芯片开发。该库提供了完整的传感器控制接口,支持 I2C 通信协议,能够精确测量三个方向的加速度值,并具备丰富的中断功能。 + +详见:[[dfrobot_lis2dh12] readme.md](./dfrobot_lis2dh12/readme.md) + +## 二、加速度检测示例(get_acceleration_sample) + +### 1、介绍 + +本例程演示了一个基于LIS2DH12三轴加速度传感器的数据采集任务。程序首先通过I2C接口初始化传感器,支持设置±2g至±16g多种量程和1Hz至400Hz可调采样率,默认配置为±16g量程和10Hz采样速率。初始化成功后,程序进入循环采集状态,每300毫秒读取一次XYZ三个方向的加速度数值,并以毫重力加速度(mg)为单位通过串口打印输出,实时显示传感器的运动状态数据。该例程适用于运动检测、姿态识别和振动监测等嵌入式应用场景。 + +### 2、实验流程 + +- 执行Clean命令清理资源 +- 打开KConfig,选择获取加速度示例,并配置I2C相关引脚参数: + +![img](.\images\lis_img1.png) + +- 编译、烧录后,挥动传感器观察加速度参数打印是否正常: + +![img](.\images\lis_img2.png) + +## 三、中断检测示例(interrupt_sample) + +### 1、介绍 + +本例程演示了基于LIS2DH12加速度传感器的中断检测功能。程序通过配置中断引脚和阈值,实现了当Z轴加速度超过设定值(6g)时自动触发中断的机制。系统初始化后持续监测三轴加速度数据,并在检测到中断事件时立即输出"Z轴加速度超过阈值"的警告信息,实现了硬件级别的实时事件响应,适用于需要快速响应特定运动状态的应用场景如掉落检测、碰撞检测等等。 + +### 2、实验流程 + +- 执行Clean命令清理资源 +- 打开KConfig,选择掉落检测interrupt示例,并配置I2C相关引脚参数,注意需要配置中断引脚: + +![img](.\images\lis_img3.png) + +- 将传感器模块的INT1脚连接到选择的中断引脚 +- 编译、烧录后观察加速度参数打印是否正常,触发掉落检测,观察是否有相关中断打印: + +![img](.\images\lis_img4.png) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..387b107d2ec54b14e53ae6e0e2d8d78b585ff332 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/CMakeLists.txt @@ -0,0 +1,8 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/wifi/wifi_connect.c + ${CMAKE_CURRENT_SOURCE_DIR}/beetle_mqtt_sample.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/wifi) + +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" ${HEADER_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..87f6bccd4184bcd5229f0ca22eb54b3a866dc56e --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/Kconfig @@ -0,0 +1,44 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== + +config SERVER_IP_ADDR + string "Set MQTT server ip addr." + default "192.168.x.x" + +config WIFI_SSID + string "Set WIFI_SSID." + default "wifi_account" + +config WIFI_PWD + string "Set WIFI_PWD." + default "wifi_pwd" + +config MQTT_TOPIC_SUB + string "Set MQTT_TOPIC_SUB." + default "subTopic" + +config MQTT_TOPIC_PUB + string "Set MQTT_TOPIC_PUB." + default "pubTopic" + +config MQTT_PUB_MSG + string "Set MQTT_PUB_MSG." + default "hello!" + +config MQTT_AUTH_ENABLE + bool "Enable MQTT Authentication" + default n + help + Enable MQTT username and password authentication + +config MQTT_USERNAME + string "Set MQTT username" + default "mqtt_user" + depends on MQTT_AUTH_ENABLE + +config MQTT_PASSWORD + string "Set MQTT password" + default "mqtt_pass" + depends on MQTT_AUTH_ENABLE \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/beetle_mqtt_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/beetle_mqtt_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..a009764bf4bf3667d4da379ee041ae18a88e2674 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/beetle_mqtt_sample.c @@ -0,0 +1,147 @@ +/**! + * @file beetle_mqtt_sample.c + * @brief The development board connects to an MQTT server to publish and subscribe to messages. + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + */ + +#include "soc_osal.h" +#include "app_init.h" +#include "cmsis_os2.h" +#include +#include +#include +#include "common_def.h" +#include "MQTTClientPersistence.h" +#include "MQTTClient.h" +#include "errcode.h" +#include "wifi/wifi_connect.h" +osThreadId_t mqtt_init_task_id; // mqtt订阅数据任务 + +#define CLIENT_ID "ADMIN" + +char *g_msg = CONFIG_MQTT_PUB_MSG; +MQTTClient client; +volatile MQTTClient_deliveryToken deliveredToken; +extern int MQTTClient_init(void); + +/* 回调函数,处理消息到达 */ +void delivered(void *context, MQTTClient_deliveryToken dt) +{ + (void)context; + printf("Message with token value %d delivery confirmed\n", dt); + deliveredToken = dt; +} + +/* 回调函数,处理接收到的消息 */ +int messageArrived(void *context, char *topicname, int topiclen, MQTTClient_message *message) +{ + (void)context; + (void)topiclen; + printf("Message arrived on topic: %s\n", topicname); + printf("Message: %.*s\n", message->payloadlen, (char *)message->payload); + return 1; // 表示消息已被处理 +} + +/* 回调函数,处理连接丢失 */ +void connlost(void *context, char *cause) +{ + (void)context; + printf("Connection lost: %s\n", cause); +} +/* 消息订阅 */ +int mqtt_subscribe(const char *topic) +{ + printf("subscribe start\r\n"); + MQTTClient_subscribe(client, topic, 1); + return 0; +} + +int mqtt_publish(const char *topic, char *g_msg) +{ + MQTTClient_message pubmsg = MQTTClient_message_initializer; + MQTTClient_deliveryToken token; + int ret = 0; + pubmsg.payload = g_msg; + pubmsg.payloadlen = (int)strlen(g_msg); + pubmsg.qos = 1; + pubmsg.retained = 0; + ret = MQTTClient_publishMessage(client, topic, &pubmsg, &token); + if (ret != MQTTCLIENT_SUCCESS) { + printf("mqtt_publish failed\r\n"); + } + printf("mqtt_publish(), the payload is %s, the topic is %s\r\n", g_msg, topic); + return ret; +} +static errcode_t mqtt_connect(void) +{ + int ret; + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; + /* 初始化MQTT客户端 */ + MQTTClient_init(); + /* 创建 MQTT 客户端 */ + ret = MQTTClient_create(&client, CONFIG_SERVER_IP_ADDR, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL); + if (ret != MQTTCLIENT_SUCCESS) { + printf("Failed to create MQTT client, return code %d\n", ret); + return ERRCODE_FAIL; + } + conn_opts.keepAliveInterval = 120; /* 120: 保活时间 */ + conn_opts.cleansession = 1; + +#ifdef CONFIG_MQTT_AUTH_ENABLE + // 设置MQTT服务器认证信息 + conn_opts.username = CONFIG_MQTT_USERNAME; + conn_opts.password = CONFIG_MQTT_PASSWORD; +#endif + + // 绑定回调函数 + MQTTClient_setCallbacks(client, NULL, connlost, messageArrived, delivered); + + // 尝试连接 + if ((ret = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { + printf("Failed to connect, return code %d\n", ret); + MQTTClient_destroy(&client); // 连接失败时销毁客户端 + return ERRCODE_FAIL; + } + printf("Connected to MQTT broker!\n"); + osDelay(200); /* 200: 延时2s */ + // 订阅MQTT主题 + mqtt_subscribe(CONFIG_MQTT_TOPIC_SUB); + while (1) { + osDelay(100); /* 100: 延时1s */ + mqtt_publish(CONFIG_MQTT_TOPIC_PUB, g_msg); + } + + return ERRCODE_SUCC; +} +void mqtt_init_task(const char *argument) +{ + unused(argument); + wifi_connect(); + osDelay(200); /* 200: 延时2s */ + mqtt_connect(); +} + +static void network_wifi_mqtt_example(void) +{ + printf("Enter network_wifi_mqtt_example()!"); + + osThreadAttr_t options; + options.name = "mqtt_init_task"; + options.attr_bits = 0; + options.cb_mem = NULL; + options.cb_size = 0; + options.stack_mem = NULL; + options.stack_size = 0x3000; + options.priority = osPriorityNormal; + + mqtt_init_task_id = osThreadNew((osThreadFunc_t)mqtt_init_task, NULL, &options); + if (mqtt_init_task_id != NULL) { + printf("ID = %d, Create mqtt_init_task_id is OK!", mqtt_init_task_id); + } +} +/* Run the sample. */ +app_run(network_wifi_mqtt_example); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img1.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img1.png new file mode 100644 index 0000000000000000000000000000000000000000..b9f5d27d9948274003130cfe990e29dbd258d04a Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img1.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img2.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img2.png new file mode 100644 index 0000000000000000000000000000000000000000..ced6812dc04e70fa2d2b287f078d6f6e9584d106 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img2.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img3.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img3.png new file mode 100644 index 0000000000000000000000000000000000000000..0b0f91173ee619f9364b87f806216ffee3c2c7f5 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img3.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img4.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img4.png new file mode 100644 index 0000000000000000000000000000000000000000..2cb0a6e28f8fa8351e4c2a4c51a606b1a6e4562a Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img4.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img5.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img5.png new file mode 100644 index 0000000000000000000000000000000000000000..93f94daf089f090429004ebd75284968faccb404 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/images/mqtt_img5.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..c6591412520b6a7ea1f02e4ac41ba650972b4edc --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/readme.md @@ -0,0 +1,33 @@ +# beetle_mqtt + +## 一、介绍 + +本例程演示了如何在WS63开发板上实现MQTT客户端功能,通过本地回环测试验证MQTT消息的发布和订阅能力。开发板连接到MQTT服务器后,能够: + +- 自动发布消息:周期性地向指定主题发布预设消息 +- 实时订阅消息:监听同一主题并接收处理消息 + +## 二、实验流程 + +安装MQTT服务器EMQX和客户端MQTTX,注意开发板和PC需处于同一局域网内。 + +- 执行Clean命令清理资源 +- 安装emqx服务器并开启服务: + +![img](.\images\mqtt_img1.png) + +- 打开KConfig,选择MQTT示例,并配置好服务器地址、WIFI账号密码、订阅主题,发布主题和发布消息: + +![img](.\images\mqtt_img2.png) + +- 若连接的MQTT服务器需要配置认证信息(如SIOT服务器),请勾选"Enable MQTT Authentication"并配置账户密码: + +![img](.\images\mqtt_img3.png) + +- 编译、烧录后,打开MQTTX客户端,订阅配置好的pubTopc,观察发布的消息: + +![img](.\images\mqtt_img4.png) + +- MQTTX客户端这边发布主题为subTopic消息,观察开发板打印: + +![img](.\images\mqtt_img5.png) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/wifi/wifi_connect.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/wifi/wifi_connect.c new file mode 100644 index 0000000000000000000000000000000000000000..56eeb956e7908a300be3332d60b2c605167c74d4 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/wifi/wifi_connect.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2024 HiSilicon Technologies CO., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lwip/netifapi.h" +#include "wifi_hotspot.h" +#include "wifi_hotspot_config.h" +#include "stdlib.h" +#include "uart.h" +#include "lwip/nettool/misc.h" +#include "soc_osal.h" +#include "app_init.h" +#include "cmsis_os2.h" +#include "wifi_connect.h" + +#define WIFI_SCAN_AP_LIMIT 64 +#define WIFI_CONN_STATUS_MAX_GET_TIMES 5 /* 启动连接之后,判断是否连接成功的最大尝试次数 */ +#define DHCP_BOUND_STATUS_MAX_GET_TIMES 20 /* 启动DHCP Client端功能之后,判断是否绑定成功的最大尝试次数 */ +#define WIFI_STA_IP_MAX_GET_TIMES 5 /* 判断是否获取到IP的最大尝试次数 */ + +/***************************************************************************** + STA 扫描-关联 sample用例 +*****************************************************************************/ +static errcode_t example_get_match_network(const char *expected_ssid, + const char *key, + wifi_sta_config_stru *expected_bss) +{ + uint32_t num = WIFI_SCAN_AP_LIMIT; /* 64:扫描到的Wi-Fi网络数量 */ + uint32_t bss_index = 0; + + /* 获取扫描结果 */ + uint32_t scan_len = sizeof(wifi_scan_info_stru) * WIFI_SCAN_AP_LIMIT; + wifi_scan_info_stru *result = osal_kmalloc(scan_len, OSAL_GFP_ATOMIC); + if (result == NULL) { + return ERRCODE_MALLOC; + } + + memset_s(result, scan_len, 0, scan_len); + if (wifi_sta_get_scan_info(result, &num) != ERRCODE_SUCC) { + osal_kfree(result); + return ERRCODE_FAIL; + } + + /* 筛选扫描到的Wi-Fi网络,选择待连接的网络 */ + for (bss_index = 0; bss_index < num; bss_index++) { + if (strlen(expected_ssid) == strlen(result[bss_index].ssid)) { + if (memcmp(expected_ssid, result[bss_index].ssid, strlen(expected_ssid)) == 0) { + break; + } + } + } + + /* 未找到待连接AP,可以继续尝试扫描或者退出 */ + if (bss_index >= num) { + osal_kfree(result); + return ERRCODE_FAIL; + } + /* 找到网络后复制网络信息和接入密码 */ + if (memcpy_s(expected_bss->ssid, WIFI_MAX_SSID_LEN, result[bss_index].ssid, WIFI_MAX_SSID_LEN) != EOK) { + osal_kfree(result); + return ERRCODE_MEMCPY; + } + if (memcpy_s(expected_bss->bssid, WIFI_MAC_LEN, result[bss_index].bssid, WIFI_MAC_LEN) != EOK) { + osal_kfree(result); + return ERRCODE_MEMCPY; + } + expected_bss->security_type = result[bss_index].security_type; + if (memcpy_s(expected_bss->pre_shared_key, WIFI_MAX_KEY_LEN, key, strlen(key)) != EOK) { + osal_kfree(result); + return ERRCODE_MEMCPY; + } + expected_bss->ip_type = DHCP; /* IP类型为动态DHCP获取 */ + osal_kfree(result); + return ERRCODE_SUCC; +} + +errcode_t wifi_connect(void) +{ + char ifname[WIFI_IFNAME_MAX_SIZE + 1] = "wlan0"; /* WiFi STA 网络设备名 */ + wifi_sta_config_stru expected_bss = {0}; /* 连接请求信息 */ + const char expected_ssid[] = CONFIG_WIFI_SSID; + const char key[] = CONFIG_WIFI_PWD; /* 待连接的网络接入密码 */ + struct netif *netif_p = NULL; + wifi_linked_info_stru wifi_status; + uint8_t index = 0; + + /* 等待wifi初始化完成 */ + while (wifi_is_wifi_inited() == 0) { + (void)osDelay(1); /* 1: 延时1ms */ + } + /* 创建STA */ + if (wifi_sta_enable() != ERRCODE_SUCC) { + printf("STA enbale fail !\r\n"); + return ERRCODE_FAIL; + } + do { + printf("Start Scan !\r\n"); + (void)osDelay(100); /* 100: 延时1s */ + /* 启动STA扫描 */ + if (wifi_sta_scan() != ERRCODE_SUCC) { + printf("STA scan fail, try again !\r\n"); + continue; + } + + (void)osDelay(300); /* 300: 延时3s */ + + /* 获取待连接的网络 */ + if (example_get_match_network(expected_ssid, key, &expected_bss) != ERRCODE_SUCC) { + printf("Can not find AP, try again !\r\n"); + continue; + } + + printf("STA start connect.\r\n"); + /* 启动连接 */ + if (wifi_sta_connect(&expected_bss) != ERRCODE_SUCC) { + continue; + } + + /* 检查网络是否连接成功 */ + for (index = 0; index < WIFI_CONN_STATUS_MAX_GET_TIMES; index++) { + (void)osDelay(50); /* 延时500ms */ + memset_s(&wifi_status, sizeof(wifi_linked_info_stru), 0, sizeof(wifi_linked_info_stru)); + if (wifi_sta_get_ap_info(&wifi_status) != ERRCODE_SUCC) { + continue; + } + if (wifi_status.conn_state == WIFI_CONNECTED) { + break; + } + } + if (wifi_status.conn_state == WIFI_CONNECTED) { + break; /* 连接成功退出循环 */ + } + } while (1); + + /* DHCP获取IP地址 */ + netif_p = netifapi_netif_find(ifname); + if (netif_p == NULL) { + return ERRCODE_FAIL; + } + + if (netifapi_dhcp_start(netif_p) != ERR_OK) { + printf("STA DHCP Fail.\r\n"); + return ERRCODE_FAIL; + } + + for (uint8_t i = 0; i < DHCP_BOUND_STATUS_MAX_GET_TIMES; i++) { + (void)osDelay(500); /* 500: 延时5s */ + if (netifapi_dhcp_is_bound(netif_p) == ERR_OK) { + printf("STA DHCP bound success.\r\n"); + break; + } + } + + for (uint8_t i = 0; i < WIFI_STA_IP_MAX_GET_TIMES; i++) { + osDelay(10); /* 10: 延时10ms */ + if (netif_p->ip_addr.u_addr.ip4.addr != 0) { + printf("STA IP %u.%u.%u.%u\r\n", (netif_p->ip_addr.u_addr.ip4.addr & 0x000000ff), + (netif_p->ip_addr.u_addr.ip4.addr & 0x0000ff00) >> 8, /* 8: 移位 */ + (netif_p->ip_addr.u_addr.ip4.addr & 0x00ff0000) >> 16, /* 16: 移位 */ + (netif_p->ip_addr.u_addr.ip4.addr & 0xff000000) >> 24); /* 24: 移位 */ + + /* 连接成功 */ + printf("STA connect success.\r\n"); + return ERRCODE_SUCC; + } + } + printf("STA connect fail.\r\n"); + return ERRCODE_FAIL; +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/wifi/wifi_connect.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/wifi/wifi_connect.h new file mode 100644 index 0000000000000000000000000000000000000000..4f2c65b7c75abcc34a7ba01a60816d89e3fea98a --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_mqtt/wifi/wifi_connect.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 HiSilicon Technologies CO., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WIFI_CONNECT_H +#define WIFI_CONNECT_H + +errcode_t wifi_connect(void); +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..07cf690501d7fd6a9ab919ef6dfa79217af4a592 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/CMakeLists.txt @@ -0,0 +1,21 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== +if(DEFINED CONFIG_SAMPLE_SUPPORT_SLE_UART_SERVER) +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/sle_uart_server/sle_uart_server_adv.c + ${CMAKE_CURRENT_SOURCE_DIR}/sle_uart_server/sle_uart_server.c + ${CMAKE_CURRENT_SOURCE_DIR}/sle_uart_sample.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/sle_uart_server) +elseif(DEFINED CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT) +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/sle_uart_client/sle_uart_client.c + ${CMAKE_CURRENT_SOURCE_DIR}/sle_uart_sample.c +) +set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/sle_uart_client) +endif() + +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) +set(PUBLIC_HEADER "${PUBLIC_HEADER}" ${HEADER_LIST} PARENT_SCOPE) \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..f70600a01967a35ff05fe5fa79ecdb99f7858734 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/Kconfig @@ -0,0 +1,41 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved. +#=============================================================================== + +config SLE_UART_BUS + int + prompt "Set the UART BUS of the currrent sample." + default 0 + depends on SAMPLE_SUPPORT_SLE_UART + help + This option means the UART BUS of the currrent sample. + +config UART_TXD_PIN + int + prompt "Choose UART TXD pin." + depends on SAMPLE_SUPPORT_SLE_UART + default 17 + +config UART_RXD_PIN + int + prompt "Choose UART RXD pin." + depends on SAMPLE_SUPPORT_SLE_UART + default 18 + +choice + prompt "Select sle uart type" + default SAMPLE_SUPPORT_SLE_UART_SERVER + config SAMPLE_SUPPORT_SLE_UART_SERVER + bool "Enable SLE UART Server sample." + config SAMPLE_SUPPORT_SLE_UART_CLIENT + bool "Enable SLE UART Client sample." +endchoice +config SUPPORT_SLE_PERIPHERAL + bool + default y if (SAMPLE_SUPPORT_SLE_UART_SERVER) + + +config SUPPORT_SLE_CENTRAL + bool + default y if (SAMPLE_SUPPORT_SLE_UART_CLIENT) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/images/sleuart_img1.PNG b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/images/sleuart_img1.PNG new file mode 100644 index 0000000000000000000000000000000000000000..16aa45f0a5e19921bb872ec5e8af79bfb23a8cdd Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/images/sleuart_img1.PNG differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/images/sleuart_img2.PNG b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/images/sleuart_img2.PNG new file mode 100644 index 0000000000000000000000000000000000000000..f810d24c702b56ff9723561d6a2a8a8872c6639d Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/images/sleuart_img2.PNG differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/readme.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..865b8e1d86ab2ae5ad5e8e4e7fb63dc69380e27f --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/readme.md @@ -0,0 +1,21 @@ +# beetle_sle_uart + +## 一、介绍 + +本例程演示了如何使用两块WS63开发板通过SLE进行双向数据传输: + +- 开发板A(Server端)和开发板B(Client端)配对连接 +- A板:串口接收数据 → SLE发送 → B板:SLE接收 → 串口打印 +- B板:串口接收数据 → SLE发送 → A板:SLE接收 → 串口打印 + +## 二、实验流程 + +打开kconfig勾选beetle_demo例程中的SLE_UART示例,准备两块WS63开发板A和B,A烧录SLE_Server示例,B烧录SLE_Client示例: + +![img](.\images\sleuart_img1.PNG) + +烧录完成后,启动两个串口助手分别连接到A和B,测试AB互发消息: + +![img](.\images\sleuart_img2.PNG) + +然后交换AB固件烧录,再次观察打印。 diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_client/sle_uart_client.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_client/sle_uart_client.c new file mode 100644 index 0000000000000000000000000000000000000000..8b8528a0282eacbe015c682aca2ddb78c73cea68 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_client/sle_uart_client.c @@ -0,0 +1,246 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: SLE uart sample of client. \n + * + * History: \n + * 2023-04-03, Create file. \n + */ +#include "common_def.h" +#include "soc_osal.h" +#include "securec.h" +#include "product.h" +#include "bts_le_gap.h" + +#include "sle_device_discovery.h" +#include "sle_connection_manager.h" +#include "sle_uart_client.h" +#define SLE_MTU_SIZE_DEFAULT 520 +#define SLE_SEEK_INTERVAL_DEFAULT 100 +#define SLE_SEEK_WINDOW_DEFAULT 100 +#define UUID_16BIT_LEN 2 +#define UUID_128BIT_LEN 16 +#define SLE_UART_TASK_DELAY_MS 1000 +#define SLE_UART_WAIT_SLE_CORE_READY_MS 5000 +#define SLE_UART_RECV_CNT 1000 +#define SLE_UART_LOW_LATENCY_2K 2000 +#ifndef SLE_UART_SERVER_NAME +#define SLE_UART_SERVER_NAME "sle_uart_server" +#endif +#define SLE_UART_CLIENT_LOG "[sle uart client]" +#define DELAY_MS 5000 + +/** SLE address array index constants */ +#define SLE_ADDR_INDEX_0 0 +#define SLE_ADDR_INDEX_4 4 +#define SLE_ADDR_INDEX_5 5 + +static ssapc_find_service_result_t g_sle_uart_find_service_result = {0}; +static sle_announce_seek_callbacks_t g_sle_uart_seek_cbk = {0}; +static sle_connection_callbacks_t g_sle_uart_connect_cbk = {0}; +static ssapc_callbacks_t g_sle_uart_ssapc_cbk = {0}; +static sle_addr_t g_sle_uart_remote_addr = {0}; +ssapc_write_param_t g_sle_uart_send_param = {0}; +uint16_t g_sle_uart_conn_id = 0; + +uint16_t get_g_sle_uart_conn_id(void) +{ + return g_sle_uart_conn_id; +} + +ssapc_write_param_t *get_g_sle_uart_send_param(void) +{ + return &g_sle_uart_send_param; +} + +void sle_uart_start_scan(void) +{ + sle_seek_param_t param = {0}; + param.own_addr_type = 0; + param.filter_duplicates = 0; + param.seek_filter_policy = 0; + param.seek_phys = 1; + param.seek_type[0] = 1; + param.seek_interval[0] = SLE_SEEK_INTERVAL_DEFAULT; + param.seek_window[0] = SLE_SEEK_WINDOW_DEFAULT; + sle_set_seek_param(¶m); + sle_start_seek(); +} + +static void sle_uart_client_sample_sle_enable_cbk(errcode_t status) +{ + osal_printk("sle enable: %d.\r\n", status); + sle_uart_client_init(sle_uart_notification_cb, sle_uart_indication_cb); + sle_uart_start_scan(); +} + +static void sle_uart_client_sample_seek_enable_cbk(errcode_t status) +{ + if (status != 0) { + osal_printk("%s sle_uart_client_sample_seek_enable_cbk,status error\r\n", SLE_UART_CLIENT_LOG); + } +} + +static void sle_uart_client_sample_seek_result_info_cbk(sle_seek_result_info_t *seek_result_data) +{ + osal_printk("%s sle uart scan data :%s\r\n", SLE_UART_CLIENT_LOG, seek_result_data->data); + if (seek_result_data == NULL) { + osal_printk("status error\r\n"); + } else if (strstr((const char *)seek_result_data->data, SLE_UART_SERVER_NAME) != NULL) { + memcpy_s(&g_sle_uart_remote_addr, sizeof(sle_addr_t), &seek_result_data->addr, sizeof(sle_addr_t)); + sle_stop_seek(); + } +} + +static void sle_uart_client_sample_seek_disable_cbk(errcode_t status) +{ + if (status != 0) { + osal_printk("%s sle_uart_client_sample_seek_disable_cbk,status error = %x\r\n", SLE_UART_CLIENT_LOG, status); + } else { + sle_remove_paired_remote_device(&g_sle_uart_remote_addr); + sle_connect_remote_device(&g_sle_uart_remote_addr); + } +} + +static void sle_uart_client_sample_seek_cbk_register(void) +{ + g_sle_uart_seek_cbk.sle_enable_cb = sle_uart_client_sample_sle_enable_cbk; + g_sle_uart_seek_cbk.seek_enable_cb = sle_uart_client_sample_seek_enable_cbk; + g_sle_uart_seek_cbk.seek_result_cb = sle_uart_client_sample_seek_result_info_cbk; + g_sle_uart_seek_cbk.seek_disable_cb = sle_uart_client_sample_seek_disable_cbk; + sle_announce_seek_register_callbacks(&g_sle_uart_seek_cbk); +} + +static void sle_uart_client_sample_connect_state_changed_cbk(uint16_t conn_id, + const sle_addr_t *addr, + sle_acb_state_t conn_state, + sle_pair_state_t pair_state, + sle_disc_reason_t disc_reason) +{ + unused(addr); + unused(pair_state); + osal_printk("%s conn state changed disc_reason:0x%x\r\n", SLE_UART_CLIENT_LOG, disc_reason); + g_sle_uart_conn_id = conn_id; + if (conn_state == SLE_ACB_STATE_CONNECTED) { + osal_printk("%s SLE_ACB_STATE_CONNECTED\r\n", SLE_UART_CLIENT_LOG); + if (pair_state == SLE_PAIR_NONE) { + sle_pair_remote_device(&g_sle_uart_remote_addr); + } + osal_printk("%s sle_low_latency_rx_enable \r\n", SLE_UART_CLIENT_LOG); + } else if (conn_state == SLE_ACB_STATE_NONE) { + osal_printk("%s SLE_ACB_STATE_NONE\r\n", SLE_UART_CLIENT_LOG); + } else if (conn_state == SLE_ACB_STATE_DISCONNECTED) { + osal_printk("%s SLE_ACB_STATE_DISCONNECTED\r\n", SLE_UART_CLIENT_LOG); + sle_remove_paired_remote_device(&g_sle_uart_remote_addr); + sle_uart_start_scan(); + } else { + osal_printk("%s status error\r\n", SLE_UART_CLIENT_LOG); + } +} + +void sle_uart_client_sample_pair_complete_cbk(uint16_t conn_id, const sle_addr_t *addr, errcode_t status) +{ + osal_printk("%s pair complete conn_id:%d, addr:%02x***%02x%02x\n", SLE_UART_CLIENT_LOG, conn_id, + addr->addr[SLE_ADDR_INDEX_0], addr->addr[SLE_ADDR_INDEX_4], addr->addr[SLE_ADDR_INDEX_5]); + if (status == 0) { + ssap_exchange_info_t info = {0}; + info.mtu_size = SLE_MTU_SIZE_DEFAULT; + info.version = 1; + ssapc_exchange_info_req(0, g_sle_uart_conn_id, &info); + } +} + +static void sle_uart_client_sample_connect_cbk_register(void) +{ + g_sle_uart_connect_cbk.connect_state_changed_cb = sle_uart_client_sample_connect_state_changed_cbk; + g_sle_uart_connect_cbk.pair_complete_cb = sle_uart_client_sample_pair_complete_cbk; + sle_connection_register_callbacks(&g_sle_uart_connect_cbk); +} + +static void sle_uart_client_sample_exchange_info_cbk(uint8_t client_id, + uint16_t conn_id, + ssap_exchange_info_t *param, + errcode_t status) +{ + osal_printk("%s exchange_info_cbk,pair complete client id:%d status:%d\r\n", SLE_UART_CLIENT_LOG, client_id, + status); + osal_printk("%s exchange mtu, mtu size: %d, version: %d.\r\n", SLE_UART_CLIENT_LOG, param->mtu_size, + param->version); + ssapc_find_structure_param_t find_param = {0}; + find_param.type = SSAP_FIND_TYPE_PROPERTY; + find_param.start_hdl = 1; + find_param.end_hdl = 0xFFFF; + ssapc_find_structure(0, conn_id, &find_param); +} + +static void sle_uart_client_sample_find_structure_cbk(uint8_t client_id, + uint16_t conn_id, + ssapc_find_service_result_t *service, + errcode_t status) +{ + osal_printk("%s find structure cbk client: %d conn_id:%d status: %d \r\n", SLE_UART_CLIENT_LOG, client_id, conn_id, + status); + osal_printk("%s find structure start_hdl:[0x%02x], end_hdl:[0x%02x], uuid len:%d\r\n", SLE_UART_CLIENT_LOG, + service->start_hdl, service->end_hdl, service->uuid.len); + g_sle_uart_find_service_result.start_hdl = service->start_hdl; + g_sle_uart_find_service_result.end_hdl = service->end_hdl; + memcpy_s(&g_sle_uart_find_service_result.uuid, sizeof(sle_uuid_t), &service->uuid, sizeof(sle_uuid_t)); +} + +static void sle_uart_client_sample_find_property_cbk(uint8_t client_id, + uint16_t conn_id, + ssapc_find_property_result_t *property, + errcode_t status) +{ + osal_printk( + "%s sle_uart_client_sample_find_property_cbk, client id: %d, conn id: %d, operate ind: %d, " + "descriptors count: %d status:%d property->handle %d\r\n", + SLE_UART_CLIENT_LOG, client_id, conn_id, property->operate_indication, property->descriptors_count, status, + property->handle); + g_sle_uart_send_param.handle = property->handle; + g_sle_uart_send_param.type = SSAP_PROPERTY_TYPE_VALUE; +} + +static void sle_uart_client_sample_find_structure_cmp_cbk(uint8_t client_id, + uint16_t conn_id, + ssapc_find_structure_result_t *structure_result, + errcode_t status) +{ + unused(conn_id); + osal_printk("%s sle_uart_client_sample_find_structure_cmp_cbk,client id:%d status:%d type:%d uuid len:%d \r\n", + SLE_UART_CLIENT_LOG, client_id, status, structure_result->type, structure_result->uuid.len); +} + +static void sle_uart_client_sample_write_cfm_cb(uint8_t client_id, + uint16_t conn_id, + ssapc_write_result_t *write_result, + errcode_t status) +{ + osal_printk("%s sle_uart_client_sample_write_cfm_cb, conn_id:%d client id:%d status:%d handle:%02x type:%02x\r\n", + SLE_UART_CLIENT_LOG, conn_id, client_id, status, write_result->handle, write_result->type); +} + +static void sle_uart_client_sample_ssapc_cbk_register(ssapc_notification_callback notification_cb, + ssapc_notification_callback indication_cb) +{ + g_sle_uart_ssapc_cbk.exchange_info_cb = sle_uart_client_sample_exchange_info_cbk; + g_sle_uart_ssapc_cbk.find_structure_cb = sle_uart_client_sample_find_structure_cbk; + g_sle_uart_ssapc_cbk.ssapc_find_property_cbk = sle_uart_client_sample_find_property_cbk; + g_sle_uart_ssapc_cbk.find_structure_cmp_cb = sle_uart_client_sample_find_structure_cmp_cbk; + g_sle_uart_ssapc_cbk.write_cfm_cb = sle_uart_client_sample_write_cfm_cb; + g_sle_uart_ssapc_cbk.notification_cb = notification_cb; + g_sle_uart_ssapc_cbk.indication_cb = indication_cb; + ssapc_register_callbacks(&g_sle_uart_ssapc_cbk); +} + +void sle_uart_client_init(ssapc_notification_callback notification_cb, ssapc_indication_callback indication_cb) +{ + (void)osal_msleep(DELAY_MS); /* 延时5000ms,等待SLE初始化完毕 */ + osal_printk("[SLE Client] try enable.\r\n"); + sle_uart_client_sample_seek_cbk_register(); + sle_uart_client_sample_connect_cbk_register(); + sle_uart_client_sample_ssapc_cbk_register(notification_cb, indication_cb); + if (enable_sle() != ERRCODE_SUCC) { + osal_printk("[SLE Client] sle enbale fail !\r\n"); + } +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_client/sle_uart_client.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_client/sle_uart_client.h new file mode 100644 index 0000000000000000000000000000000000000000..d0b96016df7c896fb3cfbf25e237340fe2056db4 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_client/sle_uart_client.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: SLE UART sample of client. \n + * + * History: \n + * 2023-04-03, Create file. \n + */ +#ifndef SLE_UART_CLIENT_H +#define SLE_UART_CLIENT_H + +#include "sle_ssap_client.h" + +void sle_uart_client_init(ssapc_notification_callback notification_cb, ssapc_indication_callback indication_cb); + +void sle_uart_start_scan(void); + +uint16_t get_g_sle_uart_conn_id(void); + +ssapc_write_param_t *get_g_sle_uart_send_param(void); +void sle_uart_notification_cb(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data, errcode_t status); +void sle_uart_indication_cb(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data, errcode_t status); + +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..d9ad8f3d8d3241a56e1d5ca985b40905ec62c1e7 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_sample.c @@ -0,0 +1,245 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: SLE UART Sample Source. \n + * + * History: \n + * 2023-07-17, Create file. \n + */ +#include "common_def.h" +#include "soc_osal.h" +#include "app_init.h" +#include "pinctrl.h" +#include "uart.h" +#include "sle_low_latency.h" +#if defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_SERVER) +#include "securec.h" +#include "sle_uart_server.h" +#include "sle_uart_server_adv.h" +#include "sle_device_discovery.h" +#include "sle_errcode.h" +#elif defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT) +#define SLE_UART_TASK_STACK_SIZE 0x600 +#include "sle_connection_manager.h" +#include "sle_ssap_client.h" +#include "sle_uart_client.h" +#endif /* CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT */ + +#define SLE_UART_TASK_PRIO 28 +#define SLE_UART_TASK_DURATION_MS 2000 +#define SLE_UART_BAUDRATE 115200 +#define SLE_UART_TRANSFER_SIZE 512 + +static uint8_t g_app_uart_rx_buff[SLE_UART_TRANSFER_SIZE] = {0}; + +static uart_buffer_config_t g_app_uart_buffer_config = {.rx_buffer = g_app_uart_rx_buff, + .rx_buffer_size = SLE_UART_TRANSFER_SIZE}; + +static void uart_init_pin(void) +{ + if (CONFIG_SLE_UART_BUS == 0) { + uapi_pin_set_mode(CONFIG_UART_TXD_PIN, PIN_MODE_1); + uapi_pin_set_mode(CONFIG_UART_RXD_PIN, PIN_MODE_1); + } else if (CONFIG_SLE_UART_BUS == 1) { + uapi_pin_set_mode(CONFIG_UART_TXD_PIN, PIN_MODE_1); + uapi_pin_set_mode(CONFIG_UART_RXD_PIN, PIN_MODE_1); + } +} + +static void uart_init_config(void) +{ + uart_attr_t attr = {.baud_rate = SLE_UART_BAUDRATE, + .data_bits = UART_DATA_BIT_8, + .stop_bits = UART_STOP_BIT_1, + .parity = UART_PARITY_NONE}; + + uart_pin_config_t pin_config = { + .tx_pin = CONFIG_UART_TXD_PIN, .rx_pin = CONFIG_UART_RXD_PIN, .cts_pin = PIN_NONE, .rts_pin = PIN_NONE}; + uapi_uart_deinit(CONFIG_SLE_UART_BUS); + uapi_uart_init(CONFIG_SLE_UART_BUS, &pin_config, &attr, NULL, &g_app_uart_buffer_config); +} + +#if defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_SERVER) +#define SLE_UART_SERVER_DELAY_COUNT 5 + +#define SLE_UART_TASK_STACK_SIZE 0x1200 +#define SLE_ADV_HANDLE_DEFAULT 1 +#define SLE_UART_SERVER_MSG_QUEUE_LEN 5 +#define SLE_UART_SERVER_MSG_QUEUE_MAX_SIZE 32 +#define SLE_UART_SERVER_QUEUE_DELAY 0xFFFFFFFF +#define SLE_UART_SERVER_BUFF_MAX_SIZE 800 + +unsigned long g_sle_uart_server_msgqueue_id; +#define SLE_UART_SERVER_LOG "[sle uart server]" +static void ssaps_server_read_request_cbk(uint8_t server_id, + uint16_t conn_id, + ssaps_req_read_cb_t *read_cb_para, + errcode_t status) +{ + osal_printk("%s ssaps read request cbk callback server_id:%x, conn_id:%x, handle:%x, status:%x\r\n", + SLE_UART_SERVER_LOG, server_id, conn_id, read_cb_para->handle, status); +} +static void ssaps_server_write_request_cbk(uint8_t server_id, + uint16_t conn_id, + ssaps_req_write_cb_t *write_cb_para, + errcode_t status) +{ + osal_printk("%s ssaps write request callback cbk server_id:%x, conn_id:%x, handle:%x, status:%x\r\n", + SLE_UART_SERVER_LOG, server_id, conn_id, write_cb_para->handle, status); + if ((write_cb_para->length > 0) && write_cb_para->value) { + osal_printk("\n sle uart recived data : %s\r\n", write_cb_para->value); + uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)write_cb_para->value, write_cb_para->length, 0); + } +} + +static void sle_uart_server_read_int_handler(const void *buffer, uint16_t length, bool error) +{ + unused(error); + if (sle_uart_client_is_connected()) { + sle_uart_server_send_report_by_handle(buffer, length); + } else { + osal_printk("%s sle client is not connected! \r\n", SLE_UART_SERVER_LOG); + } +} + +static void sle_uart_server_create_msgqueue(void) +{ + if (osal_msg_queue_create("sle_uart_server_msgqueue", SLE_UART_SERVER_MSG_QUEUE_LEN, + (unsigned long *)&g_sle_uart_server_msgqueue_id, 0, + SLE_UART_SERVER_MSG_QUEUE_MAX_SIZE) != OSAL_SUCCESS) { + osal_printk("^%s sle_uart_server_create_msgqueue message queue create failed!\n", SLE_UART_SERVER_LOG); + } +} + +static void sle_uart_server_delete_msgqueue(void) +{ + osal_msg_queue_delete(g_sle_uart_server_msgqueue_id); +} + +static void sle_uart_server_write_msgqueue(uint8_t *buffer_addr, uint16_t buffer_size) +{ + osal_msg_queue_write_copy(g_sle_uart_server_msgqueue_id, (void *)buffer_addr, (uint32_t)buffer_size, 0); +} + +static int32_t sle_uart_server_receive_msgqueue(uint8_t *buffer_addr, uint32_t *buffer_size) +{ + return osal_msg_queue_read_copy(g_sle_uart_server_msgqueue_id, (void *)buffer_addr, buffer_size, + SLE_UART_SERVER_QUEUE_DELAY); +} +static void sle_uart_server_rx_buf_init(uint8_t *buffer_addr, uint32_t *buffer_size) +{ + *buffer_size = SLE_UART_SERVER_MSG_QUEUE_MAX_SIZE; + (void)memset_s(buffer_addr, *buffer_size, 0, *buffer_size); +} + +static void *sle_uart_server_task(const char *arg) +{ + unused(arg); + uint8_t rx_buf[SLE_UART_SERVER_MSG_QUEUE_MAX_SIZE] = {0}; + uint32_t rx_length = SLE_UART_SERVER_MSG_QUEUE_MAX_SIZE; + uint8_t sle_connect_state[] = "sle_dis_connect"; + + sle_uart_server_create_msgqueue(); + sle_uart_server_register_msg(sle_uart_server_write_msgqueue); + sle_uart_server_init(ssaps_server_read_request_cbk, ssaps_server_write_request_cbk); + + /* UART pinmux. */ + uart_init_pin(); + + /* UART init config. */ + uart_init_config(); + + uapi_uart_unregister_rx_callback(CONFIG_SLE_UART_BUS); + errcode_t ret = uapi_uart_register_rx_callback(CONFIG_SLE_UART_BUS, UART_RX_CONDITION_FULL_OR_IDLE, 1, + sle_uart_server_read_int_handler); + if (ret != ERRCODE_SUCC) { + osal_printk("%s Register uart callback fail.[%x]\r\n", SLE_UART_SERVER_LOG, ret); + return NULL; + } + while (1) { + sle_uart_server_rx_buf_init(rx_buf, &rx_length); + sle_uart_server_receive_msgqueue(rx_buf, &rx_length); + if (strncmp((const char *)rx_buf, (const char *)sle_connect_state, sizeof(sle_connect_state)) == 0) { + ret = sle_start_announce(SLE_ADV_HANDLE_DEFAULT); + if (ret != ERRCODE_SLE_SUCCESS) { + osal_printk("%s sle_connect_state_changed_cbk,sle_start_announce fail :%02x\r\n", SLE_UART_SERVER_LOG, + ret); + } + } + osal_msleep(SLE_UART_TASK_DURATION_MS); + } + sle_uart_server_delete_msgqueue(); + return NULL; +} +#elif defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT) + +void sle_uart_notification_cb(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data, errcode_t status) +{ + unused(client_id); + unused(conn_id); + unused(status); + osal_printk("\n sle uart recived data : %s\r\n", data->data); + uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0); +} + +void sle_uart_indication_cb(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data, errcode_t status) +{ + unused(client_id); + unused(conn_id); + unused(status); + osal_printk("\n sle uart recived data : %s\r\n", data->data); + uapi_uart_write(CONFIG_SLE_UART_BUS, (uint8_t *)(data->data), data->data_len, 0); +} + +static void sle_uart_client_read_int_handler(const void *buffer, uint16_t length, bool error) +{ + unused(error); + ssapc_write_param_t *sle_uart_send_param = get_g_sle_uart_send_param(); + uint16_t g_sle_uart_conn_id = get_g_sle_uart_conn_id(); + sle_uart_send_param->data_len = length; + sle_uart_send_param->data = (uint8_t *)buffer; + ssapc_write_req(0, g_sle_uart_conn_id, sle_uart_send_param); +} + +static void *sle_uart_client_task(const char *arg) +{ + unused(arg); + /* UART pinmux. */ + uart_init_pin(); + + /* UART init config. */ + uart_init_config(); + + uapi_uart_unregister_rx_callback(CONFIG_SLE_UART_BUS); + errcode_t ret = uapi_uart_register_rx_callback(CONFIG_SLE_UART_BUS, UART_RX_CONDITION_FULL_OR_IDLE, 1, + sle_uart_client_read_int_handler); + sle_uart_client_init(sle_uart_notification_cb, sle_uart_indication_cb); + + if (ret != ERRCODE_SUCC) { + osal_printk("Register uart callback fail."); + return NULL; + } + + return NULL; +} +#endif /* CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT */ + +static void sle_uart_entry(void) +{ + osal_task *task_handle = NULL; + osal_kthread_lock(); +#if defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_SERVER) + task_handle = osal_kthread_create((osal_kthread_handler)sle_uart_server_task, 0, "SLEUartServerTask", + SLE_UART_TASK_STACK_SIZE); +#elif defined(CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT) + task_handle = osal_kthread_create((osal_kthread_handler)sle_uart_client_task, 0, "SLEUartDongleTask", + SLE_UART_TASK_STACK_SIZE); +#endif /* CONFIG_SAMPLE_SUPPORT_SLE_UART_CLIENT */ + if (task_handle != NULL) { + osal_kthread_set_priority(task_handle, SLE_UART_TASK_PRIO); + } + osal_kthread_unlock(); +} + +/* Run the sle_uart_entry. */ +app_run(sle_uart_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server.c new file mode 100644 index 0000000000000000000000000000000000000000..a08a6cacd9526779befbebff26f708ad0e165f1a --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server.c @@ -0,0 +1,403 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: SLE UART Server Source. \n + * + * History: \n + * 2023-07-17, Create file. \n + */ +#include "common_def.h" +#include "securec.h" +#include "soc_osal.h" +#include "sle_errcode.h" +#include "sle_connection_manager.h" +#include "sle_device_discovery.h" +#include "sle_uart_server_adv.h" +#include "sle_uart_server.h" +#define OCTET_BIT_LEN 8 +#define UUID_LEN_2 2 +#define UUID_INDEX 14 +#define BT_INDEX_4 4 +#define BT_INDEX_0 0 +#define UART_BUFF_LENGTH 0x100 +#define MTU_SIZE 520 + +/* 广播ID */ +#define SLE_ADV_HANDLE_DEFAULT 1 +/* sle server app uuid for test */ +static char g_sle_uuid_app_uuid[UUID_LEN_2] = {0x12, 0x34}; +/* server notify property uuid for test */ +static char g_sle_property_value[OCTET_BIT_LEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; +/* sle connect acb handle */ +static uint16_t g_sle_conn_hdl = 0; +/* sle server handle */ +static uint8_t g_server_id = 0; +/* sle service handle */ +static uint16_t g_service_handle = 0; +/* sle ntf property handle */ +static uint16_t g_property_handle = 0; +/* sle pair acb handle */ +uint16_t g_sle_pair_hdl; + +#define UUID_16BIT_LEN 2 +#define UUID_128BIT_LEN 16 +#define sample_at_log_print(fmt, args...) osal_printk(fmt, ##args) +#define SLE_UART_SERVER_LOG "[sle uart server]" +#define SLE_SERVER_INIT_DELAY_MS 1000 +static sle_uart_server_msg_queue g_sle_uart_server_msg_queue = NULL; +static uint8_t g_sle_uart_base[] = {0x37, 0xBE, 0xA8, 0x80, 0xFC, 0x70, 0x11, 0xEA, + 0xB7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +uint16_t get_connect_id(void) +{ + return g_sle_conn_hdl; +} + +static void encode2byte_little(uint8_t *ptr, uint16_t data) +{ + *(uint8_t *)((ptr) + 1) = (uint8_t)((data) >> 0x8); + *(uint8_t *)(ptr) = (uint8_t)(data); +} + +static void sle_uuid_set_base(sle_uuid_t *out) +{ + errcode_t ret; + ret = memcpy_s(out->uuid, SLE_UUID_LEN, g_sle_uart_base, SLE_UUID_LEN); + if (ret != EOK) { + sample_at_log_print("%s sle_uuid_set_base memcpy fail\n", SLE_UART_SERVER_LOG); + out->len = 0; + return; + } + out->len = UUID_LEN_2; +} + +static void sle_uuid_setu2(uint16_t u2, sle_uuid_t *out) +{ + sle_uuid_set_base(out); + out->len = UUID_LEN_2; + encode2byte_little(&out->uuid[UUID_INDEX], u2); +} +static void sle_uart_uuid_print(sle_uuid_t *uuid) +{ + if (uuid == NULL) { + sample_at_log_print("%s uuid_print,uuid is null\r\n", SLE_UART_SERVER_LOG); + return; + } + if (uuid->len == UUID_16BIT_LEN) { + sample_at_log_print("%s uuid: %02x %02x.\n", SLE_UART_SERVER_LOG, uuid->uuid[14], + uuid->uuid[15]); /* 14 15: uuid index */ + } else if (uuid->len == UUID_128BIT_LEN) { + sample_at_log_print("%s uuid: \n", SLE_UART_SERVER_LOG); /* 14 15: uuid index */ + sample_at_log_print("%s 0x%02x 0x%02x 0x%02x \n", SLE_UART_SERVER_LOG, uuid->uuid[0], uuid->uuid[1], + uuid->uuid[2], uuid->uuid[3]); + sample_at_log_print("%s 0x%02x 0x%02x 0x%02x \n", SLE_UART_SERVER_LOG, uuid->uuid[4], uuid->uuid[5], + uuid->uuid[6], uuid->uuid[7]); + sample_at_log_print("%s 0x%02x 0x%02x 0x%02x \n", SLE_UART_SERVER_LOG, uuid->uuid[8], uuid->uuid[9], + uuid->uuid[10], uuid->uuid[11]); + sample_at_log_print("%s 0x%02x 0x%02x 0x%02x \n", SLE_UART_SERVER_LOG, uuid->uuid[12], uuid->uuid[13], + uuid->uuid[14], uuid->uuid[15]); + } +} + +static void ssaps_mtu_changed_cbk(uint8_t server_id, uint16_t conn_id, ssap_exchange_info_t *mtu_size, errcode_t status) +{ + sample_at_log_print("%s ssaps ssaps_mtu_changed_cbk callback server_id:%x, conn_id:%x, mtu_size:%x, status:%x\r\n", + SLE_UART_SERVER_LOG, server_id, conn_id, mtu_size->mtu_size, status); + if (g_sle_pair_hdl == 0) { + g_sle_pair_hdl = conn_id + 1; + } +} + +static void ssaps_start_service_cbk(uint8_t server_id, uint16_t handle, errcode_t status) +{ + sample_at_log_print("%s start service cbk callback server_id:%d, handle:%x, status:%x\r\n", SLE_UART_SERVER_LOG, + server_id, handle, status); +} +static void ssaps_add_service_cbk(uint8_t server_id, sle_uuid_t *uuid, uint16_t handle, errcode_t status) +{ + sample_at_log_print("%s add service cbk callback server_id:%x, handle:%x, status:%x\r\n", SLE_UART_SERVER_LOG, + server_id, handle, status); + sle_uart_uuid_print(uuid); +} +static void ssaps_add_property_cbk(uint8_t server_id, + sle_uuid_t *uuid, + uint16_t service_handle, + uint16_t handle, + errcode_t status) +{ + sample_at_log_print("%s add property cbk callback server_id:%x, service_handle:%x,handle:%x, status:%x\r\n", + SLE_UART_SERVER_LOG, server_id, service_handle, handle, status); + sle_uart_uuid_print(uuid); +} +static void ssaps_add_descriptor_cbk(uint8_t server_id, + sle_uuid_t *uuid, + uint16_t service_handle, + uint16_t property_handle, + errcode_t status) +{ + sample_at_log_print( + "%s add descriptor cbk callback server_id:%x, service_handle:%x, property_handle:%x, \ + status:%x\r\n", + SLE_UART_SERVER_LOG, server_id, service_handle, property_handle, status); + sle_uart_uuid_print(uuid); +} +static void ssaps_delete_all_service_cbk(uint8_t server_id, errcode_t status) +{ + sample_at_log_print("%s delete all service callback server_id:%x, status:%x\r\n", SLE_UART_SERVER_LOG, server_id, + status); +} +static errcode_t sle_ssaps_register_cbks(ssaps_read_request_callback ssaps_read_callback, + ssaps_write_request_callback ssaps_write_callback) +{ + errcode_t ret; + ssaps_callbacks_t ssaps_cbk = {0}; + ssaps_cbk.add_service_cb = ssaps_add_service_cbk; + ssaps_cbk.add_property_cb = ssaps_add_property_cbk; + ssaps_cbk.add_descriptor_cb = ssaps_add_descriptor_cbk; + ssaps_cbk.start_service_cb = ssaps_start_service_cbk; + ssaps_cbk.delete_all_service_cb = ssaps_delete_all_service_cbk; + ssaps_cbk.mtu_changed_cb = ssaps_mtu_changed_cbk; + ssaps_cbk.read_request_cb = ssaps_read_callback; + ssaps_cbk.write_request_cb = ssaps_write_callback; + ret = ssaps_register_callbacks(&ssaps_cbk); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_ssaps_register_cbks,ssaps_register_callbacks fail :%x\r\n", SLE_UART_SERVER_LOG, + ret); + return ret; + } + return ERRCODE_SLE_SUCCESS; +} + +static errcode_t sle_uuid_server_service_add(void) +{ + errcode_t ret; + sle_uuid_t service_uuid = {0}; + sle_uuid_setu2(SLE_UUID_SERVER_SERVICE, &service_uuid); + ret = ssaps_add_service_sync(g_server_id, &service_uuid, 1, &g_service_handle); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle uuid add service fail, ret:%x\r\n", SLE_UART_SERVER_LOG, ret); + return ERRCODE_SLE_FAIL; + } + return ERRCODE_SLE_SUCCESS; +} + +static errcode_t sle_uuid_server_property_add(void) +{ + errcode_t ret; + ssaps_property_info_t property = {0}; + ssaps_desc_info_t descriptor = {0}; + uint8_t ntf_value[] = {0x01, 0x0}; + + property.permissions = SLE_UUID_TEST_PROPERTIES; + property.operate_indication = SSAP_OPERATE_INDICATION_BIT_READ | SSAP_OPERATE_INDICATION_BIT_NOTIFY; + sle_uuid_setu2(SLE_UUID_SERVER_NTF_REPORT, &property.uuid); + property.value = (uint8_t *)osal_vmalloc(sizeof(g_sle_property_value)); + if (property.value == NULL) { + return ERRCODE_SLE_FAIL; + } + if (memcpy_s(property.value, sizeof(g_sle_property_value), g_sle_property_value, sizeof(g_sle_property_value)) != + EOK) { + osal_vfree(property.value); + return ERRCODE_SLE_FAIL; + } + ret = ssaps_add_property_sync(g_server_id, g_service_handle, &property, &g_property_handle); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle uart add property fail, ret:%x\r\n", SLE_UART_SERVER_LOG, ret); + osal_vfree(property.value); + return ERRCODE_SLE_FAIL; + } + descriptor.permissions = SLE_UUID_TEST_DESCRIPTOR; + descriptor.type = SSAP_DESCRIPTOR_USER_DESCRIPTION; + descriptor.operate_indication = SSAP_OPERATE_INDICATION_BIT_READ | SSAP_OPERATE_INDICATION_BIT_WRITE; + descriptor.value = ntf_value; + descriptor.value_len = sizeof(ntf_value); + ret = ssaps_add_descriptor_sync(g_server_id, g_service_handle, g_property_handle, &descriptor); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle uart add descriptor fail, ret:%x\r\n", SLE_UART_SERVER_LOG, ret); + osal_vfree(property.value); + osal_vfree(descriptor.value); + return ERRCODE_SLE_FAIL; + } + osal_vfree(property.value); + return ERRCODE_SLE_SUCCESS; +} + +static errcode_t sle_uart_server_add(void) +{ + errcode_t ret; + sle_uuid_t app_uuid = {0}; + + sample_at_log_print("%s sle uart add service in\r\n", SLE_UART_SERVER_LOG); + app_uuid.len = sizeof(g_sle_uuid_app_uuid); + if (memcpy_s(app_uuid.uuid, app_uuid.len, g_sle_uuid_app_uuid, sizeof(g_sle_uuid_app_uuid)) != EOK) { + return ERRCODE_SLE_FAIL; + } + ssaps_register_server(&app_uuid, &g_server_id); + + if (sle_uuid_server_service_add() != ERRCODE_SLE_SUCCESS) { + ssaps_unregister_server(g_server_id); + return ERRCODE_SLE_FAIL; + } + if (sle_uuid_server_property_add() != ERRCODE_SLE_SUCCESS) { + ssaps_unregister_server(g_server_id); + return ERRCODE_SLE_FAIL; + } + sample_at_log_print("%s sle uart add service, server_id:%x, service_handle:%x, property_handle:%x\r\n", + SLE_UART_SERVER_LOG, g_server_id, g_service_handle, g_property_handle); + ret = ssaps_start_service(g_server_id, g_service_handle); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle uart add service fail, ret:%x\r\n", SLE_UART_SERVER_LOG, ret); + return ERRCODE_SLE_FAIL; + } + sample_at_log_print("%s sle uart add service out\r\n", SLE_UART_SERVER_LOG); + return ERRCODE_SLE_SUCCESS; +} + +/* device通过uuid向host发送数据:report */ +errcode_t sle_uart_server_send_report_by_uuid(const uint8_t *data, uint8_t len) +{ + errcode_t ret; + ssaps_ntf_ind_by_uuid_t param = {0}; + param.type = SSAP_PROPERTY_TYPE_VALUE; + param.start_handle = g_service_handle; + param.end_handle = g_property_handle; + param.value_len = len; + param.value = (uint8_t *)osal_vmalloc(len); + if (param.value == NULL) { + sample_at_log_print("%s send report new fail\r\n", SLE_UART_SERVER_LOG); + return ERRCODE_SLE_FAIL; + } + if (memcpy_s(param.value, param.value_len, data, len) != EOK) { + sample_at_log_print("%s send input report memcpy fail\r\n", SLE_UART_SERVER_LOG); + osal_vfree(param.value); + return ERRCODE_SLE_FAIL; + } + sle_uuid_setu2(SLE_UUID_SERVER_NTF_REPORT, ¶m.uuid); + ret = ssaps_notify_indicate_by_uuid(g_server_id, g_sle_conn_hdl, ¶m); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_server_send_report_by_uuid,ssaps_notify_indicate_by_uuid fail :%x\r\n", + SLE_UART_SERVER_LOG, ret); + osal_vfree(param.value); + return ret; + } + osal_vfree(param.value); + return ERRCODE_SLE_SUCCESS; +} + +/* device通过handle向host发送数据:report */ +errcode_t sle_uart_server_send_report_by_handle(const uint8_t *data, uint16_t len) +{ + ssaps_ntf_ind_t param = {0}; + uint8_t receive_buf[UART_BUFF_LENGTH] = {0}; /* max receive length. */ + param.handle = g_property_handle; + param.type = SSAP_PROPERTY_TYPE_VALUE; + param.value = receive_buf; + param.value_len = len; + if (memcpy_s(param.value, param.value_len, data, len) != EOK) { + return ERRCODE_SLE_FAIL; + } + return ssaps_notify_indicate(g_server_id, g_sle_conn_hdl, ¶m); +} + +static void sle_connect_state_changed_cbk(uint16_t conn_id, + const sle_addr_t *addr, + sle_acb_state_t conn_state, + sle_pair_state_t pair_state, + sle_disc_reason_t disc_reason) +{ + uint8_t sle_connect_state[] = "sle_dis_connect"; + sample_at_log_print( + "%s connect state changed callback conn_id:0x%02x, conn_state:0x%x, pair_state:0x%x, \ + disc_reason:0x%x\r\n", + SLE_UART_SERVER_LOG, conn_id, conn_state, pair_state, disc_reason); + sample_at_log_print("%s connect state changed callback addr:%02x:**:**:**:%02x:%02x\r\n", SLE_UART_SERVER_LOG, + addr->addr[BT_INDEX_0], addr->addr[BT_INDEX_4]); + if (conn_state == SLE_ACB_STATE_CONNECTED) { + g_sle_conn_hdl = conn_id; + } else if (conn_state == SLE_ACB_STATE_DISCONNECTED) { + g_sle_conn_hdl = 0; + g_sle_pair_hdl = 0; + if (g_sle_uart_server_msg_queue != NULL) { + g_sle_uart_server_msg_queue(sle_connect_state, sizeof(sle_connect_state)); + } + } +} + +static void sle_pair_complete_cbk(uint16_t conn_id, const sle_addr_t *addr, errcode_t status) +{ + sample_at_log_print("%s pair complete conn_id:%02x, status:%x\r\n", SLE_UART_SERVER_LOG, conn_id, status); + sample_at_log_print("%s pair complete addr:%02x:**:**:**:%02x:%02x\r\n", SLE_UART_SERVER_LOG, + addr->addr[BT_INDEX_0], addr->addr[BT_INDEX_4]); + g_sle_pair_hdl = conn_id + 1; + ssap_exchange_info_t parameter = {0}; + parameter.mtu_size = MTU_SIZE; + parameter.version = 1; + ssaps_set_info(g_server_id, ¶meter); +} + +static errcode_t sle_conn_register_cbks(void) +{ + errcode_t ret; + sle_connection_callbacks_t conn_cbks = {0}; + conn_cbks.connect_state_changed_cb = sle_connect_state_changed_cbk; + conn_cbks.pair_complete_cb = sle_pair_complete_cbk; + ret = sle_connection_register_callbacks(&conn_cbks); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_conn_register_cbks,sle_connection_register_callbacks fail :%x\r\n", + SLE_UART_SERVER_LOG, ret); + return ret; + } + return ERRCODE_SLE_SUCCESS; +} + +uint16_t sle_uart_client_is_connected(void) +{ + return g_sle_pair_hdl; +} + +/* 初始化uuid server */ +errcode_t sle_uart_server_init(ssaps_read_request_callback ssaps_read_callback, + ssaps_write_request_callback ssaps_write_callback) +{ + errcode_t ret; + + /* 使能SLE */ + if (enable_sle() != ERRCODE_SUCC) { + sample_at_log_print("[SLE Server] sle enbale fail !\r\n"); + return -1; + } + + ret = sle_uart_announce_register_cbks(); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_server_init,sle_uart_announce_register_cbks fail :%x\r\n", SLE_UART_SERVER_LOG, + ret); + return ret; + } + ret = sle_conn_register_cbks(); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_server_init,sle_conn_register_cbks fail :%x\r\n", SLE_UART_SERVER_LOG, ret); + return ret; + } + ret = sle_ssaps_register_cbks(ssaps_read_callback, ssaps_write_callback); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_server_init,sle_ssaps_register_cbks fail :%x\r\n", SLE_UART_SERVER_LOG, ret); + return ret; + } + ret = sle_uart_server_add(); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_server_init,sle_uart_server_add fail :%x\r\n", SLE_UART_SERVER_LOG, ret); + return ret; + } + ret = sle_uart_server_adv_init(); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_server_init,sle_uart_server_adv_init fail :%x\r\n", SLE_UART_SERVER_LOG, ret); + return ret; + } + sample_at_log_print("%s init ok\r\n", SLE_UART_SERVER_LOG); + return ERRCODE_SLE_SUCCESS; +} + +void sle_uart_server_register_msg(sle_uart_server_msg_queue sle_uart_server_msg) +{ + g_sle_uart_server_msg_queue = sle_uart_server_msg; +} \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server.h new file mode 100644 index 0000000000000000000000000000000000000000..077f7e72756c272db478dece13b78f6830303d22 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server.h @@ -0,0 +1,59 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: SLE uart server Config. \n + * + * History: \n + * 2023-07-17, Create file. \n + */ + +#ifndef SLE_UART_SERVER_H +#define SLE_UART_SERVER_H + +#include +#include "sle_ssap_server.h" +#include "errcode.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/* Service UUID */ +#define SLE_UUID_SERVER_SERVICE 0x2222 + +/* Property UUID */ +#define SLE_UUID_SERVER_NTF_REPORT 0x2323 + +/* Property Property */ +#define SLE_UUID_TEST_PROPERTIES (SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE) + +/* Operation indication */ +#define SLE_UUID_TEST_OPERATION_INDICATION (SSAP_OPERATE_INDICATION_BIT_READ | SSAP_OPERATE_INDICATION_BIT_WRITE) + +/* Descriptor Property */ +#define SLE_UUID_TEST_DESCRIPTOR (SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE) + +errcode_t sle_uart_server_init(ssaps_read_request_callback ssaps_read_callback, + ssaps_write_request_callback ssaps_write_callback); + +errcode_t sle_uart_server_send_report_by_uuid(const uint8_t *data, uint8_t len); + +errcode_t sle_uart_server_send_report_by_handle(const uint8_t *data, uint16_t len); + +uint16_t sle_uart_client_is_connected(void); + +typedef void (*sle_uart_server_msg_queue)(uint8_t *buffer_addr, uint16_t buffer_size); + +void sle_uart_server_register_msg(sle_uart_server_msg_queue sle_uart_server_msg); + +uint16_t get_connect_id(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server_adv.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server_adv.c new file mode 100644 index 0000000000000000000000000000000000000000..08e87e52e99ed70d45051961019074195dcb0956 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server_adv.c @@ -0,0 +1,247 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: sle adv config for sle uart server. \n + * + * History: \n + * 2023-07-17, Create file. \n + */ +#include "securec.h" +#include "errcode.h" +#include "osal_addr.h" +#include "product.h" +#include "sle_common.h" +#include "sle_uart_server.h" +#include "sle_device_discovery.h" +#include "sle_errcode.h" +#include "osal_debug.h" +#include "osal_task.h" +#include "string.h" +#include "sle_uart_server_adv.h" + +/* sle device name */ +#define NAME_MAX_LENGTH 16 +/* 连接调度间隔12.5ms,单位125us */ +#define SLE_CONN_INTV_MIN_DEFAULT 0x64 +/* 连接调度间隔12.5ms,单位125us */ +#define SLE_CONN_INTV_MAX_DEFAULT 0x64 +/* 连接调度间隔25ms,单位125us */ +#define SLE_ADV_INTERVAL_MIN_DEFAULT 0xC8 +/* 连接调度间隔25ms,单位125us */ +#define SLE_ADV_INTERVAL_MAX_DEFAULT 0xC8 +/* 超时时间5000ms,单位10ms */ +#define SLE_CONN_SUPERVISION_TIMEOUT_DEFAULT 0x1F4 +/* 超时时间4990ms,单位10ms */ +#define SLE_CONN_MAX_LATENCY 0x1F3 +/* 广播发送功率 */ +#define SLE_ADV_TX_POWER 18 +/* 广播ID */ +#define SLE_ADV_HANDLE_DEFAULT 1 +/* 最大广播数据长度 */ +#define SLE_ADV_DATA_LEN_MAX 251 +/* 广播名称 */ +static uint8_t g_sle_local_name[NAME_MAX_LENGTH] = "sle_uart_server"; +#define SLE_SERVER_INIT_DELAY_MS 1000 +#define sample_at_log_print(fmt, args...) osal_printk(fmt, ##args) +#define SLE_UART_SERVER_LOG "[sle uart server]" + +static uint16_t sle_set_adv_local_name(uint8_t *adv_data, uint16_t max_len) +{ + errno_t ret; + uint8_t index = 0; + + uint8_t *local_name = g_sle_local_name; + uint8_t local_name_len = sizeof(g_sle_local_name) - 1; + sample_at_log_print("%s local_name_len = %d\r\n", SLE_UART_SERVER_LOG, local_name_len); + sample_at_log_print("%s local_name: ", SLE_UART_SERVER_LOG); + for (uint8_t i = 0; i < local_name_len; i++) { + sample_at_log_print("0x%02x ", local_name[i]); + } + sample_at_log_print("\r\n"); + adv_data[index++] = local_name_len + 1; + adv_data[index++] = SLE_ADV_DATA_TYPE_COMPLETE_LOCAL_NAME; + ret = memcpy_s(&adv_data[index], max_len - index, local_name, local_name_len); + if (ret != EOK) { + sample_at_log_print("%s memcpy fail\r\n", SLE_UART_SERVER_LOG); + return 0; + } + return (uint16_t)index + local_name_len; +} + +static uint16_t sle_set_adv_data(uint8_t *adv_data) +{ + size_t len = 0; + uint16_t idx = 0; + errno_t ret = 0; + + len = sizeof(struct sle_adv_common_value); + struct sle_adv_common_value adv_disc_level = { + .length = len - 1, + .type = SLE_ADV_DATA_TYPE_DISCOVERY_LEVEL, + .value = SLE_ANNOUNCE_LEVEL_NORMAL, + }; + ret = memcpy_s(&adv_data[idx], SLE_ADV_DATA_LEN_MAX - idx, &adv_disc_level, len); + if (ret != EOK) { + sample_at_log_print("%s adv_disc_level memcpy fail\r\n", SLE_UART_SERVER_LOG); + return 0; + } + idx += len; + + len = sizeof(struct sle_adv_common_value); + struct sle_adv_common_value adv_access_mode = { + .length = len - 1, + .type = SLE_ADV_DATA_TYPE_ACCESS_MODE, + .value = 0, + }; + ret = memcpy_s(&adv_data[idx], SLE_ADV_DATA_LEN_MAX - idx, &adv_access_mode, len); + if (ret != EOK) { + sample_at_log_print("%s adv_access_mode memcpy fail\r\n", SLE_UART_SERVER_LOG); + return 0; + } + idx += len; + + return idx; +} + +static uint16_t sle_set_scan_response_data(uint8_t *scan_rsp_data) +{ + uint16_t idx = 0; + errno_t ret; + size_t scan_rsp_data_len = sizeof(struct sle_adv_common_value); + + struct sle_adv_common_value tx_power_level = { + .length = scan_rsp_data_len - 1, + .type = SLE_ADV_DATA_TYPE_TX_POWER_LEVEL, + .value = SLE_ADV_TX_POWER, + }; + ret = memcpy_s(scan_rsp_data, SLE_ADV_DATA_LEN_MAX, &tx_power_level, scan_rsp_data_len); + if (ret != EOK) { + sample_at_log_print("%s sle scan response data memcpy fail\r\n", SLE_UART_SERVER_LOG); + return 0; + } + idx += scan_rsp_data_len; + + /* set local name */ + idx += sle_set_adv_local_name(&scan_rsp_data[idx], SLE_ADV_DATA_LEN_MAX - idx); + return idx; +} + +static int sle_set_default_announce_param(void) +{ + errno_t ret; + sle_announce_param_t param = {0}; + uint8_t index; + unsigned char local_addr[SLE_ADDR_LEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + param.announce_mode = SLE_ANNOUNCE_MODE_CONNECTABLE_SCANABLE; + param.announce_handle = SLE_ADV_HANDLE_DEFAULT; + param.announce_gt_role = SLE_ANNOUNCE_ROLE_T_CAN_NEGO; + param.announce_level = SLE_ANNOUNCE_LEVEL_NORMAL; + param.announce_channel_map = SLE_ADV_CHANNEL_MAP_DEFAULT; + param.announce_interval_min = SLE_ADV_INTERVAL_MIN_DEFAULT; + param.announce_interval_max = SLE_ADV_INTERVAL_MAX_DEFAULT; + param.conn_interval_min = SLE_CONN_INTV_MIN_DEFAULT; + param.conn_interval_max = SLE_CONN_INTV_MAX_DEFAULT; + param.conn_max_latency = SLE_CONN_MAX_LATENCY; + param.conn_supervision_timeout = SLE_CONN_SUPERVISION_TIMEOUT_DEFAULT; + param.announce_tx_power = SLE_ADV_TX_POWER; + param.own_addr.type = 0; + ret = memcpy_s(param.own_addr.addr, SLE_ADDR_LEN, local_addr, SLE_ADDR_LEN); + if (ret != EOK) { + sample_at_log_print("%s sle_set_default_announce_param data memcpy fail\r\n", SLE_UART_SERVER_LOG); + return 0; + } + sample_at_log_print("%s sle_uart_local addr: ", SLE_UART_SERVER_LOG); + for (index = 0; index < SLE_ADDR_LEN; index++) { + sample_at_log_print("0x%02x ", param.own_addr.addr[index]); + } + sample_at_log_print("\r\n"); + return sle_set_announce_param(param.announce_handle, ¶m); +} + +static int sle_set_default_announce_data(void) +{ + errcode_t ret; + uint8_t announce_data_len = 0; + uint8_t seek_data_len = 0; + sle_announce_data_t data = {0}; + uint8_t adv_handle = SLE_ADV_HANDLE_DEFAULT; + uint8_t announce_data[SLE_ADV_DATA_LEN_MAX] = {0}; + uint8_t seek_rsp_data[SLE_ADV_DATA_LEN_MAX] = {0}; + uint8_t data_index = 0; + + announce_data_len = sle_set_adv_data(announce_data); + data.announce_data = announce_data; + data.announce_data_len = announce_data_len; + + sample_at_log_print("%s data.announce_data_len = %d\r\n", SLE_UART_SERVER_LOG, data.announce_data_len); + sample_at_log_print("%s data.announce_data: ", SLE_UART_SERVER_LOG); + for (data_index = 0; data_index < data.announce_data_len; data_index++) { + sample_at_log_print("0x%02x ", data.announce_data[data_index]); + } + sample_at_log_print("\r\n"); + + seek_data_len = sle_set_scan_response_data(seek_rsp_data); + data.seek_rsp_data = seek_rsp_data; + data.seek_rsp_data_len = seek_data_len; + + sample_at_log_print("%s data.seek_rsp_data_len = %d\r\n", SLE_UART_SERVER_LOG, data.seek_rsp_data_len); + sample_at_log_print("%s data.seek_rsp_data: ", SLE_UART_SERVER_LOG); + for (data_index = 0; data_index < data.seek_rsp_data_len; data_index++) { + sample_at_log_print("0x%02x ", data.seek_rsp_data[data_index]); + } + sample_at_log_print("\r\n"); + + ret = sle_set_announce_data(adv_handle, &data); + if (ret == ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s set announce data success.\r\n", SLE_UART_SERVER_LOG); + } else { + sample_at_log_print("%s set adv param fail.\r\n", SLE_UART_SERVER_LOG); + } + return ERRCODE_SLE_SUCCESS; +} + +static void sle_announce_enable_cbk(uint32_t announce_id, errcode_t status) +{ + sample_at_log_print("%s sle announce enable callback id:%02x, state:%x\r\n", SLE_UART_SERVER_LOG, announce_id, + status); +} + +static void sle_announce_disable_cbk(uint32_t announce_id, errcode_t status) +{ + sample_at_log_print("%s sle announce disable callback id:%02x, state:%x\r\n", SLE_UART_SERVER_LOG, announce_id, + status); +} + +static void sle_announce_terminal_cbk(uint32_t announce_id) +{ + sample_at_log_print("%s sle announce terminal callback id:%02x\r\n", SLE_UART_SERVER_LOG, announce_id); +} + +errcode_t sle_uart_announce_register_cbks(void) +{ + errcode_t ret = 0; + sle_announce_seek_callbacks_t seek_cbks = {0}; + seek_cbks.announce_enable_cb = sle_announce_enable_cbk; + seek_cbks.announce_disable_cb = sle_announce_disable_cbk; + seek_cbks.announce_terminal_cb = sle_announce_terminal_cbk; + ret = sle_announce_seek_register_callbacks(&seek_cbks); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_announce_register_cbks,register_callbacks fail :%x\r\n", SLE_UART_SERVER_LOG, + ret); + return ret; + } + return ERRCODE_SLE_SUCCESS; +} + +errcode_t sle_uart_server_adv_init(void) +{ + errcode_t ret; + sle_set_default_announce_param(); + sle_set_default_announce_data(); + ret = sle_start_announce(SLE_ADV_HANDLE_DEFAULT); + if (ret != ERRCODE_SLE_SUCCESS) { + sample_at_log_print("%s sle_uart_server_adv_init,sle_start_announce fail :%x\r\n", SLE_UART_SERVER_LOG, ret); + return ret; + } + return ERRCODE_SLE_SUCCESS; +} diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server_adv.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server_adv.h new file mode 100644 index 0000000000000000000000000000000000000000..f2b4bc44137115743abfc178f79e6c8ea6da9331 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_sle_uart/sle_uart_server/sle_uart_server_adv.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * + * Description: SLE ADV Config. \n + * + * History: \n + * 2023-07-17, Create file. \n + */ + +#ifndef SLE_SERVER_ADV_H +#define SLE_SERVER_ADV_H + +typedef struct sle_adv_common_value { + uint8_t type; + uint8_t length; + uint8_t value; +} le_adv_common_t; + +typedef enum sle_adv_channel { + SLE_ADV_CHANNEL_MAP_77 = 0x01, + SLE_ADV_CHANNEL_MAP_78 = 0x02, + SLE_ADV_CHANNEL_MAP_79 = 0x04, + SLE_ADV_CHANNEL_MAP_DEFAULT = 0x07 +} sle_adv_channel_map_t; + +typedef enum sle_adv_data { + SLE_ADV_DATA_TYPE_DISCOVERY_LEVEL = 0x01, /* 发现等级 */ + SLE_ADV_DATA_TYPE_ACCESS_MODE = 0x02, /* 接入层能力 */ + SLE_ADV_DATA_TYPE_SERVICE_DATA_16BIT_UUID = 0x03, /* 标准服务数据信息 */ + SLE_ADV_DATA_TYPE_SERVICE_DATA_128BIT_UUID = 0x04, /* 自定义服务数据信息 */ + SLE_ADV_DATA_TYPE_COMPLETE_LIST_OF_16BIT_SERVICE_UUIDS = 0x05, /* 完整标准服务标识列表 */ + SLE_ADV_DATA_TYPE_COMPLETE_LIST_OF_128BIT_SERVICE_UUIDS = 0x06, /* 完整自定义服务标识列表 */ + SLE_ADV_DATA_TYPE_INCOMPLETE_LIST_OF_16BIT_SERVICE_UUIDS = 0x07, /* 部分标准服务标识列表 */ + SLE_ADV_DATA_TYPE_INCOMPLETE_LIST_OF_128BIT_SERVICE_UUIDS = 0x08, /* 部分自定义服务标识列表 */ + SLE_ADV_DATA_TYPE_SERVICE_STRUCTURE_HASH_VALUE = 0x09, /* 服务结构散列值 */ + SLE_ADV_DATA_TYPE_SHORTENED_LOCAL_NAME = 0x0A, /* 设备缩写本地名称 */ + SLE_ADV_DATA_TYPE_COMPLETE_LOCAL_NAME = 0x0B, /* 设备完整本地名称 */ + SLE_ADV_DATA_TYPE_TX_POWER_LEVEL = 0x0C, /* 广播发送功率 */ + SLE_ADV_DATA_TYPE_SLB_COMMUNICATION_DOMAIN = 0x0D, /* SLB通信域域名 */ + SLE_ADV_DATA_TYPE_SLB_MEDIA_ACCESS_LAYER_ID = 0x0E, /* SLB媒体接入层标识 */ + SLE_ADV_DATA_TYPE_EXTENDED = 0xFE, /* 数据类型扩展 */ + SLE_ADV_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF /* 厂商自定义信息 */ +} sle_adv_data_type; + +errcode_t sle_dev_register_cbks(void); +errcode_t sle_uart_server_adv_init(void); + +errcode_t sle_uart_announce_register_cbks(void); + +#endif \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..61a253cb73743639c4e554149164a13a3db567c5 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/CMakeLists.txt @@ -0,0 +1 @@ +set(SOURCES "${SOURCES}" "${CMAKE_CURRENT_SOURCE_DIR}/helloworld.c" "${CMAKE_CURRENT_SOURCE_DIR}/ssd1306_fonts.c" "${CMAKE_CURRENT_SOURCE_DIR}/ssd1306.c" PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/README.md b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/README.md new file mode 100644 index 0000000000000000000000000000000000000000..53a62648279528eb620779a7544d8b6acaf49718 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/README.md @@ -0,0 +1,86 @@ +# OLED + +## 1.1 介绍 + +**功能介绍:** 在g_ssd1306 OLED屏幕循环显示不同字号的"Hello,DFRobot!"。 + +## 1.2 接口介绍 + +### 1.2.1 uapi_i2c_master_read() + + +| **定义:** | errcode_t uapi_i2c_master_read(i2c_bus_t bus, uint16_t dev_addr, i2c_data_t *data); | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **功能:** | 主机接收来自目标I2C从机的数据,有两种方式,一种是手动切换方式,另外一种是自动切换模式,两种方式静态配置,手动切换方式一共有以下三种传输模式,但是不能在同一bus中同时使用 | +| **参数:** | bus:I2C总线
dev_addr:主机接收数据的目标从机地址
data:接收数据的数据指针 | +| **返回值:** | ERRCODE_SUCC:成功 Other:失败 | +| **依赖:** | include\driver\i2c.h | + +### 1.2.2 uapi_i2c_master_write() + + +| 定义: | errcode_t uapi_i2c_master_write(i2c_bus_t bus, uint16_t dev_addr, i2c_data_t *data); | +| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **功能:** | 将数据从主机写入到从机,有两种方式,一种是手动切换方式,另外一种是自动切换模式,两种方式静态配置,手动切换方式一共有以下三种传输模式,但是不能在同一bus中同时使用 | +| **参数:** | bus:I2C总线
dev_addr:主机接收数据的目标从机地址
data:发送数据的数据指针 | +| **返回值:** | ERRCODE_SUCC:成功 Other:失败 | +| **依赖:** | include\driver\i2c.h | + +### 1.2.3 uapi_i2c_master_init() + + +| **定义:** | errcode_t uapi_i2c_master_init(i2c_bus_t bus, uint32_t baudrate, uint8_t hscode); | +| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **功能:** | 根据指定的参数初始化该i2c为主机 | +| **参数:** | bus:I2C总线
baudrate:i2c波特率
hscode:i2c高速模式主机码,每个主机有自己唯一的主机码,有效取值范围0~7,仅在高速模式下需要配置 | +| **返回值:** | ERRCODE_SUCC:成功 Other:失败 | +| **依赖:** | include\driver\i2c.h | + +### 1.2.4 uapi_pin_set_mode() + + +| **定义:** | errcode_t uapi_pin_set_mode(pin_t pin, pin_mode_t mode); | +| ------------ | -------------------------------------------------------- | +| **功能:** | 设置引脚复用模式 | +| **参数:** | pin:io
mode:复用模式 | +| **返回值:** | ERRCODE_SUCC:成功 Other:失败 | +| **依赖:** | include\driver\pinctrl.h | + +### 1.2.5 ssd1306_set_cursor() + + +| **定义:** | void ssd1306_set_cursor(uint8_t x, uint8_t y); | +| ------------ | --------------------------------------------- | +| **功能:** | 设置字符串显示位置 | +| **参数:** | x:横坐标
y:众坐标 | +| **返回值:** | 无返回值 | +| **依赖:** | beetle_ssd1306\ssd1306.h | + +### 1.2.6 ssd1306_draw_string() + + +| **定义:** | char ssd1306_draw_string(char *str, font_def_t Font, ssd1306_color_t color); | +| ------------ | ------------------------------------------------------------ | +| **功能:** | 设置输出的字符串 | +| **参数:** | str:要输出的字符串
Font:字符串大小
color:颜色 | +| **返回值:** | ERRCODE_SUCC:成功 Other:失败 | +| **依赖:** | beetle_ssd1306\ssd1306.h | + +### 1.2.7 ssd1306_update_screen() + + +| **定义:** | void ssd1306_update_screen(void); | +| ------------ | -------------------------------- | +| **功能:** | 在屏幕显示字符串 | +| **参数:** | 无 | +| **返回值:** | 无 | +| **依赖:** | beetle_ssd1306\ssd1306.h | + +## 1.3 实验流程 + +- 执行Clean命令清理资源 +- 打开KConfig,选择SSD1306示例: + +![img](.\images\ssd1306_img1.png) + +- 编译、烧录后,观察屏幕是否循环打印不同字号的"Hello,DFRobot!" diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/helloworld.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/helloworld.c new file mode 100644 index 0000000000000000000000000000000000000000..0c54bdfe02f7dfcc86d34766e896eef826da8782 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/helloworld.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "i2c.h" +#include "osal_debug.h" +#include "systick.h" +#include "ssd1306_fonts.h" +#include "ssd1306.h" +#include "app_init.h" + +#define CONFIG_I2C_SCL_MASTER_PIN 15 +#define CONFIG_I2C_SDA_MASTER_PIN 16 +#define CONFIG_I2C_MASTER_PIN_MODE 2 +#define I2C_MASTER_ADDR 0x0 +#define I2C_SLAVE1_ADDR 0x38 +#define I2C_SET_BANDRATE 400000 +#define I2C_TASK_STACK_SIZE 0x1000 +#define I2C_TASK_PRIO 17 +#define DELAY_S 1000 + +#define LARGE_FONT_HEIGHT 15 + +void app_i2c_init_pin(void) +{ + uapi_pin_set_mode(CONFIG_I2C_SCL_MASTER_PIN, CONFIG_I2C_MASTER_PIN_MODE); + uapi_pin_set_mode(CONFIG_I2C_SDA_MASTER_PIN, CONFIG_I2C_MASTER_PIN_MODE); +} + +void oled_task(void) +{ + uint32_t baudrate = I2C_SET_BANDRATE; + uint32_t hscode = I2C_MASTER_ADDR; + app_i2c_init_pin(); + errcode_t ret = uapi_i2c_master_init(1, baudrate, hscode); + if (ret != 0) { + printf("i2c init failed, ret = %0x\r\n", ret); + } + ssd1306_init(); + + // 定义不同字号的字体数组 + font_def_t fonts[] = {g_font_6x8, g_font_7x10, g_font_11x18, g_font_16x26}; + char *font_names[] = {"6x8", "7x10", "11x18", "16x26"}; + int font_count = sizeof(fonts) / sizeof(fonts[0]); + int current_font = 0; + + while (1) { + // 清屏 + ssd1306_fill(SSD1306_COLOR_BLACK); + + // 显示当前使用的字体信息 + ssd1306_set_cursor(0, 0); + ssd1306_draw_string("Font:", g_font_6x8, SSD1306_COLOR_WHITE); + ssd1306_draw_string(font_names[current_font], g_font_6x8, SSD1306_COLOR_WHITE); + + // 根据字体大小调整显示位置 + int y_pos = 20; + if (fonts[current_font].font_height > LARGE_FONT_HEIGHT) { + y_pos = LARGE_FONT_HEIGHT; // 大字体需要更靠上的位置 + } + + // 显示主要文本 + ssd1306_set_cursor(0, y_pos); + ssd1306_draw_string("Hello,DFRobot!", fonts[current_font], SSD1306_COLOR_WHITE); + + // 更新屏幕 + ssd1306_update_screen(); + + // 延时2秒 + uapi_systick_delay_ms(DELAY_S * 2); + + // 切换到下一个字体 + current_font = (current_font + 1) % font_count; + } +} + +void oled_entry(void) +{ + uint32_t ret; + osal_task *taskid; + // 创建任务调度 + osal_kthread_lock(); + // 创建任务1 + taskid = osal_kthread_create((osal_kthread_handler)oled_task, NULL, "oled_task", I2C_TASK_STACK_SIZE); + ret = osal_kthread_set_priority(taskid, I2C_TASK_PRIO); + if (ret != OSAL_SUCCESS) { + printf("create task1 failed .\n"); + } + osal_kthread_unlock(); +} + +app_run(oled_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/images/ssd1306_img1.png b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/images/ssd1306_img1.png new file mode 100644 index 0000000000000000000000000000000000000000..204a62b640f05b869d6d9bc72bdd157729624d7e Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/images/ssd1306_img1.png differ diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306.c new file mode 100644 index 0000000000000000000000000000000000000000..341977790728ed876fea2ca095c31ab30d45e03d --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306.c @@ -0,0 +1,529 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "i2c.h" +#include "soc_osal.h" +#include "ssd1306.h" + +#define CONFIG_I2C_MASTER_BUS_ID 1 +#define I2C_SLAVE2_ADDR 0x3C +#define SSD1306_CTRL_CMD 0x00 +#define SSD1306_CTRL_DATA 0x40 +#define SSD1306_MASK_CONT (0x1 << 7) +#define DOUBLE 2 + +void ssd1306_reset(void) +{ + // Wait for the screen to boot,1ms The delay here is very important + osal_mdelay(1); +} + +static uint32_t ssd1306_send_data(uint8_t *buffer, uint32_t size) +{ + uint16_t dev_addr = I2C_SLAVE2_ADDR; + i2c_data_t data = {0}; + data.send_buf = buffer; + data.send_len = size; + uint32_t retval = uapi_i2c_master_write(CONFIG_I2C_MASTER_BUS_ID, dev_addr, &data); + if (retval != 0) { + printf("I2cWrite(%02X) failed, %0X!\n", data.send_buf[1], retval); + return retval; + } + return 0; +} + +static uint32_t ssd1306_write_byte(uint8_t reg_addr, uint8_t byte) +{ + uint8_t buffer[] = {reg_addr, byte}; + return ssd1306_send_data(buffer, sizeof(buffer)); +} + +// Send a byte to the command register +void ssd1306_write_command(uint8_t byte) +{ + ssd1306_write_byte(SSD1306_CTRL_CMD, byte); +} + +// Send data +void ssd1306_write_data(uint8_t *buffer, uint32_t buff_size) +{ + uint8_t data[SSD1306_WIDTH * DOUBLE] = {0}; + for (uint32_t i = 0; i < buff_size; i++) { + data[i * DOUBLE] = SSD1306_CTRL_DATA | SSD1306_MASK_CONT; + data[i * DOUBLE + 1] = buffer[i]; + } + data[(buff_size - 1) * DOUBLE] = SSD1306_CTRL_DATA; + ssd1306_send_data(data, sizeof(data)); +} + +// Screenbuffer +static uint8_t g_ssd1306_buffer[SSD1306_BUFFER_SIZE]; + +// Screen object +static ssd1306_t g_ssd1306; + +/* Fills the Screenbuffer with values from a given buffer of a fixed length */ +ssd1306_error_t ssd1306_fill_buffer(uint8_t *buf, uint32_t len) +{ + ssd1306_error_t ret = SSD1306_ERR; + if (len <= SSD1306_BUFFER_SIZE) { + memcpy_s(g_ssd1306_buffer, len + 1, buf, len); + ret = SSD1306_OK; + } + return ret; +} + +void ssd1306_init_cmd(void) +{ + ssd1306_write_command(0xA4); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content + + ssd1306_write_command(0xD3); // -set display offset - CHECK + ssd1306_write_command(0x00); // -not offset + + ssd1306_write_command(0xD5); // --set display clock divide ratio/oscillator frequency + ssd1306_write_command(0xF0); // --set divide ratio + + ssd1306_write_command(0xD9); // --set pre-charge period + ssd1306_write_command(0x11); // 0x22 by default + + ssd1306_write_command(0xDA); // --set com pins hardware configuration - CHECK +#if (SSD1306_HEIGHT == 32) + ssd1306_write_command(0x02); +#elif (SSD1306_HEIGHT == 64) + ssd1306_write_command(0x12); +#elif (SSD1306_HEIGHT == 128) + ssd1306_write_command(0x12); +#else +#error "Only 32, 64, or 128 lines of height are supported!" +#endif + + ssd1306_write_command(0xDB); // --set vcomh + ssd1306_write_command(0x30); // 0x20,0.77xVcc, 0x30,0.83xVcc + + ssd1306_write_command(0x8D); // --set DC-DC enable + ssd1306_write_command(0x14); // + ssd1306_set_display_on(1); // --turn on g_ssd1306 panel +} + +// Initialize the oled screen +void ssd1306_init(void) +{ + // Reset OLED + ssd1306_reset(); + // Init OLED + ssd1306_set_display_on(0); // display off + + ssd1306_write_command(0x20); // Set Memory Addressing Mode + ssd1306_write_command(0x00); // 00b,Horizontal Addressing Mode; 01b,Vertical Addressing Mode; + // 10b,Page Addressing Mode (RESET); 11b,Invalid + + ssd1306_write_command(0xB0); // Set Page Start Address for Page Addressing Mode,0-7 + +#ifdef SSD1306_MIRROR_VERT + ssd1306_write_command(0xC0); // Mirror vertically +#else + ssd1306_write_command(0xC8); // Set COM Output Scan Direction +#endif + + ssd1306_write_command(0x00); // ---set low column address + ssd1306_write_command(0x10); // ---set high column address + + ssd1306_write_command(0x40); // --set start line address - CHECK + + ssd1306_set_contrast(0xFF); + +#ifdef SSD1306_MIRROR_HORIZ + ssd1306_write_command(0xA0); // Mirror horizontally +#else + ssd1306_write_command(0xA1); // --set segment re-map 0 to 127 - CHECK +#endif + +#ifdef SSD1306_INVERSE_COLOR + ssd1306_write_command(0xA7); // --set inverse color +#else + ssd1306_write_command(0xA6); // --set normal color +#endif + +// Set multiplex ratio. +#if (SSD1306_HEIGHT == 128) + // Found in the Luma Python lib for SH1106. + ssd1306_write_command(0xFF); +#else + ssd1306_write_command(0xA8); // --set multiplex ratio(1 to 64) - CHECK +#endif + +#if (SSD1306_HEIGHT == 32) + ssd1306_write_command(0x1F); // +#elif (SSD1306_HEIGHT == 64) + ssd1306_write_command(0x3F); // +#elif (SSD1306_HEIGHT == 128) + ssd1306_write_command(0x3F); // Seems to work for 128px high displays too. +#else +#error "Only 32, 64, or 128 lines of height are supported!" +#endif + ssd1306_init_cmd(); + // Clear screen + ssd1306_fill(SSD1306_COLOR_BLACK); + + // Flush buffer to screen + ssd1306_update_screen(); + + // Set default values for screen object + g_ssd1306.current_x = 0; + g_ssd1306.current_y = 0; + + g_ssd1306.initialized = 1; +} + +// Fill the whole screen with the given color +void ssd1306_fill(ssd1306_color_t color) +{ + /* Set memory */ + uint32_t i; + + for (i = 0; i < sizeof(g_ssd1306_buffer); i++) { + g_ssd1306_buffer[i] = (color == SSD1306_COLOR_BLACK) ? 0x00 : 0xFF; + } +} + +// Write the screenbuffer with changed to the screen +void ssd1306_update_screen(void) +{ + // Write data to each page of RAM. Number of pages + // depends on the screen height: + // + // * 32px == 4 pages + // * 64px == 8 pages + // * 128px == 16 pages + + uint8_t cmd[] = { + 0X21, // 设置列起始和结束地址 + 0X00, // 列起始地址 0 + 0X7F, // 列终止地址 127 + 0X22, // 设置页起始和结束地址 + 0X00, // 页起始地址 0 + 0X07, // 页终止地址 7 + }; + uint32_t count = 0; + uint8_t data[sizeof(cmd) * DOUBLE + SSD1306_BUFFER_SIZE + 1] = {}; + + // copy cmd + for (uint32_t i = 0; i < sizeof(cmd) / sizeof(cmd[0]); i++) { + data[count++] = SSD1306_CTRL_CMD | SSD1306_MASK_CONT; + data[count++] = cmd[i]; + } + + // copy frame data + data[count++] = SSD1306_CTRL_DATA; + memcpy_s(&data[count], SSD1306_BUFFER_SIZE + 1, g_ssd1306_buffer, SSD1306_BUFFER_SIZE); + count += sizeof(g_ssd1306_buffer); + + // send to i2c bus + uint32_t retval = ssd1306_send_data(data, count); + if (retval != 0) { + printf("ssd1306_update_screen send frame data filed: %d!\r\n", retval); + } +} + +// Draw one pixel in the screenbuffer +// X => X Coordinate +// Y => Y Coordinate +// color => Pixel color +void ssd1306_draw_pixel(uint8_t x, uint8_t y, ssd1306_color_t color) +{ + if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) { + // Don't write outside the buffer + return; + } + ssd1306_color_t color1 = color; + // Check if pixel should be inverted + if (g_ssd1306.inverted) { + color1 = (ssd1306_color_t)!color1; + } + + // Draw in the right color + uint32_t c = 8; // 8 + if (color == SSD1306_COLOR_WHITE) { + g_ssd1306_buffer[x + (y / c) * SSD1306_WIDTH] |= 1 << (y % c); + } else { + g_ssd1306_buffer[x + (y / c) * SSD1306_WIDTH] &= ~(1 << (y % c)); + } +} + +// Draw 1 char to the screen buffer +// ch => char om weg te schrijven +// font => font waarmee we gaan schrijven +// color => SSD1306_COLOR_BLACK or SSD1306_COLOR_WHITE +char ssd1306_draw_char(char ch, font_def_t font, ssd1306_color_t color) +{ + uint32_t i; + uint32_t b; + uint32_t j; + + // Check if character is valid + uint32_t ch_min = 32; // 32 + uint32_t ch_max = 126; // 126 + if ((uint32_t)ch < ch_min || (uint32_t)ch > ch_max) { + return 0; + } + + // Check remaining space on current line + if ((g_ssd1306.current_x + font.font_width) > SSD1306_WIDTH || + (g_ssd1306.current_y + font.font_height) > SSD1306_HEIGHT) { + // Not enough space on current line + return 0; + } + + // Use the font to write + for (i = 0; i < font.font_height; i++) { + b = font.data[(ch - ch_min) * font.font_height + i]; + for (j = 0; j < font.font_width; j++) { + if ((b << j) & 0x8000) { + ssd1306_draw_pixel(g_ssd1306.current_x + j, (g_ssd1306.current_y + i), (ssd1306_color_t)color); + } else { + ssd1306_draw_pixel(g_ssd1306.current_x + j, (g_ssd1306.current_y + i), (ssd1306_color_t)!color); + } + } + } + + // The current space is now taken + g_ssd1306.current_x += font.font_width; + + // Return written char for validation + return ch; +} + +// Write full string to screenbuffer +char ssd1306_draw_string(char *str, font_def_t font, ssd1306_color_t color) +{ + // Write until null-byte + char *str1 = str; + while (*str1) { + if (ssd1306_draw_char(*str1, font, color) != *str1) { + // Char could not be written + return *str1; + } + // Next char + str1++; + } + + // Everything ok + return *str1; +} + +// Position the cursor +void ssd1306_set_cursor(uint8_t x, uint8_t y) +{ + g_ssd1306.current_x = x; + g_ssd1306.current_y = y; +} + +// Draw line by Bresenhem's algorithm +void ssd1306_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, ssd1306_color_t color) +{ + uint8_t x = x1; + uint8_t y = y1; + int32_t delta_x = abs(x2 - x1); + int32_t delta_y = abs(y2 - y1); + int32_t sign_x = ((x1 < x2) ? 1 : -1); + int32_t sign_y = ((y1 < y2) ? 1 : -1); + int32_t error = delta_x - delta_y; + int32_t error_2; + ssd1306_draw_pixel(x2, y2, color); + while ((x1 != x2) || (y1 != y2)) { + ssd1306_draw_pixel(x1, y1, color); + error_2 = error * DOUBLE; + if (error_2 > -delta_y) { + error -= delta_y; + x += sign_x; + } else { + /* nothing to do */ + } + if (error_2 < delta_x) { + error += delta_x; + y += sign_y; + } else { + /* nothing to do */ + } + } +} + +// Draw polyline +void ssd1306_draw_polyline(const ssd1306_vertex_t *par_vertex, uint16_t par_size, ssd1306_color_t color) +{ + uint16_t i; + if (par_vertex != 0) { + for (i = 1; i < par_size; i++) { + ssd1306_draw_line(par_vertex[i - 1].x, par_vertex[i - 1].y, par_vertex[i].x, par_vertex[i].y, color); + } + } else { + /* nothing to do */ + } + return; +} + +// Draw circle by Bresenhem's algorithm +void ssd1306_draw_circle(uint8_t par_x, uint8_t par_y, uint8_t par_r, ssd1306_color_t par_color) +{ + int32_t x = -par_r; + int32_t y = 0; + int32_t b = 2; + int32_t err = b - b * par_r; + int32_t e2; + + if (par_x >= SSD1306_WIDTH || par_y >= SSD1306_HEIGHT) { + return; + } + + do { + ssd1306_draw_pixel(par_x - x, par_y + y, par_color); + ssd1306_draw_pixel(par_x + x, par_y + y, par_color); + ssd1306_draw_pixel(par_x + x, par_y - y, par_color); + ssd1306_draw_pixel(par_x - x, par_y - y, par_color); + e2 = err; + if (e2 <= y) { + y++; + err = err + (y * b + 1); + if (-x == y && e2 <= x) { + e2 = 0; + } else { + /* nothing to do */ + } + } else { + /* nothing to do */ + } + if (e2 > x) { + x++; + err = err + (x * b + 1); + } else { + /* nothing to do */ + } + } while (x <= 0); + + return; +} + +// Draw rectangle +void ssd1306_draw_rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, ssd1306_color_t color) +{ + ssd1306_draw_line(x1, y1, x2, y1, color); + ssd1306_draw_line(x2, y1, x2, y2, color); + ssd1306_draw_line(x2, y2, x1, y2, color); + ssd1306_draw_line(x1, y2, x1, y1, color); +} + +void ssd1306_draw_bitmap(const uint8_t *bitmap, uint32_t size) +{ + unsigned int c = 8; + uint8_t rows = size * c / SSD1306_WIDTH; + if (rows > SSD1306_HEIGHT) { + rows = SSD1306_HEIGHT; + } + for (uint8_t y = 0; y < rows; y++) { + for (uint8_t x = 0; x < SSD1306_WIDTH; x++) { + uint8_t byte = bitmap[(y * SSD1306_WIDTH / c) + (x / c)]; + uint8_t bit = byte & (0x80 >> (x % c)); + ssd1306_draw_pixel(x, y, bit ? SSD1306_COLOR_WHITE : SSD1306_COLOR_BLACK); + } + } +} + +void ssd1306_draw_region(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data, uint32_t size) +{ + uint32_t stride = w; + uint8_t h = w; // 字体宽高一样 + uint8_t width = w; + if (x + w > SSD1306_WIDTH || y + h > SSD1306_HEIGHT || w * h == 0) { + printf("%dx%d @ %d,%d out of range or invalid!\r\n", w, h, x, y); + return; + } + + width = (width <= SSD1306_WIDTH ? width : SSD1306_WIDTH); + h = (h <= SSD1306_HEIGHT ? h : SSD1306_HEIGHT); + stride = (stride == 0 ? w : stride); + unsigned int c = 8; + + uint8_t rows = size * c / stride; + for (uint8_t i = 0; i < rows; i++) { + uint32_t base = i * stride / c; + for (uint8_t j = 0; j < width; j++) { + uint32_t idx = base + (j / c); + uint8_t byte = idx < size ? data[idx] : 0; + uint8_t bit = byte & (0x80 >> (j % c)); + ssd1306_draw_pixel(x + j, y + i, bit ? SSD1306_COLOR_WHITE : SSD1306_COLOR_BLACK); + } + } +} + +void ssd1306_set_contrast(const uint8_t value) +{ + const uint8_t g_set_contrast_control_register = 0x81; + ssd1306_write_command(g_set_contrast_control_register); + ssd1306_write_command(value); +} + +void ssd1306_set_display_on(const uint8_t on) +{ + uint8_t value; + if (on) { + value = 0xAF; // Display on + g_ssd1306.display_on = 1; + } else { + value = 0xAE; // Display off + g_ssd1306.display_on = 0; + } + ssd1306_write_command(value); +} + +uint8_t ssd1306_get_display_on(void) +{ + return g_ssd1306.display_on; +} + +int g_ssd1306_current_loc_v = 0; +#define SSD1306_INTERVAL_V (15) + +void ssd1306_clear_oled(void) +{ + ssd1306_fill(SSD1306_COLOR_BLACK); + g_ssd1306_current_loc_v = 0; +} + +void ssd1306_printf(char *fmt, ...) +{ + char buffer[20]; + int ret = 0; + if (fmt) { + va_list arg_list; + va_start(arg_list, fmt); + ret = vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), fmt, arg_list); + if (ret < 0) { + printf("buffer is null\r\n"); + } + va_end(arg_list); + ssd1306_set_cursor(0, g_ssd1306_current_loc_v); + ssd1306_draw_string(buffer, g_font_7x10, SSD1306_COLOR_WHITE); + + ssd1306_update_screen(); + } + g_ssd1306_current_loc_v += SSD1306_INTERVAL_V; +} diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306.h new file mode 100644 index 0000000000000000000000000000000000000000..ae1ffa9408651cc7d7bc77ff7c132217e08e3307 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SSD1306_H +#define SSD1306_H + +#include +#include +#include "ssd1306_fonts.h" + +// g_ssd1306 OLED height in pixels +#ifndef SSD1306_HEIGHT +#define SSD1306_HEIGHT 64 +#endif + +// g_ssd1306 width in pixels +#ifndef SSD1306_WIDTH +#define SSD1306_WIDTH 128 +#endif + +// some LEDs don't display anything in first two columns + +#ifndef SSD1306_BUFFER_SIZE +#define SSD1306_BUFFER_SIZE (SSD1306_WIDTH * SSD1306_HEIGHT / 8) +#endif + +// Enumeration for screen colors +typedef enum { + SSD1306_COLOR_BLACK = 0x00, // SSD1306_COLOR_BLACK color, no pixel + SSD1306_COLOR_WHITE = 0x01 // Pixel is set. Color depends on OLED +} ssd1306_color_t; + +typedef enum { + SSD1306_OK = 0x00, + SSD1306_ERR = 0x01 // Generic error. +} ssd1306_error_t; + +// Struct to store transformations +typedef struct { + uint16_t current_x; + uint16_t current_y; + uint8_t inverted; + uint8_t initialized; + uint8_t display_on; +} ssd1306_t; +typedef struct { + uint8_t x; + uint8_t y; +} ssd1306_vertex_t; + +// Procedure definitions +void ssd1306_init(void); +void ssd1306_fill(ssd1306_color_t color); +void ssd1306_set_cursor(uint8_t x, uint8_t y); +void ssd1306_update_screen(void); + +char ssd1306_draw_char(char ch, font_def_t font, ssd1306_color_t color); +char ssd1306_draw_string(char *str, font_def_t font, ssd1306_color_t color); + +void ssd1306_draw_pixel(uint8_t x, uint8_t y, ssd1306_color_t color); +void ssd1306_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, ssd1306_color_t color); +void ssd1306_draw_polyline(const ssd1306_vertex_t *par_vertex, uint16_t par_size, ssd1306_color_t color); +void ssd1306_draw_rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, ssd1306_color_t color); +void ssd1306_draw_circle(uint8_t par_x, uint8_t par_y, uint8_t par_r, ssd1306_color_t par_color); +void ssd1306_draw_bitmap(const uint8_t *bitmap, uint32_t size); +void ssd1306_draw_region(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data, uint32_t size); + +/** + * @brief Sets the contrast of the display. + * @param[in] value contrast to set. + * @note Contrast increases as the value increases. + * @note RESET = 7Fh. + */ +void ssd1306_set_contrast(const uint8_t value); +/** + * @brief Set Display ON/OFF. + * @param[in] on 0 for OFF, any for ON. + */ +void ssd1306_set_display_on(const uint8_t on); +/** + * @brief Reads display_on state. + * @return 0: OFF. + * 1: ON. + */ +uint8_t ssd1306_get_display_on(void); + +// Low-level procedures +void ssd1306_reset(void); +void ssd1306_write_command(uint8_t byte); +void ssd1306_write_data(uint8_t *buffer, size_t buff_size); +ssd1306_error_t ssd1306_fill_buffer(uint8_t *buf, uint32_t len); +void ssd1306_clear_oled(void); +void ssd1306_printf(char *fmt, ...); + +#endif // __SSD1306_H__ \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306_fonts.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306_fonts.c new file mode 100644 index 0000000000000000000000000000000000000000..f1d00e5406aa1a7fcff24364bea75ece6fbec69a --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306_fonts.c @@ -0,0 +1,819 @@ +/* + MIT License + + Copyright (c) 2018-2019, Alexey Dynda + + 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. +*/ +/* + * ssd1306xled_font6x8 is by Neven Boyanov + * ssd1306xled_font8x16 is by Neven Boyanov + * + * @created: 2014-08-12 + * @author: Neven Boyanov + * + * Copyright (c) 2015 Neven Boyanov, Tinusaur Team. All Rights Reserved. + * Distributed as open source software under MIT License, see LICENSE.txt file. + * Please, as a favour, retain the link http://tinusaur.org to The Tinusaur Project. + * + * Source code available at: https://bitbucket.org/tinusaur/ssd1306xled + * + */ + +#include "ssd1306_fonts.h" + +/************************************6*8的点阵************************************/ +const unsigned char F6X8[][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // sp + {0x00, 0x00, 0x00, 0x2f, 0x00, 0x00}, // ! + {0x00, 0x00, 0x07, 0x00, 0x07, 0x00}, // " + {0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14}, // # + {0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12}, // $ + {0x00, 0x62, 0x64, 0x08, 0x13, 0x23}, // % + {0x00, 0x36, 0x49, 0x55, 0x22, 0x50}, // & + {0x00, 0x00, 0x05, 0x03, 0x00, 0x00}, // ' + {0x00, 0x00, 0x1c, 0x22, 0x41, 0x00}, // ( + {0x00, 0x00, 0x41, 0x22, 0x1c, 0x00}, // ) + {0x00, 0x14, 0x08, 0x3E, 0x08, 0x14}, // * + {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08}, // + + {0x00, 0x00, 0x00, 0xA0, 0x60, 0x00}, // , + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08}, // - + {0x00, 0x00, 0x60, 0x60, 0x00, 0x00}, // . + {0x00, 0x20, 0x10, 0x08, 0x04, 0x02}, // / + {0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0 + {0x00, 0x00, 0x42, 0x7F, 0x40, 0x00}, // 1 + {0x00, 0x42, 0x61, 0x51, 0x49, 0x46}, // 2 + {0x00, 0x21, 0x41, 0x45, 0x4B, 0x31}, // 3 + {0x00, 0x18, 0x14, 0x12, 0x7F, 0x10}, // 4 + {0x00, 0x27, 0x45, 0x45, 0x45, 0x39}, // 5 + {0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6 + {0x00, 0x01, 0x71, 0x09, 0x05, 0x03}, // 7 + {0x00, 0x36, 0x49, 0x49, 0x49, 0x36}, // 8 + {0x00, 0x06, 0x49, 0x49, 0x29, 0x1E}, // 9 + {0x00, 0x00, 0x36, 0x36, 0x00, 0x00}, // : + {0x00, 0x00, 0x56, 0x36, 0x00, 0x00}, // ;号 + {0x00, 0x08, 0x14, 0x22, 0x41, 0x00}, // < + {0x00, 0x14, 0x14, 0x14, 0x14, 0x14}, // = + {0x00, 0x00, 0x41, 0x22, 0x14, 0x08}, // > + {0x00, 0x02, 0x01, 0x51, 0x09, 0x06}, // ? + {0x00, 0x32, 0x49, 0x59, 0x51, 0x3E}, // @ + {0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C}, // A + {0x00, 0x7F, 0x49, 0x49, 0x49, 0x36}, // B + {0x00, 0x3E, 0x41, 0x41, 0x41, 0x22}, // C + {0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C}, // D + {0x00, 0x7F, 0x49, 0x49, 0x49, 0x41}, // E + {0x00, 0x7F, 0x09, 0x09, 0x09, 0x01}, // F + {0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A}, // G + {0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F}, // H + {0x00, 0x00, 0x41, 0x7F, 0x41, 0x00}, // I + {0x00, 0x20, 0x40, 0x41, 0x3F, 0x01}, // J + {0x00, 0x7F, 0x08, 0x14, 0x22, 0x41}, // K + {0x00, 0x7F, 0x40, 0x40, 0x40, 0x40}, // L + {0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M + {0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F}, // N + {0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E}, // O + {0x00, 0x7F, 0x09, 0x09, 0x09, 0x06}, // P + {0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q + {0x00, 0x7F, 0x09, 0x19, 0x29, 0x46}, // R + {0x00, 0x46, 0x49, 0x49, 0x49, 0x31}, // S + {0x00, 0x01, 0x01, 0x7F, 0x01, 0x01}, // T + {0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F}, // U + {0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F}, // V + {0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F}, // W + {0x00, 0x63, 0x14, 0x08, 0x14, 0x63}, // X + {0x00, 0x07, 0x08, 0x70, 0x08, 0x07}, // Y + {0x00, 0x61, 0x51, 0x49, 0x45, 0x43}, // Z + {0x00, 0x00, 0x7F, 0x41, 0x41, 0x00}, // [ + {0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55}, // 55 + {0x00, 0x00, 0x41, 0x41, 0x7F, 0x00}, // ] + {0x00, 0x04, 0x02, 0x01, 0x02, 0x04}, // ^ + {0x00, 0x40, 0x40, 0x40, 0x40, 0x40}, // _ + {0x00, 0x00, 0x01, 0x02, 0x04, 0x00}, // ' + {0x00, 0x20, 0x54, 0x54, 0x54, 0x78}, // a + {0x00, 0x7F, 0x48, 0x44, 0x44, 0x38}, // b + {0x00, 0x38, 0x44, 0x44, 0x44, 0x20}, // c + {0x00, 0x38, 0x44, 0x44, 0x48, 0x7F}, // d + {0x00, 0x38, 0x54, 0x54, 0x54, 0x18}, // e + {0x00, 0x08, 0x7E, 0x09, 0x01, 0x02}, // f + {0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C}, // g + {0x00, 0x7F, 0x08, 0x04, 0x04, 0x78}, // h + {0x00, 0x00, 0x44, 0x7D, 0x40, 0x00}, // i + {0x00, 0x40, 0x80, 0x84, 0x7D, 0x00}, // j + {0x00, 0x7F, 0x10, 0x28, 0x44, 0x00}, // k + {0x00, 0x00, 0x41, 0x7F, 0x40, 0x00}, // l + {0x00, 0x7C, 0x04, 0x18, 0x04, 0x78}, // m + {0x00, 0x7C, 0x08, 0x04, 0x04, 0x78}, // n + {0x00, 0x38, 0x44, 0x44, 0x44, 0x38}, // o + {0x00, 0xFC, 0x24, 0x24, 0x24, 0x18}, // p + {0x00, 0x18, 0x24, 0x24, 0x18, 0xFC}, // q + {0x00, 0x7C, 0x08, 0x04, 0x04, 0x08}, // r + {0x00, 0x48, 0x54, 0x54, 0x54, 0x20}, // s + {0x00, 0x04, 0x3F, 0x44, 0x40, 0x20}, // t + {0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C}, // u + {0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C}, // v + {0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C}, // w + {0x00, 0x44, 0x28, 0x10, 0x28, 0x44}, // x + {0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C}, // y + {0x00, 0x44, 0x64, 0x54, 0x4C, 0x44}, // z + {0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, // horiz lines +}; + +/****************************************8*16的点阵************************************/ +const unsigned char F8X16[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 + 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, // ! 1 + 0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // " 2 + 0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00, 0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, // # 3 + 0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00, 0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, // $ 4 + 0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00, 0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, // % 5 + 0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00, 0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, // & 6 + 0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ' 7 + 0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, // ( 8 + 0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, // ) 9 + 0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00, 0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, // * 10 + 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, // + 11 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, // , 12 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // - 13 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // . 14 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04, 0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, // / 15 + 0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, // 0 16 + 0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // 1 17 + 0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, // 2 18 + 0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00, 0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // 3 19 + 0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, // 4 20 + 0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00, 0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, // 5 21 + 0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // 6 22 + 0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // 7 23 + 0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, // 8 24 + 0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, // 9 25 + 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, // : 26 + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, // ;号 27 + 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, // < 28 + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, // = 29 + 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, // > 30 + 0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, // ? 31 + 0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00, 0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, // @ 32 + 0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, // A 33 + 0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // B 34 + 0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // C 35 + 0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // D 36 + 0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, // E 37 + 0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, // F 38 + 0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, // G 39 + 0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, // H 40 + 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // I 41 + 0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, // J 42 + 0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00, 0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, // K 43 + 0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, // L 44 + 0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00, 0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, // M 45 + 0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, // N 46 + 0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // O 47 + 0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, // P 48 + 0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, // Q 49 + 0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, // R 50 + 0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, // S 51 + 0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // T 52 + 0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // U 53 + 0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, // V 54 + 0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00, 0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, // W 55 + 0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08, 0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, // X 56 + 0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // Y 57 + 0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, // Z 58 + 0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, // [ 59 + 0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, // \ 60 + 0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, // ] 61 + 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ^ 62 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // _ 63 + 0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ` 64 + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, // a 65 + 0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // b 66 + 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, // c 67 + 0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, // d 68 + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, // e 69 + 0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // f 70 + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, // g 71 + 0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // h 72 + 0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // i 73 + 0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, // j 74 + 0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, // k 75 + 0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // l 76 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, // m 77 + 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // n 78 + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // o 79 + 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, // p 80 + 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, // q 81 + 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, // r 82 + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, // s 83 + 0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, // t 84 + 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, // u 85 + 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, // v 86 + 0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, 0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, // w 87 + 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, // x 88 + 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, // y 89 + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, // z 90 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, // { 91 + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, // | 92 + 0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, // } 93 + 0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ~ 94 +}; + +static const unsigned short FONT7X10[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // sp + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x0000, 0x0000, // ! + 0x2800, 0x2800, 0x2800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // " + 0x2400, 0x2400, 0x7C00, 0x2400, 0x4800, 0x7C00, 0x4800, 0x4800, 0x0000, 0x0000, // # + 0x3800, 0x5400, 0x5000, 0x3800, 0x1400, 0x5400, 0x5400, 0x3800, 0x1000, 0x0000, // $ + 0x2000, 0x5400, 0x5800, 0x3000, 0x2800, 0x5400, 0x1400, 0x0800, 0x0000, 0x0000, // % + 0x1000, 0x2800, 0x2800, 0x1000, 0x3400, 0x4800, 0x4800, 0x3400, 0x0000, 0x0000, // & + 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ' + 0x0800, 0x1000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x1000, 0x0800, // ( + 0x2000, 0x1000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x1000, 0x2000, // ) + 0x1000, 0x3800, 0x1000, 0x2800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // * + 0x0000, 0x0000, 0x1000, 0x1000, 0x7C00, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, // + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x1000, 0x1000, // , + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3800, 0x0000, 0x0000, 0x0000, 0x0000, // - + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, // . + 0x0800, 0x0800, 0x1000, 0x1000, 0x1000, 0x1000, 0x2000, 0x2000, 0x0000, 0x0000, // / + 0x3800, 0x4400, 0x4400, 0x5400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // 0 + 0x1000, 0x3000, 0x5000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // 1 + 0x3800, 0x4400, 0x4400, 0x0400, 0x0800, 0x1000, 0x2000, 0x7C00, 0x0000, 0x0000, // 2 + 0x3800, 0x4400, 0x0400, 0x1800, 0x0400, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // 3 + 0x0800, 0x1800, 0x2800, 0x2800, 0x4800, 0x7C00, 0x0800, 0x0800, 0x0000, 0x0000, // 4 + 0x7C00, 0x4000, 0x4000, 0x7800, 0x0400, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // 5 + 0x3800, 0x4400, 0x4000, 0x7800, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // 6 + 0x7C00, 0x0400, 0x0800, 0x1000, 0x1000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, // 7 + 0x3800, 0x4400, 0x4400, 0x3800, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // 8 + 0x3800, 0x4400, 0x4400, 0x4400, 0x3C00, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // 9 + 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, // : + 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, 0x0000, 0x1000, 0x1000, 0x1000, // ; + 0x0000, 0x0000, 0x0C00, 0x3000, 0x4000, 0x3000, 0x0C00, 0x0000, 0x0000, 0x0000, // < + 0x0000, 0x0000, 0x0000, 0x7C00, 0x0000, 0x7C00, 0x0000, 0x0000, 0x0000, 0x0000, // = + 0x0000, 0x0000, 0x6000, 0x1800, 0x0400, 0x1800, 0x6000, 0x0000, 0x0000, 0x0000, // > + 0x3800, 0x4400, 0x0400, 0x0800, 0x1000, 0x1000, 0x0000, 0x1000, 0x0000, 0x0000, // ? + 0x3800, 0x4400, 0x4C00, 0x5400, 0x5C00, 0x4000, 0x4000, 0x3800, 0x0000, 0x0000, // @ + 0x1000, 0x2800, 0x2800, 0x2800, 0x2800, 0x7C00, 0x4400, 0x4400, 0x0000, 0x0000, // A + 0x7800, 0x4400, 0x4400, 0x7800, 0x4400, 0x4400, 0x4400, 0x7800, 0x0000, 0x0000, // B + 0x3800, 0x4400, 0x4000, 0x4000, 0x4000, 0x4000, 0x4400, 0x3800, 0x0000, 0x0000, // C + 0x7000, 0x4800, 0x4400, 0x4400, 0x4400, 0x4400, 0x4800, 0x7000, 0x0000, 0x0000, // D + 0x7C00, 0x4000, 0x4000, 0x7C00, 0x4000, 0x4000, 0x4000, 0x7C00, 0x0000, 0x0000, // E + 0x7C00, 0x4000, 0x4000, 0x7800, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, // F + 0x3800, 0x4400, 0x4000, 0x4000, 0x5C00, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // G + 0x4400, 0x4400, 0x4400, 0x7C00, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // H + 0x3800, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x3800, 0x0000, 0x0000, // I + 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // J + 0x4400, 0x4800, 0x5000, 0x6000, 0x5000, 0x4800, 0x4800, 0x4400, 0x0000, 0x0000, // K + 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x7C00, 0x0000, 0x0000, // L + 0x4400, 0x6C00, 0x6C00, 0x5400, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // M + 0x4400, 0x6400, 0x6400, 0x5400, 0x5400, 0x4C00, 0x4C00, 0x4400, 0x0000, 0x0000, // N + 0x3800, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // O + 0x7800, 0x4400, 0x4400, 0x4400, 0x7800, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, // P + 0x3800, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x5400, 0x3800, 0x0400, 0x0000, // Q + 0x7800, 0x4400, 0x4400, 0x4400, 0x7800, 0x4800, 0x4800, 0x4400, 0x0000, 0x0000, // R + 0x3800, 0x4400, 0x4000, 0x3000, 0x0800, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // S + 0x7C00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // T + 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // U + 0x4400, 0x4400, 0x4400, 0x2800, 0x2800, 0x2800, 0x1000, 0x1000, 0x0000, 0x0000, // V + 0x4400, 0x4400, 0x5400, 0x5400, 0x5400, 0x6C00, 0x2800, 0x2800, 0x0000, 0x0000, // W + 0x4400, 0x2800, 0x2800, 0x1000, 0x1000, 0x2800, 0x2800, 0x4400, 0x0000, 0x0000, // X + 0x4400, 0x4400, 0x2800, 0x2800, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // Y + 0x7C00, 0x0400, 0x0800, 0x1000, 0x1000, 0x2000, 0x4000, 0x7C00, 0x0000, 0x0000, // Z + 0x1800, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1800, // [ + 0x2000, 0x2000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0000, 0x0000, /* \ */ + 0x3000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x3000, // ] + 0x1000, 0x2800, 0x2800, 0x4400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ^ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFE00, // _ + 0x2000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ` + 0x0000, 0x0000, 0x3800, 0x4400, 0x3C00, 0x4400, 0x4C00, 0x3400, 0x0000, 0x0000, // a + 0x4000, 0x4000, 0x5800, 0x6400, 0x4400, 0x4400, 0x6400, 0x5800, 0x0000, 0x0000, // b + 0x0000, 0x0000, 0x3800, 0x4400, 0x4000, 0x4000, 0x4400, 0x3800, 0x0000, 0x0000, // c + 0x0400, 0x0400, 0x3400, 0x4C00, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0000, 0x0000, // d + 0x0000, 0x0000, 0x3800, 0x4400, 0x7C00, 0x4000, 0x4400, 0x3800, 0x0000, 0x0000, // e + 0x0C00, 0x1000, 0x7C00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // f + 0x0000, 0x0000, 0x3400, 0x4C00, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0400, 0x7800, // g + 0x4000, 0x4000, 0x5800, 0x6400, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // h + 0x1000, 0x0000, 0x7000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // i + 0x1000, 0x0000, 0x7000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xE000, // j + 0x4000, 0x4000, 0x4800, 0x5000, 0x6000, 0x5000, 0x4800, 0x4400, 0x0000, 0x0000, // k + 0x7000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // l + 0x0000, 0x0000, 0x7800, 0x5400, 0x5400, 0x5400, 0x5400, 0x5400, 0x0000, 0x0000, // m + 0x0000, 0x0000, 0x5800, 0x6400, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // n + 0x0000, 0x0000, 0x3800, 0x4400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // o + 0x0000, 0x0000, 0x5800, 0x6400, 0x4400, 0x4400, 0x6400, 0x5800, 0x4000, 0x4000, // p + 0x0000, 0x0000, 0x3400, 0x4C00, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0400, 0x0400, // q + 0x0000, 0x0000, 0x5800, 0x6400, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, // r + 0x0000, 0x0000, 0x3800, 0x4400, 0x3000, 0x0800, 0x4400, 0x3800, 0x0000, 0x0000, // s + 0x2000, 0x2000, 0x7800, 0x2000, 0x2000, 0x2000, 0x2000, 0x1800, 0x0000, 0x0000, // t + 0x0000, 0x0000, 0x4400, 0x4400, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0000, 0x0000, // u + 0x0000, 0x0000, 0x4400, 0x4400, 0x2800, 0x2800, 0x2800, 0x1000, 0x0000, 0x0000, // v + 0x0000, 0x0000, 0x5400, 0x5400, 0x5400, 0x6C00, 0x2800, 0x2800, 0x0000, 0x0000, // w + 0x0000, 0x0000, 0x4400, 0x2800, 0x1000, 0x1000, 0x2800, 0x4400, 0x0000, 0x0000, // x + 0x0000, 0x0000, 0x4400, 0x4400, 0x2800, 0x2800, 0x1000, 0x1000, 0x1000, 0x6000, // y + 0x0000, 0x0000, 0x7C00, 0x0800, 0x1000, 0x2000, 0x4000, 0x7C00, 0x0000, 0x0000, // z + 0x1800, 0x1000, 0x1000, 0x1000, 0x2000, 0x2000, 0x1000, 0x1000, 0x1000, 0x1800, // { + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, // | + 0x3000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x1000, 0x1000, 0x1000, 0x3000, // } + 0x0000, 0x0000, 0x0000, 0x7400, 0x4C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ~ +}; + +static const unsigned short FONT11X18[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // sp + 0x0000, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // ! + 0x0000, 0x1B00, 0x1B00, 0x1B00, 0x1B00, 0x1B00, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // " + 0x0000, 0x1980, 0x1980, 0x1980, 0x1980, 0x7FC0, 0x7FC0, 0x1980, 0x3300, + 0x7FC0, 0x7FC0, 0x3300, 0x3300, 0x3300, 0x3300, 0x0000, 0x0000, 0x0000, // # + 0x0000, 0x1E00, 0x3F00, 0x7580, 0x6580, 0x7400, 0x3C00, 0x1E00, 0x0700, + 0x0580, 0x6580, 0x6580, 0x7580, 0x3F00, 0x1E00, 0x0400, 0x0400, 0x0000, // $ + 0x0000, 0x7000, 0xD800, 0xD840, 0xD8C0, 0xD980, 0x7300, 0x0600, 0x0C00, + 0x1B80, 0x36C0, 0x66C0, 0x46C0, 0x06C0, 0x0380, 0x0000, 0x0000, 0x0000, // % + 0x0000, 0x1E00, 0x3F00, 0x3300, 0x3300, 0x3300, 0x1E00, 0x0C00, 0x3CC0, + 0x66C0, 0x6380, 0x6180, 0x6380, 0x3EC0, 0x1C80, 0x0000, 0x0000, 0x0000, // & + 0x0000, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ' + 0x0080, 0x0100, 0x0300, 0x0600, 0x0600, 0x0400, 0x0C00, 0x0C00, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x0400, 0x0600, 0x0600, 0x0300, 0x0100, 0x0080, // ( + 0x2000, 0x1000, 0x1800, 0x0C00, 0x0C00, 0x0400, 0x0600, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0400, 0x0C00, 0x0C00, 0x1800, 0x1000, 0x2000, // ) + 0x0000, 0x0C00, 0x2D00, 0x3F00, 0x1E00, 0x3300, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // * + 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0xFFC0, 0xFFC0, + 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0400, 0x0400, 0x0800, // , + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1E00, 0x1E00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // - + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // . + 0x0000, 0x0300, 0x0300, 0x0300, 0x0600, 0x0600, 0x0600, 0x0600, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, // / + 0x0000, 0x1E00, 0x3F00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6D80, 0x6D80, + 0x6180, 0x6180, 0x6180, 0x3300, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 0 + 0x0000, 0x0600, 0x0E00, 0x1E00, 0x3600, 0x2600, 0x0600, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // 1 + 0x0000, 0x1E00, 0x3F00, 0x7380, 0x6180, 0x6180, 0x0180, 0x0300, 0x0600, + 0x0C00, 0x1800, 0x3000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // 2 + 0x0000, 0x1C00, 0x3E00, 0x6300, 0x6300, 0x0300, 0x0E00, 0x0E00, 0x0300, + 0x0180, 0x0180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 3 + 0x0000, 0x0600, 0x0E00, 0x0E00, 0x1E00, 0x1E00, 0x1600, 0x3600, 0x3600, + 0x6600, 0x7F80, 0x7F80, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // 4 + 0x0000, 0x7F00, 0x7F00, 0x6000, 0x6000, 0x6000, 0x6E00, 0x7F00, 0x6380, + 0x0180, 0x0180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 5 + 0x0000, 0x1E00, 0x3F00, 0x3380, 0x6180, 0x6000, 0x6E00, 0x7F00, 0x7380, + 0x6180, 0x6180, 0x6180, 0x3380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 6 + 0x0000, 0x7F80, 0x7F80, 0x0180, 0x0300, 0x0300, 0x0600, 0x0600, 0x0C00, + 0x0C00, 0x0C00, 0x0800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, // 7 + 0x0000, 0x1E00, 0x3F00, 0x6380, 0x6180, 0x6180, 0x2100, 0x1E00, 0x3F00, + 0x6180, 0x6180, 0x6180, 0x6180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 8 + 0x0000, 0x1E00, 0x3F00, 0x7300, 0x6180, 0x6180, 0x6180, 0x7380, 0x3F80, + 0x1D80, 0x0180, 0x6180, 0x7300, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 9 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // : + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0400, 0x0400, 0x0800, // ; + 0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0380, 0x0E00, 0x3800, 0x6000, + 0x3800, 0x0E00, 0x0380, 0x0080, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // < + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7F80, 0x7F80, 0x0000, 0x0000, + 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // = + 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x7000, 0x1C00, 0x0700, 0x0180, + 0x0700, 0x1C00, 0x7000, 0x4000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // > + 0x0000, 0x1F00, 0x3F80, 0x71C0, 0x60C0, 0x00C0, 0x01C0, 0x0380, 0x0700, + 0x0E00, 0x0C00, 0x0C00, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // ? + 0x0000, 0x1E00, 0x3F00, 0x3180, 0x7180, 0x6380, 0x6F80, 0x6D80, 0x6D80, + 0x6F80, 0x6780, 0x6000, 0x3200, 0x3E00, 0x1C00, 0x0000, 0x0000, 0x0000, // @ + 0x0000, 0x0E00, 0x0E00, 0x1B00, 0x1B00, 0x1B00, 0x1B00, 0x3180, 0x3180, + 0x3F80, 0x3F80, 0x3180, 0x60C0, 0x60C0, 0x60C0, 0x0000, 0x0000, 0x0000, // A + 0x0000, 0x7C00, 0x7E00, 0x6300, 0x6300, 0x6300, 0x6300, 0x7E00, 0x7E00, + 0x6300, 0x6180, 0x6180, 0x6380, 0x7F00, 0x7E00, 0x0000, 0x0000, 0x0000, // B + 0x0000, 0x1E00, 0x3F00, 0x3180, 0x6180, 0x6000, 0x6000, 0x6000, 0x6000, + 0x6000, 0x6000, 0x6180, 0x3180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // C + 0x0000, 0x7C00, 0x7F00, 0x6300, 0x6380, 0x6180, 0x6180, 0x6180, 0x6180, + 0x6180, 0x6180, 0x6300, 0x6300, 0x7E00, 0x7C00, 0x0000, 0x0000, 0x0000, // D + 0x0000, 0x7F80, 0x7F80, 0x6000, 0x6000, 0x6000, 0x6000, 0x7F00, 0x7F00, + 0x6000, 0x6000, 0x6000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // E + 0x0000, 0x7F80, 0x7F80, 0x6000, 0x6000, 0x6000, 0x6000, 0x7F00, 0x7F00, + 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, // F + 0x0000, 0x1E00, 0x3F00, 0x3180, 0x6180, 0x6000, 0x6000, 0x6000, 0x6380, + 0x6380, 0x6180, 0x6180, 0x3180, 0x3F80, 0x1E00, 0x0000, 0x0000, 0x0000, // G + 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x7F80, 0x7F80, + 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // H + 0x0000, 0x3F00, 0x3F00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x3F00, 0x3F00, 0x0000, 0x0000, 0x0000, // I + 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x6180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // J + 0x0000, 0x60C0, 0x6180, 0x6300, 0x6600, 0x6600, 0x6C00, 0x7800, 0x7C00, + 0x6600, 0x6600, 0x6300, 0x6180, 0x6180, 0x60C0, 0x0000, 0x0000, 0x0000, // K + 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, + 0x6000, 0x6000, 0x6000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // L + 0x0000, 0x71C0, 0x71C0, 0x7BC0, 0x7AC0, 0x6AC0, 0x6AC0, 0x6EC0, 0x64C0, + 0x60C0, 0x60C0, 0x60C0, 0x60C0, 0x60C0, 0x60C0, 0x0000, 0x0000, 0x0000, // M + 0x0000, 0x7180, 0x7180, 0x7980, 0x7980, 0x7980, 0x6D80, 0x6D80, 0x6D80, + 0x6580, 0x6780, 0x6780, 0x6780, 0x6380, 0x6380, 0x0000, 0x0000, 0x0000, // N + 0x0000, 0x1E00, 0x3F00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, + 0x6180, 0x6180, 0x6180, 0x3300, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // O + 0x0000, 0x7E00, 0x7F00, 0x6380, 0x6180, 0x6180, 0x6180, 0x6380, 0x7F00, + 0x7E00, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, // P + 0x0000, 0x1E00, 0x3F00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, + 0x6180, 0x6580, 0x6780, 0x3300, 0x3F80, 0x1E40, 0x0000, 0x0000, 0x0000, // Q + 0x0000, 0x7E00, 0x7F00, 0x6380, 0x6180, 0x6180, 0x6380, 0x7F00, 0x7E00, + 0x6600, 0x6300, 0x6300, 0x6180, 0x6180, 0x60C0, 0x0000, 0x0000, 0x0000, // R + 0x0000, 0x0E00, 0x1F00, 0x3180, 0x3180, 0x3000, 0x3800, 0x1E00, 0x0700, + 0x0380, 0x6180, 0x6180, 0x3180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // S + 0x0000, 0xFFC0, 0xFFC0, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // T + 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, + 0x6180, 0x6180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // U + 0x0000, 0x60C0, 0x60C0, 0x60C0, 0x3180, 0x3180, 0x3180, 0x1B00, 0x1B00, + 0x1B00, 0x1B00, 0x0E00, 0x0E00, 0x0E00, 0x0400, 0x0000, 0x0000, 0x0000, // V + 0x0000, 0xC0C0, 0xC0C0, 0xC0C0, 0xC0C0, 0xC0C0, 0xCCC0, 0x4C80, 0x4C80, + 0x5E80, 0x5280, 0x5280, 0x7380, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // W + 0x0000, 0xC0C0, 0x6080, 0x6180, 0x3300, 0x3B00, 0x1E00, 0x0C00, 0x0C00, + 0x1E00, 0x1F00, 0x3B00, 0x7180, 0x6180, 0xC0C0, 0x0000, 0x0000, 0x0000, // X + 0x0000, 0xC0C0, 0x6180, 0x6180, 0x3300, 0x3300, 0x1E00, 0x1E00, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // Y + 0x0000, 0x3F80, 0x3F80, 0x0180, 0x0300, 0x0300, 0x0600, 0x0C00, 0x0C00, + 0x1800, 0x1800, 0x3000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // Z + 0x0F00, 0x0F00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0F00, 0x0F00, // [ + 0x0000, 0x1800, 0x1800, 0x1800, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0300, 0x0300, 0x0300, 0x0000, 0x0000, 0x0000, /* \ */ + 0x1E00, 0x1E00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x1E00, 0x1E00, // ] + 0x0000, 0x0C00, 0x0C00, 0x1E00, 0x1200, 0x3300, 0x3300, 0x6180, 0x6180, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ^ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFE0, 0x0000, // _ + 0x0000, 0x3800, 0x1800, 0x0C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ` + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1F00, 0x3F80, 0x6180, 0x0180, + 0x1F80, 0x3F80, 0x6180, 0x6380, 0x7F80, 0x38C0, 0x0000, 0x0000, 0x0000, // a + 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6E00, 0x7F00, 0x7380, 0x6180, + 0x6180, 0x6180, 0x6180, 0x7380, 0x7F00, 0x6E00, 0x0000, 0x0000, 0x0000, // b + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F00, 0x7380, 0x6180, + 0x6000, 0x6000, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // c + 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x1D80, 0x3F80, 0x7380, 0x6180, + 0x6180, 0x6180, 0x6180, 0x7380, 0x3F80, 0x1D80, 0x0000, 0x0000, 0x0000, // d + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F00, 0x7300, 0x6180, + 0x7F80, 0x7F80, 0x6000, 0x7180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // e + 0x0000, 0x07C0, 0x0FC0, 0x0C00, 0x0C00, 0x7F80, 0x7F80, 0x0C00, 0x0C00, + 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // f + 0x0000, 0x0000, 0x0000, 0x0000, 0x1D80, 0x3F80, 0x7380, 0x6180, 0x6180, + 0x6180, 0x6180, 0x7380, 0x3F80, 0x1D80, 0x0180, 0x6380, 0x7F00, 0x3E00, // g + 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6F00, 0x7F80, 0x7180, 0x6180, + 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // h + 0x0000, 0x0600, 0x0600, 0x0000, 0x0000, 0x3E00, 0x3E00, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // i + 0x0600, 0x0600, 0x0000, 0x0000, 0x3E00, 0x3E00, 0x0600, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x4600, 0x7E00, 0x3C00, // j + 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6180, 0x6300, 0x6600, 0x6C00, + 0x7C00, 0x7600, 0x6300, 0x6300, 0x6180, 0x60C0, 0x0000, 0x0000, 0x0000, // k + 0x0000, 0x3E00, 0x3E00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // l + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD80, 0xFFC0, 0xCEC0, 0xCCC0, + 0xCCC0, 0xCCC0, 0xCCC0, 0xCCC0, 0xCCC0, 0xCCC0, 0x0000, 0x0000, 0x0000, // m + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6F00, 0x7F80, 0x7180, 0x6180, + 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // n + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F00, 0x7380, 0x6180, + 0x6180, 0x6180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // o + 0x0000, 0x0000, 0x0000, 0x0000, 0x6E00, 0x7F00, 0x7380, 0x6180, 0x6180, + 0x6180, 0x6180, 0x7380, 0x7F00, 0x6E00, 0x6000, 0x6000, 0x6000, 0x6000, // p + 0x0000, 0x0000, 0x0000, 0x0000, 0x1D80, 0x3F80, 0x7380, 0x6180, 0x6180, + 0x6180, 0x6180, 0x7380, 0x3F80, 0x1D80, 0x0180, 0x0180, 0x0180, 0x0180, // q + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6700, 0x3F80, 0x3900, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, // r + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F80, 0x6180, 0x6000, + 0x7F00, 0x3F80, 0x0180, 0x6180, 0x7F00, 0x1E00, 0x0000, 0x0000, 0x0000, // s + 0x0000, 0x0000, 0x0800, 0x1800, 0x1800, 0x7F00, 0x7F00, 0x1800, 0x1800, + 0x1800, 0x1800, 0x1800, 0x1800, 0x1F80, 0x0F80, 0x0000, 0x0000, 0x0000, // t + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, + 0x6180, 0x6180, 0x6180, 0x6380, 0x7F80, 0x3D80, 0x0000, 0x0000, 0x0000, // u + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x60C0, 0x3180, 0x3180, 0x3180, + 0x1B00, 0x1B00, 0x1B00, 0x0E00, 0x0E00, 0x0600, 0x0000, 0x0000, 0x0000, // v + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD80, 0xDD80, 0xDD80, 0x5500, + 0x5500, 0x5500, 0x7700, 0x7700, 0x2200, 0x2200, 0x0000, 0x0000, 0x0000, // w + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x3300, 0x3300, 0x1E00, + 0x0C00, 0x0C00, 0x1E00, 0x3300, 0x3300, 0x6180, 0x0000, 0x0000, 0x0000, // x + 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x3180, 0x3300, 0x3300, + 0x1B00, 0x1B00, 0x1B00, 0x0E00, 0x0E00, 0x0E00, 0x1C00, 0x7C00, 0x7000, // y + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FC0, 0x0180, 0x0300, + 0x0600, 0x0C00, 0x1800, 0x3000, 0x7FC0, 0x7FC0, 0x0000, 0x0000, 0x0000, // z + 0x0380, 0x0780, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0E00, 0x1C00, + 0x1C00, 0x0E00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0780, 0x0380, // { + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, // | + 0x3800, 0x3C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0E00, 0x0700, + 0x0700, 0x0E00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x3C00, 0x3800, // } + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3880, 0x7F80, + 0x4700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ~ +}; +static const unsigned short FONT16X26[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [ ] + 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03C0, 0x03C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, + 0x01C0, 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [!] + 0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = ["] + 0x01CE, 0x03CE, 0x03DE, 0x039E, 0x039C, 0x079C, 0x3FFF, 0x7FFF, 0x0738, 0x0F38, 0x0F78, 0x0F78, 0x0E78, 0xFFFF, + 0xFFFF, 0x1EF0, 0x1CF0, 0x1CE0, 0x3CE0, 0x3DE0, 0x39E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [#] + 0x03FC, 0x0FFE, 0x1FEE, 0x1EE0, 0x1EE0, 0x1EE0, 0x1EE0, 0x1FE0, 0x0FE0, 0x07E0, 0x03F0, 0x01FC, 0x01FE, 0x01FE, + 0x01FE, 0x01FE, 0x01FE, 0x01FE, 0x3DFE, 0x3FFC, 0x0FF0, 0x01E0, 0x01E0, 0x0000, 0x0000, 0x0000, // Ascii = [$] + 0x3E03, 0xF707, 0xE78F, 0xE78E, 0xE39E, 0xE3BC, 0xE7B8, 0xE7F8, 0xF7F0, 0x3FE0, 0x01C0, 0x03FF, 0x07FF, 0x07F3, + 0x0FF3, 0x1EF3, 0x3CF3, 0x38F3, 0x78F3, 0xF07F, 0xE03F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [%] + 0x07E0, 0x0FF8, 0x0F78, 0x1F78, 0x1F78, 0x1F78, 0x0F78, 0x0FF0, 0x0FE0, 0x1F80, 0x7FC3, 0xFBC3, 0xF3E7, 0xF1F7, + 0xF0F7, 0xF0FF, 0xF07F, 0xF83E, 0x7C7F, 0x3FFF, 0x1FEF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [&] + 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03C0, 0x01C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = ['] + 0x003F, 0x007C, 0x01F0, 0x01E0, 0x03C0, 0x07C0, 0x0780, 0x0780, 0x0F80, 0x0F00, 0x0F00, 0x0F00, 0x0F00, 0x0F00, + 0x0F00, 0x0F80, 0x0780, 0x0780, 0x07C0, 0x03C0, 0x01E0, 0x01F0, 0x007C, 0x003F, 0x000F, 0x0000, // Ascii = [(] + 0x7E00, 0x1F00, 0x07C0, 0x03C0, 0x01E0, 0x01F0, 0x00F0, 0x00F0, 0x00F8, 0x0078, 0x0078, 0x0078, 0x0078, 0x0078, + 0x0078, 0x00F8, 0x00F0, 0x00F0, 0x01F0, 0x01E0, 0x03C0, 0x07C0, 0x1F00, 0x7E00, 0x7800, 0x0000, // Ascii = [)] + 0x03E0, 0x03C0, 0x01C0, 0x39CE, 0x3FFF, 0x3F7F, 0x0320, 0x0370, 0x07F8, 0x0F78, 0x1F3C, 0x0638, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [*] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0xFFFF, + 0xFFFF, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [+] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x01E0, 0x01E0, 0x01E0, 0x01C0, 0x0380, // Ascii = [,] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3FFE, 0x3FFE, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [-] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [.] + 0x000F, 0x000F, 0x001E, 0x001E, 0x003C, 0x003C, 0x0078, 0x0078, 0x00F0, 0x00F0, 0x01E0, 0x01E0, 0x03C0, 0x03C0, + 0x0780, 0x0780, 0x0F00, 0x0F00, 0x1E00, 0x1E00, 0x3C00, 0x3C00, 0x7800, 0x7800, 0xF000, 0x0000, // Ascii = [/] + 0x07F0, 0x0FF8, 0x1F7C, 0x3E3E, 0x3C1E, 0x7C1F, 0x7C1F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, + 0x7C1F, 0x7C1F, 0x3C1E, 0x3E3E, 0x1F7C, 0x0FF8, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [0] + 0x00F0, 0x07F0, 0x3FF0, 0x3FF0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, + 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [1] + 0x0FE0, 0x3FF8, 0x3C7C, 0x003C, 0x003E, 0x003E, 0x003E, 0x003C, 0x003C, 0x007C, 0x00F8, 0x01F0, 0x03E0, 0x07C0, + 0x0780, 0x0F00, 0x1E00, 0x3E00, 0x3C00, 0x3FFE, 0x3FFE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [2] + 0x0FF0, 0x1FF8, 0x1C7C, 0x003E, 0x003E, 0x003E, 0x003C, 0x003C, 0x00F8, 0x0FF0, 0x0FF8, 0x007C, 0x003E, 0x001E, + 0x001E, 0x001E, 0x001E, 0x003E, 0x1C7C, 0x1FF8, 0x1FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [3] + 0x0078, 0x00F8, 0x00F8, 0x01F8, 0x03F8, 0x07F8, 0x07F8, 0x0F78, 0x1E78, 0x1E78, 0x3C78, 0x7878, 0x7878, 0xFFFF, + 0xFFFF, 0x0078, 0x0078, 0x0078, 0x0078, 0x0078, 0x0078, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [4] + 0x1FFC, 0x1FFC, 0x1FFC, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1FE0, 0x1FF8, 0x00FC, 0x007C, 0x003E, 0x003E, + 0x001E, 0x003E, 0x003E, 0x003C, 0x1C7C, 0x1FF8, 0x1FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [5] + 0x01FC, 0x07FE, 0x0F8E, 0x1F00, 0x1E00, 0x3E00, 0x3C00, 0x3C00, 0x3DF8, 0x3FFC, 0x7F3E, 0x7E1F, 0x3C0F, 0x3C0F, + 0x3C0F, 0x3C0F, 0x3E0F, 0x1E1F, 0x1F3E, 0x0FFC, 0x03F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [6] + 0x3FFF, 0x3FFF, 0x3FFF, 0x000F, 0x001E, 0x001E, 0x003C, 0x0038, 0x0078, 0x00F0, 0x00F0, 0x01E0, 0x01E0, 0x03C0, + 0x03C0, 0x0780, 0x0F80, 0x0F80, 0x0F00, 0x1F00, 0x1F00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [7] + 0x07F8, 0x0FFC, 0x1F3E, 0x1E1E, 0x3E1E, 0x3E1E, 0x1E1E, 0x1F3C, 0x0FF8, 0x07F0, 0x0FF8, 0x1EFC, 0x3E3E, 0x3C1F, + 0x7C1F, 0x7C0F, 0x7C0F, 0x3C1F, 0x3F3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [8] + 0x07F0, 0x0FF8, 0x1E7C, 0x3C3E, 0x3C1E, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x3C1F, 0x3E3F, 0x1FFF, 0x07EF, 0x001F, + 0x001E, 0x001E, 0x003E, 0x003C, 0x38F8, 0x3FF0, 0x1FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [9] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [:] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x01E0, 0x01E0, 0x01E0, 0x03C0, 0x0380, // Ascii = [;] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x000F, 0x003F, 0x00FC, 0x03F0, 0x0FC0, 0x3F00, 0xFE00, + 0x3F00, 0x0FC0, 0x03F0, 0x00FC, 0x003F, 0x000F, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [<] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [=] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE000, 0xF800, 0x7E00, 0x1F80, 0x07E0, 0x01F8, 0x007E, 0x001F, + 0x007E, 0x01F8, 0x07E0, 0x1F80, 0x7E00, 0xF800, 0xE000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [>] + 0x1FF0, 0x3FFC, 0x383E, 0x381F, 0x381F, 0x001E, 0x001E, 0x003C, 0x0078, 0x00F0, 0x01E0, 0x03C0, 0x03C0, 0x07C0, + 0x07C0, 0x0000, 0x0000, 0x0000, 0x07C0, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [?] + 0x03F8, 0x0FFE, 0x1F1E, 0x3E0F, 0x3C7F, 0x78FF, 0x79EF, 0x73C7, 0xF3C7, 0xF38F, 0xF38F, 0xF38F, 0xF39F, 0xF39F, + 0x73FF, 0x7BFF, 0x79F7, 0x3C00, 0x1F1C, 0x0FFC, 0x03F8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [@] + 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x07F0, 0x07F0, 0x07F0, 0x0F78, 0x0F78, 0x0E7C, 0x1E3C, 0x1E3C, 0x3C3E, + 0x3FFE, 0x3FFF, 0x781F, 0x780F, 0xF00F, 0xF007, 0xF007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [A] + 0x0000, 0x0000, 0x0000, 0x3FF8, 0x3FFC, 0x3C3E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C3E, 0x3C7C, 0x3FF0, 0x3FF8, 0x3C7E, + 0x3C1F, 0x3C1F, 0x3C0F, 0x3C0F, 0x3C1F, 0x3FFE, 0x3FF8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [B] + 0x0000, 0x0000, 0x0000, 0x01FF, 0x07FF, 0x1F87, 0x3E00, 0x3C00, 0x7C00, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, + 0x7C00, 0x7C00, 0x3E00, 0x3F00, 0x1F83, 0x07FF, 0x01FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [C] + 0x0000, 0x0000, 0x0000, 0x7FF0, 0x7FFC, 0x787E, 0x781F, 0x781F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, + 0x780F, 0x780F, 0x781F, 0x781E, 0x787E, 0x7FF8, 0x7FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [D] + 0x0000, 0x0000, 0x0000, 0x3FFF, 0x3FFF, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3FFE, 0x3FFE, 0x3E00, + 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [E] + 0x0000, 0x0000, 0x0000, 0x1FFF, 0x1FFF, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1FFF, 0x1FFF, 0x1E00, + 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [F] + 0x0000, 0x0000, 0x0000, 0x03FE, 0x0FFF, 0x1F87, 0x3E00, 0x7C00, 0x7C00, 0x7800, 0xF800, 0xF800, 0xF87F, 0xF87F, + 0x780F, 0x7C0F, 0x7C0F, 0x3E0F, 0x1F8F, 0x0FFF, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [G] + 0x0000, 0x0000, 0x0000, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7FFF, 0x7FFF, 0x7C1F, + 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [H] + 0x0000, 0x0000, 0x0000, 0x3FFF, 0x3FFF, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, + 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [I] + 0x0000, 0x0000, 0x0000, 0x1FFC, 0x1FFC, 0x007C, 0x007C, 0x007C, 0x007C, 0x007C, 0x007C, 0x007C, 0x007C, 0x007C, + 0x007C, 0x007C, 0x0078, 0x0078, 0x38F8, 0x3FF0, 0x3FC0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [J] + 0x0000, 0x0000, 0x0000, 0x3C1F, 0x3C1E, 0x3C3C, 0x3C78, 0x3CF0, 0x3DE0, 0x3FE0, 0x3FC0, 0x3F80, 0x3FC0, 0x3FE0, + 0x3DF0, 0x3CF0, 0x3C78, 0x3C7C, 0x3C3E, 0x3C1F, 0x3C0F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [K] + 0x0000, 0x0000, 0x0000, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, + 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [L] + 0x0000, 0x0000, 0x0000, 0xF81F, 0xFC1F, 0xFC1F, 0xFE3F, 0xFE3F, 0xFE3F, 0xFF7F, 0xFF77, 0xFF77, 0xF7F7, 0xF7E7, + 0xF3E7, 0xF3E7, 0xF3C7, 0xF007, 0xF007, 0xF007, 0xF007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [M] + 0x0000, 0x0000, 0x0000, 0x7C0F, 0x7C0F, 0x7E0F, 0x7F0F, 0x7F0F, 0x7F8F, 0x7F8F, 0x7FCF, 0x7BEF, 0x79EF, 0x79FF, + 0x78FF, 0x78FF, 0x787F, 0x783F, 0x783F, 0x781F, 0x781F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [N] + 0x0000, 0x0000, 0x0000, 0x07F0, 0x1FFC, 0x3E3E, 0x7C1F, 0x780F, 0x780F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, + 0xF80F, 0x780F, 0x780F, 0x7C1F, 0x3E3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [O] + 0x0000, 0x0000, 0x0000, 0x3FFC, 0x3FFF, 0x3E1F, 0x3E0F, 0x3E0F, 0x3E0F, 0x3E0F, 0x3E1F, 0x3E3F, 0x3FFC, 0x3FF0, + 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [P] + 0x0000, 0x0000, 0x0000, 0x07F0, 0x1FFC, 0x3E3E, 0x7C1F, 0x780F, 0x780F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, + 0xF80F, 0x780F, 0x780F, 0x7C1F, 0x3E3E, 0x1FFC, 0x07F8, 0x007C, 0x003F, 0x000F, 0x0003, 0x0000, // Ascii = [Q] + 0x0000, 0x0000, 0x0000, 0x3FF0, 0x3FFC, 0x3C7E, 0x3C3E, 0x3C1E, 0x3C1E, 0x3C3E, 0x3C3C, 0x3CFC, 0x3FF0, 0x3FE0, + 0x3DF0, 0x3CF8, 0x3C7C, 0x3C3E, 0x3C1E, 0x3C1F, 0x3C0F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [R] + 0x0000, 0x0000, 0x0000, 0x07FC, 0x1FFE, 0x3E0E, 0x3C00, 0x3C00, 0x3C00, 0x3E00, 0x1FC0, 0x0FF8, 0x03FE, 0x007F, + 0x001F, 0x000F, 0x000F, 0x201F, 0x3C3E, 0x3FFC, 0x1FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [S] + 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, + 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [T] + 0x0000, 0x0000, 0x0000, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, + 0x7C0F, 0x7C0F, 0x3C1E, 0x3C1E, 0x3E3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [U] + 0x0000, 0x0000, 0x0000, 0xF007, 0xF007, 0xF807, 0x780F, 0x7C0F, 0x3C1E, 0x3C1E, 0x3E1E, 0x1E3C, 0x1F3C, 0x1F78, + 0x0F78, 0x0FF8, 0x07F0, 0x07F0, 0x07F0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [V] + 0x0000, 0x0000, 0x0000, 0xE003, 0xF003, 0xF003, 0xF007, 0xF3E7, 0xF3E7, 0xF3E7, 0x73E7, 0x7BF7, 0x7FF7, 0x7FFF, + 0x7F7F, 0x7F7F, 0x7F7E, 0x3F7E, 0x3E3E, 0x3E3E, 0x3E3E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [W] + 0x0000, 0x0000, 0x0000, 0xF807, 0x7C0F, 0x3E1E, 0x3E3E, 0x1F3C, 0x0FF8, 0x07F0, 0x07E0, 0x03E0, 0x03E0, 0x07F0, + 0x0FF8, 0x0F7C, 0x1E7C, 0x3C3E, 0x781F, 0x780F, 0xF00F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [X] + 0x0000, 0x0000, 0x0000, 0xF807, 0x7807, 0x7C0F, 0x3C1E, 0x3E1E, 0x1F3C, 0x0F78, 0x0FF8, 0x07F0, 0x03E0, 0x03E0, + 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [Y] + 0x0000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x000F, 0x001F, 0x003E, 0x007C, 0x00F8, 0x00F0, 0x01E0, 0x03E0, 0x07C0, + 0x0F80, 0x0F00, 0x1E00, 0x3E00, 0x7C00, 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [Z] + 0x07FF, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, + 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x07FF, 0x07FF, 0x0000, // Ascii = [[] + 0x7800, 0x7800, 0x3C00, 0x3C00, 0x1E00, 0x1E00, 0x0F00, 0x0F00, 0x0780, 0x0780, 0x03C0, 0x03C0, 0x01E0, 0x01E0, + 0x00F0, 0x00F0, 0x0078, 0x0078, 0x003C, 0x003C, 0x001E, 0x001E, 0x000F, 0x000F, 0x0007, 0x0000, // Ascii = [\] + 0x7FF0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, + 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x7FF0, 0x7FF0, 0x0000, // Ascii = []] + 0x00C0, 0x01C0, 0x01C0, 0x03E0, 0x03E0, 0x07F0, 0x07F0, 0x0778, 0x0F78, 0x0F38, 0x1E3C, 0x1E3C, 0x3C1E, 0x3C1E, + 0x380F, 0x780F, 0x7807, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [^] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, // Ascii = [_] + 0x00F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [`] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0FF8, 0x3FFC, 0x3C7C, 0x003E, 0x003E, 0x003E, 0x07FE, 0x1FFE, + 0x3E3E, 0x7C3E, 0x783E, 0x7C3E, 0x7C7E, 0x3FFF, 0x1FCF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [a] + 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3DF8, 0x3FFE, 0x3F3E, 0x3E1F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, + 0x3C0F, 0x3C0F, 0x3C1F, 0x3C1E, 0x3F3E, 0x3FFC, 0x3BF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [b] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03FE, 0x0FFF, 0x1F87, 0x3E00, 0x3E00, 0x3C00, 0x7C00, 0x7C00, + 0x7C00, 0x3C00, 0x3E00, 0x3E00, 0x1F87, 0x0FFF, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [c] + 0x001F, 0x001F, 0x001F, 0x001F, 0x001F, 0x001F, 0x07FF, 0x1FFF, 0x3E3F, 0x3C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x781F, + 0x781F, 0x7C1F, 0x7C1F, 0x3C3F, 0x3E7F, 0x1FFF, 0x0FDF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [d] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03F8, 0x0FFC, 0x1F3E, 0x3E1E, 0x3C1F, 0x7C1F, 0x7FFF, 0x7FFF, + 0x7C00, 0x7C00, 0x3C00, 0x3E00, 0x1F07, 0x0FFF, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [e] + 0x01FF, 0x03E1, 0x03C0, 0x07C0, 0x07C0, 0x07C0, 0x7FFF, 0x7FFF, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [f] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07EF, 0x1FFF, 0x3E7F, 0x3C1F, 0x7C1F, 0x7C1F, 0x781F, 0x781F, + 0x781F, 0x7C1F, 0x7C1F, 0x3C3F, 0x3E7F, 0x1FFF, 0x0FDF, 0x001E, 0x001E, 0x001E, 0x387C, 0x3FF8, // Ascii = [g] + 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3DFC, 0x3FFE, 0x3F9E, 0x3F1F, 0x3E1F, 0x3C1F, 0x3C1F, 0x3C1F, + 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [h] + 0x01F0, 0x01F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FE0, 0x7FE0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, + 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [i] + 0x00F8, 0x00F8, 0x0000, 0x0000, 0x0000, 0x0000, 0x3FF8, 0x3FF8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, + 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F0, 0x71F0, 0x7FE0, // Ascii = [j] + 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C1F, 0x3C3E, 0x3C7C, 0x3CF8, 0x3DF0, 0x3DE0, 0x3FC0, 0x3FC0, + 0x3FE0, 0x3DF0, 0x3CF8, 0x3C7C, 0x3C3E, 0x3C1F, 0x3C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [k] + 0x7FF0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, + 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [l] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF79E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFBE7, 0xF9E7, 0xF1C7, 0xF1C7, + 0xF1C7, 0xF1C7, 0xF1C7, 0xF1C7, 0xF1C7, 0xF1C7, 0xF1C7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [m] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3DFC, 0x3FFE, 0x3F9E, 0x3F1F, 0x3E1F, 0x3C1F, 0x3C1F, 0x3C1F, + 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [n] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07F0, 0x1FFC, 0x3E3E, 0x3C1F, 0x7C1F, 0x780F, 0x780F, 0x780F, + 0x780F, 0x780F, 0x7C1F, 0x3C1F, 0x3E3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [o] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3DF8, 0x3FFE, 0x3F3E, 0x3E1F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, + 0x3C0F, 0x3C0F, 0x3C1F, 0x3E1E, 0x3F3E, 0x3FFC, 0x3FF8, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, // Ascii = [p] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07EE, 0x1FFE, 0x3E7E, 0x3C1E, 0x7C1E, 0x781E, 0x781E, 0x781E, + 0x781E, 0x781E, 0x7C1E, 0x7C3E, 0x3E7E, 0x1FFE, 0x0FDE, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, // Ascii = [q] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1F7F, 0x1FFF, 0x1FE7, 0x1FC7, 0x1F87, 0x1F00, 0x1F00, 0x1F00, + 0x1F00, 0x1F00, 0x1F00, 0x1F00, 0x1F00, 0x1F00, 0x1F00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [r] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07FC, 0x1FFE, 0x1E0E, 0x3E00, 0x3E00, 0x3F00, 0x1FE0, 0x07FC, + 0x00FE, 0x003E, 0x001E, 0x001E, 0x3C3E, 0x3FFC, 0x1FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [s] + 0x0000, 0x0000, 0x0000, 0x0780, 0x0780, 0x0780, 0x7FFF, 0x7FFF, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, + 0x0780, 0x0780, 0x0780, 0x0780, 0x07C0, 0x03FF, 0x01FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [t] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, + 0x3C1E, 0x3C1E, 0x3C3E, 0x3C7E, 0x3EFE, 0x1FFE, 0x0FDE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [u] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF007, 0x780F, 0x780F, 0x3C1E, 0x3C1E, 0x3E1E, 0x1E3C, 0x1E3C, + 0x0F78, 0x0F78, 0x0FF0, 0x07F0, 0x07F0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [v] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF003, 0xF1E3, 0xF3E3, 0xF3E7, 0xF3F7, 0xF3F7, 0x7FF7, 0x7F77, + 0x7F7F, 0x7F7F, 0x7F7F, 0x3E3E, 0x3E3E, 0x3E3E, 0x3E3E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [w] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7C0F, 0x3E1E, 0x3E3C, 0x1F3C, 0x0FF8, 0x07F0, 0x07F0, 0x03E0, + 0x07F0, 0x07F8, 0x0FF8, 0x1E7C, 0x3E3E, 0x3C1F, 0x781F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [x] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF807, 0x780F, 0x7C0F, 0x3C1E, 0x3C1E, 0x1E3C, 0x1E3C, 0x1F3C, + 0x0F78, 0x0FF8, 0x07F0, 0x07F0, 0x03E0, 0x03E0, 0x03C0, 0x03C0, 0x03C0, 0x0780, 0x0F80, 0x7F00, // Ascii = [y] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3FFF, 0x3FFF, 0x001F, 0x003E, 0x007C, 0x00F8, 0x01F0, 0x03E0, + 0x07C0, 0x0F80, 0x1F00, 0x1E00, 0x3C00, 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [z] + 0x01FE, 0x03E0, 0x03C0, 0x03C0, 0x03C0, 0x03C0, 0x01E0, 0x01E0, 0x01E0, 0x01C0, 0x03C0, 0x3F80, 0x3F80, 0x03C0, + 0x01C0, 0x01E0, 0x01E0, 0x01E0, 0x03C0, 0x03C0, 0x03C0, 0x03C0, 0x03E0, 0x01FE, 0x007E, 0x0000, // Ascii = [{] + 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, + 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x0000, // Ascii = [|] + 0x3FC0, 0x03E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01C0, 0x03C0, 0x03C0, 0x01C0, 0x01E0, 0x00FE, 0x00FE, 0x01E0, + 0x01C0, 0x03C0, 0x03C0, 0x01C0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x03E0, 0x3FC0, 0x3F00, 0x0000, // Ascii = [}] + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3F07, 0x7FC7, 0x73E7, + 0xF1FF, 0xF07E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [~] +}; +static const unsigned short FONT6X8[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // sp + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x2000, 0x0000, // ! + 0x5000, 0x5000, 0x5000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // " + 0x5000, 0x5000, 0xf800, 0x5000, 0xf800, 0x5000, 0x5000, 0x0000, // # + 0x2000, 0x7800, 0xa000, 0x7000, 0x2800, 0xf000, 0x2000, 0x0000, // $ + 0xc000, 0xc800, 0x1000, 0x2000, 0x4000, 0x9800, 0x1800, 0x0000, // % + 0x4000, 0xa000, 0xa000, 0x4000, 0xa800, 0x9000, 0x6800, 0x0000, // & + 0x3000, 0x3000, 0x2000, 0x4000, 0x0000, 0x0000, 0x0000, 0x0000, // ' + 0x1000, 0x2000, 0x4000, 0x4000, 0x4000, 0x2000, 0x1000, 0x0000, // ( + 0x4000, 0x2000, 0x1000, 0x1000, 0x1000, 0x2000, 0x4000, 0x0000, // ) + 0x2000, 0xa800, 0x7000, 0xf800, 0x7000, 0xa800, 0x2000, 0x0000, // * + 0x0000, 0x2000, 0x2000, 0xf800, 0x2000, 0x2000, 0x0000, 0x0000, // + + 0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x3000, 0x2000, 0x0000, // , + 0x0000, 0x0000, 0x0000, 0xf800, 0x0000, 0x0000, 0x0000, 0x0000, // - + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x3000, 0x0000, // . + 0x0000, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x0000, 0x0000, // / + 0x7000, 0x8800, 0x9800, 0xa800, 0xc800, 0x8800, 0x7000, 0x0000, // 0 + 0x2000, 0x6000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // 1 + 0x7000, 0x8800, 0x0800, 0x7000, 0x8000, 0x8000, 0xf800, 0x0000, // 2 + 0xf800, 0x0800, 0x1000, 0x3000, 0x0800, 0x8800, 0x7000, 0x0000, // 3 + 0x1000, 0x3000, 0x5000, 0x9000, 0xf800, 0x1000, 0x1000, 0x0000, // 4 + 0xf800, 0x8000, 0xf000, 0x0800, 0x0800, 0x8800, 0x7000, 0x0000, // 5 + 0x3800, 0x4000, 0x8000, 0xf000, 0x8800, 0x8800, 0x7000, 0x0000, // 6 + 0xf800, 0x0800, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x0000, // 7 + 0x7000, 0x8800, 0x8800, 0x7000, 0x8800, 0x8800, 0x7000, 0x0000, // 8 + 0x7000, 0x8800, 0x8800, 0x7800, 0x0800, 0x1000, 0xe000, 0x0000, // 9 + 0x0000, 0x0000, 0x2000, 0x0000, 0x2000, 0x0000, 0x0000, 0x0000, // : + 0x0000, 0x0000, 0x2000, 0x0000, 0x2000, 0x2000, 0x4000, 0x0000, // ; + 0x0800, 0x1000, 0x2000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0000, // < + 0x0000, 0x0000, 0xf800, 0x0000, 0xf800, 0x0000, 0x0000, 0x0000, // = + 0x4000, 0x2000, 0x1000, 0x0800, 0x1000, 0x2000, 0x4000, 0x0000, // > + 0x7000, 0x8800, 0x0800, 0x3000, 0x2000, 0x0000, 0x2000, 0x0000, // ? + 0x7000, 0x8800, 0xa800, 0xb800, 0xb000, 0x8000, 0x7800, 0x0000, // @ + 0x2000, 0x5000, 0x8800, 0x8800, 0xf800, 0x8800, 0x8800, 0x0000, // A + 0xf000, 0x8800, 0x8800, 0xf000, 0x8800, 0x8800, 0xf000, 0x0000, // B + 0x7000, 0x8800, 0x8000, 0x8000, 0x8000, 0x8800, 0x7000, 0x0000, // C + 0xf000, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0xf000, 0x0000, // D + 0xf800, 0x8000, 0x8000, 0xf000, 0x8000, 0x8000, 0xf800, 0x0000, // E + 0xf800, 0x8000, 0x8000, 0xf000, 0x8000, 0x8000, 0x8000, 0x0000, // F + 0x7800, 0x8800, 0x8000, 0x8000, 0x9800, 0x8800, 0x7800, 0x0000, // G + 0x8800, 0x8800, 0x8800, 0xf800, 0x8800, 0x8800, 0x8800, 0x0000, // H + 0x7000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // I + 0x3800, 0x1000, 0x1000, 0x1000, 0x1000, 0x9000, 0x6000, 0x0000, // J + 0x8800, 0x9000, 0xa000, 0xc000, 0xa000, 0x9000, 0x8800, 0x0000, // K + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0xf800, 0x0000, // L + 0x8800, 0xd800, 0xa800, 0xa800, 0xa800, 0x8800, 0x8800, 0x0000, // M + 0x8800, 0x8800, 0xc800, 0xa800, 0x9800, 0x8800, 0x8800, 0x0000, // N + 0x7000, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, // O + 0xf000, 0x8800, 0x8800, 0xf000, 0x8000, 0x8000, 0x8000, 0x0000, // P + 0x7000, 0x8800, 0x8800, 0x8800, 0xa800, 0x9000, 0x6800, 0x0000, // Q + 0xf000, 0x8800, 0x8800, 0xf000, 0xa000, 0x9000, 0x8800, 0x0000, // R + 0x7000, 0x8800, 0x8000, 0x7000, 0x0800, 0x8800, 0x7000, 0x0000, // S + 0xf800, 0xa800, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, // T + 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, // U + 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x5000, 0x2000, 0x0000, // V + 0x8800, 0x8800, 0x8800, 0xa800, 0xa800, 0xa800, 0x5000, 0x0000, // W + 0x8800, 0x8800, 0x5000, 0x2000, 0x5000, 0x8800, 0x8800, 0x0000, // X + 0x8800, 0x8800, 0x5000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, // Y + 0xf800, 0x0800, 0x1000, 0x7000, 0x4000, 0x8000, 0xf800, 0x0000, // Z + 0x7800, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x7800, 0x0000, // [ + 0x0000, 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0000, 0x0000, /* \ */ + 0x7800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x7800, 0x0000, // ] + 0x2000, 0x5000, 0x8800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ^ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf800, 0x0000, // _ + 0x6000, 0x6000, 0x2000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, // ` + 0x0000, 0x0000, 0x6000, 0x1000, 0x7000, 0x9000, 0x7800, 0x0000, // a + 0x8000, 0x8000, 0xb000, 0xc800, 0x8800, 0xc800, 0xb000, 0x0000, // b + 0x0000, 0x0000, 0x7000, 0x8800, 0x8000, 0x8800, 0x7000, 0x0000, // c + 0x0800, 0x0800, 0x6800, 0x9800, 0x8800, 0x9800, 0x6800, 0x0000, // d + 0x0000, 0x0000, 0x7000, 0x8800, 0xf800, 0x8000, 0x7000, 0x0000, // e + 0x1000, 0x2800, 0x2000, 0x7000, 0x2000, 0x2000, 0x2000, 0x0000, // f + 0x0000, 0x0000, 0x7000, 0x9800, 0x9800, 0x6800, 0x0800, 0x0000, // g + 0x8000, 0x8000, 0xb000, 0xc800, 0x8800, 0x8800, 0x8800, 0x0000, // h + 0x2000, 0x0000, 0x6000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // i + 0x1000, 0x0000, 0x1000, 0x1000, 0x1000, 0x9000, 0x6000, 0x0000, // j + 0x8000, 0x8000, 0x9000, 0xa000, 0xc000, 0xa000, 0x9000, 0x0000, // k + 0x6000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // l + 0x0000, 0x0000, 0xd000, 0xa800, 0xa800, 0xa800, 0xa800, 0x0000, // m + 0x0000, 0x0000, 0xb000, 0xc800, 0x8800, 0x8800, 0x8800, 0x0000, // n + 0x0000, 0x0000, 0x7000, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, // o + 0x0000, 0x0000, 0xb000, 0xc800, 0xc800, 0xb000, 0x8000, 0x0000, // p + 0x0000, 0x0000, 0x6800, 0x9800, 0x9800, 0x6800, 0x0800, 0x0000, // q + 0x0000, 0x0000, 0xb000, 0xc800, 0x8000, 0x8000, 0x8000, 0x0000, // r + 0x0000, 0x0000, 0x7800, 0x8000, 0x7000, 0x0800, 0xf000, 0x0000, // s + 0x2000, 0x2000, 0xf800, 0x2000, 0x2000, 0x2800, 0x1000, 0x0000, // t + 0x0000, 0x0000, 0x8800, 0x8800, 0x8800, 0x9800, 0x6800, 0x0000, // u + 0x0000, 0x0000, 0x8800, 0x8800, 0x8800, 0x5000, 0x2000, 0x0000, // v + 0x0000, 0x0000, 0x8800, 0x8800, 0xa800, 0xa800, 0x5000, 0x0000, // w + 0x0000, 0x0000, 0x8800, 0x5000, 0x2000, 0x5000, 0x8800, 0x0000, // x + 0x0000, 0x0000, 0x8800, 0x8800, 0x7800, 0x0800, 0x8800, 0x0000, // y + 0x0000, 0x0000, 0xf800, 0x1000, 0x2000, 0x4000, 0xf800, 0x0000, // z + 0x1000, 0x2000, 0x2000, 0x4000, 0x2000, 0x2000, 0x1000, 0x0000, // { + 0x2000, 0x2000, 0x2000, 0x0000, 0x2000, 0x2000, 0x2000, 0x0000, // | + 0x4000, 0x2000, 0x2000, 0x1000, 0x2000, 0x2000, 0x4000, 0x0000, // } + 0x4000, 0xa800, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ~ +}; + +font_def_t g_font_7x10 = {7, 10, FONT7X10}; +font_def_t g_font_6x8 = {6, 8, FONT6X8}; +font_def_t g_font_11x18 = {11, 18, FONT11X18}; +font_def_t g_font_16x26 = {16, 26, FONT16X26}; \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306_fonts.h b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306_fonts.h new file mode 100644 index 0000000000000000000000000000000000000000..0a050746a60fb411660e01927cc5c5e37a2493bd --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_ssd1306/ssd1306_fonts.h @@ -0,0 +1,58 @@ +/* + MIT License + + Copyright (c) 2018, Alexey Dynda + + 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 ssd1306_fonts.h Fonts for monochrome/rgb oled display + */ + +#ifndef SSD1306_FONTS_H +#define SSD1306_FONTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LCD_FONTS FONTS: Supported LCD fonts + * @{ + */ + +extern const unsigned char F6X8[][6]; +extern const unsigned char F8X16[]; + +typedef struct { + const unsigned char font_width; /*!< Font width in pixels */ + unsigned char font_height; /*!< Font height in pixels */ + const unsigned short *data; /*!< Pointer to data font data array */ +} font_def_t; + +extern font_def_t g_font_7x10; +extern font_def_t g_font_6x8; +extern font_def_t g_font_11x18; +extern font_def_t g_font_16x26; + +#ifdef __cplusplus +} +#endif + +#endif // SSD1306_FONTS_H \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/CMakeLists.txt b/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5af69559d37f8768733bc84b3e6b1d17b81e32ff --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/CMakeLists.txt @@ -0,0 +1,4 @@ +set(SOURCES_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/beetle_urm37_sample.c +) +set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE) diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/Kconfig b/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..d9bf277f5b8b261873bc005f514e02bb2dae85c5 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/Kconfig @@ -0,0 +1,12 @@ +#=============================================================================== +# @brief Kconfig file. +# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved. +#=============================================================================== + +config URTRIG_PIN + int "Choose URTRIG pin." + default 7 + +config URECHO_PIN + int "Choose URECHO pin." + default 8 diff --git a/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/beetle_urm37_sample.c b/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/beetle_urm37_sample.c new file mode 100644 index 0000000000000000000000000000000000000000..1ac2ea57e23332d069368496ec7da6f9ecd532c0 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/demo/beetle_urm37/beetle_urm37_sample.c @@ -0,0 +1,107 @@ +/**! + * @file beetle_urm37_sample.c + * @brief Measuring distance by driving the URM37 via GPIO. + * @copyright Copyright (c) 2025 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author [Martin](Martin@dfrobot.com) + * @version V1.0 + * @date 2025-9-29 + */ + +#include "pinctrl.h" +#include "common_def.h" +#include "soc_osal.h" +#include "gpio.h" +#include "systick.h" +#include "osal_debug.h" +#include "watchdog.h" +#include "app_init.h" + +#define DELAY_US 1100 +#define DELAY_MS 200 +#define URM37_INVALID_TIME 50000 + +#define URM37_TASK_STACK_SIZE 0x1000 +#define URM37_TASK_PRIO 24 + +void urm37_init(void) +{ + uapi_pin_set_mode(CONFIG_URTRIG_PIN, HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(CONFIG_URTRIG_PIN, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(CONFIG_URTRIG_PIN, GPIO_LEVEL_HIGH); + + uapi_pin_set_mode(CONFIG_URECHO_PIN, HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(CONFIG_URECHO_PIN, GPIO_DIRECTION_INPUT); +} + +unsigned int get_distance(void) +{ + unsigned int flag = 0; + static uint64_t start_time = 0; + static uint64_t time = 0; + unsigned int distance_measured = 0; + gpio_level_t value = 0; + + uapi_gpio_set_val(CONFIG_URTRIG_PIN, GPIO_LEVEL_LOW); + uapi_systick_delay_us(DELAY_US); + uapi_gpio_set_val(CONFIG_URTRIG_PIN, GPIO_LEVEL_HIGH); + + while (1) { + uapi_watchdog_kick(); + + value = uapi_gpio_get_output_val(CONFIG_URECHO_PIN); + if (value == GPIO_LEVEL_LOW && flag == 0) { + /* + * 获取系统时间 + * get SysTime + */ + start_time = uapi_systick_get_us(); + flag = 1; + } + + if (value == GPIO_LEVEL_HIGH && flag == 1) { + /* + * 获取高电平持续时间 + * Get high level duration + */ + time = uapi_systick_get_us() - start_time; + break; + } + } + + if (time >= URM37_INVALID_TIME) { + printf("Invalid"); + } else { + distance_measured = time / 50; // every 50us low level stands for 1cm + printf("distance = %ucm\n", distance_measured); + } + + return distance_measured; +} + +void urm37_task(void) +{ + urm37_init(); + printf("urm37_task init\r\n"); + + while (1) { + get_distance(); + osal_mdelay(DELAY_MS); + } +} + +void urm37_entry(void) +{ + uint32_t ret; + osal_task *taskid; + // 创建任务调度 + osal_kthread_lock(); + // 创建任务1 + taskid = osal_kthread_create((osal_kthread_handler)urm37_task, NULL, "urm37_task", URM37_TASK_STACK_SIZE); + ret = osal_kthread_set_priority(taskid, URM37_TASK_PRIO); + if (ret != OSAL_SUCCESS) { + printf("create task1 failed .\n"); + } + osal_kthread_unlock(); +} +app_run(urm37_entry); \ No newline at end of file diff --git a/vendor/DFRobot_Beetle_WS63/doc/hardware/[DFR1232]Beetle WS63(V0.0.1).pdf b/vendor/DFRobot_Beetle_WS63/doc/hardware/[DFR1232]Beetle WS63(V0.0.1).pdf new file mode 100644 index 0000000000000000000000000000000000000000..9ad9eff8d8230668bd416a44180119c63432b092 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/hardware/[DFR1232]Beetle WS63(V0.0.1).pdf differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/add_cmake.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/add_cmake.png new file mode 100644 index 0000000000000000000000000000000000000000..9359a1675f5734c149362dca4e34589e87b3832a Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/add_cmake.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/add_kconfig.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/add_kconfig.png new file mode 100644 index 0000000000000000000000000000000000000000..f9addb586a06be9edf1dd4f6d3d8bed8eb92572c Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/add_kconfig.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/beetle_demo_success.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/beetle_demo_success.png new file mode 100644 index 0000000000000000000000000000000000000000..77415cc1e875fc133cd8e43b1664d1df47612686 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/beetle_demo_success.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/build_program.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/build_program.png new file mode 100644 index 0000000000000000000000000000000000000000..2e7e25b6c41063aa379cdf88122611b70e873477 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/build_program.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/burn_firmware.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/burn_firmware.png new file mode 100644 index 0000000000000000000000000000000000000000..d21853e8ce8a35f08d32096deb2dd9cc62508b92 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/burn_firmware.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/burn_progress.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/burn_progress.png new file mode 100644 index 0000000000000000000000000000000000000000..7a26c77ea5205e007732c76bbcefbf8e9e9ac180 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/burn_progress.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/copy_beetle_demo.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/copy_beetle_demo.png new file mode 100644 index 0000000000000000000000000000000000000000..3aab0dfa0d322557ef181f386a1bfde2ac6aeb80 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/copy_beetle_demo.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/download_toolchain.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/download_toolchain.png new file mode 100644 index 0000000000000000000000000000000000000000..9cdfb114514ff7a42c7c57e30af742bd9983a6fc Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/download_toolchain.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/hispark_graphical_interface.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/hispark_graphical_interface.png new file mode 100644 index 0000000000000000000000000000000000000000..9529ad5409f345c60432269df69df1d1f61243a0 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/hispark_graphical_interface.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/hispark_interface.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/hispark_interface.png new file mode 100644 index 0000000000000000000000000000000000000000..0a4794da2b94aefae5e6e7f1689a214d10187206 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/hispark_interface.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/io_mux_table_path.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/io_mux_table_path.png new file mode 100644 index 0000000000000000000000000000000000000000..2f17f8f38c7dbbb371b71299bb341bf6c7ccca17 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/io_mux_table_path.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/kconfig_interface.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/kconfig_interface.png new file mode 100644 index 0000000000000000000000000000000000000000..340424c97f93f70fd3060c222e5b978bd099dd7f Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/kconfig_interface.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/modify_project_config.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/modify_project_config.png new file mode 100644 index 0000000000000000000000000000000000000000..be8e32e683a3a354630f765410e8546609637e9f Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/modify_project_config.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/new_project_dialog.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/new_project_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..9aa4c2e5cf97f03852f24cfc432eeb2586368c12 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/new_project_dialog.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/project_list.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/project_list.png new file mode 100644 index 0000000000000000000000000000000000000000..3721c4dc119ea8f5f3911f937bbecb142c900692 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/project_list.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/select_hello_world.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/select_hello_world.png new file mode 100644 index 0000000000000000000000000000000000000000..1f8bebae7aa089bb4c9aeb46dd0dddd03633e1ab Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/select_hello_world.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/serial_debug.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/serial_debug.png new file mode 100644 index 0000000000000000000000000000000000000000..7a7b86ffc11e54ca384baca43ec120646bceec99 Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/serial_debug.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/vscode_plugin_install.png b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/vscode_plugin_install.png new file mode 100644 index 0000000000000000000000000000000000000000..80bc5912352c2f515ba905fcfff868a2edb3741e Binary files /dev/null and b/vendor/DFRobot_Beetle_WS63/doc/media/main_menu/vscode_plugin_install.png differ diff --git a/vendor/DFRobot_Beetle_WS63/doc/readme.md b/vendor/DFRobot_Beetle_WS63/doc/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..77fc786a972f829df9cb430f8ee07d275da47b04 --- /dev/null +++ b/vendor/DFRobot_Beetle_WS63/doc/readme.md @@ -0,0 +1,111 @@ +# DFRobot_Beetle_WS63 demo部署教程 + +## 一、安装工具和SDK: + +安装vscode HiSpark Studio插件 + +![安装vscode HiSpark Studio插件](media/main_menu/vscode_plugin_install.png) + +在快速入门界面点击下载工具链 + +![下载工具链](media/main_menu/download_toolchain.png) + +工具链安装完成后,在gitee上拉取WS63的SDK: + +```Plain +git clone https://gitee.com/HiSpark/fbb_ws63.git +``` + +用vscode打开下载好的sdk,点击左侧边栏hispark图标,看到如下界面: + +![hispark界面](media/main_menu/hispark_interface.png) + +其中COMMANDS部分为用户开发时常用命令,其中:**Kconfig**为选择编译示例和示例参数配置、**clean**为清理项目编译资源、**Build**构建项目、**Burn**烧录固件。 + +## 二、新建一个工程并编译SDK中的例程: + +在上图中我们点击Home按钮进入hispark图形化管理界面: + +![hispark图形化管理界面](media/main_menu/hispark_graphical_interface.png) + +在新建工程对话框中我们选择**芯片**为WS63,**工程类型**为普通工程,起一个**工程名**(图中为Beetle_project),**工程路径和软件包**需要选择fbb_ws63目录下的src目录: + +![新建工程对话框](media/main_menu/new_project_dialog.png) + +点击完成后,再次点击Home按钮就会发现工程列表中我们刚刚创建的工程了。(注意以后每第一次打开vscode都要来到Home这里打开工程才算进入项目) + +![工程列表](media/main_menu/project_list.png) + +点击左侧command栏中的Kconfig按钮,弹出界面: + +![Kconfig界面](media/main_menu/kconfig_interface.png) + +像下图依次展开,选择hello world示例然后点击save保存,关闭对话框: + +![选择hello world示例](media/main_menu/select_hello_world.png) + +点击Build编译构建程序,等待构建完成: + +![构建程序](media/main_menu/build_program.png) + +在项目浏览框里找到工程配置文件Beetle_project.hiproj,修改port为我们开发板连接的端口(图例为com15),然后ctrl+s保存修改: + +![修改工程配置](media/main_menu/modify_project_config.png) + +点击Burn烧录固件,会提示点击复位: + +![烧录固件](media/main_menu/burn_firmware.png) + +点击开发板上的复位按钮,进入烧录阶段,下方会提示烧录进度: + +![烧录进度](media/main_menu/burn_progress.png) + +烧录完成后,打开串口调试助手,观察打印: + +![串口调试助手](media/main_menu/serial_debug.png) + +## 三、添加我们的beetle_demo示例到SDK中: + +将demo文件夹复制到sdk的samples目录下,并修改文件名为**beetle_demo**: + +![复制beetle_demo文件](media/main_menu/copy_beetle_demo.png) + +在同级目录下Kconfig中添加: + +```Plain +config ENABLE_BEETLE_DEMO + bool + prompt "Enable the beetle_demo." + default n + depends on SAMPLE_ENABLE + help + This option means enable the beetle_demo. + +if ENABLE_BEETLE_DEMO +osource "application/samples/beetle_demo/Kconfig" +endif +``` + +![添加Kconfig配置](media/main_menu/add_kconfig.png) + +同级CmakeLists中添加: + +```Plain +if(DEFINED CONFIG_ENABLE_BEETLE_DEMO) + add_subdirectory_if_exist(beetle_demo) +endif() +``` + +![添加CMakeLists配置](media/main_menu/add_cmake.png) + +保存文件后,点击Kconfig命令,界面如下则beetle_demo添加成功: + +![beetle_demo添加成功](media/main_menu/beetle_demo_success.png) + +## 四、注意事项: + +- WS63的1、3、6、9gpio引脚连接传感器模块时会拉高boot,所以若传感器使用了这些引脚,在烧录固件时先拔线,再复位烧录,进入烧录进度后再插线。 +- WS63外设功能都是用GPIO复用的,当发现复用的功能不生效时请查表,IO复用关系表路径: + +![IO复用关系表路径](media/main_menu/io_mux_table_path.png) +