- Added messagepipe.c

- Added initial version of sicsget. This is a more generalised way of
  reading and writing SICS data wherever it is. The thing is extendable if
  reading something the current way is to slow. This has both a C interface
  and an interpreter interface.
This commit is contained in:
koennecke
2013-11-07 08:42:32 +00:00
parent d7311c6f68
commit 57b6dce6bf
6 changed files with 781 additions and 1 deletions

View File

@ -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

118
messagepipe.c Normal file
View File

@ -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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include <messagepipe.h>
/*--------------------------------------------------------------------------------*/
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);
}
}
}

82
messagepipe.h Normal file
View File

@ -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

1
ofac.c
View File

@ -35,6 +35,7 @@ static void InitGeneral(void)
INIT(SctDriveAdapterInit);
INIT(SctDriveObjInit);
INIT(SctDriveAdapterInit);
INIT(SICSGetInit);
INIT(LogReaderInit);
INIT(LogSetupInit);
INIT(InstallBackground);

548
sicsget.c Normal file
View File

@ -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 <ctype.h>
#include <sics.h>
#include <sicsget.h>
#include <messagepipe.h>
#include <sicshipadaba.h>
#include <splitter.h>
#include <stptok.h>
#include <sicsdata.h>
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);
}
}

30
sicsget.h Normal file
View File

@ -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 <hipadaba.h>
/**
* 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