/* ************************************************************** */ /* * Module PDI5025 * This module contains I/O functions for the Metrolab precision * digital integrator model 5025. * * Zachary Wolf * 8/29/98 */ /* ************************************************************** */ /* INCLUDES */ #include #include #include #include #include "pdi5025.h" /* ************************************************************** */ /* PRIVATE FUNCTIONS */ int pdi5025_open_dev(int gpib_board_addr, int gpib_dev_addr); void pdi5025_close_dev(int dev_ID); int pdi5025_check_dev_open(int dev_ID); int pdi5025_out(int dev_ID, char* buf); int pdi5025_in(int dev_ID, char* buf); int pdi5025_in_block(int dev_ID, int num_samp, double vt[]); int pdi5025_get_errors(int dev_ID); void pdi5025_get_status(int dev_ID, int reg, char* status); int pdi5025_hold_until_end_of_run_and_data_ready(int dev_ID); void pdi5025_hold_until_data_ready(int dev_ID); void pdi5025_hold_until_end_of_run(int dev_ID); int pdi5025_serial_poll(int dev_ID, int* spoll); void pdi5025_message(char* msg); void pdi5025_error(char* msg); void pdi5025_generate_samples(char rot_dir, int num_samp_per_rev, int num_samp, double vt[]); /* ************************************************************** */ /* PRIVATE DEVICE TABLE */ /* * This table allows several devices of the same type to be * used in the system. * dev_addr, contains the GPIB addresses of opened devices * dev_descr, contains the device descriptors of opened devices * dev_count, contains the number of devices open of this type */ static int dev_addr[PDI5025_MAX_NUM_DEV + 1]; static int dev_descr[PDI5025_MAX_NUM_DEV + 1]; static int dev_count; /* ************************************************************** */ /* PRIVATE GLOBAL VARIABLES */ /* * cmd, buffer for GPIB I/O strings * msg, buffer for message strings to Standard I/O */ static char cmd[PDI5025_MAX_CMD + 1]; static char msg[PDI5025_MAX_CMD + 1]; static int num_encoder_pulse_per_rev; /* ************************************************************** */ /* PUBLIC FUNCTIONS */ /* ************************************************************** */ /* * pdi5025_init * This function opens the device, queries for ID, and * initializes the device to a known state. * * Input: * gpib_board_addr, address of the GPIB board the device is connected to (0, 1, ...) * gpib_dev_addr, GPIB address of the device (1 to 30, 0 is reserved) * * Output: * ID, identifier for future references to the device * * Zachary Wolf * 8/29/98 */ void pdi5025_init(int gpib_board_addr, int gpib_dev_addr, int* ID) { /* Declare variables */ int dev_ID; int err; int i; /* Message */ pdi5025_message(""); pdi5025_message("Initializing the PDI5025..."); /* Check input parameters */ if (gpib_board_addr < 0 || gpib_board_addr > 10) { Fmt(msg, "%s 30) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 30.) { Fmt(msg, "%s 5000) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 30.) { Fmt(msg, "%s 5000) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 5000) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 30000) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s num_encoder_pulse_per_rev) { Fmt(msg, "%s 5000) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 1) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 8388608) { Fmt(msg, "%s 10000) { Fmt(msg, "%s 5000) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 8388608) { Fmt(msg, "%s 10000) { Fmt(msg, "%s 5000) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 5000) { Fmt(msg, "%s= 0; i--) vt[i] = vt[i] - vt[0]; if (fmod((double)num_call, 2.) < .2) { for (i = 0; i <= num_samp; i++) temp[i] = vt[i]; for (i = 0; i <= num_samp; i++) vt[i] = temp[num_samp - i]; for (i = num_samp; i >= 0; i--) vt[i] = vt[i] - vt[0]; } return; #endif /* Check to make sure the device is open */ dev_open = pdi5025_check_dev_open(dev_ID); if (dev_open == 0) { pdi5025_error("Instrument not open"); return; } /* Wait until the measurement is finished and the PDI is done processing the data */ err = pdi5025_hold_until_end_of_run_and_data_ready(dev_ID); if (err != 0) { for (i = 0; i <= num_samp; i++) vt[i] = 0.; return; } /* Read the measurements */ err = pdi5025_in_block(dev_ID, num_samp, vt); if (err != 0) { pdi5025_error("Problem getting VT samples"); for (i = 0; i <= num_samp; i++) vt[i] = 0.; return; } /* Check for errors */ err = pdi5025_get_errors(dev_ID); if (err != 0) { pdi5025_error("Problem with PDI5025"); for (i = 0; i <= num_samp; i++) vt[i] = 0.; return; } /* Done */ return; } /* ************************************************************** */ /* * pdi5025_locate_index * This function has the PDI5025 locate the encoder index pulse. * The motor must be turning the encoder for this function to work. * * Input: * dev_ID, device identifier * * Output: * index, 1 if found index pulse, 0 otherwise * * Zachary Wolf * 9/3/98 */ int pdi5025_locate_index(int dev_ID) { /* Declare variables */ int dev_open; char status[PDI5025_MAX_CMD]; enum {TRUE, FALSE} have_index; int num_tries = 0; int index; /* Check input parameters */ if (dev_ID < 1 || dev_ID > PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 30) pdi5025_error("Having trouble finding index pulse"); } /* Done */ return index; } /* ************************************************************** */ /* * pdi5025_set_gain * This function sets the gain of the integrator. * * Input: * dev_ID, device identifier * chan, integrator channel, A or B * gain, input amplifier gain, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 * * Zachary Wolf * 9/3/98 */ void pdi5025_set_gain(int dev_ID, char chan, int gain) { /* Declare variables */ int dev_open; int err; /* Check input parameters */ if (dev_ID < 1 || dev_ID > PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s%i", count); *count = *count / 4; /* Check for errors */ pdi5025_get_errors(dev_ID); /* Done */ return; } /* ************************************************************** */ /* * pdi5025_exit * This function puts the PDI5025 in the desired state for exit * and closes the device. * * Input: * dev_ID, device identifier * * Zachary Wolf * 8/23/98 */ void pdi5025_exit(int dev_ID) { /* Declare variables */ int dev_open; /* Check input parameters */ if (dev_ID < 1 || dev_ID > PDI5025_MAX_NUM_DEV) { Fmt(msg, "%s 10) { Fmt(msg, "%s 30) { Fmt(msg, "%s 0) { return 1; /* Open */ } else { return 0; /* Not open */ } } /* ************************************************************** */ /* * pdi5025_out * This function writes a buffer of data to the device. * * Input: * dev_ID, device identifier * buf, null terminated string, the contents up to \0 are sent * * Output: * err, 0 if ok, -1 otherwise * * Zachary Wolf * 8/29/98 */ int pdi5025_out(int dev_ID, char* buf) { /* Declare variables */ char out_buf[PDI5025_MAX_CMD]; int nbytes; int err; /* Add CR LF to the command */ Fmt(out_buf, "%s<%s%c%c", buf, 13, 10); /* Send the command */ nbytes = StringLength(out_buf); err = ibwrt(dev_descr[dev_ID], out_buf, (long)nbytes); /* Check for errors */ if (err & 0x8000) { Fmt(msg, "%s%s[t-]", buf); /* Done */ return 0; } /* ************************************************************** */ /* * pdi5025_in_block * This function reads a block of data from the integrator and puts * the measured values in an array. * * Input: * dev_ID, device identifier * num_samp, number of samples expected (error if we don't get this number) * * Output: * vt[], array of integrated voltage samples * err, 0 if ok, -1 otherwise * * Zachary Wolf * 8/23/98 */ int pdi5025_in_block(int dev_ID, int num_samp, double vt[]) { /* Declare variables */ int err; char in_buf[60000]; /* Accept up to 5000 samples * 12 (10 + CR LF) bytes per sample */ char samp_buf[20]; int samp_index, buf_index; char in_char; int num_scan; double vt_val; char vt_chan; /* Temporarily set the end-of-string character to ctrl-Z (ASCII 26 or 1A hex) */ err = ibeos(dev_descr[dev_ID], 0x141A); if (err & 0x8000) { Fmt(msg, "%s 18) /* Protection */ { pdi5025_error("pdi5025_in_block, data buffer format error"); return -1; } if (in_char == 10) /* Sample ends on LF */ { samp_buf[samp_index] = 0; /* Null terminate string */ Scan(samp_buf, "%s[t13t00]>%f %c", &vt_val, &vt_chan); /* Read to CR, extract vt value */ num_scan++; /* Sample number read so far, starts at 1 */ vt[num_scan] = vt_val * 1.e-8; /* Scale vt value, put in array */ samp_index = 0; /* Prepare for next sample */ } } /* Check the number of samples */ if (num_scan != num_samp) { pdi5025_error("pdi5025_in_block, got wrong number of samples"); return -1; } /* Done */ return 0; } /* ************************************************************** */ /* * pdi5025_get_errors * This function obtains device errors. * The operator is alerted if there is an error. * * Input: * dev_ID, device identifier * * Output: * err, 0 if no errors, -1 otherwise * * Zachary Wolf * 8/29/98 */ int pdi5025_get_errors(int dev_ID) { /* Declare variables */ char status[PDI5025_MAX_CMD]; int err; /* Default return value, no error */ err = 0; /* Register 1 */ pdi5025_get_status(dev_ID, 1, status); /* Register 1, bit 5, position 2, command error */ if (status[2] == '1') { pdi5025_error("Command error"); err = -1; } /* Register 1, bit 4, position 3, overrange error */ if (status[3] == '1') { pdi5025_error("Overrange error"); err = -1; } /* Register 2 */ pdi5025_get_status(dev_ID, 2, status); /* Register 2, bit 3, position 4, autotest failed */ if (status[4] == '1') { pdi5025_error("Autotest failed"); err = -1; } /* Register 2, bit 2, position 5, encoder count error */ if (status[5] == '1') { pdi5025_error("Encoder count error"); err = -1; } /* Register 2, bit 1, position 6, data buffer full */ if (status[6] == '1') { pdi5025_error("Data buffer full"); err = -1; } /* Register 2, bit 0, position 7, trigger too fast */ if (status[7] == '1') { pdi5025_error("Trigger too fast error"); err = -1; } /* Register 4 */ pdi5025_get_status(dev_ID, 4, status); /* Register 4, bit 5, position 2, bit 4, position 3, bit 1, position 6, bit 0, position 7, overrange error */ if (status[2] == '1' || status[3] == '1' || status[6] == '1' || status[7] == '1') { pdi5025_error("Overrange error"); err = -1; } /* Register 5 */ pdi5025_get_status(dev_ID, 5, status); /* Register 5, bits 0 to 4 indicate errors */ if (status[3] == '1' || status[4] == '1' || status[5] == '1' || status[6] == '1' || status[7] == '1') { Fmt(msg, "%s%i", spoll); /* Debug */ /* printf("%i\n", *spoll); */ /* Done */ return 0; } /* ************************************************************** */ /* * pdi5025_get_status * This function gets the contents of a status register. * * Input: * dev_ID, device identifier * reg, register number * * Output: * status, contents of the status register * * Zachary Wolf * 8/31/98 */ void pdi5025_get_status(int dev_ID, int reg, char* status) { /* Declare variables */ char status_cmd[PDI5025_MAX_CMD]; /* Check the input parameters */ if (reg < 1 || reg > 7) { Fmt(status_cmd, "%s= 500) return 1; /* Assume problem after 100 seconds */ } /* Done */ return 0; } /* ************************************************************** */ /* * pdi5025_hold_until_data_ready * This function reads status register 1 in a loop until the * data ready bit is set. * * Input: * dev_ID, device identifier * * Zachary Wolf * 8/31/98 */ void pdi5025_hold_until_data_ready(int dev_ID) { /* Declare variables */ char status[PDI5025_MAX_CMD]; enum {TRUE, FALSE} busy; /* Loop while busy */ /* Check for errors in the status word */ busy = TRUE; while (busy == TRUE) { pdi5025_get_status(dev_ID, 1, status); if (status[5] == '1') { busy = FALSE; /* Data ready */ } else { busy = TRUE; /* Data not ready */ Delay(.1); } if (status[2] == '1') /* Register 1, bit 5, position 2, command error */ { pdi5025_error("Command error"); } if (status[3] == '1') /* Register 1, bit 4, position 3, overrange error */ { pdi5025_error("Overrange error"); } } /* Done */ return; } /* ************************************************************** */ /* * pdi5025_hold_until_end_of_run * This function reads status register 1 in a loop until the * end of run bit is set. * * Input: * dev_ID, device identifier * * Zachary Wolf * 9/1/98 */ void pdi5025_hold_until_end_of_run(int dev_ID) { /* Declare variables */ char status[PDI5025_MAX_CMD]; enum {TRUE, FALSE} busy; /* Loop while busy */ /* Check for errors in the status word */ busy = TRUE; while (busy == TRUE) { pdi5025_get_status(dev_ID, 1, status); if (status[4] == '1') { busy = FALSE; /* End of run */ } else { busy = TRUE; /* Run not finished */ Delay(.5); } if (status[2] == '1') /* Register 1, bit 5, position 2, command error */ { pdi5025_error("Command error"); } if (status[3] == '1') /* Register 1, bit 4, position 3, overrange error */ { pdi5025_error("Overrange error"); } } /* Done */ return; } /* ************************************************************** */ /* * pdi5025_message * This function handles messages about the PDI5025. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 8/3/98 */ void pdi5025_message(char* message) { /* Print the message */ printf("%s\n", message); /* Done */ return; } /* ************************************************************** */ /* * pdi5025_error * This function handles error messages for the PDI5025. * * Input: * message, string to display in standard I/O * * Zachary Wolf * 8/3/98 */ void pdi5025_error(char* message) { /* Declare variables */ char buf[80]; /* Notify the operator of the error */ printf("\nPDI5025 ERROR: %s\n", message); Beep(); Delay(.5); Beep(); /* Terminate the program if the operator desires */ printf("Press ENTER to continue.\nPress any key then ENTER to terminate program.\n"); fgets(buf, 80, stdin); if (buf[0] == '\n') return; else exit(0); } /* ************************************************************** */ /* * pdi5025_generate_samples * This function generates integrated voltage samples to use while * debugging software. * * Input: * rot_dir, rotation direction, + or - * num_samp_per_rev, number of integrated voltage samples per revolution * num_samp, number of integrated voltage samples * * Output: * vt[0 to n], vt[0] = 0, vt[1 to n] = n measured integrated voltage samples * * Zachary Wolf * 9/3/98 */ void pdi5025_generate_samples(char rot_dir, int num_samp_per_rev, int num_samp, double vt[]) { /* Declare variables */ int i; double pi = 3.1415927; double ramp_ampl; double* rev_vt; /* Message */ //pdi5025_message("Generating fake data for testing..."); /* Generate samples */ /* vt(t) = A_n * [cos(nwt + phi_n) - cos(phi_n)] , subtract constant so vt starts at 0 fft_n = A_n * e^(j phi_n) */ vt[0] = 0.; for (i = 1; i <= num_samp; i++) { vt[i] = 0.; vt[i] = vt[i] + 1. * (1. / 1.) * (cos(1. * 2. * 3.141593 * i / num_samp_per_rev - 1. * (-1. * pi / 1. - pi/18.) - pi / 2.) - cos( - 1. * (-1. * pi / 1. - pi/18.) - pi / 2.)); vt[i] = vt[i] + .2 * (1. / 2.) * (cos(2. * 2. * 3.141593 * i / num_samp_per_rev - 2. * (-1. * pi / 2. - pi/18.) - pi / 2.) - cos( - 2. * (-1. * pi / 2. - pi/18.) - pi / 2.)); vt[i] = vt[i] + .3 * (1. / 3.) * (cos(3. * 2. * 3.141593 * i / num_samp_per_rev - 3. * (-1. * pi / 3. - pi/18.) - pi / 2.) - cos( - 3. * (-1. * pi / 3. - pi/18.) - pi / 2.)); vt[i] = vt[i] + .4 * (1. / 4.) * (cos(4. * 2. * 3.141593 * i / num_samp_per_rev - 4. * (-1. * pi / 4. - pi/18.) - pi / 2.) - cos( - 4. * (-1. * pi / 4. - pi/18.) - pi / 2.)); } /* Reverse the vt array if the rotation direction is negative */ if (rot_dir == '-') { rev_vt = malloc((num_samp + 1) * sizeof(double)); for (i = 0; i <= num_samp; i++) rev_vt[i] = vt[num_samp - i]; for (i = 0; i <= num_samp; i++) vt[i] = rev_vt[i]; free(rev_vt); } /* Set parameters */ //ramp_ampl = .5; /* Add a ramp for integrator offset */ //for (i = 0; i <= num_samp; i++) //{ // vt[i] = vt[i] + i * ramp_ampl / num_samp; //} /* Add a bad point to test data-check function */ /* vt[10] = 5.; */ /* Done */ return; }