evan.liu 520838ce65 V1.00.20: OTA_END ack guaranteed delivery via deferred reset
- app_ota.c: after END ok, wait until the RSP is consumed by the host
  (BLE e0005 read-out / UART TX done) plus 300ms grace before resetting,
  2s timeout fallback; polled from the BLE schedule task (rwip_schedule
  must keep running for the ATT read to be processed)
- main.c: app_ota_reset_poll() in the BLE schedule task loop
- docs: ble_protocol.md 6.6 note, dev log section 43, AGENTS.md sync
2026-09-04 17:35:01 +08:00

384 lines
15 KiB
C

/**
* Copyright (c) 2025, NSING Technologies Inc.
*
* All rights reserved.
*
* This software is the exclusive property of NSING Technologies Inc. (Hereinafter
* referred to as NSING). This software, and the product of NSING described herein
* (Hereinafter referred to as the Product) are owned by NSING under the laws and treaties
* of the People's Republic of China and other applicable jurisdictions worldwide.
*
* NSING does not grant any license under its patents, copyrights, trademarks, or other
* intellectual property rights. Names and brands of third party may be mentioned or referred
* thereto (if any) for identification purposes only.
*
* NSING reserves the right to make changes, corrections, enhancements, modifications, and
* improvements to this software at any time without notice. Please contact NSING and obtain
* the latest version of this software before placing orders.
* Although NSING has attempted to provide accurate and reliable information, NSING assumes
* no responsibility for the accuracy and reliability of this software.
*
* It is the responsibility of the user of this software to properly design, program, and test
* the functionality and safety of any application made of this information and any resulting product.
* In no event shall NSING be liable for any direct, indirect, incidental, special,exemplary, or
* consequential damages arising in any way out of the use of this software or the Product.
*
* NSING Products are neither intended nor warranted for usage in systems or equipment, any
* malfunction or failure of which may cause loss of human life, bodily injury or severe property
* damage. Such applications are deemed, "Insecure Usage".
*
* All Insecure Usage shall be made at user's risk. User shall indemnify NSING and hold NSING
* harmless from and against all claims, costs, damages, and other liabilities, arising from or related
* to any customer's Insecure Usage.
* Any express or implied warranty with regard to this software or the Product, including,but not
* limited to, the warranties of merchantability, fitness for a particular purpose and non-infringement
* are disclaimed to the fullest extent permitted by law.
* Unless otherwise explicitly permitted by NSING, anyone may not duplicate, modify, transcribe
* or otherwise distribute this software for any purposes, in whole or in part.
*
* NSING products and technologies shall not be used for or incorporated into any products or systems
* whose manufacture, use, or sale is prohibited under any applicable domestic or foreign laws or regulations.
* User shall comply with any applicable export control laws and regulations promulgated and administered by
* the governments of any countries asserting jurisdiction over the parties or transactions.
**/
/**
* @file app_rdtss.c
* @author NSING Firmware Team
* @version v1.0.1
*
* @copyright Copyright (c) 2025, NSING Technologies Inc. All rights reserved.
*/
/**
* @addtogroup APP
* @{
*/
#include "rwip_config.h" // SW configuration
#if (BLE_RDTSS_SERVER)
/* Includes ------------------------------------------------------------------*/
#include "co_utils.h"
#include "app_rdtss.h" // rdtss Application Module Definitions
#include "rdtss_task.h" // Device Information Profile Functions
#include "gapm_task.h" // GAP Manager Task API
#include "ns_ble.h"
#include "prf.h"
#include "ke_timer.h"
#include "stdio.h"
#include "rdtss.h"
#include "app_ble_proto.h"
#include "app_info.h"
#include "app_ota.h"
#include "ble_up.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t notify_en = 0;
const uint8_t app_rdts_svc_uuid[16] = ATT_SERVICE_AM_SPEED_128;
const struct attm_desc_128 app_rdts_att_db[RDTSS_IDX_NB] =
{
/* Service Declaration */
[0] = {{0x00,0x28}, PERM(RD, ENABLE), 0, 0 },
/* Characteristic Declaration */
[1] = {{0x03,0x28}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0 },
/* Characteristic Value */
[2] = {ATT_CHAR_AM_SPEED_WRITE_128, PERM(WRITE_COMMAND, ENABLE), PERM(RI, ENABLE)| PERM_VAL(UUID_LEN, 0x02), 0x200 },
/* Client Characteristic Configuration Descriptor */
[3] = {{0x01,0x29}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), PERM(RI, ENABLE), 20 },
/* Characteristic Declaration */
[4] = {{0x03,0x28}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0 },
/* Characteristic Value */
[5] = {ATT_CHAR_AM_SPEED_NTF_128, PERM(NTF, ENABLE), PERM(RI, ENABLE)| PERM_VAL(UUID_LEN, 0x02), 0x200 },
/* Client Characteristic Configuration Descriptor */
[6] = {{0x02,0x29}, PERM(RD, ENABLE) |PERM(WRITE_REQ, ENABLE), PERM(RI, ENABLE), 20 },
/* Characteristic Declaration */
[7] = {{0x03,0x28}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0 },
/* CLI Characteristic Value: raw command line in (write-with-response),
* command output text out (sequential chunked reads, 0-length = EOF) */
[8] = {ATT_CHAR_AM_SPEED_CLI_128, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), PERM(RI, ENABLE)| PERM_VAL(UUID_LEN, 0x02), 0x200 },
/* Characteristic Declaration */
[9] = {{0x03,0x28}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0 },
/* Device info Characteristic Value (read-only): TLV snapshot of all
* info items, identical content to an INFO_RSP(all) frame */
[10] = {ATT_CHAR_AM_SPEED_INFO_128, PERM(RD, ENABLE), PERM(RI, ENABLE)| PERM_VAL(UUID_LEN, 0x02), 0x200 },
/* Characteristic Declaration */
[11] = {{0x03,0x28}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0 },
/* OTA Characteristic Value: one 0xCA transport frame in
* (write-with-response), the OTA_RSP frame out (ATT read) */
[12] = {ATT_CHAR_AM_SPEED_OTA_128, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), PERM(RI, ENABLE)| PERM_VAL(UUID_LEN, 0x02), 0x200 },
};
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief Create raw data transfer server profile database.
* @return void
*/
void app_rdtss_add_rdts(void)
{
struct rdtss_db_cfg *db_cfg;
struct gapm_profile_task_add_cmd *req = KE_MSG_ALLOC_DYN(GAPM_PROFILE_TASK_ADD_CMD,
TASK_GAPM,
TASK_APP,
gapm_profile_task_add_cmd,
sizeof(struct rdtss_db_cfg));
// Fill message
req->operation = GAPM_PROFILE_TASK_ADD;
req->sec_lvl = PERM(SVC_AUTH, NO_AUTH);
req->prf_task_id = TASK_ID_RDTSS;
req->app_task = TASK_APP;
req->start_hdl = 0;
// Set parameters
db_cfg = (struct rdtss_db_cfg *) req->param;
// Attribute table. In case the handle offset needs to be saved
db_cfg->att_tbl = &app_rdts_att_db[0];
db_cfg->svc_uuid = &app_rdts_svc_uuid[0];
db_cfg->max_nb_att = RDTSS_IDX_NB;
// Send the message
ke_msg_send(req);
app_rdtss_init();
}
/**
* @brief rdtss value require indicate handler
* @param
* @return
* @note Note
*/
static int rdtss_value_req_ind_handler(ke_msg_id_t const msgid,
struct rdtss_value_req_ind const *req_value,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
NS_LOG_DEBUG("%s\r\n",__func__);
// Initialize length
uint16_t len = 0;
// Pointer to the data
const uint8_t *data = NULL;
if (req_value->att_idx == RDTSS_IDX_CLI_VAL)
{
// CLI read/write characteristic: return the last command's output text
data = app_ble_proto_cli_rsp(&len);
}
else if (req_value->att_idx == RDTSS_IDX_OTA_VAL)
{
// OTA channel: fetch the pending framed OTA_RSP (consumed on read)
data = app_ota_chan_rsp_ble(&len);
}
else if (req_value->att_idx == RDTSS_IDX_INFO_VAL)
{
// device info characteristic: TLV snapshot of all info items
data = app_info_tlv_snapshot(&len);
}
else
{
len = APP_RDTSS_MANUFACTURER_NAME_LEN;
data = (uint8_t *)APP_RDTSS_MANUFACTURER_NAME;
}
// Allocate confirmation to send the value
struct rdtss_value_req_rsp *rsp_value = KE_MSG_ALLOC_DYN(RDTSS_VALUE_REQ_RSP,
src_id, dest_id,
rdtss_value_req_rsp,
len);
rsp_value->status = 0;
rsp_value->conidx = req_value ->conidx;
rsp_value->length = len;
rsp_value->att_idx = req_value->att_idx;
if (len)
{
// Copy data
memcpy(&rsp_value->value, data, len);
}
// Send message
ke_msg_send(rsp_value);
return (KE_MSG_CONSUMED);
}
/**
* @brief cuusts write indicate handler
* @param
* @return
* @note
*/
static int rdtss_val_write_ind_handler(ke_msg_id_t const msgid,
struct rdtss_val_write_ind const *ind_value,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
uint16_t handle = ind_value->handle;
uint16_t length = ind_value->length;
/* Raw write dump, gated by the "blelog" CLI switch (the former NS_LOG_DEBUG
* dump was compiled out, leaving the downlink path completely silent) */
if (app_ble_proto_log_get())
{
uint16_t i;
uint16_t n = (length > 24) ? 24 : length;
printf("[BLE] write ind: att_idx=%u len=%u", handle, length);
for (i = 0; i < n; i++)
{
printf(" %02X", ind_value->value[i]);
}
if (length > n)
{
printf(" ...");
}
printf("\r\n");
}
switch (handle)
{
case RDTSS_IDX_NTF_CFG:
if(length == 2)
{
uint16_t cfg_value = (uint16_t)ind_value->value[0] |
((uint16_t)ind_value->value[1] << 8);
if(cfg_value == PRF_CLI_START_NTF)
{
//enabled notify
notify_en = 1;
if (app_ble_proto_log_get())
{
printf("[BLE] notify enabled\r\n");
}
}
else if(cfg_value == PRF_CLI_STOP_NTFIND)
{
notify_en = 0;
if (app_ble_proto_log_get())
{
printf("[BLE] notify disabled\r\n");
}
}
}
break;
case RDTSS_IDX_WRITE_VAL:
//ble data receive -> frame reassembler (CLI_REQ etc.)
app_ble_proto_rx_bytes(ind_value->value, ind_value->length);
break;
case RDTSS_IDX_CLI_VAL:
// raw CLI command line (write-with-response); output is fetched
// back through an ATT read of this same characteristic
app_ble_proto_cli_exec(ind_value->value, ind_value->length);
break;
case RDTSS_IDX_OTA_VAL:
// OTA transport frame (write-with-response); the OTA_RSP frame is
// fetched back through an ATT read of this same characteristic
app_ota_chan_rx_ble(ind_value->value, ind_value->length);
break;
default:
break;
}
return (KE_MSG_CONSUMED);
}
/**
* @brief Functions
* @param
* @return
* @note Note
*/
static int rdtss_val_ntf_cfm_handler(ke_msg_id_t const msgid,
struct rdtss_val_ntf_cfm const *cfm_value,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
NS_LOG_DEBUG("%s,ntf cfm handle = %x, status = %x\r\n",__func__, cfm_value->handle, cfm_value->status);
ble_up_on_cfm();
return (KE_MSG_CONSUMED);
}
/**
* @brief rdtss send notify
* @param
* @return
* @note
*/
void rdtss_send_notify(uint8_t *data, uint16_t length)
{
if (notify_en)
{
struct rdtss_val_ntf_ind_req *req = KE_MSG_ALLOC_DYN(RDTSS_VAL_NTF_REQ,
prf_get_task_from_id(TASK_ID_RDTSS),
TASK_APP,
rdtss_val_ntf_ind_req,
length);
req->conidx = app_env.conidx;
req->notification = true;
req->handle = RDTSS_IDX_NTF_VAL;
req->length = length;
memcpy(&req->value[0], data, length);
ke_msg_send(req);
}
else
{
NS_LOG_INFO("Not enable notify\r\n");
}
}
/// Default State handlers definition
const struct ke_msg_handler app_rdtss_msg_handler_list[] =
{
{RDTSS_VALUE_REQ_IND, (ke_msg_func_t)rdtss_value_req_ind_handler},
{RDTSS_VAL_WRITE_IND, (ke_msg_func_t)rdtss_val_write_ind_handler},
{RDTSS_VAL_NTF_CFM, (ke_msg_func_t)rdtss_val_ntf_cfm_handler},
};
const struct app_subtask_handlers app_rdtss_handlers = APP_HANDLERS(app_rdtss);
void app_rdtss_init(void)
{
//register application subtask to app task
struct prf_task_t prf;
prf.prf_task_id = TASK_ID_RDTSS;
prf.prf_task_handler = &app_rdtss_handlers;
ns_ble_prf_task_register(&prf);
//register get itf function to prf.c
struct prf_get_func_t get_func;
get_func.task_id = TASK_ID_RDTSS;
get_func.prf_itf_get_func = rdtss_prf_itf_get;
prf_get_itf_func_register(&get_func);
}
#endif //BLE_RDTSS_SERVER