245 lines
8.7 KiB
C
245 lines
8.7 KiB
C
/**
|
|
* @file app_cls.c
|
|
* @brief CAIIC Link Service (CLS) application module implementation.
|
|
* Derived from the SDK rdtss demo (app_rdtss.c), trimmed to a single
|
|
* custom service with one write characteristic and one notify
|
|
* characteristic. Single-packet notify API: the caller retries when
|
|
* the profile reports busy.
|
|
*/
|
|
|
|
#include "rwip_config.h" // SW configuration
|
|
|
|
#if (BLE_RDTSS_SERVER)
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include "co_utils.h"
|
|
#include "app_cls.h" // CLS Application Module Definitions
|
|
#include "rdtss_task.h" // rdtss Profile Task Messages
|
|
#include "gapm_task.h" // GAP Manager Task API
|
|
#include "ns_ble.h"
|
|
#include "prf.h"
|
|
#include "rdtss.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private constants ---------------------------------------------------------*/
|
|
const uint8_t app_cls_svc_uuid[16] = ATT_SERVICE_CLS_128;
|
|
const struct attm_desc_128 app_cls_att_db[CLS_IDX_NB] =
|
|
{
|
|
/* Service Declaration */
|
|
[CLS_IDX_SVC] = {{0x00,0x28}, PERM(RD, ENABLE), 0, 0 },
|
|
|
|
/* Characteristic Declaration */
|
|
[CLS_IDX_WRITE_CHAR] = {{0x03,0x28}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0 },
|
|
/* Characteristic Value */
|
|
[CLS_IDX_WRITE_VAL] = {ATT_CHAR_CLS_WRITE_128, PERM(WRITE_COMMAND, ENABLE), PERM(RI, ENABLE)| PERM_VAL(UUID_LEN, 0x02), 0x200 },
|
|
/* Client Characteristic Configuration Descriptor */
|
|
[CLS_IDX_WRITE_CFG] = {{0x01,0x29}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), PERM(RI, ENABLE), 20 },
|
|
|
|
/* Characteristic Declaration */
|
|
[CLS_IDX_NTF_CHAR] = {{0x03,0x28}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0 },
|
|
/* Characteristic Value */
|
|
[CLS_IDX_NTF_VAL] = {ATT_CHAR_CLS_NTF_128, PERM(NTF, ENABLE), PERM(RI, ENABLE)| PERM_VAL(UUID_LEN, 0x02), 0x200 },
|
|
/* Client Characteristic Configuration Descriptor */
|
|
[CLS_IDX_NTF_CFG] = {{0x02,0x29}, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), PERM(RI, ENABLE), 20 },
|
|
};
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
static uint8_t s_cls_notify_en = 0; /* peer enabled notification on CCCD */
|
|
static uint8_t s_cls_ntf_busy = 0; /* one notification in flight */
|
|
static app_cls_rx_cb_t s_cls_rx_cb = NULL;
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* Private functions ---------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Create the CLS profile database (called via ns_ble_add_prf_func_register).
|
|
*/
|
|
void app_cls_add_cls(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_cls_att_db[0];
|
|
db_cfg->svc_uuid = &app_cls_svc_uuid[0];
|
|
db_cfg->max_nb_att = CLS_IDX_NB;
|
|
|
|
// Send the message
|
|
ke_msg_send(req);
|
|
|
|
app_cls_init();
|
|
}
|
|
|
|
/**
|
|
* @brief Read request handler: answer with a fixed device string.
|
|
*/
|
|
static int cls_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)
|
|
{
|
|
// Initialize length
|
|
uint8_t len = 0;
|
|
// Pointer to the data
|
|
const uint8_t *data = (const uint8_t *)"CAIIC";
|
|
len = 5;
|
|
|
|
// 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[0], data, len);
|
|
}
|
|
// Send message
|
|
ke_msg_send(rsp_value);
|
|
|
|
return (KE_MSG_CONSUMED);
|
|
}
|
|
|
|
/**
|
|
* @brief Write indicate handler: CCCD updates and downlink data.
|
|
*/
|
|
static int cls_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;
|
|
|
|
switch (handle)
|
|
{
|
|
case CLS_IDX_NTF_CFG:
|
|
if (length == 2)
|
|
{
|
|
uint16_t cfg_value = ind_value->value[0] + ind_value->value[1];
|
|
|
|
if (cfg_value == PRF_CLI_START_NTF)
|
|
{
|
|
//enabled notify
|
|
s_cls_notify_en = 1;
|
|
}
|
|
else if (cfg_value == PRF_CLI_STOP_NTFIND)
|
|
{
|
|
s_cls_notify_en = 0;
|
|
}
|
|
}
|
|
break;
|
|
case CLS_IDX_WRITE_VAL:
|
|
//ble downlink data receive
|
|
if (s_cls_rx_cb != NULL)
|
|
{
|
|
s_cls_rx_cb(ind_value->value, ind_value->length);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (KE_MSG_CONSUMED);
|
|
}
|
|
|
|
/**
|
|
* @brief Notification confirm handler: release the busy flag.
|
|
*/
|
|
static int cls_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)
|
|
{
|
|
s_cls_ntf_busy = 0;
|
|
|
|
return (KE_MSG_CONSUMED);
|
|
}
|
|
|
|
/**
|
|
* @brief Send one notification packet; busy/not-enabled returns -1.
|
|
*/
|
|
int app_cls_send_notify(const uint8_t *data, uint16_t length)
|
|
{
|
|
if ((s_cls_notify_en == 0) || (s_cls_ntf_busy != 0))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
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 = CLS_IDX_NTF_VAL;
|
|
req->length = length;
|
|
memcpy(&req->value[0], data, length);
|
|
|
|
ke_msg_send(req);
|
|
s_cls_ntf_busy = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void app_cls_set_rx_callback(app_cls_rx_cb_t cb)
|
|
{
|
|
s_cls_rx_cb = cb;
|
|
}
|
|
|
|
void app_cls_notify_state_reset(void)
|
|
{
|
|
s_cls_notify_en = 0;
|
|
s_cls_ntf_busy = 0;
|
|
}
|
|
|
|
/// Default State handlers definition
|
|
const struct ke_msg_handler app_cls_msg_handler_list[] =
|
|
{
|
|
{RDTSS_VALUE_REQ_IND, (ke_msg_func_t)cls_value_req_ind_handler},
|
|
{RDTSS_VAL_WRITE_IND, (ke_msg_func_t)cls_val_write_ind_handler},
|
|
{RDTSS_VAL_NTF_CFM, (ke_msg_func_t)cls_val_ntf_cfm_handler},
|
|
};
|
|
|
|
const struct app_subtask_handlers app_cls_handlers = APP_HANDLERS(app_cls);
|
|
|
|
|
|
void app_cls_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_cls_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
|