/** Signal generator main */ int main(int argc, char *argv[]) { g_argv0 = argv[0]; if ( argc < 4 ) { usage(); return -1; } /* Channel argument parsing */ uint32_t ch = atoi(argv[1]) - 1; /* Zero based internally */ if (ch > 1) { fprintf(stderr, "Invalid channel: %s\n", argv[1]); usage(); return -1; } /* Signal amplitude argument parsing */ double ampl = strtod(argv[2], NULL); if ( (ampl < 0.0) || (ampl > c_max_amplitude) ) { fprintf(stderr, "Invalid amplitude: %s\n", argv[2]); usage(); return -1; } /* Signal frequency argument parsing */ double freq = strtod(argv[3], NULL); /* Signal type argument parsing */ signal_e type = eSignalSine; if (argc > 4) { if ( strcmp(argv[4], "sine") == 0) { type = eSignalSine; } else if ( strcmp(argv[4], "sqr") == 0) { type = eSignalSquare; } else if ( strcmp(argv[4], "tri") == 0) { type = eSignalTriangle; } else { fprintf(stderr, "Invalid signal type: %s\n", argv[4]); usage(); return -1; } } /* Check frequency limits */ if ( (freq < c_min_frequency) || (freq > c_max_frequency ) ) { fprintf(stderr, "Invalid frequency: %s\n", argv[3]); usage(); return -1; } awg_param_t params; /* Prepare data buffer (calculate from input arguments) */ synthesize_signal(ampl, freq, type, data, ¶ms); /* Write the data to the FPGA and set FPGA AWG state machine */ write_data_fpga(ch, data, ¶ms); }
/** Signal generator main */ int main(int argc, char *argv[]) { g_argv0 = argv[0]; if ( argc < 4 ) { usage(); return -1; } /* Channel argument parsing */ uint32_t ch = atoi(argv[1]) - 1; /* Zero based internally */ if (ch > 1) { fprintf(stderr, "Invalid channel: %s\n", argv[1]); usage(); return -1; } /* Signal amplitude argument parsing */ float ampl = strtod(argv[2], NULL); if ( (ampl < 0.0) || (ampl > c_max_amplitude) ) { fprintf(stderr, "Invalid amplitude: %s\n", argv[2]); usage(); return -1; } /* Signal frequency argument parsing */ float freq = strtod(argv[3], NULL); if ( (freq < 0.0) || (freq > c_max_frequency ) ) { fprintf(stderr, "Invalid frequency: %s\n", argv[3]); usage(); return -1; } /* Signal type argument parsing */ awg_signal_t type = eSignalSine; if (argc > 4) { if ( strcmp(argv[4], "sine") == 0) { type = eSignalSine; } else if ( strcmp(argv[4], "sqr") == 0) { type = eSignalSquare; } else if ( strcmp(argv[4], "tri") == 0) { type = eSignalTriangle; } else { fprintf(stderr, "Invalid signal type: %s\n", argv[4]); usage(); return -1; } } //Added by Marko float offsetVolts = 0.0; if(argc > 5){ offsetVolts = strtod(argv[5], NULL); //fprintf(stderr, "Using offset: %f\n", offsetVolts); } rp_default_calib_params(&rp_calib_params); gen_calib_params = &rp_calib_params; if(rp_read_calib_params(gen_calib_params) < 0) { fprintf(stderr, "rp_read_calib_params() failed, using default" " parameters\n"); } ch1_max_dac_v = fpga_awg_calc_dac_max_v(gen_calib_params->be_ch1_fs); ch2_max_dac_v = fpga_awg_calc_dac_max_v(gen_calib_params->be_ch2_fs); awg_param_t params; /* Prepare data buffer (calculate from input arguments) */ synthesize_signal(ampl,//Amplitude freq,//Frequency (ch == 0) ? gen_calib_params->be_ch1_dc_offs : gen_calib_params->be_ch2_dc_offs,//Calibrated Instrument DC offset (ch == 0) ? gen_calib_params->be_ch1_fs : gen_calib_params->be_ch2_fs,//Calibrated Back-End full scale coefficient (ch == 0) ? ch1_max_dac_v : ch2_max_dac_v,//Maximum DAC voltage offsetVolts,//DC offset voltage type,//Signal type/shape data,//Returned synthesized AWG data vector ¶ms);//Returned AWG parameters /* Write the data to the FPGA and set FPGA AWG state machine */ write_data_fpga(ch, data, ¶ms); }
/** * @brief Update Arbitrary Signal Generator module towards actual settings. * * A function is intended to be called whenever one of the following settings on each channel * is modified * - enable * - signal type * - amplitude * - frequency * - DC offset * - trigger mode * * @param[in] params Pointer to overall configuration parameters * @retval -1 failure, error message is repoted on standard error device * @retval 0 succesful update */ int generate_update(rp_app_params_t *params) { awg_param_t ch1_param, ch2_param; awg_signal_t ch1_type; awg_signal_t ch2_type; int ch1_enable = params[GEN_ENABLE_CH1].value; int ch2_enable = params[GEN_ENABLE_CH2].value; //float time_vect[AWG_SIG_LEN], ch1_amp[AWG_SIG_LEN], ch2_amp[AWG_SIG_LEN]; float ch1_arb[AWG_SIG_LEN]; float ch2_arb[AWG_SIG_LEN]; int wrap; //int invalid_file=0; int in_smpl_len1 = 0; int in_smpl_len2 = 0; ch1_type = (awg_signal_t)params[GEN_SIG_TYPE_CH1].value; ch2_type = (awg_signal_t)params[GEN_SIG_TYPE_CH2].value; if( (ch1_type == eSignalFile) || (params[GEN_AWG_REFRESH].value == 1) ) { if((in_smpl_len1 = read_in_file(1, ch1_arb)) < 0) { // Invalid file params[GEN_ENABLE_CH1].value = 0; params[GEN_SIG_TYPE_CH1].value = eSignalSine; ch1_type = params[GEN_SIG_TYPE_CH1].value; ch1_enable = params[GEN_ENABLE_CH1].value; //invalid_file=1; } } if( (ch2_type == eSignalFile) || (params[GEN_AWG_REFRESH].value == 2) ) { if((in_smpl_len2 = read_in_file(2, ch2_arb)) < 0) { // Invalid file params[GEN_ENABLE_CH2].value = 0; params[GEN_SIG_TYPE_CH2].value = eSignalSine; ch2_type = params[GEN_SIG_TYPE_CH2].value; ch2_enable = params[GEN_ENABLE_CH2].value; // invalid_file=1; } } params[GEN_AWG_REFRESH].value = 0; /* Waveform from signal gets treated differently then others */ if(ch1_enable > 0) { if(ch1_type < eSignalFile) { synthesize_signal(params[GEN_SIG_AMP_CH1].value, params[GEN_SIG_FREQ_CH1].value, gen_calib_params->be_ch1_dc_offs, gen_calib_params->be_ch1_fs, ch1_max_dac_v, params[GEN_SIG_DCOFF_CH1].value, ch1_type, ch1_data, &ch1_param); wrap = 0; // whole buffer used } else { /* Signal file */ calculate_data(ch1_arb, in_smpl_len1, params[GEN_SIG_AMP_CH1].value, params[GEN_SIG_FREQ_CH1].value, gen_calib_params->be_ch1_dc_offs, gen_calib_params->be_ch1_fs, ch1_max_dac_v, params[GEN_SIG_DCOFF_CH1].value, ch1_data, &ch1_param); wrap = 0; if (in_smpl_len1<AWG_SIG_LEN) wrap = 1; // wrapping after (in_smpl_lenx) samples } } else { clear_signal(gen_calib_params->be_ch1_dc_offs, ch1_data, &ch1_param); } write_data_fpga(0, params[GEN_TRIG_MODE_CH1].value, params[GEN_SINGLE_CH1].value, ch1_data, &ch1_param, wrap); /* Waveform from signal gets treated differently then others */ if(ch2_enable > 0) { if(ch2_type < eSignalFile) { synthesize_signal(params[GEN_SIG_AMP_CH2].value, params[GEN_SIG_FREQ_CH2].value, gen_calib_params->be_ch2_dc_offs, gen_calib_params->be_ch2_fs, ch2_max_dac_v, params[GEN_SIG_DCOFF_CH2].value, ch2_type, ch2_data, &ch2_param); wrap = 0; // whole buffer used } else { /* Signal file */ calculate_data(ch2_arb, in_smpl_len2, params[GEN_SIG_AMP_CH2].value, params[GEN_SIG_FREQ_CH2].value, gen_calib_params->be_ch2_dc_offs, gen_calib_params->be_ch2_fs, ch2_max_dac_v, params[GEN_SIG_DCOFF_CH2].value, ch2_data, &ch2_param); wrap = 0; if (in_smpl_len2<AWG_SIG_LEN) wrap = 1; // wrapping after (in_smpl_lenx) samples } } else { clear_signal(gen_calib_params->be_ch2_dc_offs, ch2_data, &ch2_param); } write_data_fpga(1, params[GEN_TRIG_MODE_CH2].value, params[GEN_SINGLE_CH2].value, ch2_data, &ch2_param, wrap); /* Always return singles to 0 */ params[GEN_SINGLE_CH1].value = 0; params[GEN_SINGLE_CH2].value = 0; //if (invalid_file==1) // return -1; // Use this return value to notify the GUI user about invalid file. return 0; }
void *rp_spectr_worker_thread(void *args) { rp_spectr_worker_state_t old_state, state; rp_app_params_t curr_params[PARAMS_NUM]; int fpga_update = 1; int params_dirty = 1; // TODO: Name these int jj_state = 0; int iix, iix2; int cal_butt1_old, cal_butt2_old; int start_state = 1; awg_param_t awg_par; pthread_mutex_lock(&rp_spectr_ctrl_mutex); old_state = state = rp_spectr_ctrl; pthread_mutex_unlock(&rp_spectr_ctrl_mutex); while(1) { /* update states - we save also old state to see if we need to reset * FPGA */ old_state = state; pthread_mutex_lock(&rp_spectr_ctrl_mutex); state = rp_spectr_ctrl; if(rp_spectr_params_dirty) { memcpy(&curr_params, &rp_spectr_params, sizeof(rp_app_params_t)*PARAMS_NUM); fpga_update = rp_spectr_params_fpga_update; rp_spectr_params_dirty = 0; } pthread_mutex_unlock(&rp_spectr_ctrl_mutex); /* request to stop worker thread, we will shut down */ if(state == rp_spectr_quit_state) { return 0; } if(fpga_update) { spectr_fpga_reset(); //cal_ready1 = 0; // Resets calibration //cal_ready2 = 0; // Resets calibration jj_state = 0; if(spectr_fpga_update_params(0, 0, 0, 0, 0, (int)curr_params[FREQ_RANGE_PARAM].value, 0) < 0) { rp_spectr_worker_change_state(rp_spectr_auto_state); } fpga_update = 0; } if(state == rp_spectr_idle_state) { usleep(10000); continue; } /* Prepare AWG data buffer */ // Buffer prepared only once in order to save CPU resources if (synth_ready == 0) { // Before preparing buffer visualize some constant signal rp_resp_init_sigs(&rp_tmp_signals[0], (float **)&rp_tmp_signals[1], (float **)&rp_tmp_signals[2]); rp_spectr_set_signals(rp_tmp_signals); for (iix2 = 0; iix2 < JJ; iix2++) { synthesize_fra_sig(dacamp, iix2*II*kstp, kstp, II, ch1_data, iix2*NN, &tmpdouble, &awg_par); scale[iix2] = tmpdouble; } synth_ready = 1; } if (start_state == 0) { if (round(curr_params[EN_CAL_1].value) != cal_butt1_old) { cal_ready1 = 0; } if (round(curr_params[EN_CAL_2].value) != cal_butt2_old) { cal_ready2 = 0; } } else { start_state = 0; // The calibration consists in coping the current response data to reference cal. vectors for (iix = 0; iix < SPECTR_OUT_SIG_LEN; iix++) { rp_cha_resp_cal[iix] = 56e6; rp_chb_resp_cal[iix] = 56e6; } } cal_butt1_old = round(curr_params[EN_CAL_1].value); cal_butt2_old = round(curr_params[EN_CAL_2].value); // TODO: Implement signal generator part as a separate module /* Write the data to the FPGA and set FPGA AWG state machine for current pattern*/ write_data_fpga(0, 1, 0, ch1_data, jj_state*NN, &awg_par, round(65536 / ((float)spectr_fpga_cnv_freq_range_to_dec(curr_params[FREQ_RANGE_PARAM].value)))); write_data_fpga(1, 1, 0, ch1_data, jj_state*NN, &awg_par, round(65536 / ((float)spectr_fpga_cnv_freq_range_to_dec(curr_params[FREQ_RANGE_PARAM].value)))); /* Start the writing machine: DATA ACQUISITION */ spectr_fpga_arm_trigger(); usleep(10); spectr_fpga_set_trigger(1); /* start working */ pthread_mutex_lock(&rp_spectr_ctrl_mutex); old_state = state = rp_spectr_ctrl; pthread_mutex_unlock(&rp_spectr_ctrl_mutex); if((state == rp_spectr_idle_state) || (state == rp_spectr_abort_state)) { continue; } else if(state == rp_spectr_quit_state) { break; } /* polling until data is ready */ while(1) { pthread_mutex_lock(&rp_spectr_ctrl_mutex); state = rp_spectr_ctrl; params_dirty = rp_spectr_params_dirty; pthread_mutex_unlock(&rp_spectr_ctrl_mutex); /* change in state, abort polling */ if((state != old_state) || params_dirty) { break; } if(spectr_fpga_triggered()) { break; } } if((state != old_state) || params_dirty) { params_dirty = 0; continue; } /* retrieve data and process it*/ spectr_fpga_get_signal(&rp_cha_in, &rp_chb_in); /* Calculate response at frequency components for each excitation pattern*/ rp_resp_calc(&rp_cha_in[0], &rp_chb_in[0], jj_state*II, scale[jj_state], kstp, II, (double **)&rp_cha_resp, (double **)&rp_chb_resp); // Continue acquiring and processing until all the pattern sequence completed if (jj_state < JJ) { jj_state++; } else { // Response characterization completed jj_state = 0; /* Perform calibration at startup or parameter update. * TODO: add a GUI Calibration button for individual channels */ if (cal_ready1 == 0) { // Provide calibration vector initialization since calibration cal_ready1 = 1; // executed on demand // The calibration consists in coping the current response data to reference cal. vectors for (iix = 0; iix < SPECTR_OUT_SIG_LEN; iix++) { rp_cha_resp_cal[iix] = rp_cha_resp[iix]; } } /* Perform calibration at startup or parameter update * TODO: add a GUI Calibration button for individual channels */ if (cal_ready2 == 0) { // Provide calibration vector initialization since calibration cal_ready2 = 1; // executed on demand // The calibration consists in coping the current response data to reverence cal. vectors for (iix = 0; iix < SPECTR_OUT_SIG_LEN; iix++) { rp_chb_resp_cal[iix] = rp_chb_resp[iix]; } } // Calculate frequency vector for the frequencies where response measured rp_resp_prepare_freq_vector(&rp_tmp_signals[0], c_spectr_fpga_smpl_freq, curr_params[FREQ_RANGE_PARAM].value, II, JJ, k1, kstp); // Calculate frequency response in dB and implement calibration rp_resp_cnv_to_dB(&rp_cha_resp[0], &rp_chb_resp[0], &rp_cha_resp_cal[0], &rp_chb_resp_cal[0], (float **)&rp_tmp_signals[1], (float **)&rp_tmp_signals[2], II*JJ); rp_spectr_set_signals(rp_tmp_signals); usleep(10000); } } return 0; }