1 /* $Id: console.c,v 1.1 2010/06/26 12:28:08 simimeie Exp $
2 * Functions for a serial console.
6 #include <avr/interrupt.h>
7 #include <avr/pgmspace.h>
8 #include <avr/version.h>
9 #include <util/delay.h>
13 /* PD0 is RXD, PD1 is TXD, but we don't need to address them manually */
15 /* Formula for calculating the value of UBRR from baudrate and cpufreq */
16 #define UBRRCALC ((CPUFREQ / (16 * BAUDRATE)) - 1)
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 ******************************************"\
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# ";
39 /* Handler for TXC (TX Complete) IRQ */
41 if (outputhead == outputtail) { /* Nothing more to send! */
44 UDR0 = outputbuf[outputhead];
46 if (outputhead >= OUTPUTBUFSIZE) {
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));
60 /* This can only be called safely with interrupts disabled - remember that! */
61 static void appendchar(uint8_t what) {
63 newpos = (outputtail + 1);
64 if (newpos >= OUTPUTBUFSIZE) {
67 if (newpos != outputhead) {
68 outputbuf[outputtail] = what;
75 if (outputhead >= OUTPUTBUFSIZE) {
82 void console_printchar_noirq(uint8_t what) {
86 /* This can only be called safely with interrupts disabled - remember that! */
87 void console_printhex8_noirq(uint8_t what) {
91 buf = (uint8_t)(what & (uint8_t)0xF0) >> 4;
102 /* This can only be called safely with interrupts disabled - remember that! */
103 void console_printdec_noirq(uint8_t what) {
106 appendchar(buf + '0');
109 appendchar(buf + '0');
111 appendchar(buf + '0');
114 /* This can only be called safely with interrupts disabled - remember that! */
115 void console_printbin8_noirq(uint8_t what) {
117 for (i = 0; i < 8; i++) {
127 /* This can only be called safely with interrupts disabled - remember that! */
128 static void console_printtext_noirq(const uint8_t * what) {
135 /* This can only be called safely with interrupts disabled - remember that! */
136 static void console_printpgm_noirq_P(PGM_P what) {
138 while ((t = pgm_read_byte(what++))) {
143 /* These are wrappers for our internal functions, disabling IRQs before
145 void console_printtext(const uint8_t * what) {
147 console_printtext_noirq(what);
151 void console_printpgm_P(PGM_P what) {
153 console_printpgm_noirq_P(what);
157 void console_printhex8(uint8_t what) {
159 console_printhex8_noirq(what);
163 void console_printdec(uint8_t what) {
165 console_printdec_noirq(what);
169 void console_init(void) {
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);
182 /* Handler for RXC (RX Complete) IRQ. */
183 /* We do all query processing here. */
188 if (escstatus == 1) {
193 appendchar(7); /* Bell */
197 if (escstatus == 2) {
200 /* Try to restore the last comnmand */
201 for (; inputpos > 0; inputpos--) {
204 while (inputbuf[inputpos]) {
205 appendchar(inputbuf[inputpos++]);
209 /* New empty command line */
210 for (; inputpos > 0; inputpos--) {
217 case 'D': /* Right */
219 appendchar(7); /* Bell */
225 /* escstatus == 0, i.e. not in an escape */
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 */
235 case 9: /* tab. Should be implemented some day? */
236 appendchar(7); /* Bell */
238 case 27: /* Escape */
241 case 8: /* Backspace */
252 console_printpgm_noirq_P(PROMPT);
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) {
268 uint8_t stal = 1; uint8_t endl = 4;
269 if (inputpos == 10) {
270 switch (inputbuf[9]) {
289 for (which = stal; which <= endl; which++) {
292 /* case 1: pstatus = PINA;
293 console_printpgm_noirq_P(PSTR("PINA: 0x"));
295 case 2: pstatus = PINB;
296 console_printpgm_noirq_P(PSTR("PINB: 0x"));
298 case 3: pstatus = PINC;
299 console_printpgm_noirq_P(PSTR("PINC: 0x"));
301 case 4: pstatus = PIND;
302 console_printpgm_noirq_P(PSTR("PIND: 0x"));
306 console_printpgm_noirq_P(PSTR("NOPIN: 0x"));
309 console_printhex8_noirq(pstatus);
311 console_printbin8_noirq(pstatus);
313 appendchar('\r'); appendchar('\n');
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."));
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) {
328 console_printtext_noirq(&inputbuf[4]);
329 console_printpgm_noirq_P(PSTR(": Permission denied"));
331 console_printpgm_noirq_P(PSTR("Usage: cat filename"));
333 #endif /* JOKECMDS */
336 console_printpgm_noirq_P(PSTR("bash: "));
337 console_printtext_noirq(inputbuf);
338 console_printpgm_noirq_P(PSTR(": command not found."));
340 console_printpgm_noirq_P(PSTR("Unknown command: "));
341 console_printtext_noirq(inputbuf);
342 #endif /* JOKECMDS */
344 /* show PROMPT and go back to start. */
345 console_printpgm_noirq_P(PROMPT);
349 if (inputpos < (INPUTBUFSIZE - 1)) { /* -1 for terminating \0 */
350 inputbuf[inputpos++] = inpb;
351 /* Echo the character */
354 appendchar(7); /* Bell */