Abstract Version out into header file and bump version
[uccvend-snackrom.git] / ROM2 / main_basic.c
index f6a5b9f..f48c247 100644 (file)
@@ -4,8 +4,7 @@
  * and snacks.
  */
 
-#define VERSION_STRING "R 20040622"
-
+#include "version.h"
 #include "display_basic.h"
 #include "keypad.h"
 #include "chime.h"
@@ -14,7 +13,7 @@
 #include "sci.h"
 #include "vend.h"
 #include "xmodem.h"
-#include "sha1.h"
+#include "mic.h"
 
 u8 last_standalone;
 u8 last_switch_input;
@@ -34,6 +33,14 @@ bool check_standalone() {
        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);
 }
@@ -63,6 +70,10 @@ void dispense_something() {
        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];
@@ -70,10 +81,11 @@ void dispense_something() {
                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]*10+motor[1]));
+                               motor_reply(dispense_motor((motor[0]-'0')*10+(motor[1]-'0')));
                        }
                }
                send_string("102 Vend all motors complete." CRLF);
@@ -134,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';
@@ -143,7 +155,7 @@ void give_change() {
        cost *= 10; cost = sci_rx_buf[5] - '0';
 
        coin_cost(cost);
-       send_ack();
+       //send_ack();
 } 
 
 void send_keypress(u8 key) {
@@ -175,42 +187,56 @@ void send_door_msg(bool open) {
                send_string(" door closed." CRLF);
 }
 
-u8 hexchar2u8(char b) {
-       if (b >= '0' && b <= '9') return b-'0';
-       if (b >= 'a' && b <= 'f') return b-'a'+0x0a;
-       if (b >= 'A' && b <= 'F') return b-'A'+0x0a;
-       return 0;
-}
-
-char nibble2hexchar(u8 b) {
-       if (b <= 9) return b+'0';
-       if (b >= 10 && b <= 15) return b+'A'-10;
-       return 'X';
-}
-
-u8 hex2u8(char msb, char lsb) {
-       return (hexchar2u8(msb) << 4) + hexchar2u8(lsb);
-}
-
-static char hexconv_buf[3];
-char* u82hex(u8 a) {
-       hexconv_buf[0] = nibble2hexchar((a&0xf0) >> 4);
-       hexconv_buf[1] = nibble2hexchar(a&0x0f);
-       hexconv_buf[2] = '\0';
-       return hexconv_buf;
-}
-
 void do_chime() {
        if (check_standalone()) return;
        if (sci_rx_buf[1] == '\0')
                chime_start();
-       else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
+       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 Chimed." CRLF);
+       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) {
@@ -234,8 +260,92 @@ void ping_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() {
-       send_string(is_standalone()?"$ ":"# ");
+       if (must_verify()) {
+               send_string(u82hex(mic_challenge >> 8));
+               send_string(u82hex(mic_challenge & 0xff));
+       }
+       send_string(is_standalone()?"% ":"# ");
 }
 
 void about() {
@@ -300,16 +410,27 @@ void help() {
        send_string(
                "Valid commands are:" CRLF
                " ABOUT         ROM information" CRLF
-               " PING          pongs" 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
-               " Vnn           vend an item" CRLF
-               " VALL          vend all items" CRLF
-               " DXXXXXXXXXX   show a message on the display" CRLF
-               " B[nn]         beep for a duration nn (optional)" CRLF
-               " S[...]        query all internal switch states" CRLF
-               " H[...]        this help screen" CRLF
                " GETROM        download the ROM source code using xmodem" CRLF
-               "Comments start with a #" 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
        );
 }
 
@@ -321,9 +442,16 @@ void getrom() {
                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];
@@ -333,7 +461,10 @@ void getrom() {
        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)) return;
+       if (!my_strncmp("YES", (char*)sci_rx_buf, 3)) {
+               send_string(CRLF "Transfer cancelled." CRLF);
+               return;
+       }
 
        sci_init();
        sci_doing_xmodem = 1;
@@ -346,16 +477,19 @@ void getrom() {
        char *end = (char*)_rom_src_data+_rom_src_len;
        bool aborted = 0;
        while (1) {
-               if (!xmodem_send_packet((char*)p, 128)) {
-                       aborted = 1;
-                       break;
-               }
-               p += 128;
                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();
@@ -373,9 +507,6 @@ void quit() {
                unknown_command();
 }
 
-//SHA1_CTX ctx;
-//u8 sha1_digest[SHA1_SIGNATURE_SIZE];
-
 int main() {
        u8 i;
        for (i = 0; i < 11; i++)
@@ -397,7 +528,6 @@ int main() {
 
        set_msg("  CRUEL   ");
 
-       //comm_init();
        //coinmech_init();
        sci_init();
        keypad_init();
@@ -412,7 +542,7 @@ int main() {
        chime_start();
 
        send_string("5N4X0RZ R US" CRLF);
-       
+
        last_standalone = is_standalone();
        if (last_standalone)
                cur_motor[0] = 0xff;
@@ -433,7 +563,8 @@ int main() {
                        last_door_open = door_open();
                        send_door_msg(last_door_open);
                        chime_start();
-                       set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE");
+                       if (is_standalone())
+                               set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE");
                }
 
                if (last_standalone != is_standalone()) {
@@ -455,48 +586,58 @@ int main() {
                }
 
                if (sci_have_packet) {
-                       if (must_verify()) {
-                               //SHA1_Init(&ctx);
-                               //SHA1_Update(&ctx, sci_rx_buf, my_strlen(sci_rx_buf));
-                               //SHA1_Final(sha1_digest, &ctx);
-                       }
+                       send_string(CRLF);
                        switch (sci_rx_buf[0]) {
                                case '\0':
                                case '#':
                                        send_string(CRLF);
                                        break;
-                               case 'E':
-                                       set_echo();
+                               case 'A':
+                                       about();
                                        break;
-                               case 'H':
-                                       help();
+                               case 'B': 
+                                       do_chime();
                                        break;
-                               case 'V':
-                                       dispense_something();
+                               case 'C': 
+                                       do_silence();
                                        break;
                                case 'D':
                                        write_to_display();
                                        break;
-                               case 'B': 
-                                       do_chime();
-                                       break;
-                               case 'P':
-                                       ping_pong();
+                               case 'E':
+                                       set_echo();
                                        break;
-                               case 'A':
-                                       about();
+                               case 'G':
+                                       getrom();
                                        break;
-                               case 'S':
-                                       print_switches(1);
+                               case 'H':
+                                       help();
                                        break;
                                case 'M':
                                        moo();
                                        break;
+                               case 'P':
+                                       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 'G':
-                                       getrom();
+                               case 'S':
+                                       print_switches(1);
+                                       break;
+                               case 'V':
+                                       dispense_something();
+                                       break;
+                               case 'W':
+                                       do_set_password();
                                        break;
                                default:
                                        // shurg

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