1887 lines
70 KiB
C
1887 lines
70 KiB
C
/**
|
|
****************************************************************************************
|
|
* @file mm_lights_ctl.c
|
|
*
|
|
* @brief Mesh Model Light CTL Server Module
|
|
*
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @addtogroup MM_LIGHTS_CTL
|
|
* @{
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* INCLUDE FILES
|
|
****************************************************************************************
|
|
*/
|
|
|
|
#include "mm_itf.h"
|
|
#include "mm_gens.h"
|
|
#include "mm_lights.h"
|
|
|
|
/*
|
|
* DEFINES
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/// Validity of information provided to the Replay Manager
|
|
#define MM_LIGHTS_CTL_REPLAY_MS (6000)
|
|
/// Minimum value for Light CTL Temperature state value
|
|
#define MM_LIGHTS_CTL_TEMP_MIN (0x0320)
|
|
/// Maximum value for Light CTL Temperature state value
|
|
#define MM_LIGHTS_CTL_TEMP_MAX (0x4E20)
|
|
|
|
/*
|
|
* ENUMERATIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/// Bit field content for status_info value present in environment for Light CTL Server model
|
|
/// 7 6 5 4 3 2 1 0
|
|
/// +------------+-----------+----------+-------------+-----------+----------+---------+-------+
|
|
/// | Trans Temp | Trans DUV | Trans LN | Temp Status | Wait Temp | Wait DUV | Wait LN | Relay |
|
|
/// +------------+-----------+----------+-------------+-----------+----------+---------+-------+
|
|
enum mm_lights_ctl_sinfo_bf
|
|
{
|
|
/// Relaying of sent status message is authorized
|
|
MM_LIGHTS_CTL_SINFO_RELAY_POS = 0,
|
|
MM_LIGHTS_CTL_SINFO_RELAY_BIT = (1 << MM_LIGHTS_CTL_SINFO_RELAY_POS),
|
|
|
|
/// Wait for transition event for Light CTL Lightness state
|
|
MM_LIGHTS_CTL_SINFO_WAIT_LN_POS = 1,
|
|
MM_LIGHTS_CTL_SINFO_WAIT_LN_BIT = (1 << MM_LIGHTS_CTL_SINFO_WAIT_LN_POS),
|
|
|
|
/// Wait for transition event for Light CTL Delta UV state
|
|
MM_LIGHTS_CTL_SINFO_WAIT_DUV_POS = 2,
|
|
MM_LIGHTS_CTL_SINFO_WAIT_DUV_BIT = (1 << MM_LIGHTS_CTL_SINFO_WAIT_DUV_POS),
|
|
|
|
/// Wait for transition event for Light CTL Temperature state
|
|
MM_LIGHTS_CTL_SINFO_WAIT_TEMP_POS = 3,
|
|
MM_LIGHTS_CTL_SINFO_WAIT_TEMP_BIT = (1 << MM_LIGHTS_CTL_SINFO_WAIT_TEMP_POS),
|
|
|
|
/// Wait for transition event mask
|
|
MM_LIGHTS_CTL_SINFO_WAIT_LSB = 1,
|
|
MM_LIGHTS_CTL_SINFO_WAIT_MASK = 0x0E,
|
|
|
|
/// Indicate if Light CTL Status (0) or Light CTL Temperature Status message must be sent
|
|
MM_LIGHTS_CTL_SINFO_TEMP_STATUS_POS = 4,
|
|
MM_LIGHTS_CTL_SINFO_TEMP_STATUS_BIT = (1 << MM_LIGHTS_CTL_SINFO_TEMP_STATUS_POS),
|
|
|
|
/// Transition for Light CTL Lightness state in progress
|
|
MM_LIGHTS_CTL_SINFO_TRANS_LN_POS = 5,
|
|
MM_LIGHTS_CTL_SINFO_TRANS_LN_BIT = (1 << MM_LIGHTS_CTL_SINFO_TRANS_LN_POS),
|
|
|
|
/// Transition for Light CTL Delta UV state in progress
|
|
MM_LIGHTS_CTL_SINFO_TRANS_DUV_POS = 6,
|
|
MM_LIGHTS_CTL_SINFO_TRANS_DUV_BIT = (1 << MM_LIGHTS_CTL_SINFO_TRANS_DUV_POS),
|
|
|
|
/// Transition for Light CTL Temperature in progress
|
|
MM_LIGHTS_CTL_SINFO_TRANS_TEMP_POS = 7,
|
|
MM_LIGHTS_CTL_SINFO_TRANS_TEMP_BIT = (1 << MM_LIGHTS_CTL_SINFO_TRANS_TEMP_POS),
|
|
|
|
/// Transition in progress mask
|
|
MM_LIGHTS_CTL_SINFO_TRANS_LSB = 5,
|
|
MM_LIGHTS_CTL_SINFO_TRANS_MASK = 0xE0,
|
|
};
|
|
|
|
/*
|
|
* TYPE DEFINITIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
typedef struct mm_lights_ctl_env mm_lights_ctl_env_t;
|
|
typedef struct mm_lights_ctls_env mm_lights_ctls_env_t;
|
|
typedef struct mm_lights_ctlt_env mm_lights_ctlt_env_t;
|
|
|
|
/// Structure for Light CTL Server model environment
|
|
struct mm_lights_ctl_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;
|
|
|
|
/// Pointer to environment of associated Light CTL Temperature model
|
|
mm_lights_ctlt_env_t *p_env_ctlt;
|
|
|
|
/// Delta value in case of move transition for Light CTL Lightness state value
|
|
int16_t move_delta;
|
|
/// Light CTL Lightness state value
|
|
uint16_t ln;
|
|
/// Target Light CTL Lightness state value
|
|
uint16_t ln_tgt;
|
|
/// Light CTL Delta UV state value
|
|
int16_t delta_uv;
|
|
/// Target Light CTL Delta UV state value
|
|
int16_t delta_uv_tgt;
|
|
/// Light CTL Delta Default state value
|
|
int16_t delta_uv_dflt;
|
|
|
|
/// 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 Light CTL Status
|
|
/// or Light CTL Linear Status message
|
|
m_lid_t status_app_key_lid;
|
|
/// Status information bitfield (@see enum mm_lights_ctl_sinfo_bf)
|
|
uint8_t status_info;
|
|
};
|
|
|
|
/// Structure for Light CTL Setup Server model environment
|
|
struct mm_lights_ctls_env
|
|
{
|
|
/// Basic model environment - Must be first element in the structure - DO NOT MOVE
|
|
mm_mdl_env_t env;
|
|
|
|
/// Pointer to environment of associated Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl;
|
|
};
|
|
|
|
/// Structure for Light CTL Temperature Server model environment
|
|
struct mm_lights_ctlt_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;
|
|
|
|
/// Pointer to environment of associated Light CTL Temperature model
|
|
mm_lights_ctl_env_t *p_env_ctl;
|
|
|
|
/// Delta value in case of move transition for Light CTL Temperature state value
|
|
int16_t move_delta;
|
|
/// Light CTL Temperature
|
|
uint16_t temp;
|
|
/// Target Light CTL Temperature
|
|
uint16_t temp_tgt;
|
|
/// Target Generic Level value - Keep it in order to not accumulate error due to division
|
|
int16_t lvl_tgt;
|
|
/// Light CTL Temperature Default
|
|
uint16_t temp_dflt;
|
|
/// Light CTL Temperature Range Min state value
|
|
uint16_t temp_min;
|
|
/// Light CTL Temperature Range Max state value
|
|
uint16_t temp_max;
|
|
};
|
|
|
|
/*
|
|
* LOCAL FUNCTIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Prepare and send a Light CTL Status message.
|
|
*
|
|
* @param[in] p_env_ctl Pointer to Light CTL 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_lights_ctl_send_status(mm_lights_ctl_env_t *p_env_ctl,
|
|
mm_route_env_t *p_route_env, bool publish)
|
|
{
|
|
// Get environment for Light CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
// Pointer to the buffer that will contain the message
|
|
mesh_buf_t *p_buf_status;
|
|
// Remaining time for Light CTL Lightness state and for Light CTL Temperature
|
|
// state transition
|
|
uint8_t ln_rem_time, temp_rem_time;
|
|
// Transition type for Light CTL Lightness and for Light CTL Temperature states
|
|
uint8_t ln_trans_type, temp_trans_type;
|
|
// Data length
|
|
uint8_t data_length;
|
|
|
|
// Check if a transition has been started
|
|
mm_bind_get_trans_info(p_env_ctl->env.grp_lid, &ln_trans_type, &ln_rem_time);
|
|
mm_bind_get_trans_info(p_env_ctlt->env.grp_lid, &temp_trans_type, &temp_rem_time);
|
|
|
|
// Deduce deduce data length
|
|
data_length = ((ln_trans_type != MM_TRANS_TYPE_NONE) || (temp_trans_type != MM_TRANS_TYPE_NONE))
|
|
? MM_LIGHT_CTL_STATUS_LEN : MM_LIGHT_CTL_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_ctl->status_app_key_lid;
|
|
p_buf_env->u_addr.dst = p_env_ctl->status_dst_addr;
|
|
SETB(p_buf_env->info, MM_ROUTE_INFO_RELAY,
|
|
GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_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_ctl->env.mdl_lid;
|
|
p_buf_env->opcode = MM_MSG_LIGHT_CTL_STATUS;
|
|
|
|
// Fill the message
|
|
write16p(p_data + MM_LIGHT_CTL_STATUS_LIGHTNESS_POS, p_env_ctl->ln);
|
|
write16p(p_data + MM_LIGHT_CTL_STATUS_TEMP_POS, p_env_ctlt->temp);
|
|
|
|
if (data_length == MM_LIGHT_CTL_STATUS_LEN)
|
|
{
|
|
// Sent Target Light CTL Temperature and Light CTL Lightness state values
|
|
uint16_t temp_tgt, ln_tgt;
|
|
// Sent Remaining Time value
|
|
uint8_t rem_time = 0;
|
|
|
|
if (ln_trans_type != MM_TRANS_TYPE_NONE)
|
|
{
|
|
if (ln_trans_type == MM_TRANS_TYPE_MOVE)
|
|
{
|
|
// Light Lightness Range
|
|
uint16_t ln_min = mm_lights_ln_get(p_env_ctl->env.elmt_idx,
|
|
MM_STATE_LIGHT_LN_RANGE_MIN);
|
|
uint16_t ln_max = mm_lights_ln_get(p_env_ctl->env.elmt_idx,
|
|
MM_STATE_LIGHT_LN_RANGE_MAX);
|
|
|
|
ln_tgt = (p_env_ctl->move_delta > 0) ? ln_max : ln_min;
|
|
rem_time = MM_TRANS_TIME_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
ln_tgt = p_env_ctl->ln_tgt;
|
|
rem_time = ln_rem_time;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ln_tgt = p_env_ctl->ln;
|
|
}
|
|
|
|
if (temp_trans_type != MM_TRANS_TYPE_NONE)
|
|
{
|
|
if (temp_trans_type == MM_TRANS_TYPE_MOVE)
|
|
{
|
|
temp_tgt = (p_env_ctlt->move_delta > 0) ? p_env_ctlt->temp_max
|
|
: p_env_ctlt->temp_min;
|
|
rem_time = MM_TRANS_TIME_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
temp_tgt = p_env_ctlt->temp_tgt;
|
|
|
|
if (rem_time != MM_TRANS_TIME_UNKNOWN)
|
|
{
|
|
if (temp_rem_time > ln_rem_time)
|
|
{
|
|
rem_time = temp_rem_time;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
temp_tgt = p_env_ctlt->temp;
|
|
}
|
|
|
|
write16p(p_data + MM_LIGHT_CTL_STATUS_TGT_LIGHTNESS_POS, ln_tgt);
|
|
write16p(p_data + MM_LIGHT_CTL_STATUS_TGT_TEMP_POS, temp_tgt);
|
|
*(p_data + MM_LIGHT_CTL_STATUS_REM_TIME_POS) = rem_time;
|
|
}
|
|
|
|
// Send the message
|
|
mm_route_send(p_buf_status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Prepare and send a Light CTL Temperature Status message
|
|
*
|
|
* @param[in] p_env_ctlt Pointer to Light CTL Temperature 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_lights_ctl_send_status_temp(mm_lights_ctlt_env_t *p_env_ctlt,
|
|
mm_route_env_t *p_route_env, bool publish)
|
|
{
|
|
// Get environment for Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl = p_env_ctlt->p_env_ctl;
|
|
// Pointer to the buffer that will contain the message
|
|
mesh_buf_t *p_buf_status;
|
|
// Remaining time for Light CTL Lightness state and for Light CTL Temperature
|
|
// state transition
|
|
uint8_t ln_rem_time, temp_rem_time;;
|
|
// Transition type for Light CTL Lightness and for Light CTL Temperature states
|
|
uint8_t ln_trans_type, temp_trans_type;
|
|
// Data length
|
|
uint8_t data_length;
|
|
|
|
// Check if a transition has been started
|
|
mm_bind_get_trans_info(p_env_ctl->env.grp_lid, &ln_trans_type, &ln_rem_time);
|
|
mm_bind_get_trans_info(p_env_ctlt->env.grp_lid, &temp_trans_type, &temp_rem_time);
|
|
|
|
// Deduce deduce data length
|
|
data_length = ((ln_trans_type != MM_TRANS_TYPE_NONE) || (temp_trans_type != MM_TRANS_TYPE_NONE))
|
|
? MM_LIGHT_CTL_TEMP_STATUS_LEN : MM_LIGHT_CTL_TEMP_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_ctl->status_app_key_lid;
|
|
p_buf_env->u_addr.dst = p_env_ctl->status_dst_addr;
|
|
SETB(p_buf_env->info, MM_ROUTE_INFO_RELAY,
|
|
GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_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_ctlt->env.mdl_lid;
|
|
p_buf_env->opcode = MM_MSG_LIGHT_CTL_TEMP_STATUS;
|
|
|
|
// Fill the message
|
|
write16p(p_data + MM_LIGHT_CTL_TEMP_STATUS_TEMP_POS, p_env_ctlt->temp);
|
|
write16p(p_data + MM_LIGHT_CTL_TEMP_STATUS_DELTA_UV_POS, p_env_ctl->delta_uv);
|
|
|
|
if (data_length == MM_LIGHT_CTL_TEMP_STATUS_LEN)
|
|
{
|
|
// Sent Target Light CTL Temperature and Light CTL Delta UV state values
|
|
uint16_t temp_tgt, delta_uv_tgt;
|
|
// Sent Remaining Time value
|
|
uint8_t rem_time = 0;
|
|
|
|
if (ln_trans_type != MM_TRANS_TYPE_NONE)
|
|
{
|
|
delta_uv_tgt = p_env_ctl->delta_uv_tgt;
|
|
rem_time = ln_rem_time;
|
|
}
|
|
else
|
|
{
|
|
delta_uv_tgt = p_env_ctl->delta_uv;
|
|
}
|
|
|
|
if (temp_trans_type != MM_TRANS_TYPE_NONE)
|
|
{
|
|
if (temp_trans_type == MM_TRANS_TYPE_MOVE)
|
|
{
|
|
temp_tgt = (p_env_ctlt->move_delta > 0) ? p_env_ctlt->temp_max
|
|
: p_env_ctlt->temp_min;
|
|
rem_time = MM_TRANS_TIME_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
temp_tgt = p_env_ctlt->temp_tgt;
|
|
|
|
if (temp_rem_time > ln_rem_time)
|
|
{
|
|
rem_time = temp_rem_time;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
temp_tgt = p_env_ctlt->temp;
|
|
}
|
|
|
|
write16p(p_data + MM_LIGHT_CTL_TEMP_STATUS_TGT_TEMP_POS, temp_tgt);
|
|
write16p(p_data + MM_LIGHT_CTL_TEMP_STATUS_TGT_DELTA_UV_POS, delta_uv_tgt);
|
|
*(p_data + MM_LIGHT_CTL_TEMP_STATUS_REM_TIME_POS) = rem_time;
|
|
}
|
|
|
|
// Send the message
|
|
mm_route_send(p_buf_status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Prepare and send a Light CTL Default Status message
|
|
*
|
|
* @param[in] p_env_ctl Pointer to Light CTL Server model environment
|
|
* @param[in] p_route_env Pointer to structure containing reception information provided
|
|
* by Mesh Profile for received request message
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_send_status_dflt(mm_lights_ctl_env_t *p_env_ctl,
|
|
mm_route_env_t *p_route_env)
|
|
{
|
|
// Pointer to the buffer that will contain the message
|
|
mesh_buf_t *p_buf_status = mm_route_buf_alloc_status(MM_LIGHT_CTL_DFLT_STATUS_LEN, p_route_env);
|
|
|
|
if (p_buf_status)
|
|
{
|
|
// Get pointer to environment for Light Lightness CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
// 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
|
|
p_buf_env->mdl_lid = p_env_ctl->env.mdl_lid;
|
|
p_buf_env->opcode = MM_MSG_LIGHT_CTL_DFLT_STATUS;
|
|
|
|
// Fill the message
|
|
write16p(p_data + MM_LIGHT_CTL_DFLT_STATUS_LIGHTNESS_POS,
|
|
mm_lights_ln_get(p_env_ctl->env.elmt_idx, MM_STATE_LIGHT_LN_DFLT));
|
|
write16p(p_data + MM_LIGHT_CTL_DFLT_STATUS_TEMP_POS, p_env_ctlt->temp_dflt);
|
|
write16p(p_data + MM_LIGHT_CTL_DFLT_STATUS_DELTA_UV_POS, p_env_ctl->delta_uv_dflt);
|
|
|
|
// Send the message
|
|
mm_route_send(p_buf_status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Prepare and send a Light CTL Temperature Range Status message
|
|
*
|
|
* @param[in] p_env_ctlt Pointer to Light CTL Temperature Server model environment
|
|
* @param[in] p_route_env Pointer to structure containing reception information provided
|
|
* by Mesh Profile for received request message
|
|
* @param[in] status Status sent in the Light CTL Temperature Status message
|
|
* (@see enum mm_status)
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_send_status_temp_range(mm_lights_ctl_env_t *p_env_ctl,
|
|
mm_route_env_t *p_route_env,
|
|
uint8_t status)
|
|
{
|
|
// Pointer to the buffer that will contain the message
|
|
mesh_buf_t *p_buf_status = mm_route_buf_alloc_status(MM_LIGHT_CTL_TEMP_RANGE_STATUS_LEN, p_route_env);
|
|
|
|
if (p_buf_status)
|
|
{
|
|
// Pointer to environment for Light CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
// 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
|
|
p_buf_env->mdl_lid = p_env_ctl->env.mdl_lid;
|
|
p_buf_env->opcode = MM_MSG_LIGHT_CTL_TEMP_RANGE_STATUS;
|
|
|
|
// Fill the message
|
|
*(p_data + MM_LIGHT_CTL_TEMP_RANGE_STATUS_CODE_POS) = status;
|
|
write16p(p_data + MM_LIGHT_CTL_TEMP_RANGE_STATUS_MIN_POS, p_env_ctlt->temp_min);
|
|
write16p(p_data + MM_LIGHT_CTL_TEMP_RANGE_STATUS_MAX_POS, p_env_ctlt->temp_max);
|
|
|
|
// Send the message
|
|
mm_route_send(p_buf_status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Publish Light CTL state value if sending of publications is enabled
|
|
*
|
|
* @param[in] p_env_ctl Pointer to Light CTL Server model environment
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_publish(mm_lights_ctl_env_t *p_env_ctl)
|
|
{
|
|
// Check if sending of publication is enabled
|
|
if (GETB(p_env_ctl->env.info, MM_INFO_PUBLI))
|
|
{
|
|
mm_lights_ctl_send_status(p_env_ctl, NULL, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Publish Light CTL Temperature state value if sending of publications is enabled
|
|
*
|
|
* @param[in] p_env_ctlt Pointer to Light CTL Temperature Server model environment
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_publish_temp(mm_lights_ctlt_env_t *p_env_ctlt)
|
|
{
|
|
// Check if sending of publication is enabled
|
|
if (GETB(p_env_ctlt->env.info, MM_INFO_PUBLI))
|
|
{
|
|
mm_lights_ctl_send_status_temp(p_env_ctlt, NULL, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Check if a Light CTL Status or a Light CTL Temperature Status message must be sent
|
|
* and send it if it is the case
|
|
*
|
|
* @param[in] p_env_ctl Pointer to Light CTL Server model environment
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_check_status(mm_lights_ctl_env_t *p_env_ctl, uint8_t event)
|
|
{
|
|
if (!GETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT))
|
|
{
|
|
// Get environment for Light CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
|
|
if (p_env_ctl->status_dst_addr != MESH_UNASSIGNED_ADDR)
|
|
{
|
|
// Send a response to the node that has required the transition
|
|
if (!GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TEMP_STATUS))
|
|
{
|
|
mm_lights_ctl_send_status(p_env_ctl, NULL, false);
|
|
}
|
|
else
|
|
{
|
|
mm_lights_ctl_send_status_temp(p_env_ctl->p_env_ctlt, NULL, false);
|
|
}
|
|
|
|
p_env_ctl->status_dst_addr = MESH_UNASSIGNED_ADDR;
|
|
}
|
|
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_LN)
|
|
|| GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP))
|
|
{
|
|
mm_lights_ctl_publish(p_env_ctl);
|
|
}
|
|
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_DUV)
|
|
|| GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP))
|
|
{
|
|
// Send a publication
|
|
mm_lights_ctl_publish_temp(p_env_ctlt);
|
|
}
|
|
|
|
if (event == MM_GRP_EVENT_TRANS_STARTED)
|
|
{
|
|
SETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT,
|
|
GETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS));
|
|
}
|
|
else
|
|
{
|
|
SETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT, 0);
|
|
SETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Convert a Generic Level value into a Light CTL Temperature value
|
|
*
|
|
* @param[in] lvl Generic level value
|
|
* @param[in] temp_min Light CTL Temperature Min value
|
|
* @param[in] temp_max Light CTL Temperature Max value
|
|
*
|
|
* @return Light CTL Temperature value
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC uint16_t mm_lights_ctl_lvl_to_temp(int16_t lvl, uint16_t temp_min, uint16_t temp_max)
|
|
{
|
|
// Temperature value
|
|
uint32_t temp = (int32_t)lvl + 32768;
|
|
|
|
temp *= (temp_max - temp_min);
|
|
temp /= 65535;
|
|
temp += temp_min;
|
|
|
|
return ((uint16_t)temp);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Convert a Light CTL Temperature value into a Generic Level value
|
|
*
|
|
* @param[in] temp Light CTL Temperature value
|
|
* @param[in] temp_min Light CTL Temperature Min value
|
|
* @param[in] temp_max Light CTL Temperature Max value
|
|
*
|
|
* @return Generic Level value
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC int16_t mm_lights_ctl_temp_to_lvl(uint16_t temp, uint16_t temp_min, uint16_t temp_max)
|
|
{
|
|
// Level value
|
|
int32_t lvl = ((int32_t)temp - temp_min);
|
|
|
|
lvl *= 65535;
|
|
lvl /= (temp_max - temp_min);
|
|
lvl -= 32768;
|
|
|
|
return ((int16_t)lvl);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Convert a Light CTL Temperature value into a Generic Level value
|
|
*
|
|
* @param[in] temp Light CTL Temperature value
|
|
* @param[in] temp_min Light CTL Temperature Min value
|
|
* @param[in] temp_max Light CTL Temperature Max value
|
|
*
|
|
* @return Generic Level value
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC uint16_t mm_lights_ctl_temp_add_delta(uint16_t temp, int32_t delta,
|
|
uint16_t temp_min, uint16_t temp_max)
|
|
{
|
|
delta *= (temp_max - temp_min);
|
|
delta /= 65535;
|
|
delta += temp;
|
|
|
|
return ((uint16_t)delta);
|
|
}
|
|
|
|
/*
|
|
* MESSAGE HANDLERS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Handler for Light CTL 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 buffer containing the received message
|
|
* @param[in] p_route_env Pointer to routing information for the received buffer
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_handler_set(mm_lights_ctl_env_t *p_env_ctl, mesh_buf_t *p_buf,
|
|
mm_route_env_t *p_route_env)
|
|
{
|
|
do
|
|
{
|
|
// Get environment for Light CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
// Check if a status message must be sent
|
|
bool send_status = (p_route_env->opcode == MM_MSG_LIGHT_CTL_SET);
|
|
// Get pointer to data
|
|
uint8_t *p_data = MESH_BUF_DATA(p_buf);
|
|
// TID value
|
|
uint8_t tid = *(p_data + MM_LIGHT_CTL_SET_TID_POS);
|
|
// Light CTL Lightness, Light CTL Temperature and Light CTL Delta UV value
|
|
uint16_t ln, temp;
|
|
int16_t delta_uv;
|
|
// Transition time
|
|
uint8_t trans_time;
|
|
// Delay
|
|
uint8_t delay;
|
|
|
|
// Check if request can be processed
|
|
if ((p_env_ctl->status_dst_addr != MESH_UNASSIGNED_ADDR)
|
|
|| (mm_replay_is_retx(&p_env_ctl->replay_env, p_route_env->u_addr.src, tid)))
|
|
{
|
|
// Send a Light CTL Status message
|
|
if (send_status)
|
|
{
|
|
mm_lights_ctl_send_status(p_env_ctl, p_route_env, false);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Extract and check optional parameters if present
|
|
if (p_buf->data_len == MM_LIGHT_CTL_SET_LEN)
|
|
{
|
|
trans_time = (uint16_t)(*(p_data + MM_LIGHT_CTL_SET_TRANS_TIME_POS));
|
|
|
|
// Check received value
|
|
if (GETF(trans_time, MM_TRANS_TIME_STEP_NB) > MM_TRANS_TIME_STEPS_MAX)
|
|
{
|
|
// Drop the message
|
|
break;
|
|
}
|
|
|
|
delay = *(p_data + MM_LIGHT_CTL_SET_DELAY_POS);
|
|
}
|
|
else
|
|
{
|
|
trans_time = MM_TRANS_TIME_UNKNOWN;
|
|
delay = 0;
|
|
}
|
|
|
|
ln = read16p(p_data + MM_LIGHT_CTL_SET_LIGHTNESS_POS);
|
|
temp = read16p(p_data + MM_LIGHT_CTL_SET_TEMP_POS);
|
|
delta_uv = read16p(p_data + MM_LIGHT_CTL_SET_DELTA_UV_POS);
|
|
|
|
// Ensure that Light CTL Temperature state value is between Light CTL Temperature
|
|
// Range Min and Max values
|
|
if (temp > p_env_ctlt->temp_max)
|
|
{
|
|
temp = p_env_ctlt->temp_max;
|
|
}
|
|
else if (temp < p_env_ctlt->temp_min)
|
|
{
|
|
temp = p_env_ctlt->temp_min;
|
|
}
|
|
|
|
// Check if at least one of the states is modified
|
|
if ((ln == p_env_ctl->ln)
|
|
&& (temp == p_env_ctlt->temp)
|
|
&& (delta_uv == p_env_ctl->delta_uv))
|
|
{
|
|
// Send a Light CTL Status message
|
|
if (send_status)
|
|
{
|
|
mm_lights_ctl_send_status(p_env_ctl, p_route_env, false);
|
|
}
|
|
break;
|
|
};
|
|
|
|
if (send_status)
|
|
{
|
|
// Keep information for transmission of status
|
|
p_env_ctl->status_dst_addr = p_route_env->u_addr.src;
|
|
p_env_ctl->status_app_key_lid = p_route_env->app_key_lid;
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TEMP_STATUS, 0);
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_RELAY,
|
|
GETB(p_route_env->info, MM_ROUTE_INFO_RELAY));
|
|
}
|
|
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_LN, (ln != p_env_ctl->ln));
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_DUV, (delta_uv != p_env_ctl->delta_uv));
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP, (temp != p_env_ctlt->temp));
|
|
SETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT,
|
|
GETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS));
|
|
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_LN)
|
|
|| GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_DUV))
|
|
{
|
|
// Update target state
|
|
p_env_ctl->ln_tgt = ln;
|
|
p_env_ctl->delta_uv_tgt = delta_uv;
|
|
|
|
// Inform the Binding Manager about new transition
|
|
mm_bind_trans_new(p_env_ctl->env.grp_lid, MM_TRANS_TYPE_CLASSIC, trans_time, delay);
|
|
}
|
|
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP))
|
|
{
|
|
// Update target state
|
|
p_env_ctlt->temp_tgt = temp;
|
|
p_env_ctlt->lvl_tgt = mm_lights_ctl_temp_to_lvl(p_env_ctlt->temp_tgt, p_env_ctlt->temp_min,
|
|
p_env_ctlt->temp_max);
|
|
|
|
// Inform the Binding Manager about new transition
|
|
mm_bind_trans_new(p_env_ctlt->env.grp_lid, MM_TRANS_TYPE_CLASSIC, trans_time, delay);
|
|
}
|
|
} while (0);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Handler for Light CTL Temperature 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 buffer containing the received message
|
|
* @param[in] p_route_env Pointer to routing information for the received buffer
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_handler_set_temp(mm_lights_ctlt_env_t *p_env_ctlt, mesh_buf_t *p_buf,
|
|
mm_route_env_t *p_route_env)
|
|
{
|
|
do
|
|
{
|
|
// Get pointer to environment for Light Lightness CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl = p_env_ctlt->p_env_ctl;
|
|
// Check if a status message must be sent
|
|
bool send_status = (p_route_env->opcode == MM_MSG_LIGHT_CTL_TEMP_SET);
|
|
// Get pointer to data
|
|
uint8_t *p_data = MESH_BUF_DATA(p_buf);
|
|
// Received ight CTL Temperature and Light CTL Delta UV state values
|
|
uint16_t temp;
|
|
int16_t delta_uv;
|
|
// Transition time
|
|
uint8_t trans_time = MM_TRANS_TIME_UNKNOWN;
|
|
// Delay
|
|
uint8_t delay = 0;
|
|
// TID value
|
|
uint8_t tid = *(p_data + MM_LIGHT_CTL_TEMP_SET_TID_POS);;
|
|
|
|
// Check if request can be processed
|
|
if ((p_env_ctl->status_dst_addr != MESH_UNASSIGNED_ADDR)
|
|
|| (mm_replay_is_retx(&p_env_ctl->replay_env, p_route_env->u_addr.src, tid)))
|
|
{
|
|
// Send a Light CTL Temperature Status message
|
|
if (send_status)
|
|
{
|
|
mm_lights_ctl_send_status_temp(p_env_ctlt, p_route_env, false);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Extract and check optional parameters if present
|
|
if (p_buf->data_len == MM_LIGHT_CTL_TEMP_SET_LEN)
|
|
{
|
|
trans_time = (uint16_t)(*(p_data + MM_LIGHT_CTL_TEMP_SET_TRANS_TIME_POS));
|
|
|
|
// Check received value
|
|
if (GETF(trans_time, MM_TRANS_TIME_STEP_NB) > MM_TRANS_TIME_STEPS_MAX)
|
|
{
|
|
// Drop the message
|
|
break;
|
|
}
|
|
|
|
delay = *(p_data + MM_LIGHT_CTL_TEMP_SET_DELAY_POS);
|
|
}
|
|
|
|
temp = read16p(p_data + MM_LIGHT_CTL_TEMP_SET_TEMP_POS);
|
|
delta_uv = read16p(p_data + MM_LIGHT_CTL_TEMP_SET_DELTA_UV_POS);
|
|
|
|
// Ensure that Light CTL Temperature state value is between Light CTL Temperature Range
|
|
// Min and Max values
|
|
if ((temp > p_env_ctlt->temp_max)
|
|
|| ((temp < p_env_ctlt->temp_min)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Check if at least one of the states is modified
|
|
if ((temp == p_env_ctlt->temp)
|
|
&& (delta_uv == p_env_ctl->delta_uv))
|
|
{
|
|
// Send a Light CTL Temperature Status message
|
|
if (send_status)
|
|
{
|
|
mm_lights_ctl_send_status_temp(p_env_ctlt, p_route_env, false);
|
|
}
|
|
break;
|
|
};
|
|
|
|
if (send_status)
|
|
{
|
|
// Keep information for transmission of status
|
|
p_env_ctl->status_dst_addr = p_route_env->u_addr.src;
|
|
p_env_ctl->status_app_key_lid = p_route_env->app_key_lid;
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TEMP_STATUS, 1);
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_RELAY,
|
|
GETB(p_route_env->info, MM_ROUTE_INFO_RELAY));
|
|
}
|
|
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_LN, 0);
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_DUV, (delta_uv != p_env_ctl->delta_uv));
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP, (temp != p_env_ctlt->temp));
|
|
SETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT,
|
|
GETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS));
|
|
|
|
// Check if Light CTL Delta UV value is modified
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_DUV))
|
|
{
|
|
// Update target state
|
|
p_env_ctl->delta_uv_tgt = delta_uv;
|
|
p_env_ctl->ln_tgt = p_env_ctl->ln;
|
|
|
|
// Inform the Binding Manager about new transition
|
|
mm_bind_trans_new(p_env_ctl->env.grp_lid, MM_TRANS_TYPE_CLASSIC, trans_time, delay);
|
|
}
|
|
|
|
// Check if Light CTL Temperature value is modified
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP))
|
|
{
|
|
// Update target state
|
|
p_env_ctlt->temp_tgt = temp;
|
|
p_env_ctlt->lvl_tgt = mm_lights_ctl_temp_to_lvl(p_env_ctlt->temp_tgt, p_env_ctlt->temp_min,
|
|
p_env_ctlt->temp_max);
|
|
|
|
// Inform the Binding Manager about new transition
|
|
mm_bind_trans_new(p_env_ctlt->env.grp_lid, MM_TRANS_TYPE_CLASSIC, trans_time, delay);
|
|
}
|
|
} while (0);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Handler for Light CTL Default 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 buffer containing the received message
|
|
* @param[in] p_route_env Pointer to routing information for the received buffer
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_handler_set_dflt(mm_lights_ctl_env_t *p_env_ctl,
|
|
mesh_buf_t *p_buf, mm_route_env_t *p_route_env)
|
|
{
|
|
do
|
|
{
|
|
// Get pointer to data
|
|
uint8_t *p_data = MESH_BUF_DATA(p_buf);
|
|
// Get environment for Light Lightness CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
// Extract received state values
|
|
uint16_t ln_dflt = read16p(p_data + MM_LIGHT_CTL_DFLT_SET_LIGHTNESS_POS);
|
|
uint16_t temp_dflt = read16p(p_data + MM_LIGHT_CTL_DFLT_SET_TEMP_POS);
|
|
uint16_t delta_uv_dflt = read16p(p_data + MM_LIGHT_CTL_DFLT_SET_DELTA_UV_POS);
|
|
|
|
if ((temp_dflt > p_env_ctlt->temp_max)
|
|
|| (temp_dflt < p_env_ctlt->temp_min))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Inform Light Lightness Server model about received Light Lightness Default state value
|
|
mm_lights_ln_set_dflt(p_env_ctl->env.elmt_idx, ln_dflt);
|
|
|
|
if (temp_dflt != p_env_ctlt->temp_dflt)
|
|
{
|
|
// Keep received value
|
|
p_env_ctlt->temp_dflt = temp_dflt;
|
|
|
|
// Inform application about received value
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_TEMP_DFLT,
|
|
p_env_ctlt->env.elmt_idx, temp_dflt, 0);
|
|
}
|
|
|
|
if (delta_uv_dflt != p_env_ctl->delta_uv_dflt)
|
|
{
|
|
// Keep received value
|
|
p_env_ctl->delta_uv_dflt = delta_uv_dflt;
|
|
|
|
// Inform application about received value
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_DELTA_UV_DFLT,
|
|
p_env_ctl->env.elmt_idx, delta_uv_dflt, 0);
|
|
}
|
|
|
|
// If needed, send a Light CTL Default Status message to the requester
|
|
if (p_route_env->opcode == MM_MSG_LIGHT_CTL_DFLT_SET)
|
|
{
|
|
mm_lights_ctl_send_status_dflt(p_env_ctl, p_route_env);
|
|
}
|
|
} while (0);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Handler for Light CTL Temperature Range 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 buffer containing the received message
|
|
* @param[in] p_route_env Pointer to routing information for the received buffer
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_handler_set_temp_range(mm_lights_ctl_env_t *p_env_ctl,
|
|
mesh_buf_t *p_buf,
|
|
mm_route_env_t *p_route_env)
|
|
{
|
|
do
|
|
{
|
|
// Get pointer to data
|
|
uint8_t *p_data = MESH_BUF_DATA(p_buf);
|
|
// Get environment for Light Lightness CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
// Status
|
|
uint8_t status = MM_STATUS_SUCCESS;
|
|
// Extract Light CTL Temperature Range state value
|
|
uint16_t temp_min = read16p(p_data + MM_LIGHT_CTL_TEMP_RANGE_SET_MIN_POS);
|
|
// Extract Light CTL Range state value
|
|
uint16_t temp_max = read16p(p_data + MM_LIGHT_CTL_TEMP_RANGE_SET_MAX_POS);
|
|
|
|
// Check provided values
|
|
if (temp_min < MM_LIGHTS_CTL_TEMP_MIN)
|
|
{
|
|
status = MM_STATUS_ERROR_RANGE_MIN;
|
|
}
|
|
else if (temp_max > MM_LIGHTS_CTL_TEMP_MAX)
|
|
{
|
|
status = MM_STATUS_ERROR_RANGE_MAX;
|
|
}
|
|
else if (temp_min > temp_max)
|
|
{
|
|
// Drop the message
|
|
break;
|
|
}
|
|
|
|
if ((status == MM_STATUS_SUCCESS)
|
|
&& ((p_env_ctlt->temp_min != temp_min)
|
|
|| (p_env_ctlt->temp_max != temp_max)))
|
|
{
|
|
p_env_ctlt->temp_min = temp_min;
|
|
p_env_ctlt->temp_max = temp_max;
|
|
|
|
// Inform application about received value
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_TEMP_RANGE, p_env_ctlt->env.elmt_idx,
|
|
(uint32_t)temp_min | ((uint32_t)temp_max << 16), 0);
|
|
}
|
|
|
|
// If needed, send a Light CTL Temperature Range Status message to the requester
|
|
if (p_route_env->opcode == MM_MSG_LIGHT_CTL_TEMP_RANGE_SET)
|
|
{
|
|
mm_lights_ctl_send_status_temp_range(p_env_ctl, p_route_env, status);
|
|
}
|
|
} while (0);
|
|
}
|
|
|
|
/*
|
|
* INTERNAL CALLBACK FUNCTIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Callback function called when timer monitoring publication duration for
|
|
* Light CTL Server model or for Light CTL Temperature expires
|
|
*
|
|
* @param[in] p_env Pointer to model environment for Light CTL Server or Light CTL
|
|
* Temperature model
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_cb_tmr_publi(void *p_tmr)
|
|
{
|
|
mm_lights_ctl_env_t *p_env = MESH_TMR2ENV(p_tmr, mm_lights_ctl_env_t, tmr_publi);
|
|
// Get allocated environment
|
|
mm_mdl_publi_env_t *p_env_publi = (mm_mdl_publi_env_t *)p_env;
|
|
|
|
if (p_env_publi->publi_period_ms)
|
|
{
|
|
if (p_env_publi->env.model_id == MM_ID_LIGHTS_CTL)
|
|
{
|
|
// Publish a Light CTL Status message
|
|
mm_lights_ctl_publish((mm_lights_ctl_env_t *)p_env);
|
|
}
|
|
else // (p_env_publi->env.model_id == MM_ID_LIGHTS_CTLT)
|
|
{
|
|
// Publish a Light CTL Temperature Status message
|
|
mm_lights_ctl_publish_temp((mm_lights_ctlt_env_t *)p_env);
|
|
}
|
|
|
|
// Restart the timer
|
|
mesh_timer_set(&p_env_publi->tmr_publi, p_env_publi->publi_period_ms);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Inform Light CTL Server model about a received message
|
|
*
|
|
* @param[in] p_env Pointer to the environment allocated for the Light CTL
|
|
* 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_lights_ctl_cb_rx(mm_mdl_env_t *p_env, mesh_buf_t *p_buf,
|
|
mm_route_env_t *p_route_env)
|
|
{
|
|
do
|
|
{
|
|
// Environment for Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl;
|
|
|
|
if (p_env->model_id == MM_ID_LIGHTS_CTL)
|
|
{
|
|
p_env_ctl = (mm_lights_ctl_env_t *)p_env;
|
|
|
|
switch (p_route_env->opcode)
|
|
{
|
|
case (MM_MSG_LIGHT_CTL_GET):
|
|
{
|
|
// Send a Light CTL Status message
|
|
mm_lights_ctl_send_status(p_env_ctl, p_route_env, false);
|
|
} break;
|
|
|
|
case (MM_MSG_LIGHT_CTL_SET):
|
|
case (MM_MSG_LIGHT_CTL_SET_UNACK):
|
|
{
|
|
// Handle the message
|
|
mm_lights_ctl_handler_set(p_env_ctl, p_buf, p_route_env);
|
|
} break;
|
|
|
|
case (MM_MSG_LIGHT_CTL_TEMP_RANGE_GET):
|
|
{
|
|
// Send a Light CTL Temperature Range Status message
|
|
mm_lights_ctl_send_status_temp_range(p_env_ctl, p_route_env, MM_STATUS_SUCCESS);
|
|
} break;
|
|
|
|
case (MM_MSG_LIGHT_CTL_DFLT_GET):
|
|
{
|
|
// Send a Light CTL Default Status message
|
|
mm_lights_ctl_send_status_dflt(p_env_ctl, p_route_env);
|
|
} break;
|
|
|
|
default:
|
|
{
|
|
} break;
|
|
}
|
|
}
|
|
else if (p_env->model_id == MM_ID_LIGHTS_CTLS)
|
|
{
|
|
// Environment for Light CTL Setup Server model
|
|
mm_lights_ctls_env_t *p_env_ctls = (mm_lights_ctls_env_t *)p_env;
|
|
|
|
p_env_ctl = p_env_ctls->p_env_ctl;
|
|
|
|
switch (p_route_env->opcode)
|
|
{
|
|
case (MM_MSG_LIGHT_CTL_DFLT_SET):
|
|
case (MM_MSG_LIGHT_CTL_DFLT_SET_UNACK):
|
|
{
|
|
// Handle the message
|
|
mm_lights_ctl_handler_set_dflt(p_env_ctl, p_buf, p_route_env);
|
|
} break;
|
|
|
|
case (MM_MSG_LIGHT_CTL_TEMP_RANGE_SET):
|
|
case (MM_MSG_LIGHT_CTL_TEMP_RANGE_SET_UNACK):
|
|
{
|
|
// Handle the message
|
|
mm_lights_ctl_handler_set_temp_range(p_env_ctl, p_buf, p_route_env);
|
|
} break;
|
|
|
|
default:
|
|
{
|
|
} break;
|
|
}
|
|
}
|
|
else // (p_env->model_id == MM_ID_LIGHTS_CTLT)
|
|
{
|
|
// Environment for Light CTL Temperature model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = (mm_lights_ctlt_env_t *)p_env;
|
|
|
|
switch (p_route_env->opcode)
|
|
{
|
|
case (MM_MSG_LIGHT_CTL_TEMP_GET):
|
|
{
|
|
// Send a Light CTL Temperature Status message
|
|
mm_lights_ctl_send_status_temp(p_env_ctlt, p_route_env, false);
|
|
} break;
|
|
|
|
case (MM_MSG_LIGHT_CTL_TEMP_SET):
|
|
case (MM_MSG_LIGHT_CTL_TEMP_SET_UNACK):
|
|
{
|
|
// Handle the message
|
|
mm_lights_ctl_handler_set_temp(p_env_ctlt, p_buf, p_route_env);
|
|
} break;
|
|
|
|
default:
|
|
{
|
|
} break;
|
|
}
|
|
}
|
|
} while (0);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Check if a given opcode is handled by the Light CTL Server model
|
|
*
|
|
* @param[in] p_env Pointer to the environment allocated for the Light CTL
|
|
* Server model
|
|
* @param[in] opcode Opcode to check
|
|
*
|
|
* @return An error status (@see enum mesh_err)
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC uint8_t mm_lights_ctl_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_LIGHTS_CTL)
|
|
{
|
|
if ((opcode == MM_MSG_LIGHT_CTL_GET)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_SET)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_SET_UNACK)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_TEMP_RANGE_GET)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_DFLT_GET))
|
|
{
|
|
status = MESH_ERR_NO_ERROR;
|
|
}
|
|
}
|
|
else if (p_env->model_id == MM_ID_LIGHTS_CTLS)
|
|
{
|
|
if ((opcode == MM_MSG_LIGHT_CTL_DFLT_SET)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_DFLT_SET_UNACK)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_TEMP_RANGE_SET)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_TEMP_RANGE_SET_UNACK))
|
|
{
|
|
status = MESH_ERR_NO_ERROR;
|
|
}
|
|
}
|
|
else if (p_env->model_id == MM_ID_LIGHTS_CTLT)
|
|
{
|
|
if ((opcode == MM_MSG_LIGHT_CTL_TEMP_GET)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_TEMP_SET)
|
|
|| (opcode == MM_MSG_LIGHT_CTL_TEMP_SET_UNACK))
|
|
{
|
|
status = MESH_ERR_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief
|
|
*
|
|
* @param[in] p_env Pointer the the environment allocated for the Generic OnOff
|
|
* Server model
|
|
* @param[in] state_id State identifier
|
|
* @param[in] state Light CTL Actual or Light CTL Default or Light
|
|
* Lightness Range state value
|
|
*
|
|
* @return An error status (@see enum mesh_err)
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC uint8_t mm_lights_ctl_cb_set(mm_mdl_env_t *p_env, uint16_t state_id, uint32_t state)
|
|
{
|
|
// Returned status
|
|
uint8_t status = MESH_ERR_NO_ERROR;
|
|
// Get environment for the Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl = (mm_lights_ctl_env_t *)p_env;
|
|
// Get environment for the Light CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = p_env_ctl->p_env_ctlt;
|
|
|
|
switch (state_id)
|
|
{
|
|
case (MM_STATE_LIGHT_CTL_LN):
|
|
{
|
|
// Keep the provided state value
|
|
p_env_ctl->ln = state;
|
|
|
|
// Set the Light Lightness state value
|
|
mm_bind_set_state(p_env_ctl->env.grp_lid, MM_STATE_TYPE_CURRENT,
|
|
MM_ID_LIGHTS_LN, state);
|
|
} break;
|
|
|
|
case (MM_STATE_LIGHT_CTL_DELTA_UV):
|
|
{
|
|
// Keep the provided state value
|
|
p_env_ctl->delta_uv = state;
|
|
} break;
|
|
|
|
case (MM_STATE_LIGHT_CTL_DELTA_UV_DFLT):
|
|
{
|
|
// Keep the provided state value
|
|
p_env_ctl->delta_uv_dflt = state;
|
|
} break;
|
|
|
|
case (MM_STATE_LIGHT_CTL_TEMP):
|
|
{
|
|
// Keep the provided state value
|
|
p_env_ctlt->temp = state;
|
|
} break;
|
|
|
|
case (MM_STATE_LIGHT_CTL_TEMP_DFLT):
|
|
{
|
|
// Keep the provided state value
|
|
p_env_ctlt->temp_dflt = state;
|
|
} break;
|
|
|
|
case (MM_STATE_LIGHT_CTL_TEMP_RANGE):
|
|
{
|
|
// Keep the provided state value
|
|
p_env_ctlt->temp_min = state;
|
|
p_env_ctlt->temp_max = state;
|
|
} break;
|
|
|
|
default:
|
|
{
|
|
status = MESH_ERR_INVALID_PARAM;
|
|
} break;
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
/*
|
|
* CALLBACK FUNCTIONS FOR BINDING MANAGER
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Callback function provided to the Binding Manager so that Light CTL 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_lights_ctl_cb_grp_event(m_lid_t mdl_lid, uint8_t event, uint8_t info)
|
|
{
|
|
// Get environment for Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl = (mm_lights_ctl_env_t *)mm_state_get_env(mdl_lid);
|
|
|
|
switch (event)
|
|
{
|
|
case (MM_GRP_EVENT_TRANS_DELAY_EXPIRED):
|
|
{
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_LN))
|
|
{
|
|
// Set the targeted Light Lightness state value
|
|
mm_bind_set_state(p_env_ctl->env.grp_lid, MM_STATE_TYPE_TARGET, MM_ID_LIGHTS_LN,
|
|
p_env_ctl->ln_tgt);
|
|
}
|
|
|
|
// Start the transition
|
|
mm_bind_trans_start(p_env_ctl->env.grp_lid);
|
|
} break;
|
|
|
|
case (MM_GRP_EVENT_TRANS_IMMEDIATE):
|
|
{
|
|
p_env_ctl->ln = p_env_ctl->ln_tgt;
|
|
p_env_ctl->delta_uv = p_env_ctl->delta_uv_tgt;
|
|
} // no break;
|
|
|
|
case (MM_GRP_EVENT_TRANS_STARTED):
|
|
{
|
|
uint8_t trans_time = info;
|
|
|
|
// Inform application about state update
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_LN))
|
|
{
|
|
// Expected event has been received
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_LN, 0);
|
|
|
|
// Inform application
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_LN, p_env_ctl->env.elmt_idx,
|
|
p_env_ctl->ln_tgt,
|
|
(trans_time) ? mm_get_trans_time_ms(trans_time) : 0);
|
|
}
|
|
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_DUV))
|
|
{
|
|
// Expected event has been received
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_DUV, 0);
|
|
|
|
// Inform application
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_DELTA_UV, p_env_ctl->env.elmt_idx,
|
|
p_env_ctl->delta_uv_tgt,
|
|
(trans_time) ? mm_get_trans_time_ms(trans_time) : 0);
|
|
}
|
|
|
|
// Check if status message must be sent
|
|
mm_lights_ctl_check_status(p_env_ctl, event);
|
|
} break;
|
|
|
|
case (MM_GRP_EVENT_TRANS_END):
|
|
{
|
|
p_env_ctl->ln = p_env_ctl->ln_tgt;
|
|
p_env_ctl->delta_uv = p_env_ctl->delta_uv_tgt;
|
|
|
|
// Inform application about state update
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_LN))
|
|
{
|
|
// Expected event has been received
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_LN, 0);
|
|
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_LN,
|
|
p_env_ctl->env.elmt_idx, p_env_ctl->ln, 0);
|
|
}
|
|
if (GETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_DUV))
|
|
{
|
|
// Expected event has been received
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_DUV, 0);
|
|
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_DELTA_UV,
|
|
p_env_ctl->env.elmt_idx, p_env_ctl->delta_uv, 0);
|
|
}
|
|
|
|
// Check if status message must be sent
|
|
mm_lights_ctl_check_status(p_env_ctl, event);
|
|
} break;
|
|
|
|
case (MM_GRP_EVENT_GROUP_FULL):
|
|
{
|
|
// Set the targeted Light Lightness state value
|
|
mm_bind_set_state(p_env_ctl->env.grp_lid, MM_STATE_TYPE_CURRENT, MM_ID_LIGHTS_LN,
|
|
p_env_ctl->ln);
|
|
} break;
|
|
|
|
//case (MM_GRP_EVENT_TRANS_ABORTED):
|
|
default:
|
|
{
|
|
} break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Callback function provided to the Binding Manager so that Light CTL Temperature 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_lights_ctl_cb_grp_event_temp(m_lid_t mdl_lid, uint8_t event, uint8_t info)
|
|
{
|
|
// Get environment for Light CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = (mm_lights_ctlt_env_t *)mm_state_get_env(mdl_lid);
|
|
// Get environment for Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl = p_env_ctlt->p_env_ctl;
|
|
|
|
switch (event)
|
|
{
|
|
case (MM_GRP_EVENT_TRANS_DELAY_EXPIRED):
|
|
{
|
|
// Set the targeted Generic Level state value
|
|
mm_bind_set_state(p_env_ctlt->env.grp_lid, MM_STATE_TYPE_TARGET, MM_ID_GENS_LVL,
|
|
p_env_ctlt->lvl_tgt);
|
|
|
|
// Start the transition
|
|
mm_bind_trans_start(p_env_ctlt->env.grp_lid);
|
|
} break;
|
|
|
|
case (MM_GRP_EVENT_TRANS_IMMEDIATE):
|
|
{
|
|
p_env_ctlt->temp = p_env_ctlt->temp_tgt;
|
|
} // no break;
|
|
|
|
case (MM_GRP_EVENT_TRANS_STARTED):
|
|
{
|
|
uint8_t trans_time = info;
|
|
|
|
// Mark transition as finished
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_TEMP, 0);
|
|
|
|
// Inform application about state update
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_TEMP, p_env_ctlt->env.elmt_idx,
|
|
p_env_ctlt->temp_tgt,
|
|
(trans_time) ? mm_get_trans_time_ms(trans_time) : 0);
|
|
|
|
// Check if status message must be sent
|
|
mm_lights_ctl_check_status(p_env_ctl, event);
|
|
} break;
|
|
|
|
case (MM_GRP_EVENT_TRANS_END):
|
|
{
|
|
p_env_ctlt->temp = p_env_ctlt->temp_tgt;
|
|
|
|
// Mark transition as finished
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT_TEMP, 0);
|
|
|
|
// Inform application about state update
|
|
mm_srv_state_upd_ind_send(MM_STATE_LIGHT_CTL_TEMP, p_env_ctlt->env.elmt_idx,
|
|
p_env_ctlt->temp, 0);
|
|
|
|
// Check if status message must be sent
|
|
mm_lights_ctl_check_status(p_env_ctl, event);
|
|
} break;
|
|
|
|
case (MM_GRP_EVENT_GROUP_FULL):
|
|
{
|
|
// Deduce Generic Level state value from Light CTL Temperature state value
|
|
int16_t lvl = mm_lights_ctl_temp_to_lvl(p_env_ctlt->temp, p_env_ctlt->temp_min,
|
|
p_env_ctlt->temp_max);
|
|
|
|
// Set the current Generic Level state value
|
|
mm_bind_set_state(p_env_ctlt->env.grp_lid, MM_STATE_TYPE_CURRENT, MM_ID_GENS_LVL, lvl);
|
|
};
|
|
|
|
//case (MM_GRP_EVENT_TRANS_ABORTED):
|
|
default:
|
|
{
|
|
} break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Callback function provided to the Binding Manager so that Light Lighting 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_lights_ctl_cb_trans_req(m_lid_t main_mdl_lid, uint32_t req_model_id, uint8_t trans_type,
|
|
uint32_t state_delta)
|
|
{
|
|
// Get environment for Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl = (mm_lights_ctl_env_t *)mm_state_get_env(main_mdl_lid);
|
|
// Targeted Light CTL Actual state value
|
|
uint16_t ln_tgt;
|
|
|
|
if (req_model_id == MM_ID_LIGHTS_LN)
|
|
{
|
|
ln_tgt = (uint16_t)state_delta;
|
|
}
|
|
else
|
|
{
|
|
if (req_model_id == MM_ID_GENS_OO)
|
|
{
|
|
// Requested Generic OnOff state value
|
|
uint8_t onoff = (uint8_t)state_delta;
|
|
|
|
if (onoff == 0)
|
|
{
|
|
ln_tgt = 0;
|
|
}
|
|
else
|
|
{
|
|
ln_tgt = 0;
|
|
}
|
|
}
|
|
else // (req_model_id == MM_ID_GENS_LVL)
|
|
{
|
|
if (trans_type == MM_TRANS_TYPE_CLASSIC)
|
|
{
|
|
// Requested Generic Level state value
|
|
int16_t level = (int16_t)state_delta;
|
|
|
|
// Light CTL Actual = Generic Level + 32768
|
|
ln_tgt = 32768 + level;
|
|
}
|
|
else // ((trans_type == MM_TRANS_TYPE_DELTA) || trans_type == MM_TRANS_TYPE_MOVE))
|
|
{
|
|
// Delta value
|
|
int32_t delta;
|
|
|
|
if (trans_type == MM_TRANS_TYPE_MOVE)
|
|
{
|
|
delta = (int16_t)state_delta;
|
|
|
|
// Keep the provided delta value
|
|
p_env_ctl->move_delta = (int16_t)state_delta;
|
|
}
|
|
else
|
|
{
|
|
delta = (int32_t)state_delta;
|
|
}
|
|
|
|
// Add the Light CTL Actual state value to the received delta value
|
|
delta += p_env_ctl->ln;
|
|
|
|
// The Light CTL Actual state value cannot wrap
|
|
if (delta < 0)
|
|
{
|
|
ln_tgt = 0;
|
|
}
|
|
else
|
|
{
|
|
ln_tgt = (delta > 0xFFFF) ? 0xFFFF : (uint16_t)delta;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ln_tgt != 0)
|
|
{
|
|
// Get range value
|
|
uint16_t ln_min = mm_lights_ln_get(p_env_ctl->env.elmt_idx, MM_STATE_LIGHT_LN_RANGE_MIN);
|
|
uint16_t ln_max = mm_lights_ln_get(p_env_ctl->env.elmt_idx, MM_STATE_LIGHT_LN_RANGE_MAX);
|
|
|
|
// Ensure that Light CTL Lightness state value is between Light CTL Lightness Range
|
|
// Min and Max values
|
|
if (ln_tgt > ln_max)
|
|
{
|
|
ln_tgt = ln_max;
|
|
}
|
|
else if (ln_tgt < ln_min)
|
|
{
|
|
ln_tgt = ln_min;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Check if Light CTL Actual state value is modified
|
|
if (ln_tgt != p_env_ctl->ln)
|
|
{
|
|
p_env_ctl->ln_tgt = ln_tgt;
|
|
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_LN, 1);
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_DUV, 0);
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP, 0);
|
|
SETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT,
|
|
GETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS));
|
|
|
|
// Start a new transition
|
|
mm_bind_trans_new(p_env_ctl->env.grp_lid, trans_type, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
// Reject the transition
|
|
mm_bind_trans_reject(p_env_ctl->env.grp_lid);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Inform Light CTL Temperature Server model that a transition has been requested
|
|
* using Generic Level model
|
|
*
|
|
* @param[in] main_mdl_lid Light CTL Temperature Server model local index
|
|
* @param[in] req_model_id Model ID of model requesting the transition
|
|
* @param[in] trans_type Transition type
|
|
* @param[in] state_delta State or delta value
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC void mm_lights_ctl_cb_trans_req_temp(m_lid_t main_mdl_lid, uint32_t req_model_id, uint8_t trans_type,
|
|
uint32_t state_delta)
|
|
{
|
|
// Get environment for Light CTL Temperature Server model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = (mm_lights_ctlt_env_t *)mm_state_get_env(main_mdl_lid);
|
|
// Requested Generic Level state value
|
|
int16_t lvl = (int16_t)state_delta;
|
|
// Targeted Light CTL Temperature state value
|
|
uint16_t temp_tgt;
|
|
|
|
if (trans_type == MM_TRANS_TYPE_CLASSIC)
|
|
{
|
|
temp_tgt = mm_lights_ctl_lvl_to_temp(lvl, p_env_ctlt->temp_min, p_env_ctlt->temp_max);
|
|
}
|
|
else // ((trans_type == MM_TRANS_TYPE_DELTA) || trans_type == MM_TRANS_TYPE_MOVE))
|
|
{
|
|
// Delta value
|
|
int32_t delta;
|
|
|
|
if (trans_type == MM_TRANS_TYPE_MOVE)
|
|
{
|
|
delta = (int16_t)state_delta;
|
|
|
|
// Keep the provided delta value
|
|
p_env_ctlt->move_delta = delta;
|
|
}
|
|
else
|
|
{
|
|
delta = (int32_t)state_delta;
|
|
}
|
|
|
|
temp_tgt = mm_lights_ctl_temp_add_delta(p_env_ctlt->temp, delta,
|
|
p_env_ctlt->temp_min, p_env_ctlt->temp_max);
|
|
}
|
|
|
|
// Ensure that Light CTL Temperature state value is between Light CTL Temperature Range
|
|
// Min and Max values
|
|
if (temp_tgt > p_env_ctlt->temp_max)
|
|
{
|
|
temp_tgt = p_env_ctlt->temp_max;
|
|
}
|
|
else if (temp_tgt < p_env_ctlt->temp_min)
|
|
{
|
|
temp_tgt = p_env_ctlt->temp_min;
|
|
}
|
|
|
|
// Check if Light CTL Temperature state value is modified
|
|
if (temp_tgt != p_env_ctlt->temp)
|
|
{
|
|
// Get environment for Light CTL Server model
|
|
mm_lights_ctl_env_t *p_env_ctl = p_env_ctlt->p_env_ctl;
|
|
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_LN, 0);
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_DUV, 0);
|
|
SETB(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS_TEMP, 1);
|
|
SETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_WAIT,
|
|
GETF(p_env_ctl->status_info, MM_LIGHTS_CTL_SINFO_TRANS));
|
|
|
|
p_env_ctlt->temp_tgt = temp_tgt;
|
|
p_env_ctlt->lvl_tgt = lvl;
|
|
|
|
// Start a new transition
|
|
mm_bind_trans_new(p_env_ctlt->env.grp_lid, trans_type, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
// Reject the transition
|
|
mm_bind_trans_reject(p_env_ctlt->env.grp_lid);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Register Light CTL Server, Light CTL Setup Server models on a given element and
|
|
* Light CTL Temperature Server model on next element
|
|
*
|
|
* @param[in] elmt_idx Element Index
|
|
* @param[in] p_mdl_lid Pointer to the variable in which allocated model local index
|
|
* will be written
|
|
*
|
|
* @return An error status (@see mesh_err)
|
|
****************************************************************************************
|
|
*/
|
|
__STATIC uint8_t mm_lights_ctls_register(uint8_t elmt_idx)
|
|
{
|
|
m_lid_t mdl_lid, ctls_lid, ctlt_lid;
|
|
|
|
// Register Light CTL Server model
|
|
mdl_lid = ms_register_model(MM_ID_LIGHTS_CTL, elmt_idx, MM_CFG_PUBLI_AUTH_BIT);
|
|
|
|
if (mdl_lid != MESH_INVALID_LID)
|
|
{
|
|
// Inform the Model State Manager about registered model
|
|
mm_lights_ctl_env_t *p_env_ctl = (mm_lights_ctl_env_t *)mm_state_register(elmt_idx, MM_ID_LIGHTS_CTL, mdl_lid,
|
|
MM_ROLE_SRV_PUBLI, sizeof(mm_lights_ctl_env_t));
|
|
|
|
if (p_env_ctl)
|
|
{
|
|
// Get server-specific callback functions
|
|
//p_cb_srv = p_env_ctl->env.cb.u.p_cb_srv;
|
|
|
|
// Prepare environment for Replay Manager
|
|
p_env_ctl->replay_env.delay_ms = MM_LIGHTS_CTL_REPLAY_MS;
|
|
|
|
// Prepare timer for publications
|
|
p_env_ctl->tmr_publi.cb = mm_lights_ctl_cb_tmr_publi;
|
|
//p_env_ctl->tmr_publi.p_env = (void *)p_env_ctl;
|
|
|
|
// Set internal callback functions
|
|
p_env_ctl->env.mdl_cb.cb_rx = mm_lights_ctl_cb_rx;
|
|
p_env_ctl->env.mdl_cb.cb_opcode_check = mm_lights_ctl_cb_opcode_check;
|
|
//p_env_ctl->env.mdl_cb.cb_publish_param = mm_lights_ctl_cb_publish_param;
|
|
//p_cb_srv->cb_set = mm_lights_ctl_cb_set;
|
|
p_env_ctl->env.mdl_cb.cb_srv_set = mm_lights_ctl_cb_set;
|
|
|
|
// Inform application about registered model
|
|
mm_register_ind_send(MM_ID_LIGHTS_CTL, elmt_idx, mdl_lid);
|
|
}
|
|
|
|
// Register Light CTL Setup Server model
|
|
ctls_lid = ms_register_model(MM_ID_LIGHTS_CTLS, elmt_idx, 0);
|
|
|
|
if (ctls_lid != MESH_INVALID_LID)
|
|
{
|
|
// Inform the Model State Manager about registered model
|
|
mm_lights_ctls_env_t *p_env_ctls = (mm_lights_ctls_env_t *)mm_state_register(elmt_idx, MM_ID_LIGHTS_CTLS, ctls_lid,
|
|
MM_ROLE_SRV, sizeof(mm_lights_ctls_env_t));
|
|
|
|
if (p_env_ctls)
|
|
{
|
|
// Set internal callback functions
|
|
p_env_ctls->env.mdl_cb.cb_rx = mm_lights_ctl_cb_rx;
|
|
p_env_ctls->env.mdl_cb.cb_opcode_check = mm_lights_ctl_cb_opcode_check;
|
|
|
|
// Link environment
|
|
p_env_ctls->p_env_ctl = p_env_ctl;
|
|
|
|
// Inform application about registered model
|
|
mm_register_ind_send(MM_ID_LIGHTS_CTLS, elmt_idx, ctls_lid);
|
|
}
|
|
}
|
|
|
|
// Register Light CTL Temperature Server model
|
|
ctlt_lid = ms_register_model(MM_ID_LIGHTS_CTLT, elmt_idx + 1, MM_CFG_PUBLI_AUTH_BIT);
|
|
|
|
if (ctlt_lid != MESH_INVALID_LID)
|
|
{
|
|
// Inform the Model State Manager about registered model
|
|
mm_lights_ctlt_env_t *p_env_ctlt = (mm_lights_ctlt_env_t *)mm_state_register(elmt_idx + 1, MM_ID_LIGHTS_CTLT, ctlt_lid,
|
|
MM_ROLE_SRV_PUBLI, sizeof(mm_lights_ctlt_env_t));
|
|
|
|
if (p_env_ctlt)
|
|
{
|
|
// Get server-specific callback functions
|
|
//p_cb_srv = p_env_ctlt->env.cb.u.p_cb_srv;
|
|
|
|
// Set initial range
|
|
p_env_ctlt->temp_min = MM_LIGHTS_CTL_TEMP_MIN;
|
|
p_env_ctlt->temp_max = MM_LIGHTS_CTL_TEMP_MAX;
|
|
|
|
// And initial value
|
|
p_env_ctlt->temp = MM_LIGHTS_CTL_TEMP_MIN;
|
|
|
|
// Prepare timer for publications
|
|
p_env_ctlt->tmr_publi.cb = mm_lights_ctl_cb_tmr_publi;
|
|
//p_env_ctlt->tmr_publi.p_env = (void *)p_env_ctlt;
|
|
|
|
// Set internal callback functions
|
|
p_env_ctlt->env.mdl_cb.cb_rx = mm_lights_ctl_cb_rx;
|
|
p_env_ctlt->env.mdl_cb.cb_opcode_check = mm_lights_ctl_cb_opcode_check;
|
|
//p_env_ctlt->env.mdl_cb.cb_publish_param = mm_lights_ctl_cb_publish_param;
|
|
//p_cb_srv->cb_set = mm_lights_ctl_cb_set;
|
|
p_env_ctlt->env.mdl_cb.cb_srv_set = mm_lights_ctl_cb_set;
|
|
|
|
// Inform application about registered model
|
|
mm_register_ind_send(MM_ID_LIGHTS_CTLT, elmt_idx + 1, ctlt_lid);
|
|
|
|
// Bound models together
|
|
p_env_ctlt->p_env_ctl = p_env_ctl;
|
|
p_env_ctl->p_env_ctlt = p_env_ctlt;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (mdl_lid);
|
|
}
|
|
|
|
/*
|
|
* GLOBAL FUNCTIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
uint8_t mm_lights_ctl_register(uint8_t elmt_idx, bool main)
|
|
{
|
|
m_lid_t mdl_lid = MESH_INVALID_LID;
|
|
|
|
do
|
|
{
|
|
// Model local index for Light CTL Server model and for Light CTL Tempereture Server model
|
|
// and for Light Lightness Server model
|
|
m_lid_t ln_lid, lvl1_lid, ctl_lid, ctlt_lid;
|
|
|
|
// Register Light Lightness Server model and associated models
|
|
ln_lid = mm_lights_ln_register(elmt_idx, false);
|
|
if (ln_lid == MESH_INVALID_LID)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Register Generic Level Server model
|
|
lvl1_lid = mm_gens_lvl_register(elmt_idx + 1, false);
|
|
if (lvl1_lid == MESH_INVALID_LID)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Register the Light CTL Server model and associated models
|
|
ctl_lid = mm_lights_ctls_register(elmt_idx);
|
|
|
|
if (main && (ctl_lid != MESH_INVALID_LID))
|
|
{
|
|
mdl_lid = ctl_lid;
|
|
ctlt_lid = ctl_lid + 2;
|
|
|
|
// Create group and set Light CTL Server model as main model
|
|
m_lid_t grp_lid = mm_bind_add_group(3, elmt_idx, ctl_lid,
|
|
mm_lights_ctl_cb_grp_event, mm_lights_ctl_cb_trans_req);
|
|
|
|
// Add Generic Level Server model to the group
|
|
mm_gens_lvl_bind_group(grp_lid, mm_state_get_lid(elmt_idx, MM_ID_GENS_LVL));
|
|
// Add Generic OnOff Server model to the group
|
|
mm_gens_oo_bind_group(grp_lid, mm_state_get_lid(elmt_idx, MM_ID_GENS_OO));
|
|
// Add Light Lightness Server model to the group
|
|
mm_lights_ln_bind_group(grp_lid, ln_lid);
|
|
|
|
// Create group and set Light CTL Temperature Server model as main model
|
|
grp_lid = mm_bind_add_group(1, elmt_idx + 1, ctlt_lid,
|
|
mm_lights_ctl_cb_grp_event_temp, mm_lights_ctl_cb_trans_req_temp);
|
|
|
|
// Add Generic Level Server model to the group
|
|
mm_gens_lvl_bind_group(grp_lid, lvl1_lid);
|
|
|
|
}
|
|
} while (0);
|
|
|
|
return (mdl_lid);
|
|
}
|
|
|
|
/// @} end of group
|