1f4854a5eSMatthias Ringwald /*
2f4854a5eSMatthias Ringwald * Copyright (C) 2019 BlueKitchen GmbH
3f4854a5eSMatthias Ringwald *
4f4854a5eSMatthias Ringwald * Redistribution and use in source and binary forms, with or without
5f4854a5eSMatthias Ringwald * modification, are permitted provided that the following conditions
6f4854a5eSMatthias Ringwald * are met:
7f4854a5eSMatthias Ringwald *
8f4854a5eSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
9f4854a5eSMatthias Ringwald * notice, this list of conditions and the following disclaimer.
10f4854a5eSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
11f4854a5eSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
12f4854a5eSMatthias Ringwald * documentation and/or other materials provided with the distribution.
13f4854a5eSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
14f4854a5eSMatthias Ringwald * contributors may be used to endorse or promote products derived
15f4854a5eSMatthias Ringwald * from this software without specific prior written permission.
16f4854a5eSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
17f4854a5eSMatthias Ringwald * personal benefit and not for any commercial purpose or for
18f4854a5eSMatthias Ringwald * monetary gain.
19f4854a5eSMatthias Ringwald *
20f4854a5eSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21f4854a5eSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22f4854a5eSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25f4854a5eSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26f4854a5eSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27f4854a5eSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28f4854a5eSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29f4854a5eSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30f4854a5eSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31f4854a5eSMatthias Ringwald * SUCH DAMAGE.
32f4854a5eSMatthias Ringwald *
33f4854a5eSMatthias Ringwald * Please inquire about commercial licensing options at
34f4854a5eSMatthias Ringwald * [email protected]
35f4854a5eSMatthias Ringwald *
36f4854a5eSMatthias Ringwald */
37f4854a5eSMatthias Ringwald
382d4000d1SMatthias Ringwald #define BTSTACK_FILE__ "mesh_generic_level_server.c"
39f4854a5eSMatthias Ringwald
40cb7b3e6fSMatthias Ringwald #include <inttypes.h>
41f4854a5eSMatthias Ringwald #include <string.h>
42f4854a5eSMatthias Ringwald #include <stdio.h>
43f4854a5eSMatthias Ringwald
44f4854a5eSMatthias Ringwald #include "mesh/mesh_generic_level_server.h"
45f4854a5eSMatthias Ringwald
46f4854a5eSMatthias Ringwald #include "bluetooth_company_id.h"
47321e3a3cSMatthias Ringwald #include "btstack_debug.h"
48321e3a3cSMatthias Ringwald #include "btstack_memory.h"
49321e3a3cSMatthias Ringwald #include "btstack_util.h"
50f4854a5eSMatthias Ringwald
51f4854a5eSMatthias Ringwald #include "mesh/mesh_access.h"
52f4854a5eSMatthias Ringwald #include "mesh/mesh_foundation.h"
53f4854a5eSMatthias Ringwald #include "mesh/mesh_generic_model.h"
54f4854a5eSMatthias Ringwald #include "mesh/mesh_keys.h"
55f4854a5eSMatthias Ringwald #include "mesh/mesh_network.h"
56f4854a5eSMatthias Ringwald #include "mesh/mesh_upper_transport.h"
57f4854a5eSMatthias Ringwald
generic_server_send_message(uint16_t src,uint16_t dest,uint16_t netkey_index,uint16_t appkey_index,mesh_pdu_t * pdu)58f4854a5eSMatthias Ringwald static void generic_server_send_message(uint16_t src, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_pdu_t *pdu){
59f4854a5eSMatthias Ringwald uint8_t ttl = mesh_foundation_default_ttl_get();
60f4854a5eSMatthias Ringwald mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
61321e3a3cSMatthias Ringwald mesh_access_send_unacknowledged_pdu(pdu);
62f4854a5eSMatthias Ringwald }
63f4854a5eSMatthias Ringwald
64f4854a5eSMatthias Ringwald // Transition
add_and_clip_int16(int16_t current_value,int32_t increment)65753e6a2cSMatthias Ringwald static int16_t add_and_clip_int16(int16_t current_value, int32_t increment){
66f4854a5eSMatthias Ringwald int32_t value = current_value + increment;
67f4854a5eSMatthias Ringwald if (value < -32768){
68f4854a5eSMatthias Ringwald value = -32768;
69f4854a5eSMatthias Ringwald } else if (value > 32767){
70f4854a5eSMatthias Ringwald value = 32767;
71f4854a5eSMatthias Ringwald }
72f4854a5eSMatthias Ringwald return (int16_t) value;
73f4854a5eSMatthias Ringwald }
74f4854a5eSMatthias Ringwald
generic_level_server_get_base_transition(mesh_model_t * mesh_model)75f4854a5eSMatthias Ringwald static mesh_transition_t * generic_level_server_get_base_transition(mesh_model_t * mesh_model) {
76f4854a5eSMatthias Ringwald mesh_generic_level_state_t * generic_level_server_state = (mesh_generic_level_state_t *)mesh_model->model_data;
77f4854a5eSMatthias Ringwald return &generic_level_server_state->transition_data.base_transition;
78f4854a5eSMatthias Ringwald }
79f4854a5eSMatthias Ringwald
mesh_server_transition_handler(mesh_transition_t * base_transition,model_state_update_reason_t event)80e8b9b724SMatthias Ringwald static void mesh_server_transition_handler(mesh_transition_t * base_transition, model_state_update_reason_t event){
81e8b9b724SMatthias Ringwald mesh_transition_int16_t * transition = (mesh_transition_int16_t*) base_transition;
82cb7b3e6fSMatthias Ringwald printf("Transition: event %x, current %x, target %x, increment %x, time %" PRIu32 "\n", (int) event, transition->current_value, transition->target_value, transition->stepwise_value_increment, btstack_run_loop_get_time_ms());
83e8b9b724SMatthias Ringwald switch (event){
84e8b9b724SMatthias Ringwald case MODEL_STATE_UPDATE_REASON_TRANSITION_ACTIVE:
85332b5256SMatthias Ringwald transition->current_value = add_and_clip_int16(transition->current_value, transition->stepwise_value_increment);
86332b5256SMatthias Ringwald mesh_access_state_changed(transition->base_transition.mesh_model);
87e8b9b724SMatthias Ringwald break;
88332b5256SMatthias Ringwald case MODEL_STATE_UPDATE_REASON_SET:
89e8b9b724SMatthias Ringwald case MODEL_STATE_UPDATE_REASON_TRANSITION_END:
90332b5256SMatthias Ringwald transition->current_value = transition->target_value;
91332b5256SMatthias Ringwald mesh_access_state_changed(transition->base_transition.mesh_model);
92e8b9b724SMatthias Ringwald break;
93e8b9b724SMatthias Ringwald case MODEL_STATE_UPDATE_REASON_TRANSITION_ABORT:
94e8b9b724SMatthias Ringwald break;
95e8b9b724SMatthias Ringwald default:
96e8b9b724SMatthias Ringwald break;
97e8b9b724SMatthias Ringwald }
98e8b9b724SMatthias Ringwald
99332b5256SMatthias Ringwald // notify app
100332b5256SMatthias Ringwald mesh_model_t * generic_level_server_model = transition->base_transition.mesh_model;
101332b5256SMatthias Ringwald mesh_access_emit_state_update_int16(generic_level_server_model->model_packet_handler,
102332b5256SMatthias Ringwald mesh_access_get_element_index(generic_level_server_model),
103332b5256SMatthias Ringwald generic_level_server_model->model_identifier,
104332b5256SMatthias Ringwald MODEL_STATE_ID_GENERIC_LEVEL,
105332b5256SMatthias Ringwald event,
106332b5256SMatthias Ringwald transition->current_value);
107f4854a5eSMatthias Ringwald }
108f4854a5eSMatthias Ringwald
mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model_t * mesh_model,uint8_t transition_time_gdtt,uint8_t delay_time_gdtt,uint32_t delta_value)109262d85eeSMatthias Ringwald static void mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model_t *mesh_model, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint32_t delta_value){
110f4854a5eSMatthias Ringwald mesh_generic_level_state_t * generic_level_server_state = (mesh_generic_level_state_t *)mesh_model->model_data;
111618a5fc3SMatthias Ringwald mesh_transition_t * transition = &generic_level_server_state->transition_data.base_transition;
112f4854a5eSMatthias Ringwald
113c5df3df4SMatthias Ringwald // calc step increment
114c5df3df4SMatthias Ringwald int num_steps = mesh_access_transitions_num_steps_from_gdtt(transition_time_gdtt);
115c5df3df4SMatthias Ringwald if (num_steps > 0){
116c5df3df4SMatthias Ringwald generic_level_server_state->transition_data.stepwise_value_increment = delta_value / num_steps;
117c5df3df4SMatthias Ringwald } else {
118c5df3df4SMatthias Ringwald generic_level_server_state->transition_data.stepwise_value_increment = 0;
119c5df3df4SMatthias Ringwald }
120c5df3df4SMatthias Ringwald
121332b5256SMatthias Ringwald mesh_access_transition_setup(mesh_model, transition, transition_time_gdtt, delay_time_gdtt, &mesh_server_transition_handler);
122f4854a5eSMatthias Ringwald }
123332b5256SMatthias Ringwald
124f4854a5eSMatthias Ringwald // Generic Level State
125f4854a5eSMatthias Ringwald
mesh_generic_level_server_register_packet_handler(mesh_model_t * generic_level_server_model,btstack_packet_handler_t transition_events_packet_handler)126f4854a5eSMatthias Ringwald void mesh_generic_level_server_register_packet_handler(mesh_model_t *generic_level_server_model, btstack_packet_handler_t transition_events_packet_handler){
1277ee2bdaeSMatthias Ringwald btstack_assert(generic_level_server_model != NULL);
1287ee2bdaeSMatthias Ringwald btstack_assert(transition_events_packet_handler != NULL);
1290c98c714SMatthias Ringwald generic_level_server_model->model_packet_handler = transition_events_packet_handler;
130f4854a5eSMatthias Ringwald }
131f4854a5eSMatthias Ringwald
132f4854a5eSMatthias Ringwald const mesh_access_message_t mesh_generic_level_status_transition = {
133f4854a5eSMatthias Ringwald MESH_GENERIC_LEVEL_STATUS, "221"
134f4854a5eSMatthias Ringwald };
135f4854a5eSMatthias Ringwald
136f4854a5eSMatthias Ringwald const mesh_access_message_t mesh_generic_level_status_instantaneous = {
137f4854a5eSMatthias Ringwald MESH_GENERIC_LEVEL_STATUS, "2"
138f4854a5eSMatthias Ringwald };
139f4854a5eSMatthias Ringwald
mesh_generic_level_status_message(mesh_model_t * generic_level_server_model)140f4854a5eSMatthias Ringwald static mesh_pdu_t * mesh_generic_level_status_message(mesh_model_t *generic_level_server_model){
141f4854a5eSMatthias Ringwald mesh_generic_level_state_t * state = (mesh_generic_level_state_t *) generic_level_server_model->model_data;
1427ee2bdaeSMatthias Ringwald btstack_assert(state != NULL);
143f4854a5eSMatthias Ringwald
144f4854a5eSMatthias Ringwald // setup message
145039cbf1dSMatthias Ringwald mesh_upper_transport_pdu_t * transport_pdu = NULL;
146332b5256SMatthias Ringwald if (state->transition_data.base_transition.num_steps > 0) {
147332b5256SMatthias Ringwald uint8_t remaining_time = (((uint8_t)state->transition_data.base_transition.step_resolution) << 6) | (state->transition_data.base_transition.num_steps);
1480323b889SMatthias Ringwald transport_pdu = mesh_access_setup_message(&mesh_generic_level_status_transition, state->transition_data.current_value,
14985bee781SMatthias Ringwald state->transition_data.target_value, remaining_time);
150f4854a5eSMatthias Ringwald } else {
1510323b889SMatthias Ringwald transport_pdu = mesh_access_setup_message(&mesh_generic_level_status_instantaneous, state->transition_data.current_value);
152f4854a5eSMatthias Ringwald }
153f4854a5eSMatthias Ringwald return (mesh_pdu_t *)transport_pdu;
154f4854a5eSMatthias Ringwald }
155f4854a5eSMatthias Ringwald
generic_level_handle_set_target_level_message(mesh_model_t * mesh_model,mesh_pdu_t * pdu)156f4854a5eSMatthias Ringwald static void generic_level_handle_set_target_level_message(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
157f4854a5eSMatthias Ringwald mesh_generic_level_state_t * generic_level_server_state = (mesh_generic_level_state_t *)mesh_model->model_data;
1587ee2bdaeSMatthias Ringwald btstack_assert(generic_level_server_state != NULL);
159f4854a5eSMatthias Ringwald
160f4854a5eSMatthias Ringwald mesh_access_parser_state_t parser;
161f4854a5eSMatthias Ringwald mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
162ad3a646cSMatthias Ringwald int16_t level_value = (int16_t) mesh_access_parser_get_uint16(&parser);
163f4854a5eSMatthias Ringwald // The TID field is a transaction identifier indicating whether the message is
164f4854a5eSMatthias Ringwald // a new message or a retransmission of a previously sent message
165ad3a646cSMatthias Ringwald uint8_t tid = mesh_access_parser_get_uint8(&parser);
166f4854a5eSMatthias Ringwald
167f4854a5eSMatthias Ringwald uint8_t transition_time_gdtt = 0;
168f4854a5eSMatthias Ringwald uint8_t delay_time_gdtt = 0;
1690dcabf4cSMatthias Ringwald if (mesh_access_parser_available(&parser) == 2){
1700dcabf4cSMatthias Ringwald // Generic Default Transition Time format - num_steps (higher 6 bits), step_resolution (lower 2 bits)
171ad3a646cSMatthias Ringwald transition_time_gdtt = mesh_access_parser_get_uint8(&parser);
172ad3a646cSMatthias Ringwald delay_time_gdtt = mesh_access_parser_get_uint8(&parser);
1730dcabf4cSMatthias Ringwald }
1740dcabf4cSMatthias Ringwald
175f4854a5eSMatthias Ringwald mesh_transition_t * base_transition = generic_level_server_get_base_transition(mesh_model);
176f4854a5eSMatthias Ringwald
177f4854a5eSMatthias Ringwald switch (mesh_access_transitions_transaction_status(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu))){
178f4854a5eSMatthias Ringwald case MESH_TRANSACTION_STATUS_RETRANSMISSION:
179f4854a5eSMatthias Ringwald // ignore
180f4854a5eSMatthias Ringwald break;
181f4854a5eSMatthias Ringwald default:
182332b5256SMatthias Ringwald mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
183f4854a5eSMatthias Ringwald
184f4854a5eSMatthias Ringwald generic_level_server_state->transition_data.initial_value = generic_level_server_state->transition_data.current_value;
185f4854a5eSMatthias Ringwald generic_level_server_state->transition_data.target_value = level_value;
186f4854a5eSMatthias Ringwald
187c5df3df4SMatthias Ringwald int32_t delta_value = level_value - generic_level_server_state->transition_data.current_value;
188262d85eeSMatthias Ringwald mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model, transition_time_gdtt, delay_time_gdtt, delta_value);
189f4854a5eSMatthias Ringwald mesh_access_state_changed(mesh_model);
190f4854a5eSMatthias Ringwald break;
191f4854a5eSMatthias Ringwald }
192f4854a5eSMatthias Ringwald
193f4854a5eSMatthias Ringwald }
194f4854a5eSMatthias Ringwald
generic_level_handle_set_delta_message(mesh_model_t * mesh_model,mesh_pdu_t * pdu)195c5df3df4SMatthias Ringwald static void generic_level_handle_set_delta_message(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
196c5df3df4SMatthias Ringwald mesh_generic_level_state_t * generic_level_server_state = (mesh_generic_level_state_t *)mesh_model->model_data;
197c5df3df4SMatthias Ringwald btstack_assert(generic_level_server_state != NULL);
198c5df3df4SMatthias Ringwald
199c5df3df4SMatthias Ringwald mesh_access_parser_state_t parser;
200c5df3df4SMatthias Ringwald mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
201ad3a646cSMatthias Ringwald int32_t delta_value = mesh_access_parser_get_uint32(&parser);
202c5df3df4SMatthias Ringwald
203c5df3df4SMatthias Ringwald // The TID field is a transaction identifier indicating whether the message is
204c5df3df4SMatthias Ringwald // a new message or a retransmission of a previously sent message
205ad3a646cSMatthias Ringwald uint8_t tid = mesh_access_parser_get_uint8(&parser);
206c5df3df4SMatthias Ringwald
207c5df3df4SMatthias Ringwald uint8_t transition_time_gdtt = 0;
208c5df3df4SMatthias Ringwald uint8_t delay_time_gdtt = 0;
209c5df3df4SMatthias Ringwald if (mesh_access_parser_available(&parser) == 2){
210c5df3df4SMatthias Ringwald // Generic Default Transition Time format - num_steps (higher 6 bits), step_resolution (lower 2 bits)
211ad3a646cSMatthias Ringwald transition_time_gdtt = mesh_access_parser_get_uint8(&parser);
212ad3a646cSMatthias Ringwald delay_time_gdtt = mesh_access_parser_get_uint8(&parser);
213c5df3df4SMatthias Ringwald }
214c5df3df4SMatthias Ringwald
215c5df3df4SMatthias Ringwald mesh_transition_t * base_transition = generic_level_server_get_base_transition(mesh_model);
216c5df3df4SMatthias Ringwald
217c5df3df4SMatthias Ringwald switch (mesh_access_transitions_transaction_status(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu))){
218c5df3df4SMatthias Ringwald case MESH_TRANSACTION_STATUS_DIFFERENT_DST_OR_SRC:
219c5df3df4SMatthias Ringwald // abort transaction
220c5df3df4SMatthias Ringwald printf("Transaction abort\n");
221c5df3df4SMatthias Ringwald mesh_access_transitions_abort_transaction(base_transition);
222c5df3df4SMatthias Ringwald generic_level_server_state->transition_data.current_value = generic_level_server_state->transition_data.initial_value;
223262d85eeSMatthias Ringwald mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model, 0, 0, 0);
224c5df3df4SMatthias Ringwald break;
225c5df3df4SMatthias Ringwald case MESH_TRANSACTION_STATUS_NEW:
226c5df3df4SMatthias Ringwald // start transaction with current value
227332b5256SMatthias Ringwald mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
228c5df3df4SMatthias Ringwald generic_level_server_state->transition_data.initial_value = generic_level_server_state->transition_data.current_value;
229c5df3df4SMatthias Ringwald generic_level_server_state->transition_data.target_value = add_and_clip_int16(generic_level_server_state->transition_data.initial_value, delta_value);
230c5df3df4SMatthias Ringwald printf("Transaction %u, new, init %x, target %x\n", tid, generic_level_server_state->transition_data.initial_value, generic_level_server_state->transition_data.target_value);
231262d85eeSMatthias Ringwald mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model, transition_time_gdtt, delay_time_gdtt, delta_value);
232c5df3df4SMatthias Ringwald mesh_access_state_changed(mesh_model);
233c5df3df4SMatthias Ringwald break;
234c5df3df4SMatthias Ringwald case MESH_TRANSACTION_STATUS_RETRANSMISSION:
235c5df3df4SMatthias Ringwald // replace last delta message
236332b5256SMatthias Ringwald mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
237c5df3df4SMatthias Ringwald generic_level_server_state->transition_data.target_value = add_and_clip_int16(generic_level_server_state->transition_data.initial_value, delta_value);
238c5df3df4SMatthias Ringwald printf("Transaction %u, retransmission, init %x, target %x\n", tid, generic_level_server_state->transition_data.initial_value, generic_level_server_state->transition_data.target_value);
239262d85eeSMatthias Ringwald mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model, transition_time_gdtt, delay_time_gdtt, delta_value);
240c5df3df4SMatthias Ringwald mesh_access_state_changed(mesh_model);
241c5df3df4SMatthias Ringwald break;
242c5df3df4SMatthias Ringwald default:
243c5df3df4SMatthias Ringwald break;
244c5df3df4SMatthias Ringwald }
245c5df3df4SMatthias Ringwald }
246c5df3df4SMatthias Ringwald
generic_level_handle_set_move_message(mesh_model_t * mesh_model,mesh_pdu_t * pdu)247f4854a5eSMatthias Ringwald static void generic_level_handle_set_move_message(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
248f4854a5eSMatthias Ringwald mesh_generic_level_state_t * generic_level_server_state = (mesh_generic_level_state_t *)mesh_model->model_data;
2497ee2bdaeSMatthias Ringwald btstack_assert(generic_level_server_state != NULL);
250f4854a5eSMatthias Ringwald
251f4854a5eSMatthias Ringwald mesh_access_parser_state_t parser;
252f4854a5eSMatthias Ringwald mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
253ad3a646cSMatthias Ringwald int32_t delta_value = (int32_t) mesh_access_parser_get_uint16(&parser);
254f4854a5eSMatthias Ringwald
255f4854a5eSMatthias Ringwald // The TID field is a transaction identifier indicating whether the message is
256f4854a5eSMatthias Ringwald // a new message or a retransmission of a previously sent message
257ad3a646cSMatthias Ringwald uint8_t tid = mesh_access_parser_get_uint8(&parser);
258f4854a5eSMatthias Ringwald
259f4854a5eSMatthias Ringwald uint8_t transition_time_gdtt = 0;
260f4854a5eSMatthias Ringwald uint8_t delay_time_gdtt = 0;
261753e6a2cSMatthias Ringwald if (mesh_access_parser_available(&parser) == 2){
262753e6a2cSMatthias Ringwald // Generic Default Transition Time format - num_steps (higher 6 bits), step_resolution (lower 2 bits)
263ad3a646cSMatthias Ringwald transition_time_gdtt = mesh_access_parser_get_uint8(&parser);
264ad3a646cSMatthias Ringwald delay_time_gdtt = mesh_access_parser_get_uint8(&parser);
265b66ef5c9SMatthias Ringwald } else {
266b66ef5c9SMatthias Ringwald // transition speed is delta / num steps, without num steps, and without a default transition time, we cannot do this
267b66ef5c9SMatthias Ringwald return;
268753e6a2cSMatthias Ringwald }
269753e6a2cSMatthias Ringwald
270f4854a5eSMatthias Ringwald mesh_transition_t * base_transition = generic_level_server_get_base_transition(mesh_model);
271f4854a5eSMatthias Ringwald
272f4854a5eSMatthias Ringwald switch (mesh_access_transitions_transaction_status(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu))){
273f4854a5eSMatthias Ringwald case MESH_TRANSACTION_STATUS_RETRANSMISSION:
274f4854a5eSMatthias Ringwald // ignore retransmission
275f4854a5eSMatthias Ringwald break;
276f4854a5eSMatthias Ringwald default:
277332b5256SMatthias Ringwald mesh_access_transitions_init_transaction(base_transition, tid, mesh_pdu_src(pdu), mesh_pdu_dst(pdu));
278f4854a5eSMatthias Ringwald
279f4854a5eSMatthias Ringwald generic_level_server_state->transition_data.initial_value = generic_level_server_state->transition_data.current_value;
280b66ef5c9SMatthias Ringwald generic_level_server_state->transition_data.target_value = add_and_clip_int16(generic_level_server_state->transition_data.current_value, delta_value);
281b66ef5c9SMatthias Ringwald if (delta_value > 0){
282b66ef5c9SMatthias Ringwald generic_level_server_state->transition_data.target_value = 32767;
283b66ef5c9SMatthias Ringwald } else {
284b66ef5c9SMatthias Ringwald generic_level_server_state->transition_data.target_value = -32768;
285f4854a5eSMatthias Ringwald }
286753e6a2cSMatthias Ringwald
287262d85eeSMatthias Ringwald mesh_server_transition_setup_transition_or_instantaneous_update_int16(mesh_model, transition_time_gdtt, delay_time_gdtt, delta_value);
288b66ef5c9SMatthias Ringwald generic_level_server_state->transition_data.base_transition.num_steps = MESH_TRANSITION_NUM_STEPS_INFINITE;
289f4854a5eSMatthias Ringwald break;
290f4854a5eSMatthias Ringwald }
291f4854a5eSMatthias Ringwald }
292f4854a5eSMatthias Ringwald
generic_level_get_handler(mesh_model_t * generic_level_server_model,mesh_pdu_t * pdu)293f4854a5eSMatthias Ringwald static void generic_level_get_handler(mesh_model_t *generic_level_server_model, mesh_pdu_t * pdu){
294039cbf1dSMatthias Ringwald mesh_upper_transport_pdu_t * transport_pdu = (mesh_upper_transport_pdu_t *) mesh_generic_level_status_message(generic_level_server_model);
2957ee2bdaeSMatthias Ringwald if (transport_pdu != NULL) {
296f4854a5eSMatthias Ringwald generic_server_send_message(mesh_access_get_element_address(generic_level_server_model), mesh_pdu_src(pdu), mesh_pdu_netkey_index(pdu), mesh_pdu_appkey_index(pdu), (mesh_pdu_t *) transport_pdu);
2977ee2bdaeSMatthias Ringwald }
298f4854a5eSMatthias Ringwald mesh_access_message_processed(pdu);
299f4854a5eSMatthias Ringwald }
300f4854a5eSMatthias Ringwald
generic_level_set_handler(mesh_model_t * generic_level_server_model,mesh_pdu_t * pdu)301f4854a5eSMatthias Ringwald static void generic_level_set_handler(mesh_model_t *generic_level_server_model, mesh_pdu_t * pdu){
302f4854a5eSMatthias Ringwald generic_level_handle_set_target_level_message(generic_level_server_model, pdu);
303f4854a5eSMatthias Ringwald
304039cbf1dSMatthias Ringwald mesh_upper_transport_pdu_t * transport_pdu = (mesh_upper_transport_pdu_t *) mesh_generic_level_status_message(generic_level_server_model);
3057ee2bdaeSMatthias Ringwald if (transport_pdu != NULL) {
306f4854a5eSMatthias Ringwald generic_server_send_message(mesh_access_get_element_address(generic_level_server_model), mesh_pdu_src(pdu), mesh_pdu_netkey_index(pdu), mesh_pdu_appkey_index(pdu), (mesh_pdu_t *) transport_pdu);
3077ee2bdaeSMatthias Ringwald }
308f4854a5eSMatthias Ringwald mesh_access_message_processed(pdu);
309f4854a5eSMatthias Ringwald }
310f4854a5eSMatthias Ringwald
generic_level_set_unacknowledged_handler(mesh_model_t * generic_level_server_model,mesh_pdu_t * pdu)311f4854a5eSMatthias Ringwald static void generic_level_set_unacknowledged_handler(mesh_model_t *generic_level_server_model, mesh_pdu_t * pdu){
312f4854a5eSMatthias Ringwald generic_level_handle_set_target_level_message(generic_level_server_model, pdu);
3137ee2bdaeSMatthias Ringwald mesh_access_message_processed(pdu);
314f4854a5eSMatthias Ringwald }
315f4854a5eSMatthias Ringwald
generic_delta_set_handler(mesh_model_t * generic_level_server_model,mesh_pdu_t * pdu)316f4854a5eSMatthias Ringwald static void generic_delta_set_handler(mesh_model_t *generic_level_server_model, mesh_pdu_t * pdu){
317f4854a5eSMatthias Ringwald generic_level_handle_set_delta_message(generic_level_server_model, pdu);
318f4854a5eSMatthias Ringwald
319039cbf1dSMatthias Ringwald mesh_upper_transport_pdu_t * transport_pdu = (mesh_upper_transport_pdu_t *) mesh_generic_level_status_message(generic_level_server_model);
3207ee2bdaeSMatthias Ringwald if (transport_pdu != NULL) {
321f4854a5eSMatthias Ringwald generic_server_send_message(mesh_access_get_element_address(generic_level_server_model), mesh_pdu_src(pdu), mesh_pdu_netkey_index(pdu), mesh_pdu_appkey_index(pdu), (mesh_pdu_t *) transport_pdu);
3227ee2bdaeSMatthias Ringwald }
323f4854a5eSMatthias Ringwald mesh_access_message_processed(pdu);
324f4854a5eSMatthias Ringwald }
325f4854a5eSMatthias Ringwald
generic_delta_set_unacknowledged_handler(mesh_model_t * generic_level_server_model,mesh_pdu_t * pdu)326f4854a5eSMatthias Ringwald static void generic_delta_set_unacknowledged_handler(mesh_model_t *generic_level_server_model, mesh_pdu_t * pdu){
327f4854a5eSMatthias Ringwald generic_level_handle_set_delta_message(generic_level_server_model, pdu);
3287ee2bdaeSMatthias Ringwald mesh_access_message_processed(pdu);
329f4854a5eSMatthias Ringwald }
330f4854a5eSMatthias Ringwald
generic_move_get_handler(mesh_model_t * generic_level_server_model,mesh_pdu_t * pdu)331f4854a5eSMatthias Ringwald static void generic_move_get_handler(mesh_model_t *generic_level_server_model, mesh_pdu_t * pdu){
332f4854a5eSMatthias Ringwald generic_level_handle_set_move_message(generic_level_server_model, pdu);
333f4854a5eSMatthias Ringwald
334039cbf1dSMatthias Ringwald mesh_upper_transport_pdu_t * transport_pdu = (mesh_upper_transport_pdu_t *) mesh_generic_level_status_message(generic_level_server_model);
3357ee2bdaeSMatthias Ringwald if (transport_pdu != NULL) {
336f4854a5eSMatthias Ringwald generic_server_send_message(mesh_access_get_element_address(generic_level_server_model), mesh_pdu_src(pdu), mesh_pdu_netkey_index(pdu), mesh_pdu_appkey_index(pdu), (mesh_pdu_t *) transport_pdu);
3377ee2bdaeSMatthias Ringwald }
338f4854a5eSMatthias Ringwald mesh_access_message_processed(pdu);
339f4854a5eSMatthias Ringwald }
340f4854a5eSMatthias Ringwald
generic_move_set_unacknowledged_handler(mesh_model_t * generic_level_server_model,mesh_pdu_t * pdu)341f4854a5eSMatthias Ringwald static void generic_move_set_unacknowledged_handler(mesh_model_t *generic_level_server_model, mesh_pdu_t * pdu){
342f4854a5eSMatthias Ringwald generic_level_handle_set_move_message(generic_level_server_model, pdu);
3437ee2bdaeSMatthias Ringwald mesh_access_message_processed(pdu);
344f4854a5eSMatthias Ringwald }
345f4854a5eSMatthias Ringwald
346f4854a5eSMatthias Ringwald // Generic On Off Message
347*3548b7cbSDirk Helbig static const mesh_operation_t mesh_generic_level_model_operations[] = {
348f4854a5eSMatthias Ringwald { MESH_GENERIC_LEVEL_GET, 0, generic_level_get_handler },
349f4854a5eSMatthias Ringwald { MESH_GENERIC_LEVEL_SET, 3, generic_level_set_handler },
350f4854a5eSMatthias Ringwald { MESH_GENERIC_LEVEL_SET_UNACKNOWLEDGED, 3, generic_level_set_unacknowledged_handler },
351f4854a5eSMatthias Ringwald { MESH_GENERIC_DELTA_SET, 3, generic_delta_set_handler },
352f4854a5eSMatthias Ringwald { MESH_GENERIC_DELTA_SET_UNACKNOWLEDGED, 3, generic_delta_set_unacknowledged_handler },
353f4854a5eSMatthias Ringwald { MESH_GENERIC_MOVE_SET, 3, generic_move_get_handler },
354f4854a5eSMatthias Ringwald { MESH_GENERIC_MOVE_SET_UNACKNOWLEDGED, 3, generic_move_set_unacknowledged_handler },
355f4854a5eSMatthias Ringwald { 0, 0, NULL }
356f4854a5eSMatthias Ringwald };
357f4854a5eSMatthias Ringwald
mesh_generic_level_server_get_operations(void)358f4854a5eSMatthias Ringwald const mesh_operation_t * mesh_generic_level_server_get_operations(void){
359f4854a5eSMatthias Ringwald return mesh_generic_level_model_operations;
360f4854a5eSMatthias Ringwald }
361f4854a5eSMatthias Ringwald
mesh_generic_level_server_set_publication_model(mesh_model_t * generic_level_server_model,mesh_publication_model_t * publication_model)362f4854a5eSMatthias Ringwald void mesh_generic_level_server_set_publication_model(mesh_model_t *generic_level_server_model, mesh_publication_model_t * publication_model){
363f4854a5eSMatthias Ringwald if (generic_level_server_model == NULL) return;
364f4854a5eSMatthias Ringwald if (publication_model == NULL) return;
365f4854a5eSMatthias Ringwald publication_model->publish_state_fn = &mesh_generic_level_status_message;
366f4854a5eSMatthias Ringwald generic_level_server_model->publication_model = publication_model;
367f4854a5eSMatthias Ringwald }
368