1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-29 19:08:12 +00:00
trezor-firmware/tools/pb2py

166 lines
4.6 KiB
Plaintext
Raw Normal View History

2016-09-21 12:12:46 +00:00
#!/usr/bin/env python
2016-04-26 23:32:57 +00:00
import sys
import os
from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper
2016-09-21 12:12:46 +00:00
def process_type(t, cls, msg_id, indexfile):
imports = ["import protobuf as p", "from micropython import const"]
2016-04-27 20:44:37 +00:00
out = ["t = p.MessageType('%s')" % t, ]
2016-04-26 23:32:57 +00:00
2016-05-12 14:05:33 +00:00
if msg_id is not None:
2016-10-03 13:41:15 +00:00
out.append("t.wire_type = const(%d)" % msg_id)
2016-09-21 12:12:46 +00:00
if indexfile is not None:
2016-10-03 13:41:15 +00:00
indexfile.write("%s = const(%d)\n" % (t, msg_id))
2016-05-12 14:05:33 +00:00
2016-04-27 20:44:37 +00:00
print(" * type %s" % t)
for v in sorted(cls.DESCRIPTOR.fields_by_name.values(), key=lambda x: x.number):
2016-04-26 23:32:57 +00:00
number = v.number
2016-04-27 20:44:37 +00:00
fieldname = v.name
2016-04-26 23:32:57 +00:00
type = None
repeated = v.label == 3
required = v.label == 2
2016-04-27 20:44:37 +00:00
2016-09-21 12:12:46 +00:00
# print v.has_default_value, v.default_value
2016-04-27 20:44:37 +00:00
2016-04-26 23:32:57 +00:00
if v.type in (4, 13, 14):
# TYPE_UINT64 = 4
# TYPE_UINT32 = 13
# TYPE_ENUM = 14
type = 'p.UVarintType'
2016-04-27 20:44:37 +00:00
2016-04-26 23:32:57 +00:00
elif v.type == 9:
# TYPE_STRING = 9
type = 'p.UnicodeType'
elif v.type == 8:
# TYPE_BOOL = 8
type = 'p.BoolType'
2016-04-27 20:44:37 +00:00
2016-04-26 23:32:57 +00:00
elif v.type == 12:
# TYPE_BYTES = 12
type = 'p.BytesType'
elif v.type == 11:
# TYPE_MESSAGE = 1
type = "p.EmbeddedMessage(%s)" % v.message_type.name
2016-09-21 12:12:46 +00:00
imports.append("from .%s import %s" %
(v.message_type.name, v.message_type.name))
2016-04-26 23:32:57 +00:00
else:
raise Exception("Unknown field type %s for field %s" % (v.type, k))
if repeated:
flags = ', flags=p.FLAG_REPEATED'
elif required:
flags = ', flags=p.FLAG_REQUIRED'
else:
flags = ''
if v.has_default_value:
default = ', default=%s' % repr(v.default_value)
else:
default = ''
2016-09-21 12:12:46 +00:00
out.append("t.add_field(%d, '%s', %s%s%s)" %
2016-04-26 23:32:57 +00:00
(number, fieldname, type, flags, default))
2016-04-27 20:44:37 +00:00
2016-09-21 12:12:46 +00:00
# print fieldname, number, type, repeated, default
# print v.__dict__
# print v.CPPTYPE_STRING
# print v.LABEL_REPEATED
# print v.enum_type
2016-04-26 23:32:57 +00:00
# v.has_default_value, v.default_value
# v.label == 3 # repeated
2016-09-21 12:12:46 +00:00
# print v.number
2016-04-26 23:32:57 +00:00
out.append("%s = t" % t)
return imports + out
2016-04-27 20:44:37 +00:00
2016-09-21 12:12:46 +00:00
2016-04-26 23:32:57 +00:00
def process_enum(t, cls):
out = []
2016-04-27 20:44:37 +00:00
print(" * enum %s" % t)
2016-04-26 23:32:57 +00:00
for k, v in cls.items():
# Remove type name from the beginning of the constant
2016-04-27 20:44:37 +00:00
# For example "PinMatrixRequestType_Current" -> "Current"
2016-04-26 23:32:57 +00:00
if k.startswith("%s_" % t):
k = k.replace("%s_" % t, '')
2016-04-27 20:44:37 +00:00
2016-04-26 23:32:57 +00:00
# If type ends with *Type, but constant use type name without *Type, remove it too :)
# For example "ButtonRequestType & ButtonRequest_Other" => "Other"
if t.endswith("Type") and k.startswith("%s_" % t.replace("Type", '')):
k = k.replace("%s_" % t.replace("Type", ''), '')
2016-04-27 20:44:37 +00:00
out.append("%s = const(%s)" % (k, v))
2016-04-26 23:32:57 +00:00
return out
2016-09-21 12:12:46 +00:00
def find_msg_type(msg_types, t):
for k, v in msg_types:
msg_name = k.replace('MessageType_', '')
if msg_name == t:
return v
2016-09-21 12:12:46 +00:00
def process_module(mod, genpath, indexfile):
2016-04-27 20:44:37 +00:00
print("Processing module %s" % mod.__name__)
2016-09-21 12:12:46 +00:00
types = dict([(name, cls)
for name, cls in mod.__dict__.items() if isinstance(cls, type)])
2016-04-27 20:44:37 +00:00
2016-09-21 12:12:46 +00:00
msg_types = __import__('pb2', globals(), locals(), [
'messages_pb2', ]).messages_pb2.MessageType.items()
2016-09-21 12:12:46 +00:00
for t, cls in types.items():
# Find message type for given class
msg_id = find_msg_type(msg_types, t)
2016-05-12 14:05:33 +00:00
2016-09-21 12:12:46 +00:00
out = process_type(t, cls, msg_id, indexfile)
2016-04-26 23:32:57 +00:00
write_to_file(genpath, t, out)
2016-09-21 12:12:46 +00:00
enums = dict([(name, cls) for name, cls in mod.__dict__.items()
if isinstance(cls, EnumTypeWrapper)])
2016-04-27 20:44:37 +00:00
2016-09-21 12:12:46 +00:00
for t, cls in enums.items():
2016-04-26 23:32:57 +00:00
out = process_enum(t, cls)
write_to_file(genpath, t, out)
2016-09-21 12:12:46 +00:00
2016-04-26 23:32:57 +00:00
def write_to_file(genpath, t, out):
# Write generated sourcecode to given file
f = open(os.path.join(genpath, "%s.py" % t), 'w')
2016-04-27 20:44:37 +00:00
out = ["# Automatically generated by pb2py"] + out
2016-04-26 23:32:57 +00:00
data = "\n".join(out)
2016-04-27 20:44:37 +00:00
2016-04-26 23:32:57 +00:00
f.write(data)
f.close()
2016-04-27 20:44:37 +00:00
2016-04-26 23:32:57 +00:00
if __name__ == '__main__':
if len(sys.argv) < 2:
2016-09-21 12:12:46 +00:00
print("Usage: ./pb2py modulename genpath indexfile")
2016-04-26 23:32:57 +00:00
sys.exit()
modulename = sys.argv[1]
genpath = sys.argv[2]
2016-09-21 12:12:46 +00:00
if len(sys.argv) > 2:
indexfile = open(sys.argv[3], 'a')
else:
indexfile = None
2016-04-26 23:32:57 +00:00
# Dynamically load module from argv[1]
tmp = __import__('pb2', globals(), locals(), ['%s_pb2' % modulename])
mod = getattr(tmp, "%s_pb2" % modulename)
2016-09-21 12:12:46 +00:00
process_module(mod, genpath, indexfile)