Change from bzip2 compression to lzip
[uccvend-snackrom.git] / ROM2 / coinmech.c
index 80a11a7..124c835 100644 (file)
@@ -1,2 +1,145 @@
+#include "coinmech.h"
 #include "vend.h"
 
+#define COINMECH_ID   0x20
+
+volatile u8 last_byte;
+volatile u8 packet_pos;
+volatile u16 value_1;
+volatile u8 value_2;
+volatile u8 dec_point;
+
+volatile u16 coin_value;
+u8 item_cost;
+volatile bool have_change;
+
+u8 parity_test(u8 c) {
+       u8 parity = 0;
+       for (parity = 0; c; c = c>>1) {
+               if (c&1) parity = !parity;
+       }
+       return parity;
+}
+
+bool parity_good(u8 c) {
+
+/*
+ * parity_good truth table:
+ *
+ *      | parity_test(c)
+ *      | 0   1
+ * -----+---------
+ * R8 0 | 1   0
+ *    1 | 0   1
+ *
+ * equates to even parity?
+ */
+
+       u8 R8 = (_io_ports[M6811_SCCR1] & M6811_R8)?1:0;
+       u8 p = parity_test(c)?1:0;
+       return R8 == p;
+}
+
+void send_byte(u8 c) {
+       last_byte = c;
+       while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); /* wait for TD register empty */
+
+       if (parity_test(c))
+               bset((void*)&_io_ports[M6811_SCCR1], M6811_T8);
+       else
+               bclr((void*)&_io_ports[M6811_SCCR1], M6811_T8);
+}
+
+#define IS_CTRL(x) (x & 0x10) /* true if this packet is a control packet */
+void sci_interrupt_coinmech() {
+       u8 in;
+       in = _io_ports[M6811_SCDR];
+       
+       /* test for framing errors & parity bit */
+       if (_io_ports[M6811_SCSR] & M6811_FE || !parity_good(in)) {
+               _io_ports[M6811_SCDR]; /* read of register req'd to clear FE */
+               send_byte(0xff); /* request a retransmit */
+               return;
+       }
+
+       /* all bytes must have the correct ID in the 3 MSBs */
+       if ((in & 0xe0) != COINMECH_ID) return;
+
+       /* we have a good packet */
+       if (in == 0x3f) {
+               /* retransmit was requested */
+               send_byte(last_byte);
+               return;
+       }
+
+       if (packet_pos != 0 || IS_CTRL(in)) {
+               in &= 0x0f;
+               switch (in) {
+                       case 0x01: 
+                               /* just reply with ack */
+                               /* original firmware does something with link master price holding */
+                               send_byte(0x00);
+                       case 0x02:
+                               /* write back how much change to give, or 0xfe to hold it. */
+                               if (item_cost) {
+                                       send_byte(item_cost / value_2);
+                               } else
+                                       send_byte(0xfe);
+                               break;
+                       case 0x03:
+                               /* hmmm, maybe we're sposed to do something here. firmware doesnt */
+                               /* and just sets a random bit - something like "changer in use"?  */
+                               break;
+                       case 0x08:
+                               /* start of packet */
+                               packet_pos = 1;
+                               send_byte(0x00);
+                               break;
+                       default:
+                               /* just ack it and move on */
+                               send_byte(0x00);
+               }
+       } else {
+               in &= 0x0f;
+               switch (packet_pos) {
+                       case 1: value_1  = in;           break;
+                       case 2: value_1 |= in << 4;      break;
+                       case 3: value_1 |= in << 8;      break;
+                       case 4: value_1 |= in << 12;     break;
+                       case 5: value_2  = in;           break;
+                       case 6: value_2 |= in << 4;      break;
+                       case 7: dec_point = in;          break;
+                       case 8: have_change = (in&0x01); break;
+                       default:
+                                       if (packet_pos == 9) {
+                                               packet_pos = 0;
+                                               coin_value = value_1*value_2;
+                                       }
+                                       /* hmmm, else? */
+               }
+               packet_pos++;
+               send_byte(0x00); /* ack */
+       }
+}
+
+void coin_eat() {
+       coin_cost(coin_value); /* eat everything */
+}
+
+void coin_cost(u16 cost) {
+       item_cost = cost;
+       while(coin_value); /* wait until coin mech cleared */
+}
+
+void coinmech_init() {
+       packet_pos = 0;
+       value_1 = value_2 = 0;
+       dec_point = 0;
+       coin_value = 0;
+       item_cost = 0;
+       have_change = 0;
+       _io_ports[M6811_SCCR1] = 0x10;
+       _io_ports[M6811_SCCR2] = 0x2e;
+       _io_ports[M6811_BAUD] = 0x03;
+       send_byte(0xff);
+}

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