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

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