Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base asynInterpose implementation #145

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions asyn/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ DBD += asyn.dbd
INC += asynShellCommands.h
INC += asynInterposeCom.h
INC += asynInterposeEos.h
INC += asynInterposeTemplate.h
INC += asynInterposeFlush.h
ifneq ($(EPICS_LIBCOM_ONLY),YES)
asyn_SRCS += asynShellCommands.c
Expand All @@ -111,6 +112,7 @@ asyn_SRCS += asynInterposeEos.c
asyn_SRCS += asynInterposeFlush.c
asyn_SRCS += asynInterposeDelay.c
asyn_SRCS += asynInterposeEcho.c
asyn_SRCS += asynInterposeTemplate.c

SRC_DIRS += $(ASYN)/asynPortDriver/exceptions
INC += ParamListInvalidIndex.h
Expand Down
1 change: 1 addition & 0 deletions asyn/miscellaneous/asyn.dbd
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ registrar(asynInterposeFlushRegister)
registrar(asynInterposeEosRegister)
registrar(asynInterposeDelayRegister)
registrar(asynInterposeEchoRegister)
registrar(asynInterposeTemplateRegister)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with including this declaration in the widely-used asyn.dbd file is that from now on every EPICS IOC that includes this DBD file will run the asynInterposeTemplateRegister() routine during its initialization and thus must include a full copy of your template interpose layer code. Please at least move the registrar() line to a separate DBD file so it isn't pulled in unnecessarily by IOCs that don't want it.


#
# The following ties this to EPICS records.
Expand Down
152 changes: 152 additions & 0 deletions asyn/miscellaneous/asynInterposeTemplate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*asynInterposeTemplate.c*/

/*
* Example of an asynInterpose implementation
* The template implementation does *nothing*,
* simply forwards requests to the lower port.
*
* Use this as as a base example to build your asynInterpose.
*
* Author: [email protected]
*/

#include "asynInterposeTemplate.h"

ASYN_API
int asynInterposeTemplateConfig(const char *portName) {
interposePvt *pvt;
asynInterface *plowerLevelInterface;
asynStatus status;
asynUser *pasynUser;
int addr = 0;

// Populate private data
pvt = callocMustSucceed(1, sizeof(interposePvt), "asynInterposeTemplate");
pvt->portName = epicsStrDup(portName);
pvt->templateInterface.interfaceType = asynOctetType;
pvt->templateInterface.pinterface = &octet;
pvt->templateInterface.drvPvt = pvt;
pasynUser = pasynManager->createAsynUser(0, 0);
pvt->pasynUser = pasynUser;
pvt->pasynUser->userPvt = pvt;

// Connect
status = pasynManager->connectDevice(pasynUser, portName, addr);
if (status != asynSuccess) {
printf("%s connectDevice failed\n", portName);
pasynManager->freeAsynUser(pasynUser);
free(pvt);
return -1;
}

// Add callback
status = pasynManager->exceptionCallbackAdd(pasynUser, ExceptionHandler);
if (status != asynSuccess) {
printf("%s exceptionCallbackAdd failed\n", portName);
pasynManager->freeAsynUser(pasynUser);
free(pvt);
return -1;
}

// Interpose port
status = pasynManager->interposeInterface(portName, addr, &pvt->templateInterface,
&plowerLevelInterface);
if (status != asynSuccess) {
printf("%s interposeInterface failed\n", portName);
pasynManager->exceptionCallbackRemove(pasynUser);
pasynManager->freeAsynUser(pasynUser);
free(pvt);
return -1;
}
pvt->poctet = (asynOctet *)plowerLevelInterface->pinterface;
pvt->octetPvt = plowerLevelInterface->drvPvt;

return (0);
}

// Catch all exceptions
static void ExceptionHandler(asynUser *pasynUser, asynException exception) {
// On connections/disconnections
// Occurs every streamdevice transaction
if (exception == asynExceptionConnect) {
// Default = do nothing
}
}

/**
* asynOctet methods
*/

static asynStatus writeIt(void *ppvt, asynUser *pasynUser, const char *data, size_t numchars,
size_t *nbytesTransfered) {
interposePvt *pvt = (interposePvt *)ppvt;

// Write on underlying port
return pvt->poctet->write(pvt->octetPvt, pasynUser, data, numchars, nbytesTransfered);
}

static asynStatus readIt(void *ppvt, asynUser *pasynUser, char *data, size_t maxchars,
size_t *nbytesTransfered, int *eomReason) {
interposePvt *pvt = (interposePvt *)ppvt;

// Read from underlying port
return pvt->poctet->read(pvt->octetPvt, pasynUser, data, maxchars, nbytesTransfered, eomReason);
}

static asynStatus flushIt(void *ppvt, asynUser *pasynUser) {
interposePvt *pvt = (interposePvt *)ppvt;
return pvt->poctet->flush(pvt->octetPvt, pasynUser);
}

static asynStatus registerInterruptUser(void *ppvt, asynUser *pasynUser,
interruptCallbackOctet callback, void *userPvt,
void **registrarPvt) {
interposePvt *pvt = (interposePvt *)ppvt;
return pvt->poctet->registerInterruptUser(pvt->octetPvt, pasynUser, callback, userPvt,
registrarPvt);
}

static asynStatus cancelInterruptUser(void *ppvt, asynUser *pasynUser, void *registrarPvt) {
interposePvt *pvt = (interposePvt *)ppvt;
return pvt->poctet->cancelInterruptUser(pvt->octetPvt, pasynUser, registrarPvt);
}

static asynStatus setInputEos(void *ppvt, asynUser *pasynUser, const char *eos, int eoslen) {
interposePvt *pvt = (interposePvt *)ppvt;
return pvt->poctet->setInputEos(pvt->octetPvt, pasynUser, eos, eoslen);
}

static asynStatus getInputEos(void *ppvt, asynUser *pasynUser, char *eos, int eossize,
int *eoslen) {
interposePvt *pvt = (interposePvt *)ppvt;
return pvt->poctet->getInputEos(pvt->octetPvt, pasynUser, eos, eossize, eoslen);
}

static asynStatus setOutputEos(void *ppvt, asynUser *pasynUser, const char *eos, int eoslen) {
interposePvt *pvt = (interposePvt *)ppvt;
return pvt->poctet->setOutputEos(pvt->octetPvt, pasynUser, eos, eoslen);
}

static asynStatus getOutputEos(void *ppvt, asynUser *pasynUser, char *eos, int eossize,
int *eoslen) {
interposePvt *pvt = (interposePvt *)ppvt;
return pvt->poctet->getOutputEos(pvt->octetPvt, pasynUser, eos, eossize, eoslen);
}

/* register asynInterposeTemplateConfig*/
static const iocshArg asynInterposeTemplateConfigArg0 = {"portName", iocshArgString};
static const iocshArg *asynInterposeTemplateConfigArgs[] = {&asynInterposeTemplateConfigArg0};
static const iocshFuncDef asynInterposeTemplateConfigFuncDef = {"asynInterposeTemplateConfig", 1,
asynInterposeTemplateConfigArgs};
static void asynInterposeTemplateConfigCallFunc(const iocshArgBuf *args) {
asynInterposeTemplateConfig(args[0].sval);
}

static void asynInterposeTemplateRegister(void) {
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&asynInterposeTemplateConfigFuncDef, asynInterposeTemplateConfigCallFunc);
}
}
epicsExportRegistrar(asynInterposeTemplateRegister);
71 changes: 71 additions & 0 deletions asyn/miscellaneous/asynInterposeTemplate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*asynInterposeTemplate.h*/

/*
* Example of an asynInterpose implementation
* The template implementation does *nothing*,
* simply forwards requests to the lower port.
*
* Use this as as a base example to build your asynInterpose.
*
* Author: [email protected]
*/

#ifndef asynInterposeTemplate_H
#define asynInterposeTemplate_H

#include <cantProceed.h>
#include <epicsAssert.h>
#include <epicsExport.h>
#include <epicsStdio.h>
#include <epicsString.h>
#include <iocsh.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "asynDriver.h"
#include "asynOctet.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

// Interpose private data
typedef struct interposePvt {
char *portName;
asynInterface templateInterface; /* This asynOctet interface */
asynOctet *poctet; /* The methods we're overriding */
void *octetPvt; /* Private data of next lower interface */
asynUser *pasynUser; /* For connect/disconnect reporting */
} interposePvt;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interposePvt structure may be declared in the header file like this, but it will generally only be accessed by the routines that are included in the .c file so it doesn't need to be here (putting it in the header file makes it a public API). Normally the only other code which might need to know the internals of the structure would be a unit test program for the interface.


ASYN_API
int asynInterposeTemplateConfig(const char *portName);

/* Connect/disconnect handling */
static void ExceptionHandler(asynUser *pasynUser, asynException exception);

/* asynOctet methods */
static asynStatus writeIt(void *ppvt, asynUser *pasynUser, const char *data, size_t numchars,
size_t *nbytesTransfered);
static asynStatus readIt(void *ppvt, asynUser *pasynUser, char *data, size_t maxchars,
size_t *nbytesTransfered, int *eomReason);
static asynStatus flushIt(void *ppvt, asynUser *pasynUser);
static asynStatus registerInterruptUser(void *ppvt, asynUser *pasynUser,
interruptCallbackOctet callback, void *userPvt,
void **registrarPvt);
static asynStatus cancelInterruptUser(void *ppvt, asynUser *pasynUser, void *registrarPvt);
static asynStatus setInputEos(void *ppvt, asynUser *pasynUser, const char *eos, int eoslen);
static asynStatus getInputEos(void *ppvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen);
static asynStatus setOutputEos(void *ppvt, asynUser *pasynUser, const char *eos, int eoslen);
static asynStatus getOutputEos(void *ppvt, asynUser *pasynUser, char *eos, int eossize,
int *eoslen);
static asynOctet octet = {
writeIt, readIt, flushIt, registerInterruptUser, cancelInterruptUser,
setInputEos, getInputEos, setOutputEos, getOutputEos};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This octet static structure and all the routines declared static above it look wrong to me, header files shouldn't normally define concrete data structures since a new instance of that structure will be added to every object file whose source file includes that header. You seem to be expecting that only the asynInterposeTemplate.c file will include this header so the declarations belong in that .c file anyway (if any other source file tried to #include it the compiler would fail unless that source also provides definitions for all the static routines that the octet structure includes function pointers to).


#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* asynInterposeTemplate_H */