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
8 #include "display_basic.h"
24 /* cur_motor[0] is 0 for nothing, or 1..10, or 0xff to say redraw.
25 * cur_motor[1] is 0..9 and only meaningful is cur_motor[0] != 0. */
28 bool check_standalone() {
29 if (is_standalone()) {
30 send_string("011 In standalone mode. Function disabled." CRLF);
36 bool check_badpoke() {
38 send_string("099 Can't poke without flipping DIP SW 3." CRLF);
44 void unknown_command() {
45 send_string("012 Unknown command. Type HELP for help." CRLF);
48 void motor_reply(u8 code) {
49 /* returns a message of the form MXYY - X is return code, YY is motor */
52 send_string("100 Vend successful." CRLF);
55 send_string("151 No motor there." CRLF);
57 case MOTOR_CURRENT_FAIL:
58 send_string("152 Over current." CRLF);
61 send_string("153 Home sensors failing." CRLF);
64 send_string("159 Unknown motor error." CRLF);
68 void dispense_something() {
69 /* process a message VXX in sci_rx_buf where XX is motor number */
72 if (check_standalone()) return;
73 if (must_verify() && !mic_verify((void*)sci_rx_buf)) {
74 send_string("019 Message verification failed." CRLF);
78 if (my_strncmp("ALL", (char*)sci_rx_buf+1, 3)) {
81 send_string("102 Vend all motors starting." CRLF);
82 for (motor[0] = '0'; motor[0] <= '9'; motor[0]++) {
83 for (motor[1] = '0'; motor[1] <= '9'; motor[1]++) {
84 if (motor[1] == '5') continue; /* there is now row 5 */
85 send_string("101 Vending ");
88 motor_reply(dispense_motor((motor[0]-'0')*10+(motor[1]-'0')));
91 send_string("102 Vend all motors complete." CRLF);
95 if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
96 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9')) {
97 sci_rx_buf[1] = sci_rx_buf[2] = '0';
98 motor_reply(MOTOR_NOSLOT);
102 slot = (sci_rx_buf[1] - '0') * 10;
103 slot += sci_rx_buf[2] - '0';
105 motor_reply(dispense_motor(slot));
108 void write_to_display() {
109 /* process a message in the form DXXXXXXXXXX to send to display */
113 if (check_standalone()) return;
115 for (i = 0; i < 10; i++)
117 buf[i] = sci_rx_buf[i+1];
121 for (; i < 10; i++) /* pad the rest out with spaces */
126 send_string("300 Written." CRLF);
129 void send_balance() {
131 sci_tx_buf[1] = have_change?'0':'1';
132 sci_tx_buf[2] = (coin_value/10000)%10;
133 sci_tx_buf[3] = (coin_value/1000)%10;
134 sci_tx_buf[4] = (coin_value/100)%10;
135 sci_tx_buf[5] = (coin_value/10)%10;
136 sci_tx_buf[6] = coin_value%10;
144 if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
145 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9') ||
146 (sci_rx_buf[3] < '0') || (sci_rx_buf[3] > '9') ||
147 (sci_rx_buf[4] < '0') || (sci_rx_buf[4] > '9') ||
148 (sci_rx_buf[5] < '0') || (sci_rx_buf[5] > '9')) {
151 cost = sci_rx_buf[1] - '0';
152 cost *= 10; cost = sci_rx_buf[2] - '0';
153 cost *= 10; cost = sci_rx_buf[3] - '0';
154 cost *= 10; cost = sci_rx_buf[4] - '0';
155 cost *= 10; cost = sci_rx_buf[5] - '0';
161 void send_keypress(u8 key) {
162 /* send a packet of the form KX with X being the key, or R for reset */
163 if (is_standalone()) return;
166 if (key == KEY_RESET) {
171 sci_tx_buf[2] = (key%10)+'0';
173 sci_tx_buf[3] = '\0';
175 send_string(" key." CRLF);
179 /* send a packet of the form KX with X being the key, or R for reset */
180 unsigned int t=get_timer_counter();
183 sci_tx_buf[0] = '0'+(t/10000)%10;
184 sci_tx_buf[1] = '0'+(t/1000)%10;
185 sci_tx_buf[2] = '0'+(t/100)%10;
186 sci_tx_buf[3] = '0'+(t/10)%10;
187 sci_tx_buf[4] = '0'+t%10;
192 void send_door_msg(bool open) {
193 if (is_standalone()) return;
196 sci_tx_buf[2] = open?'1':'0';
199 send_string(" door open." CRLF);
201 send_string(" door closed." CRLF);
205 if (check_standalone()) return;
206 if (sci_rx_buf[1] == '\0')
208 else if (sci_rx_buf[1] == 'S') { /* synchronous beep */
209 if (sci_rx_buf[2] == '\0')
211 else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0')
212 chime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3]));
214 send_string("510 Unknown chime duration." CRLF);
217 while (chime_count); /* spin */
218 send_string("500 Chimed." CRLF);
220 } else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
221 chime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
223 send_string("510 Unknown chime duration." CRLF);
226 send_string("500 Chime started." CRLF);
231 if (check_standalone()) return;
232 if (sci_rx_buf[1] == '\0')
234 else if (sci_rx_buf[1] == 'S') { /* synchronous beep */
235 if (sci_rx_buf[2] == '\0')
237 else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0')
238 unchime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3]));
240 send_string("511 Unknown silence duration." CRLF);
243 while (unchime_count); /* spin */
244 send_string("501 Silenced." CRLF);
246 } else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
247 unchime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
249 send_string("511 Unknown silence duration." CRLF);
252 send_string("501 Silence started." CRLF);
256 void print_switches(u8 prompted) {
261 send_string(u82hex(misc_input));
263 send_string(u82hex(switch_input));
268 /* make sure it's really a ping */
269 if (!my_strncmp("ING", (char*)sci_rx_buf+1, 3)) {
273 /* respond with ack & pong */
274 send_string("000 PONG!" CRLF);
277 u16 hex2addr(char* addrptr) {
279 v = hex2u8(addrptr[0], addrptr[1]) << 8;
280 v |= hex2u8(addrptr[2], addrptr[3]);
285 if (!my_strncmp("EEK", (char*)sci_rx_buf+1, 3)) {
289 if (check_badpoke()) return;
290 if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) &&
291 ishex(sci_rx_buf[7]) && sci_rx_buf[8] == '\0') {
292 u16 v = hex2addr((char*)(sci_rx_buf+4));
295 send_string(u82hex(v));
299 send_string("091 Invalid location given." CRLF);
303 if (!my_strncmp("OKE", (char*)sci_rx_buf+1, 3)) {
307 if (check_badpoke()) return;
308 if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) &&
309 ishex(sci_rx_buf[7]) && ishex(sci_rx_buf[8]) && ishex(sci_rx_buf[9])
310 && sci_rx_buf[10] == '\0') {
312 v = hex2addr((char*)(sci_rx_buf+4));
313 *(u8*)v = hex2u8(sci_rx_buf[8], sci_rx_buf[9]);
314 send_string("080 Written." CRLF);
317 send_string("081 Invalid location or byte given." CRLF);
321 if (!my_strncmp("UMP", (char*)sci_rx_buf+1, 3)) {
325 if (check_badpoke()) return;
326 if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) &&
327 ishex(sci_rx_buf[7]) && sci_rx_buf[8] == '\0') {
328 u16 v = hex2addr((char*)(sci_rx_buf+4));
329 send_string("070 Jumping now." CRLF);
330 asm volatile ("jsr %0" : : "m"(*(u16*)v) : "d");
331 send_string("071 And back." CRLF);
334 send_string("079 Invalid location given." CRLF);
337 void do_set_password() {
340 if (check_badpoke()) return;
341 for (i=1; i < 17; i++) {
342 if (sci_rx_buf[i] == '\0') {
347 if (good && sci_rx_buf[17] != '\0') good = 0;
349 send_string("061 Password must be exactly 16 characters." CRLF);
353 mic_set_secret((char*)(sci_rx_buf+1));
354 send_string("060 Password has been set." CRLF);
359 send_string(u82hex(mic_challenge >> 8));
360 send_string(u82hex(mic_challenge & 0xff));
362 send_string(is_standalone()?"% ":"# ");
366 if (!my_strncmp("BOUT", (char*)sci_rx_buf+1, 4)) {
373 " Revision: " VERSION_STRING " Built: " DATEBUILT_STRING CRLF "" CRLF CRLF
374 " This snack machine was brought to you by " CRLF
375 " Bernard Blackham" CRLF
376 " Harry McNally" CRLF
378 " Michal Gornisiewicz" CRLF
382 " Another UCC project in action. http://www.ucc.asn.au/" CRLF
387 if (my_strncmp("CHO ON", (char*)sci_rx_buf+1, 6))
389 else if (my_strncmp("CHO OFF", (char*)sci_rx_buf+1, 7))
396 if (!my_strncmp("OO", (char*)sci_rx_buf+1, 2)) {
405 " /___________/___/|" CRLF
407 " | ==\\ /== | |" CRLF
408 " | O O | \\ \\ |" CRLF
411 " / | \\_____/ | / /" CRLF
413 "/||\\| | /||\\/" CRLF
414 " -------------| " CRLF
418 " ... Where's the cheese?" CRLF
424 "086 ROM " VERSION_STRING " " DATEBUILT_STRING CRLF
430 "Valid commands are:" CRLF
431 " ABOUT ROM information" CRLF
432 " B[S][nn] beep [synchronously] for a duration nn (optional)" CRLF
433 " C[S][nn] silence [synchronously] for a duration nn (optional)" CRLF
434 " Dxxxxxxxxxx show a message on the display" CRLF
435 " ECHO {ON|OFF} turn echo on or off" CRLF
436 " GETROM download the ROM source code using xmodem" CRLF
437 " H[...] this help screen" CRLF
438 " IDENTIFY report ROM version" CRLF
439 "*JUMPxxxx jumps to a subroutine at location xxxx" CRLF
440 "*PEEKxxxx returns the value of the byte at location xxxx" CRLF
441 "*POKExxxxyy sets the value of location xxxx to yy" CRLF
443 " S[...] query all internal switch states" CRLF
444 "+Vnn vend an item" CRLF
445 "+VALL vend all items" CRLF
446 "*Wxxxxxxxxxxxx set a new password for authenticated vends. xxx=16 chars" CRLF
447 " password will be converted to uppercase" CRLF
449 "Very few functions are available when the machine is in standalone " CRLF
450 "mode (DIP SW 1 is set)" CRLF
451 "+ denotes that this item requires authentication if DIP SW 2 is set" CRLF
452 "* denotes that DIP SW 3 must be set to use these" CRLF
453 "Commands starting with # are ignored (comments)" CRLF
457 extern const char _rom_src_data[];
458 extern const u16 _rom_src_len;
460 if (!my_strncmp("ETROM", (char*)sci_rx_buf+1, 5)) {
467 rom_addr = (u16)(&_rom_src_data);
469 send_string("Writing to serial port (maybe). Size is 0x");
470 send_string(u82hex(_rom_src_len >> 8));
471 send_string(u82hex(_rom_src_len & 0xff));
473 send_string(u82hex(rom_addr >> 8));
474 send_string(u82hex(rom_addr & 0xff));
475 send_string(" with signature ");
476 s[0] = _rom_src_data[0];
477 s[1] = _rom_src_data[1];
478 s[2] = _rom_src_data[2];
481 send_string(CRLF " Type YES to download rom.tar.lz via XMODEM: ");
483 while (!sci_have_packet); /* spin */
484 if (!my_strncmp("YES", (char*)sci_rx_buf, 3)) {
485 send_string(CRLF "Transfer cancelled." CRLF);
490 sci_doing_xmodem = 1;
491 if (!xmodem_init_xfer()) {
492 sci_doing_xmodem = 0;
493 send_string("XMODEM init failed. Nobody's listening :(" CRLF);
496 char *p = (char*)_rom_src_data;
497 char *end = (char*)_rom_src_data+_rom_src_len;
501 /* send partial packet */
502 if (!xmodem_send_packet((char*)p, end-p)) aborted = 1;
504 } if ((u16)p == 0xb600) {
505 /* we have an eeprom here. skip it. */
508 } else if (!xmodem_send_packet((char*)p, 128)) {
515 xmodem_finish_xfer();
516 sci_doing_xmodem = 0;
518 send_string(CRLF "Transfer aborted." CRLF);
520 send_string(CRLF "Transfer complete." CRLF);
524 if (my_strncmp("UIT", (char*)sci_rx_buf+1, 3))
525 send_string("013 You can't quit you doofus." CRLF);
532 for (i = 0; i < 11; i++)
533 display_buf[i] = ' ';
534 display_buf[10] = '\0';
536 changer_output = 0x7f;
537 _io_ports[M6811_PORTA] = 0xc0; /* display on. talking to serial port */
538 _io_ports[M6811_DDRA] = 0xfc;
539 _io_ports[M6811_DDRD] = 0x3e;
540 _io_ports[M6811_SPCR] = M6811_MSTR | M6811_SPR1;
541 set_misc_output(0x00);
547 unlock(); /* enable interrupts */
564 send_string("5N4X0RZ R US" CRLF);
566 last_standalone = is_standalone();
573 last_switch_input = switch_input;
574 last_misc_input = misc_input;
577 if (cur_motor[0] == 0xff) { /* signal to say redraw screen */
578 set_msg("*5N4X0RZ* ");
582 if (door_open() != last_door_open) {
583 last_door_open = door_open();
584 send_door_msg(last_door_open);
587 set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE");
590 if (last_standalone != is_standalone()) {
591 /* somebody flicked the standalone switch */
595 last_standalone = is_standalone();
598 if (last_misc_input != misc_input) {
600 last_misc_input = misc_input;
603 if (last_switch_input != switch_input) {
605 last_switch_input = switch_input;
608 if (sci_have_packet) {
610 switch (sci_rx_buf[0]) {
643 if (sci_rx_buf[1] == 'I')
645 else if (sci_rx_buf[1] == 'O')
647 else if (sci_rx_buf[1] == 'E')
660 dispense_something();
675 if (keypad_pressed()) {
676 if (is_standalone()) {
677 if (last_key == KEY_RESET) {
682 cur_motor[1] = last_key%10;
683 display_buf[1] = cur_motor[1]+'0';
684 set_msg(display_buf);
686 motor_num = cur_motor[0]%10;
688 motor_num += cur_motor[1];
689 switch (dispense_motor(motor_num)) {
690 case MOTOR_HOME_FAIL:
691 set_msg(" HOME FAIL ");
693 case MOTOR_CURRENT_FAIL:
694 set_msg(" OVER CRNT ");
697 set_msg("THANK YOU");
700 set_msg(" NO MOTOR ");
703 set_msg("ERRRRRRRR?");
707 display_buf[0] = ' ';
708 display_buf[1] = ' ';
712 cur_motor[0] = last_key;
713 display_buf[0] = (last_key%10)+'0';
714 set_msg(display_buf);
718 send_keypress(last_key);
723 if (coin_value != last_coin_value) {
725 last_coin_value = coin_value;