mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 01:27:41 +00:00
bindings: extract btstack_parser to parse commands and events
This commit is contained in:
parent
3ad6e8fa85
commit
0f035029e4
@ -17,7 +17,7 @@
|
||||
|
||||
<target name="generate">
|
||||
<mkdir dir="${gen.dir}"/>
|
||||
<exec executable="./../tools/generate.py"/>
|
||||
<exec executable="./../tools/java_binding.py"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="generate">
|
||||
|
119
tools/btstack_parser.py
Executable file
119
tools/btstack_parser.py
Executable file
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python
|
||||
# BlueKitchen GmbH (c) 2014
|
||||
|
||||
import re
|
||||
|
||||
# paths
|
||||
hci_cmds_h_path = 'include/btstack/hci_cmds.h'
|
||||
hci_cmds_c_path = 'src/hci_cmds.c'
|
||||
hci_h_path = 'src/hci.h'
|
||||
|
||||
btstack_root = '..'
|
||||
|
||||
def set_btstack_root(path):
|
||||
btstack_root = path
|
||||
|
||||
def cap(x):
|
||||
if x.lower() == 'btstack':
|
||||
return 'BTstack'
|
||||
acronyms = ['GAP', 'GATT', 'HCI', 'L2CAP', 'LE', 'RFCOMM', 'SM', 'SDP', 'UUID16', 'UUID128']
|
||||
if x.upper() in acronyms:
|
||||
return x.upper()
|
||||
return x.capitalize()
|
||||
|
||||
def camel_case(name):
|
||||
return ''.join(map(cap, name.split('_')))
|
||||
|
||||
def camel_case_var(name):
|
||||
if name in ['uuid128', 'uuid16']:
|
||||
return name
|
||||
camel = camel_case(name)
|
||||
return camel[0].lower() + camel[1:]
|
||||
|
||||
def read_defines(infile):
|
||||
defines = dict()
|
||||
with open (infile, 'rt') as fin:
|
||||
for line in fin:
|
||||
parts = re.match('#define\s+(\w+)\s+(\w*)',line)
|
||||
if parts and len(parts.groups()) == 2:
|
||||
(key, value) = parts.groups()
|
||||
defines[key] = value
|
||||
return defines
|
||||
|
||||
def parse_defines():
|
||||
global btstack_root
|
||||
defines = dict()
|
||||
defines.update(read_defines(btstack_root + '/' + hci_cmds_h_path))
|
||||
defines.update(read_defines(btstack_root + '/' + hci_h_path))
|
||||
return defines
|
||||
|
||||
def my_parse_events(path):
|
||||
events = []
|
||||
le_events = []
|
||||
params = []
|
||||
event_types = set()
|
||||
format = None
|
||||
with open (path, 'rt') as fin:
|
||||
for line in fin:
|
||||
parts = re.match('.*@format\s*(\w*)\s*', line)
|
||||
if parts and len(parts.groups()) == 1:
|
||||
format = parts.groups()[0]
|
||||
parts = re.match('.*@param\s*(\w*)\s*', line)
|
||||
if parts and len(parts.groups()) == 1:
|
||||
param = parts.groups()[0]
|
||||
params.append(param)
|
||||
parts = re.match('\s*#define\s+(\w+)\s+(\w*)',line)
|
||||
if parts and len(parts.groups()) == 2:
|
||||
(key, value) = parts.groups()
|
||||
if format != None:
|
||||
if key.lower().startswith('hci_subevent_'):
|
||||
le_events.append((value, key.lower().replace('hci_subevent_', 'hci_event_'), format, params))
|
||||
else:
|
||||
events.append((value, key, format, params))
|
||||
event_types.add(key)
|
||||
params = []
|
||||
format = None
|
||||
return (events, le_events, event_types)
|
||||
|
||||
def parse_events():
|
||||
global btstack_root
|
||||
return my_parse_events(btstack_root + '/' + hci_cmds_h_path)
|
||||
|
||||
def my_parse_commands(infile):
|
||||
commands = []
|
||||
with open (infile, 'rt') as fin:
|
||||
|
||||
params = []
|
||||
for line in fin:
|
||||
|
||||
parts = re.match('.*@param\s*(\w*)\s*', line)
|
||||
if parts and len(parts.groups()) == 1:
|
||||
param = parts.groups()[0]
|
||||
params.append(camel_case_var(param))
|
||||
continue
|
||||
|
||||
declaration = re.match('const\s+hci_cmd_t\s+(\w+)[\s=]+', line)
|
||||
if declaration:
|
||||
command_name = camel_case(declaration.groups()[0])
|
||||
if command_name.endswith('Cmd'):
|
||||
command_name = command_name[:-len('Cmd')]
|
||||
continue
|
||||
|
||||
definition = re.match('\s*OPCODE\\(\s*(\w+)\s*,\s+(\w+)\s*\\)\s*,\s\\"(\w*)\\".*', line)
|
||||
if definition:
|
||||
(ogf, ocf, format) = definition.groups()
|
||||
if len(params) != len(format):
|
||||
params = []
|
||||
arg_counter = 1
|
||||
for f in format:
|
||||
arg_name = 'arg%u' % arg_counter
|
||||
params.append(arg_name)
|
||||
arg_counter += 1
|
||||
commands.append((command_name, ogf, ocf, format, params))
|
||||
params = []
|
||||
continue
|
||||
return commands
|
||||
|
||||
def parse_commands():
|
||||
global btstack_root
|
||||
return my_parse_commands(btstack_root + '/' + hci_cmds_c_path)
|
@ -1,11 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
# BlueKtichen GmbH (c) 2014
|
||||
# BlueKitchen GmbH (c) 2014
|
||||
|
||||
import glob
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
import btstack_parser as parser
|
||||
|
||||
print('''
|
||||
Java binding generator for BTstack
|
||||
Copyright 2014, BlueKitchen GmbH
|
||||
@ -130,11 +132,8 @@ java_event_to_string = \
|
||||
|
||||
|
||||
# global variables/defines
|
||||
package='com.bluekitchen.btstack'
|
||||
package ='com.bluekitchen.btstack'
|
||||
gen_path = 'gen/' + package.replace('.', '/')
|
||||
hci_cmds_h_path = '../include/btstack/hci_cmds.h'
|
||||
hci_cmds_c_path = '../src/hci_cmds.c'
|
||||
hci_h_path = '../src/hci.h'
|
||||
|
||||
defines = dict()
|
||||
defines_used = set()
|
||||
@ -154,22 +153,6 @@ def cap(x):
|
||||
def camel_case(name):
|
||||
return ''.join(map(cap, name.split('_')))
|
||||
|
||||
def camel_case_var(name):
|
||||
if name in ['uuid128', 'uuid16']:
|
||||
return name
|
||||
camel = camel_case(name)
|
||||
return camel[0].lower() + camel[1:]
|
||||
|
||||
def read_defines(infile):
|
||||
global defines
|
||||
with open (infile, 'rt') as fin:
|
||||
|
||||
for line in fin:
|
||||
parts = re.match('#define\s+(\w+)\s+(\w*)',line)
|
||||
if parts and len(parts.groups()) == 2:
|
||||
(key, value) = parts.groups()
|
||||
defines[key] = value
|
||||
|
||||
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 []',
|
||||
@ -267,7 +250,7 @@ def java_define_string(key):
|
||||
def java_defines_string(keys):
|
||||
return '\n'.join( map(java_define_string, sorted(keys)))
|
||||
|
||||
def parse_commands(infile):
|
||||
def create_btstack_java(commands):
|
||||
|
||||
global gen_path
|
||||
assert_dir(gen_path)
|
||||
@ -278,39 +261,11 @@ def parse_commands(infile):
|
||||
|
||||
fout.write(java_btstack_header % package)
|
||||
|
||||
with open (infile, 'rt') as fin:
|
||||
|
||||
params = []
|
||||
for line in fin:
|
||||
|
||||
parts = re.match('.*@param\s*(\w*)\s*', line)
|
||||
if parts and len(parts.groups()) == 1:
|
||||
param = parts.groups()[0]
|
||||
params.append(camel_case_var(param))
|
||||
continue
|
||||
|
||||
declaration = re.match('const\s+hci_cmd_t\s+(\w+)[\s=]+', line)
|
||||
if declaration:
|
||||
command_name = camel_case(declaration.groups()[0])
|
||||
if command_name.endswith('Cmd'):
|
||||
command_name = command_name[:-len('Cmd')]
|
||||
continue
|
||||
|
||||
definition = re.match('\s*OPCODE\\(\s*(\w+)\s*,\s+(\w+)\s*\\)\s*,\s\\"(\w*)\\".*', line)
|
||||
if definition:
|
||||
(ogf, ocf, format) = definition.groups()
|
||||
if len(params) != len(format):
|
||||
params = []
|
||||
arg_counter = 1
|
||||
for f in format:
|
||||
arg_name = 'arg%u' % arg_counter
|
||||
params.append(arg_name)
|
||||
arg_counter += 1
|
||||
create_command_java(fout, command_name, ogf, ocf, format, params);
|
||||
mark_define_as_used(ogf)
|
||||
mark_define_as_used(ocf)
|
||||
params = []
|
||||
continue
|
||||
for command in commands:
|
||||
(command_name, ogf, ocf, format, params) = command
|
||||
create_command_java(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):
|
||||
@ -403,49 +358,21 @@ def create_event_factory(events, le_events, defines):
|
||||
defines_text = java_defines_string(defines)
|
||||
fout.write(java_event_factory_template.format(package, defines_text, cases, subcases))
|
||||
|
||||
def parse_events(path):
|
||||
global gen_path
|
||||
events = []
|
||||
le_events = []
|
||||
params = []
|
||||
event_types = set()
|
||||
format = None
|
||||
with open (path, 'rt') as fin:
|
||||
for line in fin:
|
||||
parts = re.match('.*@format\s*(\w*)\s*', line)
|
||||
if parts and len(parts.groups()) == 1:
|
||||
format = parts.groups()[0]
|
||||
parts = re.match('.*@param\s*(\w*)\s*', line)
|
||||
if parts and len(parts.groups()) == 1:
|
||||
param = parts.groups()[0]
|
||||
params.append(param)
|
||||
parts = re.match('\s*#define\s+(\w+)\s+(\w*)',line)
|
||||
if parts and len(parts.groups()) == 2:
|
||||
(key, value) = parts.groups()
|
||||
if format != None:
|
||||
if key.lower().startswith('hci_subevent_'):
|
||||
le_events.append((value, key.lower().replace('hci_subevent_', 'hci_event_'), format, params))
|
||||
else:
|
||||
events.append((value, key, format, params))
|
||||
event_types.add(key)
|
||||
params = []
|
||||
format = None
|
||||
return (events, le_events, event_types)
|
||||
|
||||
# # read defines from hci_cmds.h and hci.h
|
||||
read_defines(hci_cmds_h_path)
|
||||
read_defines(hci_h_path)
|
||||
# read defines from hci_cmds.h and hci.h
|
||||
defines = parser.parse_defines()
|
||||
|
||||
# # parse commands and generate BTstack.java
|
||||
parse_commands(hci_cmds_c_path)
|
||||
# # parse commands
|
||||
commands = parser.parse_commands()
|
||||
|
||||
# parse hci.h to get used events
|
||||
(events, le_events, event_types) = parse_events(hci_cmds_h_path)
|
||||
(events, le_events, event_types) = parser.parse_events()
|
||||
|
||||
# create events, le meta events, and event factory
|
||||
# create events, le meta events, event factory, and
|
||||
create_events(events)
|
||||
create_events(le_events)
|
||||
create_event_factory(events, le_events, event_types)
|
||||
create_btstack_java(commands)
|
||||
|
||||
# done
|
||||
print('Done!')
|
Loading…
x
Reference in New Issue
Block a user