How to do unpredictable USB input
Pages: 1 2 3 4 5 6 7 8 9 10 11 12
Dave Higton (1515) 3534 posts |
I think you’ll find that it’s not implemented, rather than a bug. In the versions of USBDriver I have, the word “nopad” appears, but the word “noblock” does not. Same on Iyonix and BBxM.
The device I’m speaking of here is a FTDI USB serial device. One transfer is never any bigger than 64 bytes, which is also its maximum packet size. I can’t speak for other devices. However, in terms of generalising things: you don’t ask a USB device to transfer a certain number of bytes – at bus level, there is no way to do so. You ask it to transfer, then it transfers as many as it wants. You know it has finished transferring when it sends a packet shorter than the maximum packet length. Once it has transferred its bytes, you can ask the OS to give you your chosen number of them. |
Colin (478) 2433 posts |
Ah right. After reading this USB mass bulk I was wondering if you needed to worry about the size if the request – other than for speed issues. Regarding noblock it is processed here devicefs.s.fsystem line 2317. The OS_Args you call are processed in the same file – see fs_args. If noblock deliberately doesn’t work OS_Args shouldn’t work either. |
Dave Higton (1515) 3534 posts |
Re. mass storage: the higher level protocol allows prior knowledge of how many bytes to ask for and to expect. Still, the same limitation applies at the bus level: it is not possible to ask for a specific number of bytes. Re. OS_Args: I’ll have another look at the symptoms. One of my next challenges is to see how all this information can be used to make other protocol applications, like PTP, work better. Another is to find exactly what fails on the Raspberry Pi and see if it can be fixed. |
Dave Higton (1515) 3534 posts |
What condition(s) can lead to “IO error” from an OS_GBPB 4? I tried porting some of my findings into my PTP app last night. Using it with an HP PhotoSmart camera, I got the same problem I’ve seen many times: one call to OS_GBPB appears to proceed OK (no error) but returns no bytes. Next time round, there are no bytes waiting in the buffer, there is no transfer in progress, so I issue another OS_GBPB 4, which returns with V set, the error message ending in “IO error”. The endpoint does not claim to be stalled. |
Colin (478) 2433 posts |
I did a search of the tungsten sources and came up with ‘IO Error’ in the USBDriver messages file token CC13. However doing a search for that didn’t come up with much – I couldn’t see that it was called. There is another CC13 token used when copying directories but that is a different message. Not much help I’m afraid. Re. your serial program. Looking through the CP210x application note I noticed that it has the option to switch on delivery of status messages embedded in the input stream. It does this by putting an It just reminded me of the status bytes you were receiving where 16 could be the escape char and the following byte the reason code. A reason code of 0 for example is how an input char which is the same as the escape char is delivered. If the 16 is indeed an escape char then you would need to do a simple OS_GBPB fetch and filter the input stream. Edit: looking back I note you were receiving 0×01 0×60 and not 16 it could still be an escape sequence. |
Colin (478) 2433 posts |
Ok I finally got around to do some coding and this is how it went for me (on an Iyonix). nopad and noblock in the special field didn’t work for me but the device was opened. Putting a comma before them to see if I got the format correct caused the device not to open because of a problem with the filename. Both options worked if I set them via DeviceFS_CallDevice and OS_Args, and I can fetch 0-9\n transmitted every couple of seconds at 9600 baud in a task window which multitasks merrily. I just: 1. Open the device for input I can set the buffer size used by OS_GBPB to any size – I tried various sizes from 1-4095 bytes. The endpoint size is 64 bytes and is bulk input. However if I set the size of the buffer passed to OS_GBPB to 1, after fetching 2 or 3 bytes it would fail with the error: Error: 8491053 (0×81902d) ‘USB transfer failed: IO Error’ Do you know if the other special fields work? Seems odd if ‘interface’, ‘endpoint’ etc. work but ‘nopad’ and ‘noblock’ don’t, especially as one is implemented by DeviceFS and the other the USB module. |
Colin (478) 2433 posts |
Just to round up my findings. I have the the IN endpoint running in 1 taskwindow and the OUT endpoint running in another. So I can type in one window and bounce the data off the connected device into the other window. I could get no options to work in the special field. They had to be set via OS_Args or DeviceFS_CallDevice. ‘sleep’ worked as far a multitasking goes but did not return when the ‘nopad’ option was set. The exception was if the read was set to 1 byte It would then occasionally return a byte but more often than not would fail with the error noted in an earlier post. If the nopad option is unset the read returns as expected but the data is padded. ‘timeout’ doesn’t work. I verified that the timeout was changed by reading it back but it never timed out. ‘short’ doesn’t seem to do anything any text typed in appears in the other windows immediately, regardless of whether its on or off. ‘noblock’ works. ‘nopad’ works. Hope this help someone. |
Dave Higton (1515) 3534 posts |
I’m looking at why it doesn’t work on the Raspberry Pi.
fails with AODT at &FC1C64FC. This is RO 5.19 of 2013-02-10. The above is part of one of a series of test apps for my module and its associated serial blockdriver, and works fine on the Iyonix and BBxM. |
Dave Higton (1515) 3534 posts |
Ignore me – one argument too many. More work to follow. There is a problem to be solved – I just don’t yet know what it is. |
Dave Higton (1515) 3534 posts |
Well, as soon as I try to get input from the FTDI device’s bulk IN endpoint, the Raspberry Pi is stiffed. I suspected it was my input routine within my module that was doing it, so I used OS_GBPB 4 instead. Same result. I also took out the code that sets it to nopad and noblock. Same result. I give up. To satisfy my curiosity, I’ve just ordered a similar dongle based on the Prolific PL2303. |
Colin (478) 2433 posts |
Not much help but this thread shows similar problems with linux on the pi when using ftdi and PL2303 devices. If the problem is small infrequent fetches and you have a means of filling the ftdi internal buffers before reading with the pi, maybe send a 1000 bytes before receiving with the pi, you could test this out. |
Dave Higton (1515) 3534 posts |
Ye gods, the PL2303 is hard work. I’ve just had the first positive results from my test app – sending “Hello, world!” at 9600 baud. The bad news is that running it again sends nothing. I have yet to try receiving anything. The PL2303 has an interrupt IN endpoint as well as the obvious bulk IN and OUT. Bizarrely, it appears that, for every character transmitted via bulk OUT, several bytes have to be accepted and discarded from interrupt IN. There is hugely more setup to be done than with the FTDI chip. I have never seen so many vendor-specific commands, even for one of my Bluetooth dongles. Being vendor-specific and secret, we can only guess at what they do. At least one of them seems to affect the charge pump that powers the RS-232 drivers. Why on earth any manufacturer would want to make a charge pump programmable is beyond me. I doubt I will carry on seriously for very long on the PL2303, but, once piqued, my curiosity had to be satisfied. |
Colin (478) 2433 posts |
If you think of the generic function to send data as int putc(char) then it does make sense that char is sent in the bulk endpoint and int is returned in the interrupt endpoint. The value returned will tell you if putc was successful otherwise the reason for failure – which could be, for example, device buffer full, the device is paused due to flow control or that the device isn’t enabled. It’s likely that reading follows a similar pattern int getc(char*) where a read of 1 char from the bulk in endpoint is followed by a read from the interrupt. If multibyte versions were possible then the returned value could contain the number of bytes successfully transferred – like a non blocking socket read/write. |
Dave Higton (1515) 3534 posts |
The bytes coming in the interrupt IN endpoint bear no resemblance to those going out on the bulk OUT endpoint. They must be some kind of status information. Normally they are 10-byte transfers, with the first 9 bytes always the same, and the last byte mostly alternating between two values. |
Dave Higton (1515) 3534 posts |
I went back to my multimeter application yesterday. It’s for a Maplin N56FU, which uses a CP2101 as its USB interface. It’s an absolute dream to deal with. The opposite end of the spectrum from the PL2303. I wish free-standing CP2101-based RS-232 dongles were available. Sadly they all seem to be TTL levels rather than RS-232. I hope to have the N56FU app on my web site in a few days. |
Colin (478) 2433 posts |
Have you tested the levels on the PL2303 and and FTDI usb/serial converters you have? |
Dave Higton (1515) 3534 posts |
Yes; they meet RS-232 requirements. Not surprising when they have 9 pin D connectors. |
Colin Ferris (399) 1818 posts |
Since there are keen people here trying to put the Pi in a half pint jar – what about changing the USB rs232 adaptor cables to use the cp2102 chip instead of the FTDI/PL2303 versions? |
Dave Higton (1515) 3534 posts |
OK, off you go. Do let me know when you’ve succeeded… There are people who would like to buy a ready-made CP210x-based RS-232 dongle, if such a thing were available. |
Colin (478) 2433 posts |
I’ve just bought a cheap usb rs232 converter from amazon. Thought it was going to be a PL2303 but turned out to be a CH340. Anyway to my surprise windows found drivers for it. I put it on my oscilloscope and it’s outputting a 5v space and 0v mark. So when it comes to cheap the plug isn’t a guarantee of standards. Otherwise it may be a PL2303 clone as the interface has bulk in, bulk out and interrupt in endpoints although I note the interrupt endpoint is only 8 bytes instead of 10. |
Theo Markettos (89) 919 posts |
Dave, fancy a bulk buy? $6.50 each, minimum order 10 units . Or $12.37 in one off on a little adaptor PCB. |
Dave Higton (1515) 3534 posts |
None of the alternatives implements all the lines – although what they do implement is likely to be OK for the majority of applications. |
Rick Murray (539) 13851 posts |
Is this API documented anywhere? While playing with the USBMIDI on a Pi, I note that nopad does exactly nothing (still loads of null bytes returned). I did not see anything in the Castle USB doc describing the way to read/write options. Better yet – is any of your work-in-progress code available? I can try to hack it to receive from the MIDI keyboard to see if/how it works? What I currently do, given the buffer seems to fill up in the background, is just call OS_BGet repeatedly looking for the data (I could call GBPB but BGet is easier when you don’t know where the boundaries are). It is all pretty naff and suboptimal, namely:
<shrugs> |
Colin (478) 2433 posts |
I got my information from docs in the source code and the os_args 9 ioctI options I posted earlier I got from the device fs source code. If you set nopad in the special field it doesn’t work you need to use devicefs_calldevice as documented in the above link. Noblock doesn’t work in the special field either, you need to use os_args for that. I don’t think os_bget is reliable either. I found when requesting 1 byte with os_gbpb it would fail intermittently on an iyonix with the error you describe but requesting more than 1 byte – non blocking – is robust even if the call only returned 1 byte or indeed 0 bytes I don’t know if the code I have would be useful to you – it’s just experimental code which sends chars to a pic which bounces the char back. If the above doesn’t help or my explanation is rubbish :) and you’d like to see the code just say and I’ll post it somewhere. |
Colin (478) 2433 posts |
I’ve extracted the essential parts from my code. You should be able to convert it to BASIC. ROFile_open is just a wrapper for OS_Find and ROFile* is just a normal RISCOS file handle for reading I use: ROFile* in=ROFile_open(ROFile_OPENIN,"devices#endpoint=%d;interface=%d:%s", uart->in,uart->interface,device.handle); ROFile_setNoBlock(in,1); USB_setNoPad(&device,in,1); and for writing I use: ROFile* out=ROFile_open(ROFile_OPENOUT,"devices#endpoint=%d;interface=%d:%s", uart->out,uart->interface,device.handle); ROFile_setNoBlock(out,1); ROFile_setNoBlock and USB_setNoPad are defined below. When reading with ROFile_read I request more than 1 byte to avoid problems. typedef struct ROFile ROFile; /* * ioctl flags */ /* read and/or write */ #define ROFile_IoctlRead (1u<<30) #define ROFile_IoctlWrite (1u<<31) /* group */ #define ROFile_IoctlDeviceFS 0xff0000 /* reason code */ #define ROFile_IoctlDeviceFSNoBlock 1 #define ROFile_IoctlDeviceFSSleep 4 #define ROFile_IoctlDeviceFSSleepTimeout 5 typedef struct { unsigned int flags; unsigned int data; }ROFile_IOCtlData; void ROFile_ioctl(ROFile* handle,ROFile_IOCtlData* data) { if (data==0) return; _kernel_swi_regs r={{9,(int)handle,(int)data}}; _kernel_swi(OS_Args,&r,&r); } void ROFile_setNoBlock(ROFile* file,int on) { ROFile_IOCtlData d; d.flags=ROFile_IoctlWrite | ROFile_IoctlDeviceFS | ROFile_IoctlDeviceFSNoBlock; d.data=(on?1:0); ROFile_ioctl(file,&d); } _kernel_oserror* USB_setNoPad(const USB_Device* device,const ROFile* file,int on) { int usbHandle; _kernel_oserror* e=_swix(DeviceFS_CallDevice,_INR(0,2) | _OUT(5),(1u<<31)+7,device->handle,file,&usbHandle); if (!e) e=_swix(DeviceFS_CallDevice,_INR(0,4),(1u<<31)+8,device->handle,usbHandle,(on?1:0),1); return e; } /* * returns the number of bytes read or -1 for error */ int ROFile_read(ROFile* handle,char* buf,int len) { if (handle==0 || buf==0) return -1; _kernel_swi_regs r={{4,(int)handle,(int)buf,len}}; if (_kernel_swi(OS_GBPB,&r,&r)) return -1; return len-r.r[3]; } /* * returns the number of bytes written or -1 for error */ int ROFile_write(ROFile* handle,const char* buf,int len) { if (handle==0 || buf==0) return -1; _kernel_swi_regs r={{2,(int)handle,(int)buf,len}}; if (_kernel_swi(OS_GBPB,&r,&r)) return -1; return len-r.r[3]; } typedef enum { ROFile_OPENIN, ROFile_OPENOUT, ROFile_OPENUP, } ROFile_Direction; /* * returns 0 if open fails */ ROFile* ROFile_open(ROFile_Direction direction,const char* format,...) { va_list aptr; va_start(aptr,format); char filename[256]; int size=vsnprintf(filename,sizeof(filename),format,aptr); va_end(aptr); if (size==sizeof(filename)) return 0; _kernel_swi_regs r={{0x4f,(int)filename}}; if (direction==ROFile_OPENOUT) r.r[0]=0x8f; if (direction==ROFile_OPENUP) r.r[0]=0xCf; if (_kernel_swi(OS_Find,&r,&r)) return 0; return (ROFile*)r.r[0]; } |
Pages: 1 2 3 4 5 6 7 8 9 10 11 12