ESCAPE stops my module!
Richard Walker (2090) 416 posts |
Hi all, I’ve been developing a module which receives and parses data from a USB device. The module opens a file with DeviceFS and uses OSGBPB to read bytes from a buffer when I receive UpCall 15 (rx data ready). As far as I can tell, the basics are working. I can use my own *commands or SWIs to read the latest data from the buffer. The module shuts down cleanly enough (closing the file handles and unclaiming the UpCallV). I can write a BASIC program to use my SWI and display some data. I can put this into a loop with REPEAT UNTIL FALSE. Dandy. However, if I press ESC (which was my plan for exiting the BASIC program) then the upcalls stop being delivered to my module. I have to reinit my module for them to resume. My copy of the received data buffer is also corrupted slightly. Pressing ESCAPE seems to cause some funny business! Is there anything silly I need to be aware of regarding the ESCAPE key? And strange event handlers or whatever I should be considering? I assume this is an amateur error! Cheers, |
Colin (478) 2433 posts |
Are you checking for an error returned from the OS_GBPB call The escape key produces an error if detected during a OS_GBPB call. |
Richard Walker (2090) 416 posts |
Hmm. I did put some logging into my upcall handler so that it would count up any OS_GBPB errors. Maybe that logging isn’t quite right, which is why I have not made that connection. I shall look again, as now you mention it, I vaguely recall a specific error I can detect. Thanks for the pointer. |
Richard Walker (2090) 416 posts |
Ah, ha. My upcall handler calls OS_GBPB 4 (using OSLib). I was testing the unread byte count (R3) and only copying the buffer contents if it was zero and there was no error. I have amended the code to separately test for an error. Turns out that there is indeed an error, ‘Escape’. I allow my upcall handler to exit without attempting to process the buffer, but I never get any upcalls again. Not sure why my upcall handler stops working. I will add more logging. Also I cannot see any info in the PRM re. GBPB and Escape generating an error. |
Richard Walker (2090) 416 posts |
A refinement to that… Extra logging reveals that the upcall handler is being entered, and it is upcall 15, but the file handle never matches mine, so I never call GBPB again. One thing I am having trouble clarifying: should I set up a vector handler or generic veneer in CMHG? I need the generic one for UKSWIV, but I had been using vector handler for UpCallV. I have tried using generic, and experimenting with different return values, but no luck yet. It is most odd! |
Colin (478) 2433 posts |
How are you opening the USB device. If you are not using the ‘noblock’ option when opening the device OS_GBPB may not be returning if you have requested more bytes than are in the buffer. That may explain why escape is caught by OS_GBPB in the upcall handler. I don’t use OS_GBPB when emptying the buffer in the upcall handler I prefer to use the buffer manager to remove data from the buffer directly which is faster.
It needs to be a vector-handler. The UKSWIV needed to be able to return an error and read r11 so needed a bodge to do the vector-handler. The UPCALLV works with a standard vector-handler. |
Colin (478) 2433 posts |
Another reason not to get UpCall_DeviceRxDataPresent is that you are not emptying the buffer in the upcall handler. The UpCall_DeviceRxDataPresent upcall is only called when data enters an empty buffer. If the buffer isn’t empty data is just put in the buffer without calling the upcall. The upcall handler needs to be an emulation of the Netbsd usb callback mechanism where the data is put in a block of memory and a function is called to tell you the data is ready and you use all of the block of memory during the callback. In riscos the the netbsd callback function moves the data from the block of memory into the DeviceFS buffer. If the DeviceFSbuffer is empty when the data is copied you get a UpCall_DeviceRxDataPresent upcall where you can copy the data to where you want it – possibly another buffer. If you don’t empty the buffer the next block of data that arrives won’t trigger the UpCall_DeviceRxDataPresent upcall. It’s a very ponderous process In my SerialUSB module the user API is via DeviceFS which means to receive data in your application space program you have. 1) USB stores data in a DMA buffer edit: Having written that down it occurs to me that short of exposing the NetBSD interface in RISC OS steps 2 and 3 can be avoided if step 2 is vectorised. Then instead of using the upcall handler you’d claim a USBV which which passes the DMA buffer to your handler. The default handler can do what USBDriver does now. |
Richard Walker (2090) 416 posts |
I’ll keep with the vector-handler for UpCallV, and generic for UKSWIV. Thanks. When you say ‘empty buffer’, what exactly do you mean? I have a data structure with each device I’m talking to having its own file pointer (I open the file during the module init) and data buffer. My upcall handler will check if the file pointer is the one I’m interested in (by scanning through the data structure). If it is, then I use OSGBPB to read the bytes into a temporary buffer. If I read the expected number of bytes, then I memcpy() that into the multi-device data structure, where they are processed later. I don’t do anything to tell DeviceFS that the buffer is now ‘empty’ – should I? Is my method madness?! (it seems to work well, apart from this Escape nonsense!) |
Colin (478) 2433 posts |
Ensure that there are no more bytes to read before leaving the upcall handler otherwise it won’t be called again. Your method looks good. While its working for you I wouldn’t advise anyone to use OS_GBPB in the upcall handler |
Colin (478) 2433 posts |
The easiest way to ensure the buffer is emptied would be: If the memory block you read to using OS_GBPB is 16k, open the usb endpoint with “usb8#noblock;nopad;size=16384;…:”. Then always read 16k with OS_GBPB. OS_GBPB will return the actual number of bytes read (because it’s non blocking) and the usb buffer will be empty. |
Richard Walker (2090) 416 posts |
That’s pretty much what I do. I know a device endpoint will provide me with five bytes (it promised me!), so in the upcall handler, I ask OS_GBPB to read me five bytes. It always does, apart from when I press ESCAPE. I’ve read more about the Buffer Manager in the PRMs, and I have also spotted that I can discover the buffer number from DeviceFS, so maybe I need to prod around in there. I could end up forgetting all about OS_GBPB. I shall try and have a play with it later (code isn’t in front of me right now). Many thanks for your help, Colin. |
Richard Walker (2090) 416 posts |
OK, so I’m still a bit perplexed by this. I use OS_Find 4 to open a read only file to my device endpoint (with nopad and no block). I remember the returned handle, which the PRM suggests is the ‘FileSwitch file handle’. In my upcallv handler, I check that the up call reason is 15, and that R1 is my file handle. If so, I use OS_GBPB. Works well, unless I hit ESC, when I get an error from OS_GBPB, then no more upcalls. OS_GBPB would normally tell me how bytes were unread (and it’s normally always zero), but in the error state, this remains at zero (presumably because OS_GBPB has been aborted during its execution, so that makes sense). So I don’t have a simple way of checking how many bytes have actually been read. What I want to do in this error state is to tell DeviceFS to clear its buffer, and we can hopefully carry on after the next receive. I think I need to find the buffer’s handle, so I can ask Buffer Manager to do this for me. The USB document in CVS tells me I should use ‘get handles’ (DeviceFS_CallDevice + 3), passing in the device name and fileswitch handle. I have tried this immediately after my OS_Find, but it always tells me that the buffer handle is 0 and the DeviceFS handle (whatever that is) is also 0. I find these unlikely values. So I’m stuck again. Help! |
Colin (478) 2433 posts |
I presume you mean OS_Find 0×4x – you must do it works. ‘get_handles’ is (1u << 31) + 3 |
Richard Walker (2090) 416 posts |
Yes, and that is what I was using to get handles. Ahh… I’ve solved it. It was indeed an amateur mistake. I fluffed the out parameters in the ‘swix’ call for get handles, which is why it was returning zero! Now I get reasonable-looking values, and I can hit OSByte 21 which clears the buffer if I need it (on an OS_GBPB error). Much better. My BASIC test app no longer kills the upcalls when I ESCAPE from it. Marvellous. Thank you very much for the pointers. I may yet investigate the various buffer functions and see if I can do without OS_GBPB altogether, as it just seems crazy that it is affected by ESCAPE! |
Richard Walker (2090) 416 posts |
Slightly odd side-effect of the change, which I didn’t realise at first, is that I can no longer press ESCAPE to get out of the test app. My keypress is just ignored, and the BASIC program continues to display output. I have to hit ALT-BREAK then RETURN. I think that the writing is on the wall, and I need to investigate using Buffer Manager instead of OS_GBPB! |
Rick Murray (539) 13422 posts |
Just out of interest – are you using OS_GBPB or XOS_GBPB? I find it weird that a background file action can be aborted by pressing ESC… |
Richard Walker (2090) 416 posts |
Definitely the X version. I also thought it madness! I had a read over buffers earlier, and it looks like OSByte 145ish for reading a byte at a time (so presumably a loop required) or there is a remv_block which looks like it will do it all in one go. I will try one, or even both. |
Richard Walker (2090) 416 posts |
For thread completeless… I have binned-off OS_GBPB and used the RISC OS 3.5+ buffer manager routines instead. I don’t need to worry about the ESCAPE key causing an error, and the behaviour in my test application is back to normal: I only have to hit ESCAPE once, and the BASIC program stops cleanly (no need to ALT-BREAK). Moral of the story is to take Colin’s ‘I wouldn’t advise’ hint. :) |