add credit, add 013 debug timer message on keypress
[uccvend-snackrom.git] / ROM2 / coinmech.c
1 #include "coinmech.h"
2 #include "vend.h"
3
4 #define COINMECH_ID   0x20
5
6 volatile u8 last_byte;
7 volatile u8 packet_pos;
8 volatile u16 value_1;
9 volatile u8 value_2;
10 volatile u8 dec_point;
11
12 volatile u16 coin_value;
13 u8 item_cost;
14 volatile bool have_change;
15
16 u8 parity_test(u8 c) {
17         u8 parity = 0;
18         for (parity = 0; c; c = c>>1) {
19                 if (c&1) parity = !parity;
20         }
21         return parity;
22 }
23
24 bool parity_good(u8 c) {
25
26 /*
27  * parity_good truth table:
28  *
29  *      | parity_test(c)
30  *      | 0   1
31  * -----+---------
32  * R8 0 | 1   0
33  *    1 | 0   1
34  *
35  * equates to even parity?
36  */
37
38         u8 R8 = (_io_ports[M6811_SCCR1] & M6811_R8)?1:0;
39         u8 p = parity_test(c)?1:0;
40         return R8 == p;
41 }
42
43 void send_byte(u8 c) {
44         last_byte = c;
45         while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); /* wait for TD register empty */
46
47         if (parity_test(c))
48                 bset((void*)&_io_ports[M6811_SCCR1], M6811_T8);
49         else
50                 bclr((void*)&_io_ports[M6811_SCCR1], M6811_T8);
51 }
52
53 #define IS_CTRL(x) (x & 0x10) /* true if this packet is a control packet */
54 void sci_interrupt_coinmech() {
55         u8 in;
56         in = _io_ports[M6811_SCDR];
57         
58         /* test for framing errors & parity bit */
59         if (_io_ports[M6811_SCSR] & M6811_FE || !parity_good(in)) {
60                 _io_ports[M6811_SCDR]; /* read of register req'd to clear FE */
61                 send_byte(0xff); /* request a retransmit */
62                 return;
63         }
64
65         /* all bytes must have the correct ID in the 3 MSBs */
66         if ((in & 0xe0) != COINMECH_ID) return;
67
68         /* we have a good packet */
69         if (in == 0x3f) {
70                 /* retransmit was requested */
71                 send_byte(last_byte);
72                 return;
73         }
74
75         if (packet_pos != 0 || IS_CTRL(in)) {
76                 in &= 0x0f;
77                 switch (in) {
78                         case 0x01: 
79                                 /* just reply with ack */
80                                 /* original firmware does something with link master price holding */
81                                 send_byte(0x00);
82                         case 0x02:
83                                 /* write back how much change to give, or 0xfe to hold it. */
84                                 if (item_cost) {
85                                         send_byte(item_cost / value_2);
86                                 } else
87                                         send_byte(0xfe);
88                                 break;
89                         case 0x03:
90                                 /* hmmm, maybe we're sposed to do something here. firmware doesnt */
91                                 /* and just sets a random bit - something like "changer in use"?  */
92                                 break;
93                         case 0x08:
94                                 /* start of packet */
95                                 packet_pos = 1;
96                                 send_byte(0x00);
97                                 break;
98                         default:
99                                 /* just ack it and move on */
100                                 send_byte(0x00);
101                 }
102         } else {
103                 in &= 0x0f;
104                 switch (packet_pos) {
105                         case 1: value_1  = in;           break;
106                         case 2: value_1 |= in << 4;      break;
107                         case 3: value_1 |= in << 8;      break;
108                         case 4: value_1 |= in << 12;     break;
109                         case 5: value_2  = in;           break;
110                         case 6: value_2 |= in << 4;      break;
111                         case 7: dec_point = in;          break;
112                         case 8: have_change = (in&0x01); break;
113                         default:
114                                         if (packet_pos == 9) {
115                                                 packet_pos = 0;
116                                                 coin_value = value_1*value_2;
117                                         }
118                                         /* hmmm, else? */
119                 }
120                 packet_pos++;
121                 send_byte(0x00); /* ack */
122         }
123 }
124
125 void coin_eat() {
126         coin_cost(coin_value); /* eat everything */
127 }
128
129 void coin_cost(u16 cost) {
130         item_cost = cost;
131         while(coin_value); /* wait until coin mech cleared */
132 }
133
134 void coinmech_init() {
135         packet_pos = 0;
136         value_1 = value_2 = 0;
137         dec_point = 0;
138         coin_value = 0;
139         item_cost = 0;
140         have_change = 0;
141         _io_ports[M6811_SCCR1] = 0x10;
142         _io_ports[M6811_SCCR2] = 0x2e;
143         _io_ports[M6811_BAUD] = 0x03;
144         send_byte(0xff);
145 }

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