Friday, May 23, 2014

Arduino Code(2) - Web/Arduino/Adam

Let's make a very simple protocol to use for WebSocket.

For Digital Out:
     Turning on: "DOn=ON"
     Turning off: "DOn=OFF"
     n: channel number 0-7

For Digital In:
     If you send "DI" it returns "bbbbbbbb".
     'b' is each input channel. It either becomes '0' or '1'.


#include <SPI.h>
#include <Ethernet.h>
#include <WebSocket.h>
#include <SoftwareSerial.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0x25, 0xC4 };
byte ip[] = { 192, 168, 219, 16 };
WebSocket wsServer;

int DE485 = 2;
SoftwareSerial Soft485(3, 4);

char rx485Ln[8];
int rx485ix;
char bitMap[8];

void AdamReceiver(void);
void hexToBit(char hex, int p);

void setup() {
 Serial.begin(9600); // Arduino Sketch Serial Monitor

 Soft485.begin(9600);
 pinMode(DE485, OUTPUT);

 Ethernet.begin(mac, ip);
 wsServer.registerConnectCallback(&onConnect);
 wsServer.registerDataCallback(&onData);
 wsServer.registerDisconnectCallback(&onDisconnect);
 wsServer.begin();
 delay(100);

 rx485ix = -1;
}

void loop() {
 wsServer.listen();
 AdamReceiver();
}

void onConnect(WebSocket &socket) {
 Serial.println("onConnect called");
}

void onDisconnect(WebSocket &socket) {
 Serial.println("onDisconnect called");
}

void onData(WebSocket &socket, char* rxLn, byte rxSz) {
 // Digital Out
 // It is either "DOn=ON" or "DOn=OFF". n = "0" - "7"
 // It would really be nice if we can parse "DO", "=ON",
 // "=OFF"; however, we are not focusing on this.
 // In "DO" we are only checking for "O" and for "=ON" & 
 // "=OFF", we will only check for "N".
 if(rxLn[1] == 'O') {
  // RS-485 will be in TX mode when DE is high
  digitalWrite(DE485, HIGH);
  // We send to ADAM-4050 "#001n01"<cr> if ON or
  // "#001n00"<cr> if OFF.
  Soft485.write("#001");
  Soft485.write(rxLn[2]); // n = "0" - "7"
  Soft485.write('0');
  if(rxLn[5] == 'N')
   Soft485.write('1');
  else
   Soft485.write('0');
  Soft485.write(0x0D);
  digitalWrite(DE485, LOW); // When finished, DE must be low
 }

 // Digital In
 // We are only looking for "I" in "DI"
 else if(rxLn[1] == 'I') {
  digitalWrite(DE485, HIGH);
  Soft485.write("$006"); // We send "$AA6"<cr> to ADAM-4050
  Soft485.write(0x0D);
  digitalWrite(DE485, LOW);
 }
}

// ADAM-4050 sends "!ooii00"<cr> as reply.
// The message starts with "!" and ends in <cr>, and there are 6
// bytes in between. The input data are the "ii". For more 
// information look at ADAM - Web/Arduino/Adam posting.
void AdamReceiver(void) {
 char rxChr;

 if(Soft485.available()) {
  rxChar = Soft485.read();
  if(rxChr == '!')
   rx485ix = 0; // message starts with "!"
  else if(rx485ix >= 0) {
   if(rxChr == 0x0d) { // message ends with <cr>
    //!ooii00<cr> Between "!" and <cr> there needs to be
    // 6 bytes
    if(rx485ix == 6) {
     hexToBit(rx485Ln[2], 0);
     hexToBit(rx485Ln[3], 4);
     wsServer.send(bitMap, 8);
    }
    rx485ix = -1; // it needs to be sync to "!" again
   }
   else {
    rx485Ln[rx485ix++] = rxChr;
    if(rx485ix > 6)
     // it cannot be greater than 6 bytes.
     // Re-sync to "!".
     rx485ix = -1;
   }
  }
 }
}

// We send "bbbbbbbb" to WebSocket. b is equal to each input channel, and it becomes either '0' or '1'.
void hexToBit(char hex, int p) {
 int i;

 if(hex >= 'A')
  hex = hex - 0x41 + 10;
 else
  hex -= '0';
 hex ^= 0x0f;

 for(i = 0; i < 4; i++) {
  if(hex & 0x08)
   bitMap[p + i] = '1';
  else
   bitMap[p + i] = '0';
  hex <<= 1;
 }
}



The code can be downloaded from:
https://github.com/michelleseo/Arduino_Web/blob/master/WSAdam/WSAdam.ino