quite a few files to ignore
[moodlight.git] / console.c
CommitLineData
2d3643ee 1/* $Id: console.c,v 1.1 2010/06/26 12:28:08 simimeie Exp $
2 * Functions for a serial console.
3 */
4
5#include <avr/io.h>
6#include <avr/interrupt.h>
7#include <avr/pgmspace.h>
8#include <avr/version.h>
9#include <util/delay.h>
10#include <stdio.h>
11#include "console.h"
12
13/* PD0 is RXD, PD1 is TXD, but we don't need to address them manually */
14
15/* Formula for calculating the value of UBRR from baudrate and cpufreq */
16#define UBRRCALC ((CPUFREQ / (16 * BAUDRATE)) - 1)
17
18#define INPUTBUFSIZE 30
19static uint8_t inputbuf[INPUTBUFSIZE];
20static uint8_t inputpos = 0;
21#define OUTPUTBUFSIZE 400
22static uint8_t outputbuf[OUTPUTBUFSIZE];
23static uint16_t outputhead = 0; /* WARNING cannot be modified atomically */
24static uint16_t outputtail = 0;
25static uint8_t opinprog = 0;
26static uint8_t escstatus = 0;
27static prog_uint8_t CRLF[] = "\r\n";
28static prog_uint8_t WELCOMEMSG[] = "\r\n"\
29 "\r\n ******************************************"\
30 "\r\n * universal mainboard v1 *"\
31 "\r\n * (C) Michael 'PoempelFox' Meier 05/2010 *"\
32 "\r\n ******************************************"\
33 "\r\n"\
34 "\r\nProcessor: atmega328"\
35 "\r\nAVR-libc: " __AVR_LIBC_VERSION_STRING__ " (" __AVR_LIBC_DATE_STRING__ ")"\
36 "\r\nSoftware Version 0.1, Compiled " __DATE__ " " __TIME__;
37static prog_uint8_t PROMPT[] = "\r\nroot@mbv1# ";
38
39/* Handler for TXC (TX Complete) IRQ */
40ISR(USART_TX_vect) {
41 if (outputhead == outputtail) { /* Nothing more to send! */
42 opinprog = 0;
43 } else {
44 UDR0 = outputbuf[outputhead];
45 outputhead++;
46 if (outputhead >= OUTPUTBUFSIZE) {
47 outputhead = 0;
48 }
49 }
50}
51
52#if defined __GNUC__
53/* Unfortunately, gcc is very very dumb, and despite -Os tries to inline this
54 * function even though it is called about a thousand times, when only
55 * NETCONSOLE is defined, costing us more than 2.5 KiloBytes of Flash.
56 * Way to go, gcc "optimization". Though NETCONSOLE does not exist
57 * in this copy of the console code, it certainly can't hurt. */
58static void appendchar(uint8_t what) __attribute__((noinline));
59#endif /* __GNUC__ */
60/* This can only be called safely with interrupts disabled - remember that! */
61static void appendchar(uint8_t what) {
62 uint16_t newpos;
63 newpos = (outputtail + 1);
64 if (newpos >= OUTPUTBUFSIZE) {
65 newpos = 0;
66 }
67 if (newpos != outputhead) {
68 outputbuf[outputtail] = what;
69 outputtail = newpos;
70 }
71 if (!opinprog) {
72 /* Send the byte */
73 UDR0 = what;
74 outputhead++;
75 if (outputhead >= OUTPUTBUFSIZE) {
76 outputhead = 0;
77 }
78 opinprog = 1;
79 }
80}
81
82void console_printchar_noirq(uint8_t what) {
83 appendchar(what);
84}
85
86/* This can only be called safely with interrupts disabled - remember that! */
87void console_printhex8_noirq(uint8_t what) {
88 uint8_t buf;
89 uint8_t i;
90 for (i=0; i<2; i++) {
91 buf = (uint8_t)(what & (uint8_t)0xF0) >> 4;
92 if (buf <= 9) {
93 buf += '0';
94 } else {
95 buf += 'A' - 10;
96 }
97 appendchar(buf);
98 what <<= 4;
99 }
100}
101
102/* This can only be called safely with interrupts disabled - remember that! */
103void console_printdec_noirq(uint8_t what) {
104 uint8_t buf;
105 buf = what / 100;
106 appendchar(buf + '0');
107 what %= 100;
108 buf = what / 10;
109 appendchar(buf + '0');
110 buf = what % 10;
111 appendchar(buf + '0');
112}
113
114/* This can only be called safely with interrupts disabled - remember that! */
115void console_printbin8_noirq(uint8_t what) {
116 uint8_t i;
117 for (i = 0; i < 8; i++) {
118 if (what & 0x80) {
119 appendchar('1');
120 } else {
121 appendchar('0');
122 }
123 what <<= 1;
124 }
125}
126
127/* This can only be called safely with interrupts disabled - remember that! */
128static void console_printtext_noirq(const uint8_t * what) {
129 while (*what) {
130 appendchar(*what);
131 what++;
132 }
133}
134
135/* This can only be called safely with interrupts disabled - remember that! */
136static void console_printpgm_noirq_P(PGM_P what) {
137 uint8_t t;
138 while ((t = pgm_read_byte(what++))) {
139 appendchar(t);
140 }
141}
142
143/* These are wrappers for our internal functions, disabling IRQs before
144 * calling them. */
145void console_printtext(const uint8_t * what) {
146 cli();
147 console_printtext_noirq(what);
148 sei();
149}
150
151void console_printpgm_P(PGM_P what) {
152 cli();
153 console_printpgm_noirq_P(what);
154 sei();
155}
156
157void console_printhex8(uint8_t what) {
158 cli();
159 console_printhex8_noirq(what);
160 sei();
161}
162
163void console_printdec(uint8_t what) {
164 cli();
165 console_printdec_noirq(what);
166 sei();
167}
168
169void console_init(void) {
170 /* Set Baud Rate */
171 UBRR0H = (uint8_t)(UBRRCALC >> 8);
172 UBRR0L = (uint8_t)(UBRRCALC);
173 /* Set 8 Bit mode - how braindead is it to default to 5 bit?! */
174 UCSR0C = /* _BV(URSEL) | */ _BV(UCSZ00) | _BV(UCSZ01);
175 /* Enable Send and Receive and IRQs */
176 UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(TXCIE0) | _BV(RXCIE0);
177 console_printpgm_noirq_P(WELCOMEMSG);
178 console_printpgm_noirq_P(PROMPT);
179 return;
180}
181
182/* Handler for RXC (RX Complete) IRQ. */
183/* We do all query processing here. */
184ISR(USART_RX_vect) {
185 uint8_t inpb;
186
187 inpb = UDR0;
188 if (escstatus == 1) {
189 if (inpb == '[') {
190 escstatus = 2;
191 } else {
192 escstatus = 0;
193 appendchar(7); /* Bell */
194 }
195 return;
196 }
197 if (escstatus == 2) {
198 switch (inpb) {
199 case 'A': /* Up */
200 /* Try to restore the last comnmand */
201 for (; inputpos > 0; inputpos--) {
202 appendchar(8);
203 }
204 while (inputbuf[inputpos]) {
205 appendchar(inputbuf[inputpos++]);
206 }
207 break;
208 case 'B': /* Down */
209 /* New empty command line */
210 for (; inputpos > 0; inputpos--) {
211 appendchar(8);
212 appendchar(' ');
213 appendchar(8);
214 }
215 break;
216 case 'C': /* Left */
217 case 'D': /* Right */
218 default:
219 appendchar(7); /* Bell */
220 break;
221 };
222 escstatus = 0;
223 return;
224 }
225 /* escstatus == 0, i.e. not in an escape */
226 switch (inpb) {
227 case 0 ... 7: /* Nonprinting characters. Ignore. */
228 case 11 ... 12: /* Nonprinting characters. Ignore. */
229 case 14 ... 26: /* Nonprinting characters. Ignore. */
230 case 28 ... 31: /* Nonprinting characters. Ignore. */
231 case 0x7f ... 0xff: /* Nonprinting characters. Ignore. */
232 console_printhex8_noirq(inpb);
233 appendchar(7); /* Bell */
234 break;
235 case 9: /* tab. Should be implemented some day? */
236 appendchar(7); /* Bell */
237 break;
238 case 27: /* Escape */
239 escstatus = 1;
240 break;
241 case 8: /* Backspace */
242 if (inputpos > 0) {
243 inputpos--;
244 appendchar(inpb);
245 appendchar(' ');
246 appendchar(inpb);
247 }
248 break;
249 case '\r': /* 13 */
250 case '\n': /* 10 */
251 if (inputpos == 0) {
252 console_printpgm_noirq_P(PROMPT);
253 break;
254 }
255 inputbuf[inputpos] = 0; /* Null-terminate the string */
256 console_printpgm_noirq_P(CRLF);
257 /* now lets see what it is */
258 if (strcmp_P(inputbuf, PSTR("help")) == 0) {
259 console_printpgm_noirq_P(PSTR("Available commands:"));
260 console_printpgm_noirq_P(PSTR("\r\n motd repeat welcome message"));
261 console_printpgm_noirq_P(PSTR("\r\n showpins [x] shows the avrs inputpins"));
262 console_printpgm_noirq_P(PSTR("\r\n status show status / counters"));
263 /* console_printpgm_noirq_P(PSTR("\r\n save saves settings to EEPROM")); */
264 } else if (strcmp_P(inputbuf, PSTR("motd")) == 0) {
265 console_printpgm_noirq_P(WELCOMEMSG);
266 } else if (strncmp_P(inputbuf, PSTR("showpins"), 8) == 0) {
267 uint8_t which = 0;
268 uint8_t stal = 1; uint8_t endl = 4;
269 if (inputpos == 10) {
270 switch (inputbuf[9]) {
271 case 'a':
272 case 'A':
273 which = 1; break;
274 case 'b':
275 case 'B':
276 which = 2; break;
277 case 'c':
278 case 'C':
279 which = 3; break;
280 case 'd':
281 case 'D':
282 which = 4; break;
283 };
284 }
285 if (which) {
286 stal = which;
287 endl = which;
288 }
289 for (which = stal; which <= endl; which++) {
290 uint8_t pstatus;
291 switch (which) {
292/* case 1: pstatus = PINA;
293 console_printpgm_noirq_P(PSTR("PINA: 0x"));
294 break;*/
295 case 2: pstatus = PINB;
296 console_printpgm_noirq_P(PSTR("PINB: 0x"));
297 break;
298 case 3: pstatus = PINC;
299 console_printpgm_noirq_P(PSTR("PINC: 0x"));
300 break;
301 case 4: pstatus = PIND;
302 console_printpgm_noirq_P(PSTR("PIND: 0x"));
303 break;
304 default:
305 pstatus = 0;
306 console_printpgm_noirq_P(PSTR("NOPIN: 0x"));
307 break;
308 };
309 console_printhex8_noirq(pstatus);
310 appendchar(' ');
311 console_printbin8_noirq(pstatus);
312 if (which < endl) {
313 appendchar('\r'); appendchar('\n');
314 }
315 }
316/* } else if (strcmp_P(inputbuf, PSTR("save")) == 0) {
317 saveeepromsettings();
318 console_printpgm_noirq_P(PSTR("Settings written to EEPROM."));*/
319 } else if (strcmp_P(inputbuf, PSTR("status")) == 0) {
320 console_printpgm_noirq_P(PSTR("Current status:\r\n"));
321 console_printpgm_noirq_P(PSTR("none. nothing implemented yet."));
322#ifdef JOKECMDS
323 } else if (strncmp_P(inputbuf, PSTR("ls"), 2) == 0) {
324 console_printpgm_noirq_P(PSTR("Total 4711\r\n"));
325 console_printpgm_noirq_P(PSTR("----r-xr-- 1 root root 42234223666 Dec 18 2004 duschcam1.avi"));
326 } else if (strncmp_P(inputbuf, PSTR("cat"), 3) == 0) {
327 if (inputpos > 4) {
328 console_printtext_noirq(&inputbuf[4]);
329 console_printpgm_noirq_P(PSTR(": Permission denied"));
330 } else {
331 console_printpgm_noirq_P(PSTR("Usage: cat filename"));
332 }
333#endif /* JOKECMDS */
334 } else {
335#ifdef JOKECMDS
336 console_printpgm_noirq_P(PSTR("bash: "));
337 console_printtext_noirq(inputbuf);
338 console_printpgm_noirq_P(PSTR(": command not found."));
339#else /* JOKECMDS */
340 console_printpgm_noirq_P(PSTR("Unknown command: "));
341 console_printtext_noirq(inputbuf);
342#endif /* JOKECMDS */
343 }
344 /* show PROMPT and go back to start. */
345 console_printpgm_noirq_P(PROMPT);
346 inputpos = 0;
347 break;
348 default:
349 if (inputpos < (INPUTBUFSIZE - 1)) { /* -1 for terminating \0 */
350 inputbuf[inputpos++] = inpb;
351 /* Echo the character */
352 appendchar(inpb);
353 } else {
354 appendchar(7); /* Bell */
355 }
356 };
357}
This page took 0.075018 seconds and 4 git commands to generate.