The dynamic change of the priorities

本文介绍了如何通过ROS服务调用来获取和设置特定话题的优先级。对于本地节点和远程节点的话题优先级调整提供了详细的命令示例,并解释了相关命令参数的意义。
Regarding the dynamic change of the priorities:

To get the priority of the topic '/add_two_ints' for example you have to call:

rosservice call /R0/wmp_control [0,0,0] 6 0 0 /add_two_ints

The '6' is the command get_priority recently added (refer to  http://www.ros.org/wiki/ros-rt-wmp#Controlling_the_ros_rt_wmp)

To set the priority you have to call:

rosservice call /R0/wmp_control [0,0,0] 5 12 0 /add_two_ints

where command '5' is set_priority and '12' is the new priority of the topic.
This is only for the local node. If you need to change remote node topic's priority you have to call:

rosservice call /R0/ remote/wmp_control [0,1,0] 6 0 0 /add_two_ints

where

[0,1,0] is respectively [source_node, destination_node, priority_of_the_call] and the other fields are the same as before.

Notice that is not possible to call local service with a remote call. In other words you can't call the service at /R0/remote/wmp_control from node R0. You have to call /R0/wmp_control instead.

Of course you can call these services from within an independent program or other node (I mean also not from command line).

P.D. I guess you remember but these changes are only on the 'testing' branch


/*! \file main.c \brief Implementation of ble datatrans server demo. \version 2023-07-20, V1.0.0, firmware for GD32VW55x */ /* Copyright (c) 2023, GigaDevice Semiconductor Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdint.h> #include "dbg_print.h" #include "gd32vw55x_platform.h" #include "wrapper_os.h" #include "ble_adapter.h" #include "ble_adv.h" #include "ble_conn.h" #include "ble_utils.h" #include "ble_export.h" #include "ble_sec.h" #include "ble_datatrans_srv.h" #include "app_uart.h" /* Device name */ #define DEV_NAME "GD-BLE-DEV" /* Device name length*/ #define DEV_NAME_LEN strlen(dev_name) /* Advertising parameters */ typedef struct { uint8_t adv_idx; /*!< Advertising id. use to stop advertising */ ble_adv_state_t adv_state; /*!< Advertising state */ } app_adv_param_t; /* Definitions of the different task priorities */ enum { BLE_STACK_TASK_PRIORITY = OS_TASK_PRIORITY(2), /*!< Priority of the BLE stack task */ BLE_APP_TASK_PRIORITY = OS_TASK_PRIORITY(1), /*!< Priority of the BLE APP task */ }; /* Definitions of the different BLE task stack size requirements */ enum { BLE_STACK_TASK_STACK_SIZE = 768, /*!< BLE stack task stack size */ BLE_APP_TASK_STACK_SIZE = 512, /*!< BLE APP task stack size */ }; /* Device name array*/ char dev_name[] = {DEV_NAME}; /* advertising env*/ app_adv_param_t app_adv_env = {0}; /* connection index */ uint8_t conn_idx = 0; /*! \brief Start advertising \param[in] p_adv: pointer to BLE advertising set \param[out] none \retval none */ static ble_status_t app_adv_start(void) { ble_data_t adv_data = {0}; ble_data_t adv_scanrsp_data = {0}; ble_adv_data_set_t adv = {0}; ble_adv_data_set_t scan_rsp = {0}; uint8_t data[BLE_GAP_LEGACY_ADV_MAX_LEN] = {0}; uint8_t idx = 0; data[idx++] = 2; data[idx++] = BLE_AD_TYPE_FLAGS; data[idx++] = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED | BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE; data[idx++] = DEV_NAME_LEN + 1; data[idx++] = 0x09; memcpy(&data[idx], dev_name, DEV_NAME_LEN); idx += DEV_NAME_LEN; adv_data.len = idx; adv_data.p_data = data; adv_scanrsp_data.len = idx - 3; adv_scanrsp_data.p_data = &data[3]; adv.data_force = true; adv.data.p_data_force = &adv_data; scan_rsp.data_force = true; scan_rsp.data.p_data_force = &adv_scanrsp_data; return ble_adv_start(app_adv_env.adv_idx, &adv, &scan_rsp, NULL); } /*! \brief Callback function to handle BLE advertising events \param[in] adv_evt: BLE advertising event type \param[in] p_data: pointer to BLE advertising event data \param[in] p_context: context data used when create advertising \param[out] none \retval none */ static void app_adv_mgr_evt_hdlr(ble_adv_evt_t adv_evt, void *p_data, void *p_context) { if (adv_evt == BLE_ADV_EVT_STATE_CHG) { ble_adv_state_chg_t *p_chg = (ble_adv_state_chg_t *)p_data; ble_adv_state_t old_state = app_adv_env.adv_state; app_print("%s state change 0x%x ==> 0x%x, reason 0x%x\r\n", __func__, old_state, p_chg->state, p_chg->reason); app_adv_env.adv_state = p_chg->state; if ((p_chg->state == BLE_ADV_STATE_CREATE) && (old_state == BLE_ADV_STATE_CREATING)) { app_adv_env.adv_idx = p_chg->adv_idx; app_adv_start(); } } } /*! \brief Create an advertising \param[in] p_param: pointer to advertising parameters \param[out] none \retval ble_status_t: BLE_ERR_NO_ERROR on success, otherwise an error code */ static ble_status_t app_adv_create(void) { ble_adv_param_t adv_param = {0}; adv_param.param.disc_mode = BLE_GAP_ADV_MODE_GEN_DISC; adv_param.param.own_addr_type = BLE_GAP_LOCAL_ADDR_STATIC; adv_param.param.type = BLE_GAP_ADV_TYPE_LEGACY; adv_param.param.prop = BLE_GAP_ADV_PROP_UNDIR_CONN; adv_param.param.filter_pol = BLE_GAP_ADV_ALLOW_SCAN_ANY_CON_ANY; adv_param.param.ch_map = 0x07; adv_param.param.primary_phy = BLE_GAP_PHY_1MBPS; adv_param.param.adv_intv_min = 160; adv_param.param.adv_intv_max = 160; adv_param.restart_after_disconn = true; return ble_adv_create(&adv_param, app_adv_mgr_evt_hdlr, NULL); } /*! \brief Function to execute app code after stack ready \param[in] none \param[out] none \retval none */ void ble_task_ready(void) { app_adv_create(); } /*! \brief Callback function to handle BLE adapter events \param[in] event: BLE adapter event type \param[in] p_data: pointer to BLE adapter event data \param[out] none \retval none */ static void app_adp_evt_handler(ble_adp_evt_t event, ble_adp_data_u *p_data) { uint8_t i = 0; if (event == BLE_ADP_EVT_ENABLE_CMPL_INFO) { if (p_data->adapter_info.status == BLE_ERR_NO_ERROR) { app_print("=== Adapter enable success ===\r\n"); app_print("hci_ver 0x%x, hci_subver 0x%x, lmp_ver 0x%x, lmp_subver 0x%x, manuf_name 0x%x\r\n", p_data->adapter_info.version.hci_ver, p_data->adapter_info.version.hci_subver, p_data->adapter_info.version.lmp_ver, p_data->adapter_info.version.lmp_subver, p_data->adapter_info.version.manuf_name); app_print("adv_set_num %u, min_tx_pwr %d, max_tx_pwr %d, max_adv_data_len %d \r\n", p_data->adapter_info.adv_set_num, p_data->adapter_info.tx_pwr_range.min_tx_pwr, p_data->adapter_info.tx_pwr_range.max_tx_pwr, p_data->adapter_info.max_adv_data_len); app_print("sugg_max_tx_octets %u, sugg_max_tx_time %u \r\n", p_data->adapter_info.sugg_dft_data.sugg_max_tx_octets, p_data->adapter_info.sugg_dft_data.sugg_max_tx_time); app_print("loc irk:"); for (i = 0; i < BLE_GAP_KEY_LEN; i++) { app_print(" %02x", p_data->adapter_info.loc_irk_info.irk[i]); } app_print("\r\n"); app_print("identity addr %02X:%02X:%02X:%02X:%02X:%02X \r\n ", p_data->adapter_info.loc_irk_info.identity.addr[5], p_data->adapter_info.loc_irk_info.identity.addr[4], p_data->adapter_info.loc_irk_info.identity.addr[3], p_data->adapter_info.loc_irk_info.identity.addr[2], p_data->adapter_info.loc_irk_info.identity.addr[1], p_data->adapter_info.loc_irk_info.identity.addr[0]); app_print("=== BLE Adapter enable complete ===\r\n"); ble_task_ready(); } else { app_print("=== BLE Adapter enable fail ===\r\n"); } } } /*! \brief Init adapter application module \param[in] none \param[out] none \retval none */ void app_adapter_init(void) { ble_adp_callback_register(app_adp_evt_handler); } /*! \brief Send security request \param[in] conidx: connection index \param[out] none \retval none */ void app_sec_send_security_req(uint8_t conidx) { uint8_t auth = BLE_GAP_AUTH_REQ_NO_MITM_NO_BOND; if (ble_sec_security_req(conidx, auth) != BLE_ERR_NO_ERROR) { app_print("app_sec_send_security_req fail! \r\n"); } } /*! \brief Callback function to handle BLE connection event \param[in] event: BLE connection event type \param[in] p_data: pointer to BLE connection event data \param[out] none \retval none */ static void app_conn_evt_handler(ble_conn_evt_t event, ble_conn_data_u *p_data) { switch (event) { case BLE_CONN_EVT_STATE_CHG: { if (p_data->conn_state.state == BLE_CONN_STATE_DISCONNECTD) { app_print("disconnected. conn idx: %u, conn_hdl: 0x%x reason 0x%x\r\n", p_data->conn_state.info.discon_info.conn_idx, p_data->conn_state.info.discon_info.conn_hdl, p_data->conn_state.info.discon_info.reason); } else if (p_data->conn_state.state == BLE_CONN_STATE_CONNECTED) { app_print("connect success. conn idx:%u, conn_hdl:0x%x \r\n", p_data->conn_state.info.conn_info.conn_idx, p_data->conn_state.info.conn_info.conn_hdl); if (p_data->conn_state.info.conn_info.role == BLE_SLAVE) { app_sec_send_security_req(p_data->conn_state.info.conn_info.conn_idx); } conn_idx = p_data->conn_state.info.conn_info.conn_idx; } } break; case BLE_CONN_EVT_PARAM_UPDATE_IND: { app_print("conn idx %u, intv_min 0x%x, intv_max 0x%x, latency %u, supv_tout %u\r\n", p_data->conn_param_req_ind.conn_idx, p_data->conn_param_req_ind.intv_min, p_data->conn_param_req_ind.intv_max, p_data->conn_param_req_ind.latency, p_data->conn_param_req_ind.supv_tout); ble_conn_param_update_cfm(p_data->conn_param_req_ind.conn_idx, true, 2, 4); } break; case BLE_CONN_EVT_PARAM_UPDATE_RSP: { app_print("conn idx %u, param update result status: 0x%x\r\n", p_data->conn_param_rsp.conn_idx, p_data->conn_param_rsp.status); } break; case BLE_CONN_EVT_PARAM_UPDATE_INFO: { app_print("conn idx %u, param update ind: interval %d, latency %d, sup to %d\r\n", p_data->conn_params.conn_idx, p_data->conn_params.interval, p_data->conn_params.latency, p_data->conn_params.supv_tout); } break; case BLE_CONN_EVT_PKT_SIZE_SET_RSP: { app_print("conn idx %u, packet size set status 0x%x\r\n", p_data->pkt_size_set_rsp.conn_idx, p_data->pkt_size_set_rsp.status); } break; case BLE_CONN_EVT_PKT_SIZE_INFO: { app_print("le pkt size info: conn idx %u, tx oct %d, tx time %d, rx oct %d, rx time %d\r\n", p_data->pkt_size_info.conn_idx, p_data->pkt_size_info.max_tx_octets, p_data->pkt_size_info.max_tx_time, p_data->pkt_size_info.max_rx_octets, p_data->pkt_size_info.max_rx_time); } break; case BLE_CONN_EVT_NAME_GET_IND: { ble_conn_name_get_cfm(p_data->name_get_ind.conn_idx, 0, p_data->name_get_ind.token, DEV_NAME_LEN, (uint8_t *)dev_name, DEV_NAME_LEN); } break; case BLE_CONN_EVT_APPEARANCE_GET_IND: { ble_conn_appearance_get_cfm(p_data->appearance_get_ind.conn_idx, 0, p_data->appearance_get_ind.token, 0); } break; default: break; } } /*! \brief Callback function to handle @ref BLE_SEC_EVT_PAIRING_REQ_IND event \param[in] p_ind: pointer to the pairing request indication data \param[out] none \retval none */ static void app_pairing_req_hdlr(ble_gap_pairing_req_ind_t *p_ind) { ble_gap_pairing_param_t param = {0}; param.auth = BLE_GAP_AUTH_MASK_NONE; param.iocap = BLE_GAP_IO_CAP_NO_IO; param.key_size = 16; param.ikey_dist = BLE_GAP_KDIST_IDKEY | BLE_GAP_KDIST_SIGNKEY | BLE_GAP_KDIST_ENCKEY; param.rkey_dist = BLE_GAP_KDIST_IDKEY | BLE_GAP_KDIST_SIGNKEY | BLE_GAP_KDIST_ENCKEY; ble_sec_pairing_req_cfm(p_ind->conn_idx, true, &param, BLE_GAP_NO_SEC); } /*! \brief Callback function to handle @ref BLE_SEC_EVT_PAIRING_FAIL_INFO event \param[in] p_info: pointer to the pairing fail information data \param[out] none \retval none */ static void app_pairing_fail_hdlr(ble_sec_pairing_fail_t *p_info) { app_print("pairing fail reason 0x%x\r\n", p_info->param.reason); } /*! \brief Callback function to handle @ref BLE_SEC_EVT_PAIRING_SUCCESS_INFO event \param[in] p_info: pointer to the pairing success information data \param[out] none \retval none */ static void app_pairing_success_hdlr(ble_sec_pairing_success_t *p_info) { app_print("conn_idx %u pairing success, level 0x%x ltk_present %d sc %d\r\n", p_info->conidx, p_info->bond_info.pairing_lvl, p_info->bond_info.enc_key_present, p_info->sc); } /*! \brief Callback function to handle BLE security events \param[in] event: BLE security event type \param[in] p_data: pointer to the BLE security event data \param[out] none \retval none */ static void app_sec_evt_handler(ble_sec_evt_t event, ble_sec_data_u *p_data) { switch (event) { case BLE_SEC_EVT_PAIRING_REQ_IND: app_pairing_req_hdlr((ble_gap_pairing_req_ind_t *)p_data); break; case BLE_SEC_EVT_PAIRING_SUCCESS_INFO: app_pairing_success_hdlr((ble_sec_pairing_success_t *)p_data); break; case BLE_SEC_EVT_PAIRING_FAIL_INFO: app_pairing_fail_hdlr((ble_sec_pairing_fail_t *)p_data); break; default: break; } } /*! \brief Callback function to handle data received by datatrans server service \param[in] data_len: received data length \param[in] p_data: pointer to received data \param[out] none \retval none */ void app_datatrans_srv_rx_callback(uint16_t data_len, uint8_t *p_data) { uint8_t *p_str = sys_malloc(data_len + 1); if (p_str) { app_print("datatrans srv receive data: \r\n"); memset(p_str, 0, data_len + 1); memcpy(p_str, p_data, data_len); app_print("%s\r\n", p_str); sys_mfree(p_str); } } /*! \brief Init application security module \param[in] none \param[out] none \retval none */ void app_sec_mgr_init(void) { ble_sec_callback_register(app_sec_evt_handler); } /*! \brief Init APP connection manager module \param[in] none \param[out] none \retval none */ void app_conn_mgr_init(void) { ble_conn_callback_register(app_conn_evt_handler); } /*! \brief Init BLE component modules needed \param[in] none \param[out] none \retval none */ void ble_init(void) { ble_init_param_t param = {0}; ble_os_api_t os_interface = { .os_malloc = sys_malloc, .os_calloc = sys_calloc, .os_mfree = sys_mfree, .os_memset = sys_memset, .os_memcpy = sys_memcpy, .os_memcmp = sys_memcmp, .os_task_create = sys_task_create, .os_task_init_notification = sys_task_init_notification, .os_task_wait_notification = sys_task_wait_notification, .os_task_notify = sys_task_notify, .os_task_delete = sys_task_delete, .os_ms_sleep = sys_ms_sleep, .os_current_task_handle_get = sys_current_task_handle_get, .os_queue_init = sys_queue_init, .os_queue_free = sys_queue_free, .os_queue_write = sys_queue_write, .os_queue_read = sys_queue_read, .os_random_bytes_get = sys_random_bytes_get, }; ble_power_on(); param.role = BLE_GAP_ROLE_PERIPHERAL; param.keys_user_mgr = false; param.pairing_mode = BLE_GAP_PAIRING_SECURE_CONNECTION | BLE_GAP_PAIRING_LEGACY; param.privacy_cfg = BLE_GAP_PRIV_CFG_PRIV_EN_BIT; param.ble_task_stack_size = BLE_STACK_TASK_STACK_SIZE; param.ble_task_priority = BLE_STACK_TASK_PRIORITY; param.ble_app_task_stack_size = BLE_APP_TASK_STACK_SIZE; param.ble_app_task_priority = BLE_APP_TASK_PRIORITY; param.name_perm = BLE_GAP_WRITE_NOT_ENC; param.appearance_perm = BLE_GAP_WRITE_NOT_ENC; param.en_cfg = 0; param.p_os_api = &os_interface; ble_sw_init(&param); app_adapter_init(); app_conn_mgr_init(); app_sec_mgr_init(); ble_datatrans_srv_init(); ble_datatrans_srv_rx_cb_reg(app_datatrans_srv_rx_callback); /* The BLE interrupt must be enabled after ble_sw_init. */ ble_irq_enable(); } /*! \brief Main entry point This function is called right after the booting process has completed. \param[in] none \param[out] none \retval none */ int main(void) { sys_os_init(); platform_init(); app_uart_init(); ble_init(); sys_os_start(); for ( ; ; ); } /*! \file app_uart.c \brief APP UART for GD32VW55x SDK. \version 2023-07-20, V1.0.0, firmware for GD32VW55x */ /* Copyright (c) 2023, GigaDevice Semiconductor Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <ctype.h> #include "gd32vw55x.h" #include <stdio.h> #include "app_uart.h" #include "wrapper_os.h" #include "dbg_print.h" #include "wakelock.h" #include "log_uart.h" #include "ble_datatrans_srv.h" /* Priority of the uart task */ #define UART_TASK_PRIORITY OS_TASK_PRIORITY(4) /* Uart queque size */ #define UART_QUEUE_SIZE 3 /* Message format */ struct uart_msg { uint16_t len; /*!< Length, in bytes, of the message */ void *data; /*!< Pointer to the message */ }; extern uint8_t conn_idx; /* Uart queque */ static os_queue_t uart_queue; /* Uart cyclic buffer */ static cyclic_buf_t uart_cyc_buf; /* Uart RX buffer */ char uart_rx_buf[UART_BUFFER_SIZE]; /* Uart RX buffer index*/ uint32_t uart_index = 0; /*! \brief app uart rx handle \param[in] uart_cyc_buf: uart cyclic buffer \param[out] buf: data buf \param[in] len: data length \retval none */ static void app_uart_rx_handle_done(cyclic_buf_t *uart_cyc_buf, uint8_t *buf, uint16_t *len) { if (*len > cyclic_buf_count(uart_cyc_buf)) { *len = cyclic_buf_count(uart_cyc_buf); } if (buf == NULL) { cyclic_buf_drop(uart_cyc_buf, *len); } else { cyclic_buf_read(uart_cyc_buf, buf, *len); } } /*! \brief uart message precess \param[in] msg: uart message \retval none */ static void app_uart_msg_process(struct uart_msg *msg) { cyclic_buf_t *p_cyclic_buf = (cyclic_buf_t *)msg->data; char *command; command = sys_malloc(msg->len + 1); if (command == NULL) { app_print("No buffer alloc for uart msg !\r\n"); return; } app_uart_rx_handle_done((cyclic_buf_t *)msg->data, (uint8_t *)command, &msg->len); command[msg->len] = '\0'; if (ble_datatrans_srv_tx(conn_idx, (uint8_t *)command, msg->len) == BLE_ERR_NO_ERROR) { app_print("datatrans srv send data: \r\n"); app_print("%s\r\n", command); } sys_mfree(command); return; } /*! \brief uart task \param[in] param: \retval none */ static void app_uart_task(void *param) { struct uart_msg msg; for (;;) { sys_queue_read(&uart_queue, &msg, -1, false); app_uart_msg_process(&msg); } } /*! \brief uart message send \param[in] msg_data: message data \param[in] len: message length \retval success 0 */ int app_uart_send(void *msg_data, uint16_t len) { struct uart_msg msg; msg.len = len; msg.data = msg_data; return sys_queue_write(&uart_queue, &msg, 0, true); } /*! \brief uart rx data handler \param[in] none \retval none */ static void rx_handler(void) { // uart_index - 2 to remove 0x0d and 0x0a when using Husky if (uart_index > 2) { if (app_uart_send((void *)(&uart_cyc_buf), uart_index - 2) == 0) { if (cyclic_buf_write(&uart_cyc_buf, (uint8_t *)uart_rx_buf, uart_index - 2) == false) { dbg_print(ERR, "uart cyclic buffer full\r\n"); } } else { /* queue was full */ dbg_print(ERR, "queue full\r\n"); /* TODO: report 'message ignored' status */ } } uart_index = 0; } /*! \brief app uart rx irq handler \param[in] uart_port: uart port \retval none */ static void app_uart_rx_irq_hdl(uint32_t uart_port) { usart_interrupt_disable(uart_port, USART_INT_RBNE); while (1) { // We should have chance to check overflow error // Otherwise it may cause dead loop handle rx interrupt if (RESET != usart_flag_get(uart_port, USART_FLAG_ORERR)) { usart_flag_clear(uart_port, USART_FLAG_ORERR); } if ((RESET != usart_flag_get(uart_port, USART_FLAG_RBNE))) { uart_rx_buf[uart_index++] = (char)usart_data_receive(uart_port); if (uart_index >= UART_BUFFER_SIZE) { uart_index = 0; } } else { break; } } if (RESET != usart_flag_get(uart_port, USART_FLAG_IDLE)) { usart_flag_clear(UART2, USART_FLAG_IDLE); if (uart_index > 0) rx_handler(); } sys_wakelock_release(LOCK_ID_USART); usart_interrupt_enable(uart_port, USART_INT_RBNE); } /*! \brief app uart config \param[in] none \retval none */ void app_uart_config(void) { rcu_periph_clock_disable(RCU_GPIOA); rcu_periph_clock_disable(RCU_GPIOB); rcu_periph_clock_disable(RCU_UART2); rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_UART2); gpio_af_set(UART2_TX_GPIO, UART2_TX_AF_NUM, UART2_TX_PIN); gpio_af_set(UART2_RX_GPIO, UART2_RX_AF_NUM, UART2_RX_PIN); gpio_mode_set(UART2_TX_GPIO, GPIO_MODE_AF, GPIO_PUPD_NONE, UART2_TX_PIN); gpio_output_options_set(UART2_TX_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, UART2_TX_PIN); gpio_mode_set(UART2_RX_GPIO, GPIO_MODE_AF, GPIO_PUPD_NONE, UART2_RX_PIN); gpio_output_options_set(UART2_RX_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, UART2_RX_PIN); /* close printf buffer */ setvbuf(stdout, NULL, _IONBF, 0); usart_deinit(UART2); usart_word_length_set(UART2, USART_WL_8BIT); usart_stop_bit_set(UART2, USART_STB_1BIT); usart_parity_config(UART2, USART_PM_NONE); usart_baudrate_set(UART2, 115200U); usart_receive_config(UART2, USART_RECEIVE_ENABLE); usart_transmit_config(UART2, USART_TRANSMIT_ENABLE); usart_interrupt_enable(UART2, USART_INT_RBNE); usart_receive_fifo_enable(UART2); usart_enable(UART2); /*wait IDLEF set and clear it*/ while(RESET == usart_flag_get(UART2, USART_FLAG_IDLE)) { } usart_flag_clear(UART2, USART_FLAG_IDLE); usart_interrupt_enable(UART2, USART_INT_IDLE); } /*! \brief app uart initialize \retval success 0 */ int app_uart_init(void) { if (sys_task_create_dynamic((const uint8_t *)"UART task", 512, UART_TASK_PRIORITY, app_uart_task, NULL) == NULL) { return -1; } if (sys_queue_init(&uart_queue, UART_QUEUE_SIZE, sizeof(struct uart_msg))) { return -2; } app_uart_config(); memset(uart_rx_buf, 0, UART_BUFFER_SIZE); uart_index = 0; cyclic_buf_init(&uart_cyc_buf, 4 * UART_BUFFER_SIZE); uart_irq_callback_register(UART2, app_uart_rx_irq_hdl); return 0; } 详细介绍代码
最新发布
05-30
<think>好的,我现在需要解释用户提供的代码功能、模块划分以及关键技术点,特别是与BLE和UART相关的实现细节。首先,用户的问题是关于一段代码的详细解析,但用户没有提供具体的代码内容。这可能是个问题,因为如果没有代码,我无法直接分析其结构和功能。不过,用户之前引用了关于BLE数据格式的内容,可能之前的讨论涉及蓝牙低功耗(BLE)和通用异步收发传输器(UART)相关的代码。因此,我需要假设用户提到的代码可能与BLE和UART通信有关。接下来,我需要考虑如何在没有看到实际代码的情况下,提供一个合理的解释。通常,BLE和UART结合的代码可能涉及以下几个模块:1.**初始化模块**:负责配置BLE和UART的硬件参数,比如设置波特率、引脚分配、中断处理等。2. **BLE协议栈处理模块**:实现ATT协议,处理GATT服务,管理属性和特征值的读写操作。 3. **UART通信模块**:处理数据的接收和发送,可能包括缓冲区管理、数据解析和封装。4.**数据转发模块**:在BLE和UART之间传递数据,比如将从UART接收到的数据通过BLE发送,反之亦然。关键技术点可能包括:- **属性协议(ATT)的应用**:如何定义服务和特征,使用UUID标识类型,以及通过句柄访问属性值。- **中断处理**:UART的中断服务程序(ISR)用于实时接收数据,避免数据丢失。- **数据流管理**:确保BLE和UART之间的数据传输高效可靠,处理可能的流量控制和错误检测。 -**低功耗优化**:在BLE通信中采用适当的电源管理策略,延长设备续航时间。需要验证这些假设是否符合常见的实现方式。例如,BLE通常基于GATT架构,使用特征值进行数据交换,而UART通信需要配置正确的波特率和数据帧格式。此外,代码中可能会有回调函数处理BLE事件,如连接建立、数据写入等,并通过UART发送响应。可能还需要考虑代码中使用的库或框架,比如对于嵌入式开发,可能使用Nordic的nRF5 SDK或TI的BLE协议栈,这些库提供了API来处理底层的BLE通信。UART部分可能直接操作硬件寄存器或使用操作系统提供的接口。用户可能希望了解代码中各部分如何协同工作,特别是数据如何从UART传到BLE设备,反之亦然。需要解释数据流路径、模块间的接口以及关键函数的作用。例如,当UART接收到数据时,可能触发中断,将数据存入缓冲区,然后主循环处理这些数据并通过BLE特征值通知或指示发送给客户端。另外,需要提到可能存在的关键技术挑战,比如数据同步、缓冲区溢出处理、协议解析错误处理,以及如何保证实时性和可靠性。例如,使用双缓冲区结构来避免数据竞争,或者在BLE传输中使用确认机制确保数据送达。 最后,生成的相关问题需要围绕这些模块和关键技术点,帮助用户深入理解可能的扩展和优化方向,比如性能分析、优化方法、应用场景等。</think>### 代码功能与结构解析(基于BLE+UART典型实现) #### 一、核心功能 实现**双模数据透传系统**,完成以下功能闭环: - BLE设备接收手机端指令 $\rightarrow$ 通过UART转发给嵌入式主控 - 主控通过UART返回传感器数据 $\rightarrow$ 通过BLE特征值通知手机端 #### 二、模块划分与关键技术 $$ \begin{array}{|c|c|c|} \hline \text{模块} & \text{技术实现} & \text{关联协议} \\ \hline \text{BLE协议栈} & \text{GATT服务定义、特征值读写} & \text{ATT/GATT[^1]} \\ \text{UART驱动} & \text{波特率校准、DMA传输} & \text{RS-232标准} \\ \text{数据路由} & \text{环形缓冲区设计} & \text{生产者-消费者模型} \\ \text{电源管理} & \text{连接间隔自适应调整} & \text{BLE低功耗规范} \\ \hline \end{array} $$ #### 三、BLE关键实现细节 1. **属性表构建**: ```c // 定义透传服务UUID #define TRANSFER_SERVICE_UUID 0xFFE0 // 创建可写特征值(手机->设备) BLE_GATT_CHAR_PROPERTIES props = BLE_GATT_CHAR_WRITE; AddCharacteristic(props, "TX_DATA"); ``` 2. **数据接收回调**: ```cpp void onDataWrite(uint16_t handle) { if(handle == tx_char_handle) { uint8_t data[20]; ble.read(data); // 读取手机写入数据 uart.send(data); // 转发到UART } } ``` #### 四、UART关键技术点 1. **异步接收架构**: ```python class UARTBuffer: def __init__(self): self.buffer = bytearray() self.lock = threading.Lock() def irq_handler(data): # 硬件中断触发 with lock: buffer.extend(data) # 写入环形缓冲区 ``` 2. **协议解析状态机**: $$ \text{状态迁移条件} = \begin{cases} 0xAA \rightarrow \text{帧头检测态} \\ length \geq 5 \rightarrow \text{CRC校验态} \end{cases} $$ #### 五、双模协同难点 1. **速率匹配**:BLE MTU最大247字节 vs UART常用115200bps 2. **时序控制**:使用**硬件流控(RTS/CTS)**防止数据溢出 3. **错误恢复**:采用$\text{ARQ}$自动重传机制保障可靠性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值