Un-overengineered a bit. Made the descriptor smaller.
[cerebrum.git] / avr / generate.py
blob7a8a2d7dfcae201f0811a0300a0935e58cd24cb6
1 #Copyright (C) 2012 jaseg <s@jaseg.de>
3 #This program is free software; you can redistribute it and/or
4 #modify it under the terms of the GNU General Public License
5 #version 3 as published by the Free Software Foundation.
7 import subprocess
8 import os.path
9 import struct
10 from mako.template import Template
11 import binascii
12 import json
13 import pylzma
14 import codecs
16 autocode_stub = """\
17 /* AUTOGENERATED CODE FOLLOWS!
18 * This file contains the code generated from the module templates as well as
19 * some glue logic. It is generated following the device config by "generate.py"
20 * in this very folder. Please refrain from modifying it, modify the templates
21 * and generation logic instead.
23 %if devname:
24 * Device name: ${devname},
25 %endif
26 * Build version: ${version}, build date: ${builddate}
29 #include <string.h>
30 #include "autocode.h"
31 #include "comm.h"
32 """
34 autoglue = """
35 #include "config.h"
36 #include <avr/pgmspace.h>
38 comm_callback comm_callbacks[] = {
39 % for (callback, id) in callbacks:
40 &${callback}, //${id}
41 % endfor
44 const uint16_t num_callbacks = ${len(callbacks)};
46 void init_auto(){
47 % for initfunc in init_functions:
48 ${initfunc}();
49 % endfor
52 void loop_auto(){
53 % for loopfunc in loop_functions:
54 ${loopfunc}();
55 % endfor
58 void callback_get_descriptor_auto(uint16_t alen, uint8_t* argbuf){
59 //FIXME
60 uart_putc(auto_config_descriptor_length >> 8);
61 uart_putc(auto_config_descriptor_length & 0xFF);
62 for(const char* i=auto_config_descriptor; i < auto_config_descriptor+auto_config_descriptor_length; i++){
63 uart_putc(pgm_read_byte(i));
65 //FIXME add crc generation
66 uart_putc(0x00);
67 uart_putc(0x00);
70 """
72 accessor_callbacks = """
73 void callback_set_${name}(uint16_t alen, uint8_t* argbuf){
74 if(! ${bsize} == alen){
75 //FIXME error handling
76 return;
78 memcpy(&${name}, argbuf, ${bsize});
81 void callback_get_${name}(uint16_t alen, uint8_t* argbuf){
82 if(! alen == 0){
83 //FIXME error handling
84 return;
86 uart_putc(${bsize}>>8);
87 uart_putc(${bsize}&0xFF);
88 for(char* i=((char*)&${name}); i<((char*)&${name})+${bsize}; i++){
89 uart_putc(*i);
91 //FIXME add crc generation
92 uart_putc(0x00);
93 uart_putc(0x00);
96 """
98 config_c_template = """\
99 /* AUTOGENERATED CODE AHEAD!
100 * This file contains the device configuration in lzma-ed json-format. It is
101 * autogenerated by "generate.py" (which should be found in this folder).
103 #include "config.h"
104 unsigned int auto_config_descriptor_length = ${desc_len};
105 const char auto_config_descriptor[] PROGMEM = {${desc}};
108 def generate(dev, devicename, builddate):
109 members = dev["members"]
110 seqnum = 23
111 current_id = 0
112 dev["builddate"] = str(builddate)
113 autocode = Template(autocode_stub).render_unicode(devname=devicename, version=dev["version"], builddate=builddate)
114 init_functions = []
115 loop_functions = []
117 callbacks = []
118 def register_callback(name):
119 nonlocal current_id
120 callbacks.append((name, current_id))
121 old_id = current_id
122 current_id += 1
123 return old_id
125 register_callback("callback_get_descriptor_auto")
127 def generate_accessors(name, ctype, aval=1):
128 return Template(accessor_callbacks).render_unicode(name=name, bsize="({}*sizeof({}))".format(aval, ctype));
130 for mname, member in members.items():
131 mfile = member["type"]
132 mtype = mfile.replace('-', '_')
133 typepath = os.path.join(os.path.dirname(__file__), mfile + ".c.tp")
135 def init_function():
136 fun = "init_{}_{}".format(mtype, seqnum)
137 init_functions.append(fun)
138 return fun
139 def loop_function():
140 fun = "loop_{}_{}".format(mtype, seqnum)
141 loop_functions.append(fun)
142 return fun
144 properties = {}
145 functions = {}
146 accessors = ""
148 def modulevar(name, ctype=None, fmt=None, array=False):
149 varname = "modvar_{}_{}_{}".format(mtype, seqnum, name)
150 if fmt is not None and ctype is not None:
151 nonlocal accessors
152 aval = 1
153 if array != False:
154 aval = array
155 accessors += generate_accessors(varname, ctype, aval)
157 accid = register_callback("callback_get_" + varname)
158 register_callback("callback_set_" + varname)
159 properties[name] = {
160 "size": struct.calcsize(fmt),
161 "id": accid,
162 "format": fmt}
163 array_component = ""
164 if array == True:
165 array_component = "[]"
166 elif array:
167 array_component = "[{}]".format(array)
168 return "{} {}{}".format(ctype, varname, array_component)
170 return varname
172 def module_callback(name, argformat="", retformat=""):
173 cbname = 'callback_{}_{}_{}'.format(mtype, seqnum, name)
174 cbid = register_callback(cbname)
175 func = { 'id': cbid }
176 if argformat is not '':
177 func['args'] = argformat
178 if retformat is not '':
179 func['returns'] = retformat
180 functions[name] = func
181 return cbname
183 seqnum += 1
184 tp = Template(filename=typepath)
185 autocode += tp.render_unicode(
186 init_function=init_function,
187 loop_function=loop_function,
188 modulevar=modulevar,
189 module_callback=module_callback,
190 member=member)
191 autocode += accessors
193 if functions:
194 member['functions'] = functions
195 if properties:
196 member['properties'] = properties
198 autocode += Template(autoglue).render_unicode(init_functions=init_functions, loop_functions=loop_functions, callbacks=callbacks)
199 with open(os.path.join(os.path.dirname(__file__), 'autocode.c'), 'w') as f:
200 f.write(autocode)
201 config = pylzma.compress(json.JSONEncoder(separators=(',',':')).encode(dev))
202 with open(os.path.join(os.path.dirname(__file__), 'config.c'), 'w') as f:
203 f.write(Template(config_c_template).render_unicode(desc_len=len(config), desc=','.join(map(str, config))))
204 subprocess.call(['/usr/bin/env', 'make', '-C', os.path.dirname(__file__), 'clean', 'all'])
205 return dev, os.path.join(os.path.dirname(__file__), 'main.hex')
207 def commit(args):
208 make_env = os.environ.copy()
209 make_env["PORT"] = args.port
210 subprocess.call(["/usr/bin/env", "make", "-C", os.path.dirname(__file__), "program"], env=make_env)