read timeout on second attempt following libusb_close( ) - libusb

My linux application can use libusb to perform many IO operations to/from the device. However, if I close and then re-open access to the device, all read operations will timeout. I'm assuming that my close code is not complete but I can't find my bug.
The example program has these functions:
deviceCount( ) which returns the number of devices matching my VID/PID
deviceOpen( ) to open a connection to my device
deviceClose( ) to close the connection to my device and "clean-up"
deviceWrite( ) to write a specific number of bytes to my device
deviceRead( ) to read a specific number of bytes from my device
deviceReadRegisters( ) a function specific to my device that does a write followed by a read
runTest( ) a function to call all of the above in a reasonable sequence
main( ) the main function which tries to call runTest( ) multiple times.
Note that after running the program and getting the timeout error, I need to power-cycle my device to recover. Re-running my test program without power-cycling is not sufficient. It will then fail on the first call to runTest( ).
In the current implementation, I only call libusb_init( ) and libusb_exit( ) once. I've also tried calling these function each time through the runTest( ) function. This didn't make any difference.
I'm guessing that I'm doing something wrong in my deviceClose( ) function. Any insights would be greatly appreciated.
Thanks in advance! - Jeff
####### Example output
main() attempting to runTest(), i: 0
runTest() Starting!
runTest() Success calling libusb_init()
runTest() Number of devices: 1
deviceOpen() Number of alternate settings: 1
deviceOpen() Interface number: 0 number of endpoints: 5
deviceOpen() Descriptor type: 5 EP Address: 0x02 2
deviceOpen() Found outPort! outPort: 2 index: 0
deviceOpen() Descriptor type: 5 EP Address: 0x84 132
deviceOpen() Descriptor type: 5 EP Address: 0x86 134
deviceOpen() Found inPort! inPort: 134 index: 2
deviceOpen() Descriptor type: 5 EP Address: 0x01 1
deviceOpen() Descriptor type: 5 EP Address: 0x81 129
deviceOpen() Found device! VID: 0x0957 PID: 0x5f18 outPort: 2 inPort: 134
deviceOpen() Success calling libusb_claim_interface( ) handle: 0x88cd140
deviceOpen() Successful open! id: 0 handle: 0x88cd140
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceClose() Sucess calling libusb_release_interface( ) handle: 0x88cd140
deviceClose() Sucess calling libusb_close( ) handle: 0x88cd140
deviceClose() Success calling libusb_free_device_list( ) devs: 0x88cd170
runTest() Success!
main() attempting to runTest(), i: 1 <== this is the second call to runTest( )
runTest() Starting!
runTest() Number of devices: 1
deviceOpen() Number of alternate settings: 1
deviceOpen() Interface number: 0 number of endpoints: 5
deviceOpen() Descriptor type: 5 EP Address: 0x02 2
deviceOpen() Found outPort! outPort: 2 index: 0
deviceOpen() Descriptor type: 5 EP Address: 0x84 132
deviceOpen() Descriptor type: 5 EP Address: 0x86 134
deviceOpen() Found inPort! inPort: 134 index: 2
deviceOpen() Descriptor type: 5 EP Address: 0x01 1
deviceOpen() Descriptor type: 5 EP Address: 0x81 129
deviceOpen() Found device! VID: 0x0957 PID: 0x5f18 outPort: 2 inPort: 134
deviceOpen() Success calling libusb_claim_interface( ) handle: 0x88cd140
deviceOpen() Successful open! id: 0 handle: 0x88cd140
deviceWrite() Success writing 2 bytes
deviceRead() Problem reading 146 bytes, read only 0 bytes, inPort: 134 timeout: 2000 LIBUSB_ERROR_TIMEOUT
####### Test Program
// Test program demonstrating timeout problem following libusb_close()
//
// g++ -o libUsbTest libUsbTest.cpp -I /usr/local/include/libusb-1.0 -L /usr/local/lib -l usb-1.0
//
// sudo ./libUsbTest
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libusb.h>
// for test purposes, using global variable
libusb_device **devs = NULL;
libusb_device_handle *handle = NULL; // non-null when device is open
libusb_context *usbContext = NULL;
unsigned short outPort = 0;
unsigned short inPort = 0;
#define VID 0x957
#define PID 0x5f18
#define OUTPUT_ENDPOINT 2
#define INPUT_ENDPOINT 6
// Returns the number of devices matching our VID / PID
// A negative return value indicates a failure
int deviceCount( ) {
int count = 0;
if (devs)
{
// Note this automatically dereferrences each device
libusb_free_device_list(devs, 1);
devs = NULL;
}
ssize_t cnt;
cnt = libusb_get_device_list(usbContext, &devs);
if (cnt < 0 || devs == 0)
{
fprintf(stderr,"deviceCount() Failed libusb_get_device_list()!\n");
return -1;
}
// Walk through the device list and count those that match our VID / PID
libusb_device *dev = NULL;
count = 0;
int i = 0;
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "deviceCount() Failed libusb_get_device_descriptor()!\n");
return -1;
}
if (desc.idVendor == VID && desc.idProduct == PID)
{
count++;
}
}
return count;
}
// Open the USB device. Only one device can be open at a time because of the above global variables
// Returns negative number for errors
int deviceOpen( int id) {
if (!usbContext) {
fprintf(stderr,"deviceOpen() Can't open! Null usbContext!\n");
return -1;
}
if (handle) {
fprintf(stderr,"deviceOpen() Device already open!\n");
return 0;
}
if (devs == 0) {
fprintf(stderr,"deviceOpen() Can't open! Null devs!\n");
return -1;
}
// Walk through the same device list and stop when we get to the desired sensor VID / PID
libusb_device *dev = NULL;
int count = 0;
bool keepGoing = true;
int i = 0;
while ((dev = devs[i++]) != NULL && keepGoing) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "deviceOpen() Failed libusb_get_device_descriptor()!\n");
return -1;
}
if (desc.idVendor == VID && desc.idProduct == PID)
{
if (count == id) {
// Match!
keepGoing = false;
// Get the out and input ports
libusb_config_descriptor *config;
libusb_get_config_descriptor( dev, 0, &config);
const libusb_interface *inter;
const libusb_interface_descriptor *interdesc;
const libusb_endpoint_descriptor *epdesc;
for (int i=0; i<(int)config->bNumInterfaces; i++)
{
inter = &config->interface[i];
fprintf(stderr,"deviceOpen() Number of alternate settings: %d\n", inter->num_altsetting);
for (int j=0; j<inter->num_altsetting; j++)
{
interdesc = &inter->altsetting[j];
fprintf(stderr, "deviceOpen() Interface number: %d number of endpoints: %d\n",
interdesc->bInterfaceNumber, interdesc->bNumEndpoints);
for (int k=0; k<interdesc->bNumEndpoints; k++)
{
epdesc = &interdesc->endpoint[k];
fprintf(stderr, "deviceOpen() Descriptor type: %d EP Address: 0x%2.2x %d\n",
epdesc->bDescriptorType, epdesc->bEndpointAddress, epdesc->bEndpointAddress);
if (epdesc->bDescriptorType == LIBUSB_DT_ENDPOINT)
{
// Found an endpoint
uint8_t address = epdesc->bEndpointAddress & 0xf;
bool input = (epdesc->bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN;
if ( address == OUTPUT_ENDPOINT && input == false)
{
outPort = epdesc->bEndpointAddress;
fprintf(stderr, "deviceOpen() Found outPort! outPort: %d index: %d\n", outPort, k);
}
if ( address == INPUT_ENDPOINT && input == true)
{
inPort = epdesc->bEndpointAddress;
fprintf(stderr, "deviceOpen() Found inPort! inPort: %d index: %d\n", inPort, k);
}
}
} // endpoints}
} // num_altsetting
} // interfaces
libusb_free_config_descriptor( config);
// Open device
fprintf(stderr, "deviceOpen() Found device! VID: 0x%4.4x PID: 0x%4.4x outPort: %d inPort: %d\n", VID, PID, outPort, inPort);
libusb_error errCode;
errCode = (libusb_error) libusb_open( dev, &handle);
if (errCode)
{
fprintf(stderr, "deviceOpen() Failed in libusb_open(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
return -1;
}
// Verify not in use by kernel
if (libusb_kernel_driver_active( handle, 0))
{
// FIXME: we could call libusb_detach_kernel_driver( ) here
fprintf(stderr, "deviceOpen() Failed! kernel owns device!\n");
return -1;
}
// Claim the interface.
errCode = (libusb_error) libusb_claim_interface( handle, 0);
if (errCode)
{
fprintf(stderr, "deviceOpen() Failed in libusb_claim_interface(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
return -1;
}
fprintf(stderr, "deviceOpen() Success calling libusb_claim_interface( ) handle: %p\n", handle);
} else {
count++;
}
} // desired VID / PID
} // Walk device list
fprintf(stderr, "deviceOpen() Successful open! id: %d handle: %p\n", id, handle);
return 0;
}
// Close the USB device
// Returns negative number for errors
int deviceClose() {
if (handle)
{
// Release the interface.
libusb_error errCode = (libusb_error) libusb_release_interface( handle, 0);
if (errCode)
{
fprintf(stderr, "deviceClose() Failed in libusb_release_interface(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
return -1;
}
fprintf(stderr, "deviceClose() Sucess calling libusb_release_interface( ) handle: %p\n", handle);
libusb_close( handle);
fprintf(stderr, "deviceClose() Sucess calling libusb_close( ) handle: %p\n", handle);
handle = NULL;
}
if (devs)
{
// Note this automatically dereferrences each device
libusb_free_device_list(devs, 1);
fprintf(stderr, "deviceClose() Success calling libusb_free_device_list( ) devs: %p\n", devs);
devs = NULL;
}
outPort = 0;
inPort = 0;
return 0;
}
// Write to the device.
// Returns number of bytes written. Negative return value indicates an error
int deviceWrite( unsigned char *addr, int len){
if (!handle || !outPort) {
fprintf(stderr, "deviceWrite() No handle or outPort!\n");
return -1;
}
libusb_error errCode;
int transferred;
unsigned int timeout = 2000;
errCode = (libusb_error) libusb_bulk_transfer( handle, outPort, addr, len, &transferred, timeout);
if (errCode || transferred != len) {
fprintf(stderr, "deviceWrite() Problem writing %d bytes, wrote only %d bytes, outPort: %d timeout: %d %s\n",
len, transferred, outPort, timeout, libusb_error_name(errCode));
return -1;
}
fprintf(stderr, "deviceWrite() Success writing %ld bytes\n", transferred);
return transferred;
}
// Read from the device.
// Returns number of bytes read. Negative return value indicates an error
int deviceRead( unsigned char *addr, int len){
if (!handle || !outPort) {
fprintf(stderr, "deviceRead() No handle or outPort!\n");
return -1;
}
libusb_error errCode;
int transferred;
unsigned int timeout = 2000;
errCode = (libusb_error) libusb_bulk_transfer( handle, inPort, addr, len, &transferred, timeout);
if (errCode || (transferred != len)) {
fprintf(stderr, "deviceRead() Problem reading %ld bytes, read only %ld bytes, inPort: %d timeout: %d %s\n",
len, transferred, inPort, timeout, libusb_error_name(errCode));
return -1;
}
fprintf(stderr, "deviceRead() Success reading %ld bytes\n", transferred);
return transferred;
}
// Read the registers from the USB device
// Caution: this function is specific to my device!!!
// Returns negative number for errors
int deviceReadRegisters( ) {
// Write the command to the device so that it will return the registers
unsigned char wrBuf[2] = { 0x00, 0x10};
int rtn = deviceWrite( wrBuf, sizeof(wrBuf));
if (rtn < 0) return rtn;
// Read back 146 bytes
unsigned char rdBuf[146];
rtn = deviceRead( rdBuf, sizeof( rdBuf));
if (rtn < 0) return rtn;
// Just in case we add more logic later...
fprintf(stderr,"deviceReadRegisters() Success!\n");
return rtn;
}
// Execute the full test including initialization and cleanup
// Return negative number for error
int runTest( bool performLibUsbExit) {
int rtn;
fprintf(stderr,"runTest() Starting!\n");
// Initialize library
if (usbContext == NULL) {
int r = libusb_init( &usbContext);
if (r < 0)
{
fprintf(stderr,"runTest() failed in libusb_init()\n");
return -1;
}
fprintf(stderr,"runTest() Success calling libusb_init()\n");
}
// Make sure we have a device
int count = deviceCount();
if (count < 0) {
fprintf(stderr,"runTest() Error in deviceCount()\n");
return count;
}
if (count == 0) {
fprintf(stderr,"runTest() No devices found!\n");
return -1;
}
fprintf(stderr,"runTest() Number of devices: %d\n", count);
// Open the device
rtn = deviceOpen( 0);
if (rtn < 0) return rtn;
// Read the device registers a few times
for (int i=0; i<5; i++) {
rtn = deviceReadRegisters();
if (rtn < 0) return rtn;
}
// Close the device
rtn = deviceClose();
if (rtn < 0) return rtn;
// De-initialize the library
if (performLibUsbExit == true) {
libusb_exit(usbContext);
usbContext = NULL;
fprintf(stderr,"runTest() Success calling libusb_exit()\n");
}
fprintf(stderr,"runTest() Success!\n");
return 0;
}
int main( int argc, char *argv[]) {
int rtn;
// Run the test a few times
// The first test will pass. The second pass will timeout on the read.
int maxNum = 5;
for (int i=0; i<maxNum; i++) {
fprintf(stderr, "main() attempting to runTest(), i: %d\n", i);
// Only clean-up on the last call
rtn = runTest( i+1 == maxNum ? true : false);
if (rtn < 0) return rtn;
}
fprintf(stderr,"main() Success!\n");
return 0;
}

Related

How to get usb mass storage size using libusb library?

I am finding out usb mass storage related information using libusb library.
But don't know how to get usb mass storage size?
My tryout is:
void printdev(libusb_device *dev);
int main()
{
libusb_device **devs;
libusb_context *ctx = NULL; //a libusb session
int r;
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize a library session
if(r < 0)
{
cout<<"Init Error "<<r<<endl; //there was an error
return 1;
}
libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation
cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
if(cnt < 0)
{
cout<<"Get Device Error"<<endl; //there was an error
}
cout<<cnt<<" Devices in list."<<endl; //print total number of usb devices
int i;
for(i = 0; i < cnt; i++)
{
printdev(devs[i]);
}
libusb_free_device_list(devs, 1); //free the list, unref the devices in it
libusb_exit(ctx); //close the session
return 0;
}
void printdev(libusb_device *dev)
{
libusb_device_descriptor desc;
libusb_config_descriptor *conDesc;
char szBuffer[256] = {0};
unsigned char strDesc[256];
libusb_device_handle *devHandle = NULL;
int retVal;
__int64 i64Temp;
DWORD dwProdId;
DWORD dwProdId1;
i64Temp = 13888;
dwProdId = (DWORD)i64Temp;
retVal = libusb_open (dev, &devHandle);
if (retVal != LIBUSB_SUCCESS)
return;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0)
{
cout<<"failed to get device descriptor"<<endl;
return;
}
r = libusb_get_config_descriptor(dev, 0, &conDesc);
printf("Interface Class = %d\n", conDesc->interface->altsetting->bInterfaceClass);
cout<<"Number of possible configurations: "<<(int)desc.bNumConfigurations<<" ";
// cout<<"Device Class: "<<desc.bDeviceClass<<endl;
// cout<<"Device Class: "<<desc.bDeviceSubClass<<endl;
printf("Class = %d\n", desc.bDeviceClass);
cout<<"VendorID: "<<desc.idVendor<<endl;
cout<<"ProductID: "<<desc.idProduct<<endl;
dwProdId1 = (DWORD)desc.idProduct;
if (dwProdId1 == dwProdId)
{
printf("in if\n");
}
else
{
printf("in else\n");
}
retVal = libusb_get_string_descriptor_ascii(devHandle, desc.iManufacturer, strDesc, 256);
printf ("Manufacturer: %s\n", strDesc);
retVal = libusb_get_string_descriptor_ascii(devHandle, desc.iSerialNumber, strDesc, 256);
printf ("SerialNumber: %s\n", strDesc);
retVal = libusb_get_string_descriptor_ascii(devHandle, desc.iProduct, strDesc, 256);
printf ("Product: %s\n", strDesc);
printf("\n\n");
}

openssl BIO_do_connect returns 0 for ssl

Here's my simple openssl client test case trying to connect to google.com:443.
According to the manual, BIO_do_connect should return 1, 0 or -1.
Google didn't find me anyone for whom it returns 0, which it does for me.
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
int main()
{
SSL_load_error_strings();
SSL_library_init();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *p_ssl_ctx = NULL;
SSL *p_ssl = NULL;
BIO * bio = NULL;
int r = 0;
// init ssl context
p_ssl_ctx = SSL_CTX_new(SSLv2_client_method()); /* Create new context */
if (p_ssl_ctx == NULL)
{
ERR_print_errors_fp(stderr);
return 3;
}
const char *store_path = "/etc/ssl/certs/ca-certificates.crt";
r = SSL_CTX_load_verify_locations(p_ssl_ctx, store_path, NULL);
if (r == 0) {
fprintf(stderr, "Unable to load the trust store from %s.\n", store_path);
return 4;
}
bio = BIO_new_ssl_connect(p_ssl_ctx);
if (!bio) {
fprintf(stderr, "no bio \n");
return 5;
}
BIO_get_ssl(bio, &p_ssl);
if (!(p_ssl)) {
fprintf(stderr, "no ssl\n");
return 6;
}
SSL_set_mode(p_ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(bio, "www.google.com:443");
r = BIO_do_connect(bio);
if (r < 1) {
fprintf(stderr, "BIO_new_ssl_connect failed: %lu (0x%lx)\n", r, r);
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(stderr);
perror("bio");
return 7;
}
if (SSL_get_verify_result(p_ssl) != X509_V_OK) {
fprintf(stderr, "Unable to verify connection result.\n");
return 8;
}
return 0;
}
returns:
BIO_new_ssl_connect failed: 0 (0x0)
Error: (null)
error:00000000:lib(0):func(0):reason(0)
bio: Success
so how do i get the actual error out of this?
For getting the last state of your SSL connection in your code you can add something like fprintf(stderr,"p_ssl state: %s\n",SSL_state_string_long(p_ssl));.
More generally I suggest you to add an info callback like this : http://www.openssl.org/docs/ssl/SSL_CTX_set_info_callback.html
For your case, you must replace SSLv2_client_method() by something like TLSv1_client_method().

Read/write on a pen drive using libusb: libusb_bulk_transfer()

I am trying to perform read and write operations on a pen drive.
Details: Vendor ID: 8564 and Product ID: 1000. It is a Transcend JetFlash mass storage device.
I am keen to know that whether it is possible to achieve a read/write on a pen drive. If it is, then is it going to happen the way I have tried in the code provided below.
I have learnt the methods to get the device id, product id and endpoint addresses. This is what I have implemented.
Here the device is getting acknowledged and opened. And, even the interface claims it is successful.
But bulk transfer functions return -1.
What is the explanation?
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include </usr/include/libusb-1.0/libusb.h>
#define BULK_EP_OUT 0x82
#define BULK_EP_IN 0x02
int main(void)
{
int r = 0, e = 0;
struct libusb_device_handle *handle = NULL;
struct libusb_device **devs;
struct libusb_device *dev;
struct libusb_device_descriptor desc;
char str1[256], str2[256];
/* Init libusb */
r = libusb_init(NULL);
if (r < 0)
{
printf("\nfailed to initialise libusb\n");
return 1;
}
handle = libusb_open_device_with_vid_pid(NULL, 0x8564, 0x1000);
if(handle == NULL)
{
printf("\nError in device opening!");
}
else
printf("\nDevice Opened");
// Tell libusb to use the CONFIGNUM configuration of the device
libusb_set_configuration(handle, 1);
if(libusb_kernel_driver_active(handle, 0) == 1)
{
printf("\nKernel Driver Active");
if(libusb_detach_kernel_driver(handle, 0) == 0)
printf("\nKernel Driver Detached!");
}
e = libusb_claim_interface(handle, 0);
if(e < 0)
{
printf("\nCannot Claim Interface");
}
else
printf("\nClaimed Interface");
/* Communicate */
int bytes_read;
int nbytes = 256;
unsigned char *my_string, *my_string1;
int transferred = 0;
my_string = (unsigned char *) malloc (nbytes + 1);
my_string1 = (unsigned char *) malloc (nbytes + 1);
strcpy(my_string, "divesd");
printf("\nTo be sent : %s", my_string);
e = libusb_bulk_transfer(handle, BULK_EP_OUT, my_string, bytes_read, &transferred, 5000);
printf("\nXfer returned with %d", e);
printf("\nSent %d bytes with string: %s\n", transferred, my_string);
libusb_bulk_transfer(handle, BULK_EP_IN, my_string1, 256, &transferred, 5000);
printf("\nXfer returned with %d", e); //It returns -1... This is an error, I guess.
printf("\nReceived %d bytes with string: %s\n", transferred, my_string1);
e = libusb_release_interface(handle, 0);
libusb_close(handle);
libusb_exit(NULL);
return 0;
}
Try the code given below and it should work on LPC2148. I have tested this with an LPC2148 configured to receive an interrupt from USB after a write happens (from user-space) and the RTC starts running.
Answering to your question whether it involves a kernel driver in read/write or not: As far as I have studied, you have to detach the kernel driver and claim the interface using libusb APIs. Though I am not sure whether it can be done without detaching it or not.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include </usr/local/include/libusb-1.0/libusb.h>
#define BULK_EP_OUT 0x82
#define BULK_EP_IN 0x08
int interface_ref = 0;
int alt_interface, interface_number;
int print_configuration(struct libusb_device_handle *hDevice, struct libusb_config_descriptor *config)
{
char *data;
int index;
data = (char *)malloc(512);
memset(data, 0, 512);
index = config->iConfiguration;
libusb_get_string_descriptor_ascii(hDevice, index, data, 512);
printf("\nInterface Descriptors: ");
printf("\n\tNumber of Interfaces: %d", config->bNumInterfaces);
printf("\n\tLength: %d", config->bLength);
printf("\n\tDesc_Type: %d", config->bDescriptorType);
printf("\n\tConfig_index: %d", config->iConfiguration);
printf("\n\tTotal length: %lu", config->wTotalLength);
printf("\n\tConfiguration Value: %d", config->bConfigurationValue);
printf("\n\tConfiguration Attributes: %d", config->bmAttributes);
printf("\n\tMaxPower(mA): %d\n", config->MaxPower);
free(data);
data = NULL;
return 0;
}
struct libusb_endpoint_descriptor* active_config(struct libusb_device *dev, struct libusb_device_handle *handle)
{
struct libusb_device_handle *hDevice_req;
struct libusb_config_descriptor *config;
struct libusb_endpoint_descriptor *endpoint;
int altsetting_index, interface_index=0, ret_active;
int i, ret_print;
hDevice_req = handle;
ret_active = libusb_get_active_config_descriptor(dev, &config);
ret_print = print_configuration(hDevice_req, config);
for (interface_index=0;interface_index<config->bNumInterfaces;interface_index++)
{
const struct libusb_interface *iface = &config->interface[interface_index];
for (altsetting_index=0; altsetting_index<iface->num_altsetting; altsetting_index++)
{
const struct libusb_interface_descriptor *altsetting = &iface->altsetting[altsetting_index];
int endpoint_index;
for(endpoint_index=0; endpoint_index<altsetting->bNumEndpoints; endpoint_index++)
{
const struct libusb_endpoint_desriptor *ep = &altsetting->endpoint[endpoint_index];
endpoint = ep;
alt_interface = altsetting->bAlternateSetting;
interface_number = altsetting->bInterfaceNumber;
}
printf("\nEndPoint Descriptors: ");
printf("\n\tSize of EndPoint Descriptor: %d", endpoint->bLength);
printf("\n\tType of Descriptor: %d", endpoint->bDescriptorType);
printf("\n\tEndpoint Address: 0x0%x", endpoint->bEndpointAddress);
printf("\n\tMaximum Packet Size: %x", endpoint->wMaxPacketSize);
printf("\n\tAttributes applied to Endpoint: %d", endpoint->bmAttributes);
printf("\n\tInterval for Polling for data Tranfer: %d\n", endpoint->bInterval);
}
}
libusb_free_config_descriptor(NULL);
return endpoint;
}
int main(void)
{
int r = 1;
struct libusb_device **devs;
struct libusb_device_handle *handle = NULL, *hDevice_expected = NULL;
struct libusb_device *dev, *dev_expected;
struct libusb_device_descriptor desc;
struct libusb_endpoint_descriptor *epdesc;
struct libusb_interface_descriptor *intdesc;
ssize_t cnt;
int e = 0, config2;
int i = 0, index;
char str1[64], str2[64];
char found = 0;
// Init libusb
r = libusb_init(NULL);
if(r < 0)
{
printf("\nFailed to initialise libusb\n");
return 1;
}
else
printf("\nInit successful!\n");
// Get a list of USB devices
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
{
printf("\nThere are no USB devices on the bus\n");
return -1;
}
printf("\nDevice count: %d\n-------------------------------\n", cnt);
while ((dev = devs[i++]) != NULL)
{
r = libusb_get_device_descriptor(dev, &desc);
if (r < 0)
{
printf("Failed to get device descriptor\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
break;
}
e = libusb_open(dev, &handle);
if (e < 0)
{
printf("Error opening device\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
break;
}
printf("\nDevice Descriptors: ");
printf("\n\tVendor ID: %x", desc.idVendor);
printf("\n\tProduct ID: %x", desc.idProduct);
printf("\n\tSerial Number: %x", desc.iSerialNumber);
printf("\n\tSize of Device Descriptor: %d", desc.bLength);
printf("\n\tType of Descriptor: %d", desc.bDescriptorType);
printf("\n\tUSB Specification Release Number: %d", desc.bcdUSB);
printf("\n\tDevice Release Number: %d", desc.bcdDevice);
printf("\n\tDevice Class: %d", desc.bDeviceClass);
printf("\n\tDevice Sub-Class: %d", desc.bDeviceSubClass);
printf("\n\tDevice Protocol: %d", desc.bDeviceProtocol);
printf("\n\tMax. Packet Size: %d", desc.bMaxPacketSize0);
printf("\n\tNumber of Configurations: %d\n", desc.bNumConfigurations);
e = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, (unsigned char*) str1, sizeof(str1));
if (e < 0)
{
libusb_free_device_list(devs, 1);
libusb_close(handle);
break;
}
printf("\nManufactured: %s", str1);
e = libusb_get_string_descriptor_ascii(handle, desc.iProduct, (unsigned char*) str2, sizeof(str2));
if(e < 0)
{
libusb_free_device_list(devs, 1);
libusb_close(handle);
break;
}
printf("\nProduct: %s", str2);
printf("\n----------------------------------------");
if(desc.idVendor == 0xffff && desc.idProduct == 0x4)
{
found = 1;
break;
}
}//end of while
if(found == 0)
{
printf("\nDevice NOT found\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return 1;
}
else
{
printf("\nDevice found");
dev_expected = dev;
hDevice_expected = handle;
}
e = libusb_get_configuration(handle, &config2);
if(e!=0)
{
printf("\n***Error in libusb_get_configuration\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
printf("\nConfigured value: %d", config2);
if(config2 != 1)
{
libusb_set_configuration(handle, 1);
if(e!=0)
{
printf("Error in libusb_set_configuration\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
else
printf("\nDevice is in configured state!");
}
libusb_free_device_list(devs, 1);
if(libusb_kernel_driver_active(handle, 0) == 1)
{
printf("\nKernel Driver Active");
if(libusb_detach_kernel_driver(handle, 0) == 0)
printf("\nKernel Driver Detached!");
else
{
printf("\nCouldn't detach kernel driver!\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
}
e = libusb_claim_interface(handle, 0);
if(e < 0)
{
printf("\nCannot Claim Interface");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
else
printf("\nClaimed Interface\n");
active_config(dev_expected, hDevice_expected);
// Communicate
char *my_string, *my_string1;
int transferred = 0;
int received = 0;
int length = 0;
my_string = (char *)malloc(nbytes + 1);
my_string1 = (char *)malloc(nbytes + 1);
memset(my_string, '\0', 64);
memset(my_string1, '\0', 64);
strcpy(my_string, "Prasad Divesd");
length = strlen(my_string);
printf("\nTo be sent: %s", my_string);
e = libusb_bulk_transfer(handle, BULK_EP_IN, my_string, length, &transferred, 0);
if(e == 0 && transferred == length)
{
printf("\nWrite successful!");
printf("\nSent %d bytes with string: %s\n", transferred, my_string);
}
else
printf("\nError in write! e = %d and transferred = %d\n", e, transferred);
sleep(3);
i = 0;
for(i = 0; i < length; i++)
{
e = libusb_bulk_transfer(handle, BULK_EP_OUT, my_string1, 64, &received, 0); //64: Max Packet Length
if(e == 0)
{
printf("\nReceived: ");
printf("%c", my_string1[i]); //Will read a string from LPC2148
sleep(1);
}
else
{
printf("\nError in read! e = %d and received = %d\n", e, received);
return -1;
}
}
e = libusb_release_interface(handle, 0);
libusb_close(handle);
libusb_exit(NULL);
printf("\n");
return 0;
}

USB applications using libusb library

I want to use libusb library for writing some test applications for USB.
Can any one please suggest how to set control transfers using usb_control_msg call?
I am getting bad descriptor error while running the following code.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "usb.h"
static int vendor_id;
static int product_id;
typedef struct{
int requesttype;
int request;
int value;
int index;
char *bytes;
int size;
int timeout;
}ctrlmsg_param;
void print_endpoint(struct usb_endpoint_descriptor *endpoint)
{
printf("=====End point Information====\n");
printf("bEndpointAddress: %x\n", endpoint->bEndpointAddress);
printf("bmAttributes: %x\n", endpoint->bmAttributes);
printf("wMaxPacketSize: %d\n", endpoint->wMaxPacketSize);
printf("bInterval: %d\n", endpoint->bInterval);
printf("bRefresh: %d\n", endpoint->bRefresh);
printf("bSynchAddress: %d\n", endpoint->bSynchAddress);
}
void print_altsetting(struct usb_interface_descriptor *interface)
{
int i;
printf("\n=====Alternate Setting Information====\n");
printf("bInterfaceNumber: %d\n", interface->bInterfaceNumber);
printf("bAlternateSetting: %d\n", interface->bAlternateSetting);
printf("bNumEndpoints: %d\n", interface->bNumEndpoints);
printf("bInterfaceClass: %d\n", interface->bInterfaceClass);
printf("bInterfaceSubClass: %d\n", interface->bInterfaceSubClass);
printf("bInterfaceProtocol: %d\n", interface->bInterfaceProtocol);
printf("iInterface: %d\n", interface->iInterface);
for (i = 0; i < interface->bNumEndpoints; i++)
print_endpoint(&interface->endpoint[i]);
}
void print_interface(struct usb_interface *interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
print_altsetting(&interface->altsetting[i]);
}
void print_configuration(struct usb_config_descriptor *config)
{
int i;
printf("=====Configuration Information====\n");
printf("wTotalLength: %d\n", config->wTotalLength);
printf("bNumInterfaces: %d\n", config->bNumInterfaces);
printf("bConfigurationValue: %d\n", config->bConfigurationValue);
printf("iConfiguration: %d\n", config->iConfiguration);
printf("bmAttributes: %x\n", config->bmAttributes);
printf("MaxPower: %d\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++)
print_interface(&config->interface[i]);
}
int print_device(struct usb_device *dev)
{
usb_dev_handle *udev;
char str[100];
int ret, i;
udev = usb_open(dev);
if (udev) {
if (dev->descriptor.iManufacturer) {
ret = usb_get_string_simple(udev, dev->descriptor.iManufacturer, str, sizeof(str));
if (ret > 0)
{
printf("Manufacturer is %s\n",str);
}
}
if (dev->descriptor.iProduct) {
ret = usb_get_string_simple(udev, dev->descriptor.iProduct, str, sizeof(str));
if (ret > 0)
{
printf("Product is %s\n",str);
}
}
}
if (udev)
usb_close(udev);
printf("Possible configurations are %x\n",dev->descriptor.bNumConfigurations);
sleep(2);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
print_configuration(&dev->config[i]);
return 0;
}
int htod( const char* str )
{
int decimal;
sscanf( str, "%x", &decimal);
return decimal;
}
void set_data(struct usb_device *dev)
{
ctrlmsg_param param;
param.requesttype= 0;
param.request=0;
param.value=0;
param.index=0;
param.bytes=10;
param.size=0;
param.timeout=5000;
usb_control_msg(dev, param.requesttype, param.request, param.value, param.index, param.bytes, param.size, param.timeout);
printf("error is %s\n",strerror(errno));
return;
}
int main(int argc, char *argv[])
{
struct usb_bus *bus;
struct usb_device *dev;
if(argc != 3)
{
printf("Error in number of arguments\n");
printf("Usage:./usb_info <vendor id> <product id>\n");
exit(0);
}
vendor_id=htod(argv[1]);
product_id=htod(argv[2]);
printf("initializing USB library\n");
usb_init();
printf("Finding Buses and Devices\n");
usb_find_busses();
usb_find_devices();
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if ((dev->descriptor.idProduct == product_id) && (dev->descriptor.idVendor == vendor_id)){
printf("Found device with produxt id %x and vendor id %x\n",product_id,vendor_id);
print_device(dev);
set_data(dev);
print_device(dev);
}
}
}
return 0;
}
Regards,
Sandeep
I think that you mean usb_control_msg() is returns an error code for "bad descriptor". Please clarify if this is incorrect.
USB control transfers have some very specific formatting rules, and if the packet you are forming is sent to any compliant device, it will return a request error / stall on the bus.
You are sending the control transfer:
bmRequestType = 0x00
bRequest = 0x00
wValue = 0x0000
wIndex = 0x0000
wSize = 0x0000
this should be interpreted by the USB device as a GET_STATUS request, so wLength is required to be 2, and bmRequestType needs to have the top bit set, indicating this is an IN direction request (from the host's point of view). This is all from Chapter 9 of the USB specification 1.1/2.0/3.1 available at www.usb.org.
The parameter char *bytes (your param.bytes) also needs to be an address/pointer in the call you are making.
A good standard control transfer to test with would be:
bmRequestType = 0x80
bRequest = 0x06
wValue = 0x0001
wIndex = 0x0000
wSize = 0x0008
This request will return the first 8 bytes of the Device Descriptor, it is valid for every USB device, in all states.
The other transfer types (bulk, interrupt) don't have these strict formatting rules, and can be an easier place to start. I'd imagine you have already moved past this issue, since the question has been posted for quite a while, but maybe this response will still help someone else.

True non-blocking two-way communication between parent and external child process

I have read around 50 posts and tutorials on this topic, I have copied, written and tested around 20 alternatives and done every possible research I can think of. Still, I have not seen a working solution for the following problem:
Parent process A wants to pass data to an external process B, let process B modify the data and pass it back to parent process A, then continue with parent process A. Process B is part of an external program suite that I have no influence over, and that is normally run like this on the UNIX command line:
< input_data program_B1 | program_B2 | program_B3 > output_data
...where
input_data, output_data: Some data that is processed in programs B1-B3
program_B1,B2,B3: Programs that read data from stdin (fread) and output to stdout (fwrite) and apply some processing to the data.
So, in sequence:
(1) Parent process A passes data to child process B
(2) Child process B reads data and modifies it
(3) Child process B passes data back to parent process A
(4) Parent process A reads data and continues (for example passing it further on to a process B2..).
(5) Parent process A passes another data set to child process B etc.
The problem is, whatever I do, the program almost always ends up hanging on a read/fread (or write/fwrite?) to or from a pipe.
One important thing to note is that the parent process cannot simply close the pipes after passing data on to the child process, because it works in a loop and wants to pass another set of data to the child process once it has finished processing the first set.
Here is a working set of parent/child programs (compile with g++ pipe_parent.cc -o pipe_parent, g++ pipe_child.cc -o pipe_child) illustrating the problem with unnamed pipes. I have also tried named pipes, but not as extensively. Each execution can have a slightly different outcome. If the sleep statement is omitted in the parent, or the fflush() statement is omitted in the child, the pipes will almost surely block. If the amount of data to be passed on is increased, it will always block independent of the sleep or fflush.
Parent program A:
#include <cstring>
#include <cstdio>
#include <cstdlib>
extern "C" {
#include <unistd.h>
#include <fcntl.h>
}
using namespace std;
/*
* Parent-child inter-communication
* Child is external process
*/
int main() {
int fd[2];
if( pipe(fd) == -1 ) {
fprintf(stderr,"Unable to create pipe\n");
}
int fd_parentWrite = fd[1];
int fd_childRead = fd[0];
if( pipe(fd) == -1 ) {
fprintf(stderr,"Unable to create pipe\n");
exit(-1);
}
int fd_childWrite = fd[1];
int fd_parentRead = fd[0];
pid_t pid = fork();
if( pid == -1 ) {
fprintf(stderr,"Unable to fork new process\n");
exit(-1);
}
if( pid == 0 ) { // Child process
dup2( fd_childRead, fileno(stdin) ); // Redirect standard input(0) to child 'read pipe'
dup2( fd_childWrite, fileno(stdout) ); // Redirect standard output(1) to child 'write pipe'
close(fd_parentRead);
close(fd_parentWrite);
close(fd_childRead);
close(fd_childWrite);
// execl replaces child process with an external one
int ret = execl("/disk/sources/pipe_test/pipe_child","pipe_child",NULL);
fprintf(stderr,"External process failed, return code: %d...\n", ret);
exit(-1);
// Child process is done. Will not continue from here on
}
else { // Parent process
// Nothing to set up
}
// ...more code...
if( pid > 0 ) { // Parent process (redundant if statement)
int numElements = 10000;
int totalSize = numElements * sizeof(float);
float* buffer = new float[numElements];
for( int i = 0; i < numElements; i++ ) {
buffer[i] = (float)i;
}
for( int iter = 0; iter < 5; iter++ ) {
fprintf(stderr,"--------- Iteration #%d -----------\n", iter);
int sizeWrite = (int)write( fd_parentWrite, buffer, totalSize );
if( sizeWrite == -1 ) {
fprintf(stderr,"Parent process write error\n");
exit(-1);
}
fprintf(stderr,"Parent #%d: Wrote %d elements. Total size: %d\n", iter, sizeWrite, totalSize);
sleep(1); // <--- CHANGE!
int sizeRead = (int)read( fd_parentRead, buffer, totalSize );
if( sizeRead <= 0 ) {
fprintf(stderr,"Parent process read error\n");
}
while( sizeRead < totalSize ) {
fprintf(stderr,"Parent #%d: Read %d elements, continue reading...\n", iter, sizeRead);
int sizeNew = (int)read( fd_parentRead, &buffer[sizeRead], totalSize-sizeRead );
fprintf(stderr," ...newly read %d elements\n", sizeNew);
if( sizeNew < 0 ) {
exit(-1);
}
sizeRead += sizeNew;
}
fprintf(stderr,"Parent #%d: Read %d elements. Total size: %d\n", iter, sizeRead, totalSize);
fprintf(stderr,"Examples : %f %f %f\n", buffer[0], buffer[10], buffer[100]);
}
delete [] buffer;
}
close(fd_parentRead);
close(fd_parentWrite);
close(fd_childRead);
close(fd_childWrite);
return 0;
}
Child program B:
#include <cstdio>
using namespace std;
int main() {
int numElements = 10000;
int totalSize = numElements * sizeof(float);
float* buffer = new float[numElements];
int counter = 0;
int sizeRead = 0;
do {
sizeRead = fread( buffer, 1, totalSize, stdin);
fprintf(stderr,"Child #%d: Read %d elements, buffer100: %f\n", counter, sizeRead, buffer[100]);
if( sizeRead > 0 ) {
for( int i = 0; i < numElements; i++ ) {
buffer[i] += numElements;
}
int sizeWrite = fwrite( buffer, 1, totalSize, stdout);
fflush(stdout); // <--- CHANGE!
fprintf(stderr,"Child #%d: Wrote %d elements\n", counter, sizeWrite);
counter += 1;
}
} while( sizeRead > 0 );
return 0;
}
Is there any way to check when the pipe has enough data to be read? Or is there an alternative way to resolve the above problem, with or without pipes?
Please help!
Possibly the best solution when reading is to check with select whether you can read from the pipe. You can even pass a timeout. The alternative might be setting the O_NONBLOCK flag on file descriptor 0 (stdin) with fcntl, though I think the select way is better.
As with ensuring non-blocking write: that's a bit harder as you don't know how much you can write before the pipe blocks. One way (that I feel is very ugly) would be to only write 1 byte chunks and again check with select whether you can write. But that would be a performance killer, so use only if performance in communication is not an issue.
The first answer (using select to find out whether a pipe is ready to be read from) was good but didn't really solve my issue, see also my previous comments. Sooner or later I always ended up with a "race condition" where the program kept hanging either on a read or write.
The solution (maybe not be the only one?) is to run the child-to-parent data transfer in a different thread. I also went back and implemented the pipes as named pipes. It would probably also work with unnamed pipes but I didn't check that.
The final code is below. Note that no explicit flushing is required; the parent-to-child and child-to-parent data transfers are now decoupled. Any comments how this can be improved welcome! One residual problem I can see is that the pipes may fill up depending on how long time the child needs to process the data. I'm not sure how likely this is to happen. And by the way this worked fine with my external programs, not only with the provided child program.
Parent program A:
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <iostream>
extern "C" {
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
}
using namespace std;
static int const READING = -1;
static int const BUFFER_READY = 1;
static int const FINISHED = 0;
/*
* Parent-child inter-communication
* Child is external process
*/
struct threadStruct {
FILE* file_c2p;
int sizeBuffer;
float* buffer;
int io_flag;
};
// Custom sleep function
void mini_sleep( int millisec ) {
struct timespec req={0},rem={0};
time_t sec = (int)(millisec/1000);
millisec = (int)(millisec-(sec*1000));
req.tv_sec = sec;
req.tv_nsec = millisec*1000000L;
nanosleep(&req,&rem);
}
// Function to be executed within separate thread: Reads in data from file pointer
// Hand-shaking with main thread is done via the flag 'io_flag'
void *threadFunction( void *arg ) {
threadStruct* ptr = (threadStruct*)arg;
ptr->io_flag = READING;
while( ptr->io_flag != FINISHED ) {
if( ptr->io_flag == READING ) {
int sizeRead = fread( ptr->buffer, 1, ptr->sizeBuffer, ptr->file_c2p );
if( sizeRead <= 0 ) {
ptr->io_flag = FINISHED;
return NULL;
}
ptr->io_flag = BUFFER_READY;
}
else {
mini_sleep(10);
}
}
return NULL;
}
//--------------------------------------------------
int main() {
std::string filename_p2c("/tmp/fifo11_p2c");
std::string filename_c2p("/tmp/fifo11_c2p");
fprintf(stderr,"..started\n");
int status = mknod(filename_p2c.c_str(), S_IRUSR | S_IWUSR | S_IFIFO, 0);
if( (status == -1) && (errno != EEXIST) ) {
fprintf(stderr,"Error creating named pipe: %s\n", strerror(errno));
exit(-1);
}
status = mknod(filename_c2p.c_str(), S_IRUSR | S_IWUSR | S_IFIFO, 0);
if( (status == -1) && (errno != EEXIST) ) {
fprintf(stderr,"Error creating named pipe: %s\n", strerror(errno));
exit(-1);
}
FILE* file_dump = fopen("parent_dump","w");
int fd_p2c;
int fd_c2p;
FILE* file_c2p = NULL;
//--------------------------------------------------
// Set up parent/child processes
//
pid_t pid = fork();
if( pid == -1 ) {
fprintf(stderr,"Unable to fork new process\n");
}
if( pid == 0 ) { // Child process
fd_p2c = open( filename_p2c.c_str(), O_RDONLY );
if( fd_p2c < 0 ) {
fprintf(stderr,"Child: Error opening the named pipe: %d %d '%s'\n", fd_p2c, errno, strerror(errno));
exit(-1);
}
fd_c2p = open( filename_c2p.c_str(), O_WRONLY );
if( fd_c2p < 0 ) {
fprintf(stderr,"Child: Error opening the named pipe: %d %d '%s'\n", fd_c2p, errno, strerror(errno));
exit(-1);
}
dup2(fd_p2c,fileno(stdin)); // Redirect standard input(0) to child 'read pipe'
dup2(fd_c2p,fileno(stdout)); // Redirect standard output(1) to child 'write pipe'
close(fd_p2c);
close(fd_c2p);
int ret = execl("/disk/sources/pipe_test/pipe_child","pipe_child",NULL);
fprintf(stderr,"External process failed, return code: %d...\n", ret);
kill( getppid(), 9 ); // Kill parent process
exit(-1);
}
else { // Parent process
fd_p2c = open( filename_p2c.c_str(), O_WRONLY );
if( fd_p2c < 0 ) {
fprintf(stderr,"Parent: Error opening the named pipe: %d %d '%s'\n", fd_p2c, errno, strerror(errno));
exit(-1);
}
file_c2p = fopen( filename_c2p.c_str(), "r");
fd_c2p = fileno( file_c2p );
if( fd_c2p < 0 ) {
fprintf(stderr,"Parent: Error opening the named pipe: %d %d '%s'\n", fd_c2p, errno, strerror(errno));
exit(-1);
}
}
int numElements = 10000;
int sizeBuffer = numElements * sizeof(float);
float* bufferIn = new float[numElements];
float* bufferOut = new float[numElements];
for( int i = 0; i < numElements; i++ ) {
bufferIn[i] = 0.0;
}
int numIterations = 5;
int numBytesAll = numElements * sizeof(float) * numIterations;
pthread_t thread;
threadStruct* threadParam = new threadStruct();
threadParam->file_c2p = file_c2p;
threadParam->sizeBuffer = sizeBuffer;
threadParam->buffer = bufferIn;
threadParam->io_flag = READING;
int thread_stat = pthread_create( &thread, NULL, threadFunction, threadParam );
if( thread_stat < 0 ) {
fprintf(stderr,"Error when creating thread\n");
exit(-1);
}
int readCounter = 0;
int numBytesWrite = 0;
int numBytesRead = 0;
for( int iter = 0; iter < numIterations; iter++ ) {
for( int i = 0; i < numElements; i++ ) {
bufferOut[i] = (float)i + iter*numElements*10;
}
int sizeWrite = (int)write( fd_p2c, bufferOut, sizeBuffer );
if( sizeWrite == -1 ) {
fprintf(stderr,"Parent process write error\n");
exit(-1);
}
numBytesWrite += sizeWrite;
fprintf(file_dump,"Parent #%d: Wrote %d/%d bytes.\n", iter, numBytesWrite, numBytesAll);
if( iter == numIterations-1 ) close(fd_p2c); // Closing output pipe makes sure child receives EOF
if( threadParam->io_flag != READING ) {
numBytesRead += sizeBuffer;
fprintf(file_dump,"Parent #%d: Read %d/%d bytes. Examples: %f %f\n",
readCounter, numBytesRead, numBytesAll, bufferIn[1], bufferIn[numElements-1] );
readCounter += 1;
if( threadParam->io_flag != FINISHED ) threadParam->io_flag = READING;
}
}
//********************************************************************************
//
fprintf(file_dump,"------------------------------\n");
while( threadParam->io_flag != FINISHED ) {
if( threadParam->io_flag == BUFFER_READY ) {
numBytesRead += sizeBuffer;
fprintf(file_dump,"Parent #%d: Read %d/%d bytes. Examples: %f %f\n",
readCounter, numBytesRead, numBytesAll, bufferIn[1], bufferIn[numElements-1] );
readCounter += 1;
if( threadParam->io_flag != FINISHED ) threadParam->io_flag = READING;
}
else {
mini_sleep(10);
}
}
// wait for thread to finish before continuing
pthread_join( thread, NULL );
fclose(file_dump);
fclose(file_c2p);
waitpid(pid, &status, 0); // clean up any children
fprintf(stderr,"..finished\n");
delete [] bufferIn;
delete [] bufferOut;
return 0;
}
Child program B:
#include <cstdio>
using namespace std;
int main() {
int numElements = 10000;
int totalSize = numElements * sizeof(float);
float* buffer = new float[numElements];
FILE* file_dump = fopen("child_dump","w");
int counter = 0;
int sizeRead = 0;
do {
sizeRead = fread( buffer, 1, totalSize, stdin);
if( sizeRead > 0 ) {
fprintf(file_dump,"Child #%d: Read %d bytes, examples: %f %f\n", counter, sizeRead, buffer[1], buffer[numElements-1]);
for( int i = 0; i < numElements; i++ ) {
buffer[i] += numElements;
}
int sizeWrite = fwrite( buffer, 1, totalSize, stdout);
fprintf(file_dump,"Child #%d: Wrote %d bytes, examples: %f %f\n", counter, sizeRead, buffer[1], buffer[numElements-1]);
counter += 1;
}
} while( sizeRead > 0 );
fprintf(file_dump,"Child is finished\n");
fclose(file_dump);
fclose(stdout);
return 0;
}