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
7 #define VERSION_STRING "X 20040625"
9 #include "display_basic.h"
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. */
29 bool check_standalone() {
30 if (is_standalone()) {
31 send_string("011 In standalone mode. Function disabled." CRLF);
37 bool check_badpoke() {
39 send_string("099 Can't poke without flipping DIP SW 3." CRLF);
45 void unknown_command() {
46 send_string("012 Unknown command. Type HELP for help." CRLF);
49 void motor_reply(u8 code) {
50 /* returns a message of the form MXYY - X is return code, YY is motor */
53 send_string("100 Vend successful." CRLF);
56 send_string("151 No motor there." CRLF);
58 case MOTOR_CURRENT_FAIL:
59 send_string("152 Over current." CRLF);
62 send_string("153 Home sensors failing." CRLF);
65 send_string("159 Unknown motor error." CRLF);
69 void dispense_something() {
70 /* process a message VXX in sci_rx_buf where XX is motor number */
73 if (check_standalone()) return;
74 if (must_verify() && !mic_verify((void*)sci_rx_buf)) {
75 send_string("019 Message verification failed." CRLF);
79 if (my_strncmp("ALL", (char*)sci_rx_buf+1, 3)) {
82 send_string("102 Vend all motors starting." CRLF);
83 for (motor[0] = '0'; motor[0] <= '9'; motor[0]++) {
84 for (motor[1] = '0'; motor[1] <= '9'; motor[1]++) {
85 if (motor[1] == '5') continue; /* there is now row 5 */
86 send_string("101 Vending ");
89 motor_reply(dispense_motor((motor[0]-'0')*10+(motor[1]-'0')));
92 send_string("102 Vend all motors complete." CRLF);
96 if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
97 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9')) {
98 sci_rx_buf[1] = sci_rx_buf[2] = '0';
99 motor_reply(MOTOR_NOSLOT);
103 slot = (sci_rx_buf[1] - '0') * 10;
104 slot += sci_rx_buf[2] - '0';
106 motor_reply(dispense_motor(slot));
109 void write_to_display() {
110 /* process a message in the form DXXXXXXXXXX to send to display */
114 if (check_standalone()) return;
116 for (i = 0; i < 10; i++)
118 buf[i] = sci_rx_buf[i+1];
122 for (; i < 10; i++) /* pad the rest out with spaces */
127 send_string("300 Written." CRLF);
130 void send_balance() {
132 sci_tx_buf[1] = have_change?'0':'1';
133 sci_tx_buf[2] = (coin_value/10000)%10;
134 sci_tx_buf[3] = (coin_value/1000)%10;
135 sci_tx_buf[4] = (coin_value/100)%10;
136 sci_tx_buf[5] = (coin_value/10)%10;
137 sci_tx_buf[6] = coin_value%10;
145 if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
146 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9') ||
147 (sci_rx_buf[3] < '0') || (sci_rx_buf[3] > '9') ||
148 (sci_rx_buf[4] < '0') || (sci_rx_buf[4] > '9') ||
149 (sci_rx_buf[5] < '0') || (sci_rx_buf[5] > '9')) {
152 cost = sci_rx_buf[1] - '0';
153 cost *= 10; cost = sci_rx_buf[2] - '0';
154 cost *= 10; cost = sci_rx_buf[3] - '0';
155 cost *= 10; cost = sci_rx_buf[4] - '0';
156 cost *= 10; cost = sci_rx_buf[5] - '0';
162 void send_keypress(u8 key) {
163 /* send a packet of the form KX with X being the key, or R for reset */
164 if (is_standalone()) return;
167 if (key == KEY_RESET) {
172 sci_tx_buf[2] = (key%10)+'0';
174 sci_tx_buf[3] = '\0';
176 send_string(" key." CRLF);
179 void send_door_msg(bool open) {
180 if (is_standalone()) return;
183 sci_tx_buf[2] = open?'1':'0';
186 send_string(" door open." CRLF);
188 send_string(" door closed." CRLF);
192 if (check_standalone()) return;
193 if (sci_rx_buf[1] == '\0')
195 else if (sci_rx_buf[1] == 'S') { /* synchronous beep */
196 if (sci_rx_buf[2] == '\0')
198 else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0')
199 chime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3]));
201 send_string("510 Unknown chime duration." CRLF);
204 while (chime_count); /* spin */
205 send_string("500 Chimed." CRLF);
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]));
210 send_string("510 Unknown chime duration." CRLF);
213 send_string("500 Chime started." CRLF);
218 if (check_standalone()) return;
219 if (sci_rx_buf[1] == '\0')
221 else if (sci_rx_buf[1] == 'S') { /* synchronous beep */
222 if (sci_rx_buf[2] == '\0')
224 else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0')
225 unchime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3]));
227 send_string("511 Unknown silence duration." CRLF);
230 while (unchime_count); /* spin */
231 send_string("501 Silenced." CRLF);
233 } else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
234 unchime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
236 send_string("511 Unknown silence duration." CRLF);
239 send_string("501 Silence started." CRLF);
243 void print_switches(u8 prompted) {
248 send_string(u82hex(misc_input));
250 send_string(u82hex(switch_input));
255 /* make sure it's really a ping */
256 if (!my_strncmp("ING", (char*)sci_rx_buf+1, 3)) {
260 /* respond with ack & pong */
261 send_string("000 PONG!" CRLF);
264 u16 hex2addr(char* addrptr) {
266 v = hex2u8(addrptr[0], addrptr[1]) << 8;
267 v |= hex2u8(addrptr[2], addrptr[3]);
272 if (!my_strncmp("EEK", (char*)sci_rx_buf+1, 3)) {
276 if (check_badpoke()) return;
277 if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) &&
278 ishex(sci_rx_buf[7]) && sci_rx_buf[8] == '\0') {
279 u16 v = hex2addr((char*)(sci_rx_buf+4));
282 send_string(u82hex(v));
286 send_string("091 Invalid location given." CRLF);
290 if (!my_strncmp("OKE", (char*)sci_rx_buf+1, 3)) {
294 if (check_badpoke()) return;
295 if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) &&
296 ishex(sci_rx_buf[7]) && ishex(sci_rx_buf[8]) && ishex(sci_rx_buf[9])
297 && sci_rx_buf[10] == '\0') {
299 v = hex2addr((char*)(sci_rx_buf+4));
300 *(u8*)v = hex2u8(sci_rx_buf[8], sci_rx_buf[9]);
301 send_string("080 Written." CRLF);
304 send_string("081 Invalid location or byte given." CRLF);
308 if (!my_strncmp("UMP", (char*)sci_rx_buf+1, 3)) {
312 if (check_badpoke()) return;
313 if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) &&
314 ishex(sci_rx_buf[7]) && sci_rx_buf[8] == '\0') {
315 u16 v = hex2addr((char*)(sci_rx_buf+4));
316 send_string("070 Jumping now." CRLF);
317 asm volatile ("jsr %0" : : "m"(*(u16*)v) : "d");
318 send_string("071 And back." CRLF);
321 send_string("079 Invalid location given." CRLF);
324 void do_set_password() {
327 if (check_badpoke()) return;
328 for (i=1; i < 17; i++) {
329 if (sci_rx_buf[i] == '\0') {
334 if (good && sci_rx_buf[17] != '\0') good = 0;
336 send_string("061 Password must be exactly 16 characters." CRLF);
340 mic_set_secret((char*)(sci_rx_buf+1));
341 send_string("060 Password has been set." CRLF);
346 send_string(u82hex(mic_challenge >> 8));
347 send_string(u82hex(mic_challenge & 0xff));
349 send_string(is_standalone()?"% ":"# ");
353 if (!my_strncmp("BOUT", (char*)sci_rx_buf+1, 4)) {
358 "-----------------------------------------------------------------" CRLF
360 "-----------------------------------------------------------------" CRLF
361 " Revision " VERSION_STRING CRLF
363 " This snack machine was brought to you by " CRLF
364 " Bernard Blackham" CRLF
366 " Harry McNally" CRLF
367 " Michal Gornisiewicz" CRLF
370 " Another UCC project in action. http://www.ucc.asn.au/" CRLF
375 if (my_strncmp("CHO ON", (char*)sci_rx_buf+1, 6))
377 else if (my_strncmp("CHO OFF", (char*)sci_rx_buf+1, 7))
384 if (!my_strncmp("OO", (char*)sci_rx_buf+1, 2)) {
393 " /___________/___/|" CRLF
395 " | ==\\ /== | |" CRLF
396 " | O O | \\ \\ |" CRLF
399 " / | \\_____/ | / /" CRLF
401 "/||\\| | /||\\/" CRLF
402 " -------------| " CRLF
406 " ... Where's the cheese?" CRLF
412 "Valid commands are:" CRLF
413 " ABOUT ROM information" CRLF
414 " B[S][nn] beep [synchronously] for a duration nn (optional)" CRLF
415 " C[S][nn] silence [synchronously] for a duration nn (optional)" CRLF
416 " Dxxxxxxxxxx show a message on the display" CRLF
417 " ECHO {ON|OFF} turn echo on or off" CRLF
418 " GETROM download the ROM source code using xmodem" CRLF
419 " H[...] this help screen" CRLF
420 "*JUMPxxxx jumps to a subroutine at location xxxx" CRLF
421 "*PEEKxxxx returns the value of the byte at location xxxx" CRLF
422 "*POKExxxxyy sets the value of location xxxx to yy" CRLF
424 " S[...] query all internal switch states" CRLF
425 "+Vnn vend an item" CRLF
426 "+VALL vend all items" CRLF
427 "*Wxxxxxxxxxxxx set a new password for authenticated vends. xxx=16 chars" CRLF
428 " password will be converted to uppercase" CRLF
430 "Very few functions are available when the machine is in standalone " CRLF
431 "mode (DIP SW 1 is set)" CRLF
432 "+ denotes that this item requires authentication if DIP SW 2 is set" CRLF
433 "* denotes that DIP SW 3 must be set to use these" CRLF
434 "Commands starting with # are ignored (comments)" CRLF
438 extern const char _rom_src_data[];
439 extern const u16 _rom_src_len;
441 if (!my_strncmp("ETROM", (char*)sci_rx_buf+1, 5)) {
448 rom_addr = (u16)(&_rom_src_data);
450 send_string("Writing to serial port (maybe). Size is 0x");
451 send_string(u82hex(_rom_src_len >> 8));
452 send_string(u82hex(_rom_src_len & 0xff));
454 send_string(u82hex(rom_addr >> 8));
455 send_string(u82hex(rom_addr & 0xff));
456 send_string(" with signature ");
457 s[0] = _rom_src_data[0];
458 s[1] = _rom_src_data[1];
459 s[2] = _rom_src_data[2];
462 send_string(CRLF " Type YES to download rom.tar.bz2 via XMODEM: ");
464 while (!sci_have_packet); /* spin */
465 if (!my_strncmp("YES", (char*)sci_rx_buf, 3)) {
466 send_string(CRLF "Transfer cancelled." CRLF);
471 sci_doing_xmodem = 1;
472 if (!xmodem_init_xfer()) {
473 sci_doing_xmodem = 0;
474 send_string("XMODEM init failed. Nobody's listening :(" CRLF);
477 char *p = (char*)_rom_src_data;
478 char *end = (char*)_rom_src_data+_rom_src_len;
482 /* send partial packet */
483 if (!xmodem_send_packet((char*)p, end-p)) aborted = 1;
485 } if ((u16)p == 0xb600) {
486 /* we have an eeprom here. skip it. */
489 } else if (!xmodem_send_packet((char*)p, 128)) {
496 xmodem_finish_xfer();
497 sci_doing_xmodem = 0;
499 send_string(CRLF "Transfer aborted." CRLF);
501 send_string(CRLF "Transfer complete." CRLF);
505 if (my_strncmp("UIT", (char*)sci_rx_buf+1, 3))
506 send_string("013 You can't quit you doofus." CRLF);
513 for (i = 0; i < 11; i++)
514 display_buf[i] = ' ';
515 display_buf[10] = '\0';
517 changer_output = 0x7f;
518 _io_ports[M6811_PORTA] = 0xc0; /* display on. talking to serial port */
519 _io_ports[M6811_DDRA] = 0xfc;
520 _io_ports[M6811_DDRD] = 0x3e;
521 _io_ports[M6811_SPCR] = M6811_MSTR | M6811_SPR1;
522 set_misc_output(0x00);
528 unlock(); /* enable interrupts */
545 send_string("5N4X0RZ R US" CRLF);
547 last_standalone = is_standalone();
554 last_switch_input = switch_input;
555 last_misc_input = misc_input;
558 if (cur_motor[0] == 0xff) { /* signal to say redraw screen */
559 set_msg("*5N4X0RZ* ");
563 if (door_open() != last_door_open) {
564 last_door_open = door_open();
565 send_door_msg(last_door_open);
568 set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE");
571 if (last_standalone != is_standalone()) {
572 /* somebody flicked the standalone switch */
576 last_standalone = is_standalone();
579 if (last_misc_input != misc_input) {
581 last_misc_input = misc_input;
584 if (last_switch_input != switch_input) {
586 last_switch_input = switch_input;
589 if (sci_have_packet) {
591 switch (sci_rx_buf[0]) {
621 if (sci_rx_buf[1] == 'I')
623 else if (sci_rx_buf[1] == 'O')
625 else if (sci_rx_buf[1] == 'E')
638 dispense_something();
653 if (keypad_pressed()) {
654 if (is_standalone()) {
655 if (last_key == KEY_RESET) {
660 cur_motor[1] = last_key%10;
661 display_buf[1] = cur_motor[1]+'0';
662 set_msg(display_buf);
664 motor_num = cur_motor[0]%10;
666 motor_num += cur_motor[1];
667 switch (dispense_motor(motor_num)) {
668 case MOTOR_HOME_FAIL:
669 set_msg(" HOME FAIL ");
671 case MOTOR_CURRENT_FAIL:
672 set_msg(" OVER CRNT ");
675 set_msg("THANK YOU");
678 set_msg(" NO MOTOR ");
681 set_msg("ERRRRRRRR?");
685 display_buf[0] = ' ';
686 display_buf[1] = ' ';
690 cur_motor[0] = last_key;
691 display_buf[0] = (last_key%10)+'0';
692 set_msg(display_buf);
696 send_keypress(last_key);
700 if (coin_value != last_coin_value) {
702 last_coin_value = coin_value;