Message Integrity Checking
[uccvend-snackrom.git] / ROM2 / main_basic.c
1 /*
2  * main_basic.c - a simplified main procedure that relies upon a ersver to do
3  * anything smart. Just be a dumb interface to a display, keypad, coin mech
4  * and snacks.
5  */
6
7 #define VERSION_STRING "R 20040622"
8
9 #include "display_basic.h"
10 #include "keypad.h"
11 #include "chime.h"
12 #include "coinmech.h"
13 #include "motors.h"
14 #include "sci.h"
15 #include "vend.h"
16 #include "xmodem.h"
17 #include "mic.h"
18
19 u8 last_standalone;
20 u8 last_switch_input;
21 u8 last_misc_input;
22 u16 last_coin_value;
23 bool last_door_open;
24 char display_buf[11];
25 /* cur_motor[0] is 0 for nothing, or 1..10, or 0xff to say redraw.
26  * cur_motor[1] is 0..9 and only meaningful is cur_motor[0] != 0. */
27 u8 cur_motor[2];
28
29 bool check_standalone() {
30         if (is_standalone()) {
31                 send_string("011 In standalone mode. Function disabled." CRLF);
32                 return 1;
33         }
34         return 0;
35 }
36
37 void unknown_command() {
38         send_string("012 Unknown command. Type HELP for help." CRLF);
39 }
40
41 void motor_reply(u8 code) {
42         /* returns a message of the form MXYY - X is return code, YY is motor */
43         switch (code) {
44                 case MOTOR_SUCCESS:
45                         send_string("100 Vend successful." CRLF);
46                         break;
47                 case MOTOR_NOSLOT:
48                         send_string("151 No motor there." CRLF);
49                         break;
50                 case MOTOR_CURRENT_FAIL:
51                         send_string("152 Over current." CRLF);
52                         break;
53                 case MOTOR_HOME_FAIL:
54                         send_string("153 Home sensors failing." CRLF);
55                         break;
56                 default:
57                         send_string("159 Unknown motor error." CRLF);
58         }
59 }
60
61 void dispense_something() {
62         /* process a message VXX in sci_rx_buf where XX is motor number */
63         u8 slot;
64
65         if (check_standalone()) return;
66         if (must_verify() && !mic_verify((void*)sci_rx_buf)) {
67                 send_string("019 Message verification failed." CRLF);
68                 return;
69         }
70
71         if (my_strncmp("ALL", (char*)sci_rx_buf+1, 3)) {
72                 char motor[3];
73                 motor[2] = '\0';
74                 send_string("102 Vend all motors starting." CRLF);
75                 for (motor[0] = '0'; motor[0] <= '9'; motor[0]++) {
76                         for (motor[1] = '0'; motor[1] <= '9'; motor[1]++) {
77                                 send_string("101 Vending ");
78                                 send_string(motor);
79                                 send_string(CRLF);
80                                 motor_reply(dispense_motor(motor[0]*10+motor[1]));
81                         }
82                 }
83                 send_string("102 Vend all motors complete." CRLF);
84                 return;
85         }
86
87         if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
88                 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9')) {
89                 sci_rx_buf[1] = sci_rx_buf[2] = '0';
90                 motor_reply(MOTOR_NOSLOT);
91                 return;
92         }
93
94         slot = (sci_rx_buf[1] - '0') * 10;
95         slot += sci_rx_buf[2] - '0';
96
97         motor_reply(dispense_motor(slot));
98 }
99
100 void write_to_display() {
101         /* process a message in the form DXXXXXXXXXX to send to display */
102         u8 i;
103         char buf[11];
104
105         if (check_standalone()) return;
106
107         for (i = 0; i < 10; i++)
108                 if (sci_rx_buf[i+1])
109                         buf[i] = sci_rx_buf[i+1];
110                 else
111                         break;
112
113         for (; i < 10; i++) /* pad the rest out with spaces */
114                 buf[i] = ' ';
115         buf[i] = '\0';
116
117         set_msg(buf);
118         send_string("300 Written." CRLF);
119 }
120
121 void send_balance() {
122         sci_tx_buf[0] = 'C';
123         sci_tx_buf[1] = have_change?'0':'1';
124         sci_tx_buf[2] = (coin_value/10000)%10;
125         sci_tx_buf[3] = (coin_value/1000)%10;
126         sci_tx_buf[4] = (coin_value/100)%10;
127         sci_tx_buf[5] = (coin_value/10)%10;
128         sci_tx_buf[6] = coin_value%10;
129         sci_tx_buf[8] = 0;
130         send_buffer(1);
131 }
132
133 void give_change() {
134         u16 cost;
135
136         if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
137                 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9') ||
138                 (sci_rx_buf[3] < '0') || (sci_rx_buf[3] > '9') ||
139                 (sci_rx_buf[4] < '0') || (sci_rx_buf[4] > '9') ||
140                 (sci_rx_buf[5] < '0') || (sci_rx_buf[5] > '9')) {
141                 send_nack();
142         }
143         cost = sci_rx_buf[1] - '0';
144         cost *= 10; cost = sci_rx_buf[2] - '0';
145         cost *= 10; cost = sci_rx_buf[3] - '0';
146         cost *= 10; cost = sci_rx_buf[4] - '0';
147         cost *= 10; cost = sci_rx_buf[5] - '0';
148
149         coin_cost(cost);
150         send_ack();
151
152
153 void send_keypress(u8 key) {
154         /* send a packet of the form KX with X being the key, or R for reset */
155         if (is_standalone()) return;
156
157         sci_tx_buf[0] = '2';
158         if (key == KEY_RESET) {
159                 sci_tx_buf[1] = '1';
160                 sci_tx_buf[2] = '1';
161         } else {
162                 sci_tx_buf[1] = '0';
163                 sci_tx_buf[2] = (key%10)+'0';
164         }
165         sci_tx_buf[3] = '\0';
166         send_buffer(0);
167         send_string(" key." CRLF);
168 }
169
170 void send_door_msg(bool open) {
171         if (is_standalone()) return;
172         sci_tx_buf[0] = '4';
173         sci_tx_buf[1] = '0';
174         sci_tx_buf[2] = open?'1':'0';
175         send_buffer(0);
176         if (open)
177                 send_string(" door open." CRLF);
178         else
179                 send_string(" door closed." CRLF);
180 }
181
182 void do_chime() {
183         if (check_standalone()) return;
184         if (sci_rx_buf[1] == '\0')
185                 chime_start();
186         else if (sci_rx_buf[1] == 'S') { /* synchronous beep */
187                 if (sci_rx_buf[2] == '\0')
188                         chime_start();
189                 else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0')
190                         chime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3]));
191                 else {
192                         send_string("510 Unknown chime duration." CRLF);
193                         return;
194                 }
195                 while (chime_count); /* spin */
196                 send_string("500 Chimed." CRLF);
197                 return;
198         } else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
199                 chime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
200         else {
201                 send_string("510 Unknown chime duration." CRLF);
202                 return;
203         }
204         send_string("500 Chime started." CRLF);
205         return;
206 }
207
208 void do_silence() {
209         if (check_standalone()) return;
210         if (sci_rx_buf[1] == '\0')
211                 unchime_start();
212         else if (sci_rx_buf[1] == 'S') { /* synchronous beep */
213                 if (sci_rx_buf[2] == '\0')
214                         unchime_start();
215                 else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0')
216                         unchime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3]));
217                 else {
218                         send_string("511 Unknown silence duration." CRLF);
219                         return;
220                 }
221                 while (unchime_count); /* spin */
222                 send_string("501 Silenced." CRLF);
223                 return;
224         } else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
225                 unchime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
226         else {
227                 send_string("511 Unknown silence duration." CRLF);
228                 return;
229         }
230         send_string("500 Silence started." CRLF);
231         return;
232 }
233
234 void print_switches(u8 prompted) {
235         if (prompted)
236                 send_string("600 ");
237         else
238                 send_string("610 ");
239         send_string(u82hex(misc_input));
240         send_string(" ");
241         send_string(u82hex(switch_input));
242         send_string(CRLF);
243 }
244
245 void ping_pong() {
246         /* make sure it's really a ping */
247         if (!my_strncmp("ING", (char*)sci_rx_buf+1, 3)) {
248                 unknown_command();
249                 return;
250         }
251         /* respond with ack & pong */
252         send_string("000 PONG!" CRLF);
253 }
254
255 void send_prompt() {
256         if (must_verify()) {
257                 send_string(u82hex(mic_challenge >> 8));
258                 send_string(u82hex(mic_challenge & 0xff));
259         }
260         send_string(is_standalone()?"% ":"# ");
261 }
262
263 void about() {
264         if (!my_strncmp("BOUT", (char*)sci_rx_buf+1, 4)) {
265                 unknown_command();
266                 return;
267         }
268         send_string(
269                 "-----------------------------------------------------------------" CRLF
270                 "    ROM2 (C) 2004 Bernard Blackham <[email protected]>" CRLF
271                 "-----------------------------------------------------------------" CRLF
272                 "                                        Revision " VERSION_STRING CRLF
273                 "" CRLF
274                 "   This snack machine was brought to you by " CRLF
275                 "    Bernard Blackham" CRLF
276                 "    Mark Tearle" CRLF
277                 "    Harry McNally" CRLF
278                 "    Michal Gornisiewicz" CRLF
279                 "    and others." CRLF
280                 "" CRLF
281                 " Another UCC project in action.         http://www.ucc.asn.au/" CRLF
282         );
283 }
284
285 void set_echo() {
286         if (my_strncmp("CHO ON", (char*)sci_rx_buf+1, 6))
287                 sci_echo = 1;
288         else if (my_strncmp("CHO OFF", (char*)sci_rx_buf+1, 7))
289                 sci_echo = 0;
290         else
291                 unknown_command();
292 }
293
294 void moo() {
295         if (!my_strncmp("OO", (char*)sci_rx_buf+1, 2)) {
296                 unknown_command();
297                 return;
298         }
299         send_string(
300 "       ____________" CRLF
301 "       |__________|" CRLF
302 "      /           /\\" CRLF
303 "     /  U C C    /  \\" CRLF
304 "    /___________/___/|" CRLF
305 "    |          |     |" CRLF
306 "    |  ==\\ /== |     |" CRLF
307 "    |   O   O  | \\ \\ |" CRLF
308 "    |     <    |  \\ \\|" CRLF
309 "   /|          |   \\ \\" CRLF
310 "  / |  \\_____/ |   / /" CRLF
311 " / /|          |  / /|" CRLF
312 "/||\\|          | /||\\/" CRLF
313 "    -------------|   " CRLF
314 "        | |    | | " CRLF
315 "       <__/    \\__>" CRLF
316 "" CRLF
317 "  ... Where's the cheese?" CRLF
318         );
319 }
320
321 void help() {
322         send_string(
323                 "Valid commands are:" CRLF
324                 " ABOUT         ROM information" CRLF
325                 " PING          pongs" CRLF
326                 " ECHO {ON|OFF} turn echo on or off" CRLF
327                 " Vnn           vend an item" CRLF
328                 " VALL          vend all items" CRLF
329                 " DXXXXXXXXXX   show a message on the display" CRLF
330                 " B[nn]         beep for a duration nn (optional)" CRLF
331                 " S[...]        query all internal switch states" CRLF
332                 " H[...]        this help screen" CRLF
333                 " GETROM        download the ROM source code using xmodem" CRLF
334                 "Comments start with a #" CRLF
335         );
336 }
337
338 extern const char _rom_src_data[];
339 extern const u16 _rom_src_len;
340 void getrom() {
341         if (!my_strncmp("ETROM", (char*)sci_rx_buf+1, 5)) {
342                 unknown_command();
343                 return;
344         }
345         char s[4];
346         send_string("Writing to serial port (maybe). Size is 0x");
347         send_string(u82hex(_rom_src_len >> 8));
348         send_string(u82hex(_rom_src_len & 0xff));
349         send_string("@0x");
350         send_string(u82hex((u16)(&_rom_src_data) >> 8));
351         send_string(u82hex((u16)(&_rom_src_data) & 0xff));
352         send_string(" with signature ");
353         s[0] = _rom_src_data[0];
354         s[1] = _rom_src_data[1];
355         s[2] = _rom_src_data[2];
356         s[3] = '\0';
357         send_string(s);
358         send_string(CRLF " Type YES to download rom.tar.bz2 via XMODEM: ");
359         msg_clr();
360         while (!sci_have_packet); /* spin */
361         if (!my_strncmp("YES", (char*)sci_rx_buf, 3)) {
362                 send_string(CRLF "Transfer cancelled." CRLF);
363                 return;
364         }
365
366         sci_init();
367         sci_doing_xmodem = 1;
368         if (!xmodem_init_xfer()) {
369                 sci_doing_xmodem = 0;
370                 send_string("XMODEM init failed. Nobody's listening :(" CRLF);
371                 return;
372         }
373         char *p = (char*)_rom_src_data;
374         char *end = (char*)_rom_src_data+_rom_src_len;
375         bool aborted = 0;
376         while (1) {
377                 if (p + 128 > end) {
378                         /* send partial packet */
379                         if (!xmodem_send_packet((char*)p, end-p)) aborted = 1;
380                         break;
381                 } if ((u16)p == 0xb600) {
382                         /* we have an eeprom here. skip it. */
383                         p += 0x0200;
384                         continue;
385                 } else if (!xmodem_send_packet((char*)p, 128)) {
386                         aborted = 1;
387                         break;
388                 }
389                 p += 128;
390         }
391
392         xmodem_finish_xfer();
393         sci_doing_xmodem = 0;
394         if (aborted)
395                 send_string(CRLF "Transfer aborted." CRLF);
396         else
397                 send_string(CRLF "Transfer complete." CRLF);
398 }
399
400 void quit() {
401         if (my_strncmp("UIT", (char*)sci_rx_buf+1, 3))
402                 send_string("013 You can't quit you doofus." CRLF);
403         else
404                 unknown_command();
405 }
406
407 //SHA1_CTX ctx;
408 //u8 sha1_digest[SHA1_SIGNATURE_SIZE];
409
410 int main() {
411         u8 i;
412         for (i = 0; i < 11; i++)
413                 display_buf[i] = ' ';
414         display_buf[10] = '\0';
415
416         changer_output = 0x7f;
417         _io_ports[M6811_PORTA] = 0xc0; /* display on. talking to serial port */
418         _io_ports[M6811_DDRA] = 0xfc;
419         _io_ports[M6811_DDRD] = 0x3e;
420         _io_ports[M6811_SPCR] = M6811_MSTR | M6811_SPR1;
421         set_misc_output(0x00);
422
423         display_init();
424         set_msg(" HELLO    ");
425         delay(1000);
426
427         unlock(); /* enable interrupts */
428
429         set_msg("  CRUEL   ");
430
431         //coinmech_init();
432         sci_init();
433         keypad_init();
434         last_coin_value = 0;
435         last_door_open = 0;
436
437         delay(1000);
438
439         set_msg("   WORLD  ");
440         delay(1000);
441
442         chime_start();
443
444         send_string("5N4X0RZ R US" CRLF);
445
446         mic_challenge = 0;
447         mic_set_secret("ABCDEFGH12345678");
448         
449         last_standalone = is_standalone();
450         if (last_standalone)
451                 cur_motor[0] = 0xff;
452         else
453                 cur_motor[0] = 0;
454         send_prompt();
455
456         last_switch_input = switch_input;
457         last_misc_input = misc_input;
458
459         while(1) {
460                 if (cur_motor[0] == 0xff) { /* signal to say redraw screen */
461                         set_msg("*5N4X0RZ* ");
462                         cur_motor[0] = 0;
463                 }
464
465                 if (door_open() != last_door_open) {
466                         last_door_open = door_open();
467                         send_door_msg(last_door_open);
468                         chime_start();
469                         if (is_standalone())
470                                 set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE");
471                 }
472
473                 if (last_standalone != is_standalone()) {
474                         /* somebody flicked the standalone switch */
475                         msg_clr();
476                         send_string(CRLF);
477                         send_prompt();
478                         last_standalone = is_standalone();
479                 }
480
481                 if (last_misc_input != misc_input) {
482                         print_switches(0);
483                         last_misc_input = misc_input;
484                 }
485
486                 if (last_switch_input != switch_input) {
487                         print_switches(0);
488                         last_switch_input = switch_input;
489                 }
490
491                 if (sci_have_packet) {
492                         switch (sci_rx_buf[0]) {
493                                 case '\0':
494                                 case '#':
495                                         send_string(CRLF);
496                                         break;
497                                 case 'E':
498                                         set_echo();
499                                         break;
500                                 case 'H':
501                                         help();
502                                         break;
503                                 case 'V':
504                                         dispense_something();
505                                         break;
506                                 case 'D':
507                                         write_to_display();
508                                         break;
509                                 case 'B': 
510                                         do_chime();
511                                         break;
512                                 case 'C': 
513                                         do_silence();
514                                         break;
515                                 case 'P':
516                                         ping_pong();
517                                         break;
518                                 case 'A':
519                                         about();
520                                         break;
521                                 case 'S':
522                                         print_switches(1);
523                                         break;
524                                 case 'M':
525                                         moo();
526                                         break;
527                                 case 'Q':
528                                         quit();
529                                         break;
530                                 case 'G':
531                                         getrom();
532                                         break;
533                                 default:
534                                         // shurg
535                                         unknown_command();
536                                         break;
537                         }
538                         msg_clr();
539                         send_prompt();
540                 }
541
542                 keypad_read();
543                 if (keypad_pressed()) {
544                         if (is_standalone()) {
545                                 if (last_key == KEY_RESET) {
546                                         cur_motor[0] = 0xff;
547                                 } else {
548                                         if (cur_motor[0]) {
549                                                 u8 motor_num;
550                                                 cur_motor[1] = last_key%10;
551                                                 display_buf[1] = cur_motor[1]+'0';
552                                                 set_msg(display_buf);
553
554                                                 motor_num = cur_motor[0]%10;
555                                                 motor_num *= 10;
556                                                 motor_num += cur_motor[1];
557                                                 switch (dispense_motor(motor_num)) {
558                                                         case MOTOR_HOME_FAIL:
559                                                                 set_msg(" HOME FAIL ");
560                                                                 break;
561                                                         case MOTOR_CURRENT_FAIL:
562                                                                 set_msg(" OVER CRNT ");
563                                                                 break;
564                                                         case MOTOR_SUCCESS:
565                                                                 set_msg("THANK  YOU");
566                                                                 break;
567                                                         case MOTOR_NOSLOT:
568                                                                 set_msg(" NO MOTOR ");
569                                                                 break;
570                                                         default:
571                                                                 set_msg("ERRRRRRRR?");
572                                                                 break;
573                                                 }
574
575                                                 display_buf[0] = ' ';
576                                                 display_buf[1] = ' ';
577                                                 cur_motor[0] = 0xff;
578                                                 delay(500);
579                                         } else {
580                                                 cur_motor[0] = last_key;
581                                                 display_buf[0] = (last_key%10)+'0';
582                                                 set_msg(display_buf);
583                                         }
584                                 }
585                         } else
586                                 send_keypress(last_key);
587                 }
588
589                 /*
590                 if (coin_value != last_coin_value) {
591                         send_balance();
592                         last_coin_value = coin_value;
593                 }
594                 */
595         }
596 }

UCC git Repository :: git.ucc.asn.au