1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8
9 #include "mesh.h"
10 #include "mesh_config.h"
11 #include "access.h"
12 #include "mesh_common.h"
13 #include "generic_server.h"
14 #include "lighting_server.h"
15
16 #if CONFIG_BLE_MESH_SERVER_MODEL
17
18 /**
19 * According to Mesh Model Spec:
20 * If the Transition Time field is not present and the Generic Default Transition
21 * Time state is supported, the Generic Default Transition Time state shall be
22 * used. Otherwise the transition shall be instantaneous.
23 */
24 #define INSTANTANEOUS_TRANS_TIME 0
25
bt_mesh_get_default_trans_time(struct bt_mesh_model * model)26 uint8_t bt_mesh_get_default_trans_time(struct bt_mesh_model *model)
27 {
28 /**
29 * 1. If a Generic Default Transition Time Server model is present on the
30 * main element of the model, that model instance shall be used.
31 * 2. If a Generic Default Transition Time Server model is not present on
32 * the main element of the model, then the Generic Default Transition
33 * Time Server model instance that is present on the element with the
34 * largest address that is smaller than the address of the main element
35 * of the node shall be used; if no model instance is present on any
36 * element with an address smaller than the address of the main element,
37 * then the Generic Default Transition Time Server is not supported.
38 */
39 struct bt_mesh_elem *element = bt_mesh_model_elem(model);
40 struct bt_mesh_gen_def_trans_time_srv *state = NULL;
41 uint16_t primary_addr = bt_mesh_primary_addr();
42 struct bt_mesh_model *srv = NULL;
43
44 for (uint16_t addr = element->addr; addr >= primary_addr; addr--) {
45 element = bt_mesh_elem_find(addr);
46 if (element) {
47 srv = bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV);
48 if (srv) {
49 state = (struct bt_mesh_gen_def_trans_time_srv *)srv->user_data;
50 if (state) {
51 return state->state.trans_time;
52 }
53 }
54 }
55 }
56
57 return INSTANTANEOUS_TRANS_TIME;
58 }
59
bt_mesh_get_light_lc_trans_time(struct bt_mesh_model * model,uint8_t * trans_time)60 int bt_mesh_get_light_lc_trans_time(struct bt_mesh_model *model, uint8_t *trans_time)
61 {
62 struct bt_mesh_light_lc_srv *srv = NULL;
63 uint32_t value = 0U;
64
65 if (model == NULL || trans_time == NULL) {
66 BT_ERR("%s, Invalid parameter", __func__);
67 return -EINVAL;
68 }
69
70 if (model->id != BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
71 BT_ERR("Invalid a Light LC Server 0x%04x", model->id);
72 return -EINVAL;
73 }
74
75 srv = (struct bt_mesh_light_lc_srv *)model->user_data;
76 if (srv == NULL) {
77 BT_ERR("Invalid Light LC Server user data");
78 return -EINVAL;
79 }
80
81 /**
82 * 1. Set transition time to 0x54 for BQB test case MESH/SR/LLC/BV-04-C.
83 * Light LC Property Set: 0x3C, 0x004E20 -> Light LC Time Run On
84 * Light LC Property Set: 0x37, 0x004E20 -> Light LC Time Fade On
85 * Light LC Property Set: 0x39, 0x004E20 -> Light LC Time Fade Standby Manual
86 *
87 * 2. Set transition time to 0x0 for BQB test case MESH/SR/LLC/BV-08-C.
88 *
89 * TODO: Based on Light LC state and choose property property value as the
90 * transition time. Currently directly use Light LC Time Run On property value.
91 * Unit: Millisecond, range: [0, 16777214(0xFFFFFE)]
92 */
93 value = srv->lc->prop_state.time_run_on & 0xFFFFFF;
94
95 /**
96 * Convert value into Default Transition Time state format.
97 * 0b00: 0 ~ 6.2s, 100 millisecond step resolution
98 * 0b01: 0 ~ 62s, 1 second step resolution
99 * 0b10: 0 ~ 620s, 10 seconds step resolution
100 * 0b11: 0 ~ 620m, 10 minutes step resolution
101 */
102 if (value <= 6200) {
103 *trans_time = (0 << 6) | (value / 100);
104 } else if (value <= 62000) {
105 *trans_time = (1 << 6) | (value / 1000);
106 } else if (value <= 620000) {
107 *trans_time = (2 << 6) | (value / 10000);
108 } else {
109 *trans_time = (3 << 6) | (value / 600000);
110 }
111
112 return 0;
113 }
114
bt_mesh_server_get_optional(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf,uint8_t * trans_time,uint8_t * delay,bool * optional)115 int bt_mesh_server_get_optional(struct bt_mesh_model *model,
116 struct bt_mesh_msg_ctx *ctx,
117 struct net_buf_simple *buf,
118 uint8_t *trans_time, uint8_t *delay,
119 bool *optional)
120 {
121 if (model == NULL || buf == NULL || trans_time == NULL ||
122 delay == NULL || optional == NULL) {
123 BT_ERR("%s, Invalid parameter", __func__);
124 return -EINVAL;
125 }
126
127 if (buf->len != 0x00 && buf->len != 0x02) {
128 BT_ERR("Invalid optional message length %d", buf->len);
129 return -EINVAL;
130 }
131
132 /* Currently we only get optional msg info which dst is set to a unicast address */
133 if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) {
134 *trans_time = 0U;
135 *delay = 0U;
136 *optional = false;
137 return 0;
138 }
139
140 /* No optional fields are available */
141 if (buf->len == 0x00) {
142 if (model->id == BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
143 /**
144 * Both messages(i.e. Light LC OnOff Set/Set Unack) may optionally include
145 * a Transition Time field indicating the transition time to the target state.
146 * If the Transition Time is not included, the Light LC Server shall use
147 * its appropriate transition times defined by the Light LC Property states.
148 */
149 if (bt_mesh_get_light_lc_trans_time(model, trans_time)) {
150 BT_ERR("Failed to get Light LC transition time");
151 return -EIO;
152 }
153 } else {
154 *trans_time = bt_mesh_get_default_trans_time(model);
155 }
156 *delay = 0U;
157 *optional = false;
158 return 0;
159 }
160
161 /* Optional fields are available */
162 *trans_time = net_buf_simple_pull_u8(buf);
163 if ((*trans_time & 0x3F) == 0x3F) {
164 BT_ERR("Invalid Transaction Number of Steps 0x3f");
165 return -EINVAL;
166 }
167
168 *delay = net_buf_simple_pull_u8(buf);
169 *optional = true;
170 return 0;
171 }
172
bt_mesh_server_alloc_ctx(struct k_work * work)173 void bt_mesh_server_alloc_ctx(struct k_work *work)
174 {
175 /**
176 * This function is used to allocate memory for storing "struct bt_mesh_msg_ctx"
177 * of the received messages, because some server models will callback the "struct
178 * bt_mesh_msg_ctx" info to the application layer after a certain delay.
179 * Here we use the allocated heap memory to store the "struct bt_mesh_msg_ctx".
180 */
181 __ASSERT(work, "Invalid parameter");
182 if (!work->_reserved) {
183 work->_reserved = bt_mesh_calloc(sizeof(struct bt_mesh_msg_ctx));
184 __ASSERT(work->_reserved, "Out of memory");
185 }
186 }
187
188 #if CONFIG_BLE_MESH_DEINIT
bt_mesh_server_free_ctx(struct k_work * work)189 void bt_mesh_server_free_ctx(struct k_work *work)
190 {
191 __ASSERT(work, "Invalid parameter");
192 if (work->_reserved) {
193 bt_mesh_free(work->_reserved);
194 work->_reserved = NULL;
195 }
196 }
197 #endif /* CONFIG_BLE_MESH_DEINIT */
198
bt_mesh_is_server_recv_last_msg(struct bt_mesh_last_msg_info * last,uint8_t tid,uint16_t src,uint16_t dst,int64_t * now)199 bool bt_mesh_is_server_recv_last_msg(struct bt_mesh_last_msg_info *last,
200 uint8_t tid, uint16_t src, uint16_t dst, int64_t *now)
201 {
202 *now = k_uptime_get();
203
204 /* Currently we only compare msg info which dst is set to a unicast address */
205 if (!BLE_MESH_ADDR_IS_UNICAST(dst)) {
206 return false;
207 }
208
209 if (last->tid == tid && last->src == src && last->dst == dst &&
210 (*now - last->timestamp <= K_SECONDS(6))) {
211 return true;
212 }
213
214 return false;
215 }
216
bt_mesh_server_update_last_msg(struct bt_mesh_last_msg_info * last,uint8_t tid,uint16_t src,uint16_t dst,int64_t * now)217 void bt_mesh_server_update_last_msg(struct bt_mesh_last_msg_info *last,
218 uint8_t tid, uint16_t src, uint16_t dst, int64_t *now)
219 {
220 /* Currently we only update msg info which dst is set to a unicast address */
221 if (!BLE_MESH_ADDR_IS_UNICAST(dst)) {
222 return;
223 }
224
225 last->tid = tid;
226 last->src = src;
227 last->dst = dst;
228 last->timestamp = *now;
229 return;
230 }
231
bt_mesh_server_get_pub_msg(struct bt_mesh_model * model,uint16_t msg_len)232 struct net_buf_simple *bt_mesh_server_get_pub_msg(struct bt_mesh_model *model, uint16_t msg_len)
233 {
234 struct net_buf_simple *buf = NULL;
235
236 if (model == NULL) {
237 BT_ERR("%s, Invalid parameter", __func__);
238 return NULL;
239 }
240
241 if (model->pub == NULL || model->pub->msg == NULL ||
242 model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) {
243 BT_DBG("No publication support, model id 0x%04x", model->id);
244 return NULL;
245 }
246
247 buf = model->pub->msg;
248 if (buf->size < msg_len) {
249 BT_ERR("Too small publication msg size %d, model id 0x%04x",
250 buf->size, model->id);
251 return NULL;
252 }
253
254 return buf;
255 }
256
257 #endif /* CONFIG_BLE_MESH_SERVER_MODEL */
258