// https://forum.arduino.cc/t/virtual-bingo-machine-sketch/1298160/4

/*
  || @version build 32
  ||
  || This program is only for use with BALLY Bingo Backglass simulation by Joop.
  || It also requires the UNO Stepper Motor controller.
  ||
*/
#define RELAY_ON  1
#define RELAY_OFF 0
#define RELAY_1 4            // YELLOW RO light
#define RELAY_2 5            // RED RO light
#define ON 1
#define OFF 0
#define OPENED 1
#define CLOSED 0
// Table containing numbered hole codes for JR's simulation
char Ballcodes [26] = { 
  ' ', 
  'A', 'B', 'C', 'D', 'E', 
  'F', 'G', 'H', 'I', 'J',
  'K', 'L', 'M', 'N', 'O', 
  'P', 'Q', 'R', 'S', 'T', 
  'U', 'V', 'W', 'X', 'Y'
};
//
char ch;                       // characters from Backglass
int BallsinPocket [26];        // slots 0 and 26 are not used
int sensorvalue;
int magiclines;
int shutter;
int Abutton;
int Bbutton;
int Cbutton;
int Dbutton;
int Ebutton;
int Fbutton;
int RedRO;
int YellowRO;
int RedROon;
int YellowROon;

void setup()
{
  Serial.begin  (9600);       // Comms to/from Joops BALLY BINGO simulations
  Serial3.begin (9600);       // Comms to UNO Motor Controller(TX only)
  shutter   = CLOSED;         //
  // To indicaate a Magic Line machine hold A button while pressing the RED button at
  // start of game
  magiclines = OFF;           // set when magic line BALLY BINGO
  Abutton   = OFF;            // Buttons A - F
  Bbutton   = OFF;
  Cbutton   = OFF;
  Dbutton   = OFF;
  Ebutton   = OFF;
  Fbutton   = OFF;
  YellowROon = OFF;           // set when YELLOW Rollover active
  YellowRO   = OFF;           // YELLOW Rollover switch set
  RedROon    = OFF;           // set when RED Rollover active
  RedRO      = OFF;           // RED Rollover switch set

  // Set up Rollover Light relays
  // Intialise pins so relays are inactive
  digitalWrite(RELAY_1, RELAY_OFF);         // NOTE - needs to be a High Level Trigger
  digitalWrite(RELAY_2, RELAY_OFF);         // Solid State Relay
  //
  pinMode(2, INPUT_PULLUP);    // YELLOW rollover
  pinMode(3, INPUT_PULLUP);    // RED rollover
  pinMode(RELAY_1, OUTPUT);    // YELLOW lamp output
  pinMode(RELAY_2, OUTPUT);    // RED lamp output
  pinMode(6, INPUT_PULLUP);    // White
  pinMode(7, INPUT_PULLUP);    // Blue
  pinMode(8, INPUT_PULLUP);    // Green
  pinMode(9, INPUT_PULLUP);    // R Button
  pinMode(10, INPUT_PULLUP);   // tilt
  pinMode(11, INPUT_PULLUP);   // rotate switch >
  pinMode(12, INPUT_PULLUP);   // rotate switch <
  pinMode(13, OUTPUT);         // test purposes only
  //
  pinMode(A0, INPUT_PULLUP);   // Ball thro gate
  pinMode(A1, INPUT_PULLUP);   // Ball return
  pinMode(A2, INPUT_PULLUP);   // Ball in Lane
  pinMode(A3, INPUT_PULLUP);   // 8th Ball Switch
  pinMode(A8, INPUT_PULLUP);   // Red New Game Button
  pinMode(A9, INPUT_PULLUP);   // Yellow Extra Ball Button
  pinMode(A10, INPUT_PULLUP);  // A Button
  pinMode(A11, INPUT_PULLUP);  // B Button
  pinMode(A12, INPUT_PULLUP);  // C Button
  pinMode(A13, INPUT_PULLUP);  // D Button
  pinMode(A14, INPUT_PULLUP);  // E Button
  pinMode(A15, INPUT_PULLUP);  // F Button
  delay (2000);                // make sure relays reset

  // Setup numbers 1 to 25 on pins 22 to 47 inclusive
  for (int i = 22; i <= 47; i++)
  {
    pinMode( i, INPUT_PULLUP);
  }
}
void loop()
{
  //
  //Process commands from backglass
  //
  if (Serial.available() > 0)
  {
    ch = Serial.read();
    if (ch == 'l')
      // check to see if ball in shooter lane if so do not lift ball
      // this should only happen when a ball lands in ballyhole for an extra ball
      // and the next ball is in the shooter lane already
      // also acts as an anti cheat, no balls in shooter lane at beginning of game
    {
      sensorvalue = digitalRead(A2);
      // if switch open no ball in lane so raise new ball
      if (sensorvalue == HIGH)
      {
        Serial3.println ('l');  // send lift ball to UNO motor controller
        delay (3000);
      }
    }
    //
    // Check backglass command
    // for Yellow and Red lights ON or OFF
    // 7 Yellow ON     6 Yellow OFF
    // 5 Red    ON     4 Red    OFF
    if (ch == '7' )
    {
      digitalWrite(RELAY_1, RELAY_ON);
      YellowROon = 1;
      digitalWrite (13, HIGH);
    }
    if (ch == '6' )
    {
      digitalWrite(RELAY_1, RELAY_OFF);
      YellowROon = 0;
      digitalWrite (13, LOW);
    }
    if (ch == '5' )
    {
      digitalWrite(RELAY_2, RELAY_ON);
      RedROon = 1;
    }
    if (ch == '4' )
    {
      digitalWrite(RELAY_2, RELAY_OFF);
      RedROon = 0;
    }
    ch = ' ';
  }

  // check for ball over YELLOW rollover
  sensorvalue = digitalRead(2);
  if (sensorvalue == LOW)
  {
    // check if Rollover light ON
    if (YellowROon == 1)
    {
      if (YellowRO == 0)
      {
        Serial.print ("8");
        delay (250);
        Serial.print ("^");
        YellowRO = 1;
        digitalWrite (13, HIGH);   //Debugging
      }
    }
  }
  // check for ball over RED rollover
  sensorvalue = digitalRead(3);
  if (sensorvalue == LOW)
  {
    // check if Rollover light ON
    if (RedROon == 1)
    {
      if (RedRO == 0)
      {
        Serial.print ("9");
        delay (250);
        Serial.print ("^");
        RedRO = 1;
        digitalWrite (13, HIGH);   //Debugging
      }
    }
  }
  // check for white button
  sensorvalue = digitalRead(6);
  if (sensorvalue == LOW)
  {
    Serial.print ('w');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');       // stops credits being continuosly counted down
    delay (1000);             // this allows time to release button
  }
  // check for blue button
  sensorvalue = digitalRead(7);
  if (sensorvalue == LOW)
  {
    Serial.print ('v');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');       // stops credits being continuosly counted down
    delay (1000);             // this allows time to release button
  }
  // check for green button
  sensorvalue = digitalRead(8);
  if (sensorvalue == LOW)
  {
    Serial.print ('u');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');       // stops credits being continuosly counted down
    delay (1000);             // this allows time to release button
  }
  // check for R button
  sensorvalue = digitalRead(9);
  if (sensorvalue == LOW)
  {
    Serial.print ('r');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');       // stops credits being continuosly counted down
    delay (1000);             // this allows time to release button
  }
  // Check if machine tilted
  sensorvalue = digitalRead(10);
  if (sensorvalue == LOW)
  {
    Serial.print ('t');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');
  }
  // Rotate right
  sensorvalue = digitalRead(11);
  if (sensorvalue == LOW)
  {
    Serial.print ('>');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');
    delay (1000);              // this allows time to release button
  }
  // Rotate left
  sensorvalue = digitalRead(12);
  if (sensorvalue == LOW)
  {
    Serial.print ('<');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');
    delay (1000);             // this allows time to release button
  }
  // Check if A Button pressed
  sensorvalue = digitalRead(A10);
  if (sensorvalue == LOW)
  {
    if (Abutton == OFF)
      // button still pressed
      // do not send anymore A button pressed code
    {
      Abutton = ON;
      Serial.print ('a');
      delay (250);
      Serial.println ('^');
      delay (250);
      if (magiclines == ON)Serial.print ('^');
    }
  }
  // button released
  if ((sensorvalue) == HIGH && (Abutton) == ON)
  {
    Abutton = OFF;
    Serial.print ('^');
  }
  // Check if B Button pressed
  sensorvalue = digitalRead(A11);
  if (sensorvalue == LOW)
  {
    if (Bbutton == OFF)
      // button still pressed
      // do not send anymore B button pressed code
    {
      Bbutton = ON;
      Serial.print ('b');
      delay (250);
      Serial.print ('^');
      delay (250);
      if (magiclines == ON)Serial.print ('^');
    }
  }
  if ((sensorvalue) ==  HIGH && (Bbutton) == ON)
  {
    Bbutton = OFF;
    Serial.print ('^');
  }
  // Check if C Button pressed
  sensorvalue = digitalRead(A12);
  if (sensorvalue == LOW)
  {
    if (Cbutton == OFF)
      // button still pressed
      // do not send anymore C button pressed code
    {
      Cbutton = ON;
      Serial.print ('c');
      delay (250);
      Serial.print ('^');
      delay (250);
      if (magiclines == ON)Serial.print ('^');
    }
  }
  if ((sensorvalue) == HIGH && (Cbutton) == ON)
  {
    Cbutton = OFF;
    Serial.print ('^');
  }
  // Check if D Button pressed
  sensorvalue = digitalRead(A13);
  if (sensorvalue == LOW)
  {
    if (Dbutton == OFF)
      // button still pressed
      // then do not send anymore D button pressed code
    {
      Dbutton = ON;
      Serial.print ('d');
      delay (250);
      Serial.print ('^');
      delay (250);
      if (magiclines == ON)Serial.print ('^');
    }
  }
  if ((sensorvalue) == HIGH && (Dbutton) == ON)
  {
    Dbutton = OFF;
    Serial.print ('^');
  }
  // Check if E Button pressed
  sensorvalue = digitalRead(A14);
  if (sensorvalue == LOW)
  {
    if (Ebutton == OFF)
      // check button pressed still pressed
      // then do not send anymore E button pressed code
    {
      Ebutton = ON;
      Serial.print ('e');
      delay (250);
      Serial.print ('^');
      delay (250);
      if (magiclines == ON)Serial.print ('^');
    }
  }
  if ((sensorvalue) == HIGH && (Ebutton) == ON)
  {
    Ebutton = OFF;
    Serial.print ('^');
  }
  // Check if F Button pressed
  sensorvalue = digitalRead(A15);
  if (sensorvalue == LOW)
  {
    if (Fbutton == OFF)
      // check button pressed still pressed
      // then do not send anymore F button pressed code
    {
      Fbutton = ON;
      Serial.print ('f');
      delay (250);
      Serial.print ('^');
      delay (250);
      if (magiclines == ON)Serial.print ('^');
    }
  }
  if ((sensorvalue) == HIGH && (Fbutton) == ON)
  {
    Fbutton = OFF;
    Serial.print ('^');
  }
  // Check for ball return
  sensorvalue = digitalRead(A1);
  if (sensorvalue == LOW)
  {
    sensorvalue = digitalRead(A2);
    if (sensorvalue == HIGH)
    {
      Serial3.println ('l');    // send lift ball to UNO motor controller
      delay (3000);
    }
  }
  // New Check for ball thro gate open
  sensorvalue = digitalRead(A0);
  if (sensorvalue == LOW)
  {
    Serial.write ('z');
    delay(2000);
    Serial3.println ('l');
  }
  // Check if Red Button pressed for new game
  sensorvalue = digitalRead(A8);
  if (sensorvalue == LOW)
  {
    RedRO = 0;
    YellowRO = 0;
    RedROon = 0;
    YellowROon = 0;
    for ( int i = 1; i < 26; i++)
    {
      BallsinPocket [i] = 0;
    }
    if (shutter == CLOSED)
    {
      // the following is only needed to be excuted once per new game
      magiclines = OFF;
      if (digitalRead(A10) == LOW) magiclines = ON;
      Serial.print ('q');        // reset machine
      delay (500);
      Serial3.print ('h');       // open shutter
      delay (3000);              // allow balls to drop
      Serial3.print ('i');       // close shutter
      shutter = OPENED;          // indicate shutter has been opened
    }
    Serial.print ('n');
    delay (500);
    Serial.print ('^');
    delay (500);
    Serial.print ('^');
    delay (1000);
  }

  // Check if YELLOW button pressed for extra ball
  sensorvalue = digitalRead(A9);
  if (sensorvalue == LOW)
  {
    Serial.print ('x');
    delay (500);
    Serial.print ('^');
    delay (500);                 // this allows time to release button
    Serial.print ('^');          // stops credits being continuosly counted down
    delay (1000);
  }

  // check for ball in numbered hole
  for (int i = 22; i <= 47; i++)
  {
    int sensorvalue = digitalRead(i);
    if ((sensorvalue) == LOW && (BallsinPocket [i - 21]) == 0)
    {
      BallsinPocket [i - 21] = 1;
      Serial.print('z');
      delay (500);
      Serial.print('^');
      delay (250);
      Serial.print(Ballcodes [i - 21]);
      delay (250);
      Serial.print(Ballcodes [i - 21]);
      shutter = CLOSED;
    }
  }
}
A F K P U
B G L Q V
C H M R W
D I N S X
E J O T Y
BALLCODES
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
R.O.
R.O.
< LEFT
RIGHT >
[ R ]
'9 '4 25 '6 12
'1 19 22 24 '8
'2 '7 16 '5 14
11 22 13 21 '3
15 18 17 20 10
BACKGLASS