Lots of changes! Takes us to rom S
[uccvend-snackrom.git] / ROM2 / main_basic.c
1 /*
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
4  * and snacks.
5  */
6
7 #define VERSION_STRING "R 20040622"
8
9 #include "display_basic.h"
10 #include "keypad.h"
11 #include "chime.h"
12 #include "coinmech.h"
13 #include "motors.h"
14 #include "sci.h"
15 #include "vend.h"
16
17 u8 last_standalone;
18 u8 last_switch_input;
19 u8 last_misc_input;
20 u16 last_coin_value;
21 bool last_door_open;
22 char display_buf[11];
23 /* cur_motor[0] is 0 for nothing, or 1..10, or 0xff to say redraw.
24  * cur_motor[1] is 0..9 and only meaningful is cur_motor[0] != 0. */
25 u8 cur_motor[2];
26
27 bool check_standalone() {
28         if (is_standalone()) {
29                 send_string("011 In standalone mode. Function disabled." CRLF);
30                 return 1;
31         }
32         return 0;
33 }
34
35 void unknown_command() {
36         send_string("012 Unknown command. Type HELP for help." CRLF);
37 }
38
39 void motor_reply(u8 code) {
40         /* returns a message of the form MXYY - X is return code, YY is motor */
41         switch (code) {
42                 case MOTOR_SUCCESS:
43                         send_string("100 Vend successful." CRLF);
44                         break;
45                 case MOTOR_NOSLOT:
46                         send_string("151 No motor there." CRLF);
47                         break;
48                 case MOTOR_CURRENT_FAIL:
49                         send_string("152 Over current." CRLF);
50                         break;
51                 case MOTOR_HOME_FAIL:
52                         send_string("153 Home sensors failing." CRLF);
53                         break;
54                 default:
55                         send_string("159 Unknown motor error." CRLF);
56         }
57 }
58
59 void dispense_something() {
60         /* process a message VXX in sci_rx_buf where XX is motor number */
61         u8 slot;
62
63         if (check_standalone()) return;
64
65         if (my_strncmp("ALL", (char*)sci_rx_buf+1, 3)) {
66                 char motor[3];
67                 motor[2] = '\0';
68                 send_string("102 Vend all motors starting." CRLF);
69                 for (motor[0] = '0'; motor[0] <= '9'; motor[0]++) {
70                         for (motor[1] = '0'; motor[1] <= '9'; motor[1]++) {
71                                 send_string("101 Vending ");
72                                 send_string(motor);
73                                 send_string(CRLF);
74                                 motor_reply(dispense_motor(motor[0]*10+motor[1]));
75                         }
76                 }
77                 send_string("102 Vend all motors complete." CRLF);
78                 return;
79         }
80
81         if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
82                 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9')) {
83                 sci_rx_buf[1] = sci_rx_buf[2] = '0';
84                 motor_reply(MOTOR_NOSLOT);
85                 return;
86         }
87
88         slot = (sci_rx_buf[1] - '0') * 10;
89         slot += sci_rx_buf[2] - '0';
90
91         motor_reply(dispense_motor(slot));
92 }
93
94 void write_to_display() {
95         /* process a message in the form DXXXXXXXXXX to send to display */
96         u8 i;
97         char buf[11];
98
99         if (check_standalone()) return;
100
101         for (i = 0; i < 10; i++)
102                 if (sci_rx_buf[i+1])
103                         buf[i] = sci_rx_buf[i+1];
104                 else
105                         break;
106
107         for (; i < 10; i++) /* pad the rest out with spaces */
108                 buf[i] = ' ';
109         buf[i] = '\0';
110
111         set_msg(buf);
112         send_string("300 Written." CRLF);
113 }
114
115 void send_balance() {
116         sci_tx_buf[0] = 'C';
117         sci_tx_buf[1] = have_change?'0':'1';
118         sci_tx_buf[2] = (coin_value/10000)%10;
119         sci_tx_buf[3] = (coin_value/1000)%10;
120         sci_tx_buf[4] = (coin_value/100)%10;
121         sci_tx_buf[5] = (coin_value/10)%10;
122         sci_tx_buf[6] = coin_value%10;
123         sci_tx_buf[8] = 0;
124         send_buffer(1);
125 }
126
127 void give_change() {
128         u16 cost;
129
130         if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') ||
131                 (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9') ||
132                 (sci_rx_buf[3] < '0') || (sci_rx_buf[3] > '9') ||
133                 (sci_rx_buf[4] < '0') || (sci_rx_buf[4] > '9') ||
134                 (sci_rx_buf[5] < '0') || (sci_rx_buf[5] > '9')) {
135                 send_nack();
136         }
137         cost = sci_rx_buf[1] - '0';
138         cost *= 10; cost = sci_rx_buf[2] - '0';
139         cost *= 10; cost = sci_rx_buf[3] - '0';
140         cost *= 10; cost = sci_rx_buf[4] - '0';
141         cost *= 10; cost = sci_rx_buf[5] - '0';
142
143         coin_cost(cost);
144         send_ack();
145
146
147 void send_keypress(u8 key) {
148         /* send a packet of the form KX with X being the key, or R for reset */
149         if (is_standalone()) return;
150
151         sci_tx_buf[0] = '2';
152         if (key == KEY_RESET) {
153                 sci_tx_buf[1] = '1';
154                 sci_tx_buf[2] = '1';
155         } else {
156                 sci_tx_buf[1] = '0';
157                 sci_tx_buf[2] = (key%10)+'0';
158         }
159         sci_tx_buf[3] = '\0';
160         send_buffer(0);
161         send_string(" key." CRLF);
162 }
163
164 void send_door_msg(bool open) {
165         if (is_standalone()) return;
166         sci_tx_buf[0] = '4';
167         sci_tx_buf[1] = '0';
168         sci_tx_buf[2] = open?'1':'0';
169         send_buffer(0);
170         if (open)
171                 send_string(" door open." CRLF);
172         else
173                 send_string(" door closed." CRLF);
174 }
175
176 u8 hexchar2u8(char b) {
177         if (b >= '0' && b <= '9') return b-'0';
178         if (b >= 'a' && b <= 'f') return b-'a'+0x0a;
179         if (b >= 'A' && b <= 'F') return b-'A'+0x0a;
180         return 0;
181 }
182
183 char nibble2hexchar(u8 b) {
184         if (b <= 9) return b+'0';
185         if (b >= 10 && b <= 15) return b+'A';
186         return 'X';
187 }
188
189 u8 hex2u8(char msb, char lsb) {
190         return (hexchar2u8(msb) << 4) + hexchar2u8(lsb);
191 }
192
193 static char hexconv_buf[3];
194 char* u82hex(u8 a) {
195         hexconv_buf[0] = nibble2hexchar((a&0xf0) >> 4);
196         hexconv_buf[1] = nibble2hexchar(a&0x0f);
197         hexconv_buf[2] = '\0';
198         return hexconv_buf;
199 }
200
201 void do_chime() {
202         if (check_standalone()) return;
203         if (sci_rx_buf[1] == '\0')
204                 chime_start();
205         else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
206                 chime_start(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
207         else {
208                 send_string("510 Unknown chime duration." CRLF);
209                 return;
210         }
211         send_string("500 Chimed." CRLF);
212 }
213
214 void print_switches(u8 prompted) {
215         if (prompted)
216                 send_string("600 ");
217         else
218                 send_string("610 ");
219         send_string(u82hex(misc_input));
220         send_string(" ");
221         send_string(u82hex(switch_input));
222         send_string(CRLF);
223 }
224
225 void ping_pong() {
226         /* make sure it's really a ping */
227         if (!my_strncmp("ING", (char*)sci_rx_buf+1, 3)) {
228                 unknown_command();
229                 return;
230         }
231         /* respond with ack & pong */
232         send_string("000 PONG!" CRLF);
233 }
234
235 void send_prompt() {
236         send_string(is_standalone()?"$ ":"# ");
237 }
238
239 void about() {
240         if (!my_strncmp("BOUT", (char*)sci_rx_buf+1, 4)) {
241                 unknown_command();
242                 return;
243         }
244         send_string(
245                 "-----------------------------------------------------------------" CRLF
246                 "    ROM2 (C) 2004 Bernard Blackham <[email protected]>" CRLF
247                 "-----------------------------------------------------------------" CRLF
248                 "                                        Revision " VERSION_STRING CRLF
249                 "" CRLF
250                 "   This snack machine was brought to you by " CRLF
251                 "    Bernard Blackham" CRLF
252                 "    Mark Tearle" CRLF
253                 "    Harry McNally" CRLF
254                 "    Michal Gornisiewicz" CRLF
255                 "    and others." CRLF
256                 "" CRLF
257                 " Another UCC project in action.         http://www.ucc.asn.au/" CRLF
258         );
259 }
260
261 void set_echo() {
262         if (my_strncmp("CHO ON", (char*)sci_rx_buf+1, 6))
263                 sci_echo = 1;
264         else if (my_strncmp("CHO OFF", (char*)sci_rx_buf+1, 7))
265                 sci_echo = 0;
266         else
267                 unknown_command();
268 }
269
270 void moo() {
271         if (!my_strncmp("OO", (char*)sci_rx_buf+1, 2)) {
272                 unknown_command();
273                 return;
274         }
275         send_string(
276 "       ____________" CRLF
277 "       |__________|" CRLF
278 "      /           /\\" CRLF
279 "     /  U C C    /  \\" CRLF
280 "    /___________/___/|" CRLF
281 "    |          |     |" CRLF
282 "    |  ==\\ /== |     |" CRLF
283 "    |   O   O  | \\ \\ |" CRLF
284 "    |     <    |  \\ \\|" CRLF
285 "   /|          |   \\ \\" CRLF
286 "  / |  \\_____/ |   / /" CRLF
287 " / /|          |  / /|" CRLF
288 "/||\\|          | /||\\/" CRLF
289 "    -------------|   " CRLF
290 "        | |    | | " CRLF
291 "       <__/    \\__>" CRLF
292         );
293 }
294
295 void help() {
296         send_string(
297                 "Valid commands are:" CRLF
298                 " ABOUT         ROM information" CRLF
299                 " PING          pongs" CRLF
300                 " ECHO {ON|OFF} turn echo on or off" CRLF
301                 " Vnn           vend an item" CRLF
302                 " VALL          vend all items" CRLF
303                 " DXXXXXXXXXX   show a message on the display" CRLF
304                 " B[nn]         beep for a duration nn (optional)" CRLF
305                 " S[...]        query all internal switch states" CRLF
306                 " H[...]        this help screen" CRLF
307                 "Comments start with a #" CRLF
308         );
309 }
310
311 void quit() {
312         if (my_strncmp("UIT", (char*)sci_rx_buf+1, 3))
313                 send_string("013 You can't quit you doofus." CRLF);
314         else
315                 unknown_command();
316 }
317
318 int main() {
319         u8 i;
320         for (i = 0; i < 11; i++)
321                 display_buf[i] = ' ';
322         display_buf[10] = '\0';
323
324         changer_output = 0x7f;
325         _io_ports[M6811_PORTA] = 0xc0; /* display on. talking to serial port */
326         _io_ports[M6811_DDRA] = 0xfc;
327         _io_ports[M6811_DDRD] = 0x3e;
328         _io_ports[M6811_SPCR] = M6811_MSTR | M6811_SPR1;
329         set_misc_output(0x00);
330
331         display_init();
332         set_msg(" HELLO    ");
333         delay(1000);
334
335         unlock(); /* enable interrupts */
336
337         set_msg("  CRUEL   ");
338
339         //comm_init();
340         //coinmech_init();
341         sci_init();
342         keypad_init();
343         last_coin_value = 0;
344         last_door_open = 0;
345
346         delay(1000);
347
348         set_msg("   WORLD  ");
349         delay(1000);
350
351         chime_start();
352
353         send_string("5N4X0RZ R US" CRLF);
354         
355         last_standalone = is_standalone();
356         if (last_standalone)
357                 cur_motor[0] = 0xff;
358         else
359                 cur_motor[0] = 0;
360         send_prompt();
361
362         last_switch_input = switch_input;
363         last_misc_input = misc_input;
364
365         while(1) {
366                 if (cur_motor[0] == 0xff) { /* signal to say redraw screen */
367                         set_msg("*5N4X0RZ* ");
368                         cur_motor[0] = 0;
369                 }
370
371                 if (door_open() != last_door_open) {
372                         last_door_open = door_open();
373                         send_door_msg(last_door_open);
374                         chime_start();
375                         set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE");
376                 }
377
378                 if (last_standalone != is_standalone()) {
379                         /* somebody flicked the standalone switch */
380                         msg_clr();
381                         send_string(CRLF);
382                         send_prompt();
383                         last_standalone = is_standalone();
384                 }
385
386                 if (last_misc_input != misc_input) {
387                         print_switches(0);
388                         last_misc_input = misc_input;
389                 }
390
391                 if (last_switch_input != switch_input) {
392                         print_switches(0);
393                         last_switch_input = switch_input;
394                 }
395
396                 if (sci_have_packet) {
397                         switch (sci_rx_buf[0]) {
398                                 case '\0':
399                                 case '#':
400                                         send_string(CRLF);
401                                         break;
402                                 case 'E':
403                                         set_echo();
404                                         break;
405                                 case 'H':
406                                         help();
407                                         break;
408                                 case 'V':
409                                         dispense_something();
410                                         break;
411                                 case 'D':
412                                         write_to_display();
413                                         break;
414                                 case 'B': 
415                                         do_chime();
416                                         break;
417                                 case 'P':
418                                         ping_pong();
419                                         break;
420                                 case 'A':
421                                         about();
422                                         break;
423                                 case 'S':
424                                         print_switches(1);
425                                         break;
426                                 case 'M':
427                                         moo();
428                                         break;
429                                 case 'Q':
430                                         quit();
431                                         break;
432                                 default:
433                                         // shurg
434                                         unknown_command();
435                                         break;
436                         }
437                         msg_clr();
438                         send_prompt();
439                 }
440
441                 keypad_read();
442                 if (keypad_pressed()) {
443                         if (is_standalone()) {
444                                 if (last_key == KEY_RESET) {
445                                         cur_motor[0] = 0xff;
446                                 } else {
447                                         if (cur_motor[0]) {
448                                                 u8 motor_num;
449                                                 cur_motor[1] = last_key%10;
450                                                 display_buf[1] = cur_motor[1]+'0';
451                                                 set_msg(display_buf);
452
453                                                 motor_num = cur_motor[0]%10;
454                                                 motor_num *= 10;
455                                                 motor_num += cur_motor[1];
456                                                 switch (dispense_motor(motor_num)) {
457                                                         case MOTOR_HOME_FAIL:
458                                                                 set_msg(" HOME FAIL ");
459                                                                 break;
460                                                         case MOTOR_CURRENT_FAIL:
461                                                                 set_msg(" OVER CRNT ");
462                                                                 break;
463                                                         case MOTOR_SUCCESS:
464                                                                 set_msg("THANK  YOU");
465                                                                 break;
466                                                         case MOTOR_NOSLOT:
467                                                                 set_msg(" NO MOTOR ");
468                                                                 break;
469                                                         default:
470                                                                 set_msg("ERRRRRRRR?");
471                                                                 break;
472                                                 }
473
474                                                 display_buf[0] = ' ';
475                                                 display_buf[1] = ' ';
476                                                 cur_motor[0] = 0xff;
477                                                 delay(500);
478                                         } else {
479                                                 cur_motor[0] = last_key;
480                                                 display_buf[0] = (last_key%10)+'0';
481                                                 set_msg(display_buf);
482                                         }
483                                 }
484                         } else
485                                 send_keypress(last_key);
486                 }
487
488                 /*
489                 if (coin_value != last_coin_value) {
490                         send_balance();
491                         last_coin_value = coin_value;
492                 }
493                 */
494         }
495 }

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