MSP device support complete. NOT TESTED YET! Preliminary python host lib
[cerebrum.git] / msp / generate.py
blob66373f4532103d1c7e80642b3097c30bc14b07e3
2 import subprocess
3 import os.path
4 import struct
5 from mako.template import Template
6 from datetime import datetime
7 import binascii
8 import json
9 import pylzma
10 import codecs
12 autocode_stub = """\
13 /* AUTOGENERATED CODE FOLLOWS!
14 * This file contains the code generated from the module templates as well as
15 * some glue logic. It is generated following the device config by "generate.py"
16 * in this very folder. Please refrain from modifying it, modify the templates
17 * and generation logic instead.
19 * Device name: ${devname}, build version: ${version}, build date: ${builddate}
22 #include <string.h>
23 #include "autocode.h"
24 #include "comm.h"
25 """
27 autoglue = """
28 #include "config.h"
30 comm_callback comm_callbacks[] = {
31 % for (callback, id) in callbacks:
32 &${callback}, //${id}
33 % endfor
36 void init_auto(){
37 % for initfunc in init_functions:
38 ${initfunc}();
39 %endfor
42 void loop_auto(){
43 % for loopfunc in loop_functions:
44 ${loopfunc}();
45 %endfor
48 void callback_get_descriptor_auto(uint16_t alen, uint8_t* argbuf){
49 //FIXME
50 putc_escaped(auto_config_descriptor_length >> 8);
51 putc_escaped(auto_config_descriptor_length & 0xFF);
52 for(char* i=auto_config_descriptor; i < auto_config_descriptor+auto_config_descriptor_length; i++){
53 putc_escaped(*i);
55 //FIXME add crc generation
56 putc_escaped(0x00);
57 putc_escaped(0x00);
60 """
62 accessor_callbacks = """
63 void callback_set_${name}(uint16_t alen, uint8_t* argbuf){
64 if(! sizeof(${ctype}) == alen){
65 //FIXME error handling
66 return;
68 memcpy(&${name}, argbuf, sizeof(${ctype}));
71 void callback_get_${name}(uint16_t alen, uint8_t* argbuf){
72 if(! alen == 0){
73 //FIXME error handling
74 return;
76 putc_escaped(sizeof(${ctype})>>8);
77 putc_escaped(sizeof(${ctype})&0xFF);
78 for(char* i=((char*)&${name}); i<((char*)&${name})+sizeof(${ctype}); i++){
79 putc_escaped(*i);
81 //FIXME add crc generation
82 putc_escaped(0x00);
83 putc_escaped(0x00);
86 """
88 config_c_template = """\
89 /* AUTOGENERATED CODE AHEAD!
90 * This file contains the device configuration in lzma-ed json-format. It is
91 * autogenerated by "generate.py" (which should be found in this folder).
93 #include "config.h"
94 unsigned int auto_config_descriptor_length = ${desc_len};
95 char auto_config_descriptor[] = {${desc}};
96 """
98 def generate(dev, devicename):
99 members = dev["members"]
100 seqnum = 23
101 current_id = 0
102 builddate = datetime.now()
103 dev["builddate"] = str(builddate)
104 autocode = Template(autocode_stub).render_unicode(devname=devicename, version=dev["version"], builddate=builddate)
105 init_functions = []
106 loop_functions = []
108 callbacks = []
109 def register_callback(name):
110 nonlocal current_id
111 callbacks.append((name, current_id))
112 current_id += 1
114 register_callback("callback_get_descriptor_auto")
116 def generate_accessors(name, ctype):
117 return Template(accessor_callbacks).render_unicode(name=name, ctype=ctype);
119 for mname, member in members.items():
120 mfile = member["type"]
121 mtype = mfile.replace('-', '_')
122 typepath = os.path.join(os.path.dirname(__file__), mfile + ".c.tp")
123 # if not os.path.exists(typepath):
124 # print("Cannot find a handler for member type " + dev["type"])
125 # exit(1)
127 init_function = "init_{}_{}".format(mtype, seqnum)
128 init_functions.append(init_function)
129 loop_function = "loop_{}_{}".format(mtype, seqnum)
130 loop_functions.append(loop_function)
132 member["properties"] = {}
133 member["functions"] = {}
134 accessors = ""
136 def modulevar(name, ctype=None, fmt=None):
137 varname = "modvar_{}_{}_{}".format(mtype, seqnum, name)
138 if fmt is not None and ctype is not None:
139 nonlocal accessors
140 accessors += generate_accessors(varname, ctype)
142 register_callback("callback_get_" + varname)
143 member["properties"][name] = {
144 "size": struct.calcsize(fmt),
145 "id": current_id,
146 "format": fmt}
147 register_callback("callback_set_" + varname)
148 return "{} {}".format(ctype, varname)
150 return varname
152 def module_callback(name, argformat="", retformat=""):
153 cbname = "callback_{}_{}_{}".format(mtype, seqnum, name)
154 register_callback(cbname)
155 member["functions"][name] = {
156 "id": current_id,
157 "args": argformat,
158 "returns": retformat}
159 return cbname
161 seqnum += 1
162 tp = Template(filename=typepath)
163 autocode += tp.render_unicode(
164 init_function=init_function,
165 loop_function=loop_function,
166 modulevar=modulevar,
167 module_callback=module_callback,
168 dev=dev)
169 autocode += accessors
171 autocode += Template(autoglue).render_unicode(init_functions=init_functions, loop_functions=loop_functions, callbacks=callbacks)
172 with open(os.path.join(os.path.dirname(__file__), "autocode.c"), "w") as f:
173 f.write(autocode)
174 subprocess.call(["/usr/bin/env", "make", "-C", os.path.dirname(__file__), "clean", "all"])
175 config = pylzma.compress(json.JSONEncoder(separators=(',',':')).encode(dev))
176 with open(os.path.join(os.path.dirname(__file__), "config.c"), "w") as f:
177 f.write(Template(config_c_template).render_unicode(desc_len=len(config), desc=",".join(map(str, config))))
178 return dev
180 def commit(dev):
181 make_env = os.environ.copy()
182 make_env["SERIAL"] = dev["location"] # "location" contains the launchpad's USB serial number
183 subprocess.call(["/usr/bin/env", "make", "-C", os.path.dirname(__file__), "program"], env=make_env)