#!/usr/bin/env python # BlueKitchen GmbH (c) 2018 import glob import re import sys import os import btstack_parser as parser print(''' Python binding generator for BTstack Server Copyright 2018, BlueKitchen GmbH ''') # com.bluekitchen.btstack.BTstack.java templates command_builder_header = \ '''#!/usr/bin/env python3 import struct def opcode(ogf, ocf): return ocf | (ogf << 10) def pack24(value): return struct.pack("B", value & 0xff) + struct.pack("> 8) def name248(str): arg = str.encode('utf-8') return arg[:248] + bytes(248-len(arg)) # Command Builder class CommandBuilder(object): def __init__(self): pass def send_command(command): return FALSE ''' command_builder_command = ''' def {name}(self, {args}): cmd_args = bytes() {args_builder} cmd = struct.pack(""); # return t.toString(); ''' # global variables/defines package ='com.bluekitchen.btstack' gen_path = 'gen/' + package.replace('.', '/') defines = dict() defines_used = set() def java_type_for_btstack_type(type): param_types = { '1' : 'int', '2' : 'int', '3' : 'int', '4' : 'long', 'H' : 'int', 'B' : 'BD_ADDR', 'D' : 'byte []', 'E' : 'byte [] ', 'N' : 'String' , 'P' : 'byte []', 'A' : 'byte []', 'R' : 'byte []', 'S' : 'byte []', 'Q' : 'byte []', 'J' : 'int', 'L' : 'int', 'V' : 'byte []', 'U' : 'BT_UUID', 'X' : 'GATTService', 'Y' : 'GATTCharacteristic', 'Z' : 'GATTCharacteristicDescriptor', 'T' : 'String'} return param_types[type] def size_for_type(type): param_sizes = { '1' : 1, '2' : 2, '3' : 3, '4' : 4, 'H' : 2, 'B' : 6, 'D' : 8, 'E' : 240, 'N' : 248, 'P' : 16, 'A' : 31, 'S' : -1, 'V': -1, 'J' : 1, 'L' : 2, 'Q' : 32, 'U' : 16, 'X' : 20, 'Y' : 24, 'Z' : 18, 'T':-1} return param_sizes[type] def create_command_python(fout, name, ogf, ocf, format, params): global command_builder_command ind = ' ' param_store = { '1' : 'cmd_args += struct.pack("B", %s)', 'J' : 'cmd_args += struct.pack("B", %s)', '2' : 'cmd_args += struct.pack(" 0: size_fixed += size else: size_var += ' + %s.length' % arg[2] size_string = '%u%s' % (size_fixed, size_var) store_params = '' length_name = '' for (param_type, arg_size, arg_name) in args: if param_type in ['L', 'J']: length_name = arg_name if param_type == 'V': store_params += ind + 'Util.storeBytes(command, offset, %s, %s);' % (arg_name, length_name) + '\n'; length_name = '' else: store_params += ind + (param_store[param_type] % arg_name) + '\n'; size = arg_size fout.write( command_builder_command.format(name=name, args=args_string, ogf=ogf, ocf=ocf, args_builder=store_params)) def mark_define_as_used(term): if term.startswith('0'): return defines_used.add(term) def python_define_string(key): global defines if key in defines: return ' %s = %s\n' % (key, defines[key]) else: return ' # defines[%s] not set\n' % key def python_defines_string(keys): return '\n'.join( map(python_define_string, sorted(keys))) def create_command_builder(commands): global gen_path parser.assert_dir(gen_path) outfile = '%s/command_builder.py' % gen_path with open(outfile, 'wt') as fout: fout.write(command_builder_header) for command in commands: (command_name, ogf, ocf, format, params) = command create_command_python(fout, command_name, ogf, ocf, format, params); mark_define_as_used(ogf) mark_define_as_used(ocf) fout.write('\n # defines used\n\n') for key in sorted(defines_used): fout.write(python_define_string(key)) def create_event(fout, event_name, format, args): global gen_path global java_event_template param_read = { '1' : 'return self.payload[{offset}]', 'J' : 'return self.payload[{offset}]', '2' : 'return struct.unpack("