1#!/usr/bin/env python3 2 3import glob 4import re 5import sys 6import os 7 8import btstack_parser as parser 9 10meta_events = [ 11 'A2DP', 12 'ANCS', 13 'AVDTP', 14 'AVRCP', 15 'GAP', 16 'GATTSERVICE', 17 'GOEP', 18 'HFP', 19 'HID', 20 'HIDS', 21 'HSP', 22 'LE', 23 'MAP', 24 'MESH', 25 'PBAP', 26] 27 28supported_event_groups = meta_events + [ 29 'ATT', 30 'BNEP', 31 'BTSTACK', 32 'GAP', 33 'GATT', 34 'HCI', 35 'HID', 36 'L2CAP', 37 'RFCOMM', 38 'SDP', 39 'SM' 40] 41 42program_info = ''' 43BTstack Event Getter Generator for BTstack 44Copyright 2016, BlueKitchen GmbH 45''' 46 47copyright = """/* 48 * Copyright (C) 2016 BlueKitchen GmbH 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of the copyright holders nor the names of 60 * contributors may be used to endorse or promote products derived 61 * from this software without specific prior written permission. 62 * 4. Any redistribution, use, or modification is done solely for 63 * personal benefit and not for any commercial purpose or for 64 * monetary gain. 65 * 66 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 67 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 68 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 69 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 70 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 71 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 72 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 73 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 74 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 75 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 76 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 77 * SUCH DAMAGE. 78 * 79 * Please inquire about commercial licensing options at 80 * [email protected] 81 * 82 */ 83""" 84 85hfile_header_begin = """ 86 87/** 88 * HCI Event Getter 89 * 90 * Note: Don't edit this file. It is generated by tool/btstack_event_generator.py 91 * 92 */ 93 94#ifndef BTSTACK_EVENT_H 95#define BTSTACK_EVENT_H 96 97#if defined __cplusplus 98extern "C" { 99#endif 100 101#include "btstack_util.h" 102#include <stdint.h> 103 104#ifdef ENABLE_BLE 105#include "ble/gatt_client.h" 106#endif 107 108/* API_START */ 109 110/** 111 * @brief Get event type 112 * @param event 113 * @return type of event 114 */ 115static inline uint8_t hci_event_packet_get_type(const uint8_t * event){ 116 return event[0]; 117} 118 119""" 120 121hfile_header_end = """ 122 123/* API_END */ 124 125#if defined __cplusplus 126} 127#endif 128 129#endif // BTSTACK_EVENT_H 130""" 131 132c_prototoype_simple_return = '''/** 133 * @brief {description} 134 * @param event packet 135 * @return {result_name} 136 * @note: btstack_type {format} 137 */ 138static inline {result_type} {fn_name}(const uint8_t * event){{ 139 {code} 140}} 141''' 142 143c_prototoype_array_getter = '''/** 144 * @brief {description} 145 * @param event packet 146 * @param index 147 * @return {result_name} 148 * @note: btstack_type {format} 149 */ 150static inline {result_type} {fn_name}(const uint8_t * event, uint8_t index){{ 151 {code} 152}} 153''' 154 155c_prototoype_struct_return = '''/** 156 * @brief {description} 157 * @param event packet 158 * @param Pointer to storage for {result_name} 159 * @note: btstack_type {format} 160 */ 161static inline void {fn_name}(const uint8_t * event, {result_type} {result_name}){{ 162 {code} 163}} 164''' 165 166c_prototoype_unsupported = '''/** 167 * @brief {description} 168 * @param event packet 169 * @return {result_name} 170 * @note: btstack_type {format} 171 */ 172// static inline {result_type} {fn_name}(const uint8_t * event){{ 173// not implemented yet 174// }} 175''' 176 177meta_event_template = '''/*** 178 * @brief Get subevent code for {meta_event} event 179 * @param event packet 180 * @return subevent_code 181 */ 182static inline uint8_t hci_event_{meta_event}_meta_get_subevent_code(const uint8_t * event){{ 183 return event[2]; 184}} 185''' 186 187# global variables/defines 188defines = dict() 189defines_used = set() 190 191param_read = { 192 '1' : 'return event[{offset}];', 193 'J' : 'return event[{offset}];', 194 '2' : 'return little_endian_read_16(event, {offset});', 195 'L' : 'return little_endian_read_16(event, {offset});', 196 '3' : 'return little_endian_read_24(event, {offset});', 197 '4' : 'return little_endian_read_32(event, {offset});', 198 'H' : 'return little_endian_read_16(event, {offset});', 199 'B' : 'reverse_bytes(&event[{offset}], {result_name}, 6);', 200 'R' : 'return &event[{offset}];', 201 'N' : 'return (const char *) &event[{offset}];', 202 'T' : 'return (const char *) &event[{offset}];', 203 'D' : 'return (const uint8_t *) &event[{offset}];', 204 'K' : 'reverse_bytes(&event[{offset}], {result_name}, 16);', 205 'Q' : 'reverse_bytes(&event[{offset}], {result_name}, 32);', 206 'V' : 'return &event[{offset}];', 207 'X' : 'gatt_client_deserialize_service(event, {offset}, {result_name});', 208 'Y' : 'gatt_client_deserialize_characteristic(event, {offset}, {result_name});', 209 'Z' : 'gatt_client_deserialize_characteristic_descriptor(event, {offset}, {result_name});', 210 'V' : 'return &event[{offset}];', 211 'C' : 'return little_endian_read_16(event, {offset} + (2 * index));' 212} 213 214def c_type_for_btstack_type(type): 215 param_types = { '1' : 'uint8_t', '2' : 'uint16_t', '3' : 'uint32_t', '4' : 'uint32_t', 'H' : 'hci_con_handle_t', 'B' : 'bd_addr_t', 216 'D' : 'const uint8_t *', 'E' : 'const uint8_t * ', 'N' : 'const char *' , 'P' : 'const uint8_t *', 'A' : 'const uint8_t *', 217 'R' : 'const uint8_t *', 'S' : 'const uint8_t *', 218 'J' : 'uint8_t', 'L' : 'uint16_t', 'V' : 'const uint8_t *', 'U' : 'BT_UUID', 219 'Q' : 'uint8_t *', 'K' : 'uint8_t *', 220 'X' : 'gatt_client_service_t *', 'Y' : 'gatt_client_characteristic_t *', 'Z' : 'gatt_client_characteristic_descriptor_t *', 221 'T' : 'const char *', 'C' : 'uint16_t' } 222 return param_types[type] 223 224def size_for_type(type): 225 param_sizes = { '1' : 1, '2' : 2, '3' : 3, '4' : 4, 'H' : 2, 'B' : 6, 'D' : 8, 'E' : 240, 'N' : 248, 'P' : 16, 'Q':32, 'K':16, 226 'A' : 31, 'S' : -1, 'V': -1, 'J' : 1, 'L' : 2, 'U' : 16, 'X' : 20, 'Y' : 24, 'Z' : 18, 'T':-1, 'C':-1 } 227 return param_sizes[type] 228 229def format_function_name(event_name): 230 event_name = event_name.lower() 231 if 'event' in event_name: 232 return event_name; 233 return event_name+'_event' 234 235def template_for_type(field_type): 236 global c_prototoype_simple_return 237 global c_prototoype_struct_return 238 global c_prototoype_array_getter 239 if field_type == 'C': 240 return c_prototoype_array_getter 241 types_with_struct_return = "BKQXYZ" 242 if field_type in types_with_struct_return: 243 return c_prototoype_struct_return 244 else: 245 return c_prototoype_simple_return 246 247def all_fields_supported(format): 248 global param_read 249 for f in format: 250 if not f in param_read: 251 return False 252 return True 253 254def create_getter(event_name, field_name, field_type, offset, supported): 255 global c_prototoype_unsupported 256 global param_read 257 258 if field_type == 'C': 259 description_template = 'Get element of array field %s from event %s' 260 else: 261 description_template = "Get field %s from event %s" 262 description = description_template % (field_name, event_name.upper()) 263 result_name = field_name 264 fn_name = "%s_get_%s" % (event_name, field_name) 265 result_type = c_type_for_btstack_type(field_type) 266 template = c_prototoype_unsupported 267 code = '' 268 if supported and field_type in param_read: 269 template = template_for_type(field_type) 270 code = param_read[field_type].format(offset=offset, result_name=result_name) 271 return template.format(description=description, fn_name=fn_name, result_name=result_name, result_type=result_type, code=code, format=field_type) 272 273def is_le_event(event_group): 274 return event_group in ['GATT', 'ANCS', 'SM'] 275 276def create_events(events): 277 global gen_path 278 global copyright 279 global hfile_header_begin 280 global hfile_header_end 281 global meta_event_template 282 283 with open(gen_path, 'wt') as fout: 284 fout.write(copyright) 285 fout.write(hfile_header_begin) 286 287 for meta_event in meta_events: 288 fout.write(meta_event_template.format(meta_event=meta_event.lower())) 289 290 for event_type, event_name, format, args in events: 291 parts = event_name.split("_") 292 event_group = parts[0] 293 if not event_group in supported_event_groups: 294 print("// %s " % event_name) 295 continue 296 # print(event_name) 297 base_name = format_function_name(event_name) 298 length_name = '' 299 offset = 2 300 offset_is_number = 1 301 offset_unknown = 0 302 supported = all_fields_supported(format) 303 last_variable_length_field_pos = "" 304 if is_le_event(event_group): 305 fout.write("#ifdef ENABLE_BLE\n") 306 if len(format) != len(args): 307 print(event_name.upper()) 308 print ("Format %s does not match params %s " % (format, args)) 309 print 310 for f, arg in zip(format, args): 311 field_name = arg 312 if field_name.lower() == 'subevent_code': 313 offset += 1 314 continue 315 if offset_unknown: 316 print("Param after variable length field without preceding 'J' length field") 317 break 318 field_type = f 319 text = create_getter(base_name, field_name, field_type, offset, supported) 320 fout.write(text) 321 if field_type in 'RT': 322 break 323 if field_type in 'J': 324 if offset_is_number: 325 last_variable_length_field_pos = '%u' % offset 326 else: 327 last_variable_length_field_pos = offset 328 if field_type in 'V': 329 if last_variable_length_field_pos != '': 330 if offset_is_number: 331 # convert to string 332 offset = '%uu' % offset 333 offset_is_number = 0 334 offset = offset + ' + event[%s]' % last_variable_length_field_pos 335 else: 336 offset_unknown = 1 337 else: 338 if offset_is_number: 339 offset += size_for_type(field_type) 340 else: 341 offset = offset + ' + %uu' % size_for_type(field_type) 342 if is_le_event(event_group): 343 fout.write("#endif\n") 344 fout.write("\n") 345 346 fout.write(hfile_header_end) 347 348btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..') 349gen_path = btstack_root + '/src/btstack_event.h' 350 351print(program_info) 352 353# parse events 354(events, le_events, event_types) = parser.parse_events() 355 356# create event field accesors 357create_events(events + le_events) 358 359# done 360print('Done!') 361