EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  <20232024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  <20232024 
<== Date ==> <== Thread ==>

Subject: Re: Issue with streamdevice and I/o Intr
From: Zimoch Dirk via Tech-talk <tech-talk at aps.anl.gov>
To: "florian at ep1.ruhr-uni-bochum.de" <florian at ep1.ruhr-uni-bochum.de>, "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
Date: Tue, 4 Jul 2023 09:55:51 +0000
On Tue, 2023-07-04 at 11:09 +0200, Florian Feldbauer wrote:
> Hey Dirk,
> 
> thanks for the detailed explanation.
> I worked with StreamDevice and I/O intr a lot before, but always with 
> the asynSerialPort as lower level driver.
> 
> Just to be clear: Let's assume my input record with "I/O Intr" is the 
> only record reading on the bus, do I need to create a polling on the bus 
> myself or does StreamDevice internally create a polling thread?

StreamDevice does it automatically. In fact, ALL "I/O Intr" try to poll the bus.
The first one that gets the bus just cancels the poll of all others. This way,
the "I/O Intr" record with the fastest poll rate is effectively the one which
does the polling.

> 
> Thx for the advice with the eomReason, I changed my driver accordingly.
> My protocol and record now look like this:
> 
> Terminator = '';
> recv {
>    MaxInput = 4;
>    in  0x07 $1 "%r";
> }
> 
> record( longin, "CAN${N}:TEST:R" ) {
>    field( DTYP, "stream" )
>    field( SCAN, "I/O Intr" )
>    field( INP,  "@can.proto recv(0x00) ${port}" )
> }
> 

Your protocol expects 3 bytes, 0x07 0x00 and one byte data. But it received 4
bytes, 0x07 0x00 0x00 0x15. Thus one byte is left and makes the protocol fail.

Using %2r should give you the signed 16 bit integer value 0x0015.

> The first two bytes contain the 11bit CAN arbitration ID followed by the 
> up to 8 data bytes.
> We have one device that sends 32bit floats via CAN bus, which is why we 
> use the raw format, so we can parse those values later with the %R 
> format converter.

Be aware that %r and %R both cannot fail and thus only the input length can
distinguish between the two formats. You will not be able to separate %4r from
%4R if the first two bytes are the same.

I find it strange that in the log below you send 4 bytes (0x07 0x00 0x00 0x15)
but receive 5 (0x07 0x00 0x00 0x15 0x00). Is everything correct in your driver?

I still don't see messages from asynReadHandler. Strange. Does your driver not
pass the data through asynOctetBase? Look how drvAsynSerialPort links to
asynOctetBase in drvAsynSerialPortConfigure: pasynOctetBase->initialize()

If not using pasynOctetBase, your read function will not call
callInterruptUsers() unless you explicitly do it yourself and thus "I/O Intr"
records will not receive anything.

Dirk

> 
> My IOC has 2 CAN interfaces and I was trying to send a frame from can0 
> to can1 or vise versa.
> 
> 
> Here is the complete log from Stream:
> 
> epics> dbpf CAN0:TEST:W 21
> 2023/07/04 11:03:07.127321 _main_ StreamEpics.cc:908: 
> Stream::process(CAN0:TEST:W)
> 2023/07/04 11:03:07.127508 _main_ StreamEpics.cc:934: 
> Stream::process(CAN0:TEST:W) start
> 2023/07/04 11:03:07.127628 _main_ StreamCore.cc:429: 
> StreamCore::startProtocol(CAN0:TEST:W, startMode=StartNormal)
> 2023/07/04 11:03:07.127725 _main_ StreamCore.cc:564: 
> StreamCore::evalCommand(CAN0:TEST:W): activeCommand = out
> 2023/07/04 11:03:07.127828 _main_ StreamCore.cc:689: 
> StreamCore::formatOutput(CAN0:TEST:W): format = %.2r
> 2023/07/04 11:03:07.127945 _main_ StreamEpics.cc:1173: 
> Stream::formatValue(CAN0:TEST:W, format=%r, fieldaddr=(nil)
> 2023/07/04 11:03:07.128054 _main_ StreamEpics.cc:1298: 
> Stream::formatValue(CAN0:TEST:W) format=%r type=DBF_LONG
> 2023/07/04 11:03:07.128166 _main_ StreamEpics.cc:693: 
> streamPrintf(CAN0:TEST:W,format=%r)
> 2023/07/04 11:03:07.128284 _main_ StreamCore.cc:777: 
> StreamCore::printValue(CAN0:TEST:W, %r, 21 = 0x15): "<07><00><00><15>"
> 2023/07/04 11:03:07.128402 _main_ StreamCore.cc:612: 
> StreamCore::evalOut: outputLine = "<07><00><00><15>"
> 2023/07/04 11:03:07.128503 _main_ StreamCore.cc:623: 
> StreamCore::evalOut(CAN0:TEST:W): lockRequest(5000)
> 2023/07/04 11:03:07.128599 _main_ AsynDriverInterface.cc:549: 
> AsynDriverInterface::lockRequest(CAN0:TEST:W, 5000 msec)
> 2023/07/04 11:03:07.128739 _main_ StreamEpics.cc:948: 
> Stream::process(CAN0:TEST:W): protocol started
> 2023/07/04 11:03:07.128794 can0 AsynDriverInterface.cc:590: 
> AsynDriverInterface::lockHandler(CAN0:TEST:W)
> DBF_LONG:           21 = 0x15
> 2023/07/04 11:03:07.129004 can0 StreamCore.cc:832: 
> StreamCore::lockCallback(CAN0:TEST:W, StreamIoSuccess)
> 2023/07/04 11:03:07.129122 can0 AsynDriverInterface.cc:627: 
> AsynDriverInterface::writeRequest(CAN0:TEST:W, "<07><00><00><15>", 300 msec)
> epics> 2023/07/04 11:03:07.129265 can0 AsynDriverInterface.cc:649: 
> AsynDriverInterface::writeHandler(CAN0:TEST:W)
> 2023/07/04 11:03:07.129375 can0 AsynDriverInterface.cc:667: 
> AsynDriverInterface::writeHandler(CAN0:TEST:W): reading old input
> 2023/07/04 11:03:07.130 can0: wrote 4 bytes to can0, return asynSuccess
> 2023/07/04 11:03:07.129714 can0 AsynDriverInterface.cc:715: 
> AsynDriverInterface::writeHandler(CAN0:TEST:W): write(..., 
> "<07><00><00><15>", outputSize=4, written=4) [timeout=0.3 sec] = 
> asynSuccess
> 2023/07/04 11:03:07.129844 can0 StreamCore.cc:877: 
> StreamCore::writeCallback(CAN0:TEST:W, StreamIoSuccess)
> 2023/07/04 11:03:07.129948 can0 StreamCore.cc:564: 
> StreamCore::evalCommand(CAN0:TEST:W): activeCommand = end
> 2023/07/04 11:03:07.130403 can0 StreamCore.cc:465: 
> StreamCore::finishProtocol(CAN0:TEST:W, Success) bus owner
> 2023/07/04 11:03:07.130508 can0 AsynDriverInterface.cc:610: 
> AsynDriverInterface::unlock(CAN0:TEST:W)
> 2023/07/04 11:03:07.130606 can0 AsynDriverInterface.cc:1468: 
> AsynDriverInterface::finish(CAN0:TEST:W) start
> 2023/07/04 11:03:07.130697 can0 AsynDriverInterface.cc:1478: 
> AsynDriverInterface::finish(CAN0:TEST:W) done
> 2023/07/04 11:03:07.130792 can0 StreamEpics.cc:1034: 
> Stream::protocolFinishHook(CAN0:TEST:W, Success)
> 2023/07/04 11:03:07.130967 cbLow StreamEpics.cc:1112: 
> recordProcessCallback(CAN0:TEST:W) processing record
> 2023/07/04 11:03:07.131135 cbLow StreamEpics.cc:908: 
> Stream::process(CAN0:TEST:W)
> 2023/07/04 11:03:07.131230 cbLow StreamEpics.cc:922: 
> Stream::process(CAN0:TEST:W) ready. don't convert
> 2023/07/04 11:03:07.131344 cbLow StreamEpics.cc:1116: 
> recordProcessCallback(CAN0:TEST:W) processing record done
> 2023/07/04 11:03:07.484 can1: read 5 bytes from can1, return asynSuccess
> 2023/07/04 11:03:07.483786 can1 AsynDriverInterface.cc:951: 
> AsynDriverInterface::readHandler(CAN1:TEST:R): ioAction=AsyncRead read(4 
> bytes, timeout=0 sec) returned status asynSuccess: received=5 bytes, 
> eomReason=END, buffer="<07><00><00><15><00>"
> 2023/07/04 11:03:07.483917 can1 AsynDriverInterface.cc:977: 
> AsynDriverInterface::readHandler(CAN1:TEST:R): AsyncRead poll: received 
> 5 of 4 bytes "<07><00><00><15><00>" eomReason=END [data ignored]
> 2023/07/04 11:03:07.484024 can1 AsynDriverInterface.cc:1123: 
> AsynDriverInterface::readHandler(CAN1:TEST:R) readMore=-1 bytesToRead=63
> 2023/07/04 11:03:07.484160 can1 AsynDriverInterface.cc:951: 
> AsynDriverInterface::readHandler(CAN1:TEST:R): ioAction=AsyncRead 
> read(63 bytes, timeout=0.5 sec) returned status asynTimeout: received=0 
> bytes, eomReason=NONE, buffer=""
> 2023/07/04 11:03:07.484273 can1 AsynDriverInterface.cc:1051: 
> AsynDriverInterface::readHandler(CAN1:TEST:R): ioAction=AsyncRead, 
> timeout [0.5 sec] after 0 of 63 bytes ""
> 2023/07/04 11:03:07.484397 can1 StreamCore.cc:963: 
> StreamCore::readCallback(CAN1:TEST:R, StreamIoTimeout input="", size=0)
> 2023/07/04 11:03:07.484504 can1 StreamCore.cc:1015: 
> StreamCore::readCallback(CAN1:TEST:R) inputBuffer="", size 0
> 2023/07/04 11:03:07.484806 can1 StreamCore.cc:1108: 
> StreamCore::readCallback(CAN1:TEST:R) async timeout: just restart
> 2023/07/04 11:03:07.484975 can1 AsynDriverInterface.cc:806: 
> AsynDriverInterface::readRequest(CAN1:TEST:R, 500 msec reply, 500 msec 
> read, expect 4 bytes, async=yes)
> 2023/07/04 11:03:07.485125 can1 AsynDriverInterface.cc:831: 
> AsynDriverInterface::readRequest CAN1:TEST:R: queueRequest(..., 
> priority=0, queueTimeout=-1 sec) = asynSuccess [async=true]
> 
> Setting eomReason to ASYN_EOM_END seems to attach a 0 to the received 
> data, but it still should match the %r format converter.
> 
> Cheres,
> Florian
> 
> 
> On 7/4/23 10:45, Zimoch Dirk wrote:
> > Hi Florian,
> > 
> > For "I/O Intr" records, StreamDevice uses intrCallbackOctet but still needs to
> > poll the device, because despite its name, intrCallbackOctet does not deliver
> > any data asynchronously when nobody reads synchronously. The "I/O Intr" records
> > receives ALL input, regardless of the active reader, which may be the record
> > itself, some other StreamDevice Record or even non-StreamDevice records or any
> > other software calling asynOctet->read on that port.
> > 
> > Thus, to avoid receiving the data twice, in case the intrCallbackOctet receiver
> > is the polling record, StreamDevice discards the input received with the polled
> > read and only uses the input received with intrCallbackOctet.
> > 
> > As ALL "I/O Intr" StreamDevice records receive ALL input, they all match the
> > input against their 'in' commands. Only those records  which could match the
> > input successfully are processed. All others silently ignore the input!
> > 
> > The intrCallbackOctet input log messages should show up in the logs BEFORE the
> > message form the polled read (because asyn calls the interrupt callbacks before
> > returning from read). What do you have in the logs right before the first line
> > you posted? Anything from AsynDriverInterface::asynReadHandler() and
> > StreamCore::readCallback()?
> > 
> > 
> > As StreamDevice did not receive a termination signal, it assumes there may be
> > more input and tries to read it. But that results in a timeout, which is then
> > interpreted as a termination signal, because no InTerminator is used.
> > 
> > This is probably not what you want. If the message never exceeds one CAN frame,
> > set eomReason to ASYN_EOM_END. This avoids wasting time on another read attempt.
> > If you may have messages that span multiple frames and have a method to find out
> > when this is the case in your driver, do that. Otherwise waiting for timeout (or
> > InTerminator or maxInput) is in fact the only way.
> > 
> > Now the question is why the input is rejected. Hard to say without knowing your
> > protocol. What do you have in your 'in' command?
> > 
> > Dirk
> > 
> > 
> > On Tue, 2023-07-04 at 09:05 +0200, Florian Feldbauer via Tech-talk wrote:
> > > Hey all,
> > > 
> > > we have some devices controlled via CAN bus.
> > > Since CAN bus is based on the transmission of 1-8 bytes, I wrote an
> > > AsynPortDriver with an asynOctet interface as lower level driver.
> > > 
> > > I wanted to use StreamDevice as higher level driver defining the actual
> > > payload data that is tranmitted between our PC and the devices.
> > > 
> > > Sending and receiving messages in principal works, but I have an issue
> > > with I/O Interrupts and I don't know why.
> > > Setting the streamDebug variable to 1, I see the following output from
> > > StreamDevice:
> > > 
> > > 2023/07/04 08:54:44.301618 can1 AsynDriverInterface.cc:951:
> > > AsynDriverInterface::readHandler(CAN1:TEST:R): ioAction=AsyncRead
> > > read(63 bytes, timeout=0 sec) returned status asynSuccess: received=4
> > > bytes, eomReason=NONE, buffer="<07><00><00><ea>"
> > > 2023/07/04 08:54:44.301765 can1 AsynDriverInterface.cc:977:
> > > AsynDriverInterface::readHandler(CAN1:TEST:R): AsyncRead poll: received
> > > 4 of 63 bytes "<07><00><00><ea>" eomReason=NONE [data ignored]
> > > 2023/07/04 08:54:44.301889 can1 AsynDriverInterface.cc:1123:
> > > AsynDriverInterface::readHandler(CAN1:TEST:R) readMore=-1 bytesToRead=63
> > > 2023/07/04 08:54:44.302015 can1 AsynDriverInterface.cc:951:
> > > AsynDriverInterface::readHandler(CAN1:TEST:R): ioAction=AsyncRead
> > > read(63 bytes, timeout=0.5 sec) returned status asynTimeout: received=0
> > > bytes, eomReason=NONE, buffer=""
> > > 2023/07/04 08:54:44.302140 can1 AsynDriverInterface.cc:1051:
> > > AsynDriverInterface::readHandler(CAN1:TEST:R): ioAction=AsyncRead,
> > > timeout [0.5 sec] after 0 of 63 bytes ""
> > > 2023/07/04 08:54:44.302262 can1 StreamCore.cc:963:
> > > StreamCore::readCallback(CAN1:TEST:R, StreamIoTimeout input="", size=0)
> > > 2023/07/04 08:54:44.302378 can1 StreamCore.cc:1015:
> > > StreamCore::readCallback(CAN1:TEST:R) inputBuffer="", size 0
> > > 2023/07/04 08:54:44.302490 can1 StreamCore.cc:1067:
> > > StreamCore::readCallback(CAN1:TEST:R) end flag received
> > > 2023/07/04 08:54:44.302605 can1 StreamCore.cc:1127:
> > > StreamCore::readCallback(CAN1:TEST:R) input line: ""
> > > 2023/07/04 08:54:44.302726 can1 StreamCore.cc:1151:
> > > StreamCore::readCallback(CAN1:TEST:R) async match failure: just restart
> > > 2023/07/04 08:54:44.302847 can1 AsynDriverInterface.cc:806:
> > > AsynDriverInterface::readRequest(CAN1:TEST:R, 500 msec reply, 500 msec
> > > read, expect 0 bytes, async=yes)
> > > 2023/07/04 08:54:44.302964 can1 AsynDriverInterface.cc:831:
> > > AsynDriverInterface::readRequest CAN1:TEST:R: queueRequest(...,
> > > priority=0, queueTimeout=-1 sec) = asynSuccess [async=true]
> > > 
> > > The readHandler reads the message from the bus but ignores it. According
> > > to the comments in the code it is ignored because the asyncReadHandler
> > > should also receive this message and handle the I/O interrupt, but it
> > > seems the Interrupt callback is not executed.
> > > Any idea why the callbacks don't work?
> > > 
> > > I'm using
> > > base 7.0.6.1
> > > stream 2.8.24
> > > asyn (current HEAD on master branch)
> > > 
> > > Cheers,
> > > Florian
> > > 
> > > 

Replies:
Re: Issue with streamdevice and I/o Intr Florian Feldbauer via Tech-talk
References:
Issue with streamdevice and I/o Intr Florian Feldbauer via Tech-talk
Re: Issue with streamdevice and I/o Intr Zimoch Dirk via Tech-talk
Re: Issue with streamdevice and I/o Intr Florian Feldbauer via Tech-talk

Navigate by Date:
Prev: RE : VME configuration : mrfioc2-master version in the new vme-evg-300, vme-evr-300 environment 이민균 via Tech-talk
Next: Re: Issue with streamdevice and I/o Intr Florian Feldbauer via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  <20232024 
Navigate by Thread:
Prev: Re: Issue with streamdevice and I/o Intr Florian Feldbauer via Tech-talk
Next: Re: Issue with streamdevice and I/o Intr Florian Feldbauer via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  <20232024 
ANJ, 04 Jul 2023 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·