* and snacks.
*/
-#define VERSION_STRING "R 20040622"
+#define VERSION_STRING "V 20040624"
#include "display_basic.h"
#include "keypad.h"
#include "sci.h"
#include "vend.h"
#include "xmodem.h"
-//#include "sha1.h"
+#include "mic.h"
u8 last_standalone;
u8 last_switch_input;
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);
}
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];
(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';
cost *= 10; cost = sci_rx_buf[5] - '0';
coin_cost(cost);
- send_ack();
+ //send_ack();
}
void send_keypress(u8 key) {
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("500 Silence started." CRLF);
+ return;
}
void print_switches(u8 prompted) {
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() {
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 subroute 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
+ "" 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
);
}
unknown_command();
}
-//SHA1_CTX ctx;
-//u8 sha1_digest[SHA1_SIGNATURE_SIZE];
-
int main() {
u8 i;
for (i = 0; i < 11; i++)
set_msg(" CRUEL ");
- //comm_init();
//coinmech_init();
sci_init();
keypad_init();
chime_start();
send_string("5N4X0RZ R US" CRLF);
+
+ mic_challenge = 0;
last_standalone = is_standalone();
if (last_standalone)
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()) {
}
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);
- }
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