Peter Teoh - 2007-12-18

Thank you very much for the source. I purchased this device from OSR, and
have adapted your source code to use the libusb API (libusb.sourceforge.net), as the following (noticed it is much simpler):

/***********/
/ Define the vendor id and product id. /
/***********/

include <stdio.h>

include <string.h>

include <usb.h>

define VENDOR_ID 0x0547

define PRODUCT_ID 0x1002

/***********/
/ Define the vendor commands supported by OSR USB FX2 device. /
/***********/

define OSRFX2_READ_7SEGMENT_DISPLAY 0xD4

define OSRFX2_READ_SWITCHES 0xD6

define OSRFX2_READ_BARGRAPH_DISPLAY 0xD7

define OSRFX2_SET_BARGRAPH_DISPLAY 0xD8

define OSRFX2_IS_HIGH_SPEED 0xD9

define OSRFX2_REENUMERATE 0xDA

define OSRFX2_SET_7SEGMENT_DISPLAY 0xDB

define USB_CTRL_GET_TIMEOUT 1000

/***********/
/ BARGRAPH_STATE is a bit field structure with each bit corresponding /
/ to one on the bars on the bargraph LED of the OSR USB FX2 Learner Kit /
/ development board. /
/***********/
struct bargraph_state {
union {
struct {
/
* Individual bars (LEDs) starting from the top of the display.

* NOTE: The display has 10 LEDs, but the top two LEDs are not
* connected (don't light) and are not included here.
/
unsigned char Bar4 : 1;
unsigned char Bar5 : 1;
unsigned char Bar6 : 1;
unsigned char Bar7 : 1;
unsigned char Bar8 : 1;
unsigned char Bar1 : 1;
unsigned char Bar2 : 1;
unsigned char Bar3 : 1;
};
/

* The state of all eight bars as a single octet.
*/
unsigned char BarsOctet;
};
} attribute ((packed));

/***********/
/ SEGMENT_STATE is a bit field structure with each bit corresponding /
/ to one on the segments on the 7-segment display of the OSR USB FX2 /
/ Learner Kit development board. /
/***********/
struct segment_state {
union {
struct {
/
* Individual segments.
/
unsigned char Segment_top : 1; / 0x01 /
unsigned char Segment_upper_right : 1; / 0x02 /
unsigned char Segment_lower_right : 1; / 0x04 /
unsigned char Segment_dot : 1; / 0x08 /
unsigned char Segment_lower_left : 1; / 0x10 /
unsigned char Segment_middle : 1; / 0x20 /
unsigned char Segment_upper_left : 1; / 0x40 /
unsigned char Segment_bottom : 1; / 0x80 /
};
/
* The state of all the segments as a single octet.
/
unsigned char SegmentsOctet;
};
} attribute ((packed));

static const unsigned char digit_to_segments [10] = {
0xD7, / 0 /
0x06, / 1 /
0xB3, / 2 /
0xA7, / 3 /
0x66, / 4 /
0xE5, / 5 /
0xF5, / 6 /
0x07, / 7 /
0xF7, / 8 /
0x67 / 9 /
};

static const unsigned char nondisplayable = 0x08; / the "dot" segment /
static const unsigned char high_speed = 0x76; / high-speed "H" /
static const unsigned char power_active = 0x77; / PM active "A" /
static const unsigned char power_suspend = 0xE5; / PM suspend "S" /

/***********/
/ SWITCHES_STATE is a bit field structure with each bit corresponding /
/ to one of the DIP switches on the OSR USB FX2 Learner Kit development /
/ board. /
/***********/
struct switches_state {
union {
struct {
/
* Individual switches starting from the left
/
unsigned char Switch8 : 1;
unsigned char Switch7 : 1;
unsigned char Switch6 : 1;
unsigned char Switch5 : 1;
unsigned char Switch4 : 1;
unsigned char Switch3 : 1;
unsigned char Switch2 : 1;
unsigned char Switch1 : 1;
};
/
* The state of all the switches as a single octet.
/
unsigned char SwitchesOctet;
};
} attribute ((packed));

define TRUE 1

define FALSE 0

define EP1 1 / in / / out /

define EP2 2 / in /

define EP3 3

define EP4 4 / in /

define EP5 5

define EP6 6 / out /

define EP7 7

define EP8 8 / out /

int main(int argc, char argv[])
{
struct usb_bus
bus;
char buffer[256];
usb_dev_handle udev;
struct usb_device
dev;
int loop_count;

loop_count = atoi(argv[1]);
usb_init();
usb_find_busses();
usb_find_devices();

for (bus = usb_busses; bus; bus = bus-&gt;next) {
for (dev = bus-&gt;devices; dev; dev = dev-&gt;next) {

udev = usb_open(dev);
if (udev) {
        if (dev-&gt;descriptor.iManufacturer) {
        if (usb_get_string_simple(udev, dev-&gt;descriptor.iManufacturer, buffer, sizeof(buffer)) &gt; 0)
            if ((dev-&gt;descriptor.idVendor == VENDOR_ID) &amp;&amp; ( dev-&gt;descriptor.idProduct == PRODUCT_ID)) {
                usb_close(udev);
                if (show_switches(dev))
                    printf(&quot;showswitches dev passed: %x\n&quot;, dev);
                else
                    printf(&quot;showswitches dev failed: %x\n&quot;, dev);
                if (set_bargraph(dev, argv[1]))
                    printf(&quot;set_bar dev passed: %x\n&quot;, dev);
                else
                    printf(&quot;set_bar dev failed: %x\n&quot;, dev);
                if (show_7segment(dev))
                    printf(&quot;show_7seg dev passed: %x\n&quot;, dev);
                else
                    printf(&quot;show_7seg dev failed: %x\n&quot;, dev);
                if (set_7segment(dev, argv[1]))
                    printf(&quot;set_7segment dev passed: %x\n&quot;, dev);
                else
                    printf(&quot;set_7segment dev failed: %x\n&quot;, dev);
            }
            else
                usb_close(udev);
    }
    else
        usb_close(udev);
}
}
}

}

/***********/
/ This routine will retrieve the switches state, format it and return a /
/ representative string. /
/ /
/ Note the two different function defintions depending on kernel version. /
/***********/
int show_switches(struct usb_device * dev)
{
struct switches_state * packet;
int retval;
usb_dev_handle *udev;

udev = usb_open(dev);

usb_claim_interface(udev, 0);

packet = malloc(sizeof(*packet));
if (!packet) {
    return FALSE;
}
packet-&gt;SwitchesOctet = 0;

retval = usb_control_msg(udev,
                         USB_ENDPOINT_IN | USB_TYPE_VENDOR,
                         OSRFX2_READ_SWITCHES, 
                         0,
                         0,
                         packet, 
                         sizeof(*packet),
                         USB_CTRL_GET_TIMEOUT);

if (retval &lt; 0) {
    fprintf(stderr, &quot;%s - retval=%d\n&quot;, __FUNCTION__, retval);
    free(packet);
    return FALSE;
}

printf(&quot;%s%s%s%s%s%s%s%s&quot;,    /* left sw --&gt; right sw */
                 (packet-&gt;Switch1) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Switch2) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Switch3) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Switch4) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Switch5) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Switch6) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Switch7) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Switch8) ? &quot;*&quot; : &quot;.&quot; );

free(packet);

usb_release_interface(udev, 0);

if (udev)
    usb_close(udev);

return TRUE;

}

/***********/
/ This macro creates an attribute under the sysfs directory /
/ --- /sys/bus/usb/devices/<root_hub>-<hub>:1.0/switches /
/ /
/ The DEVICE_ATTR() will create "dev_attr_switches" . /
/ "dev_attr_switches" is referenced in both probe and disconnect routines. /
/ /
/ Note that there is no "set" function for this attribute; therefore the /
/ S_IWUGO (write) flag is not included and the "set" routine point is set /
/ to NULL. /
/***********/
/static DEVICE_ATTR( switches, S_IRUGO, show_switches, NULL );/

/***********/
/ This routine will retrieve the bargraph LED state, format it and return a /
/ representative string. /
/ /
/ Note the two different function defintions depending on kernel version. /
/***********/
int show_bargraph(struct usb_device * dev)
{
struct bargraph_state * packet;
int retval;
usb_dev_handle *udev;

udev = usb_open(dev);

usb_claim_interface(udev, 0);

packet = malloc(sizeof(*packet));
if (!packet) {
    return FALSE;
}
packet-&gt;BarsOctet = 0;

retval = usb_control_msg(udev,
                         USB_ENDPOINT_IN | USB_TYPE_VENDOR,
                         OSRFX2_READ_BARGRAPH_DISPLAY, 
                         0,
                         0,
                         packet, 
                         sizeof(*packet),
                         USB_CTRL_GET_TIMEOUT);

if (retval &lt; 0) {
    fprintf(stderr, &quot;%s - retval=%d\n&quot;, 
            __FUNCTION__, retval);
    free(packet);
    return FALSE;
}

printf(&quot;%s%s%s%s%s%s%s%s&quot;,    /* bottom LED --&gt; top LED */
                 (packet-&gt;Bar1) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Bar2) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Bar3) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Bar4) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Bar5) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Bar6) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Bar7) ? &quot;*&quot; : &quot;.&quot;,
                 (packet-&gt;Bar8) ? &quot;*&quot; : &quot;.&quot; );

free(packet);

usb_release_interface(udev, 0);

if (udev)
    usb_close(udev);

return TRUE;

}

/***********/
/ This routine will set the bargraph LEDs. /
/ /
/ Note the two different function defintions depending on kernel version. /
/***********/
int set_bargraph(struct usb_device * dev, const char * buf)
{
struct bargraph_state * packet;

unsigned int value;
int retval;
char * end;

usb_dev_handle *udev;

udev = usb_open(dev);

usb_claim_interface(udev, 0);

packet = malloc(sizeof(*packet));
if (!packet) {
    return FALSE;
}
packet-&gt;BarsOctet = 0;

value = (strtoul(buf, &amp;end, 10) &amp; 0xFF);
if (buf == end) {
    value = 0;
}

packet-&gt;Bar1 = (value &amp; 0x01) ? 1 : 0;
packet-&gt;Bar2 = (value &amp; 0x02) ? 1 : 0;
packet-&gt;Bar3 = (value &amp; 0x04) ? 1 : 0;
packet-&gt;Bar4 = (value &amp; 0x08) ? 1 : 0;
packet-&gt;Bar5 = (value &amp; 0x10) ? 1 : 0;
packet-&gt;Bar6 = (value &amp; 0x20) ? 1 : 0;
packet-&gt;Bar7 = (value &amp; 0x40) ? 1 : 0;
packet-&gt;Bar8 = (value &amp; 0x80) ? 1 : 0;

retval = usb_control_msg(udev,
                         USB_ENDPOINT_OUT | USB_TYPE_VENDOR,
                         OSRFX2_SET_BARGRAPH_DISPLAY, 
                         0,
                         0,
                         packet, 
                         sizeof(*packet),
                         USB_CTRL_GET_TIMEOUT);

if (retval &lt; 0) {
    fprintf(stderr, &quot;%s - retval=%d\n&quot;, 
            __FUNCTION__, retval);
}

free(packet);
usb_release_interface(udev, 0);

if (udev)
    usb_close(udev);

return TRUE;

}

/***********/
/ This routine will show the 7-segment display value. /
/ /
/ The 7-segment display raw value is read and then looked-up in the /
/ mapping table, digit_to_segments. /
/ Any raw display value which is not mapped will be displayed as a ".". /
/ There are other special cases handles as well, e.g "H" for high-speed. /
/ /
/ Note the two different function defintions depending on kernel version. /
/***********/
int show_7segment(struct usb_device * dev)
{
struct segment_state * packet;
int retval;
int i;
usb_dev_handle *udev;

udev = usb_open(dev);

usb_claim_interface(udev, 0);

packet = malloc(sizeof(*packet));
if (!packet) {
    return FALSE;
}
packet-&gt;SegmentsOctet = nondisplayable;

retval = usb_control_msg(udev,
                         USB_ENDPOINT_IN | USB_TYPE_VENDOR,
                         OSRFX2_READ_7SEGMENT_DISPLAY, 
                         0,
                         0,
                         packet, 
                         sizeof(*packet),
                         USB_CTRL_GET_TIMEOUT);
if (retval &lt; 0) {
    fprintf(stderr, &quot;Error: %s - retval=%d\n&quot;, 
            __FUNCTION__, retval);
    free(packet);
    return FALSE;
}

for (i=0; i &lt; sizeof(digit_to_segments); i++) {
    if (packet-&gt;SegmentsOctet == digit_to_segments[i]) {
        break;
    }
}

if (i &lt; sizeof(digit_to_segments)) {
    printf(&quot;%d &quot;, i );
}
else {
    /* Check for special cases */
    printf(&quot;%s &quot;, 
                     (packet-&gt;SegmentsOctet == nondisplayable) ? &quot;.&quot; : 
                     (packet-&gt;SegmentsOctet == high_speed)     ? &quot;H&quot; : 
                     (packet-&gt;SegmentsOctet == power_active)   ? &quot;A&quot; : 
                     &quot;?&quot; );
}

free(packet);

usb_release_interface(udev, 0);

if (udev)
    usb_close(udev);

return TRUE;

}

/***********/
/ This routine will set the 7-segment display. /
/ /
/ The input string (buf) is expected to be a numeric character between 0-9. /
/ Any ohter string values will be displayed on the 7-segment display by /
/ turning on the "dot" segment, thus indicating a "nondisplayable" value. /
/ /
/ Note the two different function defintions depending on kernel version. /
/***********/
int set_7segment(struct usb_device * dev, const char * buf)
{
struct segment_state * packet;

unsigned int value;
int retval;
char * end;
usb_dev_handle *udev;

udev = usb_open(dev);

usb_claim_interface(udev, 0);

packet = malloc(sizeof(*packet));
if (!packet) {
    return FALSE;
}
packet-&gt;SegmentsOctet = 0;

value = (strtoul(buf, &amp;end, 10) &amp; 0xFF);
if (buf == end) {
    value = nondisplayable;
}

packet-&gt;SegmentsOctet = (value &lt; 10) ? 
    digit_to_segments[value] : nondisplayable;

retval = usb_control_msg(udev,
                         USB_ENDPOINT_OUT | USB_TYPE_VENDOR,
                         OSRFX2_SET_7SEGMENT_DISPLAY, 
                         0,
                         0,
                         packet, 
                         sizeof(*packet),
                         USB_CTRL_GET_TIMEOUT);
if (retval &lt; 0) {
    fprintf(stderr, &quot;Error: %s - retval=%d\n&quot;, 
            __FUNCTION__, retval);
    free(packet);
    return FALSE;
}

free(packet);

usb_release_interface(udev, 0);

if (udev)
    usb_close(udev);

return TRUE;

}