+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 (!my_strncmp("ING", (char*)sci_rx_buf+1, 3)) {
+ unknown_command();
+ return;
+ }
+ /* respond with ack & pong */
+ send_string("000 PONG!" CRLF);
+}
+
+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
+ " Revision: " VERSION_STRING " Built: " DATEBUILT_STRING CRLF "" CRLF CRLF
+ " This snack machine was brought to you by " CRLF
+ " Bernard Blackham" CRLF
+ " Harry McNally" CRLF
+ " Mark Tearle" CRLF
+ " Michal Gornisiewicz" CRLF
+ " Nick Bannon" 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 identify() {
+ send_string(
+ "086 ROM " VERSION_STRING " " DATEBUILT_STRING 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
+ " IDENTIFY report ROM version" 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];