Detecting Device plugged and unplugged - c

I'm writing a code and im using libudev.h so far i can i can detect devices and open them and put the fd's of the opened devices in devlist for reading and writing of data. My problem is that when i unplugged the device i get a segmentation error.
if (FD_ISSET(fd, &fds))
{
dev = udev_monitor_receive_device(mon);
if (dev)
{
if(strcmp(udev_device_get_action(dev),"add")==0)
{
if(strcmp(udev_device_get_devnode(dev), "/dev/ttyUSB0")==0)
{
fd1 = open(udev_device_get_devnode(dev), O_RDWR | O_NONBLOCK);
if(fd1<0)
{
printf("Can't open Device\n");
exit(0);
}
}
printf("Device plugged\n");
printf(" Node: %s\n", udev_device_get_devnode(dev));
printf(" Action: %s\n", udev_device_get_action(dev));
printf("device opened\n");
int opt =1;
ioctl(fd1, FIONBIO,(char *) &opt);
for(loop=0; loop<MAXDEV; loop++)
if(devlist[loop] == 0)
{
devlist[loop] = fd1;
fd1 = -1;
}
}
else {
printf("Device unplugged\n");
printf(" Node: %s\n", udev_device_get_devnode(dev));
printf(" Action: %s\n", udev_device_get_action(dev));
FD_CLR(devlist[loop],&fds);
close(devlist[loop]);
devlist[loop] = -1;
}
udev_device_unref(dev);
}
Once i get deviced open i can read to its fd and there's no problem with it but when i unplugged the device i get error.
this is the part where i'm having trouble.
printf("Device unplugged\n");
printf(" Node: %s\n", udev_device_get_devnode(dev));
printf(" Action: %s\n", udev_device_get_action(dev));
FD_CLR(devlist[loop],&fds);
close(devlist[loop]);
devlist[loop] = -1;
Thanks..

Accessing a USB serial adapter after it's been unplugged doesn't cause a segfault for me--I tested this pretty heavily for my work a while back.
I notice for one thing that you don't seem to have initialized "loop" to the element of "devlist" that corresponds to unplugged device. That might happen to work if you haven't returned from the function between the plug and unplug events and you unplug the same device as you last plugged in. But that's my bet for where you're segfaulting.
The other candidate I'd suspect is your code for reading or writing the device. The read and write syscalls will return -1 after the device is unplugged, and if you aren't checking for that error or your error handling code has a bug, that could be your problem too.
In general, I'd recommend running your program under gdb and getting a stack trace when it crashes. That will tell you which line number the error occurred on.

Related

Getting the v4l2 device number for a connected USB camera (webcam) from a C application (Linux)

I'm working on a embedded linux system (yocto based) and I'm trying to simply get a list of the camera USB video devices (webcams) numbers with the related connected usb port from a C program.
I'm able to get the devices list with vendor ID and connected port doing this:
void usbdevs()
{
libusb_device*** list=NULL;
libusb_context *context = NULL;
ssize_t count;
uint8_t port;
char ncameras=0;
libusb_init(&context);
count = libusb_get_device_list(context,&list);
for(int i=0; i < MAX_NUM_CAMS; i++)
usb_dev_list[i]=0;
for (size_t idx = 0; idx < count; ++idx) {
libusb_device *device = list[idx];
struct libusb_device_descriptor desc = {0};
libusb_get_device_descriptor(device, &desc);
port = libusb_get_port_number(device);
printf("Vendor:Device = %04x:%04x Port: %d\n", desc.idVendor, desc.idProduct,port);
}
libusb_free_device_list(list, count);
libusb_exit(context);
}
What I need now is to know (from the C application) what v4l2 device number is related to the usb camera port, eg. I've got two webcam (same vendor ID) connected which appear as /dev/video0 and /dev/video1 respectively and I can get the connected port for each one using the above code, but, how can I know which ports are connected each one?
I tried to get information from the devices using ioctl calls as it is recommended in this question but when I run the code:
int checkvideodev()
{
int fd;
struct video_capability video_cap;
struct video_window video_win;
struct video_picture video_pic;
if((fd = open("/dev/video0", O_RDONLY)) == -1){
perror("cam_info: Can't open device");
return 1;
}
if(xioctl(fd, VIDIOCGCAP, &video_cap) == -1)
perror("cam_info: Can't get capabilities");
else {
printf("Name:\t\t '%s'\n", video_cap.name);
printf("Minimum size:\t%d x %d\n", video_cap.minwidth, video_cap.minheight);
printf("Maximum size:\t%d x %d\n", video_cap.maxwidth, video_cap.maxheight);
}
if(xioctl(fd, VIDIOCGWIN, &video_win) == -1)
perror("cam_info: Can't get window information");
else
printf("Current size:\t%d x %d\n", video_win.width, video_win.height);
if(xioctl(fd, VIDIOCGPICT, &video_pic) == -1)
perror("cam_info: Can't get picture information");
else
printf("Current depth:\t%d\n", video_pic.depth);
close(fd);
return 0;
}
I've got the next errors:
cam_info: Can't get capabilities: Inappropriate ioctl for device
cam_info: Can't get window information: Inappropriate ioctl for device
cam_info: Can't get picture information: Inappropriate ioctl for device
If I'm checking through command line for instance I can get the capabilities without issues running:
v4l2-ctl --device-/dev/video0 --list-formats-ext
Any ideas how can this be done?
Thanks in advance.
I don't know if this specifically answers your question, but you can get useful information by globbing certain patterns under /dev or /sys, for example this will return the full device path (including PCI bus) of each video device,
#include <glob.h>
#include <unistd.h>
void list_videos() {
int i;
glob_t globbuf;
if (glob("/sys/class/video4linux/video*", 0, NULL, &globbuf) != 0) {
perror("glob");
return;
}
for (i=0; i < globbuf.gl_pathc; i++) {
char buf[256] = {};
if (readlink(globbuf.gl_pathv[i], buf, sizeof(buf)-1) > 0) {
puts(buf);
}
}
}
On one system with 2 cameras this prints,
../../devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1.1/2-1.1:1.0/video4linux/video0
../../devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/video4linux/video1
Other interesting glob strings include /dev/v4l/by-id/* and /dev/v4l/by-path/*.

Sending data to AVR microcontroller over CP2102 USB to Serial device using C

I've been working on building an AVR powered EEPROM programmer, running on an ATmega1284. I've been trying to write a rather simple program in C that will send the bytes of the hex file over the to AVR, so they can be programmed into the EEPROM. However, although my program does send bytes over a direct USB connection, to my Arduino, it doesn't seem to want to send bytes over the CP2102 device, and so I am unable to send data to my programmer.
For some reason, however, the Arduino IDE's serial monitor seems to work fine sending data over the CP2102. The programmer receives the data just fine. Obviously though this can't be a solution, since the serial monitor has no way of sending mass data, hence the need for this program. Does anyone know how I'm supposed to interface with this CP2102 device? I've tried using normal USB code, and have looked at the Linux CP2102 driver on Torvalds' GitHub, but couldn't extrapolate anything useful. My current program uses the code from the accepted answer here, running on Linux Mint 18, compiled with gcc. My implementation of it is as follows:
void main(int argc, char *argv[]) { //file, port
portname = argv[2];
printf("Programming EEPROM...\n");
char* fileBytes = readFileBytes(argv[1]);
int fd = open(argv[2], O_RDWR);
if (fd < 0)
{
printf("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B57600, 0);
set_blocking (fd, 0);
for(int i = 0; i < len; i++){
char byte = fileBytes[i];
printf("%02x\n", byte);//TODO remove
write(fd, byte, 1);
char buf[1];
buf[0] = (int)NULL;
while(buf[0] == NULL){
read(fd, buf, 1);
}
char b = buf[0];
if(b == 0x0f){
printf("ERROR REPORTED BY PROGRAMMER, EXITING\n");
exit(1);
}else if(b == 0x0e){
printf("Byte good, continuing...\n");//TODO remove
}else{
printf("Unknown byte received: %02x\n", b);
exit(1);
}
}
printf("Transmission finished.\n");
usleep(20000); //wait 20ms (or maybe a tiny bit more)
write(fd, 0x0d, 1);
usleep(500); //wait for slow ass avr
char buf[1];
buf[0] = (int)NULL;
read(fd, buf, 1);
if(buf[0] == 0x0d){
printf("Programmer acknowledge. All good!\n");
}
printf("EEPROM programming successful. Exiting...\n");
}

I/O pending error while reading data from serial port

I have a C program that trying to read data from COM Port in windows.
I am able to write the data on com port but not able to read it.
This is my read function? if anyone could take a look and point me to correct direction.
I am starting a seperate thread in main method
------ Code of main method function ------
if(!SetCommMask(hSerial,eventFlags)){
printf("Error in setting the event maskwith error: %d \n",GetLastError());}
_beginthread(*readDataFromPort,0,NULL);
----- Code of read data function ------
void readDataFromPort(void*)
{
DWORD dwReadResult;
bool waitOnRead = FALSE;
bool abContinue = TRUE;
memset(&ovRead,0,sizeof(ovRead));
ovRead.hEvent = CreateEvent(0,TRUE,0,0);
if(ovRead.hEvent == NULL){
fprintf(stderr,"Error creating overlapped event for reading");
}
//Reading data from port
while (true){
//Changed the overlap to NULL
if(WaitCommEvent(hSerial,&eventFlags,NULL)){
if(GetCommMask(hSerial,&dwMask)){
ResetEvent(ovRead.hEvent);
if(dwMask == EV_RXCHAR){
printf("character arrived");
}
}
memset(tmp,0,sizeof(tmp));
if(!ReadFile(hSerial, tmp, sizeof(tmp), NULL, &ovRead)){
if(GetLastError()!=ERROR_IO_PENDING){
printf("error io pending: Error is %d\n",GetLastError());
break;
}else{
waitOnRead=TRUE;
}
}
if(waitOnRead){
dwReadResult = WaitForSingleObject(ovRead.hEvent,10000);
switch(dwReadResult){
case WAIT_OBJECT_0:
if(!GetOverlappedResult(hSerial,&ovRead,&dwBytesRead,TRUE)){
printf("Damn error again :-(");
}else{
if(dwBytesRead>0){
++Rx;
printf("Tx - %d: Rx - %d\n",Tx,Rx);
printf("%s",tmp);
}
}
}
}
waitOnRead=FALSE;
}
if(strlen(tmp)>0 && inLoop){
writeDataToPort(*tmp);
}
}
CloseHandle(ovRead.hEvent);
_endthread();
}
> Blockquote
_beginthread(*readDataFromPort,0,NULL);
This snippet starts the thread regardless of SetComMask outcome, but if you are reading OK must have worked.
Check out MSDN threaded port read/write which works (VC5 compile worked straight off out of the box) above code looks really similar though, is it same?.

socket connection getting closed abruptly with code 141

What im trying to do is connect to a remote server , read contents from a file on the local machine and send it over to the server. Then capture the server response and save it. I put the GET command in a text file and am trying get the results of the same. Here is some part of the code. Im doing this using sockets and C.
if ( inet_pton(AF_INET,ip, &(nc_args->destaddr.sin_addr.s_addr)) <= 0 )
printf("\n\t\t inet_pton error");
if (connect(sockfd, (struct sockaddr *) &nc_args->destaddr, sizeof(&nc_args->destaddr)) < 0)
{
printf("\n\t\t Connection error");
exit(1);
}
puts("\n\t\t Connection successful to ...");
// file parameter is taken from command line and passéd to this function
fp = fopen(file,"rb");
if ( fp == NULL)
{
printf("\n\t\t File not found");
exit(3);
}
else
{
printf("\n\t\t Found file %s\n", file);
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
rewind(fp);
//allocate memory to the buffer dynamically
buffer = (char*) malloc (sizeof(char)*file_size);
if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
for (i=0 ; i<sizeof(buffer); i++)
{
printf("\n\t\t %s", buffer);
}
printf("\n\t\t File contains %ld bytes!\n", file_size);
printf("\n\t\t Sending the file now");
}
while (1)
{
bytes_read = fread(buffer,1, file_size, fp);
printf("\n\t\t The bytes read is %zd", bytes_read);
if (bytes_read == 0) // We're done reading from the file
{
printf("\n\t\t The bytes read is %zd", bytes_read);
break;
}
if (bytes_read < 0)
{
printf("\n\t\t ERROR reading from file");
}
void *p = buffer;
while (bytes_read > 0)
{
ssize_t bytes_written = send(sockfd, buffer, bytes_read,0);
if (bytes_written <= 0)
{
printf("\n\t\t ERROR writing to socket\n");
}
bytes_read -= bytes_written;
p += bytes_written;
printf("\n\t\t Bytes %zd written", bytes_written);
}
}
printf("\n\n\t\t Sending complete.");
What is happening here is that i get the message "connection successful", then it displays "sending the file now" and then the program quits unexpectedly. if i do echo $? i get 141 as the exit code. I am trying to connect from my server to a different server at work and get the results. These two can communicate correctly, and i can run the GET command from command line without issues. Its just not working from the code. Can someone let me know what the issue could be ?
On Linux, and probably other Unixes, the return code encodes a signal that the process received. Here it is 141 - 128 so 13 which corresponds to SIGPIPE.
If you don't want that signal to be raised because you capture the error return of send, anyhow, on Linux you can use MSG_NOSIGNAL in the flags argument to send to inhibit that signal. On other platforms you might have to program more complicated signal handlers to deal with that situation.
sizeof(&nc_args->destaddr) is the wrong thing to pass to connect. It wants the size of the address, not the size of a pointer to the address.
And this loop:
for (i=0 ; i<sizeof(buffer); i++)
{
printf("\n\t\t %s", buffer);
}
is baffling. buffer is a pointer, as we can see from when it was assigned a vlue returned by malloc. So its size is going to be 4 or 8 bytes on 32-bit and 64-bit architectures respectively; not related to the size of the malloc'ed object it points to. The loop runs 4 or 8 times, and prints... the same thing each time. Why?

Issues writing to serial port on MAC OSX using unistd.h in c

I am trying to write to a bluetooth device on MAC OSX using the unistd.h Linux functions in c. I am connecting fine and writing the first few bytes with success. When I try to write other commands to it (there are bytes added to the write buffer every 15ms), I don't see any results even though the write() function returns 1 (write success).
If you start a write and it doesn't finish by the time you try to start another write (since it is non-blocking), could that possibly screw up the initial write? (If so, is there any way to check if a write has completed?) That is the only thing I can think of since the writes are occurring fairly frequently and the first two are successfully sent.
qwbyte() simply adds a byte to the output array and increments its length
The open port function:
BAMid = -1;
struct termios options;
struct termios originalTTYAttrs;
// Open the serial port read/write, nonblocking, with no controlling terminal, and don't wait for a connection.
BAMid = open(strPath, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (BAMid == -1)
{
printf("Error opening serial port %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
// Issue TIOCEXCL ioctl to prevent additional opens except by root-owned processes.
if (ioctl(BAMid, TIOCEXCL) == -1)
{
printf("Error setting TIOCEXCL on %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
// Get the current options and save them so we can restore the default settings later.
if (tcgetattr(BAMid, &originalTTYAttrs) == -1)
{
printf("Error getting tty attributes %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
// The serial port attributes such as timeouts and baud rate are set by modifying the termios
// structure and then calling tcsetattr() to cause the changes to take effect. Note that the
// changes will not become effective without the tcsetattr() call.
options = originalTTYAttrs;
// Set raw input (non-canonical) mode, with reads blocking until either a single character
// has been received or a one second timeout expires. [should be moot since we are leaving it as nonblocking]
cfmakeraw(&options);
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 10;
cfsetspeed(&options, B57600); // Set 57600 baud
options.c_cflag |= CS8; // Use 8 bit words
// Cause the new options to take effect immediately.
if (tcsetattr(BAMid, TCSANOW, &options) == -1)
{
printf("Error setting tty attributes %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
//flush old transmissions
if (tcflush(BAMid,TCIOFLUSH) == -1) {
printf("Error flushing BAM serial port - %s(%d).\n",
strerror(errno), errno);
}
oBufLength = 0;
// Ask it to start
if (! qwbyte(CmdStart) ) {
goto error;
}
if (! qwbyte(CmdFull) ) {
goto error;
}
//this transmit works
txbytes();
printf("success opening port!");
return -1;
// Failure path
error:
if (BAMid != -1) {
close(BAMid);
}
printf("returning an error--%d",errno);
return errno;
}
The write function (txbytes):
int i, bufSize, numBytes;
if(oBufLength != 0) { //if the output array isn't empty
//duplicating the output array and its size so it can
//be overwritten while this write is occuring
printf("about to transmit: ");
for(i = 0; i < oBufLength; i++) {
printf(" %u",oBuf[i]);
tempBuf[i] = oBuf[i];
}
printf("\n");
bufSize = oBufLength;
oBufLength = 0;
numBytes = write(BAMid, &tempBuf, bufSize);
printf("bytes written = %d\n",numBytes);
if (numBytes == -1) {
printf("Error writing to port - %s(%d).\n", strerror(errno), errno);
}
return (numBytes > 0);
}
else {
return 0;
}
Non-blocking writes don't work how you're expecting them to.
If the write can't be completed immediately, write() returns to your code - but it doesn't keep trying to send the data in the background. All it does is say "I couldn't write at the moment - try again later". It does this by returning -1, with errno set to EAGAIN.
Also, remember that when successful, write() returns the number of bytes successfully written. So if you're getting a return value of 1 when you asked for 2 bytes to be written, that means it was only partially successful, and you need to call write() again some time for the second byte.
Basically, if you're using non-blocking IO, you want your txbytes() function to call write() in a loop until either your buffer is empty, or it returns -1. If it returned -1 you need to check errno - if it's EAGAIN, you'll have to call write() again some other time; anything else is probably a real error. Something like this:
ssize_t written = 0;
while (oBufLength > 0 && written > -1)
{
size_t i;
printf("about to transmit %d bytes: ", oBufLength);
for(i = 0; i < oBufLength; i++) {
printf(" %u",oBuf[i]);
}
printf("\n");
written = write(BAMid, oBuf, oBufLength);
printf("Write returned %d\n", written);
if (written > 0)
{
/* The first "written" number of bytes in the buffer have now been sent, so
* we discard them and move up the remaining bytes (if any) to the start of
* the buffer */
oBufLength -= written;
memmove(oBuf, oBuf + written, oBufLength);
printf("Now have %d bytes left to send.\n", oBufLength);
}
}
if (written > -1 || errno == EAGAIN)
{
/* No fatal errors... */
return 0;
} else
/* error left in errno for caller to inspect */
return -1;
}
Note that there's no need to duplicate the buffer - since write() doesn't do anything in parallel with your code. If it says its written the bytes, it doesn't need your buffer any more. Hope that helps!

Resources