state_binding.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
  2. *
  3. * Copyright (c) 2018 Vikrant More
  4. * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
  5. *
  6. * SPDX-License-Identifier: Apache-2.0
  7. */
  8. #include <errno.h>
  9. #include "model_opcode.h"
  10. #include "state_binding.h"
  11. #include "state_transition.h"
  12. #define MINDIFF (2.25e-308)
  13. static float bt_mesh_sqrt(float square)
  14. {
  15. float root = 0.0, last = 0.0, diff = 0.0;
  16. root = square / 3.0;
  17. diff = 1;
  18. if (square <= 0) {
  19. return 0;
  20. }
  21. do {
  22. last = root;
  23. root = (root + square / root) / 2.0;
  24. diff = root - last;
  25. } while (diff > MINDIFF || diff < -MINDIFF);
  26. return root;
  27. }
  28. static s32_t bt_mesh_ceiling(float num)
  29. {
  30. s32_t inum = (s32_t)num;
  31. if (num == (float)inum) {
  32. return inum;
  33. }
  34. return inum + 1;
  35. }
  36. u16_t bt_mesh_convert_lightness_actual_to_linear(u16_t actual)
  37. {
  38. float tmp = ((float) actual / UINT16_MAX);
  39. return bt_mesh_ceiling(UINT16_MAX * tmp * tmp);
  40. }
  41. u16_t bt_mesh_convert_lightness_linear_to_actual(u16_t linear)
  42. {
  43. return (u16_t) (UINT16_MAX * bt_mesh_sqrt(((float) linear / UINT16_MAX)));
  44. }
  45. s16_t bt_mesh_convert_temperature_to_gen_level(u16_t temp, u16_t min, u16_t max)
  46. {
  47. float tmp = (temp - min) * UINT16_MAX / (max - min);
  48. return (s16_t) (tmp + INT16_MIN);
  49. }
  50. u16_t bt_mesh_covert_gen_level_to_temperature(s16_t level, u16_t min, u16_t max)
  51. {
  52. float diff = (float) (max - min) / UINT16_MAX;
  53. u16_t tmp = (u16_t) ((level - INT16_MIN) * diff);
  54. return (u16_t) (min + tmp);
  55. }
  56. s16_t bt_mesh_convert_hue_to_level(u16_t hue)
  57. {
  58. return (s16_t) (hue + INT16_MIN);
  59. }
  60. u16_t bt_mesh_convert_level_to_hue(s16_t level)
  61. {
  62. return (u16_t) (level - INT16_MIN);
  63. }
  64. s16_t bt_mesh_convert_saturation_to_level(u16_t saturation)
  65. {
  66. return (s16_t) (saturation + INT16_MIN);
  67. }
  68. u16_t bt_mesh_convert_level_to_saturation(s16_t level)
  69. {
  70. return (u16_t) (level - INT16_MIN);
  71. }
  72. int bt_mesh_update_binding_state(struct bt_mesh_model *model,
  73. bt_mesh_server_state_type_t type,
  74. bt_mesh_server_state_value_t *value)
  75. {
  76. if (model == NULL || model->user_data == NULL ||
  77. value == NULL || type > BIND_STATE_MAX) {
  78. BT_ERR("%s, Invalid parameter", __func__);
  79. return -EINVAL;
  80. }
  81. switch (type) {
  82. case GENERIC_ONOFF_STATE: {
  83. if (model->id != BLE_MESH_MODEL_ID_GEN_ONOFF_SRV) {
  84. BT_ERR("%s, Not a Generic OnOff Server Model, id 0x%04x", __func__, model->id);
  85. return -EINVAL;
  86. }
  87. struct bt_mesh_gen_onoff_srv *srv = model->user_data;
  88. bt_mesh_server_stop_transition(&srv->transition);
  89. srv->state.onoff = value->gen_onoff.onoff;
  90. gen_onoff_publish(model);
  91. break;
  92. }
  93. case GENERIC_LEVEL_STATE: {
  94. if (model->id != BLE_MESH_MODEL_ID_GEN_LEVEL_SRV) {
  95. BT_ERR("%s, Not a Generic Level Server Model, id 0x%04x", __func__, model->id);
  96. return -EINVAL;
  97. }
  98. struct bt_mesh_gen_level_srv *srv = model->user_data;
  99. bt_mesh_server_stop_transition(&srv->transition);
  100. srv->state.level = value->gen_level.level;
  101. gen_level_publish(model);
  102. break;
  103. }
  104. case GENERIC_ONPOWERUP_STATE: {
  105. if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV) {
  106. BT_ERR("%s, Not a Generic Power OnOff Server Model, id 0x%04x", __func__, model->id);
  107. return -EINVAL;
  108. }
  109. struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
  110. if (srv->state == NULL) {
  111. BT_ERR("%s, Invalid Generic Power OnOff Server state", __func__);
  112. return -EINVAL;
  113. }
  114. srv->state->onpowerup = value->gen_onpowerup.onpowerup;
  115. gen_onpowerup_publish(model);
  116. break;
  117. }
  118. case GENERIC_POWER_ACTUAL_STATE: {
  119. if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
  120. BT_ERR("%s, Not a Generic Power Level Server Model, id 0x%04x", __func__, model->id);
  121. return -EINVAL;
  122. }
  123. struct bt_mesh_gen_power_level_srv *srv = model->user_data;
  124. if (srv->state == NULL) {
  125. BT_ERR("%s, Invalid Generic Power Level Server state", __func__);
  126. return -EINVAL;
  127. }
  128. bt_mesh_server_stop_transition(&srv->transition);
  129. srv->state->power_actual = value->gen_power_actual.power;
  130. /**
  131. * Whenever the Generic Power Actual state is changed to a non-zero value
  132. * as a result of a non-transactional message or a completed sequence of
  133. * transactional messages, the value of the Generic Power Last state shall
  134. * be set to the value of the Generic Power Actual state.
  135. */
  136. if (srv->state->power_actual) {
  137. srv->state->power_last = srv->state->power_actual;
  138. }
  139. gen_power_level_publish(model, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
  140. break;
  141. }
  142. case LIGHT_LIGHTNESS_ACTUAL_STATE: {
  143. if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
  144. BT_ERR("%s, Not a Light Lightness Server Model, id 0x%04x", __func__, model->id);
  145. return -EINVAL;
  146. }
  147. struct bt_mesh_light_lightness_srv *srv = model->user_data;
  148. if (srv->state == NULL) {
  149. BT_ERR("%s, Invalid Light Lightness Server state", __func__);
  150. return -EINVAL;
  151. }
  152. bt_mesh_server_stop_transition(&srv->actual_transition);
  153. srv->state->lightness_actual = value->light_lightness_actual.lightness;
  154. /**
  155. * Whenever the Light Lightness Actual state is changed with a non-transactional
  156. * message or a completed sequence of transactional messages to a non-zero value,
  157. * the value of the Light Lightness Last shall be set to the value of the Light
  158. * Lightness Actual.
  159. */
  160. if (srv->state->lightness_actual) {
  161. srv->state->lightness_last = srv->state->lightness_actual;
  162. }
  163. light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
  164. break;
  165. }
  166. case LIGHT_LIGHTNESS_LINEAR_STATE: {
  167. if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
  168. BT_ERR("%s, Not a Light Lightness Server Model, id 0x%04x", __func__, model->id);
  169. return -EINVAL;
  170. }
  171. struct bt_mesh_light_lightness_srv *srv = model->user_data;
  172. if (srv->state == NULL) {
  173. BT_ERR("%s, Invalid Light Lightness Server state", __func__);
  174. return -EINVAL;
  175. }
  176. bt_mesh_server_stop_transition(&srv->linear_transition);
  177. srv->state->lightness_linear = value->light_lightness_linear.lightness;
  178. light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
  179. break;
  180. }
  181. case LIGHT_CTL_LIGHTNESS_STATE: {
  182. if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_SRV) {
  183. BT_ERR("%s, Not a Light CTL Server Model, id 0x%04x", __func__, model->id);
  184. return -EINVAL;
  185. }
  186. struct bt_mesh_light_ctl_srv *srv = model->user_data;
  187. if (srv->state == NULL) {
  188. BT_ERR("%s, Invalid Light CTL Server state", __func__);
  189. return -EINVAL;
  190. }
  191. bt_mesh_server_stop_transition(&srv->transition);
  192. srv->state->lightness = value->light_ctl_lightness.lightness;
  193. light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
  194. break;
  195. }
  196. case LIGHT_CTL_TEMP_DELTA_UV_STATE: {
  197. if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV) {
  198. BT_ERR("%s, Not a Light CTL Temperature Server Model, id 0x%04x", __func__, model->id);
  199. return -EINVAL;
  200. }
  201. struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
  202. if (srv->state == NULL) {
  203. BT_ERR("%s, Invalid Light CTL Temperature Server state", __func__);
  204. return -EINVAL;
  205. }
  206. bt_mesh_server_stop_transition(&srv->transition);
  207. srv->state->temperature = value->light_ctl_temp_delta_uv.temperature;
  208. srv->state->delta_uv = value->light_ctl_temp_delta_uv.delta_uv;
  209. light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
  210. break;
  211. }
  212. case LIGHT_HSL_LIGHTNESS_STATE: {
  213. if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
  214. BT_ERR("%s, Not a Light HSL Server Model, id 0x%04x", __func__, model->id);
  215. return -EINVAL;
  216. }
  217. struct bt_mesh_light_hsl_srv *srv = model->user_data;
  218. if (srv->state == NULL) {
  219. BT_ERR("%s, Invalid Light HSL Server state", __func__);
  220. return -EINVAL;
  221. }
  222. bt_mesh_server_stop_transition(&srv->transition);
  223. srv->state->lightness = value->light_hsl_lightness.lightness;
  224. light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
  225. break;
  226. }
  227. case LIGHT_HSL_HUE_STATE: {
  228. if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV) {
  229. BT_ERR("%s, Not a Light HSL Hue Server Model, id 0x%04x", __func__, model->id);
  230. return -EINVAL;
  231. }
  232. struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
  233. if (srv->state == NULL) {
  234. BT_ERR("%s, Invalid Light HSL Hue Server state", __func__);
  235. return -EINVAL;
  236. }
  237. bt_mesh_server_stop_transition(&srv->transition);
  238. srv->state->hue = value->light_hsl_hue.hue;
  239. light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
  240. break;
  241. }
  242. case LIGHT_HSL_SATURATION_STATE: {
  243. if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV) {
  244. BT_ERR("%s, Not a Light HSL Saturation Server Model, id 0x%04x", __func__, model->id);
  245. return -EINVAL;
  246. }
  247. struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
  248. if (srv->state == NULL) {
  249. BT_ERR("%s, Invalid Light HSL Saturation Server state", __func__);
  250. return -EINVAL;
  251. }
  252. bt_mesh_server_stop_transition(&srv->transition);
  253. srv->state->saturation = value->light_hsl_saturation.saturation;
  254. light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
  255. break;
  256. }
  257. case LIGHT_XYL_LIGHTNESS_STATE: {
  258. if (model->id != BLE_MESH_MODEL_ID_LIGHT_XYL_SRV) {
  259. BT_ERR("%s, Not a Light xyL Server Model, id 0x%04x", __func__, model->id);
  260. return -EINVAL;
  261. }
  262. struct bt_mesh_light_xyl_srv *srv = model->user_data;
  263. if (srv->state == NULL) {
  264. BT_ERR("%s, Invalid Light xyL Server state", __func__);
  265. return -EINVAL;
  266. }
  267. bt_mesh_server_stop_transition(&srv->transition);
  268. srv->state->lightness = value->light_xyl_lightness.lightness;
  269. light_xyl_publish(model, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
  270. break;
  271. }
  272. case LIGHT_LC_LIGHT_ONOFF_STATE: {
  273. if (model->id != BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
  274. BT_ERR("%s, Not a Light LC Server Model, id 0x%04x", __func__, model->id);
  275. return -EINVAL;
  276. }
  277. struct bt_mesh_light_lc_srv *srv = model->user_data;
  278. if (srv->lc == NULL) {
  279. BT_ERR("%s, Invalid Light LC Server state", __func__);
  280. return -EINVAL;
  281. }
  282. bt_mesh_server_stop_transition(&srv->transition);
  283. srv->lc->state.light_onoff = value->light_lc_light_onoff.onoff;
  284. light_lc_publish(model, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
  285. break;
  286. }
  287. default:
  288. BT_WARN("%s, Unknown binding state type 0x%02x", __func__, type);
  289. return -EINVAL;
  290. }
  291. return 0;
  292. }