X-Git-Url: https://git.ucc.asn.au/?p=uccvend-snackrom.git;a=blobdiff_plain;f=ROM2%2Fmain_basic.c;h=f48c2476f2ddd8eec7218d6c7dbb19af412f9f01;hp=b2923bc11c8caaadef347e31755d20d0b9fd4bab;hb=e32e95e05f80aa8a35f768af4b2b0f0aa92d362a;hpb=c34cbe163ce52f1d8fc553993701054f4942152f diff --git a/ROM2/main_basic.c b/ROM2/main_basic.c index b2923bc..f48c247 100644 --- a/ROM2/main_basic.c +++ b/ROM2/main_basic.c @@ -4,6 +4,7 @@ * and snacks. */ +#include "version.h" #include "display_basic.h" #include "keypad.h" #include "chime.h" @@ -11,40 +12,106 @@ #include "motors.h" #include "sci.h" #include "vend.h" +#include "xmodem.h" +#include "mic.h" -void motor_reply(char* slotptr, u8 code) { +u8 last_standalone; +u8 last_switch_input; +u8 last_misc_input; +u16 last_coin_value; +bool last_door_open; +char display_buf[11]; +/* cur_motor[0] is 0 for nothing, or 1..10, or 0xff to say redraw. + * cur_motor[1] is 0..9 and only meaningful is cur_motor[0] != 0. */ +u8 cur_motor[2]; + +bool check_standalone() { + if (is_standalone()) { + send_string("011 In standalone mode. Function disabled." CRLF); + return 1; + } + return 0; +} + +bool check_badpoke() { + if (cant_poke()) { + send_string("099 Can't poke without flipping DIP SW 3." CRLF); + return 1; + } + return 0; +} + +void unknown_command() { + send_string("012 Unknown command. Type HELP for help." CRLF); +} + +void motor_reply(u8 code) { /* returns a message of the form MXYY - X is return code, YY is motor */ - wait_for_tx_free(); - sci_tx_buf[0] = 'M'; - sci_tx_buf[1] = code + '0'; - sci_tx_buf[2] = *slotptr; - sci_tx_buf[3] = *(slotptr+1); - sci_tx_buf[4] = '\n'; - sci_tx_buf[5] = 0; - send_packet(); + switch (code) { + case MOTOR_SUCCESS: + send_string("100 Vend successful." CRLF); + break; + case MOTOR_NOSLOT: + send_string("151 No motor there." CRLF); + break; + case MOTOR_CURRENT_FAIL: + send_string("152 Over current." CRLF); + break; + case MOTOR_HOME_FAIL: + send_string("153 Home sensors failing." CRLF); + break; + default: + send_string("159 Unknown motor error." CRLF); + } } void dispense_something() { /* process a message VXX in sci_rx_buf where XX is motor number */ u8 slot; + if (check_standalone()) return; + if (must_verify() && !mic_verify((void*)sci_rx_buf)) { + send_string("019 Message verification failed." CRLF); + return; + } + + if (my_strncmp("ALL", (char*)sci_rx_buf+1, 3)) { + char motor[3]; + motor[2] = '\0'; + send_string("102 Vend all motors starting." CRLF); + for (motor[0] = '0'; motor[0] <= '9'; motor[0]++) { + for (motor[1] = '0'; motor[1] <= '9'; motor[1]++) { + if (motor[1] == '5') continue; /* there is now row 5 */ + send_string("101 Vending "); + send_string(motor); + send_string(CRLF); + motor_reply(dispense_motor((motor[0]-'0')*10+(motor[1]-'0'))); + } + } + send_string("102 Vend all motors complete." CRLF); + return; + } + if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') || (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9')) { sci_rx_buf[1] = sci_rx_buf[2] = '0'; - motor_reply((char*)&sci_rx_buf[1], MOTOR_NOSLOT); + motor_reply(MOTOR_NOSLOT); return; } slot = (sci_rx_buf[1] - '0') * 10; slot += sci_rx_buf[2] - '0'; - motor_reply((char*)&sci_rx_buf[1], dispense_motor(slot)); + motor_reply(dispense_motor(slot)); } void write_to_display() { - /* process a message in the form DXXXXXXXXXXX to send to display */ + /* process a message in the form DXXXXXXXXXX to send to display */ u8 i; - char buf[10]; + char buf[11]; + + if (check_standalone()) return; + for (i = 0; i < 10; i++) if (sci_rx_buf[i+1]) buf[i] = sci_rx_buf[i+1]; @@ -53,13 +120,13 @@ void write_to_display() { for (; i < 10; i++) /* pad the rest out with spaces */ buf[i] = ' '; + buf[i] = '\0'; set_msg(buf); - send_ack(); + send_string("300 Written." CRLF); } void send_balance() { - wait_for_tx_free(); sci_tx_buf[0] = 'C'; sci_tx_buf[1] = have_change?'0':'1'; sci_tx_buf[2] = (coin_value/10000)%10; @@ -67,9 +134,8 @@ void send_balance() { sci_tx_buf[4] = (coin_value/100)%10; sci_tx_buf[5] = (coin_value/10)%10; sci_tx_buf[6] = coin_value%10; - sci_tx_buf[7] = '\n'; sci_tx_buf[8] = 0; - send_packet(); + send_buffer(1); } void give_change() { @@ -80,7 +146,7 @@ void give_change() { (sci_rx_buf[3] < '0') || (sci_rx_buf[3] > '9') || (sci_rx_buf[4] < '0') || (sci_rx_buf[4] > '9') || (sci_rx_buf[5] < '0') || (sci_rx_buf[5] > '9')) { - send_nack(); + //send_nack(); } cost = sci_rx_buf[1] - '0'; cost *= 10; cost = sci_rx_buf[2] - '0'; @@ -89,61 +155,357 @@ void give_change() { cost *= 10; cost = sci_rx_buf[5] - '0'; coin_cost(cost); - send_ack(); + //send_ack(); } void send_keypress(u8 key) { /* send a packet of the form KX with X being the key, or R for reset */ - wait_for_tx_free(); - sci_tx_buf[0] = 'K'; - if (key == KEY_RESET) - sci_tx_buf[1] = 'R'; - else - sci_tx_buf[1] = (key%10)+'0'; - sci_tx_buf[2] = '\n'; - sci_tx_buf[3] = 0; - send_packet(); + if (is_standalone()) return; + + sci_tx_buf[0] = '2'; + if (key == KEY_RESET) { + sci_tx_buf[1] = '1'; + sci_tx_buf[2] = '1'; + } else { + sci_tx_buf[1] = '0'; + sci_tx_buf[2] = (key%10)+'0'; + } + sci_tx_buf[3] = '\0'; + send_buffer(0); + send_string(" key." CRLF); } void send_door_msg(bool open) { - wait_for_tx_free(); - sci_tx_buf[0] = 'D'; - sci_tx_buf[1] = open?'1':'0'; - sci_tx_buf[2] = '\n'; - sci_tx_buf[3] = 0; - send_packet(); + if (is_standalone()) return; + sci_tx_buf[0] = '4'; + sci_tx_buf[1] = '0'; + sci_tx_buf[2] = open?'1':'0'; + send_buffer(0); + if (open) + send_string(" door open." CRLF); + else + send_string(" door closed." CRLF); } void do_chime() { - chime_start(); - send_ack(); + if (check_standalone()) return; + if (sci_rx_buf[1] == '\0') + chime_start(); + else if (sci_rx_buf[1] == 'S') { /* synchronous beep */ + if (sci_rx_buf[2] == '\0') + chime_start(); + else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0') + chime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3])); + else { + send_string("510 Unknown chime duration." CRLF); + return; + } + while (chime_count); /* spin */ + send_string("500 Chimed." CRLF); + return; + } else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0') + chime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2])); + else { + send_string("510 Unknown chime duration." CRLF); + return; + } + send_string("500 Chime started." CRLF); + return; +} + +void do_silence() { + if (check_standalone()) return; + if (sci_rx_buf[1] == '\0') + unchime_start(); + else if (sci_rx_buf[1] == 'S') { /* synchronous beep */ + if (sci_rx_buf[2] == '\0') + unchime_start(); + else if (sci_rx_buf[3] != '\0' && sci_rx_buf[4] == '\0') + unchime_for(hex2u8(sci_rx_buf[2], sci_rx_buf[3])); + else { + send_string("511 Unknown silence duration." CRLF); + return; + } + while (unchime_count); /* spin */ + send_string("501 Silenced." CRLF); + return; + } else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0') + unchime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2])); + else { + send_string("511 Unknown silence duration." CRLF); + return; + } + send_string("501 Silence started." CRLF); + return; +} + +void print_switches(u8 prompted) { + if (prompted) + send_string("600 "); + else + send_string("610 "); + send_string(u82hex(misc_input)); + send_string(" "); + send_string(u82hex(switch_input)); + send_string(CRLF); } void ping_pong() { /* make sure it's really a ping */ - if (sci_rx_buf[1] != 'I' || - sci_rx_buf[2] != 'N' || - sci_rx_buf[3] != 'G') { - send_nack(); + if (!my_strncmp("ING", (char*)sci_rx_buf+1, 3)) { + unknown_command(); return; } /* respond with ack & pong */ - wait_for_tx_free(); - sci_tx_buf[0] = 'P'; - sci_tx_buf[1] = 'O'; - sci_tx_buf[2] = 'N'; - sci_tx_buf[3] = 'G'; - sci_tx_buf[4] = '\n'; - sci_tx_buf[5] = 0; - send_packet(); + send_string("000 PONG!" CRLF); } -u16 last_coin_value; -bool last_door_open; -char display_buf[11]; -/* cur_motor[0] is 0 for nothing, or 1..10, or 0xff to say redraw. - * cur_motor[1] is 0..9 and only meaningful is cur_motor[0] != 0. */ -u8 cur_motor[2]; +u16 hex2addr(char* addrptr) { + u16 v; + v = hex2u8(addrptr[0], addrptr[1]) << 8; + v |= hex2u8(addrptr[2], addrptr[3]); + return v; +} + +void peek() { + if (!my_strncmp("EEK", (char*)sci_rx_buf+1, 3)) { + unknown_command(); + return; + } + if (check_badpoke()) return; + if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) && + ishex(sci_rx_buf[7]) && sci_rx_buf[8] == '\0') { + u16 v = hex2addr((char*)(sci_rx_buf+4)); + v = *((u8*)v); + send_string("090 "); + send_string(u82hex(v)); + send_string(CRLF); + return; + } + send_string("091 Invalid location given." CRLF); +} + +void poke() { + if (!my_strncmp("OKE", (char*)sci_rx_buf+1, 3)) { + unknown_command(); + return; + } + if (check_badpoke()) return; + if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) && + ishex(sci_rx_buf[7]) && ishex(sci_rx_buf[8]) && ishex(sci_rx_buf[9]) + && sci_rx_buf[10] == '\0') { + u16 v; + v = hex2addr((char*)(sci_rx_buf+4)); + *(u8*)v = hex2u8(sci_rx_buf[8], sci_rx_buf[9]); + send_string("080 Written." CRLF); + return; + } + send_string("081 Invalid location or byte given." CRLF); +} + +void jump() { + if (!my_strncmp("UMP", (char*)sci_rx_buf+1, 3)) { + unknown_command(); + return; + } + if (check_badpoke()) return; + if (ishex(sci_rx_buf[4]) && ishex(sci_rx_buf[5]) && ishex(sci_rx_buf[6]) && + ishex(sci_rx_buf[7]) && sci_rx_buf[8] == '\0') { + u16 v = hex2addr((char*)(sci_rx_buf+4)); + send_string("070 Jumping now." CRLF); + asm volatile ("jsr %0" : : "m"(*(u16*)v) : "d"); + send_string("071 And back." CRLF); + return; + } + send_string("079 Invalid location given." CRLF); +} + +void do_set_password() { + u8 i; + bool good = 1; + if (check_badpoke()) return; + for (i=1; i < 17; i++) { + if (sci_rx_buf[i] == '\0') { + good = 0; + break; + } + } + if (good && sci_rx_buf[17] != '\0') good = 0; + if (!good) { + send_string("061 Password must be exactly 16 characters." CRLF); + return; + } + + mic_set_secret((char*)(sci_rx_buf+1)); + send_string("060 Password has been set." CRLF); +} + +void send_prompt() { + if (must_verify()) { + send_string(u82hex(mic_challenge >> 8)); + send_string(u82hex(mic_challenge & 0xff)); + } + send_string(is_standalone()?"% ":"# "); +} + +void about() { + if (!my_strncmp("BOUT", (char*)sci_rx_buf+1, 4)) { + unknown_command(); + return; + } + send_string( + "-----------------------------------------------------------------" CRLF + " ROM2 (C) 2004 Bernard Blackham " CRLF + "-----------------------------------------------------------------" CRLF + " Revision " VERSION_STRING CRLF + "" CRLF + " This snack machine was brought to you by " CRLF + " Bernard Blackham" CRLF + " Mark Tearle" CRLF + " Harry McNally" CRLF + " Michal Gornisiewicz" CRLF + " and others." CRLF + "" CRLF + " Another UCC project in action. http://www.ucc.asn.au/" CRLF + ); +} + +void set_echo() { + if (my_strncmp("CHO ON", (char*)sci_rx_buf+1, 6)) + sci_echo = 1; + else if (my_strncmp("CHO OFF", (char*)sci_rx_buf+1, 7)) + sci_echo = 0; + else + unknown_command(); +} + +void moo() { + if (!my_strncmp("OO", (char*)sci_rx_buf+1, 2)) { + unknown_command(); + return; + } + send_string( +" ____________" CRLF +" |__________|" CRLF +" / /\\" CRLF +" / U C C / \\" CRLF +" /___________/___/|" CRLF +" | | |" CRLF +" | ==\\ /== | |" CRLF +" | O O | \\ \\ |" CRLF +" | < | \\ \\|" CRLF +" /| | \\ \\" CRLF +" / | \\_____/ | / /" CRLF +" / /| | / /|" CRLF +"/||\\| | /||\\/" CRLF +" -------------| " CRLF +" | | | | " CRLF +" <__/ \\__>" CRLF +"" CRLF +" ... Where's the cheese?" CRLF + ); +} + +void help() { + send_string( + "Valid commands are:" CRLF + " ABOUT ROM information" CRLF + " B[S][nn] beep [synchronously] for a duration nn (optional)" CRLF + " C[S][nn] silence [synchronously] for a duration nn (optional)" CRLF + " Dxxxxxxxxxx show a message on the display" CRLF + " ECHO {ON|OFF} turn echo on or off" CRLF + " GETROM download the ROM source code using xmodem" CRLF + " H[...] this help screen" CRLF + "*JUMPxxxx jumps to a subroutine at location xxxx" CRLF + "*PEEKxxxx returns the value of the byte at location xxxx" CRLF + "*POKExxxxyy sets the value of location xxxx to yy" CRLF + " PING pongs" CRLF + " S[...] query all internal switch states" CRLF + "+Vnn vend an item" CRLF + "+VALL vend all items" CRLF + "*Wxxxxxxxxxxxx set a new password for authenticated vends. xxx=16 chars" CRLF + " password will be converted to uppercase" CRLF + "" CRLF + "Very few functions are available when the machine is in standalone " CRLF + "mode (DIP SW 1 is set)" CRLF + "+ denotes that this item requires authentication if DIP SW 2 is set" CRLF + "* denotes that DIP SW 3 must be set to use these" CRLF + "Commands starting with # are ignored (comments)" CRLF + ); +} + +extern const char _rom_src_data[]; +extern const u16 _rom_src_len; +void getrom() { + if (!my_strncmp("ETROM", (char*)sci_rx_buf+1, 5)) { + unknown_command(); + return; + } + char s[4]; + + u16 rom_addr; + rom_addr = (u16)(&_rom_src_data); + + send_string("Writing to serial port (maybe). Size is 0x"); + send_string(u82hex(_rom_src_len >> 8)); + send_string(u82hex(_rom_src_len & 0xff)); + send_string("@0x"); + send_string(u82hex(rom_addr >> 8)); + send_string(u82hex(rom_addr & 0xff)); + send_string(" with signature "); + s[0] = _rom_src_data[0]; + s[1] = _rom_src_data[1]; + s[2] = _rom_src_data[2]; + s[3] = '\0'; + send_string(s); + send_string(CRLF " Type YES to download rom.tar.bz2 via XMODEM: "); + msg_clr(); + while (!sci_have_packet); /* spin */ + if (!my_strncmp("YES", (char*)sci_rx_buf, 3)) { + send_string(CRLF "Transfer cancelled." CRLF); + return; + } + + sci_init(); + sci_doing_xmodem = 1; + if (!xmodem_init_xfer()) { + sci_doing_xmodem = 0; + send_string("XMODEM init failed. Nobody's listening :(" CRLF); + return; + } + char *p = (char*)_rom_src_data; + char *end = (char*)_rom_src_data+_rom_src_len; + bool aborted = 0; + while (1) { + if (p + 128 > end) { + /* send partial packet */ + if (!xmodem_send_packet((char*)p, end-p)) aborted = 1; + break; + } if ((u16)p == 0xb600) { + /* we have an eeprom here. skip it. */ + p += 0x0200; + continue; + } else if (!xmodem_send_packet((char*)p, 128)) { + aborted = 1; + break; + } + p += 128; + } + + xmodem_finish_xfer(); + sci_doing_xmodem = 0; + if (aborted) + send_string(CRLF "Transfer aborted." CRLF); + else + send_string(CRLF "Transfer complete." CRLF); +} + +void quit() { + if (my_strncmp("UIT", (char*)sci_rx_buf+1, 3)) + send_string("013 You can't quit you doofus." CRLF); + else + unknown_command(); +} int main() { u8 i; @@ -155,15 +517,17 @@ int main() { _io_ports[M6811_PORTA] = 0xc0; /* display on. talking to serial port */ _io_ports[M6811_DDRA] = 0xfc; _io_ports[M6811_DDRD] = 0x3e; - _io_ports[M6811_SPCR] = 0x12; + _io_ports[M6811_SPCR] = M6811_MSTR | M6811_SPR1; set_misc_output(0x00); - + display_init(); set_msg(" HELLO "); + delay(1000); unlock(); /* enable interrupts */ - //comm_init(); + set_msg(" CRUEL "); + //coinmech_init(); sci_init(); keypad_init(); @@ -172,16 +536,23 @@ int main() { delay(1000); - set_msg(" CRUEL "); - - delay(1000); - set_msg(" WORLD "); delay(1000); chime_start(); - cur_motor[0] = 0xff; + send_string("5N4X0RZ R US" CRLF); + + last_standalone = is_standalone(); + if (last_standalone) + cur_motor[0] = 0xff; + else + cur_motor[0] = 0; + send_prompt(); + + last_switch_input = switch_input; + last_misc_input = misc_input; + while(1) { if (cur_motor[0] == 0xff) { /* signal to say redraw screen */ set_msg("*5N4X0RZ* "); @@ -192,84 +563,136 @@ int main() { last_door_open = door_open(); send_door_msg(last_door_open); chime_start(); - if (last_door_open) { - set_msg("DOOR OPEND"); - } else { - set_msg("DOOR CLOSE"); - } + if (is_standalone()) + set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE"); + } + + if (last_standalone != is_standalone()) { + /* somebody flicked the standalone switch */ + msg_clr(); + send_string(CRLF); + send_prompt(); + last_standalone = is_standalone(); + } + + if (last_misc_input != misc_input) { + print_switches(0); + last_misc_input = misc_input; + } + + if (last_switch_input != switch_input) { + print_switches(0); + last_switch_input = switch_input; } if (sci_have_packet) { + send_string(CRLF); switch (sci_rx_buf[0]) { - case 'V': - dispense_something(); + case '\0': + case '#': + send_string(CRLF); break; - case 'D': - write_to_display(); + case 'A': + about(); break; case 'B': do_chime(); break; - case 'U': - send_balance(); + case 'C': + do_silence(); + break; + case 'D': + write_to_display(); + break; + case 'E': + set_echo(); break; case 'G': - give_change(); + getrom(); + break; + case 'H': + help(); + break; + case 'M': + moo(); break; case 'P': - ping_pong(); + if (sci_rx_buf[1] == 'I') + ping_pong(); + else if (sci_rx_buf[1] == 'O') + poke(); + else if (sci_rx_buf[1] == 'E') + peek(); + break; + case 'J': + jump(); + break; + case 'Q': + quit(); + break; + case 'S': + print_switches(1); + break; + case 'V': + dispense_something(); + break; + case 'W': + do_set_password(); break; default: // shurg - send_nack(); + unknown_command(); break; } msg_clr(); + send_prompt(); } keypad_read(); if (keypad_pressed()) { - if (last_key == KEY_RESET) { - cur_motor[0] = 0xff; - } else { - if (cur_motor[0]) { - u8 motor_num; - cur_motor[1] = last_key%10; - display_buf[1] = cur_motor[1]+'0'; - set_msg(display_buf); - - motor_num = cur_motor[0]%10; - motor_num *= 10; - motor_num += cur_motor[1]; - switch (dispense_motor(motor_num)) { - case MOTOR_HOME_FAIL: - set_msg(" HOME FAIL "); - break; - case MOTOR_CURRENT_FAIL: - set_msg(" OVER CRNT "); - break; - case MOTOR_SUCCESS: - set_msg("THANK YOU"); - break; - case MOTOR_NOSLOT: - set_msg(" NO MOTOR "); - break; - default: - set_msg("ERRRRRRRR?"); - break; - } - - display_buf[0] = ' '; - display_buf[1] = ' '; + if (is_standalone()) { + if (last_key == KEY_RESET) { cur_motor[0] = 0xff; - delay(500); } else { - cur_motor[0] = last_key; - display_buf[0] = (last_key%10)+'0'; - set_msg(display_buf); + if (cur_motor[0]) { + u8 motor_num; + cur_motor[1] = last_key%10; + display_buf[1] = cur_motor[1]+'0'; + set_msg(display_buf); + + motor_num = cur_motor[0]%10; + motor_num *= 10; + motor_num += cur_motor[1]; + switch (dispense_motor(motor_num)) { + case MOTOR_HOME_FAIL: + set_msg(" HOME FAIL "); + break; + case MOTOR_CURRENT_FAIL: + set_msg(" OVER CRNT "); + break; + case MOTOR_SUCCESS: + set_msg("THANK YOU"); + break; + case MOTOR_NOSLOT: + set_msg(" NO MOTOR "); + break; + default: + set_msg("ERRRRRRRR?"); + break; + } + + display_buf[0] = ' '; + display_buf[1] = ' '; + cur_motor[0] = 0xff; + delay(500); + } else { + cur_motor[0] = last_key; + display_buf[0] = (last_key%10)+'0'; + set_msg(display_buf); + } } - } - send_keypress(last_key); + } else + send_keypress(last_key); } /*