quite a few files to ignore
[moodlight.git] / console.c
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
19 static uint8_t inputbuf[INPUTBUFSIZE];
20 static uint8_t inputpos = 0;
21 #define OUTPUTBUFSIZE 400
22 static uint8_t outputbuf[OUTPUTBUFSIZE];
23 static uint16_t outputhead = 0; /* WARNING cannot be modified atomically */
24 static uint16_t outputtail = 0;
25 static uint8_t opinprog = 0;
26 static uint8_t escstatus = 0;
27 static prog_uint8_t CRLF[] = "\r\n";
28 static 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__;
37 static prog_uint8_t PROMPT[] = "\r\nroot@mbv1# ";
38
39 /* Handler for TXC (TX Complete) IRQ */
40 ISR(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. */
58 static void appendchar(uint8_t what) __attribute__((noinline));
59 #endif /* __GNUC__ */
60 /* This can only be called safely with interrupts disabled - remember that! */
61 static 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
82 void console_printchar_noirq(uint8_t what) {
83   appendchar(what);
84 }
85
86 /* This can only be called safely with interrupts disabled - remember that! */
87 void 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! */
103 void 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! */
115 void 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! */
128 static 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! */
136 static 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. */
145 void console_printtext(const uint8_t * what) {
146         cli();
147         console_printtext_noirq(what);
148         sei();
149 }
150
151 void console_printpgm_P(PGM_P what) {
152         cli();
153         console_printpgm_noirq_P(what);
154         sei();
155 }
156
157 void console_printhex8(uint8_t what) {
158         cli();
159         console_printhex8_noirq(what);
160         sei();
161 }
162
163 void console_printdec(uint8_t what) {
164         cli();
165         console_printdec_noirq(what);
166         sei();
167 }
168
169 void 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. */
184 ISR(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.072906 seconds and 3 git commands to generate.