1034
|
1 import tempfile, subprocess, logging, os
|
|
2 log = logging.getLogger('arduino_code')
|
|
3
|
|
4 def writeMakefile(dev, tag, allLibs):
|
|
5 return '''
|
|
6 BOARD_TAG = %(tag)s
|
|
7 USER_LIB_PATH := %(libs)s
|
|
8 ARDUINO_LIBS = %(arduinoLibs)s
|
|
9 MONITOR_PORT = %(dev)s
|
|
10
|
|
11 include /usr/share/arduino/Arduino.mk
|
|
12 ''' % {
|
|
13 'dev': dev,
|
|
14 'tag': tag,
|
|
15 'libs': os.path.abspath('arduino-libraries'),
|
|
16 'arduinoLibs': ' '.join(allLibs),
|
|
17 }
|
|
18
|
|
19 def writeCode(baudrate, devs, devCommandNum):
|
|
20 generated = {
|
|
21 'baudrate': baudrate,
|
|
22 'includes': '',
|
|
23 'global': '',
|
|
24 'setups': '',
|
|
25 'polls': '',
|
|
26 'idles': '',
|
|
27 'actions': '',
|
|
28 }
|
|
29 for attr in ['includes', 'global', 'setups', 'polls', 'idles',
|
|
30 'actions']:
|
|
31 for dev in devs:
|
|
32 if attr == 'includes':
|
|
33 gen = '\n'.join('#include "%s"\n' % inc
|
|
34 for inc in dev.generateIncludes())
|
|
35 elif attr == 'global': gen = dev.generateGlobalCode()
|
|
36 elif attr == 'setups': gen = dev.generateSetupCode()
|
|
37 elif attr == 'polls': gen = dev.generatePollCode()
|
|
38 elif attr == 'idles': gen = dev.generateIdleCode()
|
|
39 elif attr == 'actions':
|
|
40 code = dev.generateActionCode()
|
|
41 if code:
|
|
42 gen = '''else if (cmd == %(cmdNum)s) {
|
|
43 %(code)s
|
|
44 Serial.write('k');
|
|
45 }
|
|
46 ''' % dict(cmdNum=devCommandNum[dev.uri],
|
|
47 code=code)
|
|
48 else:
|
|
49 gen = ''
|
|
50 else:
|
|
51 raise NotImplementedError
|
|
52
|
|
53 if gen:
|
|
54 generated[attr] += '// for %s\n%s\n' % (dev.uri, gen.strip())
|
|
55
|
|
56 code = '''
|
|
57 %(includes)s
|
|
58
|
|
59 %(global)s
|
|
60 byte frame=1;
|
|
61 unsigned long lastFrame=0;
|
|
62
|
|
63 void setup() {
|
|
64 Serial.begin(%(baudrate)d);
|
|
65 Serial.flush();
|
|
66 %(setups)s
|
|
67 }
|
|
68
|
|
69 void idle() {
|
|
70 // this slowdown is to spend somewhat less time PWMing, to reduce
|
|
71 // leaking from on channels to off ones (my shift register has no
|
|
72 // latching)
|
|
73 if (micros() < lastFrame + 80) {
|
|
74 return;
|
|
75 }
|
|
76 lastFrame = micros();
|
|
77 frame++;
|
|
78 %(idles)s
|
|
79 }
|
|
80
|
|
81 void loop() {
|
|
82 byte head, cmd;
|
|
83 idle();
|
|
84 if (Serial.available() >= 2) {
|
|
85 head = Serial.read();
|
|
86 if (head != 0x60) {
|
|
87 Serial.flush();
|
|
88 return;
|
|
89 }
|
|
90 cmd = Serial.read();
|
|
91 if (cmd == 0x00) { // poll
|
|
92 %(polls)s
|
|
93 Serial.write('x');
|
|
94 } else if (cmd == 0x01) { // get code checksum
|
|
95 Serial.write("CODE_CHECKSUM");
|
|
96 }
|
|
97 %(actions)s
|
|
98 }
|
|
99 }
|
|
100 ''' % generated
|
|
101 return code
|
|
102
|
|
103 def indent(code):
|
|
104 try:
|
|
105 with tempfile.SpooledTemporaryFile() as codeFile:
|
|
106 codeFile.write(code)
|
|
107 codeFile.seek(0)
|
|
108 code = subprocess.check_output([
|
|
109 'indent',
|
|
110 '-linux',
|
|
111 '-fc1', # ok to indent comments
|
|
112 '-i4', # 4-space indent
|
|
113 '-sob' # swallow blanks (not working)
|
|
114 ], stdin=codeFile)
|
|
115 except OSError as e:
|
|
116 log.warn("indent failed (%r)", e)
|
|
117 return code
|
|
118
|