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     /* No optional fields are available */
133     if (buf->len == 0x00) {
134         if (model->id == BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
135             /**
136              * Both messages(i.e. Light LC OnOff Set/Set Unack) may optionally include
137              * a Transition Time field indicating the transition time to the target state.
138              * If the Transition Time is not included, the Light LC Server shall use
139              * its appropriate transition times defined by the Light LC Property states.
140              */
141             if (bt_mesh_get_light_lc_trans_time(model, trans_time)) {
142                 BT_ERR("Failed to get Light LC transition time");
143                 return -EIO;
144             }
145         } else {
146             *trans_time = bt_mesh_get_default_trans_time(model);
147         }
148         *delay = 0U;
149         *optional = false;
150         return 0;
151     }
152 
153     /* Optional fields are available */
154     *trans_time = net_buf_simple_pull_u8(buf);
155     if ((*trans_time & 0x3F) == 0x3F) {
156         BT_ERR("Invalid Transaction Number of Steps 0x3f");
157         return -EINVAL;
158     }
159 
160     *delay = net_buf_simple_pull_u8(buf);
161     *optional = true;
162     return 0;
163 }
164 
bt_mesh_server_alloc_ctx(struct k_work * work)165 void bt_mesh_server_alloc_ctx(struct k_work *work)
166 {
167     /**
168      * This function is used to allocate memory for storing "struct bt_mesh_msg_ctx"
169      * of the received messages, because some server models will callback the "struct
170      * bt_mesh_msg_ctx" info to the application layer after a certain delay.
171      * Here we use the allocated heap memory to store the "struct bt_mesh_msg_ctx".
172      */
173     __ASSERT(work, "Invalid parameter");
174     if (!work->_reserved) {
175         work->_reserved = bt_mesh_calloc(sizeof(struct bt_mesh_msg_ctx));
176         __ASSERT(work->_reserved, "Out of memory");
177     }
178 }
179 
180 #if CONFIG_BLE_MESH_DEINIT
bt_mesh_server_free_ctx(struct k_work * work)181 void bt_mesh_server_free_ctx(struct k_work *work)
182 {
183     __ASSERT(work, "Invalid parameter");
184     if (work->_reserved) {
185         bt_mesh_free(work->_reserved);
186         work->_reserved = NULL;
187     }
188 }
189 #endif /* CONFIG_BLE_MESH_DEINIT */
190 
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)191 bool bt_mesh_is_server_recv_last_msg(struct bt_mesh_last_msg_info *last,
192                                      uint8_t tid, uint16_t src, uint16_t dst, int64_t *now)
193 {
194     *now = k_uptime_get();
195 
196     /* Currently we only compare msg info which dst is set to a unicast address */
197     if (!BLE_MESH_ADDR_IS_UNICAST(dst)) {
198         return false;
199     }
200 
201     if (last->tid == tid && last->src == src && last->dst == dst &&
202             (*now - last->timestamp <= K_SECONDS(6))) {
203         return true;
204     }
205 
206     return false;
207 }
208 
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)209 void bt_mesh_server_update_last_msg(struct bt_mesh_last_msg_info *last,
210                                     uint8_t tid, uint16_t src, uint16_t dst, int64_t *now)
211 {
212     /* Currently we only update msg info which dst is set to a unicast address */
213     if (!BLE_MESH_ADDR_IS_UNICAST(dst)) {
214         return;
215     }
216 
217     last->tid = tid;
218     last->src = src;
219     last->dst = dst;
220     last->timestamp = *now;
221     return;
222 }
223 
bt_mesh_server_get_pub_msg(struct bt_mesh_model * model,uint16_t msg_len)224 struct net_buf_simple *bt_mesh_server_get_pub_msg(struct bt_mesh_model *model, uint16_t msg_len)
225 {
226     struct net_buf_simple *buf = NULL;
227 
228     if (model == NULL) {
229         BT_ERR("%s, Invalid parameter", __func__);
230         return NULL;
231     }
232 
233     if (model->pub == NULL || model->pub->msg == NULL ||
234             model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) {
235         BT_DBG("No publication support, model id 0x%04x", model->id);
236         return NULL;
237     }
238 
239     buf = model->pub->msg;
240     if (buf->size < msg_len) {
241         BT_ERR("Too small publication msg size %d, model id 0x%04x",
242                 buf->size, model->id);
243         return NULL;
244     }
245 
246     return buf;
247 }
248 
249 #endif /* CONFIG_BLE_MESH_SERVER_MODEL */
250