Skip to content

Instantly share code, notes, and snippets.

@Bouni
Last active May 31, 2019 01:53
Show Gist options
  • Save Bouni/10188466 to your computer and use it in GitHub Desktop.
Save Bouni/10188466 to your computer and use it in GitHub Desktop.
Some tests for an MDB project
// global state variable
unsigned int coinstate;
// structure for storing the coin changer info
struct COIN_INFO {
byte feature_level;
unsigned int country_code;
byte scaling_factor;
byte decimal_places;
byte type_routing;
byte type_credit[16];
};
// struct for storing the tube status
struct TUBE_STATUS {
unsigned int full_status;
byte status[16];
};
COIN_INFO coin_info =
{0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
TUBE_STATUS tube_status =
{0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
void setup() {
Serial.begin(9600);
Serial1.begin(9600, true);
coinstate = 0;
Serial.println("VMC stated.");
}
void loop() {
// run the statemachine
statemachine();
// everytime we wait we can do funny stuff here in the meantime :-)
// but make sure it takes not longer then 100ms, because we have to poll the
// coin acceptor every 100ms at least!
do_funny_stuff();
}
unsigned int calculate_checksum(unsigned int data[], unsigned int n) {
unsigned int checksum = 0x000;
// sum up all bytes except the last one (thats the checksum!)
for(int i=0; i < n-1; i++) {
checksum += data[i];
}
// cut off the bits higher than 8 using a simple binary &
checksum &= 0x0FF;
// check the calculation against the checksum
return checksum;
}
bool validate_checksum(unsigned int data[], unsigned int n) {
unsigned int checksum = calculate_checksum(data, n);
// check the calculation against the checksum
return (checksum == data[n-1]);
}
void do_funny_stuff() {
}
// A simple statemachine for the coinchanger
void statemachine() {
unsigned int reply[40];
unsigned int data[40];
// This will print the coinstate and then wait 10ms to avoid the buffers to be flooded
Serial.print("State ");
Serial.println(coinstate, DEC);
delay(10);
switch(coinstate) {
// We have just powered up
case 0:
Serial1.write9bit(0x108);
Serial1.write9bit(0x008);
coinstate++;
break;
// we have already sent the reset command
case 1:
// wait for an answer
if(Serial1.available() < 1) {
return;
}
if(Serial1.read() == 0x100) {
// ACK received go ahead in the statemachine
coinstate++;
} else {
// No ACK received, start again from the beginning
coinstate = 0;
}
break;
// Poll the coin changer
case 2:
Serial1.write9bit(0x10B);
Serial1.write9bit(0x00B);
coinstate++;
break;
// Wait for the JUST RESET to be received
case 3:
// Check if the received byte is just an ACK
// read and discard it if so
if(Serial1.peek() == 0x100) {
Serial1.read();
return;
}
// If the first byte is no ACK, wait for 2 bytes to be received
if(Serial1.available() < 2) {
return;
}
// read the 2 bytes and verify it is the JUST RESET
for(int i = 0; i < 2; i++) {
reply[i] = Serial1.read();
}
if(reply[0] == 0x000 && reply[1] == 0x100) {
// JUST RESET received, send ACk and go ahead
Serial1.write9bit(0x100);
coinstate++;
} else {
// something else received send RET
Serial1.write9bit(0x0AA);
}
break;
// send the SETUP command
case 4:
Serial1.write9bit(0x109);
Serial1.write9bit(0x009);
coinstate++;
break;
// wait for the answer
case 5:
// Wait for 24 bytes to be received
if(Serial1.available() < 24) {
return;
}
// read the replied 23 databytes + checksum
for(int i = 0; i < 24; i++){
reply[i] = Serial1.read();
}
// validate the checksum
if(validate_checksum(reply, 24)) {
// checksum oki send ACK, go ahead
Serial1.write9bit(0x100);
coinstate++;
} else {
// checksum incorrect, send RET
Serial1.write9bit(0x0AA);
}
break;
// store device info
case 6:
coin_info.feature_level = reply[0];
coin_info.country_code = (reply[1] << 8 | reply[2]);
coin_info.scaling_factor = reply[3];
coin_info.decimal_places = reply[4];
coin_info.type_routing = (reply[5] << 8 | reply[6]);
for(int i = 0; i < 16; i++) {
coin_info.type_credit[i] = reply[i+7];
}
coinstate++;
break;
// send TUBE STATUS command
case 7:
Serial1.write9bit(0x10A);
Serial1.write9bit(0x00A);
coinstate++;
break;
// wait for the answer
case 8:
// Wait for 19 bytes to be received
if(Serial1.available() < 19) {
return;
}
// read the replied 18 databytes + checksum
for(int i = 0; i < 19; i++){
reply[i] = Serial1.read();
}
// validate the checksum
if(validate_checksum(reply, 19)) {
// checksum ok send ACK, go ahead
Serial1.write9bit(0x100);
coinstate++;
} else {
// checksum incorrect, send RET
Serial1.write9bit(0x0AA);
}
break;
// store tube status info
case 9:
tube_status.full_status = (reply[0] << 8 | reply[1]);
for(int i=0; i < 19; i++) {
tube_status.status[i] = reply[i+2];
}
coinstate++;
break;
// send coin type command
case 10:
// prepare the data for the coin type command
data[0] = 0x10C;
data[1] = 0x00C;
data[2] = 0x0FF;
data[3] = 0x0FF;
data[4] = 0x0FF;
data[5] = 0x0FF;
// calculate the necessary checksum
data[6] = calculate_checksum(data, 6);
for(int i = 0; i < 7; i++) {
Serial1.write9bit(data[i]);
}
coinstate++;
break;
// wait for the ACK of the coin changer
case 11:
reply[0] = Serial1.read();
if(reply[0] == 0x100) {
// ACK received go ahead
coinstate++;
} else {
// No ACK received, send the coin type command again
Serial.print("Error: expected ACK, received instead: ");
Serial.println(reply[0], HEX);
coinstate--;
}
break;
// Now we should be able to dispense a coin
case 12:
Serial.println("boot proccess completed :-)");
coinstate++;
break;
// Lets poll the coin changer no forever
case 13:
Serial1.write9bit(0x10B);
Serial1.write9bit(0x00B);
coinstate++;
break;
case 14:
// Check if the received byte is just an ACK
// read and discard it if so
if(Serial1.peek() == 0x100) {
Serial1.read();
return;
}
// If the first byte is no ACK, wait for 16 bytes to be received
if(Serial1.available() < 16) {
return;
}
for(int i = 0; i < 17; i++) {
reply[i] = Serial1.read();
}
// validate the checksum
if(validate_checksum(reply, 17)) {
// checksum ok send ACK, go ahead
Serial1.write9bit(0x100);
coinstate++;
} else {
// checksum incorrect, send RET
Serial1.write9bit(0x0AA);
}
break;
// Lets write the reply to the console for testing purposes
case 15:
for(int i = 0; i < 17; i++) {
Serial.print("Byte ");
Serial.print(i, DEC);
Serial.print(" = ");
Serial.println(reply[i]);
}
delay(50);
coinstate = 13;
break;
}
}
*Power Up*
VMC: Reset 0x108 0x008
Coin: Ack 0x100
// Now poll as long as you get the Just Reset
// That can happen emdiately after the Reset, but also
// can take a few seconds with ACK answers in between
VMC: Poll 0x10B 0x00B
Coin: Ack 0x100
VMC: Poll 0x10B 0x00B
Coin: Ack 0x100
VMC: Poll 0x10B 0x00B
Coin: Ack 0x100
VMC: Poll 0x10B 0x00B
Coin: Just Reset 0x000 0x100
// Now get the Coin Mech setup information. See MDB Spec page 64 for details
// Store this infomation in a struct
VMC: Setup 0x109 0x009
Coin: Answer [1 Byte] // Feature level
[2 Bytes] // Country / Currency Code
[1 Byte] // Coin Scaling factor
[1 Byte] // Decimal Places
[2 Bytes] // Coin Routing
[16 Bytes] // Coin Type Credit
[1 Byte] // Checksum
VMC: Ack 0x100
VMC: Tube Status 010A 0x00A
Coin: Answer [2 Bytes] // Tube Full Status
[16 Bytes] // Tube Status
[1 Byte] // Checksum
VMC: Ack 0x100
// Whenever you idle around, you need to send polls to the device to make sure they are alive
// But expect every time you poll that you get up to 16 Bytes of Status Data
VMC: Poll 0x10B 0x00B
Coin: Ack 0x100
// Now enable the coin types for dispense (only need to be done once)
VMC: Coin Type 0x10C 0x00C
0x0FF 0x0FF // activate all coin types
0x0FF 0x0FF // activate all coin types for maual dispense
[1 Byte] // Checksum
Coin: Ack
// Now dispense a coin
// From here you can cycle and dispense as much coins as you wnat
VMC: Dispense 0x10D 0x00D
0x011 // 0b00110001 -> Bit 0 means Coin type 1, bit 4 and 5 means dispnse 3 coins
[1 Byte] // Checksum
Coin: Ack 0x100
// If you poll after the Ack of the coin mech, you get the status of the dispense.
// connect Serial1 Rx to Serial2 Tx
// connect Serial2 Rx to Serial1 Tx
void setup()
{
Serial.begin(9600);
Serial1.begin(9600,true);
Serial2.begin(9600,true);
Serial.println("Setup completed");
}
void loop()
{
unsigned int tmp;
Serial.println("sending 0x000 on Serial1");
Serial1.write9bit(0x000);
Serial.println("wait for arrival on Serial2");
while(!Serial2.available()) {
delay(1);
}
tmp = Serial2.read();
Serial.println("received on Serial2:");
Serial.println(tmp, HEX);
Serial.println("sending 0x100 on Serial1");
Serial1.write9bit(0x100);
Serial.println("wait for arrival on Serial2");
while(!Serial2.available()) {
delay(1);
}
tmp = Serial2.read();
Serial.println("received on Serial2:");
Serial.println(tmp, HEX);
Serial.println("sending 0x000 on Serial2");
Serial2.write9bit(0x000);
Serial.println("wait for arrival on Serial1");
while(!Serial1.available()) {
delay(1);
}
tmp = Serial1.read();
Serial.println("received on Serial1:");
Serial.println(tmp, HEX);
Serial.println("sending 0x100 on Serial2");
Serial2.write9bit(0x100);
Serial.println("wait for arrival on Serial1");
while(!Serial1.available()) {
delay(1);
}
tmp = Serial1.read();
Serial.println("received on Serial1:");
Serial.println(tmp, HEX);
}
@lvlisael
Copy link

lvlisael commented Nov 6, 2018

what is your definition for function Serial1.write9bit? it does not exist when i compile it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment