bleSDK_expansion_board/mesh/model/gen/gens/mm_gens_loc.c

634 lines
23 KiB
C

/**
****************************************************************************************
* @file mm_gens_loc.c
*
* @brief Mesh Model Generic Location Server Module
*
****************************************************************************************
*/
/**
****************************************************************************************
* @addtogroup MM_GENS_LOC
* @{
****************************************************************************************
*/
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "mm_itf.h"
#include "mm_gens.h"
/*
* ENUMERATIONS
****************************************************************************************
*/
/// Information bit field - base on Bit[7:4] of mm_info
/// 8 7 6 5 4
/// +--------------+---------------+-----------+------------+
/// | Wait App Loc | Wait App Glob | Publi Loc | Publi Glob |
/// +--------------+---------------+-----------+------------+
enum mm_gens_loc_info
{
/// Publication for Generic Location state (global part) to be sent after
/// confirmation received from application
MM_GENS_LOC_INFO_PUBLI_GLOB_POS = 4,
MM_GENS_LOC_INFO_PUBLI_GLOB_BIT = (1 << MM_GENS_LOC_INFO_PUBLI_GLOB_POS),
/// Publication for Generic Location state (local part) to be sent after
/// confirmation received from application
MM_GENS_LOC_INFO_PUBLI_LOC_POS = 5,
MM_GENS_LOC_INFO_PUBLI_LOC_BIT = (1 << MM_GENS_LOC_INFO_PUBLI_LOC_POS),
/// Wait for confirmation from application for Generic Location Global Get message
MM_GENS_LOC_INFO_WAIT_APP_GLOB_POS = 6,
MM_GENS_LOC_INFO_WAIT_APP_GLOB_BIT = (1 << MM_GENS_LOC_INFO_WAIT_APP_GLOB_POS),
/// Wait for confirmation from application for Generic Location Local Get message
MM_GENS_LOC_INFO_WAIT_APP_LOC_POS = 7,
MM_GENS_LOC_INFO_WAIT_APP_LOC_BIT = (1 << MM_GENS_LOC_INFO_WAIT_APP_LOC_POS),
};
/*
* TYPE DEFINITIONS
****************************************************************************************
*/
/// Structure for Generic Location Server model environment
typedef struct mm_gens_loc_env
{
/// Basic model environment - Must be first element in the structure - DO NOT MOVE
mm_mdl_env_t env;
/// Timer for sending of publications
mesh_timer_t tmr_publi;
/// Publication period
uint32_t publi_period_ms;
/// List of prepared Generic Location Global Status messages
list_t list_status_glob;
/// List of prepared Generic Location Local Status messages
list_t list_status_loc;
/// Information (@see enum mm_gens_loc_info) - combine to env.info
//uint8_t info;
} mm_gens_loc_env_t;
/// Structure for Generic Location Setup Server model environment
typedef struct mm_gens_locs_env
{
/// Basic model environment - Must be first element in the structure - DO NOT MOVE
mm_mdl_env_t env;
/// Pointer to environment of associated Generic Location Server model
mm_gens_loc_env_t *p_env_loc;
} mm_gens_locs_env_t;
/*
* LOCAL FUNCTIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief TODO [LT]
****************************************************************************************
*/
__STATIC mesh_buf_t *mm_gens_loc_find_buf(list_t *p_list, uint16_t src, bool extract)
{
// Get first buffer
mesh_buf_t *p_buf = (mesh_buf_t *)list_pick(p_list);
while (p_buf)
{
// Read environment
mm_route_env_t *p_env = (mm_route_env_t *)&p_buf->env[0];
if (p_env->u_addr.src == src)
{
// Extract the buffer if required
if (extract)
{
list_extract(p_list, &(p_buf->hdr));
}
break;
}
// Get next buffer
p_buf = (mesh_buf_t *)p_buf->hdr.next;
}
return (p_buf);
}
/**
****************************************************************************************
* @brief Prepare and send a Generic Location Global Status message
*
* @param[in] p_env_loc Pointer to Generic Location Server model environment
****************************************************************************************
*/
__STATIC void mm_gens_loc_send_status_global(mm_gens_loc_env_t *p_env_loc, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env,
int32_t latitude, int32_t longitude, int16_t altitude)
{
// Status
//uint8_t status;
if (!p_buf)
{
p_buf = mm_route_buf_alloc(MM_GEN_LOC_STATUS_GLOB_LEN);
}
if (p_buf)
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf);
// Get pointer to environment
mm_route_env_t *p_env = (mm_route_env_t *)&p_buf->env[0];
if (p_route_env)
{
memcpy(p_env, p_route_env, sizeof(mm_route_env_t));
}
p_env->opcode = MM_MSG_GEN_LOCG_STATUS;
p_env->mdl_lid = p_env_loc->env.mdl_lid;
SETB(p_env->info, MM_ROUTE_INFO_PUBLISH, (p_buf == NULL) && (p_route_env == NULL));
SETB(p_env->info, MM_ROUTE_INFO_RX, 0);
// Fill the message
write32p(p_data + MM_GEN_LOC_STATUS_GLOB_LAT_POS, latitude);
write32p(p_data + MM_GEN_LOC_STATUS_GLOB_LONG_POS, longitude);
write16p(p_data + MM_GEN_LOC_STATUS_GLOB_ALT_POS, altitude);
// Send the message
mm_route_send(p_buf);
}
}
/**
****************************************************************************************
* @brief Prepare and send a Generic Location Local Status message
*
* @param[in] p_env_loc Pointer to Generic Location Server model environment
****************************************************************************************
*/
__STATIC void mm_gens_loc_send_status_local(mm_gens_loc_env_t *p_env_loc, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env,
int16_t north, int16_t east, int16_t altitude, uint8_t floor,
uint16_t uncertainty)
{
// Status
//uint8_t status;
if (!p_buf)
{
p_buf = mm_route_buf_alloc(MM_GEN_LOC_STATUS_LOC_LEN);
}
if (p_buf)
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf);
// Get pointer to environment
mm_route_env_t *p_env = (mm_route_env_t *)&p_buf->env[0];
if (p_route_env)
{
memcpy(p_env, p_route_env, sizeof(mm_route_env_t));
}
p_env->opcode = MM_MSG_GEN_LOCL_STATUS;
p_env->mdl_lid = p_env_loc->env.mdl_lid;
SETB(p_env->info, MM_ROUTE_INFO_PUBLISH, (p_buf == NULL) && (p_route_env == NULL));
SETB(p_env->info, MM_ROUTE_INFO_RX, 0);
// Fill the message
write16p(p_data + MM_GEN_LOC_STATUS_LOC_NORTH_POS, north);
write16p(p_data + MM_GEN_LOC_STATUS_LOC_EAST_POS, east);
write16p(p_data + MM_GEN_LOC_STATUS_LOC_ALT_POS, altitude);
*(p_data + MM_GEN_LOC_STATUS_LOC_FLOOR_POS) = floor;
write16p(p_data + MM_GEN_LOC_STATUS_LOC_UNCERT_POS, uncertainty);
// Send the message
mm_route_send(p_buf);
}
}
/**
****************************************************************************************
* @brief Inform application that current Generic Location State is required (global part)
*
* @param[in] p_env_loc Pointer to Generic Location Server model environment
****************************************************************************************
*/
__STATIC void mm_gens_loc_send_global_req_ind(mm_gens_loc_env_t *p_env_loc)
{
// Check that a confirmation is not already expected from application
if (!GETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_GLOB))
{
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_GLOB, 1);
mm_srv_state_req_ind_send(MM_SRV_LOCG_REQ_IND, p_env_loc->env.elmt_idx);
}
}
/**
****************************************************************************************
* @brief Inform application that current Generic Location State is required (local part)
*
* @param[in] p_env_loc Pointer to Generic Location Server model environment
****************************************************************************************
*/
__STATIC void mm_gens_loc_send_local_req_ind(mm_gens_loc_env_t *p_env_loc)
{
// Check that a confirmation is not already expected from application
if (!GETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_LOC))
{
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_LOC, 1);
mm_srv_state_req_ind_send(MM_SRV_LOCL_REQ_IND, p_env_loc->env.elmt_idx);
}
}
/**
****************************************************************************************
* @brief Handler for Generic Location Global Set/Set Unacknowledged message
*
* @param[in] p_env_loc Pointer to Generic Location Server model environment
* @param[in] p_buf Pointer to buffer containing the received message
* @param[in] opcode Received operation code
****************************************************************************************
*/
__STATIC void mm_gens_loc_handler_set_global(mm_gens_loc_env_t *p_env_loc, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env)
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf);
// Global Latitude
int32_t latitude = (int32_t)read32p(p_data + MM_GEN_LOC_SET_GLOB_LAT_POS);
// Global Longitude
int32_t longitude = (int32_t)read32p(p_data + MM_GEN_LOC_SET_GLOB_LONG_POS);
// Global Altitude
int16_t altitude = (int16_t)read16p(p_data + MM_GEN_LOC_SET_GLOB_ALT_POS);
// Inform application about new state value
mm_srv_locg_upd_ind_send(p_env_loc->env.elmt_idx, latitude, longitude, altitude);
if (p_route_env->opcode == MM_MSG_GEN_LOCG_SET)
{
// Send a Generic Location Global Status message
mm_gens_loc_send_status_global(p_env_loc, NULL, p_route_env, latitude, longitude, altitude);
}
}
/**
****************************************************************************************
* @brief Handler for Generic Location Local Set/Set Unacknowledged message
*
* @param[in] p_env_loc Pointer to Generic Location Server model environment
* @param[in] p_buf Pointer to buffer containing the received message
* @param[in] opcode Received operation code
****************************************************************************************
*/
__STATIC void mm_gens_loc_handler_set_local(mm_gens_loc_env_t *p_env_loc, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env)
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf);
// Local North
int16_t north = (int16_t)read16p(p_data + MM_GEN_LOC_SET_LOC_NORTH_POS);
// Local East
int16_t east = (int16_t)read16p(p_data + MM_GEN_LOC_SET_LOC_EAST_POS);
// Global Altitude
int16_t altitude = (int16_t)read16p(p_data + MM_GEN_LOC_SET_LOC_ALT_POS);
// Floor
uint8_t floor = *(p_data + MM_GEN_LOC_SET_LOC_FLOOR_POS);
// Uncertainty
uint16_t uncertainty = read16p(p_data + MM_GEN_LOC_SET_LOC_UNCERT_POS);
// Inform application about new state value
mm_srv_locl_upd_ind_send(p_env_loc->env.elmt_idx, north, east, altitude,
floor, uncertainty);
if (p_route_env->opcode == MM_MSG_GEN_LOCL_SET)
{
// Send a Generic Location Local Status message
mm_gens_loc_send_status_local(p_env_loc, NULL, p_route_env, north, east, altitude,
floor, uncertainty);
}
}
/**
****************************************************************************************
* @brief Prepare a buffer for transmission of Generic Location Global Status or Generic
* Location Local Status message after reception of a get message
*
* @param[in] p_env_loc Pointer to Generic Location Server model environment
* @param[in] p_route_env Information about received Generic Location Global/Local Get message
* @param[in] global True if Generic Location Global Get message has been received, else False
****************************************************************************************
*/
__STATIC void mm_gens_loc_prepare_status(mm_gens_loc_env_t *p_env_loc,
mm_route_env_t *p_route_env, bool global)
{
// Pointer to the list of received get messages to parse
list_t *p_list = (global) ? &p_env_loc->list_status_glob : &p_env_loc->list_status_loc;
// Check that a Generic Location Global/Local Get message from the same source address has not already
// been received
if (!mm_gens_loc_find_buf(p_list, p_route_env->u_addr.src, false))
{
// Buffer that will contain the Generic Location Global/Local Status message
mesh_buf_t *p_buf_status = mm_route_buf_alloc((global) ? MM_GEN_LOC_STATUS_GLOB_LEN
: MM_GEN_LOC_STATUS_LOC_LEN);
if (p_buf_status)
{
// Copy the received environment
memcpy(&p_buf_status->env[0], p_route_env, sizeof(mm_route_env_t));
// Insert the buffer in the list of received get messages
list_push_back(p_list, &p_buf_status->hdr);
// Retrieve the Generic Location state from the application
if (global)
{
mm_gens_loc_send_global_req_ind(p_env_loc);
}
else
{
mm_gens_loc_send_local_req_ind(p_env_loc);
}
}
}
}
/*
* INTERNAL CALLBACK FUNCTIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Callback function called when timer monitoring publication duration for
* Generic Location Server model expires
*
* @param[in] p_env Pointer to model environment for Generic Location Server model
****************************************************************************************
*/
__STATIC void mm_gens_loc_cb_tmr_publi(void *p_tmr)
{
// Get allocated environment
mm_gens_loc_env_t *p_env_loc = MESH_TMR2ENV(p_tmr, mm_gens_loc_env_t, tmr_publi);
if (p_env_loc->publi_period_ms)
{
// Keep in mind that a publication must be sent
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_PUBLI_LOC, 1);
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_PUBLI_GLOB, 1);
// Retrieve current Generic Location state (Global part) from the application
mm_gens_loc_send_global_req_ind(p_env_loc);
// Retrieve current Generic Location state (Location part) from the application
mm_gens_loc_send_local_req_ind(p_env_loc);
// Restart the timer
mesh_timer_set(&p_env_loc->tmr_publi, p_env_loc->publi_period_ms);
}
}
/**
****************************************************************************************
* @brief Inform Generic Location Server model about a received message
*
* @param[in] p_env Pointer to the environment allocated for the Generic Location
* Server model
* @param[in] p_buf Pointer to the buffer containing the received message
* @param[in] p_route_env Pointer to structure containing reception parameters provided
* by the Mesh Profile block
****************************************************************************************
*/
__STATIC void mm_gens_loc_cb_rx(mm_mdl_env_t *p_env, mesh_buf_t *p_buf, mm_route_env_t *p_route_env)
{
// Environment for Generic Location Server model
mm_gens_loc_env_t *p_env_loc;
if ((p_route_env->opcode == MM_MSG_GEN_LOCG_GET)
|| (p_route_env->opcode == MM_MSG_GEN_LOCL_GET))
{
p_env_loc = (mm_gens_loc_env_t *)p_env;
// Prepare environment for transition of status message
mm_gens_loc_prepare_status(p_env_loc, p_route_env,
(p_route_env->opcode == MM_MSG_GEN_LOCG_GET));
}
else
{
// Environment for Generic Location Setup Server model
mm_gens_locs_env_t *p_env_locs = (mm_gens_locs_env_t *)p_env;
p_env_loc = p_env_locs->p_env_loc;
if ((p_route_env->opcode == MM_MSG_GEN_LOCG_SET)
|| (p_route_env->opcode == MM_MSG_GEN_LOCG_SET_UNACK))
{
// Handle the received message
mm_gens_loc_handler_set_global(p_env_loc, p_buf, p_route_env);
}
else
{
// Handle the receive message
mm_gens_loc_handler_set_local(p_env_loc, p_buf, p_route_env);
}
}
}
/**
****************************************************************************************
* @brief Check if a given opcode is handled by the Generic Location Server model
*
* @param[in] p_env Pointer to the environment allocated for the Generic Location
* Server model
* @param[in] opcode Opcode to check
*
* @return An error status (@see enum mesh_err)
****************************************************************************************
*/
__STATIC uint8_t mm_gens_loc_cb_opcode_check(mm_mdl_env_t *p_env, uint32_t opcode)
{
uint8_t status = MESH_ERR_MDL_INVALID_OPCODE;
if (p_env->model_id == MM_ID_GENS_LOC)
{
if ((opcode == MM_MSG_GEN_LOCG_GET)
|| (opcode == MM_MSG_GEN_LOCL_GET))
{
status = MESH_ERR_NO_ERROR;
}
}
else if (p_env->model_id == MM_ID_GENS_LOCS)
{
if ((opcode == MM_MSG_GEN_LOCG_SET)
|| (opcode == MM_MSG_GEN_LOCG_SET_UNACK)
|| (opcode == MM_MSG_GEN_LOCL_SET)
|| (opcode == MM_MSG_GEN_LOCL_SET_UNACK))
{
status = MESH_ERR_NO_ERROR;
}
}
return (status);
}
/*
* GLOBAL FUNCTIONS
****************************************************************************************
*/
uint8_t mm_gens_loc_register(uint8_t elmt_idx)
{
// Register Generic Location Server model
m_lid_t mdl_lid = ms_register_model(MM_ID_GENS_LOC, elmt_idx, MM_CFG_PUBLI_AUTH_BIT);
if (mdl_lid != MESH_INVALID_LID)
{
// Inform the Model State Manager about registered model
mm_gens_loc_env_t *p_env_loc = (mm_gens_loc_env_t *)mm_state_register(elmt_idx, MM_ID_GENS_LOC, mdl_lid,
MM_ROLE_SRV_PUBLI, sizeof(mm_gens_loc_env_t));
if (p_env_loc)
{
// Set internal callback functions
p_env_loc->tmr_publi.cb = mm_gens_loc_cb_tmr_publi;
//p_env_loc->tmr_publi.p_env = (void *)p_env_loc;
// Set internal callback functions
p_env_loc->env.mdl_cb.cb_rx = mm_gens_loc_cb_rx;
p_env_loc->env.mdl_cb.cb_opcode_check = mm_gens_loc_cb_opcode_check;
//p_env_loc->env.mdl_cb.cb_publish_param = mm_gens_loc_cb_publish_param;
// Inform application about registered model
mm_register_ind_send(MM_ID_GENS_LOC, elmt_idx, mdl_lid);
}
// Register Generic Location Setup Server model
m_lid_t locs_lid = ms_register_model(MM_ID_GENS_LOCS, elmt_idx, 0);
if (locs_lid != MESH_INVALID_LID)
{
// Inform the Model State Manager about registered model
mm_gens_locs_env_t *p_env_locs = (mm_gens_locs_env_t *)mm_state_register(elmt_idx, MM_ID_GENS_LOCS, locs_lid,
MM_ROLE_SRV, sizeof(mm_gens_locs_env_t));
if (p_env_locs)
{
// Set internal callback functions
p_env_locs->env.mdl_cb.cb_rx = mm_gens_loc_cb_rx;
p_env_locs->env.mdl_cb.cb_opcode_check = mm_gens_loc_cb_opcode_check;
// Link environment
p_env_locs->p_env_loc = p_env_loc;
// Inform application about registered model
mm_register_ind_send(MM_ID_GENS_LOCS, elmt_idx, locs_lid);
}
}
}
return (mdl_lid);
}
void mm_gens_locg_cfm(uint8_t elmt_idx, uint8_t status, int32_t latitude,
int32_t longitude, int16_t altitude)
{
// Look for Generic Location Server model in the list of models
m_lid_t mdl_lid = mm_state_get_lid(elmt_idx, MM_ID_GENS_LOC);
if (mdl_lid != MESH_INVALID_LID)
{
mm_gens_loc_env_t *p_env_loc = (mm_gens_loc_env_t *)mm_state_get_env(mdl_lid);
// Check if confirmation from application was expected
if (GETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_GLOB))
{
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_GLOB, 0);
if (status != MESH_ERR_NO_ERROR)
{
latitude = MM_LOC_GLOBAL_LAT_NOT_CONFIG;
longitude = MM_LOC_GLOBAL_LONG_NOT_CONFIG;
altitude = MM_LOC_GLOBAL_ALT_NOT_CONFIG;
}
// Send responses for received get requests
while (!list_is_empty(&p_env_loc->list_status_glob))
{
mesh_buf_t *p_buf = (mesh_buf_t *)list_pop_front(&p_env_loc->list_status_glob);
mm_gens_loc_send_status_global(p_env_loc, p_buf, NULL,
latitude, longitude, altitude);
}
// Send a publication if needed
if (GETB(p_env_loc->env.info, MM_GENS_LOC_INFO_PUBLI_GLOB))
{
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_PUBLI_GLOB, 0);
mm_gens_loc_send_status_global(p_env_loc, NULL, NULL,
latitude, longitude, altitude);
}
}
}
}
void mm_gens_locl_cfm(uint8_t elmt_idx, uint8_t status, int16_t north,
int16_t east, int16_t altitude, uint8_t floor, uint16_t uncertainty)
{
// Look for Generic Location Server model in the list of models
m_lid_t mdl_lid = mm_state_get_lid(elmt_idx, MM_ID_GENS_LOC);
if (mdl_lid != MESH_INVALID_LID)
{
mm_gens_loc_env_t *p_env_loc = (mm_gens_loc_env_t *)mm_state_get_env(mdl_lid);
// Check if confirmation from application was expected
if (GETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_LOC))
{
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_WAIT_APP_LOC, 0);
if (status != MESH_ERR_NO_ERROR)
{
north = MM_LOC_LOCAL_NORTH_NOT_CONFIG;
east = MM_LOC_LOCAL_EAST_NOT_CONFIG;
altitude = MM_LOC_LOCAL_ALT_NOT_CONFIG;
floor = MM_LOC_FLOOR_NOT_CONFIG;
uncertainty = 0;
}
// Send responses for received get requests
while (!list_is_empty(&p_env_loc->list_status_loc))
{
mesh_buf_t *p_buf = (mesh_buf_t *)list_pop_front(&p_env_loc->list_status_loc);
mm_gens_loc_send_status_local(p_env_loc, p_buf, NULL,
north, east, altitude, floor, uncertainty);
}
// Send a publication if needed
if (GETB(p_env_loc->env.info, MM_GENS_LOC_INFO_PUBLI_LOC))
{
SETB(p_env_loc->env.info, MM_GENS_LOC_INFO_PUBLI_LOC, 0);
mm_gens_loc_send_status_local(p_env_loc, NULL, NULL,
north, east, altitude, floor, uncertainty);
}
}
}
}
/// @} end of group