firmware
[nixiedisp] / fw / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <ctype.h>
5 #include <avr/io.h>
6 #include <avr/interrupt.h>
7 #include <util/delay.h>
8 #include "serial.h"
9
10 /* TODO before board arrive:
11  * - USB comms
12  * - RTC time/data setting
13  * - hack the digit drivers with 7seg?
14  */
15
16 /* pin assignments
17  * B[0,2]: serial clock for the 3 shift registers
18  * B4: SPI MISO connected to RTC I/O pin
19  * B5: SPI SCK connected to RTC serial clock
20  *
21  * C0: serial data for the 3 shift registers
22  * C1: hour separator LEDs
23  * C2: RTC chip select (active high)
24  *
25  * D[2,7]: nixie dots
26  */
27 #define PB_CK1          0x01
28 #define PB_CK2          0x02
29 #define PB_CK3          0x04
30 #define PB_RTC_DATA     0x10
31 #define PB_RTC_CK       0x20
32 #define PC_SDATA        0x01
33 #define PC_HRSEP        0x02
34 #define PC_RTC_EN       0x04
35 #define PD_ADOT         0x04
36 #define PD_BDOT         0x08
37 #define PD_CDOT         0x10
38 #define PD_DDOT         0x20
39 #define PD_EDOT         0x40
40 #define PD_FDOT         0x80
41
42 static void proc_cmd(char *input);
43 static void update_display(void);
44 static void show_number(uint32_t xnum);
45 static void setclock(int hr, int min, int sec);
46 static void setdate(int day, int mon, int year);
47
48 enum { MODE_CLOCK, MODE_NUM };
49
50 static int mode;
51 static int echo, blank;
52 static uint32_t number;
53
54 static char input[128];
55 static unsigned char inp_cidx;
56
57
58 int main(void)
59 {
60         /* SPI (SS/MOSI/SCK) are outputs */
61         DDRB = ~PB_RTC_DATA;    /* port B all outputs except the RTC data line */
62         PORTB = 0;
63         DDRC = 0xff;                    /* port C all outputs */
64         PORTC = 0;
65         DDRD = 0xff;                    /* port D all outputs */
66         PORTD = 0;
67
68         /* init the serial port we use to talk to the host */
69         init_serial(38400);
70         sei();
71
72         for(;;) {
73                 if(have_input()) {
74                         int c = getchar();
75                         if(echo) {
76                                 putchar(c);
77                         }
78
79                         if(c == '\r' || c == '\n') {
80                                 input[inp_cidx] = 0;
81                                 proc_cmd(input);
82                                 inp_cidx = 0;
83                         } else if(inp_cidx < sizeof input - 1) {
84                                 input[inp_cidx++] = c;
85                         }
86                 }
87         }
88         return 0;
89 }
90
91 static const char *helpstr =
92         "<num>: set number\n"
93         " e 0|1: turn echo on/off\n"
94         " b 0|1: blank/unblank display\n"
95         " m n|c: change display mode (n: number, c: clock)\n"
96         " s <hr>:<min>.<sec>: set clock\n"
97         " d <day>/<mon>/<year>: set date\n"
98         " ?/h: print command help\n";
99
100 static void proc_cmd(char *input)
101 {
102         int cmd, hr, min, sec, day, mon, year;
103         char *args;
104
105         while(*input && isspace(*input)) input++;
106         if(!*input) return;
107
108         cmd = *input;
109         args = input + 1;
110         while(*args && isspace(*args)) args++;
111
112         switch(cmd) {
113         case 'e':
114                 echo = atoi(args);
115                 printf("OK echo %s\n", echo ? "on" : "off");
116                 break;
117
118         case 'b':
119                 printf("OK %sblanking display\n", blank ? "" : "un");
120                 blank = atoi(args);
121                 update_display();
122                 break;
123
124         case 'm':
125                 if(input[1] == 'c') {
126                         printf("OK clock mode\n");
127                         mode = MODE_CLOCK;
128                         update_display();
129                 } else if(input[1] == 'n') {
130                         printf("OK number mode\n");
131                         mode = MODE_NUM;
132                         update_display();
133                 } else {
134                         printf("ERR invalid mode: '%s'\n", args);
135                 }
136                 break;
137
138         case 's':
139                 sec = 0;
140                 if(sscanf(args, "%d:%d.%d", &hr, &min, &sec) < 2) {
141                         printf("ERR invalid time string: \"%s\"\n", args);
142                         break;
143                 }
144                 setclock(hr, min, sec);
145                 printf("OK clock set\n");
146                 if(mode == MODE_CLOCK) {
147                         update_display();
148                 }
149                 break;
150
151         case 'd':
152                 if(sscanf(args, "%d/%d/%d", &day, &mon, &year) != 3 || day < 1 || day > 31 ||
153                                 mon < 1 || mon > 12 || year < 0) {
154                         printf("ERR invalid date string: \"%s\"\n", args);
155                         break;
156                 }
157                 if(year < 100) year += 2000;
158                 setdate(day, mon, year);
159                 printf("OK date set\n");
160                 /* TODO */
161                 break;
162
163         case 'x':
164                 {
165                         char *endp;
166                         long num = strtol(args, &endp, 16);
167                         if(endp == args) {
168                                 printf("ERR invalid hex number: \"%s\"\n", args);
169                                 break;
170                         }
171                         number = num;
172                         if(mode == MODE_NUM) {
173                                 update_display();
174                         }
175                 }
176                 break;
177
178         case '?':
179         case 'h':
180                 puts("OK command help");
181                 puts(helpstr);
182                 break;
183
184         default:
185                 if(isdigit(args[0])) {
186                         int num = atoi(args);
187                         number = (uint32_t)num << 16;
188                         printf("OK number: %d (%08lxh)\n", num, number);
189                         if(mode == MODE_NUM) {
190                                 update_display();
191                         }
192                 } else {
193                         printf("ERR unknown command: '%c'\n", cmd);
194                 }
195         }
196 }
197
198 static void update_display(void)
199 {
200         show_number(number);
201 }
202
203 static void set_digit(int idx, unsigned int d)
204 {
205         int i;
206         unsigned int clkbit = 1 << idx;
207
208         for(i=0; i<8; i++) {
209                 PORTC = (PORTC & 0xfe) | (d >> 7);
210                 PORTB = (PORTB & 0xf8) | clkbit;
211                 PORTB &= 0xf8;
212                 d <<= 1;
213         }
214 }
215
216 static void show_number(uint32_t n)
217 {
218         int i, d;
219
220         for(i=0; i<6; i++) {
221                 d = n % 10;
222                 n /= 10;
223
224                 set_digit(i, d);
225         }
226 }
227
228 static void setclock(int hr, int min, int sec)
229 {
230 }
231
232 static void setdate(int day, int mon, int year)
233 {
234 }