Tuesday, September 18, 2018

Don's Electronic Thing 09 -- New program!

This is the latest version of the program!

Included in this version:
  MicroScout Program 4 Protocol works!
  MicroScout Switches works!

Problems:
  It does work, but after a while the switches stop responding.  So the switches need to be turned off, and then back on.  (Why?  Have to figure that one out...)

The code:

/*
  Lego Connector Version 4
 by Donald Hosford (Donzerme@Yahoo.com)

 Last Update: 09/18/2018

 Purpose:
 -- Use an Arduino Uno to enable old Lego Computer Bricks to be
 controlled by any bluetooth enabled smart phone/tablet/PC etc.

 -- Working on:  VLL protocol

 ----------------------------
 Physical Pin assignments:

 pin 0 - BT transmit
 pin 1 - BT receive
 pin 2 - IR receiver unit
 pin 3 - IR transmit led
 pin 4 - MicroScout 1 led
 pin 5 - MicroScout 2 led
 pin 6 - MicroScout 3 led
 pin 7 - MicroScout 1 touch switch
 pin 8 - MicroScout 2 touch switch
 pin 9 - MicroScout 3 touch switch
 pin 10 - BT connect led?

 ----------------------------
 Commands:
 All commands are simple text characters.  Every command will start
 with a two letter device code (upper case for now).  Below is a
 list of Lego P-brick devices I intend to support.

 ----------------------------
 Command format: (Device)(unit id)(action)

 Devices: (So far -- this may change.)
 BM - Bionicle Manas
 MS - MicroScout (Program 4)
 PF - Power Functions
 RC - RCX
 SB - Spybot
 SC - Scout
 VL - MicroScout VLL

 ----------------------------
 Microscout:

 Device: MS

 Unit ID:
 0 - All units
 1 - First unit
 2 - Second unit
 3 - Third unit

 Action:
 0 - Stop motor
 1 - Forward rotation
 2 - Backwards rotation

 Switch Watcher
 MSS0 - Turn Switch watcher off.
 MSS1 - Turn Switch watcher on.

 Example: MS11 - MicroScout unit 1, Motor forwards.
 MS02 - All MicroScouts, motor backwards.

 ----------------------------
 VLL:

 Device: VL

 Unit ID:
 0 - All units
 1 - First unit
 2 - Second unit
 3 - Third unit

 Action:
 code 0 to 127
 I - Initialize microscout for vll?


 Examples:
 VL1100 - Send VLL code 100 to Microscout port 1,
 VL1I   - Initialize microscout port 1 for vll?
 Note: call VLLInit() first?  Then send VLL commands.

 ----------------------------
 */
// Code Start:

// init variables
String message = "";

// initialize MicroScout variables
int MSNum = 0;
int Action = 0;

//Array hold MicroScout data
int MSD[] = {
  0, 1, 1, 1
};

//Pin array to hold the assignments
int pin[] = {
  0, 4, 5, 6, 7, 8, 9, 3, 2, 0, 1
};
/*
  Pin[] array positions
 0 = space holder, not a pin number
 1 = MS1 Led
 2 = MS2 Led
 3 = MS3 Led
 4 = MS1 sw
 5 = MS2 sw
 6 = MS3 sw
 7 = IR transmitter led
 8 = IR receiver unit
 9 = BT transmitter
 10 = BT receiver
 */


// MS Switch Last Total
int LTot = 1000;

// Switch Debounce
// SwitchDebounce time in ms for microscout switches.
int SwitchDebounce = 100;

// Last Time Switches Checked
int LSC = millis();

// Current Time Checked
int CC = LSC;

// MS Switch Status
int MS1St = 0;
int MS2St = 0;
int MS3St = 0;

// MS Switch pins
int SW1=7;
int SW2=8;
int SW3=9;

// Switchtoggle 0=switch check off, 1=switch check on
int Switchtoggle = 1;
// Switchtoggle 0=switch check off, 1=switch check on
// Switchtoggle 0=switch check off, 1=switch check on

//VLL variables
int N = 0;
int N2 = 0;
int command = 0;

// Infared variables
//   None yet...

void setup() {
  LSC = CC;


  //pinmodes
  pinMode(pin[1], OUTPUT); // MS1 led
  pinMode(pin[2], OUTPUT); // MS2 led
  pinMode(pin[3], OUTPUT); // MS3 led
  pinMode(SW1, INPUT_PULLUP); // MS1 switch
  pinMode(SW2, INPUT_PULLUP); // MS2 switch
  pinMode(SW3, INPUT_PULLUP); // MS3 switch
  pinMode(pin[7], OUTPUT); // IR send
  pinMode(pin[8], INPUT); // IR receive
  pinMode(pin[9], OUTPUT); // BT send
  pinMode(pin[10], INPUT); // BT receive
  pinMode(pin[11], OUTPUT); // BT connect led

  //serial setup/output ready
  Serial.begin(9600);
  delay(5000); // give user time to open serial monitor.
  Serial.println("Ready");  //tell user its ready for commands


// ----------------------------
void loop() {
  message = "";




  // listen for message
  // receive messages from the serial monitor/BT HC-05 module
  while (Serial.available() == 0) {
    // loop until something is recieved from serial.

    // If Switchtoggle is on, then check status of switches.
    // report any changes from last check.
    if (Switchtoggle == 1) {
      MSSwitches();
    }

    // this code is remarked out, because it doesn't exist yet...
    // If IRToggle is on, then check status of IR reciever.
    //if (IRToggle == 1) {
    // IRWatcher();
    //} 
  }
  message = Serial.readString();
  Serial.print ("you typed: ");
  Serial.println(message);
  // process message
  if (message > "") {
    protocol();
  }
  // end of voidloop
}

// ----------------------------
void protocol() {
  // if message starts with a two letter code then 'gosub'
  // to appropriate 'subroutine'

  if (message.startsWith("MS")) {
    MicroScout();
  }

  if (message.startsWith("VL")) {
    VLL();
  }

  if (message.startsWith("RC")) {
    RCX();
  }

  if (message.startsWith("BM")) {
    Manas();
  }

  if (message.startsWith("SB")) {
    Spybot();
  }

  if (message.startsWith("SC")) {
    Scout();
  }

  if (message.startsWith("PF")) {
    PowerFunctions();
  }

}

// ----------------------------
void VLL() {
  // The main entry for MicroScout/Code Pilot VLL protocol.

  // Init variables
  String c = "";
  int CS = 0;
  int n = 0;

  // get message length
  int mlen = message.length();

  // retrieve MS number, and convert to number
  MSNum = message.charAt(2);
  MSNum = MSNum - 48;

  // retrieve action
  c = message.substring(3);
  Action = c.toInt();

  Serial.print (Action);

  //Serial.println(MSNum);
  //Serial.println(Action);

  // check for init action.
  if (Action == 73) {
    // Initalize VLL.
    VLLInit();
    // Done, clear message.
    message = "";
    Action = -1;
  }
  else {
    VLLSend();
  }
}

void VLLSend() {
  //retreive action, send it
  // This VLL code has been adapted from a python3 program by:
  // https://github.com/JorgePe/mindstorms-vll/blob/master/vll-atat.py

  //Serial.println("Start");

  // Init variables
  int CS = 0;
  int n = 0;
  int v = 0;
  // Delay long: 40ms
  int DLo = 38;
  // Delay short: 20ms
  int DSh = 19;

  Action = message.toInt();

  // vll send number
  //void VLLsend()
  //VLLstart
  // led off, delay 20ms
  digitalWrite(pin[MSNum], LOW);
  delay(20);

  // checksum calculation
  // checksum formulas:
  //         C or Perl: 7-((n+(n>2)+(n>>4))&7)
  //             Basic: 7-(n+int(n/4)+int(n/16)) mod 8
  //   Arduino Scratch: 7-(n+int(n/4)+int(n/16)) % 8

  // Arduino uno scratch MOD command: z = x % y

  n = Action;

  //Serial.println("---");
  //Serial.print(n);
  //Serial.print("/");

  // checksum calculation -- seems to be correct
  CS = 7 - (n + int(n / 4) + int(n / 16)) % 8;
  //Serial.print(CS);
  //Serial.print("/");

  // Shift the bits to the left, seven spaces.
  // Makes room for the number.
  CS = CS << 7;
  //Serial.print(CS);
  //Serial.print("/");

  // Add number.
  CS = CS + n;
  //Serial.println(CS);
  //Serial.println("---");

  // Read bits, and send them.
  for ( int i = 9; i >= 0; i--) {
    v = bitRead(CS, i);

    //Serial.print(i);
    //Serial.print("/");
    //Serial.print(v);
    //Serial.print("/");

    //Serial.print (i);

    if (v == 1) {
      //VLL1();
      //led on, delay 20ms, led off, delay 40ms
      //Serial.print("One");
      digitalWrite(pin[MSNum], HIGH);
      delay(DSh);
      digitalWrite(pin[MSNum], LOW);
      delay(DLo);
    }
    else {
      //VLL0();
      // Led on, delay 40ms, led off, delay 20ms
      //Serial.print("Zero");
      digitalWrite(pin[MSNum], HIGH);
      delay(DLo);
      digitalWrite(pin[MSNum], LOW);
      delay(DSh);
    }
    //Serial.print("/");
  }
  //VLLstop();
  // led on, delay 20ms, led off, delay 60ms, led on, delay 120ms
  digitalWrite(pin[MSNum], HIGH);
  delay(20);
  digitalWrite(pin[MSNum], LOW);
  delay(60);
  digitalWrite(pin[MSNum], HIGH);
  delay(120);
  digitalWrite(pin[MSNum], LOW);

  //vllpause();
  //led on, delay 150
  digitalWrite(pin[MSNum], HIGH);
  delay(150);
  digitalWrite(pin[MSNum], LOW);
  // all done, clear message.
  message = "";
  Action = -1;
  //Serial.println("Done");
}

void VLLInit() {
  // VLLinit() {
  // led on, delay 400ms, (led off?)
  digitalWrite(pin[MSNum], HIGH);
  delay(400);
  digitalWrite(pin[MSNum], LOW);

  // delay 2000ms?
  //delay(2000);
}

// ----------------------------
void MicroScout() {
  // The main entry for MicroScout program 4 protocol.
  String c = "";
  int d = 0;

  // pull MS number, and Action
  MSNum = message.charAt(2);
  MSNum = MSNum - 48;

  // get action  -- action "e"  integer
  c = message.substring(3);
  Action = c.toInt();
  d = Action;

  // code for all MS.
  if (MSNum == 0) {

    MSNum = 1;
    MSSend();
    Action = d;
    MSNum = 2;
    MSSend();
    Action = d;
    MSNum = 3;
    MSSend();
    // clear message
    message = "";
    Action = -1;
    MSNum = 0;
  }
  else {
    // code for 1 MS
    MSSend();
    // clear message
    MSNum = 0;
    Action = -1;
    message = "";
  }
}

void MSSend() {
  // code for MS program 4

  // MS switches toggle
  if (MSNum == 35) {
    if (Action == 0) {
      Switchtoggle = 0;
      Serial.println("MS Switches OFF");
    }
    else {
      Switchtoggle = 1;
      Serial.println("MS Switches ON");
    }
  }

  //check direction here
  //if needed do reverse blink
  if (Action == 1 && MSD[MSNum] == 2) {
    MSRevBlink();
    MSD[MSNum] = 1;
  }

  if (Action == 2 && MSD[MSNum] == 1) {
    MSRevBlink();
    MSD[MSNum] = 2;
  }

  // Action: stop motor
  if (Action == 0) {
    digitalWrite(pin[MSNum], LOW);
  }

  // Action: motor forwards
  if (Action == 1) {
    digitalWrite(pin[MSNum], HIGH);
  }

  // Action: motor backwards
  if (Action == 2) {
    digitalWrite(pin[MSNum], HIGH);
  }

  // all done, clear message.
  message = "";
  Action = -1;

}

void MSRevBlink() {
  digitalWrite(pin[MSNum], HIGH);
  delay(100);
  digitalWrite(pin[MSNum], LOW);
  delay(100);
  digitalWrite(pin[MSNum], HIGH);
  delay(100);
  digitalWrite(pin[MSNum], LOW);
  delay(100);
  digitalWrite(pin[MSNum], HIGH);
}

void MSSwitches() {

  CC = millis();

  // check MicroScout Switches and report changes in status if any.
  if ((CC - LSC) > SwitchDebounce) {

    int CTot = 1000;

    // read pins
    MS1St=digitalRead(SW1);
    MS2St=digitalRead(SW2);
    MS3St=digitalRead(SW3);

    // total statuses
    if (MS1St == 0) {
      CTot=CTot+100;
    }
    if (MS2St == 0) {
      CTot=CTot+10;
    }
    if (MS3St == 0) {
      CTot=CTot+1;
    }

    // check results
    if (CTot == LTot) {
      // if equal, do nothing.
    }
    else {
      //print CTot
      Serial.print("MS");
      Serial.println(CTot);
      LTot=CTot;
      LSC = CC;


    }
  }
}

void MVIdAct(){
  // Init variables
  String a = "";
  char b = 0;
  String c = "";
  int d = 0; 
  int e = 0;

  // get protocol -- protocol "a"  String
  a = message.substring(0,2);
  // get MS port address -- MS address "d"  integer
  b = message.charAt(2);
  d=b-48;
  // get action  -- action "e"  integer
  c = message.substring(3);
  e = c.toInt();
}


// ----------------------------
// code for RCX
void RCX() {
  Serial.println("RCX");
}

// ----------------------------
// code for Bionicle Manas
void Manas() {
  Serial.println("Bionicle Manas");
}

// ----------------------------
// code for Spybot
void Spybot() {
  Serial.println("Spybot");
}

// ----------------------------
// code for Scout brick
void Scout() {
  Serial.println("Scout");
}

// ----------------------------
// code for Power Functions
void PowerFunctions() {
  Serial.println("Power9 Function");
}