32 void led_toggle () |
34 void led_toggle () |
33 { |
35 { |
34 xbi(&DEBUG_PORT, DEBUG_LED); |
36 xbi(&DEBUG_PORT, DEBUG_LED); |
35 } |
37 } |
36 |
38 |
37 // DMX |
39 // dmx |
38 #define DMX_DDR DDRB |
40 /* |
39 #define DMX_PORT PORTB |
41 * DMX state |
40 #define DMX_DATA 3 // SPI MOSI |
42 */ |
41 |
43 static struct dmx_state { |
42 // baud rate: 250k = 4µs / bit |
44 byte out[256]; |
43 #define DMX_BAUD (250 * 1000) |
45 byte count; |
44 #define DMX_US 4 |
46 } dmx; |
45 |
47 |
46 // CPU cycles / bit: 64 @ 16Mhz |
48 |
47 #define DMX_CYCLES (F_CPU / DMX_BAUD) |
49 enum state { |
48 |
50 START = '\n', |
49 void dmx_init () |
51 CMD = ';', |
50 { |
52 ARG = ',', |
51 // dmx data out: idle (high) |
53 ERROR = '!', |
52 sbi(&DMX_PORT, DMX_DATA); |
54 }; |
53 sbi(&DMX_DDR, DMX_DATA); |
55 |
54 } |
56 enum cmd { |
55 |
57 CMD_ |
56 static inline void dmx_high () |
58 }; |
57 { |
59 |
58 sbi(&DMX_PORT, DMX_DATA); |
60 #define CONSOLE_ARGS 8 |
59 } |
61 |
60 |
62 /* |
61 static inline void dmx_low () |
63 * Console input state. |
62 { |
64 */ |
63 cbi(&DMX_PORT, DMX_DATA); |
65 static struct console { |
64 } |
66 enum state state; |
65 |
67 |
66 #define dmx_pause(bits) _delay_us((DMX_US * bits)) |
68 enum cmd cmd; |
67 |
69 char argc; |
68 static void dmx_break () |
70 char argv[CONSOLE_ARGS]; |
69 { |
71 } console; |
70 // break |
72 |
71 dmx_low(); |
73 /* |
72 dmx_pause(22); |
74 * Process console command. |
73 |
75 */ |
74 // mark-after-break (MAB) |
76 int command () |
75 dmx_high(); |
77 { |
76 dmx_pause(2); |
78 switch (console.cmd) { |
77 } |
79 default: |
78 |
80 return '?'; |
79 #include "dmx_frame.c" |
81 } |
80 |
82 } |
81 static void dmx_packet (byte r, byte g, byte b) |
83 |
|
84 /* |
|
85 * Process console input. |
|
86 */ |
|
87 char input (char c) |
|
88 { |
|
89 // control |
|
90 if (c == '\r') { |
|
91 char ret = '?'; |
|
92 |
|
93 if (console.state == CMD) { |
|
94 console.argc = 0; |
|
95 } else if (console.state == ARG) { |
|
96 console.argc++; |
|
97 } else { |
|
98 console.state = START; |
|
99 return '\n'; |
|
100 } |
|
101 |
|
102 // command |
|
103 if ((ret = command(console.cmd))) { |
|
104 |
|
105 } else { |
|
106 ret = '\n'; |
|
107 } |
|
108 |
|
109 // return to START with response |
|
110 console.state = START; |
|
111 return ret; |
|
112 |
|
113 } else if (c == ' ' || c == '\t') { |
|
114 // argument |
|
115 if (console.state == CMD) { |
|
116 console.state = ARG; |
|
117 console.argc = 0; |
|
118 |
|
119 return c; |
|
120 |
|
121 } else if (console.state == ARG) { |
|
122 if (console.argc++ < CONSOLE_ARGS) { |
|
123 console.argv[console.argc] = 0; |
|
124 |
|
125 return c; |
|
126 } |
|
127 } |
|
128 |
|
129 // printable |
|
130 } else if (32 < c && c < 128) { |
|
131 // process input char |
|
132 if (console.state == START) { |
|
133 console.cmd = c; |
|
134 console.state = CMD; |
|
135 |
|
136 return c; |
|
137 |
|
138 } else if (console.state == ARG) { |
|
139 if (c >= '0' && c <= '9') { |
|
140 console.argv[console.argc] *= 10; |
|
141 console.argv[console.argc] += (c - '0'); |
|
142 |
|
143 return c; |
|
144 } |
|
145 } |
|
146 } else { |
|
147 // ignore |
|
148 return ' '; |
|
149 } |
|
150 |
|
151 // reject |
|
152 console.state = ERROR; |
|
153 return ERROR; |
|
154 } |
|
155 |
|
156 /* |
|
157 * Tick output state |
|
158 */ |
|
159 void update () |
82 { |
160 { |
83 dmx_break(); |
161 dmx_break(); |
84 dmx_frame(0); |
162 dmx_frame(0); |
85 |
163 |
86 dmx_frame(0); // control |
164 for (byte i = 0; i < dmx.count; i++) { |
87 dmx_frame(r); |
165 dmx_frame(dmx.out[i]); |
88 dmx_frame(g); |
166 } |
89 dmx_frame(b); |
|
90 dmx_frame(0); // madness |
|
91 } |
167 } |
92 |
168 |
93 void main () |
169 void main () |
94 { |
170 { |
95 led_init(); |
171 led_init(); |
96 dmx_init(); |
172 timer_init(); |
97 |
173 serial_init(); |
98 // dmx |
174 //dmx_init(); |
|
175 |
|
176 // mainloop |
|
177 char c = '>'; |
|
178 unsigned timeout = 8000; // 2Hz |
|
179 |
|
180 sei(); |
|
181 |
99 while (true) { |
182 while (true) { |
100 dmx_packet(0x00, 0x00, 0xff); |
183 // sleep |
101 dmx_pause(100); |
184 //led_on(); |
102 |
185 if (timer_sleep(timeout)) { |
|
186 c = '.'; |
|
187 |
|
188 } else if ((c = serial_read())) { |
|
189 // got serial data |
|
190 c = input(c); |
|
191 |
|
192 } else { |
|
193 // unknown interrupt |
|
194 c = '?'; |
|
195 } |
|
196 //led_off(); |
|
197 |
|
198 // respond |
|
199 serial_write(c); |
|
200 |
|
201 // output |
|
202 update(); |
|
203 |
103 led_toggle(); |
204 led_toggle(); |
104 } |
205 } |
105 } |
206 } |