Files
cdev-1.7.2n/extensions/tclnew/tcl_cdevvector.cc
2022-12-13 12:44:04 +01:00

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;
}