xref: /btstack/src/mesh/mesh_generic_level_client.c (revision f4854a5efbe174cdf16fcaf3de7491781eef80ab)
1*f4854a5eSMatthias Ringwald /*
2*f4854a5eSMatthias Ringwald  * Copyright (C) 2019 BlueKitchen GmbH
3*f4854a5eSMatthias Ringwald  *
4*f4854a5eSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*f4854a5eSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*f4854a5eSMatthias Ringwald  * are met:
7*f4854a5eSMatthias Ringwald  *
8*f4854a5eSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*f4854a5eSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*f4854a5eSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*f4854a5eSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*f4854a5eSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*f4854a5eSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*f4854a5eSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*f4854a5eSMatthias Ringwald  *    from this software without specific prior written permission.
16*f4854a5eSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*f4854a5eSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*f4854a5eSMatthias Ringwald  *    monetary gain.
19*f4854a5eSMatthias Ringwald  *
20*f4854a5eSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*f4854a5eSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*f4854a5eSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*f4854a5eSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*f4854a5eSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*f4854a5eSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*f4854a5eSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*f4854a5eSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*f4854a5eSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*f4854a5eSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*f4854a5eSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*f4854a5eSMatthias Ringwald  * SUCH DAMAGE.
32*f4854a5eSMatthias Ringwald  *
33*f4854a5eSMatthias Ringwald  * Please inquire about commercial licensing options at
34*f4854a5eSMatthias Ringwald  * [email protected]
35*f4854a5eSMatthias Ringwald  *
36*f4854a5eSMatthias Ringwald  */
37*f4854a5eSMatthias Ringwald 
38*f4854a5eSMatthias Ringwald #define __BTSTACK_FILE__ "mesh_generic_client.c"
39*f4854a5eSMatthias Ringwald 
40*f4854a5eSMatthias Ringwald #include <string.h>
41*f4854a5eSMatthias Ringwald #include <stdio.h>
42*f4854a5eSMatthias Ringwald 
43*f4854a5eSMatthias Ringwald #include "mesh/mesh_generic_client.h"
44*f4854a5eSMatthias Ringwald 
45*f4854a5eSMatthias Ringwald #include "bluetooth_company_id.h"
46*f4854a5eSMatthias Ringwald #include "btstack_debug.h"
47*f4854a5eSMatthias Ringwald #include "btstack_memory.h"
48*f4854a5eSMatthias Ringwald #include "btstack_util.h"
49*f4854a5eSMatthias Ringwald 
50*f4854a5eSMatthias Ringwald #include "mesh/mesh_access.h"
51*f4854a5eSMatthias Ringwald #include "mesh/mesh_foundation.h"
52*f4854a5eSMatthias Ringwald #include "mesh/mesh_generic_model.h"
53*f4854a5eSMatthias Ringwald #include "mesh/mesh_keys.h"
54*f4854a5eSMatthias Ringwald #include "mesh/mesh_network.h"
55*f4854a5eSMatthias Ringwald #include "mesh/mesh_upper_transport.h"
56*f4854a5eSMatthias Ringwald 
57*f4854a5eSMatthias Ringwald // Generic Level Messages
58*f4854a5eSMatthias Ringwald 
59*f4854a5eSMatthias Ringwald // Level Messages
60*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_level_get = {
61*f4854a5eSMatthias Ringwald         MESH_GENERIC_LEVEL_GET, ""
62*f4854a5eSMatthias Ringwald };
63*f4854a5eSMatthias Ringwald 
64*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_level_set_with_transition = {
65*f4854a5eSMatthias Ringwald         MESH_GENERIC_LEVEL_SET, "2111"
66*f4854a5eSMatthias Ringwald };
67*f4854a5eSMatthias Ringwald 
68*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_level_set_instantaneous = {
69*f4854a5eSMatthias Ringwald         MESH_GENERIC_LEVEL_SET, "21"
70*f4854a5eSMatthias Ringwald };
71*f4854a5eSMatthias Ringwald 
72*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_level_set_unacknowledged_with_transition = {
73*f4854a5eSMatthias Ringwald         MESH_GENERIC_LEVEL_SET_UNACKNOWLEDGED, "2111"
74*f4854a5eSMatthias Ringwald };
75*f4854a5eSMatthias Ringwald 
76*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_level_set_unacknowledged_instantaneous = {
77*f4854a5eSMatthias Ringwald         MESH_GENERIC_LEVEL_SET_UNACKNOWLEDGED, "21"
78*f4854a5eSMatthias Ringwald };
79*f4854a5eSMatthias Ringwald 
80*f4854a5eSMatthias Ringwald // Delta Messages
81*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_delta_set_with_transition = {
82*f4854a5eSMatthias Ringwald         MESH_GENERIC_DELTA_SET, "2111"
83*f4854a5eSMatthias Ringwald };
84*f4854a5eSMatthias Ringwald 
85*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_delta_set_instantaneous = {
86*f4854a5eSMatthias Ringwald         MESH_GENERIC_DELTA_SET, "21"
87*f4854a5eSMatthias Ringwald };
88*f4854a5eSMatthias Ringwald 
89*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_delta_set_unacknowledged_with_transition = {
90*f4854a5eSMatthias Ringwald         MESH_GENERIC_DELTA_SET_UNACKNOWLEDGED, "2111"
91*f4854a5eSMatthias Ringwald };
92*f4854a5eSMatthias Ringwald 
93*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_delta_set_unacknowledged_instantaneous = {
94*f4854a5eSMatthias Ringwald         MESH_GENERIC_DELTA_SET_UNACKNOWLEDGED, "21"
95*f4854a5eSMatthias Ringwald };
96*f4854a5eSMatthias Ringwald 
97*f4854a5eSMatthias Ringwald // Move Messages
98*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_move_set_with_transition = {
99*f4854a5eSMatthias Ringwald         MESH_GENERIC_MOVE_SET, "2111"
100*f4854a5eSMatthias Ringwald };
101*f4854a5eSMatthias Ringwald 
102*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_move_set_instantaneous = {
103*f4854a5eSMatthias Ringwald         MESH_GENERIC_MOVE_SET, "21"
104*f4854a5eSMatthias Ringwald };
105*f4854a5eSMatthias Ringwald 
106*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_move_set_unacknowledged_with_transition = {
107*f4854a5eSMatthias Ringwald         MESH_GENERIC_MOVE_SET_UNACKNOWLEDGED, "2111"
108*f4854a5eSMatthias Ringwald };
109*f4854a5eSMatthias Ringwald 
110*f4854a5eSMatthias Ringwald static const mesh_access_message_t mesh_generic_move_set_unacknowledged_instantaneous = {
111*f4854a5eSMatthias Ringwald         MESH_GENERIC_MOVE_SET_UNACKNOWLEDGED, "21"
112*f4854a5eSMatthias Ringwald };
113*f4854a5eSMatthias Ringwald 
114*f4854a5eSMatthias Ringwald 
115*f4854a5eSMatthias Ringwald // Generic Level Client functions
116*f4854a5eSMatthias Ringwald 
117*f4854a5eSMatthias Ringwald static void generic_client_send_message_unacknowledged(uint16_t src, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_pdu_t *pdu){
118*f4854a5eSMatthias Ringwald     uint8_t  ttl  = mesh_foundation_default_ttl_get();
119*f4854a5eSMatthias Ringwald     mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
120*f4854a5eSMatthias Ringwald     mesh_access_send_unacknowledged_pdu(pdu);
121*f4854a5eSMatthias Ringwald }
122*f4854a5eSMatthias Ringwald 
123*f4854a5eSMatthias Ringwald static void generic_client_send_message_acknowledged(uint16_t src, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_pdu_t *pdu, uint32_t ack_opcode){
124*f4854a5eSMatthias Ringwald     uint8_t  ttl  = mesh_foundation_default_ttl_get();
125*f4854a5eSMatthias Ringwald     mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
126*f4854a5eSMatthias Ringwald     mesh_access_send_acknowledged_pdu(pdu, mesh_access_acknowledged_message_retransmissions(), ack_opcode);
127*f4854a5eSMatthias Ringwald }
128*f4854a5eSMatthias Ringwald 
129*f4854a5eSMatthias Ringwald static inline uint8_t mesh_generic_level_client_set_value(mesh_model_t * mesh_model,
130*f4854a5eSMatthias Ringwald     const mesh_access_message_t * message_template_with_transition, const mesh_access_message_t * message_template_instantaneous,
131*f4854a5eSMatthias Ringwald     uint16_t dest, uint16_t netkey_index, uint16_t appkey_index,
132*f4854a5eSMatthias Ringwald     int16_t value, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint8_t transaction_id, uint8_t acknowledged){
133*f4854a5eSMatthias Ringwald 
134*f4854a5eSMatthias Ringwald     mesh_transport_pdu_t * transport_pdu;
135*f4854a5eSMatthias Ringwald     if (transition_time_gdtt != 0) {
136*f4854a5eSMatthias Ringwald         transport_pdu = mesh_access_setup_segmented_message(message_template_with_transition, value, transaction_id, transition_time_gdtt, delay_time_gdtt);
137*f4854a5eSMatthias Ringwald     } else {
138*f4854a5eSMatthias Ringwald         transport_pdu = mesh_access_setup_segmented_message(message_template_instantaneous, value, transaction_id);
139*f4854a5eSMatthias Ringwald     }
140*f4854a5eSMatthias Ringwald     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
141*f4854a5eSMatthias Ringwald 
142*f4854a5eSMatthias Ringwald     if (acknowledged != 0){
143*f4854a5eSMatthias Ringwald         generic_client_send_message_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_GENERIC_LEVEL_STATUS);
144*f4854a5eSMatthias Ringwald     } else {
145*f4854a5eSMatthias Ringwald         generic_client_send_message_unacknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu);
146*f4854a5eSMatthias Ringwald     }
147*f4854a5eSMatthias Ringwald     return ERROR_CODE_SUCCESS;
148*f4854a5eSMatthias Ringwald }
149*f4854a5eSMatthias Ringwald 
150*f4854a5eSMatthias Ringwald // Level
151*f4854a5eSMatthias Ringwald 
152*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_get(mesh_model_t *mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
153*f4854a5eSMatthias Ringwald     // setup message
154*f4854a5eSMatthias Ringwald     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_generic_level_get);
155*f4854a5eSMatthias Ringwald     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
156*f4854a5eSMatthias Ringwald     // send as segmented access pdu
157*f4854a5eSMatthias Ringwald     generic_client_send_message_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_GENERIC_LEVEL_STATUS);
158*f4854a5eSMatthias Ringwald     return ERROR_CODE_SUCCESS;;
159*f4854a5eSMatthias Ringwald }
160*f4854a5eSMatthias Ringwald 
161*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_level_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index,
162*f4854a5eSMatthias Ringwald     int16_t level_value, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint8_t transaction_id){
163*f4854a5eSMatthias Ringwald 
164*f4854a5eSMatthias Ringwald     return mesh_generic_level_client_set_value(mesh_model, &mesh_generic_level_set_with_transition, &mesh_generic_level_set_instantaneous,
165*f4854a5eSMatthias Ringwald         dest, netkey_index, appkey_index, level_value, transition_time_gdtt, delay_time_gdtt, transaction_id, 1);
166*f4854a5eSMatthias Ringwald }
167*f4854a5eSMatthias Ringwald 
168*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_level_set_unacknowledged(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index,
169*f4854a5eSMatthias Ringwald     int16_t level_value, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint8_t transaction_id){
170*f4854a5eSMatthias Ringwald 
171*f4854a5eSMatthias Ringwald     return mesh_generic_level_client_set_value(mesh_model, &mesh_generic_level_set_unacknowledged_with_transition, &mesh_generic_level_set_unacknowledged_instantaneous,
172*f4854a5eSMatthias Ringwald         dest, netkey_index, appkey_index, level_value, transition_time_gdtt, delay_time_gdtt, transaction_id, 0);
173*f4854a5eSMatthias Ringwald }
174*f4854a5eSMatthias Ringwald 
175*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_publish_level(mesh_model_t * mesh_model, int16_t level_value, uint8_t transaction_id){
176*f4854a5eSMatthias Ringwald     mesh_publication_model_t * publication_model = mesh_model->publication_model;
177*f4854a5eSMatthias Ringwald     uint16_t appkey_index = publication_model->appkey_index;
178*f4854a5eSMatthias Ringwald     mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
179*f4854a5eSMatthias Ringwald     if (app_key == NULL) return MESH_ERROR_APPKEY_INDEX_INVALID;
180*f4854a5eSMatthias Ringwald 
181*f4854a5eSMatthias Ringwald     return mesh_generic_level_client_level_set_unacknowledged(mesh_model, publication_model->address, app_key->netkey_index, appkey_index, level_value, 0, 0, transaction_id);
182*f4854a5eSMatthias Ringwald }
183*f4854a5eSMatthias Ringwald 
184*f4854a5eSMatthias Ringwald // Delta
185*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_delta_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index,
186*f4854a5eSMatthias Ringwald     uint16_t delta_value, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint8_t transaction_id){
187*f4854a5eSMatthias Ringwald 
188*f4854a5eSMatthias Ringwald     return mesh_generic_level_client_set_value(mesh_model, &mesh_generic_delta_set_with_transition, &mesh_generic_delta_set_instantaneous,
189*f4854a5eSMatthias Ringwald         dest, netkey_index, appkey_index, delta_value, transition_time_gdtt, delay_time_gdtt, transaction_id, 1);
190*f4854a5eSMatthias Ringwald }
191*f4854a5eSMatthias Ringwald 
192*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_delta_set_unacknowledged(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index,
193*f4854a5eSMatthias Ringwald     uint16_t delta_value, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint8_t transaction_id){
194*f4854a5eSMatthias Ringwald 
195*f4854a5eSMatthias Ringwald     return mesh_generic_level_client_set_value(mesh_model, &mesh_generic_delta_set_unacknowledged_with_transition, &mesh_generic_delta_set_unacknowledged_instantaneous,
196*f4854a5eSMatthias Ringwald         dest, netkey_index, appkey_index, delta_value, transition_time_gdtt, delay_time_gdtt, transaction_id, 0);
197*f4854a5eSMatthias Ringwald }
198*f4854a5eSMatthias Ringwald 
199*f4854a5eSMatthias Ringwald // Move
200*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_move_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index,
201*f4854a5eSMatthias Ringwald     uint16_t delta_value, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint8_t transaction_id){
202*f4854a5eSMatthias Ringwald 
203*f4854a5eSMatthias Ringwald     return mesh_generic_level_client_set_value(mesh_model, &mesh_generic_move_set_with_transition, &mesh_generic_move_set_instantaneous,
204*f4854a5eSMatthias Ringwald         dest, netkey_index, appkey_index, delta_value, transition_time_gdtt, delay_time_gdtt, transaction_id, 1);
205*f4854a5eSMatthias Ringwald }
206*f4854a5eSMatthias Ringwald 
207*f4854a5eSMatthias Ringwald uint8_t mesh_generic_level_client_move_set_unacknowledged(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index,
208*f4854a5eSMatthias Ringwald     uint16_t delta_value, uint8_t transition_time_gdtt, uint8_t delay_time_gdtt, uint8_t transaction_id){
209*f4854a5eSMatthias Ringwald 
210*f4854a5eSMatthias Ringwald     return mesh_generic_level_client_set_value(mesh_model, &mesh_generic_move_set_unacknowledged_with_transition, &mesh_generic_move_set_unacknowledged_instantaneous,
211*f4854a5eSMatthias Ringwald         dest, netkey_index, appkey_index, delta_value, transition_time_gdtt, delay_time_gdtt, transaction_id, 0);
212*f4854a5eSMatthias Ringwald }
213*f4854a5eSMatthias Ringwald 
214*f4854a5eSMatthias Ringwald // Model Operations
215*f4854a5eSMatthias Ringwald 
216*f4854a5eSMatthias Ringwald static void generic_level_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
217*f4854a5eSMatthias Ringwald     if (!mesh_model->model_packet_handler){
218*f4854a5eSMatthias Ringwald         log_error("model_packet_handler == NULL");
219*f4854a5eSMatthias Ringwald     }
220*f4854a5eSMatthias Ringwald 
221*f4854a5eSMatthias Ringwald     mesh_access_parser_state_t parser;
222*f4854a5eSMatthias Ringwald     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
223*f4854a5eSMatthias Ringwald 
224*f4854a5eSMatthias Ringwald     uint8_t present_value = mesh_access_parser_get_u8(&parser);
225*f4854a5eSMatthias Ringwald     uint8_t target_value = 0;
226*f4854a5eSMatthias Ringwald     uint8_t remaining_time_gdtt = 0;
227*f4854a5eSMatthias Ringwald 
228*f4854a5eSMatthias Ringwald     if (mesh_access_parser_available(&parser) == 2){
229*f4854a5eSMatthias Ringwald         target_value = mesh_access_parser_get_u8(&parser);
230*f4854a5eSMatthias Ringwald         remaining_time_gdtt = mesh_access_parser_get_u8(&parser);
231*f4854a5eSMatthias Ringwald     }
232*f4854a5eSMatthias Ringwald 
233*f4854a5eSMatthias Ringwald     uint8_t event[16];
234*f4854a5eSMatthias Ringwald     int pos = 0;
235*f4854a5eSMatthias Ringwald     event[pos++] = HCI_EVENT_MESH_META;
236*f4854a5eSMatthias Ringwald     // reserve for size
237*f4854a5eSMatthias Ringwald     pos++;
238*f4854a5eSMatthias Ringwald     event[pos++] = MESH_SUBEVENT_GENERIC_LEVEL_STATUS;
239*f4854a5eSMatthias Ringwald 
240*f4854a5eSMatthias Ringwald     // element index
241*f4854a5eSMatthias Ringwald     event[pos++] = mesh_model->element->element_index;
242*f4854a5eSMatthias Ringwald     // model_id
243*f4854a5eSMatthias Ringwald     little_endian_store_32(event, pos, mesh_model->model_identifier);
244*f4854a5eSMatthias Ringwald     pos += 4;
245*f4854a5eSMatthias Ringwald 
246*f4854a5eSMatthias Ringwald     little_endian_store_16(event, pos, present_value);
247*f4854a5eSMatthias Ringwald     pos += 2;
248*f4854a5eSMatthias Ringwald     little_endian_store_16(event, pos, present_value);
249*f4854a5eSMatthias Ringwald     pos += 2;
250*f4854a5eSMatthias Ringwald 
251*f4854a5eSMatthias Ringwald     little_endian_store_32(event, pos, (uint32_t) mesh_access_time_gdtt2ms(remaining_time_gdtt));
252*f4854a5eSMatthias Ringwald     pos += 4;
253*f4854a5eSMatthias Ringwald     event[1] = pos - 2;
254*f4854a5eSMatthias Ringwald 
255*f4854a5eSMatthias Ringwald     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
256*f4854a5eSMatthias Ringwald     mesh_access_message_processed(pdu);
257*f4854a5eSMatthias Ringwald }
258*f4854a5eSMatthias Ringwald 
259*f4854a5eSMatthias Ringwald const static mesh_operation_t mesh_generic_level_model_operations[] = {
260*f4854a5eSMatthias Ringwald     { MESH_GENERIC_LEVEL_STATUS, 0, generic_level_status_handler },
261*f4854a5eSMatthias Ringwald     { 0, 0, NULL }
262*f4854a5eSMatthias Ringwald };
263*f4854a5eSMatthias Ringwald 
264*f4854a5eSMatthias Ringwald const mesh_operation_t * mesh_generic_level_client_get_operations(void){
265*f4854a5eSMatthias Ringwald     return mesh_generic_level_model_operations;
266*f4854a5eSMatthias Ringwald }
267*f4854a5eSMatthias Ringwald 
268*f4854a5eSMatthias Ringwald void mesh_generic_level_client_register_packet_handler(mesh_model_t *mesh_model, btstack_packet_handler_t transition_events_packet_handler){
269*f4854a5eSMatthias Ringwald     if (transition_events_packet_handler == NULL){
270*f4854a5eSMatthias Ringwald         log_error("mesh_generic_level_client_register_packet_handler called with NULL callback");
271*f4854a5eSMatthias Ringwald         return;
272*f4854a5eSMatthias Ringwald     }
273*f4854a5eSMatthias Ringwald     if (mesh_model == NULL){
274*f4854a5eSMatthias Ringwald         log_error("mesh_generic_level_client_register_packet_handler called with NULL mesh_model");
275*f4854a5eSMatthias Ringwald         return;
276*f4854a5eSMatthias Ringwald     }
277*f4854a5eSMatthias Ringwald     mesh_model->model_packet_handler = &transition_events_packet_handler;
278*f4854a5eSMatthias Ringwald }
279