Arduino + Processing GUI "mini Projekt"

Hallo zusammen,
wer mal einen Blick riskieren möchte: Bitteschön
(Das ganze ist noch in der “beta” und hat noch einiges an effizienz-Potential)
Gruß grillgemuese
Arduino:

//SerialGUI_Arduino_v3 13.02.2019
//???sending back command to validate???
//to receive int use lowByte() & highByte()
//byte in processing = -128/127
const char arduinoId = 45, processingId = 25;
//pins:
const uint8_t DIPin[2] = { 2, 3 };
const uint8_t DOPin[2] = { 4, 13 };
const uint8_t AIPin[2] = { A0, A1 };
const uint8_t AOPin[2] = { 9, 10 };
//serial commands:
const byte readDI1 = 0x02, readDI2 = 0x03;
const byte readAI1 = 0x12, readAI2 = 0x13;
const byte setDO1 = 0x22, setDO2 = 0x23;
const byte setAO1 = 0x32, setAO2 = 0x33;
//serial setting:
const int baudRate = 19200;
const uint32_t serialTimeout = 2000; //ms
//function prototypes:
void serialConnect();

void setup()
{
  Serial.begin(baudRate);
  //Serial.setTimeout(500);
  for (uint8_t x = 0; x < sizeof(DOPin); x++) pinMode(DOPin[x], OUTPUT);
  for (uint8_t x = 0; x < sizeof(AOPin); x++) pinMode(AOPin[x], OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  while (!Serial) {}
  //wait for valid processingId
  serialConnect();
  Serial.flush();
}//void setup() END


void loop()
{
  byte inLength = 0;
  byte inBuffer[4] = {0, 0, 0, 0}; //cmd,valueLOW,valueHIGH,'\n'

  static uint32_t lastSerialMs = millis();

  //serialTimeout
  if (millis() - lastSerialMs >= serialTimeout)
  {
    for (uint8_t x = 0; x < sizeof(DOPin); x++) digitalWrite(DOPin[x], LOW);
    for (uint8_t x = 0; x < sizeof(AOPin); x++) digitalWrite(AOPin[x], LOW);
    while (Serial.available() == 0)
    {
      //only needed if auto-reset is disabled
      serialConnect();
      lastSerialMs = millis();
    }
  }

  if (Serial.available() > 0)
  {
    inLength = Serial.readBytesUntil('\n', inBuffer, sizeof(inBuffer));
    lastSerialMs = millis();
  }
  if (inLength > 0)
  {
    byte tempByte = 0;
    int tempInt = 0;
    //first byte is the command/address
    switch (inBuffer[0])
    {
      case readDI1:
        for (uint8_t x = 0; x < sizeof(DIPin); x++) bitWrite(tempByte, x, digitalRead(DIPin[x]));
        Serial.write(tempByte);
        break;

      case readAI1:
        tempInt = analogRead(AIPin[0]); //2bytes!
        Serial.write(lowByte(tempInt));
        Serial.write(highByte(tempInt));
        break;

      case readAI2:
        tempInt = analogRead(AIPin[1]);
        Serial.write(lowByte(tempInt));
        Serial.write(highByte(tempInt));
        break;

      case setDO1:
        for (uint8_t x = 0; x < sizeof(DIPin); x++) digitalWrite(DOPin[x], bitRead(inBuffer[1], x));
        break;

      case setAO1:
        //tempByte = Serial.read();
        analogWrite(AOPin[0], inBuffer[1]);
        break;

      case setAO2:
        analogWrite(AOPin[1], inBuffer[1]);
        break;
        //default:
    }
  }
}//void loop() END


void serialConnect()
{
  bool validId = false;
  while (!validId)
  {
    if (Serial.available() > 0)
    {
      if (Serial.read() == processingId)
      {
        Serial.write(arduinoId);
        validId = true;
      }
    }
  }
}//void serialConnect() END

SerialGUI.PNG

Processing: TAB 1 GUI

//SerialGUI_Processing_v3 13.02.2019
/*ToDo:
 *total cleanup!!!
 *private/public not needed for TAB
 *only transmit data if values changed?
 *reduce draw() calculations
 *update serialTimeout procedure
   *timeout calc: lastSerialRequestMs - ...
*/
/*Description:
  *processing acts as serial "master".
  *arduino is only sending data if requestet from master
  *
*/
//import serialHandler; //?
//final variables:
final byte arduinoId = 45, processingId = 25;
final byte X = 0, Y = 1;

final byte DIPin1 = 2, DIPin2 = 3;
final byte AIPin1 = 0, AIPin2 = 1;
final byte DOPin1 = 4, DOPin2 = 13;
final byte AOPin1 = 9, AOPin2 = 10;

interface Button {
  byte
  Name1 = 0,
  Name2 = 1;
};
interface Output {
  byte
  Name1 = 0,
  Name2 = 1;
};
interface Slider {
  byte
  Name1 = 0,
  Name2 = 1;
};
final int normalFontSize = 12, titleFontSize = 14;

final int generalSpace = 2;
final int buttonSize = 25;    //diameter of rect's X=Y
final int buttonStartPos = buttonSize;
final int circleSize = buttonSize;
final int circleStartPos = circleSize + circleSize/2 + 1;
final int circleSpace = generalSpace;
final int sliderStartPos = 1;
final int sliderSize = 15;
final int sliderSpace = generalSpace; 
//colors:
final color wndColor = #F0F0F0;  //window color
final color normalFontCol = #000000, titleFontCol = #A50202;
final color colorOFF = #FF0000, colorON = #00FF0A;
final color rectColBorder = #DBB837;
final color circColBorder = #0D26FA;
final color sliderBorder = #03FA10;
//variables:
//private long lastUpdateMs = 0;
byte arduinoDIByte1 = 0; //or as array? , arduinoDIByte2 = 0;
byte DOByte1 = 0, lastDOByte1 = 1;
//public int arduinoAOVal1 = 0, arduinoAOVal2 = 0;
int arduinoAIVal1 = 0, arduinoAIVal2 = 0;

int sliderEndPos = 0;

boolean[] buttonState = {false, false};
boolean[] sliderState = {false, false};
int[] AOVal = {0, 0}, lastAOVal = {1, 1};
int textXPos = buttonSize + 5; //define space from button
int[] textYPos = {0, 0};
int[][] rectPos = { {0,0}, {0,0} };
int[][] circPos = { {0,0}, {0,0} };
int[][] sliderPos = { {0,0}, {0,0} };


void setup()
{
  size(250, 200);
  serialStart();
  serialConnect(); //is blocking!
  //position of Button.Name1 [rect]
  rectPos[Button.Name1][X] = 1;
  rectPos[Button.Name1][Y] = buttonStartPos;
  //position of Button.Name2
  rectPos[Button.Name2][X] = rectPos[Button.Name1][X];
  rectPos[Button.Name2][Y] = rectPos[Button.Name1][Y] + buttonSize + generalSpace;
  //position of Output.Name1 (circle)
  circPos[Output.Name1][X] = width/2 + circleSize/2 + 3;
  circPos[Output.Name1][Y] = circleStartPos;
  //position of Output.Name2 (circle)
  circPos[Output.Name2][X] = circPos[Output.Name1][X]; 
  circPos[Output.Name2][Y] = circPos[Output.Name1][Y] + circleSize + circleSpace;
  //position of Slider.Name1 [moveable rect]
  sliderPos[Slider.Name1][X] = sliderStartPos;
  sliderPos[Slider.Name1][Y] = rectPos[Button.Name2][Y] + 45 + normalFontSize;
  //position of Slider.Name1 [moveable rect]
  sliderPos[Slider.Name2][X] = sliderStartPos;
  sliderPos[Slider.Name2][Y] = sliderPos[Slider.Name1][Y] + sliderSize + sliderSpace + normalFontSize;
  //calculate sliderEndPos
  sliderEndPos = width/2 - sliderSpace - sliderSize;
  //calculate text pos
  for (int t = 0; t < 2; t++) textYPos[t] = rectPos[t][Y] + buttonSize - normalFontSize / 2;
}//void setup() END


void draw() //like void loop()
{
  // !!! reduce calculations !!!
  //window:
  background(wndColor);  //wndBackground color
  //text: titles
  fill(titleFontCol);
  textSize(titleFontSize);
  text("Digital OUT", 1, titleFontSize);
  text("Digital IN", width/2 + generalSpace, titleFontSize);
  text("Analog OUT", 1, rectPos[Button.Name2][Y] + buttonSize + generalSpace + titleFontSize);
  text("Analog IN", width/2 + generalSpace, rectPos[Button.Name2][Y] + buttonSize + generalSpace + titleFontSize);
  //text: normal
  fill(normalFontCol);
  textSize(normalFontSize);
  text("Button Pin: " + DOPin1, textXPos, textYPos[0]);
  text("Button Pin: " + DOPin2, textXPos, textYPos[1]);
  text("State Pin: " + DIPin1, textXPos+width/2, textYPos[0]);
  text("State Pin: " + DIPin2, textXPos+width/2, textYPos[1]);
  text("PWM Pin: " + AOPin1 + " = " + AOVal[0], sliderStartPos, sliderPos[Slider.Name1][Y] - sliderSpace);
  text("PWM Pin: " + AOPin2 + " = " + AOVal[1], sliderStartPos, sliderPos[Slider.Name2][Y] - sliderSpace);
  text("Pin: A" + AIPin1 + " = " + arduinoAIVal1, width/2 + 2, sliderPos[Slider.Name1][Y] - sliderSpace);
  text("Pin: A" + AIPin2 + " = " + arduinoAIVal2, width/2 + 2, sliderPos[Slider.Name1][Y] + 1 + normalFontSize);
  //text: COMPort
  fill(#764401);
  text("Port: " + portName + " State:", 1, height - normalFontSize/2);
  //text: ArId + PrId
  fill(#0014B9);
  text("ArId: " + arduinoId, width/2 + generalSpace, height - normalFontSize/2);
  text("PrId: " + processingId, width - 55, height - normalFontSize/2);
  //(under)line:
  stroke(0);
  //underline titles:
  //line (width/2+1, normalFontSize + 1, width/2 +textWidth(InputTitle) + 9, normalFontSize + 1);
  //lines: splitframe
  line(0, rectPos[Button.Name2][Y] + buttonSize + generalSpace,width,rectPos[Button.Name2][Y] + buttonSize + generalSpace);
  line(0,height - normalFontSize * 2,width,height - normalFontSize * 2);
  line(width/2, 0, width/2, height /*- normalFontSize * 2*/); //split screen vertical

  //buttons:
  for (int b = 0; b < 2; b++)
  {  
    stroke(rectColBorder);
    if (buttonState[b]) fill(colorON);
    else fill(colorOFF);
    rect(rectPos[b][X], rectPos[b][Y], buttonSize, buttonSize);
  }
  //inputs:
  for (byte i = 0; i < 2; i++)
  {
    stroke(circColBorder);
    if (bitRead(arduinoDIByte1, i)) fill(colorON);
    else fill(colorOFF);
    //println("arDIb:" + bitRead(arduinoDIByte1, i));
    circle(circPos[i][X], circPos[i][Y], circleSize);
  }
  //sliders:
  for (int s = 0; s < 2; s++)
  {
    if (sliderState[s])
    {
      sliderPos[s][X] = constrain(mouseX - sliderSize/2, sliderStartPos, sliderEndPos);
      AOVal[s] = int(map(sliderPos[s][X], sliderStartPos, sliderEndPos, 0, 255));
    }
    stroke(0);
    fill(#F7FAA4);
    rect(sliderStartPos, sliderPos[s][Y], sliderEndPos + sliderSize - 1, sliderSize);
    //stroke(sliderBorder);  //sliderBorder color
    fill(#000FAD);
    rect(sliderPos[s][X], sliderPos[s][Y], sliderSize, sliderSize);
  }
  //COMStatus rect
  if (serialTimeoutState) fill(colorOFF);
  else fill(colorON);
  rect(width/2 - 18, height - 20, 16, 16);
  
  //update Arduino values
  updateArduinoValues();
  serialUpdate();
}//void draw() END


void mousePressed()
{
  for (int b = 0; b < 2; b++)
  {
    if (overRect(rectPos[b][X], rectPos[b][Y], buttonSize, buttonSize))
    {
      buttonState[b] = !buttonState[b];
    }
  }
  for (int s = 0; s < 2; s++)
  {
    sliderState[s] = overRect(sliderPos[s][X], sliderPos[s][Y], sliderSize, sliderSize);
  }
}//void mousePressed() END


void mouseReleased()
{
  for (int s = 0; s < 2; s++)
  {
    sliderState[s] = false;
  }
}//void mouseReleased() END


boolean overRect(final int x,final int y,final int wid,final int hei)  
{
  if (mouseX >= x && mouseX <= x + wid &&
      mouseY >= y && mouseY <= y + hei)
  {
    return true;
  } else {
    return false;
  }
}//boolean overRect(.) END


void updateArduinoValues()
{
  for (byte b = 0; b < 2/*7*/; b++) DOByte1 = bitWrite(DOByte1, b, buttonState[b]);
  //for (byte b = 0; b < 7; b++) arduinoDOByte2 = bitWrite(arduinoDOByte2, b, buttonState[b+7]);
}//void updateArduinoValues() END


//bitwise functions:
boolean bitRead(final byte val, final byte pos)
{
  return boolean(val & 1 << pos);
}//boolean bitRead(.) END

//would be better with usage of reference/pointer.
byte bitWrite(byte val, final byte pos, final boolean state)
{
  if (!bitRead(val, pos) && state) val |= 1 << pos;
  else if (bitRead(val, pos) && !state) val ^= 1 << pos;
  return val;
}//byte bitWrite(.) END

Processing: TAB 2 serialHandler

//serialHandler 13.02.2019
import processing.serial.*;

Serial myPort;

final int baudRate = 19200;
final long serialTimeout = 2000; //ms
//serial commands:
final char commandEnd = '\n';
interface Cmd
{
  byte
  pause = 0x01,
  readDI1 = 0x02,  //DI Pin 0-7 (0=DIPin1,...)
  //readDI2 = 0x03,  //DI Pin 8-13 (15) 
  readAI1 = 0x12,  //AI Pin AIPin1
  readAI2 = 0x13,  //AI Pin AIPin2
  setDO1 = 0x22,   //DO Pin 0-7 (0=DOPin1,...)
  //setDO2 = 0x23,   //DO Pin 8-13 (15)
  setAO1 = 0x32,   //AO Pin AOPin1
  setAO2 = 0x33;   //AO Pin AOPin2
};
//variables:
boolean serialTimeoutState = false;
byte CmdStage = Cmd.pause, requestStage = 1;
long lastSerialMs = millis();
String portName = "";


void serialStart()
{
  portName = Serial.list()[0];
  //portName = "COM3";
  println("port: " + portName);
  myPort = new Serial(this, portName, baudRate);
}//void serialStart() END


void serialConnect()
{
  boolean validId = false;
  while (!validId)
  {
    myPort.write(processingId);
    delay(1000); // ! ! !
    if (myPort.available() > 0)
    {
      if (myPort.read() == arduinoId) 
      {
        validId = true;
        //reset variables:
        CmdStage = Cmd.pause;
        requestStage = 1;
        for (byte x = 0; x < /*sizeof()?*/2; x++) lastAOVal[x] += 1;
        lastDOByte1 += 1;
        serialTimeoutState = false;
        lastSerialMs = millis();
      }
    }
  }
  println("found Arduino!");
}//void serialConnect() END


void serialUpdate()
{
  //serialTimeout
  if (!serialTimeoutState && millis() - lastSerialMs >= serialTimeout)
  {
    serialTimeoutState = true;
    println("lost Arduino!");
  }
  else if (serialTimeoutState && millis() - lastSerialMs >= serialTimeout + 2000L)
  {
    serialConnect(); //is blocking!
  }
  
  final byte Request = 1, Receive = 2;
  int lowByte = 0, highByte = 0; //could not use byte 127/-128
  switch(CmdStage)
  {
    case Cmd.pause:
      if (myPort.available() == 0) CmdStage = Cmd.readDI1;
      else {
        println("ERROR #1");
        myPort.clear();
      }
      break;
      
    case Cmd.readDI1:
      switch(requestStage)
      {
        case Request:
          serialRequest(Cmd.readDI1);
          requestStage = Receive;
          break;
        case Receive:
          if (myPort.available() > 0)
          {
            arduinoDIByte1 = byte(myPort.read());
            requestStage = Request;
            //CmdStage = Cmd.readDI2;
            CmdStage = Cmd.readAI1;
          }
          break;
      }
      break;
      
    case Cmd.readAI1:
      switch(requestStage)
      {
        case Request:
          serialRequest(Cmd.readAI1);
          requestStage = Receive;
          break;
        case Receive:
          if (myPort.available() > 1)
          {
            lowByte = myPort.read();
            highByte = myPort.read();
            arduinoAIVal1 = (lowByte + (highByte << 8));
            requestStage = Request;
            CmdStage = Cmd.readAI2;
          }
          break;
      }
      break;
    
    case Cmd.readAI2:
      switch(requestStage)
      {
        case Request:
          serialRequest(Cmd.readAI2);
          requestStage = Receive;
          break;
        case Receive:
          if (myPort.available() > 1)
          {
            lowByte = myPort.read();
            highByte = myPort.read();
            arduinoAIVal2 = (lowByte + (highByte << 8));
            requestStage = Request;
            //CmdStage = Cmd.readAI3;
            CmdStage = Cmd.setDO1;
          }
          break;
      }
      break;
    
    case Cmd.setDO1:
      if (DOByte1 != lastDOByte1)
      {
        lastDOByte1 = DOByte1;
        serialTransmit(Cmd.setDO1, DOByte1);
      }
      //CmdStage = Cmd.setDO2;
      CmdStage = Cmd.setAO1;
      break;
    
    case Cmd.setAO1:
      if (AOVal[0] != lastAOVal[0])
      {
        lastAOVal[0] = AOVal[0];
        serialTransmitInt(Cmd.setAO1, AOVal[0]);
      }
      CmdStage = Cmd.setAO2;
      break;
      
    case Cmd.setAO2:
      if (AOVal[1] != lastAOVal[1])
      {
        lastAOVal[1] = AOVal[1];
        serialTransmitInt(Cmd.setAO2, AOVal[1]);
      }
      CmdStage = Cmd.pause; //back to pause
      break;
    default:
      CmdStage = Cmd.pause;
  }
}//void serialUpdate() END


void serialRequest(final byte command)
{
  myPort.write(command);
  myPort.write(commandEnd);
  updateSerialMs();
}//void serialRequest(.) END

void serialTransmit(final byte command, final byte value)
{
  myPort.write(command);
  myPort.write(value);
  myPort.write(commandEnd);
}//void serialTransmit(.,byte) END

void serialTransmitInt(final byte command, final int value)
{
  myPort.write(command);
  //if (value > 255) //low/highByte!!!
  myPort.write(value);
  myPort.write(commandEnd);
}//void serialTransmitInt(.) END

void updateSerialMs()
{
  lastSerialMs = millis();
}//void updateSerialMs() END