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)14static 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)26static 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)46static 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)55void 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