436 lines
10 KiB
C++
436 lines
10 KiB
C++
// March, 97, start
|
|
// cdev $vector $device $message ... ..
|
|
|
|
#include <tcl.h>
|
|
#include "blt.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <iostream.h>
|
|
#include <math.h>
|
|
//#include <dl.h>
|
|
|
|
// cdev includes
|
|
#include <cdevSystem.h>
|
|
#include <cdevRequestObject.h>
|
|
#include <cdevDevice.h>
|
|
#include <cdevGroup.h>
|
|
#include <cdevData.h>
|
|
|
|
static int VALUE_TAG_ID =- 1;
|
|
#define VALUE_TAG ((VALUE_TAG_ID<0 && cdevData::tagC2I("value", &VALUE_TAG_ID)!= CDEV_SUCCESS)?-1:VALUE_TAG_ID)
|
|
// static int STATUS_TAG_ID =- 1;
|
|
// #define STATUS_TAG ((STATUS_TAG_ID<0 && cdevData::tagC2I("status", &STATUS_TAG_ID)!= CDEV_SUCCESS)?-1:STATUS_TAG_ID)
|
|
// static int SEVERITY_TAG_ID =- 1;
|
|
// #define SEVERITY_TAG ((SEVERITY_TAG_ID<0 && cdevData::tagC2I("severity", &SEVERITY_TAG_ID)!= CDEV_SUCCESS)?-1:SEVERITY_TAG_ID)
|
|
|
|
static int cdevdebug = 0;
|
|
|
|
class tclCdevDataV {
|
|
public:
|
|
tclCdevDataV();
|
|
void parse(Tcl_Interp*, char* *, int);
|
|
~tclCdevDataV();
|
|
|
|
cdevData out, context;
|
|
int hascontext;
|
|
|
|
int tagn, *taglist;
|
|
char *callbacktag;
|
|
|
|
int state, async;
|
|
};
|
|
|
|
tclCdevDataV::~tclCdevDataV() {
|
|
delete taglist;
|
|
}
|
|
|
|
tclCdevDataV::tclCdevDataV():hascontext(0), tagn(0), taglist(NULL), async(0), state(TCL_ERROR) {
|
|
};
|
|
|
|
// Parses command line, fills up the outgoing cdevData and the context (if any)
|
|
void tclCdevDataV::parse(Tcl_Interp *interp, char **argv, int argc) {
|
|
int i, c1, c2;
|
|
cdevData *ptr;
|
|
char **s1 = NULL;
|
|
char **s2 = NULL;
|
|
|
|
// Point to 'out' cdevData until we hit the context (if any)
|
|
ptr = &out;
|
|
for(i = 3; i < argc; i++) {
|
|
// skip 'cdev' '$device' and '$message'
|
|
if(Tcl_SplitList(interp, argv[i], &c1, &s1) != TCL_OK) {
|
|
return;
|
|
}
|
|
if(c1 == 2) {
|
|
// {tag value} pair, check if the value is a scalar
|
|
if(Tcl_SplitList(interp, s1[1], &c2, &s2) != TCL_OK) {
|
|
free((char *) s1);
|
|
return;
|
|
}
|
|
if(c2 == 1) {
|
|
// we have a scalar
|
|
ptr->insert(s1[0], s1[1]);
|
|
// insert scalar
|
|
}
|
|
else {
|
|
ptr->insert(s1[0], s2, c2);
|
|
// insert vector of scalars, does not handle matrices
|
|
}
|
|
free((char *) s2);
|
|
}
|
|
else if(c1 == 1) {
|
|
// can be one of "-context" , "-tags" or a callbacktag
|
|
if(strcmp(argv[i], "-context") == 0) {
|
|
// all remaining 'tag value' pairs go in the context
|
|
ptr = &context;
|
|
hascontext = 1;
|
|
}
|
|
else if(strcmp(argv[i], "-tags") == 0) {
|
|
// get the list of tags to print out from the result data
|
|
i++;
|
|
// points to next entry in argv
|
|
if(i == argc) {
|
|
interp->result = "expected tag names";
|
|
free((char *) s1);
|
|
return;
|
|
}
|
|
if(Tcl_SplitList(interp, argv[i], &tagn, &s2) != TCL_OK) {
|
|
interp->result = "tag problem";
|
|
free((char *) s1);
|
|
return;
|
|
}
|
|
else {
|
|
taglist = new int[tagn];
|
|
for(int j = 0; j < tagn; j++) {
|
|
if(cdevData::tagC2I(s2[j], &taglist[j]) != CDEV_SUCCESS) {
|
|
interp->result = "unknown tag";
|
|
free((char *) s2);
|
|
free((char *) s1);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
free((char *) s2);
|
|
}
|
|
else {
|
|
// single entry, a callbacktag, better be at end of input
|
|
if(i != argc-1) {
|
|
interp->result = "expecting callbacktag at end";
|
|
free((char *) s1);
|
|
return;
|
|
}
|
|
// Here we have a callback tag, hence we want to send asynchronously
|
|
callbacktag = argv[i];
|
|
async = 1;
|
|
}
|
|
}
|
|
else {
|
|
// c1 > 2
|
|
// tag / string pair (i.e. "value this is a string with spaces embedded"
|
|
char **av = s1;
|
|
av++;
|
|
char *concat = Tcl_Concat(c1-1, av);
|
|
ptr->insert(s1[0], concat);
|
|
if(cdevdebug == 1) {
|
|
fprintf(stderr, "inserted: %s, with value: %s\n", s1[0], concat);
|
|
}
|
|
free(concat);
|
|
}
|
|
free((char *) s1);
|
|
}
|
|
state = TCL_OK;
|
|
}
|
|
|
|
class callbackInfoV {
|
|
public:
|
|
callbackInfoV(Tcl_Interp*, char *, Blt_Vector); // vectorname
|
|
callbackInfoV(Tcl_Interp*, char *, Blt_Vector, int); // vectorname
|
|
~callbackInfoV();
|
|
Tcl_Interp *interp;
|
|
cdevCallback *callback;
|
|
Blt_Vector vecInfo;
|
|
char *vecName;
|
|
int index;
|
|
};
|
|
|
|
callbackInfoV::callbackInfoV(Tcl_Interp *e, char *arg, Blt_Vector i) {
|
|
interp = e;
|
|
vecName = new char[strlen(arg)+1];
|
|
vecInfo = i;
|
|
strcpy(vecName, arg);
|
|
callback = NULL;
|
|
index = -1;
|
|
}
|
|
|
|
callbackInfoV::callbackInfoV(Tcl_Interp *e, char *arg, Blt_Vector i, int ind) {
|
|
interp = e;
|
|
vecName = new char[strlen(arg)+1];
|
|
vecInfo = i;
|
|
strcpy(vecName, arg);
|
|
callback = NULL;
|
|
index = ind;
|
|
}
|
|
|
|
callbackInfoV::~callbackInfoV() {
|
|
delete vecName;
|
|
}
|
|
|
|
cdevBounds *BoundsV;
|
|
int DimV;
|
|
|
|
int HandleTagV(Tcl_Interp *interp, cdevData &result, Blt_Vector *vecInfo, char* vecname, int index) {
|
|
int i, len;
|
|
size_t dim;
|
|
|
|
if(result.getDim(VALUE_TAG, &dim) != CDEV_SUCCESS) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
if( ((dim == 0) && (index < 0)) || ((dim == 1) && (index >= 0)) ) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
if (dim == 0) {
|
|
if (vecInfo->numValues <= index) {
|
|
return TCL_ERROR;
|
|
}
|
|
vecInfo->valueArr[index] = (double)result;
|
|
return Blt_ResetVector(interp, vecname, vecInfo, TCL_DYNAMIC);
|
|
}
|
|
|
|
// dim = 1
|
|
DimV = (int) dim;
|
|
BoundsV = new cdevBounds[DimV];
|
|
result.getBounds(VALUE_TAG, BoundsV, DimV);
|
|
len = 1;
|
|
for(i = 0; i < DimV; i++) {
|
|
len *= BoundsV[i].length;
|
|
}
|
|
|
|
if (vecInfo->arraySize < len) { // resize if necc.
|
|
if (Blt_ResizeVector(interp, vecname, len) != TCL_OK) return TCL_ERROR;
|
|
Blt_GetVector(interp, vecname, vecInfo);
|
|
}
|
|
|
|
result.get(VALUE_TAG, vecInfo->valueArr);
|
|
|
|
delete BoundsV;
|
|
if (Blt_ResetVector(interp, vecname, vecInfo, TCL_DYNAMIC) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
return TCL_OK;
|
|
}
|
|
|
|
// executes inside poll() whenever 'file' is readable
|
|
void Cdev_CallbackFunctionV(int, void *userarg, cdevRequestObject&, cdevData &result) {
|
|
// could check status and do appropriate action like: set Error(info->s) ???
|
|
callbackInfoV *info = (callbackInfoV *) userarg;
|
|
HandleTagV(info->interp, result, &info->vecInfo, info->vecName, info->index);
|
|
}
|
|
|
|
// same as above, plus removes callbackinfo
|
|
void Cdev_CallbackFunctionOnceV(int, void *userarg, cdevRequestObject&, cdevData &result) {
|
|
callbackInfoV *info = (callbackInfoV *) userarg;
|
|
HandleTagV(info->interp, result, &info->vecInfo, info->vecName, info->index);
|
|
delete info;
|
|
}
|
|
|
|
typedef cdevRequestObject *cdevRequestObjectPtr;
|
|
|
|
int CdevVectorCmd(ClientData, Tcl_Interp *interp, int argc, char **argv) {
|
|
// cdevvector vector device message {tag value} {..} cb
|
|
|
|
cdevData result;
|
|
cdevCallback *cb = NULL;
|
|
callbackInfoV *info;
|
|
tclCdevDataV data;
|
|
int n, delinfo = 0;
|
|
Blt_Vector vecInfo;
|
|
char **devices = NULL;
|
|
cdevRequestObjectPtr request, *requests;
|
|
|
|
if(argc < 4) {
|
|
Tcl_AppendResult(interp, "cdevvector: wrong # args", (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
if (!Blt_VectorExists(interp, argv[1])) {
|
|
if (Blt_CreateVector(interp, argv[1], 64, &vecInfo) != TCL_OK) {
|
|
interp->result = "vector creation error";
|
|
return TCL_ERROR;
|
|
}
|
|
} else {
|
|
if (Blt_GetVector(interp, argv[1], &vecInfo) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
int ndevices = 0;
|
|
|
|
if(Tcl_SplitList(interp, argv[2], &ndevices, &devices) != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
if (ndevices == 1) {
|
|
request = cdevRequestObject::attachPtr(argv[2], argv[3]);
|
|
free((char*)devices);
|
|
} else {
|
|
requests = new cdevRequestObjectPtr[ndevices];
|
|
for(n = 0; n < ndevices; n++) {
|
|
requests[n] = cdevRequestObject::attachPtr(devices[n], argv[3]);
|
|
}
|
|
if (vecInfo.arraySize < ndevices) { // resize if necc.
|
|
if (Blt_ResizeVector(interp, argv[1], ndevices) != TCL_OK) return TCL_ERROR;
|
|
Blt_GetVector(interp, argv[1], &vecInfo);
|
|
}
|
|
free((char *) devices);
|
|
}
|
|
|
|
data.parse(interp, argv+1, argc-1);
|
|
|
|
if(data.state != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
if(strncmp(argv[3], "monitorOn", 9) == 0) data.async = 1;
|
|
|
|
if(data.async) {
|
|
// we want to sent it async
|
|
|
|
if (ndevices == 1) {
|
|
info = new callbackInfoV(interp, argv[1], vecInfo);
|
|
|
|
if(strncmp(argv[3], "monitorOn", 9) == 0) {
|
|
cb = new cdevCallback(Cdev_CallbackFunctionV, (void *) info);
|
|
}
|
|
else if(strncmp(argv[3], "monitorOff", 10) == 0) {
|
|
delinfo = 1;
|
|
cb = new cdevCallback(NULL, NULL);
|
|
}
|
|
else {
|
|
cb = new cdevCallback(Cdev_CallbackFunctionOnceV, (void *) info);
|
|
}
|
|
|
|
info->callback = cb;
|
|
|
|
if(data.hascontext) {
|
|
if(request->setContext(data.context) != CDEV_SUCCESS) {
|
|
interp->result = "setContext error";
|
|
delete info;
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
if(request->sendCallback(data.out, *cb) != CDEV_SUCCESS) {
|
|
delete info;
|
|
return TCL_ERROR;
|
|
} else {
|
|
if(delinfo) delete info;
|
|
return TCL_OK;
|
|
}
|
|
} else { // ndevices > 1
|
|
int j = 0;
|
|
|
|
if(strncmp(argv[3], "monitorOn", 9) == 0) {
|
|
j = 1;
|
|
}
|
|
else if(strncmp(argv[3], "monitorOff", 10) == 0) {
|
|
j = 2;
|
|
}
|
|
|
|
for(n = 0; n < ndevices; n++) {
|
|
info = new callbackInfoV(interp, argv[1], vecInfo, n);
|
|
|
|
if(j == 1) {
|
|
cb = new cdevCallback(Cdev_CallbackFunctionV, (void *) info);
|
|
}
|
|
else if(j == 2) {
|
|
delinfo = 1;
|
|
cb = new cdevCallback(NULL, NULL);
|
|
}
|
|
else {
|
|
cb = new cdevCallback(Cdev_CallbackFunctionOnceV, (void *) info);
|
|
}
|
|
|
|
info->callback = cb;
|
|
|
|
if(data.hascontext) {
|
|
if(requests[n]->setContext(data.context) != 0) {
|
|
interp->result = "setContext error";
|
|
delete [] requests;
|
|
delete info;
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
if(requests[n]->sendCallback(data.out, *cb) != CDEV_SUCCESS) {
|
|
delete [] requests;
|
|
delete info;
|
|
return TCL_ERROR;
|
|
} else {
|
|
if(delinfo) delete info;
|
|
}
|
|
}
|
|
delete [] requests;
|
|
return TCL_OK;
|
|
}
|
|
}
|
|
|
|
// send it sync
|
|
if (ndevices == 1) {
|
|
if(data.hascontext) {
|
|
if(request->setContext(data.context) != CDEV_SUCCESS) {
|
|
interp->result = "setContext error";
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
if(request->send(data.out, result) != CDEV_SUCCESS) {
|
|
sprintf(interp->result, "error in send: %s %s", argv[2], argv[3]);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
HandleTagV(interp, result, &vecInfo, argv[1], -1);
|
|
|
|
return TCL_OK;
|
|
} else {
|
|
for(n = 0; n < ndevices; n++) {
|
|
if(data.hascontext) {
|
|
if(requests[n]->setContext(data.context) != 0) {
|
|
interp->result = "setContext error";
|
|
delete [] requests;
|
|
delete info;
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
if(requests[n]->send(data.out, result) != CDEV_SUCCESS) {
|
|
delete [] requests;
|
|
delete info;
|
|
return TCL_ERROR;
|
|
} else {
|
|
if(delinfo) delete info;
|
|
HandleTagV(interp, result, &vecInfo, argv[1], n);
|
|
}
|
|
}
|
|
delete [] requests;
|
|
return TCL_OK;
|
|
}
|
|
}
|
|
|
|
extern "C" int Cdevvector_Init(Tcl_Interp *interp) {
|
|
|
|
Tcl_PkgRequire(interp, "BLT", "2.4", 0);
|
|
Tcl_PkgRequire(interp, "Cdev", "", 0);
|
|
|
|
if(Tcl_PkgProvide(interp, "Cdevvector", "1.0") != TCL_OK) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
Tcl_CreateCommand(interp, "cdevvector", CdevVectorCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
|
|
|
|
return TCL_OK;
|
|
}
|
|
|
|
|
|
|