Sunday, August 7, 2016

Ardxcv ver 0.21 - I2C Master for Raspberry Pi

Ardxcv ver 0.21 - I2C Master for Raspberry Pi

(Go back to i2c article)

/* Peter Mount's I2C Pi Master..
 modified 7/20/16 by Pat Struthers

 general purpose i2c transceiver to Arduino
 all good so far, 15:31 7/20 adding general purpose send  
 ver0.2 (7/30) - modularization
  definition of i2ccom, etc.
 
*/
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// Arduino address
#define ARD_ADDRESS 0x08
#define MAX_STR 20
#define SIG_BASE 0xA0
#define ARD_SLEEP 10000


//proto for i2ccom function
//
// devid = i2c device address
// devname = i2c bus name 
// cmd = command string e.g "4 F1-13" to turn on PIN 13
// res = received bytes
// dbg = debug flag
//
int i2ccom(int devid, char *devname, char *cmd, char *res, int dbg);
 // return values:
 // -9: no command string given, bus and device ok
 // -1: bus not available
 // -2: device not available
 // >0, x: command x completed
 // -3: unrecognized command 

// the main deal
int main(int argc, char** argv) {
  //I2C bus: for Pi V1 use i2c-0
 char *busname = "/dev/i2c-1";
  // other inits
 char cmd[MAX_STR + 1];
 char sbuf[MAX_STR + 1] = "\0";
 int dummy;

 int debugflag = 0;
 int ardaddr = ARD_ADDRESS;

  // any command line args?
 if (argc == 1) {
  printf("ardxcv - Pi to Arduino I2C transceiver\n");
  printf("--------------------------------------\n");
  printf("get status  : ardxcv 1\n");
  printf("query pins  : ardxcv 7 <pincode>\n");
  printf("   pincode - A-F (analog), a-z (digital)\n");
  printf("send command: ardxcv 4 <data>\n");
  printf("   data - no more than 20 characters, ASCII only\n\n");
  printf("option -D      : debug\n");
  printf("option -A<addr>: address of I2C devide\n");
  printf("option -B<bus> : I2C bus number (0 or 1)\n");
  exit(1);
 } else {
  int i = 1;
  while(i < argc) {
   if (argv[i][0] == '-') {   //--handle options
    switch (argv[i][1]) {
     case 'D': 
      debugflag = 1;
      break;
     case 'A':
      ardaddr = (int)(argv[i][2]) - 32;
      break;
     case 'B':
      if (argv[i][2] == '0') busname[strlen(busname)] = '0';
      if (argv[i][2] == '1') busname[strlen(busname)] = '1';
      break; 
    }
    i++;
   } else { 
    strcpy(cmd, argv[i++]);
    if (i < argc && argv[i][0] != '-') {
     strcat(cmd, " ");
     strcat(cmd, argv[i++]);
    }
   }
  }
 } 
 if (ardaddr < 3 || ardaddr > 13) {
  printf("I2C: device address 0x%x out of range (3-13).", ardaddr);
  exit(1);
 }

  // do whatever command...
 dummy = i2ccom(ardaddr, busname, cmd , sbuf, debugflag);

  // print result
 printf("I2C: %s sent to 0x%x: status %d|result", cmd, ardaddr, dummy);
 if (strlen(sbuf) > 0) {
  printf(" %s\n", sbuf);
 } else printf(" NIL\n");
 exit (dummy);
}

// i2ccom

int i2ccom(int devid, char *devname, char *cmd, char *res, int dbg) {
 int retval = 0;
 int file;
 char sbuf[MAX_STR + 1] = "\0";
 int ccnt = 0;
 int cmode = 0;
 char cparm[MAX_STR + 1] = "\0";
 char ccmd[2];

  // see if bus is reachable
 if ((file = open(devname, O_RDWR)) < 0) {
  fprintf(stderr, "I2C: failed to access bus %s\n", devname);
  return(-1);
 } 
  // make sure device is there
 if (ioctl(file, I2C_SLAVE, devid) < 0) {
  fprintf(stderr, "I2C: failed to talk to device %x\n", devid);
  return(-2);
 }
  // get command string stuff;
 if (strlen(cmd) > 0) {
   cmode = (int)(cmd[0]-48);
  ccmd[0] = cmd[0];
  ccmd[1] = '\0';
  if (strlen(cmd) > 2) strcpy(cparm, cmd + 2);
 } else {
   // no command to process, exit and assume bus/device OK
  return(-9);
 }

 while(cmode != 0) {
   // write a byte, even if it's wrong
   //
  if (dbg != 0) printf("Mode %d before send.\n", cmode);
  switch(cmode) {
   case 1:
    write(file, ccmd, 1);
    cmode = 2;
    break;
   case 4:
    write(file, ccmd, 1);
    cmode = 5;
    break;
   case 5: {
    char stmp[2];
    stmp[0] = cparm[ccnt++]; 
    stmp[1] = '\0';
    write(file, stmp, 1);
    if (ccnt > MAX_STR || ccnt > strlen(cparm)) {
     ccnt = 0;
     cmode = 6;
    } 
    break; }
   case 6:
    write(file, "\0", 1);
    break;
   case 7:
    write(file, ccmd, 1);
    cmode = 8;
    break;
   case 8:
    write(file, cparm, 1);
    cmode = 9;
    break;
   case 9:
    write(file, "K", 1);
    break;
   default:
    cmode = 0;
    break;
  }
  usleep(ARD_SLEEP); 
   //
   // read a byte, now
   //
  char buf[2] = "\0";
  if (dbg != 0) printf("Mode %d before recv.\n", cmode);
  switch(cmode) {
   case 0:
    retval = -3;
    break;
   case 2:
    if (read(file, buf, 1) == 1) {
     if (dbg != 0) printf("Received (hex) %x\n", buf[0]);
     retval = 1;
     cmode = 0;
    }
    break;
   case 5:
   case 6:
    if (read(file, buf, 1) == 1) {
     if (dbg != 0) printf("Byte Send Acked (hex) %x\n", buf[0]);
     if (buf[0] > SIG_BASE + 5 || cmode == 6) {
      if (dbg != 0) printf("Received %x, All data sent!\n", buf[0]);
      retval = 4;
      cmode = 0;
     }
    }
    break;
   case 8:
    if (read(file, buf, 1) == 1) {
     if (dbg != 0) printf("Received (hex) %x\n", buf[0]);
    }
    break;
   case 9:
    if (read(file, buf, 1) == 1) {
     if (buf[0] >= SIG_BASE) {
      if (dbg != 0) printf("Received %x, Done getting bytes.\n", buf[0]);
      retval = 7;
      cmode = 0;
     } else {
      strcat(sbuf, buf);
      if (dbg != 0) printf("Received %x, %s so far.\n", buf[0], sbuf);
     }
    }
    break;
/*   default:
    if (read(file, buf, 1) == 1) {
     printf("Not sure why here, but..(hex) %x\n", buf[0]);
     werr = 9;
    }
    break;
*/
  }
  usleep(ARD_SLEEP);
 }
 close(file);
 if (retval == 7 && strlen(sbuf) > 0) strcpy(res, sbuf);
 return(retval); 
}



// end of ardi2c3.c

No comments:

Post a Comment