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 2023 2024 | 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 2023 2024 |
<== Date ==> | <== Thread ==> |
---|
Subject: | RE: drvAsynIPPortConfigure and I/O Intr with asynRecord possible? |
From: | Mark Rivers via Tech-talk <[email protected]> |
To: | 'Benjamin Franksen' <[email protected]> |
Cc: | "'[email protected]'" <[email protected]> |
Date: | Mon, 8 Apr 2019 17:00:14 +0000 |
Hi Ben, My previous messages had some typos where I said “registerInterruptUser” when I meant “registerInterruptSource”. I have fixed them in this version. I figured it out. drvAsynIPPort does the following during initialization: pasynOctet->read = readIt; pasynOctet->write = writeIt; pasynOctet->flush = flushIt; tty->octet.interfaceType = asynOctetType; tty->octet.pinterface = pasynOctet; tty->octet.drvPvt = tty; status = pasynOctetBase->initialize(tty->portName,&tty->octet, 0, 0, 1); if(status != asynSuccess) { printf("drvAsynIPPortConfigure: pasynOctetBase->initialize failed.\n"); ttyCleanup(tty); return -1; } Note that it calls pasynOctetBase->initialize() with a final argument of 1. This is the initialize code that it calls in interfaces/asynOctetBase.c static asynStatus initialize(const char *portName, asynInterface *pdriver, int processEosIn,int processEosOut, int interruptProcess) { octetPvt *poctetPvt; … poctetPvt->interruptProcess = interruptProcess; if(interruptProcess) { status = pasynManager->registerInterruptSource( portName,&poctetPvt->octetBase,&poctetPvt->pasynPvt); if(status!=asynSuccess) { printf("registerInterruptSource failed\n"); return status; } } The final argument to the initialize() function is thus interruptProcess, and if that is non-zero then the initialize routine calls pasynManager->registerInterruptSource()
for the asynOctet interface. So the drvAsynIPPort driver does explicitly ask for pasynManager->registerInterruptSource() to be called on the asynOctet interface. Marty wrote this code a long time ago, and I’m not sure why he added the call to pasynManager->registerInterruptSource() for the asynOctet interface initialization, but
not for the other interfaces. These are all the place in asyn itself where pasynOctetBase->initialize() is called. ./testApp/src/addrChangeDriver.c: status = pasynOctetBase->initialize(portName,&paddrChangePvt->octet, ./testApp/src/addrChangeDriver.c- 0,0,0); ./testApp/src/echoDriver.c- if(multiDevice) { ./testApp/src/echoDriver.c: status = pasynOctetBase->initialize(portName,&pechoPvt->octet,0,0,0); ./testApp/src/echoDriver.c- } else { ./testApp/src/echoDriver.c: status = pasynOctetBase->initialize(portName,&pechoPvt->octet,1,1,0); ./testApp/src/echoDriver.c- } ./asyn/drvAsynSerial/drvAsynSerialPort.c: status = pasynOctetBase->initialize(tty->portName,&tty->octet, ./asyn/drvAsynSerial/drvAsynSerialPort.c- (noProcessEos ? 0 : 1),(noProcessEos ? 0 : 1),1); ./asyn/drvAsynSerial/drvAsynSerialPortWin32.c: status = pasynOctetBase->initialize(tty->portName,&tty->octet, ./asyn/drvAsynSerial/drvAsynSerialPortWin32.c- (noProcessEos ? 0 : 1),(noProcessEos ? 0 : 1),1); ./asyn/drvAsynSerial/drvAsynIPServerPort.c: status = pasynOctetBase->initialize(tty->portName, &tty->octet, 0, 0, 0); ./asyn/drvAsynSerial/drvAsynIPPort.c: status = pasynOctetBase->initialize(tty->portName,&tty->octet, 0, 0, 1); ./asyn/drvAsynUSBTMC/drvAsynUSBTMC.c: status = pasynOctetBase->initialize(pdpvt->portName, &pdpvt->asynOctet, 0, 0, 0); ./asyn/asynGpib/asynGpib.c: status = pasynOctetBase->initialize(portName,&pgpibPvt->octet,0,0,0); ./asyn/interfaces/asynStandardInterfacesBase.c: status = pasynOctetBase->initialize(portName, &pInterfaces->octet, ./asyn/interfaces/asynStandardInterfacesBase.c- pInterfaces->octetProcessEosIn, ./asyn/interfaces/asynStandardInterfacesBase.c- pInterfaces->octetProcessEosIn, ./asyn/interfaces/asynStandardInterfacesBase.c- pInterfaces->octetInterruptProcess); Note that the final argument is only set to 1 for the drvAsynSerialPort, drvAsynSerialPortWin32, drvAsynIPPort, and optionally for asynStandardInterfacesBase. Note that asynOctetBase.c also implements a convenience function called callInterruptUser() to actually do the interrupt callbacks. This is the locations in asyn itself
where that function is called: corvette:~/devel/asyn>find . -name '*.c*' -exec grep -H callInterruptUsers {} \; ./testApp/src/addrChangeDriver.c: pasynOctetBase->callInterruptUsers(pasynUser,paddrChangePvt->pasynPvt, ./testApp/src/echoDriver.c: pasynOctetBase->callInterruptUsers(pasynUser,pechoPvt->pasynPvt, ./asyn/asynGpib/asynGpib.c: pasynOctetBase->callInterruptUsers(pasynUser,pgpibPvt->pasynPvt, Note that the drvAsynSerialPort and drvAsynIPPort drivers do not call it. So I am not sure why the interruptProcess flag is set to 1 in those drivers calls to pasynOctetBase->initialize(),
since they never actually do interrupt callbacks. But if you want to try to implement interrupt callbacks in drvAsynIPPort, then most of the groundwork is already done. You just need to call pasynOctetBase->callInterruptUsers(). Mark -----Original Message----- Hi Ben, Please ignore my previous post. I just tried adding a call to pasynManager->registerInterruptSource() to drvAsynIPPort.c, and I get the same error you do: ************************* diff --git a/asyn/drvAsynSerial/drvAsynIPPort.c b/asyn/drvAsynSerial/drvAsynIPPort.c index 12c0205..2f85616 100644 --- a/asyn/drvAsynSerial/drvAsynIPPort.c +++ b/asyn/drvAsynSerial/drvAsynIPPort.c @@ -1031,7 +1031,14 @@ drvAsynIPPortConfigure(const char *portName, ttyCleanup(tty); return -1; } - +void *octetCallbackPvt; +status = pasynManager->registerInterruptSource(tty->portName, &tty->octet, + &octetCallbackPvt); +if (status != asynSuccess) { + printf("drvAsynIPortConfigure registerInterruptSource failed\n"); + ttyCleanup(tty); + return -1; +} /* * Register for socket cleanup */ ************************* drvAsynIPPortConfigure("IPPort", "newport-xps12:5001", 0, 0, 1); IPPort asynManager:registerInterruptSource already registered drvAsynIPortConfigure registerInterruptSource failed I need to figure this out. I don't know what code is calling registerInterruptSource for that interface, but it should not be standardInterfacesBase.c. Mark -----Original Message----- From: [email protected] <[email protected]>
On Behalf Of Mark Rivers via Tech-talk Sent: Monday, April 8, 2019 10:58 AM To: 'Benjamin Franksen' <[email protected]> Cc: '[email protected]' <[email protected]> Subject: RE: drvAsynIPPortConfigure and I/O Intr with asynRecord possible? > It is easy to add this capability to drvAsynIPPort. But when I call > pasynManager->registerInterruptSource I get an error > "asynManager:registerInterruptSource already registered".
Where are you calling that from? How did you call it? > Apparently there is a mechanism in place that generically registers an
> interrupt source for /every/ asynOctet interface (and all other
> standard asyn interfaces, too). This effectively blocks this feature
> for all standard asyn interfaces, so it becomes impossible to add I/O
> Intr support to drvAsynIPPort. The code that calls > registerInterruptSource in this generic manner is guarded by an "if
> (octetCanInterrupt)" but I was unable to find out what I should do for this flag to be reset. > It gets set by the constructor for class asynPortDriver, but I found
> no place where this class actually gets instantiated to an object,
> i.e. a call to the constructor takes place. I find all this pretty confusing and would appreciate hints... The code that guards with "if (octetCanInterrupt)" is in asynStandardInterfacesBase.c. That is typically called in the constructor of asynPortDriver. In the asynPortDriver constructor you pass it a bit mask of interfaces on which your
driver will register interrupts. If you set the asynOctetMask bit in that mask then asynStandardInterfacesBase will call registerInterruptSource on the asynOctet interface. However, this should be completely irrelevant for the drvAsynIPPort driver, because it does not derive from asynPortDriver and does not use asynStandardInterfacesBase. Are you sure you were calling pasynManager->registerInterruptSource with a drvAsynIPPort name, and not some other port that derived from asynPortDriver? Mark -----Original Message----- From: [email protected] <[email protected]>
On Behalf Of Benjamin Franksen via Tech-talk Sent: Monday, April 8, 2019 9:51 AM Subject: Re: drvAsynIPPortConfigure and I/O Intr with asynRecord possible? Am 04.04.19 um 20:32 schrieb Mark Rivers via Tech-talk: > The asyn record does NOT work with SCAN=I/O Intr for TCP devices. The
> problem is that drvAsynIPPort does not have a mechanism to do
> callbacks when there is new data, so asyn client needs to poll. The
> only code I know of that does this is StreamDevice. It is easy to add this capability to drvAsynIPPort. But when I call pasynManager->registerInterruptSource I get an error "asynManager:registerInterruptSource already registered". Apparently there is a mechanism in place that generically registers an interrupt source for /every/ asynOctet interface (and all other standard asyn interfaces, too). This effectively
blocks this feature for all standard asyn interfaces, so it becomes impossible to add I/O Intr support to drvAsynIPPort. The code that calls registerInterruptSource in this generic manner is guarded by an "if (octetCanInterrupt)" but I was unable to find out
what I should do for this flag to be reset. It gets set by the constructor for class asynPortDriver, but I found no place where this class actually gets instantiated to an object, i.e. a call to the constructor takes place. I find all this pretty confusing
and would appreciate hints... Cheers Ben |