// ======================================================================================================== // ======================================================================================================== // ****************************************** verifier_common.c ******************************************* // ======================================================================================================== // ======================================================================================================== #include "common.h" #include "verifier_common.h" // ======================================================================================================== // ======================================================================================================== // Simply gets the acknowledgement string from labview that the operation was carried out. void GetAck(int max_string_len, int labview_socket_desc) { char ACK_str[max_string_len]; if ( SockGetB((unsigned char *)ACK_str, max_string_len, labview_socket_desc) < 0 ) { printf("ERROR: GetAck(): Error receiving ACK from labview!\n"); fflush(stdout); exit(EXIT_FAILURE); } // Labview writes a at end of string -- replace with NULL ACK_str[3] = '\0'; if ( strcmp(ACK_str, "ACK") != 0 ) { printf("ERROR: GetAck(): Expected ACK, received '%s'\n", ACK_str); fflush(stdout); exit(EXIT_FAILURE); } return; } // ======================================================================================================== // ======================================================================================================== // Issue labview commands to set the TV corner. void SetTVCorner(int max_string_len, int TV_num, int max_TVs, int temperatures[max_TVs], float currents_uAs[max_TVs], int labview_socket_desc, int do_2nd_SMU) { char command_str[max_string_len], response_str[max_string_len]; float present_curr_src, present_temperature; int iterations; // Set voltage. The Agilent power supply is used to change voltage on the Zedboard. It is configured as a current source and connected // to the Vfb pin on the MAXIM part (see README.jim). It is important to change the voltage SLOWLY by changing the current source value 1 uA // at a time and then waiting. This will prevent the Zedboard from resetting (we hope). Note that the Zedboard is spec'ed to +/- 5% only. // Get the current value of the current source. sprintf(command_str, "%s %s\n", InstrCoreSM0, CommandReadCurrentAmplitude); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } if ( SockGetB((unsigned char *)response_str, max_string_len, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Error receiving existing current setting!\n"); fflush(stdout); exit(EXIT_FAILURE); } sscanf(response_str, "%f", &present_curr_src); printf("Read current from SMU %f\n", present_curr_src); fflush(stdout); #ifdef DEBUG #endif // No more than 21 iterations are ever required. Never allow the value to get outside of -50-6 to -30e-6 // for ( iterations = 0; iterations < 41 && present_curr_src != currents_uAs[TV_num] && present_curr_src >= -110e-6 && present_curr_src <= -50e-6; iterations++ ) for ( iterations = 0; iterations < 21 && present_curr_src != currents_uAs[TV_num] && present_curr_src > -50e-6 && present_curr_src < -30e-6; iterations++ ) { if ( present_curr_src < currents_uAs[TV_num] ) sprintf(command_str, "%s %s %f\n", InstrCoreSM0, CommandSetCurrentAmplitude, present_curr_src + 1e-6); else sprintf(command_str, "%s %s %f\n", InstrCoreSM0, CommandSetCurrentAmplitude, present_curr_src - 1e-6); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } // Get acknowledgement GetAck(max_string_len, labview_socket_desc); usleep(100000); // usleep(500000); // Read set current. sprintf(command_str, "%s %s\n", InstrCoreSM0, CommandReadCurrentAmplitude); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } if ( SockGetB((unsigned char *)response_str, max_string_len, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Error receiving existing current setting!\n"); fflush(stdout); exit(EXIT_FAILURE); } sscanf(response_str, "%f", &present_curr_src); usleep(100000); // usleep(500000); } // Do the same for the Keithley if ( do_2nd_SMU == 1 ) { sprintf(command_str, "%s %s\n", InstrCoreSM1, CommandReadCurrentAmplitude); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } if ( SockGetB((unsigned char *)response_str, max_string_len, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Error receiving existing current setting!\n"); fflush(stdout); exit(EXIT_FAILURE); } sscanf(response_str, "%f", &present_curr_src); // No more than 21 iterations are ever required. Never allow the value to get outside of -50e-6 to -30e-6 // for ( iterations = 0; iterations < 41 && present_curr_src != currents_uAs[TV_num] && present_curr_src >= -110e-6 && present_curr_src <= -50e-6; iterations++ ) for ( iterations = 0; iterations < 21 && present_curr_src != currents_uAs[TV_num] && present_curr_src > -50e-6 && present_curr_src < -30e-6; iterations++ ) { if ( present_curr_src < currents_uAs[TV_num] ) sprintf(command_str, "%s %s %f\n", InstrCoreSM1, CommandSetCurrentAmplitude, present_curr_src + 1e-6); else sprintf(command_str, "%s %s %f\n", InstrCoreSM1, CommandSetCurrentAmplitude, present_curr_src - 1e-6); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } // Get acknowledgement GetAck(max_string_len, labview_socket_desc); usleep(100000); // usleep(500000); // Read set current. sprintf(command_str, "%s %s\n", InstrCoreSM1, CommandReadCurrentAmplitude); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } if ( SockGetB((unsigned char *)response_str, max_string_len, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Error receiving existing current setting!\n"); fflush(stdout); exit(EXIT_FAILURE); } sscanf(response_str, "%f", &present_curr_src); usleep(100000); // usleep(500000); } usleep(100000); // usleep(500000); } // Read and then set the temperature (if necessary). sprintf(command_str, "%s %s\n", InstrTC, CommandReadTemperature); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } if ( SockGetB((unsigned char *)response_str, max_string_len, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Error receiving existing temperature!\n"); fflush(stdout); exit(EXIT_FAILURE); } sscanf(response_str, "%f", &present_temperature); sprintf(command_str, "%s %s %d\n", InstrTC, CommandSetTemperature, temperatures[TV_num]); if ( SockSendB((unsigned char *)command_str, strlen(command_str) + 1, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Send '%s' failed!\n", command_str); fflush(stdout); exit(EXIT_FAILURE); } if ( SockGetB((unsigned char *)response_str, max_string_len, labview_socket_desc) < 0 ) { printf("ERROR: SetTVCorner(): Error receiving new temperature!\n"); fflush(stdout); exit(EXIT_FAILURE); } sscanf(response_str, "%f", &present_temperature); return; } // ======================================================================================================== // ======================================================================================================== // FILE VERSION: Find the vectors and masks to be used in the protocol operation in the master_xxx_vecs_b/master_masks. // If any are not found, generate an error and quite. void FindVecsInMaster(int max_string_len, int num_PIs, int num_PNR_and_PNF, int session_num_vecs, unsigned char **session_first_vecs_b, unsigned char **session_second_vecs_b, int session_has_masks, unsigned char **session_masks_b, int session_num_rise_vecs, int master_num_vecs, unsigned char **master_first_vecs_b, unsigned char **master_second_vecs_b, int master_has_masks, unsigned char **master_masks_b, int master_num_rise_vecs, int **session_vec_nums_ptr, int **session_PO_nums_ptr) { int bit_cnter, mask_bit_num, mask_byte_num, bit_val, num_tested_paths, byte_num, found_it; int tested_path_num, session_vec_num, master_vec_num, last_master_vec_num; unsigned char *mask_record_ptr; // Sanity check. We MUST have masks with either the session or master file in order for this code to work. if ( session_has_masks == 0 && master_has_masks == 0 ) { printf("ERROR: FindVecsInMaster(): One of Session or Master MUST have 'has_masks' set to 1!\n"); exit(EXIT_FAILURE); } // Sanity check. if ( (num_PIs % 8) != 0 ) { printf("ERROR: FindVecsInMaster(): 'num_PIs' %d is not a multiple of 8 -- FIX ME TO WORK!\n", num_PIs); exit(EXIT_FAILURE); } // Allocate space for the session_xxx arrays. if ( (*session_vec_nums_ptr = (int *)malloc(sizeof(int)*num_PNR_and_PNF)) == NULL ) { printf("ERROR: FindVecsInMaster(): Failed to allocate memory for session_vec_nums_ptr!\n"); exit(EXIT_FAILURE); } if ( (*session_PO_nums_ptr = (int *)malloc(sizeof(int)*num_PNR_and_PNF)) == NULL ) { printf("ERROR: FindVecsInMaster(): Failed to allocate memory for session_PO_nums_ptr!\n"); exit(EXIT_FAILURE); } // First initialize the vectors and PO numbers to invalid. for ( tested_path_num = 0; tested_path_num < num_PNR_and_PNF; tested_path_num++ ) { (*session_vec_nums_ptr)[tested_path_num] = -1; (*session_PO_nums_ptr)[tested_path_num] = -1; } // Basic idea is to parse the session_masks if they are present (otherwise use mask_masks) and for each bit that is // set in a mask, record the master vector number and PO number. num_tested_paths = 0; for ( session_vec_num = 0; session_vec_num < session_num_vecs; session_vec_num++ ) { // Sanity check if ( num_tested_paths >= num_PNR_and_PNF ) { printf("ERROR: FindVecsInMaster(): Too many tested paths in session vectors/masks %d -- max is %d!\n", num_tested_paths, num_PNR_and_PNF); fflush(stdout); exit(EXIT_FAILURE); } // Search for each of the session vectors in the master. Record the vector number when found, and error if not found. // Vectors are binary and CANNOT BE TREATED AS STRING the '0' byte can show UP ANYWHERE and THEY ARE NOT NULL-terminated. found_it = 0; for ( master_vec_num = 0; master_vec_num < master_num_vecs; master_vec_num++ ) { for ( byte_num = 0; byte_num < num_PIs/8; byte_num++ ) if ( session_first_vecs_b[session_vec_num][byte_num] != master_first_vecs_b[master_vec_num][byte_num] ) break; // We must match both vectors. If this is true, we found match to first session and master vectors. if ( byte_num == num_PIs/8 ) { // Check the second vector for a match. for ( byte_num = 0; byte_num < num_PIs/8; byte_num++ ) if ( session_second_vecs_b[session_vec_num][byte_num] != master_second_vecs_b[master_vec_num][byte_num] ) break; // If this is true, then BOTH vectors match. Assume vector pairs are NOT repeated. if ( byte_num == num_PIs/8 ) found_it = 1; } if ( found_it == 1 ) break; } if ( found_it == 0 ) { printf("ERROR: FindVecsInMaster(): Failed to find session vector pair %d in master vectors!\n", session_vec_num); fflush(stdout); exit(EXIT_FAILURE); } // Sanity check. We must move progressively through the master vec file. This may need to be REMOVED if we allow ARBITRARY application orders // of vectors in the session file. if ( session_vec_num == 0 ) last_master_vec_num = master_vec_num; else { if ( master_vec_num > last_master_vec_num ) last_master_vec_num = master_vec_num; else { printf("WARNING: FindVecsInMaster(): Last master vec num %d is GREATER or EQUAL TO than current master vec num %d -- THIS SHOULD NEVER HAPPEN!\n", last_master_vec_num, master_vec_num); int i; printf("Session First Vec:\t"); for ( i = 0; i < num_PIs/8; i++ ) printf("%02X ", session_first_vecs_b[session_vec_num][i]); printf("\n"); printf("Master First Vec:\t"); for ( i = 0; i < num_PIs/8; i++ ) printf("%02X ", master_first_vecs_b[master_vec_num][i]); printf("\n"); // fflush(stdout); exit(EXIT_FAILURE); } } // Now that we have found the session vector, process the POs and update the arrays. If the session uses masks, then use the masks specified. // Otherwise, use the master_masks. NOTE: I check above to ensure that one of these is 1. Session masks GET PRIORITY and MUST specify EXACTLY // 4096 paths. If only master_masks are available (rare case), then allow extra paths at the end of the last vector. if ( session_has_masks == 1 ) mask_record_ptr = session_masks_b[session_vec_num]; else mask_record_ptr = master_masks_b[master_vec_num]; // Vectors and mask are given left-to-right as high order to low order PO numbers. For each mask, find the '1's from low order to high order -- // this is the way the POs are written to the database file for each vector. for ( bit_cnter = 0; bit_cnter < num_PIs; bit_cnter++ ) { mask_byte_num = bit_cnter/8; mask_bit_num = bit_cnter % 8; bit_val = (mask_record_ptr[mask_byte_num] & (unsigned char)(1 << mask_bit_num)) >> mask_bit_num; #ifdef DEBUG printf("Sesson vec %d\tMaster vec %d\tbit_cnter %d\tmask_byte_num %d\tmask_bit_num %d\tHas bit val %d\tCurrent # paths tested %d\n", session_vec_num, master_vec_num, bit_cnter, mask_byte_num, mask_bit_num, bit_val, num_tested_paths); fflush(stdout); #endif // Sanity check. Make sure the session bit matches with the master. if ( session_has_masks == 1 && master_has_masks == 1 && bit_val == 1 ) if ( ((master_masks_b[master_vec_num][mask_byte_num] & (unsigned char)(1 << mask_bit_num)) >> mask_bit_num) != 1 ) { printf("ERROR: FindVecsInMaster(): '1' for session mask bit NOT '1' in master mask!\n"); fflush(stdout); exit(EXIT_FAILURE); } // Skip this path if the mask is 0. if ( bit_val == 0 ) continue; // Otherwise use record vector number and PO number in output arrays. USE THE master_vec_num since the MasterDB uses this number. (*session_vec_nums_ptr)[num_tested_paths] = master_vec_num; (*session_PO_nums_ptr)[num_tested_paths] = bit_cnter; num_tested_paths++; // If number of tested paths is 1/2 or equal to num_PNR_and_PNF, then skip the rest of the tested paths for this vector. This happens // when session masks are used too. if ( (num_tested_paths == num_PNR_and_PNF/2 || num_tested_paths == num_PNR_and_PNF) ) break; } // Sanity check. If we just processed the last rising session vec num, then WE MUST HAVE 2048 paths that are tested. if ( session_vec_num == session_num_rise_vecs-1 && num_tested_paths != num_PNR_and_PNF/2 ) { printf("ERROR: FindVecsInMaster(): Finished processing LAST rising vector with number of tested paths %d -- THIS MUST EQUAL %d!\n", num_tested_paths, num_PNR_and_PNF/2); fflush(stdout); exit(EXIT_FAILURE); } } // Sanity check. Masks should allow the testing of more than 4096 paths in any given session. if ( num_tested_paths != num_PNR_and_PNF ) { printf("ERROR: FindVecsInMaster(): Number of tested paths according to mask is %d which is larger than allowed %d!\n", num_tested_paths, num_PNR_and_PNF); fflush(stdout); exit(EXIT_FAILURE); } return; } // ======================================================================================================== // ======================================================================================================== // FILE VERSION: Read in the database of PNs stored during enrollment. This is closer to how we will do it. Use // the vector numbers and masks to select from a much larger set of PNs those to be used for this protocol execution. int ReadDatabasePNsFromMaster(int max_string_len, char *database_path, int num_PNs, TimingValCacheStruct **TVC_arr_ptr, int *num_TVC_arr_ptr, int *session_vec_nums, int *session_PO_nums, int *tot_DB_PNs_ptr, int DEBUG) { int chip_num, rise_fall, PN_num, num_sams, sam_num, vec_num, PO_num; float PN_sum, temp_float; char line[max_string_len]; int just_incr_chip_num; int first_skip_MPS; char *char_ptr; FILE *INFILE; if ( (INFILE = fopen(database_path, "r")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Could not open PNs database file %s\n", database_path); exit(EXIT_FAILURE); } // Create the timing val cache structure, one element for each of the 4096 PNs. Do the structure allocation first. We re-allocate the PNs member // field as successive chips are processed below. NOTE: WE DEPEND on calloc here because we use realloc ONLY on the PN arrays. if ( (*TVC_arr_ptr = (TimingValCacheStruct *)calloc(sizeof(TimingValCacheStruct), 2 * num_PNs)) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Failed to allocate storage for TVC structure array!\n"); exit(EXIT_FAILURE); } chip_num = 0; rise_fall = 0; PN_num = 0; num_sams = 0; *tot_DB_PNs_ptr = 0; *num_TVC_arr_ptr = 0; first_skip_MPS = 1; while ( fgets(line, max_string_len, INFILE) != NULL ) { // For testing an error condition in which the last line of the file is not empty (blank) below. Must be for chip_num to be incremented properly. just_incr_chip_num = 0; #ifdef DEBUG printf("ReadDatabasePNsFromMaster(): Current line %s", line); fflush(stdout); #endif // Sanity check if ( session_vec_nums[*num_TVC_arr_ptr] == -1 || session_PO_nums[*num_TVC_arr_ptr] == -1 ) { printf("ERROR: ReadDatabasePNsFromMaster(): 'session_vec_nums' or 'session_PO_nums' set to invalid -1!\n"); exit(EXIT_FAILURE); } // There are blank lines between the rise and fall PNs and after each chip. if ( strlen(line) == 0 || strlen(line) == 1 ) { // Sanity check if ( PN_num != num_PNs || (*num_TVC_arr_ptr != num_PNs && *num_TVC_arr_ptr != num_PNs*2) ) { printf("ERROR: ReadDatabasePNsFromMaster(): 'PN_num' must be %d => currently %d and *num_TVC_arr_ptr must be %d or %d => currently %d : CHECK MasterDB is CONSISTENT with MasterVecs and MasterPOs!\n", num_PNs, PN_num, num_PNs, num_PNs*2, *num_TVC_arr_ptr); exit(EXIT_FAILURE); } // Every other blank line, count a new chip. With 1 chip, assume last line in file is blank. Reset *num_TVC_arr_ptr if ( rise_fall == 1 ) { // DEBUG #ifdef DEBUG printf("ReadDatabasePNsFromMaster(): DONE reading PN for chip %d\n", chip_num); fflush(stdout); #endif chip_num++; if ( *num_TVC_arr_ptr != num_PNs*2 ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected '*num_TVC_arr_ptr to be %d!\n", 2*num_PNs); exit(EXIT_FAILURE); } *num_TVC_arr_ptr = 0; just_incr_chip_num = 1; } // DEBUG #ifdef DEBUG printf("ReadDatabasePNsFromMaster(): Chip %d\tFlipping current value of rise_fall flag %d\n", chip_num, rise_fall); fflush(stdout); #endif // Reset PN_num and invert rise_fall flag. Note that we now use separate arrays for the rise and fall PNs. PN_num = 0; rise_fall = !rise_fall; continue; } // 8/3/2019: Added this to handle TDC enrollment files which contain calibration data at the beginning of the file. // ONLY process lines that begin with 'V:' AND '0:' AND 'C:'. This should skip ALL of the calibration data lines. // 'V: 0 O: 0 C: 0 MPS1: 3 MPS2: 3 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316' if ( strstr(line, "V:") == NULL || strstr(line, "O:") == NULL || strstr(line, "C:") == NULL ) continue; // Databases MUST identify vector and PO num, whether they have samples or not. // 'V: 11 O: 0 C: 2705 ...' if ((char_ptr = strtok(line, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): No ' ' found in data line for 'V:'!\n"); exit(EXIT_FAILURE); } if ( strcmp(char_ptr, "V:") != 0 ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected 'V:' as first token!\n"); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): No ' ' found in data line for vector number!\n"); exit(EXIT_FAILURE); } if ( sscanf(char_ptr, "%d", &vec_num) != 1 ) { printf("ERROR: ReadDatabasePNsFromMaster(): Failed to sscanf vector number!\n"); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): No ' ' found in data line for 'O:'!\n"); exit(EXIT_FAILURE); } if ( strcmp(char_ptr, "O:") != 0 ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected 'O:' as third token => '%s'!\n", char_ptr); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): No ' ' found in data line for output number!\n"); exit(EXIT_FAILURE); } if ( sscanf(char_ptr, "%d", &PO_num) != 1 ) { printf("ERROR: ReadDatabasePNsFromMaster(): Failed to sscanf PO number!\n"); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): No ' ' found in data line for 'C:'!\n"); exit(EXIT_FAILURE); } if ( strcmp(char_ptr, "C:") != 0 ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected 'C:' as fifth token => '%s'!\n", char_ptr); exit(EXIT_FAILURE); } if ((char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): No ' ' found in data line for PN cnter!\n"); exit(EXIT_FAILURE); } #ifdef DEBUG printf("Looking for Vec %d and PO %d\tCurrent values %d and %d!\n\n", session_vec_nums[*num_TVC_arr_ptr], session_PO_nums[*num_TVC_arr_ptr], vec_num, PO_num); fflush(stdout); #endif // Total number of PNs in the Master database. if ( chip_num == 0 ) (*tot_DB_PNs_ptr)++; // Skip paths that are NOT identified as participating in the current session. if ( vec_num != session_vec_nums[*num_TVC_arr_ptr] || PO_num != session_PO_nums[*num_TVC_arr_ptr] ) continue; // NOTE: PN_num counts to 2047 while *num_TVC_arr_ptr counts to 4095. if ( PN_num >= num_PNs || (*num_TVC_arr_ptr) >= 2*num_PNs ) { printf("ERROR: Number of PNs LARGER than %d!\n", num_PNs); exit(EXIT_FAILURE); } // Allocate storage for new PN. This array is arranged as PN in the outside dimension and chip_num in the inside dimension to // match what we are doing in the database. (*TVC_arr_ptr)[*num_TVC_arr_ptr].vecpair_id = session_vec_nums[*num_TVC_arr_ptr]; (*TVC_arr_ptr)[*num_TVC_arr_ptr].PO_num = session_PO_nums[*num_TVC_arr_ptr]; (*TVC_arr_ptr)[*num_TVC_arr_ptr].rise_or_fall = rise_fall; // Realloc the PNs array for each additional PN that is read. After the first chip is processed, each TVC_arr element has 1 PN. Increase // each of the 2*num_PN arrays by 1 as each chip is processed. if ( ((*TVC_arr_ptr)[*num_TVC_arr_ptr].PNs = (float *)realloc((*TVC_arr_ptr)[*num_TVC_arr_ptr].PNs, sizeof(float) * (chip_num + 1))) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Failed to allocate storage for TVC structure array!\n"); exit(EXIT_FAILURE); } // Assume each line in one of these formats with multiple sams // 'V: 11 O: 0 C: 2705 319 320 320 320 320 320 320 320 320 320 323 320 320 320 320 320' // 'V: 0 O: 0 C: 0 MPS1: 3 MPS2: 3 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316' // Retrieve the samples, one at a time, to compute the average. sam_num = 0; PN_sum = 0.0; while ( (char_ptr = strtok(NULL, " \t")) != NULL ) { // 8/3/2019: Skip the MPSx if they exist. if ( strstr(char_ptr, "MPS1:") != NULL ) { if ( first_skip_MPS == 1 ) { printf("Skipping MPSx data on line!\n"); fflush(stdout); } first_skip_MPS = 0; if ( (char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected MPS data!\n"); exit(EXIT_FAILURE); } if ( (char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected MPS data!\n"); exit(EXIT_FAILURE); } if ( strstr(char_ptr, "MPS2:") == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected 'MPS2:' !\n"); exit(EXIT_FAILURE); } if ( (char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected MPS data!\n"); exit(EXIT_FAILURE); } if ( (char_ptr = strtok(NULL, " \t")) == NULL ) { printf("ERROR: ReadDatabasePNsFromMaster(): Expected sample data!\n"); exit(EXIT_FAILURE); } } sscanf(char_ptr, "%f", &temp_float); PN_sum += temp_float; sam_num++; } // Sanity check. Number of samples MUST be consistent across all chips and PN lines if ( num_sams == 0 ) num_sams = sam_num; else if ( num_sams != sam_num ) { printf("ERROR: ReadDatabasePNsFromMaster(): Sample number mismatch across PN lines!\n"); exit(EXIT_FAILURE); } // Compute the average value. if ( num_sams != 0 ) (*TVC_arr_ptr)[*num_TVC_arr_ptr].PNs[chip_num] = PN_sum/num_sams; else { printf("ERROR: ReadDatabasePNsFromMaster(): Number of samples is 0!\n"); exit(EXIT_FAILURE); } #ifdef DEBUG printf("Just processed num_TVC_arr index %d for chip %d with vecpair_id %d, PO_num %d and PN %.4f\n", *num_TVC_arr_ptr, chip_num, (*TVC_arr_ptr)[*num_TVC_arr_ptr].vecpair_id, (*TVC_arr_ptr)[*num_TVC_arr_ptr].PO_num, (*TVC_arr_ptr)[*num_TVC_arr_ptr].PNs[chip_num]); fflush(stdout); #endif // Increment counters. PN_num++; (*num_TVC_arr_ptr)++; } fclose(INFILE); // This must be true otherwise the chip_num is NOT incremented. if ( just_incr_chip_num == 0 ) { printf("ERROR: ReadDatabasePNsFromMaster(): LAST LINE OF data file MUST be empty!\n"); exit(EXIT_FAILURE); } if ( DEBUG == 1 ) printf("ReadDatabasePNsFromMaster(): Number of chips %d\tNumber of samples read from data file %d\n", chip_num, num_sams); fflush(stdout); // *num_TVC_arr_ptr is used as an index above. Set it to the total number of TVC_arr structures created. *num_TVC_arr_ptr = 2 * num_PNs; // Return the number of chip data sets that were read. return chip_num; }