(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