//int PDQ_CreateNode(char *name, int device, int sched) void PDQ_CreateNode(char *name, int device, int sched) { extern NODE_TYPE *node; extern char s1[], s2[]; extern int nodes; extern int PDQ_DEBUG; char *p = "PDQ_CreateNode"; FILE* out_fd; if (PDQ_DEBUG) { debug(p, "Entering"); out_fd = fopen("PDQ.out", "a"); fprintf(out_fd, "name : %s device : %d sched : %d\n", name, device, sched); //PJP this really needed to be fclose //close(out_fd); fclose(out_fd); } if (k > MAXNODES) { sprintf(s1, "Allocating \"%s\" exceeds %d max nodes", name, MAXNODES); errmsg(p, s1); } if (strlen(name) >= MAXCHARS) { sprintf(s1, "Nodename \"%s\" is longer than %d characters", name, MAXCHARS); errmsg(p, s1); } strcpy(node[k].devname, name); if (sched == MSQ && device < 0) { // interpret node as multiserver and // number of servers must be positive integer sprintf(s1, "Must specify MSQ node with CEN equal to positive number of servers"); errmsg(p, s1); } node[k].devtype = device; node[k].sched = sched; if (PDQ_DEBUG) { typetostr(s1, node[k].devtype); typetostr(s2, node[k].sched); PRINTF("\tNode[%d]: %s %s \"%s\"\n", k, s1, s2, node[k].devname); resets(s1); resets(s2); }; if (PDQ_DEBUG) debug(p, "Exiting"); // update global node count k = ++nodes; } // PDQ_CreateNode
double getjob_pop(int c) { extern char s1[], s2[]; char *p = "getjob_pop()"; if (PDQ_DEBUG) debug(p, "Entering"); switch (job[c].should_be_class) { case TERM: if (PDQ_DEBUG) debug(p, "Exiting"); return (job[c].term->pop); break; case BATCH: if (PDQ_DEBUG) debug(p, "Exiting"); return (job[c].batch->pop); break; default: /* error */ typetostr(s1, job[c].should_be_class); sprintf(s2, "Stream %d. Unknown job type %s", c, s1); errmsg(p, s2); break; } return -1.0; } /* getjob_pop */
void create_batch_stream(int net, char* label, double number) { extern JOB_TYPE *job; extern char s1[]; extern int PDQ_DEBUG; char *p = "create_batch_stream()"; if (PDQ_DEBUG) debug(p, "Entering"); /***** using global value of n *****/ strcpy(job[c].batch->name, label); job[c].should_be_class = BATCH; job[c].network = net; job[c].batch->pop = number; if (PDQ_DEBUG) { typetostr(s1, job[c].should_be_class); PRINTF("\tStream[%d]: %s \"%s\"; N: %3.1f\n", c, s1, job[c].batch->name, job[c].batch->pop); resets(s1); } if (PDQ_DEBUG) debug(p, "Exiting"); } // create_batch_stream
void create_term_stream(int circuit, char *label, double pop, double think) { extern JOB_TYPE *job; extern char s1[]; extern int PDQ_DEBUG; char *p = "create_term_stream()"; if (PDQ_DEBUG) debug(p, "Entering"); strcpy(job[c].term->name, label); job[c].should_be_class = TERM; job[c].network = circuit; job[c].term->think = think; job[c].term->pop = pop; if (PDQ_DEBUG) { typetostr(s1, job[c].should_be_class); PRINTF("\tStream[%d]: %s \"%s\"; N: %3.1f, Z: %3.2f\n", c, s1, job[c].term->name, job[c].term->pop, job[c].term->think ); resets(s1); } if (PDQ_DEBUG) debug(p, "Exiting"); } // create_term_stream
//------------------------------------------------------------------------- // Subroutines //------------------------------------------------------------------------- void create_transaction(int net, char* label, double lambda) { extern JOB_TYPE *job; extern char s1[]; extern int PDQ_DEBUG; strcpy(job[c].trans->name, label); job[c].should_be_class = TRANS; job[c].network = net; job[c].trans->arrival_rate = lambda; if (PDQ_DEBUG) { typetostr(s1, job[c].should_be_class); PRINTF("\tStream[%d]: %s\t\"%s\";\tLambda: %3.1f\n", c, s1, job[c].trans->name, job[c].trans->arrival_rate); resets(s1); } } // create_transaction
static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { struct hci_dev *hdev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", typetostr(hdev->type)); }
void PDQ_CreateMultiserverClosed(int servers, char *name, int device, int sched) { extern NODE_TYPE *node; extern char s1[], s2[]; extern int nodes; extern int PDQ_DEBUG; FILE* out_fd; char *p = "PDQ_CreateMultiserverClosed"; // hack to force FESC node type //sched = FESC; //device = servers; if (PDQ_DEBUG) { debug(p, "Entering"); out_fd = fopen("PDQ.out", "a"); fprintf(out_fd, "name : %s device : %d sched : %d\n", name, device, sched); //The following should really be fclose // close(out_fd); fclose(out_fd); } if (streams > 1) { sprintf(s1, "Only single workload allowed with CreateMultiserverClosed()\n"); errmsg(p, s1); } if (k > 1) { sprintf(s1, "Allocating \"%s\" exceeds %d max nodes", name, MAXNODES); errmsg(p, s1); } if (strlen(name) >= MAXCHARS) { sprintf(s1, "Nodename \"%s\" is longer than %d characters", name, MAXCHARS); errmsg(p, s1); } strcpy(node[k].devname, name); if (servers <= 0) { // number of servers must be positive integer sprintf(s1, "Must specify a positive number of servers"); errmsg(p, s1); } // Added by NJG on Dec 29, 2018 node[k].devtype = device; node[k].sched = sched; node[k].servers = servers; if (PDQ_DEBUG) { typetostr(s1, node[k].devtype); typetostr(s2, node[k].sched); PRINTF("\tNode[%d]: %s %s \"%s\"\n", k, s1, s2, node[k].devname); resets(s1); resets(s2); }; if (PDQ_DEBUG) debug(p, "Exiting"); // update global node count k = ++nodes; } // PDQ_CreateMultiserverClosed
void approx(void) { extern int PDQ_DEBUG, iterations, streams, nodes; extern char s1[], s2[], s3[], s4[]; extern double tolerance; extern JOB_TYPE *job; extern NODE_TYPE *node; extern void typetostr(); extern void getjob_name(); int k, c; int should_be_class; double sumQ(); double sumR[MAXSTREAMS]; double delta = 2 * TOL; int iterate; char jobname[MAXBUF]; NODE_TYPE *last; char *p = "approx()"; if (PDQ_DEBUG) debug(p, "Entering"); if (nodes == 0 || streams == 0) errmsg(p, "Network nodes and streams not defined."); #ifndef __R_PDQ if ((last = (NODE_TYPE *) calloc(sizeof(NODE_TYPE), nodes)) == NULL) #else if ((last = (NODE_TYPE *) Calloc((size_t) nodes, NODE_TYPE )) == NULL) #endif errmsg(p, "Node (last) allocation failed!\n"); iterations = 0; if (PDQ_DEBUG) { sprintf(s1, "\nIteration: %d", iterations); debug(p, s1); resets(s1); } /* initialize all queues */ for (c = 0; c < streams; c++) { should_be_class = job[c].should_be_class; for (k = 0; k < nodes; k++) { switch (should_be_class) { case TERM: last[k].qsize[c] = node[k].qsize[c] = job[c].term->pop / nodes; break; case BATCH: last[k].qsize[c] = node[k].qsize[c] = job[c].batch->pop / nodes; break; default: break; } if (PDQ_DEBUG) { getjob_name(jobname, c); sprintf(s2, "Que[%s][%s]: %3.4f (D=%f)", node[k].devname, jobname, node[k].qsize[c], delta); debug(p, s2); resets(s2); resets(jobname); } } /* over k */ } /* over c */ do { iterations++; if (PDQ_DEBUG) { sprintf(s1, "\nIteration: %d", iterations); debug(p, s1); resets(s1); } for (c = 0; c < streams; c++) { getjob_name(jobname, c); sumR[c] = 0.0; if (PDQ_DEBUG) { sprintf(s1, "\nStream: %s", jobname); debug(p, s1); resets(s1); } should_be_class = job[c].should_be_class; for (k = 0; k < nodes; k++) { if (PDQ_DEBUG) { sprintf(s2, "Que[%s][%s]: %3.4f (D=%1.5f)", node[k].devname, jobname, node[k].qsize[c], delta); debug(p, s2); resets(s1); } /* approximate avg queue length */ switch (should_be_class) { double N; case TERM: N = job[c].term->pop; node[k].avqsize[c] = sumQ(k, c) + (node[k].qsize[c] * (N - 1.0) / N); break; case BATCH: N = job[c].batch->pop; node[k].avqsize[c] = sumQ(k, c) + (node[k].qsize[c] * (N - 1.0) / N); break; default: typetostr(s1, should_be_class); sprintf(s2, "Unknown should_be_class: %s", s1); errmsg(p, s2); resets(s2); break; } if (PDQ_DEBUG) { sprintf(s2, "<Q>[%s][%s]: %3.4f (D=%1.5f)", node[k].devname, jobname, node[k].avqsize[c], delta ); debug(p, s2); resets(s2); } /* residence times */ switch (node[k].sched) { case FCFS: case PSHR: case LCFS: node[k].resit[c] = node[k].demand[c] * (node[k].avqsize[c] + 1.0); break; case ISRV: node[k].resit[c] = node[k].demand[c]; break; default: typetostr(s1, node[k].sched); sprintf(s2, "Unknown queue type: %s", s1); errmsg(p, s2); break; } sumR[c] += node[k].resit[c]; if (PDQ_DEBUG) { PRINTF("\tTot ResTime[%s] = %3.4f\n", jobname, sumR[c]); PRINTF("\tnode[%s].qsize[%s] = %3.4f\n", node[k].devname, jobname, node[k].qsize[c] ); PRINTF("\tnode[%s].demand[%s] = %3.4f\n", node[k].devname, jobname, node[k].demand[c] ); PRINTF("\tnode[%s].resit[%s] = %3.4f\n", node[k].devname, jobname, node[k].resit[c] ); } } /* over k */ /* system throughput, residency & response-time */ switch (should_be_class) { case TERM: job[c].term->sys->thruput = (job[c].term->pop / (sumR[c] + job[c].term->think)); job[c].term->sys->response = (job[c].term->pop / job[c].term->sys->thruput) - job[c].term->think; job[c].term->sys->residency = job[c].term->pop - (job[c].term->sys->thruput * job[c].term->think); if (PDQ_DEBUG) { sprintf(s2, "\tTERM<X>[%s]: %5.4f", jobname, job[c].term->sys->thruput); debug(p, s2); resets(s2); sprintf(s2, "\tTERM<R>[%s]: %5.4f", jobname, job[c].term->sys->response); debug(p, s2); resets(s2); } break; case BATCH: job[c].batch->sys->thruput = job[c].batch->pop / sumR[c]; job[c].batch->sys->response = (job[c].batch->pop / job[c].batch->sys->thruput); job[c].batch->sys->residency = job[c].batch->pop; if (PDQ_DEBUG) { sprintf(s2, "\t<X>[%s]: %3.4f", jobname, job[c].batch->sys->thruput); debug(p, s2); resets(s2); sprintf(s2, "\t<R>[%s]: %3.4f", jobname, job[c].batch->sys->response); debug(p, s2); resets(s2); } break; default: sprintf(s1, "Unknown should_be_class: %s", should_be_class); errmsg(p, s1); break; } resets(jobname); } /* over c */ /* update queue sizes */ for (c = 0; c < streams; c++) { getjob_name(jobname, c); should_be_class = job[c].should_be_class; iterate = FALSE; if (PDQ_DEBUG) { sprintf(s1, "Updating queues of \"%s\"", jobname); PRINTF("\n"); debug(p, s1); resets(s1); } for (k = 0; k < nodes; k++) { switch (should_be_class) { case TERM: node[k].qsize[c] = job[c].term->sys->thruput * node[k].resit[c]; break; case BATCH: node[k].qsize[c] = job[c].batch->sys->thruput * node[k].resit[c]; break; default: sprintf(s1, "Unknown should_be_class: %s", should_be_class); errmsg(p, s1); break; } /* check convergence */ delta = fabs((double) (last[k].qsize[c] - node[k].qsize[c])); if (delta > tolerance) /* for any node */ iterate = TRUE; /* but complete all queue updates */ last[k].qsize[c] = node[k].qsize[c]; if (PDQ_DEBUG) { sprintf(s2, "Que[%s][%s]: %3.4f (D=%1.5f)", node[k].devname, jobname, node[k].qsize[c], delta); debug(p, s2); resets(s2); } } /* over k */ resets(jobname); } /* over c */ if (PDQ_DEBUG) debug(p, "Update complete"); } while (iterate); /* cleanup */ if (last) { PDQ_FREE(last); last = NULL; } if (PDQ_DEBUG) debug(p, "Exiting"); } /* approx */
void canonical(void) { extern int PDQ_DEBUG, streams, nodes; extern char s1[], s2[], s3[], s4[]; extern JOB_TYPE *job; extern NODE_TYPE *node; extern double ErlangR(double arrivrate, double servtime, int servers); // ANSI int k; int m; // servers in MSQ case int c = 0; double X; double Xsat; double Dsat = 0.0; double Ddev; double sumR[MAXSTREAMS]; double devU; double sumU(); char jobname[MAXBUF]; char satname[MAXBUF]; char *p = "canonical()"; if (PDQ_DEBUG) debug(p, "Entering"); for (c = 0; c < streams; c++) { sumR[c] = 0.0; Dsat = 0.0; // Fix submitted by James Newsom, 23 Feb 2011 //Otherwise, stream index can be compared to wrong (old) device index X = job[c].trans->arrival_rate; // find bottleneck node (== largest service demand) for (k = 0; k < nodes; k++) { // Hope to remove single class restriction eventually if (node[k].sched == MSQ && streams > 1) { sprintf(s1, "Only single PDQ stream allowed with MSQ nodes."); errmsg(p, s1); } Ddev = node[k].demand[c]; if (node[k].sched == MSQ) { // multiserver case m = node[k].devtype; // contains number of servers > 0 Ddev /= m; } if (Ddev > Dsat) { Dsat = Ddev; //Since we're about to fall out this k-loop //keep device name in case of error msg sprintf(satname, "%s", node[k].devname); } } // end of k-loop Xsat = 1.0 / Dsat; job[c].trans->saturation_rate = Xsat; if (Dsat == 0) { sprintf(s1, "Dsat = %3.3f", Dsat); errmsg(p, s1); } if (X > Xsat) { getjob_name(jobname, c); sprintf(s1, "\nArrival rate %3.3f for stream \'%s\' exceeds saturation thruput %3.3f of node \'%s\' with demand %3.3f", X, jobname, Xsat, satname, Dsat ); errmsg(p, s1); } for (k = 0; k < nodes; k++) { node[k].utiliz[c] = X * node[k].demand[c]; if (node[k].sched == MSQ) { // multiserver case m = node[k].devtype; // recompute m in every k-loop node[k].utiliz[c] /= m; // per server } devU = sumU(k); // sum all workload classes if (devU > 1.0) { sprintf(s1, "\nTotal utilization of node \"%s\" is %2.2f%% (> 100%%)", node[k].devname, devU * 100 ); errmsg(p, s1); } if (PDQ_DEBUG) printf("Tot Util: %3.4f for %s\n", devU, node[k].devname); switch (node[k].sched) { case FCFS: case PSHR: case LCFS: node[k].resit[c] = node[k].demand[c] / (1.0 - devU); node[k].qsize[c] = X * node[k].resit[c]; break; case MSQ: // Added by NJG on Mon, Apr 2, 2007 node[k].resit[c] = ErlangR(X, node[k].demand[c], m); node[k].qsize[c] = X * node[k].resit[c]; break; case ISRV: node[k].resit[c] = node[k].demand[c]; node[k].qsize[c] = node[k].utiliz[c]; break; default: typetostr(s1, node[k].sched); sprintf(s2, "Unknown queue type: %s", s1); errmsg(p, s2); break; } sumR[c] += node[k].resit[c]; } // end of k-loop job[c].trans->sys->thruput = X; // system throughput job[c].trans->sys->response = sumR[c]; // system response time job[c].trans->sys->residency = X * sumR[c]; // total number in system if (PDQ_DEBUG) { getjob_name(jobname, c); printf("\tX[%s]: %3.4f\n", jobname, job[c].trans->sys->thruput); printf("\tR[%s]: %3.4f\n", jobname, job[c].trans->sys->response); printf("\tN[%s]: %3.4f\n", jobname, job[c].trans->sys->residency); } } // end of c-loop if (PDQ_DEBUG) debug(p, "Exiting"); } // canonical
int main(int argc, char *argv[]){ int err; int i, j, k; char err_msg[ME_ERROR_MSG_MAX_COUNT] = {0}; char description[ME_DEVICE_DESCRIPTION_MAX_COUNT] = {0}; char name_device[ME_DEVICE_NAME_MAX_COUNT] = {0}; char name_driver[ME_DEVICE_DRIVER_NAME_MAX_COUNT] = {0}; int d_version; int l_version; int n_devices; int n_subdevices; int n_channels; int n_ranges; int unit; double min; double max; int max_data; int type; int subtype; //Initialization of ME-iDS err = meOpen(ME_OPEN_NO_FLAGS); if (err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meOpen(): %s\n", err_msg); return 1; } //Get library version err = meQueryVersionLibrary(&l_version); if (err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryLibraryVersion(): %s\n", err_msg); return 1; } printf("Library version is 0x%X\n", l_version); //Get number of registered devices err = meQueryNumberDevices(&n_devices); if (err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberDevices(): %s\n", err_msg); return 1; } if (n_devices >0) { //Get main driver version err = meQueryVersionMainDriver(&d_version); if (err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDriverVersion(): %s\n", err_msg); return 1; } printf("Main driver version is 0x%X\n", d_version); } printf("%d devices detected by driver system\n", n_devices); for(i = 0; i < n_devices; i++) { // For each device get: // - device name // - device description // - driver name // - driver version // - number sub-devices printf("\n"); printf("Device %d:\n", i); printf("=========\n"); err = meQueryNameDevice(i, name_device, sizeof(name_device)); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDeviceName(): %s\n", err_msg); return 1; } printf("Device name is %s\n", name_device); err = meQueryNameDeviceDriver(i, name_driver, sizeof(name_driver)); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNameDeviceDriver(): %s\n", err_msg); return 1; } printf("Driver name is %s\n", name_driver); err = meQueryDescriptionDevice(i, description, sizeof(description)); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDescriptionDevice(): %s\n", err_msg); return 1; } printf("Device description: %s\n", description); err = meQueryVersionDeviceDriver(i, &d_version); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDriverName(): %s\n", err_msg); return 1; } printf("Device driver version is 0x%X\n", d_version); err = meQueryNumberSubdevices(i, &n_subdevices); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberSubdevices(): %s\n", err_msg); return 1; } printf("%d subdevices available:\n", n_subdevices); for(j = 0; j < n_subdevices; j++) { // For each sub-device get: // - type // - sub-type err = meQuerySubdeviceType(i, j, &type, &subtype); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQuerySubdeviceType(): %s\n", err_msg); return 1; } printf("\tSubdevice %d is of type %s (0x%X) and subtype %s (0x%X)\n", j, typetostr(type), type , subtypetostr(subtype), subtype); err = meQueryNumberChannels(i, j, &n_channels); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberChannels(): %s\n", err_msg); return 1; } printf("\t\tSubdevice %d has %d channels\n", j, n_channels); if (type == ME_TYPE_AI || type == ME_TYPE_AO) { //For AI and AO sub-device get number ranges err = meQueryNumberRanges(i, j, ME_UNIT_ANY, &n_ranges); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberRanges(): %s\n", err_msg); return 1; } printf("\t\t\tSubdevice %d has %d ranges:\n", j, n_ranges); for(k = 0; k < n_ranges; k++) { err = meQueryRangeInfo( i, j, k, &unit, &min, &max, &max_data); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberRanges(): %s\n", err_msg); return 1; } printf("\t\t\t\tRange %d: Unit = 0x%X, Min = %lf, Max = %lf, Max Data = %d\n", k, unit, min, max, max_data); } } } } //Close ME-iDS err = meClose(ME_CLOSE_NO_FLAGS); if (err) { meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meClose(): %s\n", err_msg); return 1; } return 0; }
int main(int argc, char *argv[]){ int err; int i, j, k; char err_msg[ME_ERROR_MSG_MAX_COUNT] = {0}; char description[ME_DEVICE_DESCRIPTION_MAX_COUNT] = {0}; char name_device[ME_DEVICE_NAME_MAX_COUNT] = {0}; char name_driver[ME_DEVICE_DRIVER_NAME_MAX_COUNT] = {0}; int d_version; int l_version; int n_devices; int n_subdevices; int n_channels; int n_ranges; int unit; double min; double max; int max_data; int type; int subtype; ///@NOTE Due to internal synchronization delays timeouts shorter than 150ms can generate ambiguous response. int timeout = 200; SetMeRemoteDetectionTimeout(timeout); err = meOpen(0); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meOpen(): %s\n", err_msg); return 1; } err = meQueryVersionLibrary(&l_version); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryLibraryVersion(): %s\n", err_msg); return 1; } printf("Library version is 0x%X\n", l_version); err = meQueryNumberDevices(&n_devices); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberDevices(): %s\n", err_msg); return 1; } if (n_devices >0) { err = meQueryVersionMainDriver(&d_version); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDriverVersion(): %s\n", err_msg); return 1; } printf("Main driver version is 0x%X\n", d_version); } printf("%d devices detected by driver system\n", n_devices); for(i = 0; i < n_devices; i++){ printf("\n"); printf("Device %d:\n", i); printf("=========\n"); err = meQueryNameDevice(i, name_device, sizeof(name_device)); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDeviceName(): %s\n", err_msg); return 1; } printf("Device name is %s\n", name_device); err = meQueryNameDeviceDriver(i, name_driver, sizeof(name_driver)); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNameDeviceDriver(): %s\n", err_msg); return 1; } printf("Driver name is %s\n", name_driver); err = meQueryDescriptionDevice(i, description, sizeof(description)); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDescriptionDevice(): %s\n", err_msg); return 1; } printf("Device description: %s\n", description); err = meQueryVersionDeviceDriver(i, &d_version); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryDriverName(): %s\n", err_msg); return 1; } printf("Device driver version is 0x%X\n", d_version); err = meQueryNumberSubdevices(i, &n_subdevices); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberSubdevices(): %s\n", err_msg); return 1; } printf("%d subdevices available:\n", n_subdevices); for(j = 0; j < n_subdevices; j++){ err = meQuerySubdeviceType(i, j, &type, &subtype); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQuerySubdeviceType(): %s\n", err_msg); return 1; } printf("\tSubdevice %d is of type %s (0x%X) and subtype %s (0x%X)\n", j, typetostr(type), type , subtypetostr(subtype), subtype); err = meQueryNumberChannels(i, j, &n_channels); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberChannels(): %s\n", err_msg); return 1; } printf("\t\tSubdevice %d has %d channels\n", j, n_channels); if(type == ME_TYPE_AI || type == ME_TYPE_AO){ err = meQueryNumberRanges(i, j, ME_UNIT_ANY, &n_ranges); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberRanges(): %s\n", err_msg); return 1; } printf("\t\t\tSubdevice %d has %d ranges:\n", j, n_ranges); for(k = 0; k < n_ranges; k++){ err = meQueryRangeInfo( i, j, k, &unit, &min, &max, &max_data); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meQueryNumberRanges(): %s\n", err_msg); return 1; } printf("\t\t\t\tRange %d: Unit = 0x%X, Min = %lf, Max = %lf, Max Data = %d\n", k, unit, min, max, max_data); } } } } err = meClose(0); if(err){ meErrorGetMessage(err, err_msg, sizeof(err_msg)); fprintf(stderr, "In meClose(): %s\n", err_msg); return 1; } return 0; }