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