/* Rev. 24-Dec-2020 This version is to read the HP 3490A DVM in a loop and write the Measurement data to the screen and to a file. Each "measurement" that is displayed on the screen and written to the output file consists of: - the average DC value from N DVM Samples - the AC RMS Noise based on N DVM Samples - the time - the number of errors detected in making this measurement - the Measurement Number starting from 1 The information that is sent to the screen includes details about each Sample that is read from the DVM. Typically many Samples (perhaps 10 to 100) are averaged to make a Measurement. The Output File contains a Header, all of the Measurement Data, and a Trailer. The Serial Number of the ft245r in HP-3490A 1637 is: FTC8MGZF typically used for Current The Serial Number of the ft245r in HP-3490A 1529 is: FTC8MH7K typically used for Voltage Recall that the FTD library is in: /usr/local/lib/libftd2xx.a and we need the header files: ftd2xx.h and WinTypes.h */ #include #include #include #include #include #include #include "ftd2xx.h" #define MAXLINE 80 int main() { /* Declare the variables and structures in this program. */ char ft_dev_SN[20]; // ft245r device USB serial number unsigned char ReadBuffer[256]; DWORD dwRxSize = 0; DWORD dwBytesPerFrame = 8; DWORD dwBytesRead; FT_STATUS ftStatus; FT_HANDLE ftHandle; int queueChecks = 0; int check_for_error = 0; int usb_reset_counts = 0; int dvm_data_frame_errors = 0; int dvm_read_attempts = 0; int wait_between_measurements = 100; // finish one until start next in seconds long int timeout = 5; // timeout in seconds struct timeval run_start_time; // start of this data collection run struct timeval start_time; // start of the Queue Check Timeout struct timeval now_time; struct timeval elapsed_time; int Loops_to_Make = 1; // Number of Measurements to record. int Loop_Index = 1; // Index Number of the Measurement being made now int Sample_Index = 1; // Index of DVM Samples per Measurement int Number_of_Samples_Collected = 0; int Number_of_Samples_per_Measurement = 10; // i.e. DVM Samples per Measurement int Temp_Index = 1; // Temporary Loop Index double This_DVM_Reading = 0.0; double DVM_Reads[50005]; // Maximum number of Samples per Measurement. int SN_of_DVM; // Serial Number of the DVM 1529 or 1637. char output_filename[MAXLINE]; FILE *fpout; // Pointer to the Output File time_t current_time; // arithmetic time type - time since the epoch char* c_time_string; double This_DC_Measurement = 0.0; // The DC value of the current Measurement double This_RMS_Measurement = 0.0; // The RMS value of the current Measurement double *pt_This_DC_Measurement; // Pointer to This_DC_Measurement double *pt_This_RMS_Measurement; // Pointer to This_RMS_Measurement double DC_Measurements_Array[1005]; // The array that holds the DC Measurements double RMS_Measurements_Array[1005]; // The array that holds the RMS Measurements double total_sum = 0.0; // Temporary working double float location double avg_of_sum = 0.0; // Temporary working double float location /* Declare the functions that are called by this program. */ int dumpBuffer(unsigned char *buffer, int elements); double Volts_from_Buffer(unsigned char *buffer); int Check_DVM_Frame(unsigned char *buffer); int min_max_locate(double *DVM_Reads, int Number_of_Samples_per_Measurement); int calc_DC_and_RMSs(double *DVM_Reads, int Number_of_Samples_per_Measurement, double *pt_This_DC_Measurement, double *pt_This_RMS_Measurement); /*==================================================================*/ /* */ /* First do all of the things that we will do only once before */ /* starting the loop over the number of Measurements to be taken. */ /* */ /*==================================================================*/ /* Set the value of the Pointers to the variables that */ /* will hold the Current DC and RMS Measurements */ pt_This_DC_Measurement = &This_DC_Measurement; pt_This_RMS_Measurement = &This_RMS_Measurement; /* Ask the operator Which DVM is this run is going to read */ printf("\n\n"); printf(" Enter the Serial Number of the DVM (1529 or \n"); printf(" 1637) that this run of the program will record: "); scanf( "%d", &SN_of_DVM ); printf("\n"); if (SN_of_DVM == 1529) { ft_dev_SN[0] = 'F'; ft_dev_SN[1] = 'T'; ft_dev_SN[2] = 'C'; ft_dev_SN[3] = '8'; ft_dev_SN[4] = 'M'; ft_dev_SN[5] = 'H'; ft_dev_SN[6] = '7'; ft_dev_SN[7] = 'K'; ft_dev_SN[8] = '\0'; } else if (SN_of_DVM == 1637) { ft_dev_SN[0] = 'F'; ft_dev_SN[1] = 'T'; ft_dev_SN[2] = 'C'; ft_dev_SN[3] = '8'; ft_dev_SN[4] = 'M'; ft_dev_SN[5] = 'G'; ft_dev_SN[6] = 'Z'; ft_dev_SN[7] = 'F'; ft_dev_SN[8] = '\0'; } else { printf("\n This is an unknown DVM Serial Number - Exiting \n"); exit(2); } /* Ask the operator how many Measurements to make and record. */ printf(" Enter the number Measurements \n"); printf(" to make and record in the output file: "); scanf( "%d", &Loops_to_Make ); printf("\n"); /* Ask the operator how many DVM Samples to average per Measurement. */ printf(" Enter the number of DVM Samples \n"); printf(" to average per recorded Measurement. \n"); printf(" 50k is max. Typically 1 Sample per second: "); scanf( "%d", &Number_of_Samples_per_Measurement ); printf("\n"); /* Ask the operator how long to wait between Measurements */ printf(" Enter the number of seconds to wait between \n"); printf(" finishing one Measurement and starting the next: "); scanf( "%d", &wait_between_measurements ); printf("\n"); /* Ask the operator the filename for the Measurement output file */ printf(" Enter the filename for the \n"); printf(" Measurement output text file: "); scanf( "%s", output_filename ); printf("\n"); if ((fpout = fopen(output_filename, "w")) == NULL) { printf("\nERROR: Can't open output file %s\n", output_filename); exit (2); } /* Zero the arrays that holds the DC & RMS Measurements. */ Temp_Index = 0; while (Temp_Index <= 1003) { DC_Measurements_Array[Temp_Index] = 0.0; RMS_Measurements_Array[Temp_Index] = 0.0; ++Temp_Index; } Temp_Index = 0; printf("\n The DC & RMS Measurement Arrays have been zeroed. \n\n"); /* Obtain current time - for screen display and the output file header */ /* The time(NULL) function returns current system time as a time_t value */ current_time = time(NULL); if (current_time == ((time_t)-1)) { (void) fprintf(stderr, "Failure to obtain the current time.\n"); exit(EXIT_FAILURE); } /* Convert to local time format as a character string. */ /* The c_time() function converts a time_t value to a textual representation */ c_time_string = ctime(¤t_time); if (c_time_string == NULL) { (void) fprintf(stderr, "Failure to convert the current time.\n"); exit(EXIT_FAILURE); } /* Print to stdout. ctime() has already added a terminating newline */ /* character and put this time-stamp in the output file. */ printf("\n\n Current time is %s", c_time_string); /* Write a Header into the Output File so that we */ /* know the Conditions under which this Run was taken. */ fprintf(fpout, "\n\n Current time is %s", c_time_string); fprintf(fpout, "\n This is a run of %d Measurements", Loops_to_Make ); fprintf(fpout, "\n Number of Samples per Measurement is %d", Number_of_Samples_per_Measurement ); fprintf(fpout, "\n The number of seconds between Measurements is %d \n\n", wait_between_measurements ); /*================================================================================*/ /* */ /* Now start the loop over the number of Measurements to be made and recorded */ /* */ /*================================================================================*/ Loop_Index = 1; while ( Loop_Index <= Loops_to_Make ) { /* Zero the array that holds the DVM Samples. */ Sample_Index = 0; while (Sample_Index <= 50000) { DVM_Reads[Sample_Index] = 0.0; ++Sample_Index; } Sample_Index = 1; printf("\n The DVM Sample Storage Array has been zeroed. \n\n"); /* Advertize the USB Serial Number of the DVM's ft245r interface. */ printf("\n The USB Serial Number of the DVM's FT245R is - %s\n", ft_dev_SN); /* Open the ft245r device with the serial number = ft_dev_SN. */ /* Note that we will Open the ft245r interface at the */ /* beginning of each Measurement and then Close it after all */ /* of the DVM Samples have been collected for that Measurement. */ if((ftStatus = FT_OpenEx(ft_dev_SN, FT_OPEN_BY_SERIAL_NUMBER, &ftHandle)) != FT_OK){ /* This can fail if the ftdi_sio driver is loaded use lsmod to check this and rmmod ftdi_sio to remove also rmmod usbserial */ printf("Error FT_OpenEx(%d)\n", (int)ftStatus); printf("Use lsmod to check if ftdi_sio (and usbserial) are present.\n"); printf("Unload them using rmmod ftdi_sio as they conflict with ftd2xx.\n"); return 1; } printf(" Opened USB Device - %s\n\n", ft_dev_SN); /* Get the time at the start of this DVM data collection run. */ gettimeofday(&run_start_time, NULL); /* Start the loop that collects the Required Number of DVM Samples */ while (Sample_Index <= Number_of_Samples_per_Measurement) { printf("\n\n Starting Read Sample Number = %d\n\n", Sample_Index); /* Check the ft245 Queue Status and wait for 8 bytes */ /* of read data. Give up if this takes too long. */ Restart_Queue_Check: dwRxSize = 0; gettimeofday(&start_time, NULL); for (queueChecks = 1; dwRxSize < dwBytesPerFrame; queueChecks++) { /* Delay for 100 msec before the First check of the */ /* Queue Status and between checks of Queue Status. */ usleep(100000); ftStatus = FT_GetQueueStatus(ftHandle, &dwRxSize); if (ftStatus != FT_OK) { printf("\nFT_GetQueueStatus failed (%d).\n", (int)ftStatus); return 1; } /* Check for time-out in getting data as shown by Queue Status. */ gettimeofday(&now_time, NULL); timersub(&now_time, &start_time, &elapsed_time); if (elapsed_time.tv_sec > timeout) { /* We've waited too long. Give up. */ printf("\n\07 Queue check timed out after %ld seconds\n", elapsed_time.tv_sec); printf(" queue check count = %d \n\n", queueChecks); printf(" Bytes in Read FIFO reported by Queue Check = %d \n\n", dwRxSize); printf(" Try Close - Open the ft245r and then checking the Queue again.\n\n"); FT_Close(ftHandle); sleep(1); ftStatus = FT_OpenEx(ft_dev_SN, FT_OPEN_BY_SERIAL_NUMBER, &ftHandle); if (ftStatus != FT_OK) { printf("\n Queue error recovery by FT_Open failed - exiting now.\n\n"); return 1; } printf(" FT Close-Open has been done - Restart the Check Queue loop.\n\n"); ++usb_reset_counts; // Increment the counter of USB Resets. goto Restart_Queue_Check; } } printf(" queue check count = %d \n\n", queueChecks); /* If we get here then the above Queue Status test has */ /* derermined that there are 8 bytes in the Read Queue. */ if(ftStatus == FT_OK) { ftStatus = FT_Read(ftHandle, ReadBuffer, dwRxSize, &dwBytesRead); if (ftStatus != FT_OK) { printf("Error FT_Read(%d)\n", (int)ftStatus); return 1; } if (dwBytesRead != dwRxSize) { printf("FT_Read only read %d (of %d) bytes\n", (int)dwBytesRead, (int)dwRxSize); return 1; } ++dvm_read_attempts; printf(" FT_Read read %d bytes. Read-buffer currently holds:\n\n", (int)dwBytesRead); dumpBuffer(ReadBuffer, (int)dwBytesRead); check_for_error = Check_DVM_Frame(ReadBuffer); if (check_for_error != 0) { ++dvm_data_frame_errors; } This_DVM_Reading = Volts_from_Buffer(ReadBuffer); if (check_for_error == 0) { DVM_Reads[Sample_Index] = This_DVM_Reading; ++Sample_Index; } } } /*==============================================================*/ /* */ /* The required number of DVM Samples have been collected. */ /* Now call the Analysis Functions */ /* */ /* Note that I'm passing to the analysis routines the */ /* actual number of Samples that were collected (not the */ /* desired number that we would like to collect). */ /* */ /* Before calling the analysis routines first report */ /* how long this run actually took in seconds and how */ /* many DVM Samples were actually collected */ /* */ /* Once we have received the DC and RMS values for this */ /* Measurement from the analysis routines: write them */ /* to the Output File and store them in the arrays that */ /* hold all of the DC and RMS Measurements from this run. */ /* */ /*==============================================================*/ gettimeofday(&now_time, NULL); timersub(&now_time, &run_start_time, &elapsed_time); printf("\n This DVM data collection run took %ld seconds\n", elapsed_time.tv_sec); Number_of_Samples_Collected = --Sample_Index; printf(" Number of DVM Samples actually collected = %d \n", Number_of_Samples_Collected); printf(" Number of DVM read attempts = %d \n", dvm_read_attempts ); printf(" Number of DVM Data Frame Errors = %d \n", dvm_data_frame_errors ); printf(" Number of USB Resets = %d \n", usb_reset_counts ); /* Now call the Analysis Routines */ min_max_locate(DVM_Reads, Number_of_Samples_Collected); calc_DC_and_RMSs(DVM_Reads, Number_of_Samples_Collected, pt_This_DC_Measurement, pt_This_RMS_Measurement); /* Now write to the Output File: This Measurement's Loop Index, */ /* This Measurement's DC Value, */ /* and This Measurement's AC RMS Value */ fprintf(fpout, "\n Measurement Loop = %4d", Loop_Index ); fprintf(fpout, " Average DC Value = %8.5f AC RMS = %8.5f", This_DC_Measurement, This_RMS_Measurement ); /* Store the values for the current Measurement in the arrays */ /* that hold all of the DC and RMS Measurements for this run. */ DC_Measurements_Array[Loop_Index] = This_DC_Measurement; RMS_Measurements_Array[Loop_Index] = This_RMS_Measurement; printf(" This completes Measurement Loop Number = %d \n", Loop_Index ); /*==============================================================*/ /* */ /* We have finished a Measurement, Close the ft245r USB */ /* connection. If this is NOT the last Measurement then */ /* Wait for the time between Measurements, and then */ /* Increment the Loop_Index and go back to the top of the */ /* loop over all Measurements. */ /* */ /*==============================================================*/ FT_Close(ftHandle); printf(" Closed USB Device - %s\n\n", ft_dev_SN); if (Loop_Index < Loops_to_Make) { sleep(wait_between_measurements); } ++Loop_Index; /* and back up to the Measurement */ /* Loops_to_Make While statement. */ } /*==============================================================*/ /* */ /* We reach here after ALL of the Measurements have been */ /* made and recorded. */ /* */ /* Calculate the Average of All of the DC Measurements and */ /* the Average of All of the RMS Measurements in this run */ /* and print these values on the screen and write them into */ /* the Output File. then */ /* */ /* Write a Trailer to the Output File and then */ /* cleanup before exiting. */ /* */ /*==============================================================*/ /* Calculate the Average of ALL of the DC and RMS Measurements */ printf(" \n\n All Measurements have now been made and recorded. \n"); fprintf(fpout," \n\n All Measurements have now been made and recorded. \n"); Temp_Index = 1; total_sum = 0.0; while (Temp_Index <= Loops_to_Make) { total_sum = total_sum + DC_Measurements_Array[Temp_Index]; ++Temp_Index; } avg_of_sum = total_sum / Loops_to_Make; printf("\n The average of All the DC Measurements = %8.5f", avg_of_sum); fprintf(fpout, "\n The average of All the DC Measurements = %8.5f", avg_of_sum); Temp_Index = 1; total_sum = 0.0; while (Temp_Index <= Loops_to_Make) { total_sum = total_sum + RMS_Measurements_Array[Temp_Index]; ++Temp_Index; } avg_of_sum = total_sum / Loops_to_Make; printf("\n The average of All the RMS Measurements = %8.5f", avg_of_sum); fprintf(fpout, "\n The average of All the RMS Measurements = %8.5f", avg_of_sum); /* Write the Trailer to the Output File */ fprintf(fpout," \n\n Trailer written at the end of the Output File. \n"); fprintf(fpout," Number of DVM Samples collected for the final Measurement = %d \n", Number_of_Samples_Collected); fprintf(fpout," Total Number of DVM Read attempts for all Measurements = %d \n", dvm_read_attempts ); fprintf(fpout," Total Number of DVM Data Frame Errors for all Measurements = %d \n", dvm_data_frame_errors ); fprintf(fpout," Total Number of USB Resets for all Measurements = %d \n", usb_reset_counts ); /* Obtain Current Time and add a Final Time-Stamp */ /* at the End of the Output File and on the Screen */ current_time = time(NULL); if (current_time == ((time_t)-1)) { (void) fprintf(stderr, "Failure to obtain the current time.\n"); exit(EXIT_FAILURE); } c_time_string = ctime(¤t_time); if (c_time_string == NULL) { (void) fprintf(stderr, "Failure to convert the current time.\n"); exit(EXIT_FAILURE); } fprintf(fpout, "\n\n Current time is %s \n\n", c_time_string); printf("\n\n Current time is %s", c_time_string); /* The Output File Trailer is complete - Close the Output File */ fclose(fpout); printf(" Closed the Output File - %s \n\n", output_filename); return 0; /* This ends the main function */ }