I've nothing but trouble trying to work with _every_ USB/Serial adapter on OpenBSD. Hacking on drivers didn't helped, so I tend to think our USB stack is quite poor.

But I don't blame; USB is a toy, and USB devices are toys. Getting real(tm) hardware you should solve your problems.

PS: This is my opinion, based on my experience. Your mileage may vary.

El 28/11/2011 7:17, Byron Klippert escribis:
I wrote a C program to talk to a I2C usb master device. On the surface
this program seems to work consistently. It wasn't until I wrapped the C
program in shell code and looped it, when a problem was exposed
ultimately crashing the system. I do not know whether my program is
causing the crash or if it's something related to ucom(4).

The shell script runs for days at a time and then it fails with
"ucomstart: null oxfer". When I unplug the device the system hangs or if
I run usbdevs the system hangs, once hung the watchdog kicks in and
reboots the machine. The device is directly connected (no usb hub) and
is the only external usb device on the bus.

I'm very new to C so any criticisms are welcome.

dmesg:
OpenBSD 4.9 (GENERIC) #671: Wed Mar  2 07:09:00 MST 2011
     dera...@i386.openbsd.org:/usr/src/sys/arch/i386/compile/GENERIC
cpu0: Geode(TM) Integrated Processor by AMD PCS ("AuthenticAMD"
586-class) 499 MHz
cpu0: FPU,DE,PSE,TSC,MSR,CX8,SEP,PGE,CMOV,CFLUSH,MMX
real mem  = 268009472 (255MB)
avail mem = 253493248 (241MB)
mainbus0 at root
bios0 at mainbus0: AT/286+ BIOS, date 11/05/08, BIOS32 rev. 0 @ 0xfd088
pcibios0 at bios0: rev 2.1 @ 0xf0000/0x10000
pcibios0: pcibios_get_intr_routing - function not supported
pcibios0: PCI IRQ Routing information unavailable.
pcibios0: PCI bus #0 is the last bus
bios0: ROM list: 0xe0000/0xa800
cpu0 at mainbus0: (uniprocessor)
pci0 at mainbus0 bus 0: configuration mode 1 (bios)
pchb0 at pci0 dev 1 function 0 "AMD Geode LX" rev 0x33
glxsb0 at pci0 dev 1 function 2 "AMD Geode LX Crypto" rev 0x00: RNG AES
vr0 at pci0 dev 9 function 0 "VIA VT6105M RhineIII" rev 0x96: irq 10,
address 00:0d:b9:1c:c9:48
ukphy0 at vr0 phy 1: Generic IEEE 802.3u media interface, rev. 3: OUI
0x004063, model 0x0034
glxpcib0 at pci0 dev 15 function 0 "AMD CS5536 ISA" rev 0x03: rev 3,
32-bit 3579545Hz timer, watchdog, gpio
gpio0 at glxpcib0: 32 pins
pciide0 at pci0 dev 15 function 2 "AMD CS5536 IDE" rev 0x01: DMA,
channel 0 wired to compatibility, channel 1 wired to compatibility
wd0 at pciide0 channel 0 drive 0:<CF CARD 4GB>
wd0: 1-sector PIO, LBA, 3831MB, 7847280 sectors
wd0(pciide0:0:0): using PIO mode 4, Ultra-DMA mode 2
pciide0: channel 1 ignored (disabled)
ohci0 at pci0 dev 15 function 4 "AMD CS5536 USB" rev 0x02: irq 12,
version 1.0, legacy support
ehci0 at pci0 dev 15 function 5 "AMD CS5536 USB" rev 0x02: irq 12
usb0 at ehci0: USB revision 2.0
uhub0 at usb0 "AMD EHCI root hub" rev 2.00/1.00 addr 1
isa0 at glxpcib0
isadma0 at isa0
com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
com0: console
com1 at isa0 port 0x2f8/8 irq 3: ns16550a, 16 byte fifo
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
npx0 at isa0 port 0xf0/16: reported by CPUID; using exception 16
usb1 at ohci0: USB revision 1.0
uhub1 at usb1 "AMD OHCI root hub" rev 1.00/1.00 addr 1
biomask fbe7 netmask ffe7 ttymask ffff
mtrr: K6-family MTRR support (2 registers)
nvram: invalid checksum
uftdi0 at uhub1 port 2 "FTDI FT232R USB UART" rev 2.00/6.00 addr 2
ucom0 at uftdi0 portno 1
vscsi0 at root
scsibus0 at vscsi0: 256 targets
softraid0 at root
root on wd0a swap on wd0b dump on wd0b
clock: unknown CMOS layout

---

usbdevs -v:
Controller /dev/usb0:
addr 1: high speed, self powered, config 1, EHCI root hub(0x0000),
AMD(0x1022), rev 1.00
  port 1 powered
  port 2 powered
  port 3 powered
  port 4 powered
Controller /dev/usb1:
addr 1: full speed, self powered, config 1, OHCI root hub(0x0000),
AMD(0x1022), rev 1.00
  port 1 powered
  port 2 addr 2: full speed, power 90 mA, config 1, FT232R USB
  UART(0x6001), FTDI(0x0403), rev 6.00, iSerialNumber A700etwC
  port 3 powered
  port 4 powered

---

I2C device info:
http://www.robot-electronics.co.uk/htm/usb_i2c_tech.htm

---

C program "i2c.c":

#include<stdio.h>
#include<fcntl.h>
#include<termios.h>
#include<sys/types.h>
#include<unistd.h>
#include<err.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>

int open_port(void);
void clearBuf(unsigned char bufType[], int nbytes);
void writeBuf(int fd, unsigned char command[], int nbytes);
void readBuf(int fd, int nbytes);

struct termios options;

int v = 0;                      /* turn off verbose output */

int i, n, p, fd;
char *input, *string;

unsigned char wrBuf[4];
unsigned char rdBuf[64];

unsigned char blank[4]          = {0x5a, 0x00, 0x00, 0x00};
unsigned char version[4]        = {0x5a, 0x01, 0x00, 0x00};
unsigned char led_on[4]         = {0x5a, 0x10, 0x01, 0x00};
unsigned char led_off[4]        = {0x5a, 0x10, 0x00, 0x00};
unsigned char set_pins_h[4]     = {0x5a, 0x10, 0x0f, 0x00}; /* 3rd byte
= [ (3=I/O3) (2=I/O2) (1=Input1) (0=RedLED) ] */
unsigned char set_pins_l[4]     = {0x5a, 0x10, 0x00, 0x00}; /* 3rd byte
= [ (3=I/O3) (2=I/O2) (1=Input1) (0=RedLED) ] */
unsigned char get_pins[4]       = {0x5a, 0x11, 0x00, 0x00};
unsigned char get_AD[4]         = {0x5a, 0x12, 0x00, 0x00};

int
main(int argc, char *argv[]) {
         if (argc<  2) {
                 errx(1, "Invalid command: Not enough arguments");
         } else if (argc>  2) {
                 errx(1, "Invalid command: Too many arguments");
         }
         else {
                 /* if only argument is "help" display list of commands
                 */
                 if (strcmp(argv[1], "help") == 0) {
                         printf("version: return version number\n");
                         printf("set_pins_h: set both I/O pins as
                         inputs\n");
                         printf("set_pins_l: set both I/O pins as
                         outputs\n");
                         printf("get_pins: get status of I/O pins\n");
                         printf("get_AD: get analogue values on pins I/O2
                         and I/O3\n");
                         printf("led_on: turn red LED on\n");
                         printf("led_off: turn red LED off\n");
                         return 0;
                 /* parse input command for internal use */
                 } else if (strcmp(argv[1], "version") == 0) {
                         input = version;
                 } else if (strcmp(argv[1], "set_pins_h") == 0) {
                         input = set_pins_h;
                 } else if (strcmp(argv[1], "set_pins_l") == 0) {
                         input = set_pins_l;
                 } else if (strcmp(argv[1], "get_pins") == 0) {
                         input = get_pins;
                 } else if (strcmp(argv[1], "get_AD") == 0) {
                         input = get_AD;
                 } else if (strcmp(argv[1], "led_on") == 0) {
                         input = led_on;
                 } else if (strcmp(argv[1], "led_off") == 0) {
                         input = led_off;
                 } else {
                         errx(1, "Invalid command: Unknown argument");
                 }

                 string = argv[1];

                 if (v == 1) {
                         /* echo input command and display contents in
                         hex */
                         printf("Input selected: %s, ", argv[1]);
                         for (i=0; i<(sizeof(input)); i++) {
                                 printf("%02x ", input[i]);
                                 if (i == ((sizeof(input)-1))) {
                                         printf("\n");
                                 }
                         }
                 }

                 clearBuf(rdBuf, 64);            /* clear buffer before
                 use */

                 fd = open_port();               /* open port to device
                 */

                 if (v == 1) {
                         printf("\n");
                 }

                 writeBuf(fd, input, 4);         /* write command to
                 device */
                 usleep(75000);
                 readBuf(fd, 4);                 /* read data from device
                 */

                 close(fd);                      /* close port to device
                 */
         }
         return 0;
}

/*
  *      open USB device for asynchronous read/write access
  *      19200 baud, 8 data bits, no parity, two stop bits
  */
int
open_port(void) {
         const char *device = "/dev/cuaU0";

         if ((fd = open(device, O_RDWR | O_NONBLOCK)) == -1) {
                 errx(1, "open(): %s: %s", strerror(errno), device);
         }
         else {
                 if ((tcflush(fd, TCIOFLUSH)) != 0) {
                         warnx("%s: while attempting tcflush()",
                         strerror(errno));
                 }

                 /* get current options for port */
                 if ((tcgetattr(fd,&options)) != 0) {
                         warnx("%s: while getting termios options",
                         strerror(errno));
                 } else if (v == 1) {
                         printf("\ndefault termios options\n");
                         printf("input speed = %d\n",
                         cfgetispeed(&options));
                         printf("output speed = %d\n",
                         cfgetospeed(&options));
                         printf("c_cflag = %08x\n", options.c_cflag);
                         printf("c_oflag = %08x\n", options.c_oflag);
                         printf("c_iflag = %08x\n", options.c_iflag);
                         printf("c_lflag = %08x\n", options.c_lflag);
                         printf("c_cc[VMIN] = %d\n", options.c_cc[VMIN]);
                         printf("c_cc[VTIME] = %d\n",
                         options.c_cc[VTIME]);
                 }

                 cfsetispeed(&options, B19200);                  /* set
                 the input baud rate */
                 cfsetospeed(&options, B19200);                  /* set
                 the output baud rate */

                 options.c_cflag = 0;    /* clear all */
                 options.c_lflag = 0;    /* clear all */
                 options.c_iflag = 0;    /* clear all */
                 options.c_oflag = 0;    /* clear all */

                 options.c_cflag |= (CS8 | CLOCAL | CREAD | CSTOPB);
                 /* this works - do not fuck with this */

                 options.c_lflag&= ~ICANON;             /* disable
                 canonicalized input; make use of VMIN and VTIME */
                 options.c_cc[VMIN]=0;                   /* minimum bytes
                 before successful read */
                 options.c_cc[VTIME]=50;                 /* timer to
                 prevent read from hanging (VTIME*0.1) */

                 /* set new options for port */
                 if ((tcsetattr(fd, TCSANOW,&options)) != 0) {
                         warnx("%s: while setting termios options",
                         strerror(errno));
                 } else if (v == 1) {
                         printf("\nnew termios options\n");
                         printf("input speed = %d\n",
                         cfgetispeed(&options));
                         printf("output speed = %d\n",
                         cfgetospeed(&options));
                         printf("c_cflag = %08x\n", options.c_cflag);
                         printf("c_oflag = %08x\n", options.c_oflag);
                         printf("c_iflag = %08x\n", options.c_iflag);
                         printf("c_lflag = %08x\n", options.c_lflag);
                         printf("c_cc[VMIN] = %d\n", options.c_cc[VMIN]);
                         printf("c_cc[VTIME] = %d\n",
                         options.c_cc[VTIME]);
                 }

                 if ((fcntl(fd, F_SETFL, O_NONBLOCK)) == -1) {
                         warnx("%s: while attempting to clear
                         O_NONBLOCK", strerror(errno));
                 }
         }
         return fd;
}

/*      load write buffer with command then send to device      */
void
writeBuf(int fd, unsigned char command[], int nbytes) {
         for (i=0; i<nbytes; i++) {
                 wrBuf[i] = command[i];
         }
         if ((n = (write(fd, wrBuf, nbytes))) != nbytes) {
                 warnx("write(): %s", strerror(errno));
         } else {
                 printf("bytes written: %d, ", n);
                 for (i=0; i<nbytes; i++) {
                         printf("%02x ", wrBuf[i]);
                         if (i == (nbytes-1)) {
                                 printf("\n");
                         }
                 }
         }
}


/*      clear the first nbytes of buffer (either rdBuf or wrBuf)
*/
void
clearBuf(unsigned char bufType[], int nbytes) {
         for (i=0; i<nbytes; i++) {
                 bufType[i] = 0x00;
         }
}

/*      capture and display the first nbytes of read buffer     */
void
readBuf(int fd, int nbytes) {
         int sum;
         if ((n = (read(fd, rdBuf, nbytes))) == -1) {
                 warnx("read(): %s", strerror(errno));
         } else {
                 printf("bytes read: %d, ", n);
                 for (i=0; i<nbytes; i++) {
                         printf("%02x ", rdBuf[i]);
                         if (i == (nbytes-1)) {
                                 printf("\n");
                         }
                 }
                 /* if input command is requesting AD values, output to
                 decimal */
                 if ((strcmp(string, "get_AD")) == 0) {
                         sum = ((rdBuf[0] * 256) + rdBuf[1]);
                         printf("IO2 = %02d\n", sum);
                         sum = ((rdBuf[2] * 256) + rdBuf[3]);
                         printf("IO3 = %02d\n", sum);
                 /* if input command is requesting IO values, output to
                 binary */
                 } else if ((strcmp(string, "get_pins")) == 0) {
                         printf("IO = ");
                         for(i=7; i>=0; i--) {
                                 putchar('0' + ((rdBuf[0]>>  i)&  1));
                         }
                         printf("\n");
                 }
         }
}

---

shell script:
clear; while true; do
         value=$(/home/admin/c_dev/i2c get_pins | grep 'IO' | cut -d ' '
         -f 3 | cut -b 7);

         if [ $value -eq 0 ]; then
                 printf "activated! sending email message, please
                 wait...\n";
                 echo "" | mail -s "alert" byronklipp...@ml1.net&&  sleep
                 9;
         fi

         sleep 9;
done



   Byron Klippert
   byronklipp...@ml1.net
   (867) 332-4184

Reply via email to