On 03.08.2011 04:56, Max S. wrote: > Thanks bundles for your reply. > > On Tue, 2011-08-02 at 20:44 +0200, Oliver Hartkopp wrote: >> > I would like to know if and how socketcan supports hotpluging. >> > >> > I'm using a usb device (PCANUsb). >> >> in general the PCAN driver comes with some udev rules that set up the chardev >> CAN devices (like /dev/pcan32, etc). >> >> These udev rules are not very relevant to the netdevices called can0, can1, >> ... that are created additionally when the PEAK driver detects it's USB >> hardware. >> >> > What are the basics of making a socket device hotplugable, and what does >> > that look like in C? >> > >> > If a socket file descriptor disappears, you will get a short read. How >> > would one know when the device reappears and recover? >> >> The problem (especially with USB devices) is that they can disappear and >> reappear. In the module commandline from the pcan driver you can assign >> netdevice names to chardevice names (see PDF doc) but there's no guarantee, >> that the chardev-name is chosen the same at re-plug time. >> >> The best is to create a udev rule, that checks the 'irq' column in /proc/pcan >> which contains a device ID (usually 255) that can be modified with a PEAK >> tool >> to distinguish PCAN USB devices properly. > > For simplicity lets assume there is only one CAN device. or lets assume that > my application is only interested in can0 wherever that interface comes from > (usb/pci/etc.). Perhaps stating i was working with a usb device was somewhat > misleading.
If you only have ONE CAN device, this makes it really much easier, indeed: You just need to set the interface index to zero, which means, you receive from ALL CAN interfaces. But in the 'sending' case you need to specify the outgoing interface anyway ... > >> >> You can use this kind of udev rule to put a defined PCAN USB device ID to a >> predefined CAN netdevice name (by renaming the netdev with the ip tool). >> > > So the trick becomes finding out when can0 comes back. correct? Yes! > >> In any case you would need to handle the -ENODEV in your CAN application. > > When I unplug the device while reading I get ENETDOWN. catching this error is > simple. which gives me an event when the device disappears, recovering from it > is more difficult... > Yes :-( >> E.g. you can terminate the application and start it, after the udev rule >> recovered the correct CAN device. Or your can poll until -ENODEV does not >> appear when opening the socket (more precisely when using ioctl() ) :-( > > In this case i want the application to recover on its own, without the need > for a restart. I've cooked up the following... But there is a race condition > between read and the SIOCGIFINDEX ioctl call. Is there no better way to check > if can0 exists? There's a notification available in userspace regarding emerging netdevices via netlink ... see: http://book.chinaunix.net/special/ebook/oreilly/Understanding_Linux_Network_Internals/0596002556/understandlni-CHP-8-SECT-8.html You could try this! > > const char *dev = "can0"; > int sfd; > struct sockaddr_can addr; > struct ifreq ifr; > > while(1){ > // open part SocketCAN > sfd = socket(PF_CAN, SOCK_RAW, CAN_RAW); > if(sfd<0){ > perror("socket"); > return -1; > } > > // resolve dev name to a ifindex for bind > strcpy(ifr.ifr_name, dev); // "can0" is the name of the CAN network > interface > if(ioctl(sfd, SIOCGIFINDEX, &ifr)==-1){ > perror("ioctl"); > } restart: // label for goto > // select CAN and bind the socket > addr.can_family = AF_CAN; > addr.can_ifindex = ifr.ifr_ifindex; > if(bind(sfd, (struct sockaddr *)&addr, sizeof(addr))<0){ > perror("bind"); > close(sfd); > return -1; > } > > // Part if you want the CAN_ERROR frames for reading > can_err_mask_t err_mask = CAN_ERR_MASK; > setsockopt(sfd, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, > sizeof(err_mask)); > > struct can_frame frame = { > .can_id=0x00, > .can_dlc=0, > .data = { 0x00, 0x00 }, > }; > > printf("reading more frames.\n"); > while((read( sfd, &frame, sizeof(frame) )) == sizeof(frame)){ // Read a > CAN frames > print_frame(frame,silent); > } > > perror("read"); > You should initialize &ifr here again (not sure what parts of &ifr survive) > while(ioctl(sfd, SIOCGIFINDEX, &ifr)==-1){ // see if dev (can0) "resolves" > perror("ioctl"); > sleep(1); > } goto restart; // right? > > printf("found new index.\n"); > > //close sfd so we can open it again later > close(sfd); > } > > Thanks, > Max S. > _______________________________________________ Socketcan-users mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-users
