From: Craig on 2 Jul 2010 18:29 I understand about not wanting a Tk app to block, but sometimes you do want blocking calls and other times you don't. The beauty of the select/read combo is you can have both a blocking read, but test ahead of time if might be successful. blah blah blah. What is the behavior from the script level? chan event $cid readable $script Does your script assume that zero bytes is EOF? Does the channel mechanism only allow return values in the range [-1 ...)? Can you implement a script level timeout that can cancel a hung receive call? How does Tcl know that the channel is readable? Aren't you implementing that, too? Seems like you could with xxPoll() so much I don't know. craig ..... David Gravereaux wrote: > On 07/02/2010 02:03 PM, Donal K. Fellows wrote: >> On 2 July, 20:52, David Gravereaux <davyg...(a)pobox.com> wrote: >>> I'm writing a GPIB channel driver extension and was wondering what the >>> proper error code I should return for a timeout from a blocking read? >> That sounds dodgy. Surely a read on a blocking channel should not >> return until it has something definite to report, whether data or >> error? (EWOULDBLOCK is exactly right when not blocking.) >> >> Donal. > > > By blocking, I meant the GPIB library call, not the Tcl channel. I > don't want blocking at the Tcl level. A real blocking read locks the > GPIB buss from other devices using it to communicate with the > controller. I'll allow it (I guess), but it can never work in a system > of multiple units. The channel itself will be non-blocking by using low > timeout values to the blocking Receive() call in the GPIB library. > > There is a background read call, ibrda(), but looks a bit complicated > (at this time) as well as it not being part of the 'multi-device' API. > > I REALLY don't want my Tk controls to freeze during I/O which is a big > problem with this arcane 1978(!) IEEE488.2 way of moving bits. > > Ok, EWOULDBLOCK is good then, Thanks.
From: David Gravereaux on 2 Jul 2010 18:51 On 07/02/2010 02:52 PM, Craig wrote: > The Receive call sounds like a combination of a select call with a > timeout followed by a read. Sounds right, but these descriptors aren't select'able. > A posix select call would return 0 with no error on a timeout and the > read would never occur. > If the read really were blocking and you attempted a read after a > timeout, it would block and this driver would hang. Yes, and hang the whole buss, too. > Were I a user of this code, i don't think i'd want an error returned on > a timeout (which, btw, seems quite different from EWOULDBLOCK semantics, > since a timeout on a select allows the app to block for a defined period > of time, while EWOULDBLOCK is returned from a NON-BLOCKING read call, > when it would block.) EWOULDBLOCK is a transient condition. There isn't a non-blocking call, though. Just a blocking Receive() <http://linux-gpib.sourceforge.net/doc_html/r2741.html> with a low timeout value of maybe 10uS <http://linux-gpib.sourceforge.net/doc_html/r2137.html>. > Since i don't understand how channel drivers are s'posed to work, it > isn't clear if returning an error is the only way to return out-of-band > information. What about a return code of -2? If that's not possible, > then I can understand your quandary, because none of the read call > errors really map to what's happening. Are you limited to returning read > call errors? Nope. Tcl_SetChannelError() <http://www.tcl.tk/man/tcl/TclLib/SetChanErr.htm> allows for the return of specific conditions. > What is it that drives the call to GpibInputProc? what is it's response > to an error or zero bytes returned? GpibInputProc is the channel driver's Tcl_DriverInputProc <http://www.tcl.tk/man/tcl/TclLib/CrtChannel.htm#M11> it is called by [gets] or [read] on the channel. [read] without a length limit, and the channel set to non-blocking will recursively call the Tcl_DriverInputProc until EWOULDBLOCK is returned, thus everything is pulled in. [gets] will be mostly invalid as reads on the buss are message oriented, not a stream, per se. Notification of readable is unfortunately GPIB device specific but will be centered around WaitSRQ()/FindRQS() <http://linux-gpib.sourceforge.net/doc_html/r3144.html> in a service thread for zapping Tcl_AlertNotifier(). For example, my Tektronix DM5010 multimeter asserts SRQ when it has taken a measurement (when configured to). In the fileevent readable handler, I'll have to first read the status byte of the device with a serial poll to see if it is 132 (10000100b). Only then, should I call [read] to acquire it. The DMM asserts SRQ for numerous other reasons, too (not shown). proc readDMM {chan} { switch {[fconfigure $chan -spoll]} { case 132 { set measurement [read $chan] } } } --
From: David Gravereaux on 2 Jul 2010 19:03 On 07/02/2010 03:29 PM, Craig wrote: > I understand about not wanting a Tk app to block, but sometimes you do > want blocking calls and other times you don't. I'd NEVER want that :) > The beauty of the > select/read combo is you can have both a blocking read, but test ahead > of time if might be successful. blah blah blah. select() would great, but the Linux-GPIB library doesn't have descriptors that are slect'able as mentioned previously. > What is the behavior from the script level? > > chan event $cid readable $script > > Does your script assume that zero bytes is EOF? It's actually Tcl that does that, not any script. EOF is set to the channel by any Tcl_DriverInputProc that returns zero. > Does the channel mechanism only allow return values in the range [-1 ...)? no. > Can you implement a script level timeout that can cancel a hung receive > call? Yes, that's an fconfigure to ibtmo() <http://linux-gpib.sourceforge.net/doc_html/r2137.html> > How does Tcl know that the channel is readable? Aren't you implementing > that, too? Seems like you could with xxPoll() WaitSRQ()/FindRQS() in a service thread. > so much I don't know. > craig --
From: David Gravereaux on 3 Jul 2010 03:49 On 07/02/2010 08:05 PM, David Gravereaux wrote: > On 07/02/2010 06:31 PM, Craig wrote: >> >> since it seems like the timeout for reading from specific devices will >> vary and it appears you don't trust the reliability of WaitSRQ/FindRQS >> calls, > > What gave you that idea? I do trust WaitSRQ(). I think I understand where you might be confused on the concept of SRQ. For the Tektronix DM5010, SRQ can be asserted for many conditions. Only one of them is "reading available". A more complete readable handler might be this. Note here that "readable" just means that the device has asserted the SRQ line and requires that the status byte needs to be read with a serial poll. From the decoding of the status byte (which is device specific) I'll then know what to do. set DMM [agpib open -board 0 -sad 16 -timeout 1ms -eoi yes] fconfigure $DMM -translation binary fileevent $DMM readable [list readDMM $DMM] proc readDMM {chan} { switch {[fconfigure $chan -spoll]} { case 97 - 98 - 99 { # get a more detailed error code puts $chan {ERR?} } case 65 { # Power on notification puts $chan {RQS ON;OVER ON;USER ON;OPC ON} } case 66 { # Operation complete } case 67 { # user pressed the front panel 'INST ID' button } case 102 { # Over-range } case 193 { # Below limits } case 195 { # Above limits } case 132 - 140 { # Reading available, get it. set data [read $chan] DMM_parse $data } } } puts $DMM {RQS ON;OVER ON;USER ON;OPC ON;DIG 4.5;ACV;MODE RUN} Of course, the above doesn't work yet as I haven't completed the extension. --
From: Craig on 6 Jul 2010 01:49
David Gravereaux wrote: > What gave you that idea? I do trust WaitSRQ(). Because you seemed reluctant to do a blocking read on the device after WaitSRQ told you it had data. ;^) It's been 20+ years since I did any HPIB programming on 9825s and 9816s, so anything I might say about current systems must be taken with a heavy dose of salt. My recollection is that though the bus is pretty good, badly behaved devices or drivers can get it stuck, so you do need to be able to handle the case where a read really would block forever. > I wouldn't do that as it's lame to let my Tk stuff get stuck. Here we agree. > Blocking is lame. Here we disagree, although, in a Tcl script it is difficult to make this work right. threads are required for this to be robust. >> Perhaps you could set a short timeout for the Receive() >> and return EINTR and arrange for that to reschedule the channel for >> reading - not sure how that would work. > > EWOULDBLOCK reschedules. Actually, it properly ends the recursion of an > unsized [read]. Am I wrong that this is true only if the channel is configured to be non-blocking? If so and if there is something about the semantics of a blocking channel that you want (rather than just translating the Receive call behavior into a blocking channel,) then I think that EINTR might be the appropriate error code for a read on a blocking channel that returned because it timed out. It probably would make more sense to pass it back to the script and let the script figure out how to handle it. You could set a potentially longer timeout, that might actually give you better average performance. > (I knew it was a bad idea to ask my question when I knew the answer) No. I learned a lot about the Tcl channel API. and maybe you'll release your extension, someday? Most of our Agilent gear is ethernet or serial, but I think there may be some GPIB stuff lying around. Craig |