// Cdev collection access from tcl // Johannes van Zeijts // March 97, first version /* cdevcollection $devices cdevcollection $devices $attr $c set attrib $value $c get devices $c get attrib $c get $c get vector $v // store in blt::vector $v $c $message // send to cdev and return results */ #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) typedef cdevRequestObject *cdevRequestObjectPtr; // class DeviceEntry { // public: // DeviceEntry(char*); // ~DeviceEntry(); // // cdevRequestObject *request; // cdevData result; // int status; // }; class TclCdevCollection { public: TclCdevCollection(int, char**); ~TclCdevCollection(); char *getAttrib(); void setAttrib(char*); void getDevices(Tcl_Interp *); void getStatus(Tcl_Interp *); void getResult(Tcl_Interp *); void getCallback(Tcl_Interp *); int getLength() { return ndevices;} void getVector(double*); static void deleteCollection(ClientData); int send(); int sendCallback(Tcl_Interp*, char*); int checkCallback(); static void callbackFunction(int, void *, cdevRequestObject&, cdevData &); static void TimerHandler(ClientData); private: cdevRequestObjectPtr *requests; cdevData *results; char **devices; int ndevices; char *attrib; int *status, *callbacks; }; TclCdevCollection::TclCdevCollection(int n, char** s) : ndevices(0), devices(NULL), attrib(NULL) { if (n < 0) return; ndevices = n; devices = new char*[ndevices]; for (int i = 0; iptr; c->status[info->index] = stat; c->results[info->index] = result; c->callbacks[info->index] = 1; } int TclCdevCollection::checkCallback() { int stat = 0; for (int i = 0; i < ndevices; i++) { if (callbacks[i] == 0) return 0; } return 1; } void TclCdevCollection::TimerHandler(ClientData dummy) { cdevSystem::defaultSystem().poll(); callbackInfo2 *info = (callbackInfo2 *) dummy; if (info->ptr->checkCallback()) { // set something Tcl_SetVar2(info->interp, "Control", info->s, "1", TCL_GLOBAL_ONLY); delete info; } else { /// try again later Tcl_CreateTimerHandler(50, TclCdevCollection::TimerHandler, dummy); } } void TclCdevCollection::setAttrib(char* a) { char message[256]; delete attrib; attrib = new char[strlen(a)+1]; strcpy(attrib, a); strcpy(message,"get "); strcat(message, attrib); for(int i = 0; i < ndevices; i++) { requests[i] = cdevRequestObject::attachPtr(devices[i], message); } } char* TclCdevCollection::getAttrib() { return attrib; } void TclCdevCollection::getDevices(Tcl_Interp *interp) { int i; for (i = 0; i < ndevices; i++) { Tcl_AppendElement(interp, devices[i]); } } void TclCdevCollection::getStatus(Tcl_Interp *interp) { int i; char res[256]; for (i = 0; i < ndevices; i++) { sprintf(res, "%d", status[i]); Tcl_AppendElement(interp, res); } } void TclCdevCollection::getCallback(Tcl_Interp *interp) { int i; char res[256]; for (i = 0; i < ndevices; i++) { sprintf(res, "%d", callbacks[i]); Tcl_AppendElement(interp, res); } } void TclCdevCollection::getResult(Tcl_Interp *interp) { int i; char res[300]; for (i = 0; i < ndevices; i++) { results[i].get(VALUE_TAG, res, 255); Tcl_AppendElement(interp, res); } } void TclCdevCollection::getVector(double *res) { for (int i = 0; i < ndevices; i++) { results[i].get(VALUE_TAG, &res[i]); } } int TclCdevCollection::send() { int stat = CDEV_SUCCESS; int i; for (i = 0; i < ndevices; i++) { results[i].remove(); status[i] = requests[i]->send(NULL, results[i]); if ((status[i] != CDEV_SUCCESS) && (stat == CDEV_SUCCESS)) { stat = CDEV_ERROR; } } return stat; } int TclCdevCollection::sendCallback(Tcl_Interp* interp, char* v) { int stat = CDEV_SUCCESS; for (int i = 0; i < ndevices; i++) { results[i].remove(); callbacks[i] = 0; callbackInfo1* info1 = new callbackInfo1(this, i); cdevCallback* cb = new cdevCallback(TclCdevCollection::callbackFunction, (void *) info1); status[i] = requests[i]->sendCallback(NULL, *cb); if ((status[i] != CDEV_SUCCESS) && (stat == CDEV_SUCCESS)) { stat = CDEV_ERROR; } } callbackInfo2 *info2 = new callbackInfo2(interp, this, v); Tcl_SetVar2(interp, "Control", v, "0", TCL_GLOBAL_ONLY); Tcl_CreateTimerHandler(50, TclCdevCollection::TimerHandler, (ClientData) info2); return stat; } void TclCdevCollection::deleteCollection(ClientData clientData) { TclCdevCollection *collectionPtr; collectionPtr = (TclCdevCollection *) clientData; delete collectionPtr; } int CollectionCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]){ TclCdevCollection *collectionPtr; collectionPtr = (TclCdevCollection *) clientData; if (strcmp(argv[1], "get") == 0) { if (argc == 2) { // send it out to cdev // get if (collectionPtr->getAttrib() == NULL) { interp->result = "did not set attrib"; return TCL_ERROR; } if (collectionPtr->send() == CDEV_SUCCESS) { collectionPtr->getResult(interp); return TCL_OK; } interp->result = "encountered cdev error"; return TCL_ERROR; } if (strcmp(argv[2], "attrib") == 0) { // get attrib Tcl_SetResult(interp, collectionPtr->getAttrib(), TCL_STATIC); return TCL_OK; } if (strcmp(argv[2], "devices") == 0) { // get devices collectionPtr->getDevices(interp); return TCL_OK; } if (strcmp(argv[2], "status") == 0) { // get status collectionPtr->getStatus(interp); return TCL_OK; } if (strcmp(argv[2], "callback") == 0) { // get status collectionPtr->getCallback(interp); return TCL_OK; } if (strcmp(argv[2], "vector") == 0) { // get vector if (argc != 4) return TCL_ERROR; Blt_Vector vecInfo; if (!Blt_VectorExists(interp, argv[3])) { interp->result = "vector does not exist"; return TCL_ERROR; } if (collectionPtr->send() != CDEV_SUCCESS) { interp->result = "encountered cdev error"; return TCL_ERROR; } if (vecInfo.arraySize < collectionPtr->getLength()) { // resize if necc. if (Blt_ResizeVector(interp, argv[3], collectionPtr->getLength()) != TCL_OK) return TCL_ERROR; } if (Blt_GetVector(interp, argv[3], &vecInfo) != TCL_OK) return TCL_ERROR; vecInfo.numValues = collectionPtr->getLength(); vecInfo.valueArr = (double *) malloc(sizeof(double) * collectionPtr->getLength()); collectionPtr->getVector(vecInfo.valueArr); if (Blt_ResetVector(interp, argv[3], &vecInfo, TCL_DYNAMIC) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } } if (strcmp(argv[1], "set") == 0) { if (argc != 4) return TCL_ERROR; if (strcmp(argv[2], "attrib") == 0) { // set attrib $value collectionPtr->setAttrib(argv[3]); return TCL_OK; } } if (strcmp(argv[1], "sendcallback") == 0) { if (strcmp(argv[2], "vector") == 0) { // sendcallback vector $v if (argc != 4) return TCL_ERROR; Blt_Vector vecInfo; if (!Blt_VectorExists(interp, argv[3])) { interp->result = "vector does not exist"; return TCL_ERROR; } if (collectionPtr->sendCallback(interp, argv[3]) != CDEV_SUCCESS) { interp->result = "encountered cdev error"; return TCL_ERROR; } return TCL_OK; } return TCL_ERROR; } if (strcmp(argv[1], "checkcallback") == 0) { if (collectionPtr->checkCallback()) { interp->result = "1"; } else { interp->result = "0"; } return TCL_OK; } if (strcmp(argv[1], "getcallback") == 0) { if (strcmp(argv[2], "vector") == 0) { // getcallback vector $v if (argc != 4) return TCL_ERROR; Blt_Vector vecInfo; if (!Blt_VectorExists(interp, argv[3])) { interp->result = "vector does not exist"; return TCL_ERROR; } if (!collectionPtr->checkCallback()) { interp->result = "callbacks not ready"; return TCL_ERROR; } if (vecInfo.arraySize < collectionPtr->getLength()) { // resize if necc. if (Blt_ResizeVector(interp, argv[3], collectionPtr->getLength()) != TCL_OK) return TCL_ERROR; } if (Blt_GetVector(interp, argv[3], &vecInfo) != TCL_OK) return TCL_ERROR; vecInfo.numValues = collectionPtr->getLength(); vecInfo.valueArr = (double *) malloc(sizeof(double) * collectionPtr->getLength()); collectionPtr->getVector(vecInfo.valueArr); if (Blt_ResetVector(interp, argv[3], &vecInfo, TCL_DYNAMIC) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } } interp->result = "unknown command"; return TCL_ERROR; } int MakeCollectionCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]){ TclCdevCollection *collectionPtr; static int id = 0; int c1; char** s1; if (argc < 2 || argc >3) { interp->result = "wrong # args"; return TCL_ERROR; } if(Tcl_SplitList(interp, argv[1], &c1, &s1) != TCL_OK) { return TCL_ERROR; } collectionPtr = new TclCdevCollection(c1,s1); free ((char*) s1); sprintf(interp->result, "col%d", id); id++; Tcl_CreateCommand(interp, interp->result, CollectionCmd, (ClientData) collectionPtr, TclCdevCollection::deleteCollection); if (argc == 3) { collectionPtr->setAttrib(argv[2]); } return TCL_OK; } extern "C" int Cdevcollection_Init(Tcl_Interp *interp) { Tcl_PkgRequire(interp, "Blt", "2.1", 0); Tcl_PkgRequire(interp, "Cdev", "1.4", 0); if(Tcl_PkgProvide(interp, "Cdevcollection", CDEV_VERSION) != TCL_OK) { return TCL_ERROR; } Tcl_CreateCommand(interp, "cdevcollection", MakeCollectionCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; }