diff --git a/make_gen b/make_gen index 5b3f34df..3f29eedb 100644 --- a/make_gen +++ b/make_gen @@ -44,7 +44,8 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ singlenb.o simindex.o simidx.o uselect.o singletas.o motorsec.o \ rwpuffer.o asynnet.o background.o countersec.o hdbtable.o velosec.o \ histmemsec.o sansbc.o sicsutil.o strlutil.o genbinprot.o trace.o\ - singlebinb.o taskobj.o sctcomtask.o tasmono.o multicountersec.o + singlebinb.o taskobj.o sctcomtask.o tasmono.o multicountersec.o \ + messagepipe.o sicsget.o MOTOROBJ = motor.o simdriv.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/messagepipe.c b/messagepipe.c new file mode 100644 index 00000000..c0ad59fb --- /dev/null +++ b/messagepipe.c @@ -0,0 +1,118 @@ +/** + * An implementation for a message pipe system as described in + * + * http://eventuallyconsistent.net/2013/08/14/messaging-as-a-programming-model-part-2/ + * + * A message is passed through a series of filter routines which do things. + * + * Rather then loops I try using recursion here. + * + * copyright: GPL Copyleft + * + * Mark Koennecke, November 2013 + */ +#include +#include +#include +#include + +/*--------------------------------------------------------------------------------*/ +typedef struct __MessagePipe { + void *userData; + mpUserKill killFunc; + mpFilterFunc filterFunc; + struct __MessagePipe *next; + struct __MessagePipe *previous; +} MessagePipe; +/*--------------------------------------------------------------------------------*/ +static int EmptyFunc(void *message, void *userData) +{ + return MPCONTINUE; +} +/*---------------------------------------------------------------------------------*/ +pMP MakeMP() +{ + pMP result = NULL; + + result = malloc(sizeof(MessagePipe)); + if(result != NULL){ + memset(result,0,sizeof(MessagePipe)); + result->filterFunc = EmptyFunc; + } + return result; +} +/*---------------------------------------------------------------------------------*/ +void KillMP(pMP self) +{ + if(self == NULL){ + return; + } + + pMP next = self->next; + if(self->userData != NULL && self->killFunc != NULL){ + self->killFunc(self->userData); + } + free(self); + KillMP(next); +} +/*-----------------------------------------------------------------------------------*/ +int AppendMPFilter(pMP self, mpFilterFunc func, void *userData, mpUserKill usKill) +{ + assert(self != NULL); + assert(func != NULL); + + if(self->next == NULL){ + self->next = malloc(sizeof(MessagePipe)); + if(self->next != NULL){ + self->next->previous = self; + self->next->next = NULL; + self->next->userData = userData; + self->next->killFunc = usKill; + self->next->filterFunc = func; + return 0; + } else { + return 1; + } + } else { + return AppendMPFilter(self->next, func, userData, usKill); + } +} +/*-----------------------------------------------------------------------------------*/ +pMP PrependMPFilter(pMP self, mpFilterFunc func, void *userData, mpUserKill usKill) +{ + pMP result = NULL; + + assert(func != NULL); + + result = malloc(sizeof(MessagePipe)); + if(result != NULL){ + result->userData = userData; + result->killFunc = usKill; + result->filterFunc = func; + result->next = self; + result->previous = NULL; + return result; + } else { + /* + we are ignoring an error here......... + */ + return self; + } +} + +/*-----------------------------------------------------------------------------------*/ +int MPprocess(pMP self, void *message) +{ + int status; + + if(self == NULL || self->filterFunc == NULL){ + return MPCONTINUE; + } else { + status = self->filterFunc(message, self->userData); + if(status == MPSTOP){ + return status; + } else { + return MPprocess(self->next, message); + } + } +} diff --git a/messagepipe.h b/messagepipe.h new file mode 100644 index 00000000..c2f9fbfc --- /dev/null +++ b/messagepipe.h @@ -0,0 +1,82 @@ +/** + * An implementation for a message pipe system as described in + * + * http://eventuallyconsistent.net/2013/08/14/messaging-as-a-programming-model-part-2/ + * + * A message is passed through a series of filter routines which do things. + * + * copyright: GPL Copyleft + * + * Mark Koennecke, November 2013 + */ +#ifndef __MESSAGEPIPE +#define __MESSAGEPIPE + +#define MPCONTINUE 1 +#define MPSTOP 0 + +/** + * The messagePipe data structure defined in messagepipe.c + */ +typedef struct __MessagePipe *pMP; + +/** + * Protoype of the message filter function. + * @param message The message to process + * @param Optional private data for this message filter function + * @return MPSTOP for stopping further processing of the filter pipe + * or MPCONTINUE to continue processing + */ +typedef int (*mpFilterFunc)(void *message, void *userData); + +/** + * A function to free the userData when it is used + * @param userData The data structure passed in for userData to a filter function. + */ +typedef void (*mpUserKill)(void *userData); + + +/** + * Create an empty message pipe + * @return A message pipe structure or NULL when out of memory + */ +pMP MakeMP(); + +/** + * Delete a message pipe + * @param self The message pipe to delete + */ +void KillMP(pMP self); + +/** + * Append a filter function to the list of message filters to process + * @param self The message queue to append too + * @param func The filter function to append + * @param Optional userData to pass through to the filter function + * @param usKill An optional function to free the userData when the message pipe gets deleted + * @return 0 on success, 1 when out of memory + */ +int AppendMPFilter(pMP self, mpFilterFunc func, void *userData, mpUserKill usKill); + +/** + * Preppend a filter function to the list of message filters to process + * @param self The message queue to append too + * @param func The filter function to append + * @param Optional userData to pass through to the filter function + * @param usKill An optional function to free the userData when the message pipe gets deleted + * @return An updated pointer to the message pipe. + */ +pMP PrependMPFilter(pMP self, mpFilterFunc func, void *userData, mpUserKill usKill); + + +/** + * Process the message pipe with the given message + * @param self The messae pipe to process + * @param message The message to process. + * @return MPCONTINUE on successfull completion, MPABORT when the chain was + * aborted for some reason. + */ +int MPprocess(pMP self, void *message); + + +#endif diff --git a/ofac.c b/ofac.c index 441ad23c..095482f9 100644 --- a/ofac.c +++ b/ofac.c @@ -35,6 +35,7 @@ static void InitGeneral(void) INIT(SctDriveAdapterInit); INIT(SctDriveObjInit); INIT(SctDriveAdapterInit); + INIT(SICSGetInit); INIT(LogReaderInit); INIT(LogSetupInit); INIT(InstallBackground); diff --git a/sicsget.c b/sicsget.c new file mode 100644 index 00000000..252f5bad --- /dev/null +++ b/sicsget.c @@ -0,0 +1,548 @@ +/** + * This is a generalized SICS get/put routine. It tries to hard to match a name + * with the data. + * + * The other difference is that this uses the message pipe system for implementation. + * See messsagepipe.c for a pointer to documentation. + * + * copyright: see file COPYRIGHT + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +static pMP getPipe, setPipe, sicsPipe, tclPipe; + + +typedef struct { + int success; + char *name; + hdbValue *v; +} SSGMessage, *pSSGMessage; +/*---------------------------------------------------------------------------*/ +typedef struct { + int success; + char *command; + char *response; + hdbValue *v; +} ParseMessage, *pParseMessage; + +extern char *trim(char *txt); +/*---------------------------------------------------------------------------*/ +int sget(char *name, hdbValue *v) +{ + SSGMessage ssg; + int status; + + ssg.success = 0; + ssg.name = strdup(name); + ssg.v = v; + + MPprocess(getPipe,&ssg); + free(ssg.name); + + return ssg.success; +} +/*---------------------------------------------------------------------------*/ +int sput(char *name, hdbValue v) +{ + SSGMessage ssg; + int status; + + ssg.success = 0; + ssg.name = strdup(name); + ssg.v = &v; + + MPprocess(setPipe,&ssg); + free(ssg.name); + + return ssg.success; +} +/*---------------------------------------------------------------------------*/ +static int SICSGetCommand(SConnection * pCon, SicsInterp * pSics, void *pData, + int argc, char *argv[]) +{ + int status; + hdbValue v; + pDynString data; + + if(argc < 2) { + SCWrite(pCon,"ERROR: need at least address for sicsget",eError); + return 0; + } + + status = sget(argv[1], &v); + if(status){ + data = formatValue(v,NULL); + if(data != NULL){ + SCPrintf(pCon,eValue,"%s",GetCharArray(data)); + DeleteDynString(data); + } else { + SCPrintf(pCon,eError,"ERROR: formatting value for %s failed", argv[1]); + ReleaseHdbValue(&v); + return 0; + } + } else { + SCPrintf(pCon,eError,"ERROR: value for %s not found", argv[1]); + return 0; + } + ReleaseHdbValue(&v); + return 1; +} +/*---------------------------------------------------------------------------*/ +static int SICSPutCommand(SConnection * pCon, SicsInterp * pSics, void *pData, + int argc, char *argv[]) +{ + int status; + hdbValue v; + char buffer[2048]; + char error[132]; + + if(argc < 2) { + SCWrite(pCon,"ERROR: need at least address for sicsget",eError); + return 0; + } + + status = sget(argv[1],&v); + if(!status){ + SCPrintf(pCon,eError,"ERROR: %s not found",argv[1]); + return 0; + } + + Arg2Text(argc-2, &argv[2], buffer,sizeof(buffer)); + status = readHdbValue(&v,buffer,error,sizeof(error)); + if(status == 0){ + SCPrintf(pCon,eError,"ERROR: failed to parse data for %s, error %s", + argv[1], error); + return 0; + } + + status = sput(argv[1],v); + if(status == 0){ + SCPrintf(pCon,eError,"ERROR: error setting %s, value invalid?", + argv[1]); + } else { + SCSendOK(pCon); + } + + return status; +} +/*---------------------------------------------------------------------------*/ +static int InvokeSICSFunc(void *ms, void *userData) +{ + pParseMessage self = (pParseMessage)ms; + int status; + + SCsetMacro(pServ->dummyCon,1); + status = InterpExecute(pServ->pSics, pServ->dummyCon, self->command); + SCsetMacro(pServ->dummyCon,0); + if(!status){ + self->success = 0; + return MPSTOP; + } + self->response = strdup(Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int CheckSICSError(void *ms, void *userData) +{ + pParseMessage self = (pParseMessage)ms; + + if(strstr(self->response,"ERROR") != NULL){ + self->success = 0; + return MPSTOP; + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int SplitOffEqual(void *ms, void *userData) +{ + pParseMessage self = (pParseMessage)ms; + char *pPtr, *pEQ; + + pPtr = self->response; + if((pEQ = strstr(pPtr, "=")) != NULL){ + self->response = strdup(trim(pEQ+1)); + free(pPtr); + } + return MPCONTINUE; +} +/*---------------------------------------------------------------------------*/ +static int isNumber(char *txt) +{ + if(*txt == '\0'){ + return 1; + } + if(isalpha(*txt)){ + return 0; + } else { + return isNumber(txt+1); + } +} +/*---------------------------------------------------------------------------*/ +static int countWords(char *txt) +{ + char number[80]; + + if(txt == NULL){ + return 0; + } else { + return 1 + countWords(stptok(txt,number,sizeof(number)," ")); + } +} +/*---------------------------------------------------------------------------*/ +static hdbValue makeArray(char *txt, int type, int count) +{ + hdbValue ar; + char *pPtr; + char number[80]; + int i = 0; + + if(type == HIPINT){ + ar = makeHdbValue(HIPINTAR,count); + } else { + ar = makeHdbValue(HIPFLOATAR,count); + } + pPtr = txt; + while((pPtr = stptok(pPtr,number,sizeof(number)," ")) != NULL){ + if(type == HIPINT){ + ar.v.intArray[i] = atoi(number); + } else { + ar.v.floatArray[i] = atof(number); + } + } + return ar; +} +/*---------------------------------------------------------------------------*/ +static int ReturnAsNumber(void *ms, void *userData) +{ + pParseMessage self = (pParseMessage)ms; + int type, count; + hdbValue v; + + if(isNumber(self->response)){ + if(strstr(self->response,".") != NULL){ + type = HIPFLOAT; + } else { + type = HIPINT; + } + count = countWords(self->response); + if(count > 1) { + v = makeArray(self->response, type, count); + } else { + if(type == HIPINT){ + v = MakeHdbInt(atoi(self->response)); + } else { + v = MakeHdbFloat(atof(self->response)); + } + } + cloneHdbValue(&v,self->v); + ReleaseHdbValue(&v); + self->success = 1; + return MPSTOP; + } else { + return MPCONTINUE; + } +} +/*---------------------------------------------------------------------------*/ +static int ReturnAsText(void *ms, void *userData) +{ + hdbValue v; + + pParseMessage self = (pParseMessage)ms; + self->success = 1; + v = MakeHdbText(strdup(self->response)); + cloneHdbValue(&v,self->v); + ReleaseHdbValue(&v); + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static void configureSICSPipe() +{ + sicsPipe = MakeMP(); + AppendMPFilter(sicsPipe, InvokeSICSFunc, NULL, NULL); + AppendMPFilter(sicsPipe, CheckSICSError, NULL, NULL); + AppendMPFilter(sicsPipe, SplitOffEqual, NULL, NULL); + AppendMPFilter(sicsPipe, ReturnAsNumber, NULL, NULL); + AppendMPFilter(sicsPipe, ReturnAsText, NULL, NULL); + +} +/*----------------------------------------------------------------------------*/ +static int FindTclVar(void *ms, void *userData) +{ + pParseMessage self = (pParseMessage)ms; + + self->response = Tcl_GetVar(InterpGetTcl(pServ->pSics),self->command, TCL_GLOBAL_ONLY); + if(self->response == NULL){ + return MPSTOP; + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static void configureTclPipe() +{ + tclPipe = MakeMP(); + AppendMPFilter(tclPipe, FindTclVar, NULL, NULL); + AppendMPFilter(tclPipe, SplitOffEqual, NULL, NULL); + AppendMPFilter(tclPipe, ReturnAsNumber, NULL, NULL); + AppendMPFilter(tclPipe, ReturnAsText, NULL, NULL); + +} +/*----------------------------------------------------------------------------*/ +static int GetHdbFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + pHdb node = NULL; + + node = FindHdbNode(NULL,self->name,NULL); + if(node != NULL){ + cloneHdbValue(&node->value, self->v); + self->success = 1; + return MPSTOP; + } else { + return MPCONTINUE; + } +} +/*---------------------------------------------------------------------------*/ +static int GetSICSFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + ParseMessage ps; + + memset(&ps,0,sizeof(ParseMessage)); + ps.command = strdup(self->name); + ps.v = self->v; + MPprocess(sicsPipe,&ps); + self->success = ps.success; + free(ps.command); + if(ps.response != NULL){ + free(ps.response); + } + if(self->success){ + return MPSTOP; + } + return MPCONTINUE; +} +/*---------------------------------------------------------------------------*/ +static int GetTclFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + ParseMessage ps; + + memset(&ps,0,sizeof(ParseMessage)); + ps.command = strdup(self->name); + ps.v = self->v; + MPprocess(tclPipe,&ps); + self->success = ps.success; + free(ps.command); + if(self->success){ + return MPSTOP; + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int GetDrivableFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + void *data = NULL; + pIDrivable pDriv = NULL; + float fVal; + hdbValue v; + + data = FindCommandData(pServ->pSics, self->name,NULL); + if(data != NULL){ + pDriv = GetDrivableInterface(data); + if(pDriv != NULL){ + fVal = pDriv->GetValue(data,pServ->dummyCon); + v = MakeHdbFloat(fVal); + self->success = 1; + cloneHdbValue(&v,self->v); + return MPSTOP; + } + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int GetSicsdataFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + pSICSData data = NULL; + hdbValue v; + int i; + + data = FindCommandData(pServ->pSics,self->name, "SICSData"); + if(data != NULL){ + if(data->dataType[0] == INTTYPE){ + v = makeHdbValue(HIPINTVARAR, data->dataUsed); + for(i = 0; i < data->dataUsed; i++){ + v.v.intArray[i] = data->data[i]; + } + } else { + v = makeHdbValue(HIPFLOATVARAR, data->dataUsed); + for(i = 0; i < data->dataUsed; i++){ + v.v.floatArray[i] = (double)data->data[i]; + } + } + cloneHdbValue(&v, self->v); + ReleaseHdbValue(&v); + self->success = 1; + return MPSTOP; + } + + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static void configureGetPipe() +{ + getPipe = MakeMP(); + AppendMPFilter(getPipe, GetHdbFunc, NULL, NULL); + AppendMPFilter(getPipe, GetDrivableFunc, NULL, NULL); + AppendMPFilter(getPipe, GetSicsdataFunc, NULL, NULL); + AppendMPFilter(getPipe, GetSICSFunc, NULL, NULL); + AppendMPFilter(getPipe, GetTclFunc, NULL, NULL); +} +/*----------------------------------------------------------------------------*/ +static int PutHdbFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + pHdb node = NULL; + int status; + + node = FindHdbNode(NULL,self->name,NULL); + if(node != NULL){ + status = UpdateHipadabaPar(node,*(self->v),NULL); + self->success = status; + if(status == 1){ + return MPSTOP; + } + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int PutSICSFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + pDynString data = NULL; + int status; + char sicsobj[80]; + void *cdata; + + + data = formatValue(*(self->v),NULL); + if(data != NULL){ + DynStringInsert(data," ", 0); + DynStringInsert(data,self->name, 0); + status = InterpExecute(pServ->pSics, pServ->dummyCon, GetCharArray(data)); + DeleteDynString(data); + if(status == 1) { + self->success = 1; + return MPSTOP; + } else { + /* + Without this test bad sets on SICS commands may fall + through to Tcl where they succedd + */ + stptok(self->name,sicsobj,sizeof(sicsobj)," "); + cdata = FindCommandData(pServ->pSics,sicsobj,NULL); + if(cdata != NULL){ + self->success = 0; + return MPSTOP; + } + } + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int PutTclFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + pDynString data = NULL; + int status; + char *pPtr = NULL; + + data = formatValue(*(self->v),NULL); + if(data != NULL){ + pPtr = Tcl_SetVar(InterpGetTcl(pServ->pSics),self->name,GetCharArray(data),TCL_GLOBAL_ONLY); + DeleteDynString(data); + if(pPtr != NULL) { + self->success = 1; + return MPSTOP; + } + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int PutDrivableFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + void *data = NULL; + pIDrivable pDriv = NULL; + float fVal; + hdbValue v; + + data = FindCommandData(pServ->pSics, self->name,NULL); + if(data != NULL){ + pDriv = GetDrivableInterface(data); + if(pDriv != NULL){ + StartMotor(pServ->pExecutor,pServ->pSics, pServ->dummyCon, + self->name, RUNRUN, (float)self->v->v.doubleValue); + self->success = 1; + return MPSTOP; + } + } + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static int PutSicsdataFunc(void *ms, void *userData) +{ + pSSGMessage self = (pSSGMessage)ms; + pSICSData data = NULL; + int i; + + data = FindCommandData(pServ->pSics,self->name, "SICSData"); + if(data != NULL){ + if(self->v->dataType == HIPINTAR || self->v->dataType == HIPINTVARAR){ + for(i = 0; i < self->v->arrayLength; i++){ + setSICSDataInt(data,i,self->v->v.intArray[i]); + } + } else if(self->v->dataType == HIPFLOATAR || self->v->dataType == HIPFLOATVARAR){ + for(i = 0; i < self->v->arrayLength; i++){ + setSICSDataFloat(data,i,(float)self->v->v.floatArray[i]); + } + } else { + return MPSTOP; + } + self->success = 1; + return MPSTOP; + } + + return MPCONTINUE; +} +/*----------------------------------------------------------------------------*/ +static void configureSetPipe() +{ + setPipe = MakeMP(); + AppendMPFilter(setPipe, PutHdbFunc, NULL, NULL); + AppendMPFilter(setPipe, PutDrivableFunc, NULL, NULL); + AppendMPFilter(setPipe, PutSicsdataFunc, NULL, NULL); + AppendMPFilter(setPipe, PutSICSFunc, NULL, NULL); + AppendMPFilter(setPipe, PutTclFunc, NULL, NULL); +} +/*----------------------------------------------------------------------------*/ +void SICSGetInit(void) +{ + if (getPipe == NULL) { + configureGetPipe(); + configureSetPipe(); + configureSICSPipe(); + configureTclPipe(); + AddCmd("sget", SICSGetCommand); + AddCmd("sput", SICSPutCommand); + } +} diff --git a/sicsget.h b/sicsget.h new file mode 100644 index 00000000..ae1596c4 --- /dev/null +++ b/sicsget.h @@ -0,0 +1,30 @@ +/** + * This is a generalized SICS get/put routine. It tries to hard to match a name + * with the data. + * + * copyright: see file COPYRIGHT + * + */ +#ifndef __SICSGET +#define __SICSGET +#include + +/** + * Get a SICS value + * @param name The name of the value to get + * @param v The output hdbValue + * @return 1 on success, 0 on failure + */ +int sget(char *name, hdbValue *v); +/** + * Put a SICS value + * @param name The name of the value to write to + * @param v The hdbValue to write + * @return 1 on success, 0 on failure + */ +int sput(char *name, hdbValue v); + + + +#endif +