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