// March, 97, start // cdev $vector $device $message ... .. #include #include "blt.h" #include #include #include #include #include // cdev includes #include #include #include #include #include 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.1", 0); Tcl_PkgRequire(interp, "Cdev", CDEV_VERSION, 0); if(Tcl_PkgProvide(interp, "Cdevvector", CDEV_VERSION) != TCL_OK) { return TCL_ERROR; } Tcl_CreateCommand(interp, "cdevvector", CdevVectorCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; }