xref: /nrf52832-nimble/packages/NimBLE-latest/apps/blemesh_models_example_2/src/state_binding.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
2  *
3  * Copyright (c) 2018 Vikrant More
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <math.h>
9 
10 #include "common.h"
11 #include "ble_mesh.h"
12 #include "device_composition.h"
13 
ceiling(float num)14 static s32_t ceiling(float num)
15 {
16 	s32_t inum;
17 
18 	inum = (s32_t) num;
19 	if (num == (float) inum) {
20 		return inum;
21 	}
22 
23 	return inum + 1;
24 }
25 
constrain_light_actual_state(u16_t var)26 static bool constrain_light_actual_state(u16_t var)
27 {
28 	bool is_value_within_range;
29 
30 	is_value_within_range = false;
31 
32 	if (var > 0 &&
33 	    var < light_lightness_srv_user_data.light_range_min) {
34 		var = light_lightness_srv_user_data.light_range_min;
35 	} else if (var > light_lightness_srv_user_data.light_range_max) {
36 		var = light_lightness_srv_user_data.light_range_max;
37 	} else {
38 		is_value_within_range = true;
39 	}
40 
41 	light_lightness_srv_user_data.actual = var;
42 
43 	return is_value_within_range;
44 }
45 
update_gen_onoff_state(void)46 static void update_gen_onoff_state(void)
47 {
48 	if (light_lightness_srv_user_data.actual == 0) {
49 		gen_onoff_srv_root_user_data.onoff = STATE_OFF;
50 	} else {
51 		gen_onoff_srv_root_user_data.onoff = STATE_ON;
52 	}
53 }
54 
state_binding(u8_t lightness,u8_t temperature)55 void state_binding(u8_t lightness, u8_t temperature)
56 {
57 	bool is_value_within_range;
58 	u16_t tmp16;
59 	float tmp;
60 
61 	switch (temperature) {
62 	case ONOFF_TEMP:/* Temp. update as per Light CTL temp. default state */
63 	case CTL_TEMP:	/* Temp. update as per Light CTL temp. state */
64 		/* Mesh Model Specification 6.1.3.1.1 2nd formula start */
65 		tmp = (light_ctl_srv_user_data.temp -
66 		       light_ctl_srv_user_data.temp_range_min) * 65535;
67 		tmp = tmp / (light_ctl_srv_user_data.temp_range_max -
68 			     light_ctl_srv_user_data.temp_range_min);
69 		gen_level_srv_s0_user_data.level = tmp - 32768;
70 		/* 6.1.3.1.1 2nd formula end */
71 		break;
72 	case LEVEL_TEMP:/* Temp. update as per Generic Level (s0) state */
73 		/* Mesh Model Specification 6.1.3.1.1 1st formula start */
74 		tmp = (float) (light_ctl_srv_user_data.temp_range_max -
75 			       light_ctl_srv_user_data.temp_range_min) / 65535;
76 		tmp = (gen_level_srv_s0_user_data.level + 32768) * tmp;
77 		light_ctl_srv_user_data.temp =
78 			light_ctl_srv_user_data.temp_range_min + tmp;
79 		/* 6.1.3.1.1 1st formula end */
80 		break;
81 	default:
82 		break;
83 	}
84 
85 	tmp16 = 0;
86 
87 	switch (lightness) {
88 	case ONPOWERUP: /* Lightness update as per Generic OnPowerUp state */
89 		if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) {
90 			light_lightness_srv_user_data.actual = 0;
91 			light_lightness_srv_user_data.linear = 0;
92 			gen_level_srv_root_user_data.level = -32768;
93 			light_ctl_srv_user_data.lightness = 0;
94 			return;
95 		} else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
96 			light_lightness_srv_user_data.actual =
97 				light_lightness_srv_user_data.last;
98 		}
99 
100 		break;
101 	case ONOFF: /* Lightness update as per Generic OnOff (root) state */
102 		if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) {
103 			light_lightness_srv_user_data.actual = 0;
104 			light_lightness_srv_user_data.linear = 0;
105 			gen_level_srv_root_user_data.level = -32768;
106 			light_ctl_srv_user_data.lightness = 0;
107 			return;
108 		} else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
109 			if (light_lightness_srv_user_data.def == 0) {
110 				light_lightness_srv_user_data.actual =
111 					light_lightness_srv_user_data.last;
112 			} else {
113 				light_lightness_srv_user_data.actual =
114 					light_lightness_srv_user_data.def;
115 			}
116 		}
117 
118 		break;
119 	case LEVEL: /* Lightness update as per Generic Level (root) state */
120 		tmp16 = gen_level_srv_root_user_data.level + 32768;
121 		constrain_light_actual_state(tmp16);
122 		update_gen_onoff_state();
123 		break;
124 	case DELTA_LEVEL: /* Lightness update as per Gen. Level (root) state */
125 		/* This is as per Mesh Model Specification 3.3.2.2.3 */
126 		tmp16 = gen_level_srv_root_user_data.level + 32768;
127 		if (tmp16 > 0 &&
128 		    tmp16 < light_lightness_srv_user_data.light_range_min) {
129 			if (gen_level_srv_root_user_data.last_delta < 0) {
130 				tmp16 = 0;
131 			} else {
132 				tmp16 =
133 				light_lightness_srv_user_data.light_range_min;
134 			}
135 		} else if (tmp16 >
136 			   light_lightness_srv_user_data.light_range_max) {
137 			tmp16 =
138 			light_lightness_srv_user_data.light_range_max;
139 		}
140 
141 		light_lightness_srv_user_data.actual = tmp16;
142 
143 		update_gen_onoff_state();
144 		break;
145 	case ACTUAL: /* Lightness update as per Light Lightness Actual state */
146 		update_gen_onoff_state();
147 		break;
148 	case LINEAR: /* Lightness update as per Light Lightness Linear state */
149 		tmp16 = (u16_t) 65535 *
150 			sqrt(((float) light_lightness_srv_user_data.linear /
151 			      65535));
152 
153 		is_value_within_range = constrain_light_actual_state(tmp16);
154 		update_gen_onoff_state();
155 
156 		if (is_value_within_range) {
157 			goto ignore_linear_update_others;
158 		}
159 
160 		break;
161 	case CTL: /* Lightness update as per Light CTL Lightness state */
162 		constrain_light_actual_state(light_ctl_srv_user_data.lightness);
163 		update_gen_onoff_state();
164 		break;
165 	default:
166 		return;
167 	}
168 
169 	tmp = ((float) light_lightness_srv_user_data.actual / 65535);
170 	light_lightness_srv_user_data.linear = ceiling(65535 * tmp * tmp);
171 
172 ignore_linear_update_others:
173 	if (light_lightness_srv_user_data.actual != 0) {
174 		light_lightness_srv_user_data.last =
175 			light_lightness_srv_user_data.actual;
176 	}
177 
178 	gen_level_srv_root_user_data.level =
179 		light_lightness_srv_user_data.actual - 32768;
180 
181 	light_ctl_srv_user_data.lightness =
182 		light_lightness_srv_user_data.actual;
183 }
184