436 lines
12 KiB
C
436 lines
12 KiB
C
#include "system/includes.h"
|
|
#include "api/sig_mesh_api.h"
|
|
#include "api/gen_ponoff.h"
|
|
#include "api/gen_ponoff_srv.h"
|
|
#include "model_api.h"
|
|
#include "model_types.h"
|
|
#include "model_utils.h"
|
|
|
|
#define LOG_TAG "[Gen_Level]"
|
|
#define LOG_ERROR_ENABLE
|
|
#define LOG_DEBUG_ENABLE
|
|
#define LOG_INFO_ENABLE
|
|
/* #define LOG_DUMP_ENABLE */
|
|
#define LOG_CLI_ENABLE
|
|
#include "debug.h"
|
|
|
|
#if (CONFIG_BT_MESH_PONOFF_SRV)
|
|
/** Persistent storage handling */
|
|
struct ponoff_settings_data {
|
|
uint8_t on_power_up;
|
|
bool on_off;
|
|
} __attribute__((__packed__));
|
|
|
|
#if CONFIG_BT_SETTINGS
|
|
static int store_data(struct bt_mesh_ponoff_srv *srv,
|
|
const struct bt_mesh_onoff_status *onoff_status)
|
|
{
|
|
struct ponoff_settings_data data;
|
|
ssize_t size;
|
|
|
|
data.on_power_up = (uint8_t)srv->on_power_up;
|
|
|
|
switch (srv->on_power_up) {
|
|
case BT_MESH_ON_POWER_UP_OFF:
|
|
data.on_off = false;
|
|
break;
|
|
case BT_MESH_ON_POWER_UP_ON:
|
|
data.on_off = true;
|
|
break;
|
|
case BT_MESH_ON_POWER_UP_RESTORE:
|
|
data.on_off = onoff_status->remaining_time > 0 ?
|
|
onoff_status->target_on_off :
|
|
onoff_status->present_on_off;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Models that extend Generic Power OnOff Setup Server and, which states are
|
|
* bound with Generic OnOff state, store the value of the bound state
|
|
* separately, therefore they don't need to store Generic OnOff state.
|
|
*/
|
|
if (bt_mesh_model_is_extended(srv->ponoff_setup_model)) {
|
|
size = sizeof(data.on_power_up);
|
|
} else {
|
|
size = sizeof(data);
|
|
}
|
|
|
|
return bt_mesh_model_data_store(srv->ponoff_model, false, NULL, &data,
|
|
size);
|
|
|
|
}
|
|
|
|
static void bt_mesh_ponoff_srv_pending_store(struct bt_mesh_model *model)
|
|
{
|
|
int err;
|
|
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
|
|
struct bt_mesh_onoff_status onoff_status = {0};
|
|
|
|
if (!bt_mesh_model_is_extended(srv->ponoff_setup_model)) {
|
|
srv->onoff.handlers->get(&srv->onoff, NULL, &onoff_status);
|
|
}
|
|
|
|
err = store_data(srv, &onoff_status);
|
|
|
|
if (err) {
|
|
LOG_ERR("Failed storing data: %d", err);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void store_state(struct bt_mesh_ponoff_srv *srv)
|
|
{
|
|
#if CONFIG_BT_SETTINGS
|
|
bt_mesh_model_data_store_schedule(srv->ponoff_model);
|
|
#endif
|
|
}
|
|
|
|
static void send_rsp(struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
|
|
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_PONOFF_OP_STATUS,
|
|
BT_MESH_PONOFF_MSG_LEN_STATUS);
|
|
bt_mesh_model_msg_init(&msg, BT_MESH_PONOFF_OP_STATUS);
|
|
net_buf_simple_add_u8(&msg, srv->on_power_up);
|
|
bt_mesh_model_send(model, ctx, &msg, NULL, NULL);
|
|
}
|
|
|
|
static int handle_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
send_rsp(model, ctx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void set_on_power_up(struct bt_mesh_ponoff_srv *srv,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
enum bt_mesh_on_power_up new)
|
|
{
|
|
if (new == srv->on_power_up) {
|
|
return;
|
|
}
|
|
|
|
enum bt_mesh_on_power_up old = srv->on_power_up;
|
|
|
|
srv->on_power_up = new;
|
|
|
|
bt_mesh_model_msg_init(srv->ponoff_model->pub->msg,
|
|
BT_MESH_PONOFF_OP_STATUS);
|
|
net_buf_simple_add_u8(srv->ponoff_model->pub->msg, srv->on_power_up);
|
|
|
|
if (srv->update) {
|
|
srv->update(srv, ctx, old, new);
|
|
}
|
|
|
|
store_state(srv);
|
|
}
|
|
|
|
static int handle_set_msg(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf, bool ack)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
enum bt_mesh_on_power_up new = net_buf_simple_pull_u8(buf);
|
|
|
|
if (new >= BT_MESH_ON_POWER_UP_INVALID) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
set_on_power_up(srv, ctx, new);
|
|
|
|
if (ack) {
|
|
send_rsp(model, ctx);
|
|
}
|
|
|
|
(void)bt_mesh_ponoff_srv_pub(srv, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
return handle_set_msg(model, ctx, buf, true);
|
|
}
|
|
|
|
static int handle_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
return handle_set_msg(model, ctx, buf, false);
|
|
}
|
|
|
|
/* Need to intercept the onoff state to get the right value on power up. */
|
|
static void onoff_intercept_set(struct bt_mesh_onoff_srv *onoff_srv,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
const struct bt_mesh_onoff_set *set,
|
|
struct bt_mesh_onoff_status *status)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv =
|
|
CONTAINER_OF(onoff_srv, struct bt_mesh_ponoff_srv, onoff);
|
|
|
|
srv->onoff_handlers->set(onoff_srv, ctx, set, status);
|
|
|
|
if ((srv->on_power_up == BT_MESH_ON_POWER_UP_RESTORE) &&
|
|
!bt_mesh_model_is_extended(srv->ponoff_setup_model)) {
|
|
store_state(srv);
|
|
}
|
|
}
|
|
|
|
static void onoff_intercept_get(struct bt_mesh_onoff_srv *onoff_srv,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct bt_mesh_onoff_status *out)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv =
|
|
CONTAINER_OF(onoff_srv, struct bt_mesh_ponoff_srv, onoff);
|
|
|
|
srv->onoff_handlers->get(onoff_srv, ctx, out);
|
|
}
|
|
|
|
const struct bt_mesh_model_op _bt_mesh_ponoff_srv_op[] = {
|
|
{
|
|
BT_MESH_PONOFF_OP_GET,
|
|
BT_MESH_LEN_EXACT(BT_MESH_PONOFF_MSG_LEN_GET),
|
|
handle_get,
|
|
},
|
|
BT_MESH_MODEL_OP_END,
|
|
};
|
|
|
|
const struct bt_mesh_model_op _bt_mesh_ponoff_setup_srv_op[] = {
|
|
{
|
|
BT_MESH_PONOFF_OP_SET,
|
|
BT_MESH_LEN_EXACT(BT_MESH_PONOFF_MSG_LEN_SET),
|
|
handle_set,
|
|
},
|
|
{
|
|
BT_MESH_PONOFF_OP_SET_UNACK,
|
|
BT_MESH_LEN_EXACT(BT_MESH_PONOFF_MSG_LEN_SET),
|
|
handle_set_unack,
|
|
},
|
|
BT_MESH_MODEL_OP_END,
|
|
};
|
|
|
|
const struct bt_mesh_onoff_srv_handlers _bt_mesh_ponoff_onoff_intercept = {
|
|
.set = onoff_intercept_set,
|
|
.get = onoff_intercept_get,
|
|
};
|
|
|
|
static ssize_t scene_store(struct bt_mesh_model *model, uint8_t data[])
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
struct bt_mesh_onoff_status status = { 0 };
|
|
|
|
/* Only store the next stable on_off state: */
|
|
srv->onoff_handlers->get(&srv->onoff, NULL, &status);
|
|
data[0] = status.remaining_time ? status.target_on_off :
|
|
status.present_on_off;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void scene_recall(struct bt_mesh_model *model, const uint8_t data[],
|
|
size_t len, struct bt_mesh_model_transition *transition)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
struct bt_mesh_onoff_status status = { 0 };
|
|
struct bt_mesh_onoff_set set = {
|
|
.on_off = data[0],
|
|
.transition = transition,
|
|
};
|
|
|
|
srv->onoff_handlers->set(&srv->onoff, NULL, &set, &status);
|
|
}
|
|
|
|
static void scene_recall_complete(struct bt_mesh_model *model)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
struct bt_mesh_onoff_status status = { 0 };
|
|
|
|
srv->onoff_handlers->get(&srv->onoff, NULL, &status);
|
|
|
|
(void)bt_mesh_onoff_srv_pub(&srv->onoff, NULL, &status);
|
|
}
|
|
|
|
/* MeshMDL1.0.1, section 5.1.3.1.1:
|
|
* If a model is extending another model, the extending model shall determine
|
|
* the Stored with Scene behavior of that model.
|
|
*
|
|
* Use Setup Model to handle Scene Store/Recall as it is not extended
|
|
* by other models.
|
|
*/
|
|
// BT_MESH_SCENE_ENTRY_SIG(ponoff) = {
|
|
// .id.sig = BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV,
|
|
// .maxlen = 1,
|
|
// .store = scene_store,
|
|
// .recall = scene_recall,
|
|
// .recall_complete = scene_recall_complete,
|
|
// };
|
|
|
|
const struct bt_mesh_scene_entry bt_mesh_scene_entry_sig_ponoff = {
|
|
.id.sig = BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV,
|
|
.maxlen = 1,
|
|
.store = scene_store,
|
|
.recall = scene_recall,
|
|
.recall_complete = scene_recall_complete,
|
|
};
|
|
|
|
|
|
static int update_handler(struct bt_mesh_model *model)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
|
|
bt_mesh_model_msg_init(srv->ponoff_model->pub->msg,
|
|
BT_MESH_PONOFF_OP_STATUS);
|
|
net_buf_simple_add_u8(srv->ponoff_model->pub->msg, srv->on_power_up);
|
|
return 0;
|
|
}
|
|
|
|
static int bt_mesh_ponoff_srv_init(struct bt_mesh_model *model)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
|
|
srv->ponoff_model = model;
|
|
srv->pub.msg = &srv->pub_buf;
|
|
srv->pub.update = update_handler;
|
|
net_buf_simple_init_with_data(&srv->pub_buf, srv->pub_data,
|
|
sizeof(srv->pub_data));
|
|
#if CONFIG_BT_MESH_MODEL_EXTENSIONS
|
|
return bt_mesh_model_extend(model, srv->onoff.model);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static void bt_mesh_ponoff_srv_reset(struct bt_mesh_model *model)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
|
|
srv->on_power_up = BT_MESH_ON_POWER_UP_OFF;
|
|
net_buf_simple_reset(srv->pub.msg);
|
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
(void)bt_mesh_model_data_store(srv->ponoff_model, false, NULL,
|
|
NULL, 0);
|
|
}
|
|
}
|
|
|
|
//for compiler, not used now.
|
|
#if 0
|
|
static int bt_mesh_ponoff_srv_settings_set(struct bt_mesh_model *model,
|
|
const char *name,
|
|
size_t len_rd,
|
|
settings_read_cb read_cb,
|
|
void *cb_arg)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
struct bt_mesh_onoff_status dummy;
|
|
struct ponoff_settings_data data;
|
|
ssize_t size = MIN(len_rd, sizeof(data));
|
|
|
|
if (name) {
|
|
return -ENOENT;
|
|
}
|
|
|
|
if (read_cb(cb_arg, &data, size) != size) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
set_on_power_up(srv, NULL, (enum bt_mesh_on_power_up)data.on_power_up);
|
|
|
|
/* Models that extend Generic Power OnOff Setup Server and, which states are
|
|
* bound with Generic OnOff state, store the value of the bound state
|
|
* separately, therefore they don't need to set Generic OnOff state.
|
|
*/
|
|
if (bt_mesh_model_is_extended(srv->ponoff_setup_model)) {
|
|
return 0;
|
|
}
|
|
|
|
struct bt_mesh_onoff_set onoff_set = { .transition = NULL };
|
|
|
|
switch (data.on_power_up) {
|
|
case BT_MESH_ON_POWER_UP_OFF:
|
|
onoff_set.on_off = false;
|
|
break;
|
|
case BT_MESH_ON_POWER_UP_ON:
|
|
onoff_set.on_off = true;
|
|
break;
|
|
case BT_MESH_ON_POWER_UP_RESTORE:
|
|
onoff_set.on_off = data.on_off;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
srv->onoff.handlers->set(&srv->onoff, NULL, &onoff_set, &dummy);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
const struct bt_mesh_model_cb _bt_mesh_ponoff_srv_cb = {
|
|
.init = bt_mesh_ponoff_srv_init,
|
|
.reset = bt_mesh_ponoff_srv_reset,
|
|
// for compiler, not used now.
|
|
#if 0
|
|
.settings_set = bt_mesh_ponoff_srv_settings_set,
|
|
.pending_store = bt_mesh_ponoff_srv_pending_store,
|
|
#endif
|
|
};
|
|
|
|
static int bt_mesh_ponoff_setup_srv_init(struct bt_mesh_model *model)
|
|
{
|
|
struct bt_mesh_ponoff_srv *srv = model->rt->user_data;
|
|
int err;
|
|
|
|
srv->ponoff_setup_model = model;
|
|
#if CONFIG_BT_MESH_MODEL_EXTENSIONS
|
|
err = bt_mesh_model_extend(model, srv->ponoff_model);
|
|
#else
|
|
err = 0;
|
|
#endif
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
#if CONFIG_BT_MESH_COMP_PAGE_1
|
|
err = bt_mesh_model_correspond(model, srv->ponoff_model);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
#endif
|
|
#if CONFIG_BT_MESH_MODEL_EXTENSIONS
|
|
return bt_mesh_model_extend(model, srv->dtt.model);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
const struct bt_mesh_model_cb _bt_mesh_ponoff_setup_srv_cb = {
|
|
.init = bt_mesh_ponoff_setup_srv_init,
|
|
};
|
|
|
|
void bt_mesh_ponoff_srv_set(struct bt_mesh_ponoff_srv *srv,
|
|
enum bt_mesh_on_power_up on_power_up)
|
|
{
|
|
set_on_power_up(srv, NULL, on_power_up);
|
|
|
|
(void)bt_mesh_ponoff_srv_pub(srv, NULL);
|
|
}
|
|
|
|
int bt_mesh_ponoff_srv_pub(struct bt_mesh_ponoff_srv *srv,
|
|
struct bt_mesh_msg_ctx *ctx)
|
|
{
|
|
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_PONOFF_OP_STATUS,
|
|
BT_MESH_PONOFF_MSG_LEN_STATUS);
|
|
bt_mesh_model_msg_init(&msg, BT_MESH_PONOFF_OP_STATUS);
|
|
net_buf_simple_add_u8(&msg, srv->on_power_up);
|
|
|
|
return bt_mesh_msg_send(srv->ponoff_model, ctx, &msg);
|
|
}
|
|
|
|
|
|
|
|
#endif |