From 61f802371239274a938fb58f3cb0fc966cec8fb4 Mon Sep 17 00:00:00 2001 From: jaseg Date: Mon, 8 Oct 2012 02:10:49 +0200 Subject: [PATCH] Un-overengineered a bit. Made the descriptor smaller. --- avr/generate.py | 49 +++++++++++++++----------- builds/sample_buildconfig.json | 16 +++------ configs/arduino-test.json | 28 +++++---------- configs/helights.json | 39 ++++++--------------- generatefw.py | 79 +++++++++++++++++++++++------------------- msp/generate.py | 49 +++++++++++++++----------- pylibcerebrum/pylibcerebrum.py | 72 ++++++-------------------------------- 7 files changed, 132 insertions(+), 200 deletions(-) rewrite configs/helights.json (97%) rewrite generatefw.py (70%) diff --git a/avr/generate.py b/avr/generate.py index 9d4c707..7a8a2d7 100644 --- a/avr/generate.py +++ b/avr/generate.py @@ -20,7 +20,10 @@ autocode_stub = """\ * in this very folder. Please refrain from modifying it, modify the templates * and generation logic instead. * - * Device name: ${devname}, build version: ${version}, build date: ${builddate} +%if devname: + * Device name: ${devname}, +%endif + * Build version: ${version}, build date: ${builddate} */ #include @@ -43,13 +46,13 @@ const uint16_t num_callbacks = ${len(callbacks)}; void init_auto(){ % for initfunc in init_functions: ${initfunc}(); - %endfor + % endfor } void loop_auto(){ % for loopfunc in loop_functions: ${loopfunc}(); - %endfor + % endfor } void callback_get_descriptor_auto(uint16_t alen, uint8_t* argbuf){ @@ -128,9 +131,6 @@ def generate(dev, devicename, builddate): mfile = member["type"] mtype = mfile.replace('-', '_') typepath = os.path.join(os.path.dirname(__file__), mfile + ".c.tp") -# if not os.path.exists(typepath): -# print("Cannot find a handler for member type " + dev["type"]) -# exit(1) def init_function(): fun = "init_{}_{}".format(mtype, seqnum) @@ -141,8 +141,8 @@ def generate(dev, devicename, builddate): loop_functions.append(fun) return fun - member["properties"] = {} - member["functions"] = {} + properties = {} + functions = {} accessors = "" def modulevar(name, ctype=None, fmt=None, array=False): @@ -156,7 +156,7 @@ def generate(dev, devicename, builddate): accid = register_callback("callback_get_" + varname) register_callback("callback_set_" + varname) - member["properties"][name] = { + properties[name] = { "size": struct.calcsize(fmt), "id": accid, "format": fmt} @@ -170,12 +170,14 @@ def generate(dev, devicename, builddate): return varname def module_callback(name, argformat="", retformat=""): - cbname = "callback_{}_{}_{}".format(mtype, seqnum, name) + cbname = 'callback_{}_{}_{}'.format(mtype, seqnum, name) cbid = register_callback(cbname) - member["functions"][name] = { - "id": cbid, - "args": argformat, - "returns": retformat} + func = { 'id': cbid } + if argformat is not '': + func['args'] = argformat + if retformat is not '': + func['returns'] = retformat + functions[name] = func return cbname seqnum += 1 @@ -188,17 +190,22 @@ def generate(dev, devicename, builddate): member=member) autocode += accessors + if functions: + member['functions'] = functions + if properties: + member['properties'] = properties + autocode += Template(autoglue).render_unicode(init_functions=init_functions, loop_functions=loop_functions, callbacks=callbacks) - with open(os.path.join(os.path.dirname(__file__), "autocode.c"), "w") as f: + with open(os.path.join(os.path.dirname(__file__), 'autocode.c'), 'w') as f: f.write(autocode) - subprocess.call(["/usr/bin/env", "make", "-C", os.path.dirname(__file__), "clean", "all"]) config = pylzma.compress(json.JSONEncoder(separators=(',',':')).encode(dev)) - with open(os.path.join(os.path.dirname(__file__), "config.c"), "w") as f: - f.write(Template(config_c_template).render_unicode(desc_len=len(config), desc=",".join(map(str, config)))) - return dev + with open(os.path.join(os.path.dirname(__file__), 'config.c'), 'w') as f: + f.write(Template(config_c_template).render_unicode(desc_len=len(config), desc=','.join(map(str, config)))) + subprocess.call(['/usr/bin/env', 'make', '-C', os.path.dirname(__file__), 'clean', 'all']) + return dev, os.path.join(os.path.dirname(__file__), 'main.hex') -def commit(dev): +def commit(args): make_env = os.environ.copy() - make_env["PORT"] = dev["serial"] # "location" contains the launchpad's USB serial number + make_env["PORT"] = args.port subprocess.call(["/usr/bin/env", "make", "-C", os.path.dirname(__file__), "program"], env=make_env) diff --git a/builds/sample_buildconfig.json b/builds/sample_buildconfig.json index 6f795b8..353ae9d 100644 --- a/builds/sample_buildconfig.json +++ b/builds/sample_buildconfig.json @@ -1,39 +1,31 @@ { - "baudrate": 57600, - "protocol": "usbserial", - "builddate": "2012-10-08 00:07:50.314648", "url": "http://jaseg.github.com/cerebrum", "version": 23, + "type": "avr", + "builddate": "2012-10-07 23:38:03", "members": { "led": { "functions": { "getState": { "returns": "B", - "args": "", "id": 2 }, "getDirection": { "returns": "B", - "args": "", "id": 4 }, "setDirection": { - "returns": "", "args": "B", "id": 3 }, "setState": { - "returns": "", "args": "B", "id": 1 } }, "type": "simple-io", "port": "B", - "pin": 5, - "properties": {} + "pin": 5 } - }, - "serial": "/dev/ttyACM0", - "type": "avr" + } } \ No newline at end of file diff --git a/configs/arduino-test.json b/configs/arduino-test.json index 53b93a1..9f04fe5 100644 --- a/configs/arduino-test.json +++ b/configs/arduino-test.json @@ -1,24 +1,12 @@ { - "dev":{ - "ar0": { - "protocol": "usbserial", - "type": "avr", - "serial": "/dev/ttyACM0", - "baudrate": 57600, - "version": 23, - "url": "http://jaseg.github.com/cerebrum", - "members": { - "led": { - "type": "simple-io", - "port": "B", - "pin": 5 - } - } - } - }, - "log":{ - "test": { - "led": "ar0.led" + "type": "avr", + "version": 23, + "url": "http://jaseg.github.com/cerebrum", + "members": { + "led": { + "type": "simple-io", + "port": "B", + "pin": 5 } } } diff --git a/configs/helights.json b/configs/helights.json dissimilarity index 97% index 6f1abd4..c1b7fa5 100644 --- a/configs/helights.json +++ b/configs/helights.json @@ -1,28 +1,11 @@ -{ - "dev":{ - "msp0": { - "protocol": "usbserial", - "type": "msp", - "location": "13982397", - "serial": "/dev/msp0", - "baudrate": 115200, - "version": 23, - "url": "http://jaseg.github.com/helights", - "members": { - "rgb": { - "type": "timer-pwm-rgb", - "ios": ["1.6", "2.1", "2.4"] - } - } - } - }, - "log":{ - "he1": { - "lighting": { - "table": { - "rgb": "msp0.rgb" - } - } - } - } -} +{ + "type": "msp", + "version": 23, + "url": "http://jaseg.github.com/cerebrum", + "members": { + "rgb": { + "type": "timer-pwm-rgb", + "ios": ["1.6", "2.1", "2.4"] + } + } +} diff --git a/generatefw.py b/generatefw.py dissimilarity index 70% index 17674d2..f749630 100755 --- a/generatefw.py +++ b/generatefw.py @@ -1,36 +1,43 @@ -#!/usr/bin/env python3 -# -#Copyright (C) 2012 jaseg -# -#This program is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public License -#version 3 as published by the Free Software Foundation. - - -import sys -import os -import json -import imp -import datetime - -desc = json.JSONDecoder().decode('\n'.join(sys.stdin.readlines())) -builddate = str(datetime.datetime.now()) - -# I think it is better to just let it throw an error -#if "dev" not in desc or "log" not in desc: -# exit(1) - -for devicename, dev in desc["dev"].items(): - dev = desc["dev"][devicename] - typepath = os.path.join(os.path.dirname(__file__), dev["type"], "generate.py") -# if not os.path.exists(typepath): -# print("Cannot find a handler for endpoint type " + dev["type"]) -# exit(1) - #known type - print(typepath) - ctx = imp.load_source("generate", typepath) - deviceconfig = ctx.generate(dev, devicename, builddate) - with open(os.path.join(os.path.dirname(__file__), "builds", builddate + "-" + devicename + ".config.json"), "w") as f: - f.write(json.JSONEncoder(indent=4).encode(deviceconfig)) - ctx.commit(dev) - +#!/usr/bin/env python3 +# +#Copyright (C) 2012 jaseg +# +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#version 3 as published by the Free Software Foundation. + + +import sys +import os +import json +import imp +import datetime +import argparse + +parser = argparse.ArgumentParser(description='Cerebrum firmware generator', epilog='To program the device upon creating the firmware image, supply either -p or -s.') +parser.add_argument('template', type=argparse.FileType('r'), default='-', help='The build template .json file') +parser.add_argument('-p', '--port', type=str, help='The tty where the device may be found to be programmed') +parser.add_argument('-b', '--baudrate', type=int, help='The baud rate of the device') +parser.add_argument('-s', '--usbserial', type=str, help='The USB serial number by which the device can be identified in order to be programmed') +parser.add_argument('-n', '--buildname', type=str, help='An optional name for the build. This is used to name the build config files.') +args = parser.parse_args() + +desc = json.JSONDecoder().decode('\n'.join(args.template.readlines())) +st = datetime.datetime.utcnow().timetuple() +builddate = str(datetime.datetime(st[0], st[1], st[2], st[3], st[4], st[5])) + +typepath = os.path.join(os.path.dirname(__file__), desc["type"], "generate.py") +print(builddate) +buildsource = 'stdin' if args.template.name is '-' else args.template.name +print('Generating firmware from ', buildsource) +print('Using generator ', typepath) +ctx = imp.load_source("generate", typepath) +(deviceconfig, output) = ctx.generate(desc, args.buildname, builddate) +with open(os.path.join(os.path.dirname(__file__), "builds", builddate + "-" + args.buildname if args.buildname else os.path.splitext(os.path.basename(buildsource))[0] + ".config.json"), "w") as f: + f.write(json.JSONEncoder(indent=4).encode(deviceconfig)) + print('Wrote build config to ', f.name) + +if args.port or args.usbserial: + print('Programming device') + ctx.commit(args) + diff --git a/msp/generate.py b/msp/generate.py index 91f993b..455dd40 100644 --- a/msp/generate.py +++ b/msp/generate.py @@ -20,7 +20,10 @@ autocode_stub = """\ * in this very folder. Please refrain from modifying it, modify the templates * and generation logic instead. * - * Device name: ${devname}, build version: ${version}, build date: ${builddate} +%if devname: + * Device name: ${devname}, +%endif + * Build version: ${version}, build date: ${builddate} */ #include @@ -43,13 +46,13 @@ const uint16_t num_callbacks = ${len(callbacks)}; void init_auto(){ % for initfunc in init_functions: ${initfunc}(); - %endfor + % endfor } void loop_auto(){ % for loopfunc in loop_functions: ${loopfunc}(); - %endfor + % endfor } void callback_get_descriptor_auto(uint16_t alen, uint8_t* argbuf){ @@ -128,9 +131,6 @@ def generate(dev, devicename, builddate): mfile = member["type"] mtype = mfile.replace('-', '_') typepath = os.path.join(os.path.dirname(__file__), mfile + ".c.tp") -# if not os.path.exists(typepath): -# print("Cannot find a handler for member type " + dev["type"]) -# exit(1) def init_function(): fun = "init_{}_{}".format(mtype, seqnum) @@ -141,8 +141,8 @@ def generate(dev, devicename, builddate): loop_functions.append(fun) return fun - member["properties"] = {} - member["functions"] = {} + properties = {} + functions = {} accessors = "" def modulevar(name, ctype=None, fmt=None, array=False): @@ -156,7 +156,7 @@ def generate(dev, devicename, builddate): accid = register_callback("callback_get_" + varname) register_callback("callback_set_" + varname) - member["properties"][name] = { + properties[name] = { "size": struct.calcsize(fmt), "id": accid, "format": fmt} @@ -170,12 +170,14 @@ def generate(dev, devicename, builddate): return varname def module_callback(name, argformat="", retformat=""): - cbname = "callback_{}_{}_{}".format(mtype, seqnum, name) + cbname = 'callback_{}_{}_{}'.format(mtype, seqnum, name) cbid = register_callback(cbname) - member["functions"][name] = { - "id": cbid, - "args": argformat, - "returns": retformat} + func = { 'id': cbid } + if argformat is not '': + func['args'] = argformat + if retformat is not '': + func['returns'] = retformat + functions[name] = func return cbname seqnum += 1 @@ -188,17 +190,22 @@ def generate(dev, devicename, builddate): member=member) autocode += accessors + if functions: + member['functions'] = functions + if properties: + member['properties'] = properties + autocode += Template(autoglue).render_unicode(init_functions=init_functions, loop_functions=loop_functions, callbacks=callbacks) - with open(os.path.join(os.path.dirname(__file__), "autocode.c"), "w") as f: + with open(os.path.join(os.path.dirname(__file__), 'autocode.c'), 'w') as f: f.write(autocode) - subprocess.call(["/usr/bin/env", "make", "-C", os.path.dirname(__file__), "clean", "all"]) config = pylzma.compress(json.JSONEncoder(separators=(',',':')).encode(dev)) - with open(os.path.join(os.path.dirname(__file__), "config.c"), "w") as f: - f.write(Template(config_c_template).render_unicode(desc_len=len(config), desc=",".join(map(str, config)))) - return dev + with open(os.path.join(os.path.dirname(__file__), 'config.c'), 'w') as f: + f.write(Template(config_c_template).render_unicode(desc_len=len(config), desc=','.join(map(str, config)))) + subprocess.call(['/usr/bin/env', 'make', '-C', os.path.dirname(__file__), 'clean', 'all']) + return dev, os.path.join(os.path.dirname(__file__), 'main') -def commit(dev): +def commit(args): make_env = os.environ.copy() - make_env["SERIAL"] = dev["location"] # "location" contains the launchpad's USB serial number + make_env["SERIAL"] = args.usbserial subprocess.call(["/usr/bin/env", "make", "-C", os.path.dirname(__file__), "program"], env=make_env) diff --git a/pylibcerebrum/pylibcerebrum.py b/pylibcerebrum/pylibcerebrum.py index 66206f6..113ca43 100644 --- a/pylibcerebrum/pylibcerebrum.py +++ b/pylibcerebrum/pylibcerebrum.py @@ -5,70 +5,15 @@ import struct import pylzma class Ganglion: - def __init__(self, config=None, configfile=None, proxies=None): - if proxies is not None: - self._config = config - self._proxies = proxies - return - if configfile is not None: - cf = open(configfile, 'r') - config = cf.readlines() - cf.close() - parsed_config = config - if not isinstance(config, dict): - parsed_config = json.JSONDecoder().decode('\n'.join(config)) - #FIXME add sanity check(s) here or just let it fail? - self._config = parsed_config["log"] - self._proxies = {} - for dname, dconf in parsed_config["dev"].items(): - self._proxies[dname] = SerialProxy(dconf) - - def __del__(self): - self.close() - - def close(self): - for name, proxy in self._proxies.items(): - proxy.close() - - @property - def _log(self): - return list(self._config.keys()) - - @property - def _dev(self): - return list(self._proxies.keys()) - - def __dir__(self): - return self._log + self._dev + list(self.__dict__.keys()) - - def __getattr__(self, name): - if name is "config": - raise AttributeError(name) - if name in self._config: - node = self._config[name] - if isinstance(node, str): - [dname, endpoint] = node.split('.') - return self._proxies[dname].__getattr__(endpoint) - else: - return Ganglion(config=node, proxies=self._proxies) - raise AttributeError(name) - - def __setattr__(self, name, value): - if not name is "_config" and name in self._config: - [dname, endpoint] = self._config[name].split('.') - self._proxies[dname].set_value(endpoint, value) - else: - self.__dict__[name] = value - -class SerialProxy: # NOTE: the device config is *not* the stuff from the config "dev" section but #read from the device. It can also be found in that [devicename].config.json #file created by the code generator - def __init__(self, config, ser=None): + def __init__(self, device=None, baudrate=115200, config=None, ser=None): + #FIXME HACK to et the initialization go smooth despite the __*__ special functions and "config" not yet being set self._config = None if ser is None: - #FIXME HACK to et the initialization go smooth despite the __*__ special functions and "config" not yet being set - self._ser = serial.Serial(config["serial"], config["baudrate"]) + self._ser = serial.Serial(device, baudrate) + self._opened_ser = self._ser self._config = self.read_config() else: self._config = config @@ -78,7 +23,10 @@ class SerialProxy: self.close() def close(self): - self._ser.close() + try: + self._opened_ser.close() + except AttributeError: + pass def read_config(self): self._ser.write(b'\\#\x00\x00\x00\x00') @@ -132,7 +80,7 @@ class SerialProxy: raise AttributeError(name) if "members" in self._config and name in self._config["members"]: - return SerialProxy(self._config["members"][name], self._ser) + return Ganglion(config=self._config["members"][name], ser=self._ser) if "properties" in self._config and name in self._config["properties"]: var = self._config["properties"][name] @@ -141,6 +89,6 @@ class SerialProxy: if "functions" in self._config and name in self._config["functions"]: fun = self._config["functions"][name] def proxy_method(*args): - return self.callfunc(fun["id"], fun["args"], args, fun["returns"]) + return self.callfunc(fun["id"], fun.get("args", ""), args, fun.get("returns", "")) return proxy_method -- 2.11.4.GIT