1363 lines
49 KiB
C
1363 lines
49 KiB
C
|
/**
|
||
|
****************************************************************************************
|
||
|
* @addtogroup LANS
|
||
|
* @{
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* INCLUDE FILES
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
|
||
|
#include "rwip_config.h"
|
||
|
|
||
|
#if (BLE_LN_SENSOR)
|
||
|
#include "lan_common.h"
|
||
|
|
||
|
#include "gap.h"
|
||
|
#include "gattc_task.h"
|
||
|
#include "gattc.h"
|
||
|
#include "attm.h"
|
||
|
#include "lans.h"
|
||
|
#include "lans_task.h"
|
||
|
#include "prf_utils.h"
|
||
|
|
||
|
#include "ke_mem.h"
|
||
|
#include "co_utils.h"
|
||
|
|
||
|
/*
|
||
|
* CYCLING POWER SERVICE ATTRIBUTES
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
|
||
|
/// Full LANS Database Description - Used to add attributes into the database
|
||
|
static const struct attm_desc lans_att_db[LNS_IDX_NB] =
|
||
|
{
|
||
|
// Location and Navigation Service Declaration
|
||
|
[LNS_IDX_SVC] = {ATT_DECL_PRIMARY_SERVICE, PERM(RD, ENABLE), 0, 0},
|
||
|
|
||
|
// LN Feature Characteristic Declaration
|
||
|
[LNS_IDX_LN_FEAT_CHAR] = {ATT_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
|
||
|
// LN Feature Characteristic Value
|
||
|
[LNS_IDX_LN_FEAT_VAL] = {ATT_CHAR_LN_FEAT, PERM(RD, ENABLE), PERM(RI, ENABLE), sizeof(uint32_t)},
|
||
|
|
||
|
// Location and Speed Characteristic Declaration
|
||
|
[LNS_IDX_LOC_SPEED_CHAR] = {ATT_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
|
||
|
// Location and Speed Characteristic Value
|
||
|
[LNS_IDX_LOC_SPEED_VAL] = {ATT_CHAR_LOC_SPEED, PERM(NTF, ENABLE), PERM(RI, ENABLE), LANP_LAN_LOC_SPEED_MAX_LEN},
|
||
|
// Location and Speed Characteristic - Client Characteristic Configuration Descriptor
|
||
|
[LNS_IDX_LOC_SPEED_NTF_CFG] = {ATT_DESC_CLIENT_CHAR_CFG, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0},
|
||
|
|
||
|
// Position Quality Characteristic Declaration
|
||
|
[LNS_IDX_POS_Q_CHAR] = {ATT_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
|
||
|
// Position Quality Characteristic Value
|
||
|
[LNS_IDX_POS_Q_VAL] = {ATT_CHAR_POS_QUALITY, PERM(RD, ENABLE), PERM(RI, ENABLE), LANP_LAN_POSQ_MAX_LEN},
|
||
|
|
||
|
// LN Control Point Characteristic Declaration
|
||
|
[LNS_IDX_LN_CTNL_PT_CHAR] = {ATT_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
|
||
|
// LN Control Point Characteristic Value - The response has the maximal length
|
||
|
[LNS_IDX_LN_CTNL_PT_VAL] = {ATT_CHAR_LN_CNTL_PT, PERM(IND, ENABLE) | PERM(WRITE_REQ, ENABLE),
|
||
|
PERM(RI, ENABLE), LANP_LAN_LN_CNTL_PT_RSP_MAX_LEN},
|
||
|
// LN Control Point Characteristic - Client Characteristic Configuration Descriptor
|
||
|
[LNS_IDX_LN_CTNL_PT_IND_CFG] = {ATT_DESC_CLIENT_CHAR_CFG, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0},
|
||
|
|
||
|
// Navigation Characteristic Declaration
|
||
|
[LNS_IDX_NAVIGATION_CHAR] = {ATT_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
|
||
|
// Navigation Characteristic Value
|
||
|
[LNS_IDX_NAVIGATION_VAL] = {ATT_CHAR_NAVIGATION, PERM(NTF, ENABLE), PERM(RI, ENABLE), LANP_LAN_NAVIGATION_MAX_LEN},
|
||
|
// Navigation Characteristic - Client Characteristic Configuration Descriptor
|
||
|
[LNS_IDX_NAVIGATION_NTF_CFG] = {ATT_DESC_CLIENT_CHAR_CFG, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0},
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* EXPORTED FUNCTIONS DEFINITIONS
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
****************************************************************************************
|
||
|
* @brief Initialization of the LANS module.
|
||
|
* This function performs all the initializations of the Profile module.
|
||
|
* - Creation of database (if it's a service)
|
||
|
* - Allocation of profile required memory
|
||
|
* - Initialization of task descriptor to register application
|
||
|
* - Task State array
|
||
|
* - Number of tasks
|
||
|
* - Default task handler
|
||
|
*
|
||
|
* @param[out] env Collector or Service allocated environment data.
|
||
|
* @param[in|out] start_hdl Service start handle (0 - dynamically allocated), only applies for services.
|
||
|
* @param[in] app_task Application task number.
|
||
|
* @param[in] sec_lvl Security level (AUTH, EKS and MI field of @see enum attm_value_perm_mask)
|
||
|
* @param[in] param Configuration parameters of profile collector or service (32 bits aligned)
|
||
|
*
|
||
|
* @return status code to know if profile initialization succeed or not.
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
static uint8_t lans_init(struct prf_task_env* env, uint16_t* start_hdl, uint16_t app_task, uint8_t sec_lvl, struct lans_db_cfg* params)
|
||
|
{
|
||
|
//------------------ create the attribute database for the profile -------------------
|
||
|
// Service Configuration Flag
|
||
|
uint16_t cfg_flag = LANS_MANDATORY_MASK;
|
||
|
// Database Creation Status
|
||
|
uint8_t status = ATT_ERR_NO_ERROR;
|
||
|
|
||
|
/*
|
||
|
* Check if Position Quality shall be added.
|
||
|
*/
|
||
|
if((LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_NUMBER_OF_BEACONS_IN_SOLUTION_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_NUMBER_OF_BEACONS_IN_VIEW_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_TIME_TO_FIRST_FIX_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_ESTIMATED_HOR_POSITION_ERROR_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_ESTIMATED_VER_POSITION_ERROR_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_HOR_DILUTION_OF_PRECISION_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_VER_DILUTION_OF_PRECISION_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_POSITION_STATUS_SUPP)))
|
||
|
{
|
||
|
//Add configuration to the database
|
||
|
cfg_flag |= LANS_POS_Q_MASK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check if the Navigation characteristic shall be added.
|
||
|
*/
|
||
|
if ((LANS_IS_FEATURE_SUPPORTED(params->prfl_config, LANS_NAVIGATION_SUPP_FLAG)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_NUMBER_OF_BEACONS_IN_SOLUTION_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_REMAINING_DISTANCE_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_REMAINING_VERTICAL_DISTANCE_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_ESTIMATED_TIME_OF_ARRIVAL_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_POSITION_STATUS_SUPP)))
|
||
|
{
|
||
|
cfg_flag |= LANS_NAVI_MASK;
|
||
|
}
|
||
|
/*
|
||
|
* Check if the LN Control Point characteristic shall be added
|
||
|
*/
|
||
|
if ((LANS_IS_FEATURE_SUPPORTED(cfg_flag, LANS_NAVI_MASK)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->prfl_config, LANS_CTNL_PT_CHAR_SUPP_FLAG)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_TOTAL_DISTANCE_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_LSPEED_CHAR_CT_MASKING_SUPP)) ||
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_FIX_RATE_SETTING_SUPP)) ||
|
||
|
((LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_ELEVATION_SUPP)) &&
|
||
|
(LANS_IS_FEATURE_SUPPORTED(params->ln_feature, LANP_FEAT_ELEVATION_SETTING_SUPP))))
|
||
|
{
|
||
|
cfg_flag |= LANS_LN_CTNL_PT_MASK;
|
||
|
}
|
||
|
|
||
|
// Add service in the database
|
||
|
status = attm_svc_create_db(start_hdl, ATT_SVC_LOCATION_AND_NAVIGATION, (uint8_t *)&cfg_flag,
|
||
|
LNS_IDX_NB, NULL, env->task, &lans_att_db[0],
|
||
|
(sec_lvl & (PERM_MASK_SVC_DIS | PERM_MASK_SVC_AUTH | PERM_MASK_SVC_EKS)) | PERM(SVC_MI, DISABLE));
|
||
|
|
||
|
//-------------------- allocate memory required for the profile ---------------------
|
||
|
if (status == ATT_ERR_NO_ERROR)
|
||
|
{
|
||
|
// Allocate LANS required environment variable
|
||
|
struct lans_env_tag* lans_env =
|
||
|
(struct lans_env_tag* ) ke_malloc(sizeof(struct lans_env_tag), KE_MEM_ATT_DB);
|
||
|
|
||
|
// Initialize LANS environment
|
||
|
env->env = (prf_env_t*) lans_env;
|
||
|
lans_env->shdl = *start_hdl;
|
||
|
lans_env->prfl_cfg = cfg_flag;
|
||
|
lans_env->features = params->ln_feature;
|
||
|
lans_env->operation = LANS_RESERVED_OP_CODE;
|
||
|
lans_env->posq = (LANS_IS_FEATURE_SUPPORTED(cfg_flag, LANS_POS_Q_MASK)) ?
|
||
|
(struct lanp_posq* ) ke_malloc(sizeof(struct lanp_posq), KE_MEM_ATT_DB) : NULL;
|
||
|
|
||
|
lans_env->op_data = NULL;
|
||
|
memset(lans_env->env, 0, sizeof(lans_env->env));
|
||
|
|
||
|
lans_env->prf_env.app_task = app_task
|
||
|
| (PERM_GET(sec_lvl, SVC_MI) ? PERM(PRF_MI, ENABLE) : PERM(PRF_MI, DISABLE));
|
||
|
// Mono Instantiated task
|
||
|
lans_env->prf_env.prf_task = env->task | PERM(PRF_MI, DISABLE);
|
||
|
|
||
|
// initialize environment variable
|
||
|
env->id = TASK_ID_LANS;
|
||
|
lans_task_init(&(env->desc));
|
||
|
|
||
|
/* Put CPS in Idle state */
|
||
|
ke_state_set(env->task, LANS_IDLE);
|
||
|
}
|
||
|
|
||
|
return (status);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
****************************************************************************************
|
||
|
* @brief Destruction of the LANS module - due to a reset for instance.
|
||
|
* This function clean-up allocated memory (attribute database is destroyed by another
|
||
|
* procedure)
|
||
|
*
|
||
|
* @param[in|out] env Collector or Service allocated environment data.
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
static void lans_destroy(struct prf_task_env* env)
|
||
|
{
|
||
|
struct lans_env_tag* lans_env = (struct lans_env_tag*) env->env;
|
||
|
|
||
|
// free profile environment variables
|
||
|
env->env = NULL;
|
||
|
|
||
|
if (lans_env->posq != NULL)
|
||
|
{
|
||
|
ke_free(lans_env->posq);
|
||
|
}
|
||
|
|
||
|
if (lans_env->op_data != NULL)
|
||
|
{
|
||
|
ke_free(lans_env->op_data->cmd);
|
||
|
if(lans_env->op_data->ntf_pending)
|
||
|
{
|
||
|
ke_free(lans_env->op_data->ntf_pending);
|
||
|
}
|
||
|
ke_free(lans_env->op_data);
|
||
|
}
|
||
|
|
||
|
ke_free(lans_env);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
****************************************************************************************
|
||
|
* @brief Handles Connection creation
|
||
|
*
|
||
|
* @param[in|out] env Collector or Service allocated environment data.
|
||
|
* @param[in] conidx Connection index
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
static void lans_create(struct prf_task_env* env, uint8_t conidx)
|
||
|
{
|
||
|
struct lans_env_tag* lans_env = (struct lans_env_tag*) env->env;
|
||
|
|
||
|
memset(&(lans_env->env[conidx]), 0, sizeof(struct lans_cnx_env));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
****************************************************************************************
|
||
|
* @brief Handles Disconnection
|
||
|
*
|
||
|
* @param[in|out] env Collector or Service allocated environment data.
|
||
|
* @param[in] conidx Connection index
|
||
|
* @param[in] reason Detach reason
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
static void lans_cleanup(struct prf_task_env* env, uint8_t conidx, uint8_t reason)
|
||
|
{
|
||
|
struct lans_env_tag* lans_env = (struct lans_env_tag*) env->env;
|
||
|
|
||
|
// clean-up environment variable allocated for task instance
|
||
|
memset(&(lans_env->env[conidx]), 0, sizeof(struct lans_cnx_env));
|
||
|
}
|
||
|
|
||
|
/// LANS Task interface required by profile manager
|
||
|
const struct prf_task_cbs lans_itf =
|
||
|
{
|
||
|
(prf_init_fnct) lans_init,
|
||
|
lans_destroy,
|
||
|
lans_create,
|
||
|
lans_cleanup,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* GLOBAL FUNCTIONS DEFINITIONS
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
|
||
|
const struct prf_task_cbs* lans_prf_itf_get(void)
|
||
|
{
|
||
|
return &lans_itf;
|
||
|
}
|
||
|
|
||
|
void lans_send_cmp_evt(uint8_t conidx, uint8_t src_id, uint8_t dest_id, uint8_t operation, uint8_t status)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
|
||
|
// Go back to the Connected state if the state is busy
|
||
|
if (ke_state_get(src_id) == LANS_BUSY)
|
||
|
{
|
||
|
ke_state_set(src_id, LANS_IDLE);
|
||
|
}
|
||
|
|
||
|
// Set the operation code
|
||
|
lans_env->operation = LANS_RESERVED_OP_CODE;
|
||
|
|
||
|
// Send the message
|
||
|
struct lans_cmp_evt *evt = KE_MSG_ALLOC(LANS_CMP_EVT,
|
||
|
dest_id, src_id,
|
||
|
lans_cmp_evt);
|
||
|
|
||
|
evt->conidx = conidx;
|
||
|
evt->operation = operation;
|
||
|
evt->status = status;
|
||
|
|
||
|
ke_msg_send(evt);
|
||
|
}
|
||
|
|
||
|
uint8_t lans_pack_loc_speed_ntf(struct lanp_loc_speed *param, uint8_t *pckd_loc_speed)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
// Packed Measurement length
|
||
|
uint8_t pckd_loc_speed_len = LANP_LAN_LOC_SPEED_MIN_LEN;
|
||
|
|
||
|
// Check provided flags
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_LSPEED_INST_SPEED_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_INSTANTANEOUS_SPEED_SUPP))
|
||
|
{
|
||
|
//Pack instantaneous speed
|
||
|
co_write16p(&pckd_loc_speed[pckd_loc_speed_len], param->inst_speed);
|
||
|
pckd_loc_speed_len += 2;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_LSPEED_INST_SPEED_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_LSPEED_TOTAL_DISTANCE_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_TOTAL_DISTANCE_SUPP))
|
||
|
{
|
||
|
//Pack total distance (24bits)
|
||
|
co_write24p(&pckd_loc_speed[pckd_loc_speed_len], param->total_dist);
|
||
|
pckd_loc_speed_len += 3;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_LSPEED_TOTAL_DISTANCE_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_LSPEED_LOCATION_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_LOCATION_SUPP))
|
||
|
{
|
||
|
//Pack Location
|
||
|
co_write32p(&pckd_loc_speed[pckd_loc_speed_len], param->latitude);
|
||
|
pckd_loc_speed_len += 4;
|
||
|
co_write32p(&pckd_loc_speed[pckd_loc_speed_len], param->longitude);
|
||
|
pckd_loc_speed_len += 4;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_LSPEED_LOCATION_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_LSPEED_ELEVATION_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ELEVATION_SUPP))
|
||
|
{
|
||
|
//Pack elevation (24 bits)
|
||
|
co_write24p(&pckd_loc_speed[pckd_loc_speed_len], param->elevation);
|
||
|
pckd_loc_speed_len += 3;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_LSPEED_ELEVATION_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_LSPEED_HEADING_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_HEADING_SUPP))
|
||
|
{
|
||
|
//Pack Extreme Force Magnitudes (Maximum Force Magnitude & Minimum Force Magnitude)
|
||
|
co_write16p(&pckd_loc_speed[pckd_loc_speed_len], param->heading);
|
||
|
pckd_loc_speed_len += 2;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_LSPEED_HEADING_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_LSPEED_ROLLING_TIME_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ROLLING_TIME_SUPP))
|
||
|
{
|
||
|
//Pack rolling time
|
||
|
pckd_loc_speed[pckd_loc_speed_len] = param->rolling_time;
|
||
|
pckd_loc_speed_len++;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_LSPEED_ROLLING_TIME_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_LSPEED_UTC_TIME_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_UTC_TIME_SUPP))
|
||
|
{
|
||
|
// Pack UTC time
|
||
|
pckd_loc_speed_len += prf_pack_date_time(&pckd_loc_speed[pckd_loc_speed_len], &(param->date_time));
|
||
|
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_LSPEED_UTC_TIME_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Force the unused bits of the flag value to 0
|
||
|
// param->flags &= LANP_LSPEED_ALL_PRESENT;
|
||
|
// Flags value
|
||
|
co_write16p(&pckd_loc_speed[0], param->flags);
|
||
|
|
||
|
return pckd_loc_speed_len;
|
||
|
}
|
||
|
|
||
|
uint8_t lans_split_loc_speed_ntf(uint8_t conidx, struct gattc_send_evt_cmd *loc_speed_ntf1)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
// Extract flags info
|
||
|
uint16_t flags = co_read16p(&loc_speed_ntf1->value[0]);
|
||
|
// Allocate the GATT notification message
|
||
|
struct gattc_send_evt_cmd *loc_speed_ntf2 = KE_MSG_ALLOC_DYN(GATTC_SEND_EVT_CMD,
|
||
|
KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(&(lans_env->prf_env), conidx),
|
||
|
gattc_send_evt_cmd, LANP_LAN_LOC_SPEED_MAX_LEN);
|
||
|
|
||
|
// Fill in the parameter structure
|
||
|
loc_speed_ntf2->operation = GATTC_NOTIFY;
|
||
|
loc_speed_ntf2->handle = LANS_HANDLE(LNS_IDX_LOC_SPEED_VAL);
|
||
|
loc_speed_ntf2->length = LANP_LAN_LOC_SPEED_MIN_LEN;
|
||
|
|
||
|
// Copy status flags
|
||
|
co_write16p(&loc_speed_ntf2->value[0], (flags & (LANP_LSPEED_POSITION_STATUS_LSB |
|
||
|
LANP_LSPEED_POSITION_STATUS_MSB |
|
||
|
LANP_LSPEED_SPEED_AND_DISTANCE_FORMAT |
|
||
|
LANP_LSPEED_ELEVATION_SOURCE_LSB |
|
||
|
LANP_LSPEED_ELEVATION_SOURCE_MSB |
|
||
|
LANP_LSPEED_HEADING_SOURCE)));
|
||
|
// Current position
|
||
|
uint8_t len = 0;
|
||
|
|
||
|
for (uint16_t feat = LANP_LSPEED_INST_SPEED_PRESENT;
|
||
|
feat <= LANP_LSPEED_POSITION_STATUS_LSB;
|
||
|
feat <<= 1)
|
||
|
{
|
||
|
// First message fits within the MTU
|
||
|
if (loc_speed_ntf1->length <= gattc_get_mtu(conidx) - 3)
|
||
|
{
|
||
|
// Stop splitting
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(flags, feat))
|
||
|
{
|
||
|
switch (feat)
|
||
|
{
|
||
|
case LANP_LSPEED_ROLLING_TIME_PRESENT:
|
||
|
// Copy uint8
|
||
|
loc_speed_ntf2->value[loc_speed_ntf2->length] =
|
||
|
loc_speed_ntf1->value[LANP_LAN_LOC_SPEED_MIN_LEN];
|
||
|
len = 1;
|
||
|
break;
|
||
|
|
||
|
case LANP_LSPEED_INST_SPEED_PRESENT:
|
||
|
case LANP_LSPEED_HEADING_PRESENT:
|
||
|
// Copy uint16
|
||
|
memcpy(&loc_speed_ntf2->value[loc_speed_ntf2->length],
|
||
|
&loc_speed_ntf1->value[LANP_LAN_LOC_SPEED_MIN_LEN],
|
||
|
2);
|
||
|
len = 2;
|
||
|
break;
|
||
|
|
||
|
case LANP_LSPEED_TOTAL_DISTANCE_PRESENT:
|
||
|
case LANP_LSPEED_ELEVATION_PRESENT:
|
||
|
// Copy uint24
|
||
|
memcpy(&loc_speed_ntf2->value[loc_speed_ntf2->length],
|
||
|
&loc_speed_ntf1->value[LANP_LAN_LOC_SPEED_MIN_LEN],
|
||
|
3);
|
||
|
len = 3;
|
||
|
break;
|
||
|
|
||
|
case LANP_LSPEED_LOCATION_PRESENT:
|
||
|
// Copy latitude and longitude
|
||
|
memcpy(&loc_speed_ntf2->value[loc_speed_ntf2->length],
|
||
|
&loc_speed_ntf1->value[LANP_LAN_LOC_SPEED_MIN_LEN],
|
||
|
8);
|
||
|
len = 8;
|
||
|
break;
|
||
|
|
||
|
case LANP_LSPEED_UTC_TIME_PRESENT:
|
||
|
// Copy time
|
||
|
memcpy(&loc_speed_ntf2->value[loc_speed_ntf2->length],
|
||
|
&loc_speed_ntf1->value[LANP_LAN_LOC_SPEED_MIN_LEN],
|
||
|
7);
|
||
|
len = 7;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
len = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (len)
|
||
|
{
|
||
|
// Update values
|
||
|
loc_speed_ntf2->length += len;
|
||
|
// Remove field and flags from the first ntf
|
||
|
loc_speed_ntf1->length -= len;
|
||
|
memcpy(&loc_speed_ntf1->value[LANP_LAN_LOC_SPEED_MIN_LEN],
|
||
|
&loc_speed_ntf1->value[LANP_LAN_LOC_SPEED_MIN_LEN + len],
|
||
|
loc_speed_ntf1->length);
|
||
|
// Update flags
|
||
|
loc_speed_ntf1->value[0] &= ~feat;
|
||
|
loc_speed_ntf2->value[0] |= feat;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// store the pending notification to send
|
||
|
lans_env->op_data->ntf_pending = loc_speed_ntf2;
|
||
|
|
||
|
return loc_speed_ntf2->length;
|
||
|
}
|
||
|
|
||
|
uint8_t lans_update_characteristic_config(uint8_t conidx, uint8_t prfl_config, struct gattc_write_req_ind const *param)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
// Status
|
||
|
uint8_t status = GAP_ERR_NO_ERROR;
|
||
|
// Get the value
|
||
|
uint16_t ntf_cfg = co_read16p(¶m->value[0]);
|
||
|
|
||
|
// Check if the value is correct
|
||
|
if (prfl_config == LANS_PRF_CFG_FLAG_LN_CTNL_PT_IND)
|
||
|
{
|
||
|
if ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_IND))
|
||
|
{
|
||
|
// Save the new configuration in the environment
|
||
|
(ntf_cfg == PRF_CLI_STOP_NTFIND) ?
|
||
|
LANS_DISABLE_NTF_IND(conidx, prfl_config) : LANS_ENABLE_NTF_IND(conidx, prfl_config);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = PRF_ERR_INVALID_PARAM;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_NTF))
|
||
|
{
|
||
|
// Save the new configuration in the environment
|
||
|
(ntf_cfg == PRF_CLI_STOP_NTFIND) ?
|
||
|
LANS_DISABLE_NTF_IND(conidx, prfl_config) : LANS_ENABLE_NTF_IND(conidx, prfl_config);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = PRF_ERR_INVALID_PARAM;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (status == GAP_ERR_NO_ERROR)
|
||
|
{
|
||
|
// Allocate message to inform application
|
||
|
struct lans_cfg_ntfind_ind *ind = KE_MSG_ALLOC(LANS_CFG_NTFIND_IND,
|
||
|
prf_dst_task_get(&(lans_env->prf_env), conidx), prf_src_task_get(&(lans_env->prf_env), conidx),
|
||
|
lans_cfg_ntfind_ind);
|
||
|
// Inform APP of configuration change
|
||
|
ind->char_code = prfl_config;
|
||
|
ind->ntf_cfg = ntf_cfg;
|
||
|
ind->conidx = conidx;
|
||
|
ke_msg_send(ind);
|
||
|
|
||
|
// Enable Bonded Data
|
||
|
LANS_ENABLE_NTF_IND(conidx, LANS_PRF_CFG_PERFORMED_OK);
|
||
|
}
|
||
|
|
||
|
return (status);
|
||
|
}
|
||
|
|
||
|
uint8_t lans_pack_navigation_ntf(struct lanp_navigation *param, uint8_t *pckd_navigation)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
// Packed Measurement length
|
||
|
uint8_t pckd_navigation_len = LANP_LAN_NAVIGATION_MIN_LEN;
|
||
|
|
||
|
// Check provided flags
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_NAVI_REMAINING_DIS_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_REMAINING_DISTANCE_SUPP))
|
||
|
{
|
||
|
//Pack distance (24bits)
|
||
|
co_write24p(&pckd_navigation[pckd_navigation_len], param->remaining_distance);
|
||
|
pckd_navigation_len += 3;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_NAVI_REMAINING_DIS_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_NAVI_REMAINING_VER_DIS_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_REMAINING_VERTICAL_DISTANCE_SUPP))
|
||
|
{
|
||
|
//Pack vertical distance (24bits)
|
||
|
co_write24p(&pckd_navigation[pckd_navigation_len], param->remaining_ver_distance);
|
||
|
pckd_navigation_len += 3;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_NAVI_REMAINING_VER_DIS_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param->flags, LANP_NAVI_ESTIMATED_TIME_OF_ARRIVAL_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ESTIMATED_TIME_OF_ARRIVAL_SUPP))
|
||
|
{
|
||
|
//Pack time
|
||
|
pckd_navigation_len += prf_pack_date_time(
|
||
|
&pckd_navigation[pckd_navigation_len], &(param->estimated_arrival_time));
|
||
|
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param->flags &= ~LANP_NAVI_ESTIMATED_TIME_OF_ARRIVAL_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Force the unused bits of the flag value to 0
|
||
|
// param->flags &= LANP_NAVI_ALL_PRESENT;
|
||
|
// Flags value
|
||
|
co_write16p(&pckd_navigation[0], param->flags);
|
||
|
// Bearing value
|
||
|
co_write16p(&pckd_navigation[2], param->bearing);
|
||
|
// heading value
|
||
|
co_write16p(&pckd_navigation[4], param->heading);
|
||
|
|
||
|
return pckd_navigation_len;
|
||
|
}
|
||
|
|
||
|
void lans_upd_posq(struct lanp_posq param)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
|
||
|
// Check provided flags
|
||
|
if (LANS_IS_PRESENT(param.flags, LANP_POSQ_NUMBER_OF_BEACONS_IN_SOLUTION_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_NUMBER_OF_BEACONS_IN_SOLUTION_SUPP))
|
||
|
{
|
||
|
//Pack beacons in solution
|
||
|
lans_env->posq->n_beacons_solution = param.n_beacons_solution;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param.flags &= ~LANP_POSQ_NUMBER_OF_BEACONS_IN_SOLUTION_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param.flags, LANP_POSQ_NUMBER_OF_BEACONS_IN_VIEW_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_NUMBER_OF_BEACONS_IN_VIEW_SUPP))
|
||
|
{
|
||
|
//Pack beacons in view
|
||
|
lans_env->posq->n_beacons_view = param.n_beacons_view;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param.flags &= ~LANP_POSQ_NUMBER_OF_BEACONS_IN_VIEW_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param.flags, LANP_POSQ_TIME_TO_FIRST_FIX_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_TIME_TO_FIRST_FIX_SUPP))
|
||
|
{
|
||
|
//Pack time to fix
|
||
|
lans_env->posq->time_first_fix = param.time_first_fix;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param.flags &= ~LANP_POSQ_TIME_TO_FIRST_FIX_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param.flags, LANP_POSQ_EHPE_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ESTIMATED_HOR_POSITION_ERROR_SUPP))
|
||
|
{
|
||
|
//Pack ehpe
|
||
|
lans_env->posq->ehpe = param.ehpe;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param.flags &= ~LANP_POSQ_EHPE_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param.flags, LANP_POSQ_EVPE_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ESTIMATED_VER_POSITION_ERROR_SUPP))
|
||
|
{
|
||
|
//Pack evpe
|
||
|
lans_env->posq->evpe = param.evpe;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param.flags &= ~LANP_POSQ_EVPE_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param.flags, LANP_POSQ_HDOP_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_HOR_DILUTION_OF_PRECISION_SUPP))
|
||
|
{
|
||
|
//Pack hdop
|
||
|
lans_env->posq->hdop = param.hdop;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param.flags &= ~LANP_POSQ_HDOP_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(param.flags, LANP_POSQ_VDOP_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_VER_DILUTION_OF_PRECISION_SUPP))
|
||
|
{
|
||
|
//Pack vdop
|
||
|
lans_env->posq->vdop = param.vdop;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
param.flags &= ~LANP_POSQ_VDOP_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Force the unused bits of the flag value to 0
|
||
|
// param.flags &= LANP_POSQ_ALL_PRESENT;
|
||
|
// Flags value
|
||
|
lans_env->posq->flags = param.flags;
|
||
|
}
|
||
|
|
||
|
uint8_t lans_pack_posq(uint8_t *pckd_posq)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
|
||
|
// Packed length
|
||
|
uint8_t pckd_posq_len = LANP_LAN_POSQ_MIN_LEN;
|
||
|
|
||
|
// Check provided flags
|
||
|
if (LANS_IS_PRESENT(lans_env->posq->flags, LANP_POSQ_NUMBER_OF_BEACONS_IN_SOLUTION_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_NUMBER_OF_BEACONS_IN_SOLUTION_SUPP))
|
||
|
{
|
||
|
//Pack beacons in solution
|
||
|
pckd_posq[pckd_posq_len] = lans_env->posq->n_beacons_solution;
|
||
|
pckd_posq_len++;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
lans_env->posq->flags &= ~LANP_POSQ_NUMBER_OF_BEACONS_IN_SOLUTION_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(lans_env->posq->flags, LANP_POSQ_NUMBER_OF_BEACONS_IN_VIEW_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_NUMBER_OF_BEACONS_IN_VIEW_SUPP))
|
||
|
{
|
||
|
//Pack beacons in view
|
||
|
pckd_posq[pckd_posq_len] = lans_env->posq->n_beacons_view;
|
||
|
pckd_posq_len++;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
lans_env->posq->flags &= ~LANP_POSQ_NUMBER_OF_BEACONS_IN_VIEW_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(lans_env->posq->flags, LANP_POSQ_TIME_TO_FIRST_FIX_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_TIME_TO_FIRST_FIX_SUPP))
|
||
|
{
|
||
|
//Pack time to fix
|
||
|
co_write16p(&pckd_posq[pckd_posq_len], lans_env->posq->time_first_fix);
|
||
|
pckd_posq_len += 2;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
lans_env->posq->flags &= ~LANP_POSQ_TIME_TO_FIRST_FIX_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(lans_env->posq->flags, LANP_POSQ_EHPE_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ESTIMATED_HOR_POSITION_ERROR_SUPP))
|
||
|
{
|
||
|
//Pack ehpe
|
||
|
co_write32p(&pckd_posq[pckd_posq_len], lans_env->posq->ehpe);
|
||
|
pckd_posq_len += 4;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
lans_env->posq->flags &= ~LANP_POSQ_EHPE_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(lans_env->posq->flags, LANP_POSQ_EVPE_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ESTIMATED_VER_POSITION_ERROR_SUPP))
|
||
|
{
|
||
|
//Pack ehpe
|
||
|
co_write32p(&pckd_posq[pckd_posq_len], lans_env->posq->evpe);
|
||
|
pckd_posq_len += 4;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
lans_env->posq->flags &= ~LANP_POSQ_EVPE_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(lans_env->posq->flags, LANP_POSQ_HDOP_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_HOR_DILUTION_OF_PRECISION_SUPP))
|
||
|
{
|
||
|
//Pack ehpe
|
||
|
pckd_posq[pckd_posq_len] = lans_env->posq->hdop;
|
||
|
pckd_posq_len++;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
lans_env->posq->flags &= ~LANP_POSQ_HDOP_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LANS_IS_PRESENT(lans_env->posq->flags, LANP_POSQ_VDOP_PRESENT))
|
||
|
{
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_VER_DILUTION_OF_PRECISION_SUPP))
|
||
|
{
|
||
|
//Pack ehpe
|
||
|
pckd_posq[pckd_posq_len] = lans_env->posq->vdop;
|
||
|
pckd_posq_len++;
|
||
|
}
|
||
|
else //Not supported by the profile
|
||
|
{
|
||
|
//Force to not supported
|
||
|
lans_env->posq->flags &= ~LANP_POSQ_VDOP_PRESENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Force the unused bits of the flag value to 0
|
||
|
// lans_env->posq->flags &= LANP_POSQ_ALL_PRESENT;
|
||
|
// Flags value
|
||
|
co_write16p(&pckd_posq[0], lans_env->posq->flags);
|
||
|
|
||
|
return pckd_posq_len;
|
||
|
}
|
||
|
|
||
|
uint8_t lans_pack_ln_ctnl_point_cfm (uint8_t conidx, struct lans_ln_ctnl_pt_cfm *param, uint8_t *rsp)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
// Response Length (At least 3)
|
||
|
uint8_t rsp_len = LANP_LAN_LN_CNTL_PT_RSP_MIN_LEN;
|
||
|
|
||
|
// Set the Response Code
|
||
|
rsp[0] = LANP_LN_CTNL_PT_RESPONSE_CODE;
|
||
|
// Set the Response Value
|
||
|
rsp[2] = (param->status > LANP_LN_CTNL_PT_RESP_FAILED) ? LANP_LN_CTNL_PT_RESP_FAILED : param->status;
|
||
|
|
||
|
switch (lans_env->operation)
|
||
|
{
|
||
|
case (LANS_SET_CUMUL_VALUE_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_SET_CUMUL_VALUE;
|
||
|
} break;
|
||
|
|
||
|
case (LANS_MASK_LSPEED_CHAR_CT_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_MASK_LSPEED_CHAR_CT;
|
||
|
if (param->status == LANP_LN_CTNL_PT_RESP_SUCCESS)
|
||
|
{
|
||
|
lans_env->env[conidx].mask_lspeed_content =
|
||
|
param->value.mask_lspeed_content & 0x007F;
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANS_NAVIGATION_CONTROL_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_NAVIGATION_CONTROL;
|
||
|
if (param->status == LANP_LN_CTNL_PT_RESP_SUCCESS)
|
||
|
{
|
||
|
switch(LANS_GET_NAV_MODE(conidx))
|
||
|
{
|
||
|
// Disable notifications
|
||
|
case LANP_LN_CTNL_STOP_NAVI:
|
||
|
case LANP_LN_CTNL_PAUSE_NAVI:
|
||
|
LANS_SET_NAV_EN(conidx, false);
|
||
|
break;
|
||
|
|
||
|
// Enable notifications
|
||
|
case LANP_LN_CTNL_START_NAVI:
|
||
|
case LANP_LN_CTNL_RESUME_NAVI:
|
||
|
case LANP_LN_CTNL_START_NST_WPT:
|
||
|
LANS_SET_NAV_EN(conidx, true);
|
||
|
break;
|
||
|
|
||
|
// Do nothing
|
||
|
case LANP_LN_CTNL_SKIP_WPT:
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANS_REQ_NUMBER_OF_ROUTES_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_REQ_NUMBER_OF_ROUTES;
|
||
|
if (param->status == LANP_LN_CTNL_PT_RESP_SUCCESS)
|
||
|
{
|
||
|
co_write16p(&rsp[rsp_len], param->value.number_of_routes);
|
||
|
rsp_len += 2;
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANS_REQ_NAME_OF_ROUTE_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_REQ_NAME_OF_ROUTE;
|
||
|
if (param->status == LANP_LN_CTNL_PT_RESP_SUCCESS)
|
||
|
{
|
||
|
// pack name of route
|
||
|
for (int i=0; i<param->value.route.length; i++)
|
||
|
{
|
||
|
rsp[i + 3] = param->value.route.name[i];
|
||
|
rsp_len++;
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANS_SELECT_ROUTE_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_SELECT_ROUTE;
|
||
|
} break;
|
||
|
|
||
|
case (LANS_SET_FIX_RATE_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_SET_FIX_RATE;
|
||
|
} break;
|
||
|
|
||
|
case (LANS_SET_ELEVATION_OP_CODE):
|
||
|
{
|
||
|
// Set the request operation code
|
||
|
rsp[1] = LANP_LN_CTNL_PT_SET_ELEVATION;
|
||
|
} break;
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
param->status = LANP_LN_CTNL_PT_RESP_NOT_SUPP;
|
||
|
} break;
|
||
|
}
|
||
|
|
||
|
return rsp_len;
|
||
|
}
|
||
|
|
||
|
uint8_t lans_unpack_ln_ctnl_point_ind (uint8_t conidx, struct gattc_write_req_ind const *param)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
|
||
|
// Indication Status
|
||
|
uint8_t ind_status = LANP_LN_CTNL_PT_RESP_NOT_SUPP;
|
||
|
|
||
|
// Allocate a request indication message for the application
|
||
|
struct lans_ln_ctnl_pt_req_ind *req_ind = KE_MSG_ALLOC(LANS_LN_CTNL_PT_REQ_IND,
|
||
|
prf_dst_task_get(&(lans_env->prf_env), conidx), prf_src_task_get(&(lans_env->prf_env), conidx),
|
||
|
lans_ln_ctnl_pt_req_ind);
|
||
|
// Operation Code
|
||
|
req_ind->op_code = param->value[0];
|
||
|
req_ind->conidx = conidx;
|
||
|
|
||
|
// Operation Code
|
||
|
switch(req_ind->op_code)
|
||
|
{
|
||
|
case (LANP_LN_CTNL_PT_SET_CUMUL_VALUE):
|
||
|
{
|
||
|
// Check if total distance feature is supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_TOTAL_DISTANCE_SUPP))
|
||
|
{
|
||
|
// Provided parameter in not within the defined range
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_INV_PARAM;
|
||
|
|
||
|
if (param->length == 4)
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_SET_CUMUL_VALUE_OP_CODE;
|
||
|
// Cumulative value
|
||
|
req_ind->value.cumul_val = co_read24p(¶m->value[1]);
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANP_LN_CTNL_PT_MASK_LSPEED_CHAR_CT):
|
||
|
{
|
||
|
// Check if the LN Masking feature is supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_LSPEED_CHAR_CT_MASKING_SUPP))
|
||
|
{
|
||
|
// Provided parameter in not within the defined range
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_INV_PARAM;
|
||
|
|
||
|
if (param->length == 3)
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_MASK_LSPEED_CHAR_CT_OP_CODE;
|
||
|
// Mask content
|
||
|
req_ind->value.mask_content = co_read16p(¶m->value[1]);
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANP_LN_CTNL_PT_NAVIGATION_CONTROL):
|
||
|
{
|
||
|
// Check if navigation feature is supported
|
||
|
if ((LANS_IS_FEATURE_SUPPORTED(lans_env->prfl_cfg, LANS_NAVI_MASK)) &&
|
||
|
(LANS_IS_NTF_IND_ENABLED(conidx, LANS_PRF_CFG_FLAG_NAVIGATION_NTF)))
|
||
|
{
|
||
|
// Provided parameter in not within the defined range
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_INV_PARAM;
|
||
|
|
||
|
if (param->length == 2)
|
||
|
{
|
||
|
if (param->value[1] <= 0x05)
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_NAVIGATION_CONTROL_OP_CODE;
|
||
|
// Control value
|
||
|
req_ind->value.control_value = param->value[1];
|
||
|
// Store value in the environment
|
||
|
LANS_SET_NAV_MODE(conidx, req_ind->value.control_value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANP_LN_CTNL_PT_REQ_NUMBER_OF_ROUTES):
|
||
|
{
|
||
|
// Check if navigation feature is supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->prfl_cfg, LANS_NAVI_MASK))
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_REQ_NUMBER_OF_ROUTES_OP_CODE;
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANP_LN_CTNL_PT_REQ_NAME_OF_ROUTE):
|
||
|
{
|
||
|
// Check if navigation feature is supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->prfl_cfg, LANS_NAVI_MASK))
|
||
|
{
|
||
|
// Provided parameter in not within the defined range
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_INV_PARAM;
|
||
|
|
||
|
if (param->length == 3)
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_REQ_NAME_OF_ROUTE_OP_CODE;
|
||
|
// Route number
|
||
|
req_ind->value.route_number = co_read16p(¶m->value[1]);
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANP_LN_CTNL_PT_SELECT_ROUTE):
|
||
|
{
|
||
|
// Check if navigation feature is supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->prfl_cfg, LANS_NAVI_MASK))
|
||
|
{
|
||
|
// Provided parameter in not within the defined range
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_INV_PARAM;
|
||
|
|
||
|
if (param->length == 3)
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_SELECT_ROUTE_OP_CODE;
|
||
|
// route number
|
||
|
req_ind->value.route_number = co_read16p(¶m->value[1]);
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANP_LN_CTNL_PT_SET_FIX_RATE):
|
||
|
{
|
||
|
// Check if the LN Masking feature is supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_FIX_RATE_SETTING_SUPP))
|
||
|
{
|
||
|
// Provided parameter in not within the defined range
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_INV_PARAM;
|
||
|
|
||
|
if (param->length == 2)
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_SET_FIX_RATE_OP_CODE;
|
||
|
// fix rate
|
||
|
req_ind->value.fix_rate = param->value[1];
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
case (LANP_LN_CTNL_PT_SET_ELEVATION):
|
||
|
{
|
||
|
// Check if the Chain Weight Adjustment feature is supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_ELEVATION_SETTING_SUPP))
|
||
|
{
|
||
|
// Provided parameter in not within the defined range
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_INV_PARAM;
|
||
|
|
||
|
if (param->length == 4)
|
||
|
{
|
||
|
// The request can be handled
|
||
|
ind_status = LANP_LN_CTNL_PT_RESP_SUCCESS;
|
||
|
// Update the environment
|
||
|
lans_env->operation = LANS_SET_ELEVATION_OP_CODE;
|
||
|
// elevation
|
||
|
req_ind->value.elevation = co_read24p(¶m->value[1]);
|
||
|
}
|
||
|
}
|
||
|
} break;
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
// Operation Code is invalid, status is already LAN_CTNL_PT_RESP_NOT_SUPP
|
||
|
} break;
|
||
|
}
|
||
|
|
||
|
// If no error raised, inform the application about the request
|
||
|
if (ind_status == LANP_LN_CTNL_PT_RESP_SUCCESS)
|
||
|
{
|
||
|
// Send the request indication to the application
|
||
|
ke_msg_send(req_ind);
|
||
|
// Go to the Busy status
|
||
|
ke_state_set(prf_src_task_get(&(lans_env->prf_env), conidx), LANS_BUSY);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Free the allocated message
|
||
|
ke_msg_free(ke_param2msg(req_ind));
|
||
|
}
|
||
|
|
||
|
return ind_status;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void lans_exe_operation(void)
|
||
|
{
|
||
|
struct lans_env_tag* lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
|
||
|
ASSERT_ERR(lans_env->op_data != NULL);
|
||
|
|
||
|
bool finished = true;
|
||
|
|
||
|
while((lans_env->op_data->cursor < BLE_CONNECTION_MAX) && finished)
|
||
|
{
|
||
|
uint8_t conidx = lans_env->op_data->cursor;
|
||
|
|
||
|
switch(lans_env->operation)
|
||
|
{
|
||
|
case LANS_NTF_LOC_SPEED_OP_CODE:
|
||
|
{
|
||
|
// notification is pending, send it first
|
||
|
if(lans_env->op_data->ntf_pending != NULL)
|
||
|
{
|
||
|
ke_msg_send(lans_env->op_data->ntf_pending);
|
||
|
lans_env->op_data->ntf_pending = NULL;
|
||
|
finished = false;
|
||
|
}
|
||
|
// Check if sending of notifications has been enabled
|
||
|
else if (LANS_IS_NTF_IND_ENABLED(conidx, LANS_PRF_CFG_FLAG_LOC_SPEED_NTF))
|
||
|
{
|
||
|
struct lans_ntf_loc_speed_req *speed_cmd =
|
||
|
(struct lans_ntf_loc_speed_req *) ke_msg2param(lans_env->op_data->cmd);
|
||
|
|
||
|
// Save flags value
|
||
|
uint16_t flags = speed_cmd->parameters.flags;
|
||
|
|
||
|
// Mask unwanted fields if supported
|
||
|
if (LANS_IS_FEATURE_SUPPORTED(lans_env->features, LANP_FEAT_LSPEED_CHAR_CT_MASKING_SUPP))
|
||
|
{
|
||
|
speed_cmd->parameters.flags &= ~lans_env->env[conidx].mask_lspeed_content;
|
||
|
}
|
||
|
|
||
|
// Allocate the GATT notification message
|
||
|
struct gattc_send_evt_cmd *meas_val = KE_MSG_ALLOC_DYN(GATTC_SEND_EVT_CMD,
|
||
|
KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(&(lans_env->prf_env),conidx),
|
||
|
gattc_send_evt_cmd, LANP_LAN_LOC_SPEED_MAX_LEN);
|
||
|
|
||
|
// Fill in the parameter structure
|
||
|
meas_val->operation = GATTC_NOTIFY;
|
||
|
meas_val->handle = LANS_HANDLE(LNS_IDX_LOC_SPEED_VAL);
|
||
|
// pack measured value in database
|
||
|
meas_val->length = lans_pack_loc_speed_ntf(&speed_cmd->parameters, meas_val->value);
|
||
|
|
||
|
if (meas_val->length > gattc_get_mtu(conidx) - 3)
|
||
|
{
|
||
|
// Split (if necessary)
|
||
|
lans_split_loc_speed_ntf(conidx, meas_val);
|
||
|
}
|
||
|
|
||
|
// Restore flags value
|
||
|
speed_cmd->parameters.flags = flags;
|
||
|
|
||
|
// Send the event
|
||
|
ke_msg_send(meas_val);
|
||
|
|
||
|
finished = false;
|
||
|
}
|
||
|
|
||
|
// update cursor only if all notification has been sent
|
||
|
if(lans_env->op_data->ntf_pending == NULL)
|
||
|
{
|
||
|
lans_env->op_data->cursor++;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LANS_NTF_NAVIGATION_OP_CODE:
|
||
|
{
|
||
|
struct lans_ntf_navigation_req *nav_cmd =
|
||
|
(struct lans_ntf_navigation_req *) ke_msg2param(lans_env->op_data->cmd);
|
||
|
|
||
|
// Check if sending of notifications has been enabled
|
||
|
if (LANS_IS_NTF_IND_ENABLED(conidx, LANS_PRF_CFG_FLAG_NAVIGATION_NTF)
|
||
|
// and if navigation is enabled
|
||
|
&& LANS_IS_NAV_EN(conidx))
|
||
|
{
|
||
|
// Allocate the GATT notification message
|
||
|
struct gattc_send_evt_cmd *meas_val = KE_MSG_ALLOC_DYN(GATTC_SEND_EVT_CMD,
|
||
|
KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(&(lans_env->prf_env),conidx),
|
||
|
gattc_send_evt_cmd, LANP_LAN_NAVIGATION_MAX_LEN);
|
||
|
|
||
|
// Fill in the parameter structure
|
||
|
meas_val->operation = GATTC_NOTIFY;
|
||
|
meas_val->handle = LANS_HANDLE(LNS_IDX_NAVIGATION_VAL);
|
||
|
// pack measured value in database
|
||
|
meas_val->length = lans_pack_navigation_ntf(&nav_cmd->parameters, meas_val->value);
|
||
|
|
||
|
// Send the event
|
||
|
ke_msg_send(meas_val);
|
||
|
|
||
|
finished = false;
|
||
|
}
|
||
|
|
||
|
lans_env->op_data->cursor++;
|
||
|
}
|
||
|
break;
|
||
|
default: ASSERT_ERR(0); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// check if operation is finished
|
||
|
if(finished)
|
||
|
{
|
||
|
// send response to requester
|
||
|
struct lans_ntf_navigation_rsp * rsp =
|
||
|
KE_MSG_ALLOC(((lans_env->operation == LANS_NTF_NAVIGATION_OP_CODE) ?
|
||
|
LANS_NTF_NAVIGATION_RSP : LANS_NTF_LOC_SPEED_RSP),
|
||
|
lans_env->op_data->cmd->src_id,
|
||
|
lans_env->op_data->cmd->dest_id,
|
||
|
lans_ntf_navigation_rsp);
|
||
|
rsp->status = GAP_ERR_NO_ERROR;
|
||
|
ke_msg_send(rsp);
|
||
|
|
||
|
// free operation data
|
||
|
ke_msg_free(lans_env->op_data->cmd);
|
||
|
ke_free(lans_env->op_data);
|
||
|
lans_env->op_data = NULL;
|
||
|
// Set the operation code
|
||
|
lans_env->operation = LANS_RESERVED_OP_CODE;
|
||
|
// go back to idle state
|
||
|
ke_state_set(prf_src_task_get(&(lans_env->prf_env), 0), LANS_IDLE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void lans_send_rsp_ind(uint8_t conidx, uint8_t req_op_code, uint8_t status)
|
||
|
{
|
||
|
// Get the address of the environment
|
||
|
struct lans_env_tag *lans_env = PRF_ENV_GET(LANS, lans);
|
||
|
|
||
|
// Allocate the GATT notification message
|
||
|
struct gattc_send_evt_cmd *ctl_pt_rsp = KE_MSG_ALLOC_DYN(GATTC_SEND_EVT_CMD,
|
||
|
KE_BUILD_ID(TASK_GATTC, conidx),
|
||
|
prf_src_task_get(&lans_env->prf_env, conidx),
|
||
|
gattc_send_evt_cmd, LANP_LAN_LN_CNTL_PT_RSP_MIN_LEN);
|
||
|
|
||
|
// Fill in the parameter structure
|
||
|
ctl_pt_rsp->operation = GATTC_INDICATE;
|
||
|
ctl_pt_rsp->handle = LANS_HANDLE(LNS_IDX_LN_CTNL_PT_VAL);
|
||
|
// Pack Control Point confirmation
|
||
|
ctl_pt_rsp->length = LANP_LAN_LN_CNTL_PT_RSP_MIN_LEN;
|
||
|
// Response Code
|
||
|
ctl_pt_rsp->value[0] = LANP_LN_CTNL_PT_RESPONSE_CODE;
|
||
|
// Request Operation Code
|
||
|
ctl_pt_rsp->value[1] = req_op_code;
|
||
|
// Response value
|
||
|
ctl_pt_rsp->value[2] = status;
|
||
|
|
||
|
// Send the event
|
||
|
ke_msg_send(ctl_pt_rsp);
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif //(BLE_LN_SENSOR)
|
||
|
|
||
|
/// @} LANS
|