Sunday, August 7, 2016

i2c 2 Pi v0.6 - Arduino i2c Slave

i2c 2 Pi - Arduino i2c Slave

(Go back to i2c article)

// new i2c to Pi transceiver
//
// 8/2/16:0837 - version 0.51
// 8/3/16:0832 - version 0.6
//

#include <Wire.h>
#include <Servo.h>
#include <string.h>

#define SLAVE_ADDR 0x08
#define END_OF_STR '\x00'
#define SIG_BASE 0xA0
#define MAXSTR 20
#define CMD 1
#define CEND 2
#define CGET 4
#define CDATA 5
#define CDEND 6
#define WSLCT 7
#define WDATA 8
#define WDEND 9

#define DEBUG 1

const int flashpin = 13;

char recvStr[MAXSTR + 1];

char cdat[MAXSTR + 1];
int ccnt = 0;
unsigned char cmode = CMD;
    //
    // pin/function maps
    // make sure pins are excluded from operations that are NOT good
    // there MUST be a -1 at the end of each list unless ALL possible pins are included
    //
    // note: can really only control three analog devices at once!
    //    if pins 5 and 6 are used for PWM, the delay() and millis() functions won't work right.
    //    ...so pins 5,6 must be same freq; 9,10 same; 3,11 same
    //
    //Timer output  Arduino Uno pins
    //OC0A          6  
    //OC0B          5  
    //OC1A          9  
    //OC1B          10   
    //OC2A          11   
    //OC2B          3  
    //
const unsigned char alimit = 6, dlimit = 14;
unsigned char algList[6] = {0, 1, 2, 3, -1};      // can be pins 0-3 (avoid SCL/SDA)
unsigned char digiList[14] = {2, 4, 7, 8, 10, 12, -1};// can be pins 2-13 (avoid serial ports)
unsigned char digoList[14] = {13, -1};            // can be pins 2-13 (avoid serial ports)
unsigned char mtrList[6] = {6, -1};               // can be any of 3,5,6,9,10,11 but see above
unsigned char srvList[6] = {9, -1};               // can be any of 3,5,6,9,10,11 but see above
unsigned char tonList[6] = {11, -1};              // can be any of 3,5,6,9,10,11 but see above
                                                  // ...but no pwm on 3 or ll if tone is on
Servo servo[alimit];

void setup() {

  if (DEBUG == 1) {
    Serial.begin(9600);
  }
    // setup I2C stuff
  Wire.begin(SLAVE_ADDR); 
  Wire.onRequest(sendData);
  Wire.onReceive(receiveData);
  strcpy(recvStr, "K");
  cdat[0] = '\0';
  
    // init servos and wake them up
  for (int i = 0; i < alimit; i++) {
    if (srvList[i] == -1) break;
    else {
      servo[i].attach(srvList[i]);
      servo[i].write(5);
      delay(500);
      servo[i].write(150);
      delay(500);
      servo[i].write(90);
    }
  }
    //init signal LED
  pinMode(flashpin, OUTPUT);
  digitalWrite(flashpin, LOW);
  delay(200);
  digitalWrite(flashpin, HIGH);
  delay(200);
  digitalWrite(flashpin, LOW);
}

void loop() {
      //
      // see if there is a command to process
      //
  if (strcmp(recvStr, "K") != 0) {
      // let us know somethings happening
      //
      DebugOut("Data rcvd:");
      DebugOut(recvStr);
      //
    //do something with received command
    if (recvStr[0] == 'S' && strlen(recvStr) >= 4 ) {
      char rtmp[6];
      int svnum = ((int) (recvStr[1])) - 48;
      unsigned char pinOK = pinCheck('s', svnum);
      if (pinOK != -1) {
        int slew = 90, mflag = 0;
        for (int i = 0; i < 6; i++) {
          rtmp[i] = recvStr[i+3];
          if (rtmp[i] == '\0') break;
          if (rtmp[i] == 'm' || rtmp[i] == 'M') {
            rtmp[i+1] = '\0';
            mflag = 1;
            break;
          }
        }
        rtmp[5] = '\0';
        slew = atoi(rtmp);
        if (mflag && slew > 500 && slew < 2100 ) servo[svnum].writeMicroseconds(slew);
        else if (!mflag && slew >= 5 && slew <= 160) servo[svnum].write(slew);
      }
    }  // end of servo slew

    if (recvStr[0] == 'M' && strlen(recvStr) >= 4 ) {
      char rtmp[6];
      int mtnum = ((int) (recvStr[1])) - 48;
      unsigned char pinOK = pinCheck('m', mtnum);
      if (pinOK != -1) {
        int mspeed = 0;
        for (int i = 0; i < 6; i++) {
          rtmp[i] = recvStr[i+3];
          if (rtmp[i] == '\0') break;
        }
        rtmp[5] = '\0';
        mspeed = atoi(rtmp);
        if (mspeed >= 0 && mspeed <= 255) {
            pinMode(pinOK, OUTPUT);
            analogWrite(pinOK, mspeed);
        }
      }
    }  // end of motor speed

    if (recvStr[0] == 'T' && strlen(recvStr) >= 4 ) {
      char rtmp[7];
      int newtpin, freq = -2;
      unsigned char i = 1, j = 0;
      while (j != 99) {
        switch (freq) {
        case -2:
          rtmp[j++] = recvStr[i++];
          break;
        case -1:
          rtmp[j] = '\0';
          newtpin = atoi(rtmp);
          freq = 0; j = 0;
          break;
        case 0:
          if (recvStr[i] == '\0') {
            rtmp[j] = '\0';
            if (strlen(rtmp) > 0) freq = atoi(rtmp);
            j = 99;
          } else rtmp[j++] = recvStr[i++];
          break;
        }
        if (recvStr[i] == '-') {i++; freq = -1;}
      }
      unsigned char pinOK = pinCheck('t', newtpin);
      if (pinOK != -1) {          
        
        char dummy[10];
          DebugOut("pin:");
          DebugOut(itoa(newtpin, dummy, 10));
          DebugOut("freq:");
          DebugOut(itoa(freq, dummy, 10));
        
        if (freq == 0) { pinMode(newtpin, OUTPUT); noTone(newtpin); }
        else { pinMode(newtpin, OUTPUT); tone(newtpin, freq); }
      }
    }  // end of write to digital pin

    
    if (recvStr[0] == 'F' && strlen(recvStr) >= 4 ) {
      char rtmp[6];
      int newfpin;
      for (int i = 0; i < 6; i++) {
        rtmp[i] = recvStr[i+3];
        if (rtmp[i] == '\0') break;
      }
      newfpin = atoi(rtmp);
      unsigned char pinOK = pinCheck('o', newfpin);
      if (pinOK != -1) { 
        pinMode(newfpin, OUTPUT);
        if (recvStr[1] == '0') digitalWrite(newfpin, LOW);
        else digitalWrite(newfpin, HIGH);
      }
    }  // end of write to digital pin
      // and reset the data for next time 'round..
    strcpy(recvStr, "K");
  }
}

void DebugOut(char *dbgstr) {
  if (DEBUG == 1) {
    Serial.println(dbgstr);
  }
}

unsigned char pinCheck(char ptype, unsigned char thepin) {
  unsigned char res = -1;
  switch (ptype) {
    case 'i':             // digital read
      for (int i = 0; i < dlimit; i++) {
        if (digiList[i] == -1) break;
        else if (digiList[i] == thepin) { res = i; break; }
      }
      break;
    case 'o':             // digital write
      for (int i = 0; i < dlimit; i++) {
        if (digoList[i] == -1) break;
        else if (digoList[i] == thepin) { res = i; break; }
      }
      break;
    case 't':             // tone output
      for (int i = 0; i < dlimit; i++) {
        if (tonList[i] == -1) break;
        else if (tonList[i] == thepin) { res = i; break; }
      }
      break;
    case 'a':             // analog read
      for (int i = 0; i < alimit; i++) {
        if (algList[i] == -1) break;
        else if (algList[i] == thepin) { res = i; break; }
      }
      break;
    case 'm':             // pwm output
      for (int i = 0; i < alimit; i++) {
        if (mtrList[i] == -1) break;
        else if (thepin == i) {res = mtrList[i]; break; }
      }
      break;
    case 's':             // servo output
      for (int i = 0; i < alimit; i++) {
        if (srvList[i] == -1) break;
        else if (thepin == i) { res = i; break; }
      }
      break;
    default:
      res = -1; break;
  }
  return res;
}

int getSensor(int isens, char sdata[MAXSTR+1]) {

  char tstr[5];
    // debugging
      itoa(isens, tstr, 10);
      DebugOut("Data req:");
      DebugOut(tstr);
    //
  if (isens > 96 && isens < 103) {
    // read analog pin senscode - 97
    unsigned char pinOK = pinCheck('a', isens - 97);
    if (pinOK != -1) {
      char szdat[MAXSTR + 1] = "\0";
      strcpy(sdata, "AV:");
      int isdat = analogRead(algList[pinOK]);
      itoa(isdat, szdat, 10);
      strcat(sdata, szdat);
    }
  } else if (isens > 64 && isens < 85) {
    unsigned char pinOK = pinCheck('i', isens - 65);
    if (pinOK != -1) {
      int isdat;
      char szdat[2];
      strcpy(sdata, "DV:");
      pinMode(digiList[pinOK], INPUT);
      isdat = digitalRead(digiList[pinOK]);
      itoa(isdat, szdat, 10);
      strcat(sdata, szdat);
    }
  } else {
    strcpy(sdata, "NOP");
  }
  return strlen(sdata);
}

void receiveData(int thebytes) {
  
  char tstr[2];
  tstr[0] = (char) (48 + cmode);
  tstr[1] = '\0';
    // debugging
      DebugOut("I2C recv:");
      DebugOut(tstr);
    //
  
  while(Wire.available()) {
    char c = Wire.read();
    int ic = ((unsigned char) c);
    switch (cmode) {
      case CMD:
        switch (c) {
          case '1':
            cmode = CMD;  // check status, sort of a NOP
            break;
          case '4':
            cmode = CGET;  // data is coming
            break;
          case '7':
            cmode = WSLCT;  // data is wanted from a pin or something
            break;
        }
        break;
      case WSLCT:
        getSensor(ic, cdat);
        ccnt = 0;
        cmode = WDATA;
        break;
      case CGET:
        cdat[0] = c;
        cdat[1] = '\0';
        ccnt = 1;
        cmode = CDATA;
        break;
      case CDATA: {
        if (c == '\0') {
          ccnt = 0;
          strcpy(recvStr, cdat);
          cmode = CDEND;
            /* flash so we know something worked
          digitalWrite(flashpin, LOW);
          delay(100);
          digitalWrite(flashpin, HIGH);
          delay(100);
          digitalWrite(flashpin, LOW);
            */
        } else {
          cdat[ccnt++] = c;
          cdat[ccnt] = '\0';
        }
        break; }
      default:
        break;
    }
  }
}

void sendData() {
  
  char tstr[2];
  tstr[0] = (char) (48 + cmode);
  tstr[1] = '\0';
    // debugging
      DebugOut("I2C send:");
      DebugOut(tstr);
    //
  switch (cmode) {
    case WSLCT:
    case CDATA:
    case CGET:
    case CMD:
      Wire.write(cmode + SIG_BASE);
      break;
    case WDATA: {
      int clen = strlen(cdat);
      Wire.write(cdat[ccnt]);
      ccnt++;
      if (ccnt == clen) {
        cmode = WDEND;
        strcpy(cdat, "\0");
        ccnt = 0;
      }
      break; }
    case CDEND:
    case WDEND:
      Wire.write(cmode + SIG_BASE);
      cmode = CMD;
      break;
  }
}

No comments:

Post a Comment