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

962 lines
33 KiB
C

/**
****************************************************************************************
* @file mm_gens_lvl.c
*
* @brief Mesh Model Generic Level Server Module
*
****************************************************************************************
*/
/**
****************************************************************************************
* @addtogroup MM_GENS_LVL
* @{
****************************************************************************************
*/
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "mm_itf.h"
#include "mm_gens.h"
/*
* DEFINES
****************************************************************************************
*/
/// Upper limit of Generic Level State when no model is bound (signed 16-bit integer)
#define MM_GENS_LVL_UPPER_LIMIT (32767)
/// Lower limit of Generic Level State when no model is bound (signed 16-bit integer)
#define MM_GENS_LVL_LOWER_LIMIT (-32768)
/// Validity of information provided to the Replay Manager
#define MM_GENS_LVL_REPLAY_MS (6000)
/*
* TYPE DEFINITIONS
****************************************************************************************
*/
/// Information for handling of move transition
typedef struct mm_gens_lvl_move_param
{
/// Received delta value
int16_t delta;
/// Received transition time
uint8_t trans_time;
} mm_gens_lvl_move_param_t;
/// Information for handling of delta transitions
typedef struct mm_gens_lvl_delta_param
{
/// Source address
uint16_t src;
/// TID
uint8_t tid;
} mm_gens_lvl_delta_param_t;
/// Structure for Generic Level server model environment
typedef struct mm_gens_lvl_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 in milliseconds
uint32_t publi_period_ms;
/// Environment for replay protection mechanism
mm_replay_env_t replay_env;
/// Parameters for a move transition
mm_gens_lvl_move_param_t move_param;
/// Parameters for a delta transition
mm_gens_lvl_delta_param_t delta_param;
union
{
/// Initial level in case of a delta transition
int16_t init_level;
/// Target level in case of move transition
int16_t tgt_move_level;
} u;
/// Current level
int16_t level;
/// Target Level
int16_t tgt_level;
/// Source address of set message that has triggered last or current transition
uint8_t status_dst_addr;
/// Application key local index to be used for transmission of Generic Level Status message
m_lid_t status_app_key_lid;
/// Relaying of sent Generic Level Status authorized
bool status_relay;
} mm_gens_lvl_env_t;
/*
* LOCAL FUNCTIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Compute target level when delta value is applied for a delta transition
*
* @param[in] p_env_lvl Pointer to Generic Level Server model environment
* @param[in] delta Delta value
*
* @return Computed target level
****************************************************************************************
*/
__STATIC int16_t mm_gens_lvl_compute_tgt_delta(mm_gens_lvl_env_t *p_env_lvl, int32_t delta)
{
// Target level
int32_t tgt_level = p_env_lvl->u.init_level;
tgt_level += delta;
if (tgt_level > MM_GENS_LVL_UPPER_LIMIT)
{
tgt_level = MM_GENS_LVL_UPPER_LIMIT;
}
else if (tgt_level < MM_GENS_LVL_LOWER_LIMIT)
{
tgt_level = MM_GENS_LVL_LOWER_LIMIT;
}
return ((int16_t)tgt_level);
}
/**
****************************************************************************************
* @brief Compute target level when delta value is applied for a move transition
*
* @param[in] p_env_lvl Pointer to Generic Level Server model environment
* @param[in] delta Delta value
*
* @return Computed target level
****************************************************************************************
*/
__STATIC int16_t mm_gens_lvl_compute_tgt_move(mm_gens_lvl_env_t *p_env_lvl)
{
// Target level
int32_t tgt_level = p_env_lvl->level;
tgt_level += p_env_lvl->move_param.delta;
if (tgt_level > MM_GENS_LVL_UPPER_LIMIT)
{
tgt_level = MM_GENS_LVL_UPPER_LIMIT;
}
else if (tgt_level < MM_GENS_LVL_LOWER_LIMIT)
{
tgt_level = MM_GENS_LVL_LOWER_LIMIT;
}
return ((int16_t)tgt_level);
}
/**
****************************************************************************************
* @brief Prepare and send a Generic Level Status message
*
* @param[in] p_env_lvl Pointer to Generic Level Server model environment
* @param[in] p_route_env Pointer to structure containing reception information provided
* by Mesh Profile for received request message
* @param[in] publish Indicate if message is sent as a publication (true) or as
* a response to a received request (false)
****************************************************************************************
*/
__STATIC void mm_gens_lvl_send_status(mm_gens_lvl_env_t *p_env_lvl, mm_route_env_t *p_route_env,
bool publish)
{
// Pointer to the buffer that will contain the message
mesh_buf_t *p_buf_status;
// Remaining time
uint8_t rem_time;
// Transition type
uint8_t trans_type;
// Data length
uint8_t data_length;
// Check if a transition has been started
mm_bind_get_trans_info(p_env_lvl->env.grp_lid, &trans_type, &rem_time);
// Deduce deduce data length
data_length = (trans_type != MM_TRANS_TYPE_NONE)
? MM_GEN_LVL_STATUS_LEN : MM_GEN_LVL_STATUS_MIN_LEN;
p_buf_status = mm_route_buf_alloc(data_length);
if (p_buf_status)
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf_status);
// Get pointer to environment
mm_route_env_t *p_buf_env = (mm_route_env_t *)&p_buf_status->env;
// Prepare environment
if (p_route_env)
{
memcpy(p_buf_env, p_route_env, sizeof(mm_route_env_t));
}
else if (!publish)
{
p_buf_env->app_key_lid = p_env_lvl->status_app_key_lid;
p_buf_env->u_addr.dst = p_env_lvl->status_dst_addr;
SETB(p_buf_env->info, MM_ROUTE_INFO_RELAY, p_env_lvl->status_relay);
}
SETB(p_buf_env->info, MM_ROUTE_INFO_RX, 0);
SETB(p_buf_env->info, MM_ROUTE_INFO_PUBLISH, publish);
p_buf_env->mdl_lid = p_env_lvl->env.mdl_lid;
p_buf_env->opcode = MM_MSG_GEN_LVL_STATUS;
// Fill the message
write16p(p_data + MM_GEN_LVL_STATUS_LVL_POS, p_env_lvl->level);
if (data_length == MM_GEN_LVL_STATUS_LEN)
{
// Targeted level
int16_t tgt_level;
if (trans_type == MM_TRANS_TYPE_MOVE)
{
rem_time = MM_TRANS_TIME_UNKNOWN;
tgt_level = p_env_lvl->u.tgt_move_level;
}
else
{
tgt_level = p_env_lvl->tgt_level;
}
write16p(p_data + MM_GEN_LVL_STATUS_TGT_LVL_POS, tgt_level);
*(p_data + MM_GEN_LVL_STATUS_REM_TIME_POS) = rem_time;
}
// Send the message
mm_route_send(p_buf_status);
}
}
/**
****************************************************************************************
* @brief Publish Generic Level state value if sending of publications is enabled
*
* @param[in] p_env_lvl Pointer to Generic Level Server model environment
****************************************************************************************
*/
__STATIC void mm_gens_lvl_publish(mm_gens_lvl_env_t *p_env_lvl)
{
// Check if sending of publication is enabled
if (GETB(p_env_lvl->env.info, MM_INFO_PUBLI))
{
mm_gens_lvl_send_status(p_env_lvl, NULL, true);
}
}
/**
****************************************************************************************
* @brief Check if a Generic Level Status message must be sent and send it if it
* is the case
*
* @param[in] p_env_lvl Pointer to Generic Level Server model environment
****************************************************************************************
*/
__STATIC void mm_gens_lvl_check_status_rsp(mm_gens_lvl_env_t *p_env_lvl)
{
if (p_env_lvl->status_dst_addr)
{
// Send a response to the node that has required the transition
mm_gens_lvl_send_status(p_env_lvl, NULL, false);
p_env_lvl->status_dst_addr = MESH_UNASSIGNED_ADDR;
}
}
/**
****************************************************************************************
* @brief Check if a transaction initiated by a peer node is a new transaction or continuation
* of an already started one
*
* @param[in] p_env_lvl Pointer to Generic Level Server model environment
* @param[in] src Source address of received Generic Delta Set/Set Unacknowledged
* message
* @param[in] tid Received transaction identifier
****************************************************************************************
*/
__STATIC bool mm_gens_lvl_is_new_transaction(mm_gens_lvl_env_t *p_env_lvl, uint16_t src, uint8_t tid)
{
// New transaction or not
bool new_transaction = true;
// Check if the SRC/TID couple has already been received in the last 6 seconds
if (mm_replay_is_retx(&p_env_lvl->replay_env, src, tid))
{
if ((src == p_env_lvl->delta_param.src)
&& (tid == p_env_lvl->delta_param.tid))
{
new_transaction = false;
}
}
return (new_transaction);
}
/*
* MESSAGE HANDLERS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Handler for Generic Level Set/Set Unacknowledged message
*
* @param[in] p_env Pointer to environment of model for which message has been received
* @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 bool mm_gens_lvl_handler_set(mm_gens_lvl_env_t *p_env_lvl, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env)
{
// Boolean indicating if Generic Level Status can be sent now
bool send_status = (p_route_env->opcode == MM_MSG_GEN_LVL_SET);
do
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf);
// Extract required Generic Level state value
int16_t level = read16p(p_data + MM_GEN_LVL_SET_LVL_POS);
// Extract TID value
uint8_t tid = *(p_data + MM_GEN_LVL_SET_TID_POS);
// Transition time
uint8_t trans_time = MM_TRANS_TIME_UNKNOWN;
// Delay
uint8_t delay = 0;
// Extract optional parameters if present
if (p_buf->data_len == MM_GEN_LVL_SET_LEN)
{
trans_time = (uint16_t)(*(p_data + MM_GEN_LVL_SET_TRANS_TIME_POS));
// Check received value
if (GETF(trans_time, MM_TRANS_TIME_STEP_NB) > MM_TRANS_TIME_STEPS_MAX)
{
// Drop the message
send_status = false;
break;
}
delay = *(p_data + MM_GEN_LVL_SET_DELAY_POS);
}
// Check if received message is a retransmitted one, if state is modified and if
// a new transition can be started now
if ((p_env_lvl->status_dst_addr != MESH_UNASSIGNED_ADDR)
|| mm_replay_is_retx(&p_env_lvl->replay_env, p_route_env->u_addr.src, tid)
|| (level == p_env_lvl->level))
{
if (send_status)
{
// Send Generic Level status message
mm_gens_lvl_send_status(p_env_lvl, p_route_env, false);
}
break;
}
// Keep information for transmission of status if needed
if (send_status)
{
// Keep transaction information
p_env_lvl->status_dst_addr = p_route_env->u_addr.src;
p_env_lvl->status_app_key_lid = p_route_env->app_key_lid;
p_env_lvl->status_relay = GETB(p_route_env->info, MM_ROUTE_INFO_RELAY);
// Delay status transmission
send_status = false;
}
if (GETB(p_env_lvl->env.info, MM_INFO_MAIN))
{
// Update target state
p_env_lvl->tgt_level = level;
// Inform the Binding Manager about new transition
mm_bind_trans_new(p_env_lvl->env.grp_lid, MM_TRANS_TYPE_CLASSIC,
trans_time, delay);
}
else
{
// Inform the Binding Manager
mm_bind_trans_req(p_env_lvl->env.grp_lid, p_env_lvl->env.mdl_lid,
MM_TRANS_TYPE_CLASSIC, level, trans_time, delay);
}
} while (0);
return (send_status);
}
/**
****************************************************************************************
* @brief Handler for Generic Delta Set/Set Unacknowledged message
*
* @param[in] p_env Pointer to environment of model for which message has been received
* @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 bool mm_gens_lvl_handler_set_delta(mm_gens_lvl_env_t *p_env_lvl, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env)
{
// Boolean indicating if Generic Level Status can be sent now
bool send_status = (p_route_env->opcode == MM_MSG_GEN_DELTA_SET);
do
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf);
// Extract required delta value
int32_t delta = (int32_t)read32p(p_data + MM_GEN_LVL_SET_DELTA_LVL_POS);
// Extract TID value
uint8_t tid = *(p_data + MM_GEN_LVL_SET_DELTA_TID_POS);
// Transition time
uint8_t trans_time = MM_TRANS_TIME_UNKNOWN;
// Delay
uint8_t delay = 0;
// Indicate if transaction is a new one
uint8_t new_transaction;
// Extract optional value if present
if (p_buf->data_len == MM_GEN_LVL_SET_DELTA_LEN)
{
trans_time = (uint16_t)(*(p_data + MM_GEN_LVL_SET_DELTA_TRANS_TIME_POS));
// Check received value
if (GETF(trans_time, MM_TRANS_TIME_STEP_NB) > MM_TRANS_TIME_STEPS_MAX)
{
// Drop the message
send_status = false;
break;
}
delay = *(p_data + MM_GEN_LVL_SET_DELTA_DELAY_POS);
}
if (delta == 0)
{
break;
}
// Check if transaction is a new transaction or if a new one must be started
new_transaction = mm_gens_lvl_is_new_transaction(p_env_lvl, p_route_env->u_addr.src, tid);
// Keep information for transmission of status if needed
if (send_status)
{
p_env_lvl->status_dst_addr = p_route_env->u_addr.src;
p_env_lvl->status_app_key_lid = p_route_env->app_key_lid;
p_env_lvl->status_relay = GETB(p_route_env->info, MM_ROUTE_INFO_RELAY);
send_status = false;
}
p_env_lvl->delta_param.src = p_route_env->u_addr.src;
p_env_lvl->delta_param.tid = tid;
if (GETB(p_env_lvl->env.info, MM_INFO_MAIN))
{
// If transition is a new transition, keep the current level
if (new_transaction)
{
p_env_lvl->u.init_level = p_env_lvl->level;
}
// Update target state
p_env_lvl->tgt_level = mm_gens_lvl_compute_tgt_delta(p_env_lvl, delta);
// Inform the Binding Manager about new transition
mm_bind_trans_new(p_env_lvl->env.grp_lid, MM_TRANS_TYPE_DELTA,
trans_time, delay);
}
else
{
// Inform the Binding Manager
mm_bind_trans_req(p_env_lvl->env.grp_lid, p_env_lvl->env.mdl_lid,
MM_TRANS_TYPE_DELTA, delta, trans_time, delay);
}
} while (0);
return (send_status);
}
/**
****************************************************************************************
* @brief Handler for Generic Move Set/Set Unacknowledged message
*
* @param[in] p_env Pointer to environment of model for which message has been received
* @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 bool mm_gens_lvl_handler_set_move(mm_gens_lvl_env_t *p_env_lvl, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env)
{
// Boolean indicating if Generic Level Status can be sent now
bool send_status = (p_route_env->opcode == MM_MSG_GEN_MOVE_SET);
do
{
// Get pointer to data
uint8_t *p_data = MESH_BUF_DATA(p_buf);
// Extract required delta value
int16_t delta = (int16_t)read16p(p_data + MM_GEN_LVL_SET_MOVE_DELTA_LVL_POS);
// Extract TID value
uint8_t tid = *(p_data + MM_GEN_LVL_SET_MOVE_TID_POS);
// Transition time
uint8_t trans_time = MM_TRANS_TIME_UNKNOWN;
// Delay
uint8_t delay = 0;
// Extract and check optional parameters if present
if (p_buf->data_len == MM_GEN_LVL_SET_MOVE_LEN)
{
trans_time = (uint16_t)(*(p_data + MM_GEN_LVL_SET_MOVE_TRANS_TIME_POS));
// Check received value
if (GETF(trans_time, MM_TRANS_TIME_STEP_NB) > MM_TRANS_TIME_STEPS_MAX)
{
// Drop the message
send_status = false;
break;
}
delay = *(p_data + MM_GEN_LVL_SET_MOVE_DELAY_POS);
}
// Check if received message is a retransmitted one, if state is modified and if
// a new transition can be started now
if ((p_env_lvl->status_dst_addr != MESH_UNASSIGNED_ADDR)
|| mm_replay_is_retx(&p_env_lvl->replay_env, p_route_env->u_addr.src, tid))
{
if (send_status)
{
// Send Generic Level status message
mm_gens_lvl_send_status(p_env_lvl, p_route_env, false);
}
break;
}
// Keep information for transmission of status if needed
if (send_status)
{
p_env_lvl->status_dst_addr = p_route_env->u_addr.src;
p_env_lvl->status_app_key_lid = p_route_env->app_key_lid;
p_env_lvl->status_relay = GETB(p_route_env->info, MM_ROUTE_INFO_RELAY);
send_status = false;
}
p_env_lvl->move_param.delta = delta;
p_env_lvl->move_param.trans_time = trans_time;
if (GETB(p_env_lvl->env.info, MM_INFO_MAIN))
{
if (delta != 0)
{
// Move target level
int16_t tgt_move_level = (delta > 0)
? MM_GENS_LVL_UPPER_LIMIT : MM_GENS_LVL_LOWER_LIMIT;
if (p_env_lvl->level != p_env_lvl->u.tgt_move_level)
{
// Update target state
p_env_lvl->u.tgt_move_level = tgt_move_level;
p_env_lvl->tgt_level = p_env_lvl->level + delta;
// Inform the Binding Manager about new transition
if (mm_bind_trans_new(p_env_lvl->env.grp_lid, MM_TRANS_TYPE_MOVE,
trans_time, delay) == MESH_ERR_NO_ERROR)
{
break;
}
}
send_status = (p_route_env->opcode == MM_MSG_GEN_MOVE_SET);
p_env_lvl->status_dst_addr = MESH_UNASSIGNED_ADDR;
}
}
else
{
// Inform the Binding Manager
mm_bind_trans_req(p_env_lvl->env.grp_lid, p_env_lvl->env.mdl_lid,
MM_TRANS_TYPE_MOVE, delta, trans_time, delay);
}
} while (0);
return (send_status);
}
/*
* INTERNAL CALLBACK FUNCTIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Callback function called when timer monitoring publication duration for
* Generic Level Server model expires
*
* @param[in] p_env Pointer to model environment for Generic Level Server model
****************************************************************************************
*/
__STATIC void mm_gens_lvl_cb_tmr_publi(void *p_tmr)
{
// Get allocated environment
mm_gens_lvl_env_t *p_env_lvl = MESH_TMR2ENV(p_tmr, mm_gens_lvl_env_t, tmr_publi);
if (p_env_lvl->publi_period_ms)
{
// Publish a Generic Level Status message
mm_gens_lvl_publish(p_env_lvl);
// Restart the timer
mesh_timer_set(&p_env_lvl->tmr_publi, p_env_lvl->publi_period_ms);
}
}
/**
****************************************************************************************
* @brief Inform Generic Level Server model about a received message
*
* @param[in] p_env Pointer to the environment allocated for the Generic Level
* 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_lvl_cb_rx(mm_mdl_env_t *p_env, mesh_buf_t *p_buf,
mm_route_env_t *p_route_env)
{
// Boolean indicating if Generic Level Status message can be sent now
bool send_status;
// Cast the provided environment structure
mm_gens_lvl_env_t *p_env_lvl = (mm_gens_lvl_env_t *)p_env;
switch (p_route_env->opcode)
{
case (MM_MSG_GEN_LVL_SET):
case (MM_MSG_GEN_LVL_SET_UNACK):
{
send_status = mm_gens_lvl_handler_set(p_env_lvl, p_buf, p_route_env);
} break;
case (MM_MSG_GEN_DELTA_SET):
case (MM_MSG_GEN_DELTA_SET_UNACK):
{
send_status = mm_gens_lvl_handler_set_delta(p_env_lvl, p_buf, p_route_env);
} break;
case (MM_MSG_GEN_MOVE_SET):
case (MM_MSG_GEN_MOVE_SET_UNACK):
{
send_status = mm_gens_lvl_handler_set_move(p_env_lvl, p_buf, p_route_env);
} break;
case (MM_MSG_GEN_LVL_GET):
{
send_status = true;
} break;
default:
{
send_status = false;
} break;
}
if (send_status)
{
// Send a Generic Level Status message
mm_gens_lvl_send_status(p_env_lvl, p_route_env, false);
}
}
/**
****************************************************************************************
* @brief Check if a given opcode is handled by the Generic Level Server model
*
* @param[in] p_env Pointer to the environment allocated for the Generic Level
* Server model
* @param[in] opcode Opcode to check
*
* @return An error status (@see enum mesh_err)
****************************************************************************************
*/
__STATIC uint8_t mm_gens_lvl_cb_opcode_check(mm_mdl_env_t *p_env, uint32_t opcode)
{
uint8_t status;
if ((opcode == MM_MSG_GEN_LVL_GET)
|| (opcode == MM_MSG_GEN_LVL_SET)
|| (opcode == MM_MSG_GEN_LVL_SET_UNACK)
|| (opcode == MM_MSG_GEN_DELTA_SET)
|| (opcode == MM_MSG_GEN_DELTA_SET_UNACK)
|| (opcode == MM_MSG_GEN_MOVE_SET)
|| (opcode == MM_MSG_GEN_MOVE_SET_UNACK)
)
{
status = MESH_ERR_NO_ERROR;
}
else
{
status = MESH_ERR_MDL_INVALID_OPCODE;
}
return (status);
}
/**
****************************************************************************************
* @brief Set Generic Level state value
*
* @param[in] p_env Pointer the the environment allocated for the Generic Level
* Server model
* @param[in] level Generic Level state value
*
* @return An error status (@see enum mesh_err)
****************************************************************************************
*/
__STATIC uint8_t mm_gens_lvl_cb_set(mm_mdl_env_t *p_env, uint16_t state_id, uint32_t state)
{
// Returned status
uint8_t status = MESH_ERR_NO_ERROR;
if (GETB(p_env->info, MM_INFO_MAIN))
{
// Get environment for the Generic Level Server model
mm_gens_lvl_env_t *p_env_lvl = (mm_gens_lvl_env_t *)p_env;
// Set state value
p_env_lvl->level = state;
}
else
{
status = MESH_ERR_COMMAND_DISALLOWED;
}
return (status);
}
/*
* CALLBACK FUNCTIONS FOR BINDING MANAGER
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Callback function provided to the Binding Manager so that Generic Level Server
* model can be informed about group event
*
* @param[in] mdl_lid Model Local Index
* @param[in] event Event
* @param[in] info Information (depends on the event type)
****************************************************************************************
*/
__STATIC void mm_gens_lvl_cb_grp_event(m_lid_t mdl_lid, uint8_t event, uint8_t info)
{
// Get environment for Generic Level Server model
mm_gens_lvl_env_t *p_env_lvl = (mm_gens_lvl_env_t *)mm_state_get_env(mdl_lid);
switch (event)
{
case (MM_GRP_EVENT_TRANS_REJECTED):
{
// Send Generic Level Status message
mm_gens_lvl_check_status_rsp(p_env_lvl);
} break;
case (MM_GRP_EVENT_TRANS_DELAY_EXPIRED):
{
// Start the transition
mm_bind_trans_start(p_env_lvl->env.grp_lid);
} break;
case (MM_GRP_EVENT_TRANS_IMMEDIATE):
{
p_env_lvl->level = p_env_lvl->tgt_level;
} // no break;
case (MM_GRP_EVENT_TRANS_STARTED):
{
// Inform application about the update
if (GETB(p_env_lvl->env.info, MM_INFO_MAIN))
{
uint8_t trans_time = info;
// Inform application about state update
mm_srv_state_upd_ind_send(MM_STATE_GEN_LVL, p_env_lvl->env.elmt_idx,
(uint16_t)p_env_lvl->tgt_level,
(trans_time) ? mm_get_trans_time_ms(trans_time) : 0);
}
// Check if a Generic Level Status message must be sent
mm_gens_lvl_check_status_rsp(p_env_lvl);
// Send a publication
mm_gens_lvl_publish(p_env_lvl);
} break;
case (MM_GRP_EVENT_TRANS_END):
{
// Transition type
uint8_t trans_type = info;
// Update current level value
p_env_lvl->level = p_env_lvl->tgt_level;
// Inform application about the update
if (GETB(p_env_lvl->env.info, MM_INFO_MAIN))
{
// Inform application about state update
mm_srv_state_upd_ind_send(MM_STATE_GEN_LVL, p_env_lvl->env.elmt_idx,
(uint16_t)p_env_lvl->level, 0);;
}
// Send a publication
mm_gens_lvl_publish(p_env_lvl);
// Check transition type
if (trans_type == MM_TRANS_TYPE_MOVE)
{
// Continue transition to the target state
if (GETB(p_env_lvl->env.info, MM_INFO_MAIN))
{
// Check if target level has been reached
if (p_env_lvl->level != p_env_lvl->u.tgt_move_level)
{
// Update target level
p_env_lvl->tgt_level = mm_gens_lvl_compute_tgt_move(p_env_lvl);
// Inform the Binding Manager about new transition
mm_bind_trans_new(p_env_lvl->env.grp_lid, MM_TRANS_TYPE_MOVE,
p_env_lvl->move_param.trans_time, 0);
}
}
else
{
// Inform the Binding Manager
mm_bind_trans_req(p_env_lvl->env.grp_lid, p_env_lvl->env.mdl_lid,
MM_TRANS_TYPE_MOVE, p_env_lvl->move_param.delta,
p_env_lvl->move_param.trans_time, 0);
}
}
} break;
// case (MM_GRP_EVENT_TRANS_ABORTED):
// case (MM_GRP_EVENT_GROUP_FULL):
default:
{
} break;
}
}
/**
****************************************************************************************
* @brief Callback function provided to the Binding Manager so that Generic Level state
* value can be set by main model of the group
*
* @param[in] mdl_lid Model Local Index
* @param[in] type Type
* @param[in] state State value
****************************************************************************************
*/
__STATIC void mm_gens_lvl_cb_set_state(m_lid_t mdl_lid, uint8_t type, uint32_t state)
{
// Get environment for Generic Level Server model
mm_gens_lvl_env_t *p_env_lvl = (mm_gens_lvl_env_t *)mm_state_get_env(mdl_lid);
// Sanity check
ASSERT_INFO(!GETB(p_env_lvl->env.info, MM_INFO_MAIN), mdl_lid, 0);
if (type == MM_STATE_TYPE_CURRENT)
{
p_env_lvl->level = (int16_t)state;
}
else if (type == MM_STATE_TYPE_TARGET)
{
p_env_lvl->tgt_level = (int16_t)state;
}
else // (type == MM_STATE_TYPE_TARGET_MOVE)
{
p_env_lvl->u.tgt_move_level = (int16_t)state;
}
}
/*
* GLOBAL FUNCTIONS
****************************************************************************************
*/
m_lid_t mm_gens_lvl_register(uint8_t elmt_idx, bool main)
{
//uint8_t status = MESH_ERR_COMMAND_DISALLOWED;
// Register the model
m_lid_t mdl_lid = ms_register_model(MM_ID_GENS_LVL, elmt_idx, MM_CFG_PUBLI_AUTH_BIT);
if (mdl_lid != MESH_INVALID_LID) //if (status == MESH_ERR_NO_ERROR)
{
// Inform the Model State Manager about registered model
mm_gens_lvl_env_t *p_env_lvl = (mm_gens_lvl_env_t *)mm_state_register(elmt_idx, MM_ID_GENS_LVL, mdl_lid,
MM_ROLE_SRV_PUBLI, sizeof(mm_gens_lvl_env_t));
if (p_env_lvl)
{
// Get server-specific callback functions
//mm_srv_cb_t *p_cb_srv = p_env_lvl->env.cb.u.p_cb_srv;
// Prepare timer for publications
p_env_lvl->tmr_publi.cb = mm_gens_lvl_cb_tmr_publi;
//p_env_lvl->tmr_publi.p_env = (void *)p_env_lvl;
// Prepare environment for Replay Manager
p_env_lvl->replay_env.delay_ms = MM_GENS_LVL_REPLAY_MS;
// Set internal callback functions
p_env_lvl->env.mdl_cb.cb_rx = mm_gens_lvl_cb_rx;
p_env_lvl->env.mdl_cb.cb_opcode_check = mm_gens_lvl_cb_opcode_check;
//p_env_lvl->env.mdl_cb.cb_publish_param = mm_gens_lvl_cb_publish_param;
//p_cb_srv->cb_set = mm_gens_lvl_cb_set;
p_env_lvl->env.mdl_cb.cb_srv_set = mm_gens_lvl_cb_set;
if (main)
{
// Create group
m_lid_t grp_lid = mm_bind_add_group(0, elmt_idx, mdl_lid,
mm_gens_lvl_cb_grp_event, NULL);
}
//status = MESH_ERR_NO_ERROR;
// Inform application about registered model
mm_register_ind_send(MM_ID_GENS_LVL, elmt_idx, mdl_lid);
}
}
return (mdl_lid);
}
uint8_t mm_gens_lvl_bind_group(m_lid_t grp_lid, m_lid_t lvl_lid)
{
return mm_bind_group_add_mdl(grp_lid, lvl_lid, MM_ID_GENS_LVL,
mm_gens_lvl_cb_grp_event,
mm_gens_lvl_cb_set_state);
}
/// @} end of group