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):
|
2016-10-26 15:32:08 +00:00
|
|
|
print(" * type %s" % t)
|
2016-04-27 20:44:37 +00:00
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
imports = ["import protobuf as p", "from micropython import const", ]
|
2016-04-26 23:32:57 +00:00
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
out = ["", "class %s(p.MessageType):" % t, ]
|
2016-05-12 14:05:33 +00:00
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
if cls.DESCRIPTOR.fields_by_name:
|
|
|
|
out.append(" FIELDS = {")
|
|
|
|
elif msg_id is None:
|
|
|
|
out.append(" pass")
|
2016-04-27 20:44:37 +00:00
|
|
|
|
|
|
|
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
|
2016-10-26 15:32:08 +00:00
|
|
|
type = 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:
|
2016-10-26 15:32:08 +00:00
|
|
|
raise Exception("Unknown field type %s for field %s" %
|
|
|
|
(v.type, fieldname))
|
2016-04-26 23:32:57 +00:00
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
if required:
|
|
|
|
comment = ' # required'
|
|
|
|
elif v.has_default_value:
|
|
|
|
comment = ' # default=%s' % repr(v.default_value)
|
2016-04-26 23:32:57 +00:00
|
|
|
else:
|
2016-10-26 15:32:08 +00:00
|
|
|
comment = ''
|
2016-04-26 23:32:57 +00:00
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
if repeated:
|
|
|
|
flags = 'p.FLAG_REPEATED'
|
2016-04-26 23:32:57 +00:00
|
|
|
else:
|
2016-10-26 15:32:08 +00:00
|
|
|
flags = '0'
|
2016-04-26 23:32:57 +00:00
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
out.append(" %d: ('%s', %s, %s),%s" %
|
|
|
|
(number, fieldname, type, flags, comment))
|
2016-04-27 20:44:37 +00:00
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
# print fieldname, number, type, repeated, comment
|
2016-09-21 12:12:46 +00:00
|
|
|
# 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
|
|
|
|
2016-10-26 15:32:08 +00:00
|
|
|
if cls.DESCRIPTOR.fields_by_name:
|
|
|
|
out.append(" }")
|
|
|
|
|
|
|
|
if msg_id is not None:
|
|
|
|
out.append(" MESSAGE_WIRE_TYPE = %d" % msg_id)
|
|
|
|
if indexfile is not None:
|
|
|
|
indexfile.write("%s = const(%d)\n" % (t, msg_id))
|
|
|
|
|
2016-04-26 23:32:57 +00:00
|
|
|
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
|
|
|
|
2016-05-05 19:30:24 +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-05-05 19:30:24 +00:00
|
|
|
|
2016-09-21 12:12:46 +00:00
|
|
|
for t, cls in types.items():
|
2016-05-05 19:30:24 +00:00
|
|
|
# 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-05-05 19:30:24 +00:00
|
|
|
|
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-10-24 13:42:59 +00:00
|
|
|
data = "\n".join(out) + "\n"
|
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)
|