mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-01-27 15:35:30 +00:00
daemon/binding/python: event factory
This commit is contained in:
parent
dbd3360137
commit
760c66926a
@ -1,14 +1,11 @@
|
||||
import socket
|
||||
import struct
|
||||
import btstack.command_builder
|
||||
import btstack.event_factory
|
||||
|
||||
BTSTACK_SERVER_HOST = "localhost"
|
||||
BTSTACK_SERVER_TCP_PORT = 13333
|
||||
|
||||
# temp
|
||||
OGF_BTSTACK = 0x3d;
|
||||
BTSTACK_SET_POWER_MODE = 0x02
|
||||
|
||||
# utils
|
||||
def print_hex(data):
|
||||
print(" ".join("{:02x}".format(c) for c in data))
|
||||
@ -31,7 +28,7 @@ class BTstackClient(btstack.command_builder.CommandBuilder):
|
||||
print("[+] Connect to server on port %u" % BTSTACK_SERVER_TCP_PORT)
|
||||
self.btstack_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.btstack_server_socket.connect((BTSTACK_SERVER_HOST, BTSTACK_SERVER_TCP_PORT))
|
||||
# TODO: handle connection failure
|
||||
# TODO: handle connection failure - e.g. retry for max 5 seconds every seconde
|
||||
|
||||
def register_packet_handler(self, callback):
|
||||
print("[+] Register packet handler")
|
||||
@ -50,6 +47,10 @@ class BTstackClient(btstack.command_builder.CommandBuilder):
|
||||
# receive packet header: packet type, channel, len
|
||||
header = self.btstack_server_socket.recv(6)
|
||||
(packet_type, channel, length) = struct.unpack("<HHH", header)
|
||||
print_hex(header)
|
||||
# print_hex(header)
|
||||
payload = self.btstack_server_socket.recv(length)
|
||||
print_hex(payload)
|
||||
# print_hex(payload)
|
||||
if packet_type == 1:
|
||||
event = btstack.event_factory.event_for_payload(payload)
|
||||
# self.packet_handler(event)
|
||||
print(event)
|
||||
|
@ -26,11 +26,8 @@ class BD_ADDR(object):
|
||||
data.reverse()
|
||||
return data
|
||||
|
||||
def __str__(self):
|
||||
return ":".join([('%02x' % a) for a in self.addr])
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
return ":".join([('%02x' % a) for a in self.addr])
|
||||
|
||||
class BT_UUID(object):
|
||||
# uuid stored in big endian
|
||||
@ -60,13 +57,11 @@ class BT_UUID(object):
|
||||
data.reverse()
|
||||
return data
|
||||
|
||||
def __str__(self):
|
||||
def __repr__(self):
|
||||
return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
|
||||
self.uuid[0], self.uuid[1], self.uuid[2], self.uuid[3], self.uuid[4], self.uuid[5], self.uuid[6], self.uuid[7],
|
||||
self.uuid[8], self.uuid[9], self.uuid[10], self.uuid[11], self.uuid[12], self.uuid[13], self.uuid[14], self.uuid[15]);
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class GATTCharacteristic(object):
|
||||
|
||||
@ -101,13 +96,10 @@ class GATTCharacteristic(object):
|
||||
def get_uuid(self):
|
||||
return BT_UUID(self.data[8:])
|
||||
|
||||
def __str__(self):
|
||||
def __repr__(self):
|
||||
return "GATTCharacteristic [start_handle={start_handle}, value_handle={value_handle}, end_handle={end_handle}, get_uuid={uuid}]".format(
|
||||
start_handle=self.get_start_handle(), value_handle=self.get_value_handle(), end_handle=self.get_end_handle(), uuid=self.get_uuid())
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
||||
|
||||
class GATTCharacteristicDescriptor(object):
|
||||
@ -128,13 +120,10 @@ class GATTCharacteristicDescriptor(object):
|
||||
def get_uuid(self):
|
||||
return BT_UUID(self.data[2:])
|
||||
|
||||
def __str__(self):
|
||||
def __repr__(self):
|
||||
return "GATTCharacteristicDescriptor [handle={handle}, get_uuid={uuid}]".format(
|
||||
handle=self.get_handle(), uuid=self.get_uuid())
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
||||
class GATTService(object):
|
||||
|
||||
@ -159,12 +148,10 @@ class GATTService(object):
|
||||
def get_uuid(self):
|
||||
return BT_UUID(self.data[4:])
|
||||
|
||||
def __str__(self):
|
||||
def __repr__(self):
|
||||
return "GattService [start_group_handle={start_group_handle}, [end_group_handle={end_group_handle}, get_uuid={uuid}]".format(
|
||||
start_group_handle=self.get_start_group_handle(), end_group_handle=self.get_end_group_handle(), uuid=self.get_uuid())
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class Packet(object):
|
||||
|
||||
@ -187,12 +174,10 @@ class Packet(object):
|
||||
def get_payload(self):
|
||||
return self.payload
|
||||
|
||||
def __str__(self):
|
||||
def __repr__(self):
|
||||
return "Packet type {packet_type}, channel {channel}, payload {payload}".format(packet_type={self.get_packet_type()},
|
||||
channel={self.get_channel()}, payload=hex_string(self.get_payload()))
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class Event(Packet):
|
||||
|
||||
@ -204,12 +189,10 @@ class Event(Packet):
|
||||
def get_event_type(self):
|
||||
return self.payload[0]
|
||||
|
||||
def __str__(self):
|
||||
def __repr__(self):
|
||||
return "Event type {event_type}, payload {payload}".format(event_type={self.get_event_type()},
|
||||
payload=hex_string(self.get_payload()))
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class BTstackEventState(Packet):
|
||||
|
||||
|
@ -32,6 +32,7 @@ def name248(str):
|
||||
# Command Builder
|
||||
|
||||
class CommandBuilder(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@ -39,6 +40,7 @@ class CommandBuilder(object):
|
||||
return FALSE
|
||||
|
||||
'''
|
||||
|
||||
command_builder_command = '''
|
||||
def {name}(self, {args}):
|
||||
cmd_args = bytes()
|
||||
@ -48,90 +50,74 @@ command_builder_command = '''
|
||||
'''
|
||||
|
||||
# com.bluekitchen.btstack.EventFactory template
|
||||
java_event_factory_template = \
|
||||
event_factory_template = \
|
||||
'''
|
||||
|
||||
class EventFactory(object:
|
||||
# dictionary to map hci event types to event classes
|
||||
event_class_for_type = {{
|
||||
{1}}}
|
||||
|
||||
# @brief event codes
|
||||
# dictionary to map hci le event types to event classes
|
||||
le_event_class_for_type = {{
|
||||
{2}}}
|
||||
|
||||
# list of all event types - not actually used
|
||||
{0}
|
||||
def event_for_packet(packet):
|
||||
event_type = packet.get_payload()[0]
|
||||
# switch (eventType){{
|
||||
{1}
|
||||
# case 0x3e: // LE_META_EVENT
|
||||
# int subEventType = Util.readByte(packet.getBuffer(), 2);
|
||||
# switch (subEventType){{
|
||||
{2}
|
||||
# default:
|
||||
# return new Event(packet);
|
||||
|
||||
# default:
|
||||
# return new Event(packet);
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
def event_for_payload(payload):
|
||||
event_type = payload[0]
|
||||
event_class = btstack.btstack_types.Event
|
||||
# LE Subevent
|
||||
if event_type == 0x3e:
|
||||
subevent_type = payload[2]
|
||||
event_class = le_event_class_for_type[subevent_type]
|
||||
else:
|
||||
event_class = event_class_for_type[event_type]
|
||||
return event_class(payload)
|
||||
'''
|
||||
java_event_factory_event = '''
|
||||
case {0}:
|
||||
return new {1}(packet);
|
||||
event_factory_event = \
|
||||
''' {0} : {1},
|
||||
'''
|
||||
java_event_factory_subevent = '''
|
||||
case {0}:
|
||||
return new {1}(packet);
|
||||
event_factory_subevent = \
|
||||
''' {0} : {1},
|
||||
'''
|
||||
|
||||
# com.bluekitchen.btstack.events.* template
|
||||
java_event_template = \
|
||||
event_header = '''
|
||||
import btstack.btstack_types
|
||||
'''
|
||||
|
||||
class {0}(Event):
|
||||
event_template = \
|
||||
'''
|
||||
|
||||
def __init__(self, packet):
|
||||
# super(packet);
|
||||
class {0}(btstack.btstack_types.Event):
|
||||
|
||||
def __init__(self, payload):
|
||||
super().__init__(payload)
|
||||
{1}
|
||||
{2}
|
||||
'''
|
||||
|
||||
java_event_getter = \
|
||||
event_getter = \
|
||||
'''
|
||||
# @return {1} as {0}
|
||||
def get_{1}(self):
|
||||
{2}
|
||||
def get_{0}(self):
|
||||
{1}
|
||||
'''
|
||||
|
||||
java_event_getter_data = \
|
||||
'''# java_event_getter_data
|
||||
# int len = get{length_name}();
|
||||
# byte[] result = new byte[len];
|
||||
# System.arraycopy(data, {offset}, result, 0, len);
|
||||
# return result;'''
|
||||
event_getter_data = \
|
||||
'''# len = self.get_{length_name}()
|
||||
return self.payload[{offset},{offset}+len]
|
||||
'''
|
||||
|
||||
java_event_getter_data_fixed = \
|
||||
'''# java_event_getter_data_fixed
|
||||
# int len = {size};
|
||||
# byte[] result = new byte[len];
|
||||
# System.arraycopy(data, {offset}, result, 0, len);
|
||||
# return result;'''
|
||||
event_getter_data_fixed = \
|
||||
'''return self.payload[{offset},{offset}+{size}]
|
||||
'''
|
||||
|
||||
java_event_getter_remaining_data = \
|
||||
'''# java_event_getter_remaining_data
|
||||
# int len = getPayloadLen() - {offset};
|
||||
# byte[] result = new byte[len];
|
||||
# System.arraycopy(data, {offset}, result, 0, len);
|
||||
# return result;'''
|
||||
|
||||
java_event_to_string = \
|
||||
'''# java_event_to_string
|
||||
def __str__(self):
|
||||
# StringBuffer t = new StringBuffer();
|
||||
# t.append("{0} < type = ");
|
||||
# t.append(String.format("0x%02x, ", getEventType()));
|
||||
# t.append(getEventType());
|
||||
event_to_string = \
|
||||
'''def __repr__(self):
|
||||
repr = '{0} < type=0x%02x' % self.get_event_type()
|
||||
{1}
|
||||
# t.append(" >");
|
||||
# return t.toString();
|
||||
repr += " >"
|
||||
return repr
|
||||
'''
|
||||
|
||||
|
||||
@ -142,15 +128,6 @@ 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}
|
||||
@ -260,7 +237,7 @@ def create_command_builder(commands):
|
||||
|
||||
def create_event(fout, event_name, format, args):
|
||||
global gen_path
|
||||
global java_event_template
|
||||
global event_template
|
||||
|
||||
param_read = {
|
||||
'1' : 'return self.payload[{offset}]',
|
||||
@ -274,14 +251,15 @@ def create_event(fout, event_name, format, args):
|
||||
'X' : 'return btstack.btstack_types.GATTService(self.payload[{offset}:20])',
|
||||
'Y' : 'return btstack.btstack_types.GATTCharacteristic(self.payload[{offset}:24])',
|
||||
'Z' : 'return btstack.btstack_types.GATTCharacteristicDescriptor(self.payload[{offset}:18])',
|
||||
'T' : '# TODO - convert remaining bytes from {offset} into string object',
|
||||
'N' : '# TODO - convert 248 bytes from {offset} into string object',
|
||||
'T' : 'return self.payload[{offset}:].decode("utf-8")',
|
||||
'N' : 'return self.payload[{offset}:{offset}+248].decode("utf-8")',
|
||||
# 'D' : 'Util.storeBytes(self.payload, %u, 8);',
|
||||
# 'Q' : 'Util.storeBytes(self.payload, %u, 32);',
|
||||
# 'E' : 'Util.storeBytes(data, %u, 240);',
|
||||
# 'P' : 'Util.storeBytes(data, %u, 16);',
|
||||
# 'A' : 'Util.storeBytes(data, %u, 31);',
|
||||
# 'S' : 'Util.storeBytes(data, %u);'
|
||||
'R' : 'return self.payload[{offset}:]',
|
||||
}
|
||||
|
||||
offset = 2
|
||||
@ -293,25 +271,25 @@ def create_event(fout, event_name, format, args):
|
||||
length_name = arg.lower()
|
||||
if f == 'R':
|
||||
# remaining data
|
||||
access = java_event_getter_remaining_data.format(offset=offset)
|
||||
access = param_read[f].format(offset=offset)
|
||||
size = 0
|
||||
elif f == 'V':
|
||||
access = java_event_getter_data.format(length_name=length_name, offset=offset)
|
||||
access = event_getter_data.format(length_name=length_name, offset=offset)
|
||||
size = 0
|
||||
elif f in ['D', 'Q']:
|
||||
size = size_for_type(f)
|
||||
access = java_event_getter_data_fixed.format(size=size, offset=offset)
|
||||
access = event_getter_data_fixed.format(size=size, offset=offset)
|
||||
else:
|
||||
access = param_read[f].format(offset=offset)
|
||||
size = size_for_type(f)
|
||||
getters += java_event_getter.format(java_type_for_btstack_type(f), arg.lower(), access)
|
||||
getters += event_getter.format(arg.lower(), access)
|
||||
offset += size
|
||||
to_string_args = ''
|
||||
for arg in args:
|
||||
to_string_args += ' # t.append(", %s = ");\n' % arg
|
||||
to_string_args += ' # t.append(get%s());\n' % parser.camel_case(arg)
|
||||
to_string_method = java_event_to_string.format(event_name, to_string_args)
|
||||
fout.write(java_event_template.format(event_name, getters, to_string_method))
|
||||
to_string_args += ' repr += ", %s = "\n' % arg
|
||||
to_string_args += ' repr += str(self.get_%s())\n' % arg.lower()
|
||||
to_string_method = event_to_string.format(event_name, to_string_args)
|
||||
fout.write(event_template.format(event_name, getters, to_string_method))
|
||||
|
||||
def event_supported(event_name):
|
||||
parts = event_name.split('_')
|
||||
@ -334,29 +312,33 @@ def create_events(fout, events):
|
||||
|
||||
def create_event_factory(events, subevents, defines):
|
||||
global gen_path
|
||||
global java_event_factory_event
|
||||
global java_event_factory_template
|
||||
global event_factory_event
|
||||
global event_factory_template
|
||||
|
||||
outfile = '%s/event_factory.py' % gen_path
|
||||
|
||||
|
||||
cases = ''
|
||||
for event_type, event_name, format, args in events:
|
||||
event_name = parser.camel_case(event_name)
|
||||
cases += java_event_factory_event.format(event_type, event_name)
|
||||
cases += event_factory_event.format(event_type, event_name)
|
||||
subcases = ''
|
||||
for event_type, event_name, format, args in subevents:
|
||||
if not event_supported(event_name):
|
||||
continue
|
||||
class_name = class_name_for_event(event_name)
|
||||
subcases += java_event_factory_subevent.format(event_type, class_name)
|
||||
subcases += event_factory_subevent.format(event_type, class_name)
|
||||
|
||||
with open(outfile, 'wt') as fout:
|
||||
# header
|
||||
fout.write(event_header)
|
||||
# event classes
|
||||
create_events(fout, events)
|
||||
create_events(fout, subevents)
|
||||
#
|
||||
defines_text = python_defines_string(defines)
|
||||
fout.write(java_event_factory_template.format(defines_text, cases, subcases))
|
||||
defines_text = ''
|
||||
# python_defines_string(,defines)
|
||||
fout.write(event_factory_template.format(defines_text, cases, subcases))
|
||||
|
||||
# find root
|
||||
btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..')
|
||||
|
Loading…
x
Reference in New Issue
Block a user