/****************************************************************************** * $HeadURL: https://svnpub.iter.org/codac/iter/codac/dev/units/m-codac-unit-templates/tags/CODAC-CORE-6.0.0/templates/cpp-sdn/main/c++/prog/prog.cpp.template $ * $Id: prog.cpp.template 83098 2018-01-08 13:23:38Z cesnikt $ * * Project : CODAC Core System * * Description : GyrotronDAN program * * Author : codac-dev * * Copyright (c) : 2010-2018 ITER Organization, * CS 90 046 * 13067 St. Paul-lez-Durance Cedex * France * * This file is part of ITER CODAC software. * For the terms and conditions of redistribution or use of this software * refer to the file ITER-LICENSE.TXT located in the top level directory * of the distribution package. ******************************************************************************/ /* header files */ #include #include #include #include #include #include #include #include #include //#include #define float32_t float32_t1 #include #undef float32_t #include #include #include #include #include #include #include // global variables static bool __terminate = false; char pxie6368_0_ai_fd[] = "/dev/pxie-6368.1.ai"; // ai segment char pxie6368_0_device[] = "/dev/pxie-6368.1"; // device descriptor typedef struct { int daq_smpl_rate; int daq_mode; double daq_smpl_st_dly; double daq_len; double daq_pub_dly; } daq_parameters; void signal_handler(int signal) { log_info("Received signal '%d' to terminate", signal); __terminate = true; }; // DAN parameter reload function ------------------------------------------------ int reload_daq_conf(int *aifd, int *ai_chan_fd, daq_parameters *daq_p) { std::cout << "reload_daq_conf was called \n"; // Common variables int retval; unsigned long number_of_samples; int chan_num = 10; // Channel number to add. uint32_t sample_period_divisor; uint32_t base_clock = 100000000; // TB3:100MHz, TB2:100 kHz uint32_t pre_samples = 1000; uint32_t post_samples = 1000; char str[40]; xseries_ai_conf_t conf; // ai segment configuraton data // calculate sampling period divisor if (daq_p->daq_smpl_rate != 0) { sample_period_divisor = base_clock / daq_p->daq_smpl_rate; } else { return 0; } // Stop ai segment---------------------------------------------------------------------- retval = xseries_stop_ai(*aifd); if (retval) { log_error("ai segment stop failed.\n"); } else { log_info("ai segment stopped.\n"); } // reset ai segment--------------------------------------------------------------------- retval = xseries_reset_ai(*aifd); if (retval) { log_error("ai segment reset failed.\n"); return -1; } // Configure AI segment mode ------------------------------------------------------------ switch (daq_p->daq_mode) { case 0: conf = xseries_software_timed_ai(); log_info("software_timed mode.\n"); break; case 1: conf = xseries_finite_ai(number_of_samples); log_info("finite mode.\n"); break; case 2: conf = xseries_retriggerable_finite_ai(number_of_samples); log_info("retriggerable_finite mode.\n"); break; case 3: conf = xseries_continuous_ai(); log_info("continuous mode.\n"); break; case 4: conf = xseries_reference_ai(pre_samples, post_samples); log_info("reference mode.\n"); break; } // disable external gate retval = xseries_set_ai_external_gate(&conf, XSERIES_AI_EXTERNAL_GATE_DISABLED, // No external pause signal XSERIES_AI_POLARITY_ACTIVE_LOW_OR_FALLING_EDGE); // Don't care if (retval) { log_error("Cannot set gate trigger.\n"); return -1; } // select start trigger (START1 signal) retval = xseries_set_ai_start_trigger(&conf, XSERIES_AI_START_TRIGGER_SW_PULSE, // Set the line to software-driven XSERIES_AI_POLARITY_ACTIVE_HIGH_OR_RISING_EDGE, // Make line active on rising... 1); // ... edge (not high level) if (retval) { log_error("Cannot set start trigger.\n"); return -1; } // set sampling clock source---------------------------------------------------------------------------------------- retval = xseries_set_ai_sample_clock(&conf, XSERIES_AI_SAMPLE_CONVERT_CLOCK_INTERNALTIMING, XSERIES_AI_POLARITY_ACTIVE_HIGH_OR_RISING_EDGE, 1); if (retval) { log_error("Cannot configure sampling clock.\n"); return -1; } // set scan interval ------------------------------------------------------------------------------------------------------------------------- retval = xseries_set_ai_scan_interval_counter(&conf, XSERIES_SCAN_INTERVAL_COUNTER_TB3, // TB3 : 100MHz base clock, TB2 : 100kHz base clock XSERIES_SCAN_INTERVAL_COUNTER_POLARITY_RISING_EDGE, sample_period_divisor, 2); // Wait 2*100MHz sec after sampling trig. if (retval) { log_error("Cannot configure scan counter.\n"); return -1; } // Set DMA buffer size----------------------------------------------------------------------------------------------------------------------- retval = xseries_set_ai_attribute(&conf, XSERIES_AI_DMA_BUFFER_SIZE, 1000); if (retval) { log_error("DMA configuration was failed.\n"); return -1; } // Add AI channels --------------------------------------------------------------------------------------------------------------------------- for (int i = 0; i < chan_num; i++) { retval = xseries_add_ai_channel(&conf, i, XSERIES_INPUT_RANGE_10V, XSERIES_AI_CHANNEL_TYPE_DIFFERENTIAL, 0); if (retval) { log_error("Add AI channel %d was failed.\n", i); return -1; } } sleep(3); // Load configuration.----------------------------------------------------------------------------------------------------------------------- retval = xseries_load_ai_conf(*aifd, conf); if (retval) { log_error("xseries_load_ai_conf was failed. error code: %d \n", retval); exit (EXIT_FAILURE); } sleep(3); // Open channels-------------------------------------------------------------------------------------------------------------------------------- for (int i = 0; i < chan_num; i++) { sprintf(str, "%s.ai.%u", pxie6368_0_device, i); //ai_chan_fd[i] = open(str, O_RDWR | O_NONBLOCK); ai_chan_fd[i] = open(str, O_RDWR); if (ai_chan_fd[i] < 0) { log_error("Cannot open ai channel %d .\n",i); sleep(1); exit (EXIT_FAILURE); } } // start ai segment task----------------------------------------------------------------------------------------------------------------------- retval = xseries_start_ai(*aifd); if (retval) { log_error("ERROR, starting AI segment failed: %s\n", strerror(retval)); exit (EXIT_FAILURE); } log_info("PXIe-6368 configuration was finished.\n"); return 0; }; int main(int argc, char **argv) { using namespace std; unsigned long n_sample_quotient = 0; log_initialize(NULL); while (!__terminate) { // Install signal handler to support graceful termination sigset(SIGTERM, signal_handler); sigset(SIGINT, signal_handler); sigset(SIGHUP, signal_handler); // ---------------------------------------------------------------------------------------------------------------- // Running parameter declaration // ---------------------------------------------------------------------------------------------------------------- // pxie6368 hardware parameters int pxie6368_0_device_number = 1; // device discriptor number int aifd = 0; // ai segment file discriptor xseries_ai_conf_t conf; // ai segment config xseries_ai_attribute_t aiatrb; // ai segment attributes char str[40]; // fd tmp var int ai_chan_fd[16]; // ai channels file discriptor int pxie6368_sampling_rate = 1000; // sampling rate Hz uint32_t sample_period_divisor = 100000000 / pxie6368_sampling_rate; // TB3 100MHz, TB2:100kHz, TB1:20MHz int sampleSize = 2; // Sample size in bytes <---> uInt16 int n_channels; // Number of opened channels struct xseries_dma *dma; // Ptr to dma struct int chan_num = 10; // Channel number to add. // DAN parameters char dan_source_name[] = "GYBDanSource"; // DAN data source (ds) name long offset_ai = 0; // offset size in published data int dma_mode = 1; // 0:All, 1:AI only, 2:AO only dan_DataCore dc = NULL; // Datacore reference declaration dan_Source ds = NULL; // DAN source declaration long samplesCounter = 0; // Total acquired sample size size_t n_samples; // prepared sample size to publish // TCN parameters uint64_t tBase_old = 0; uint64_t tBase = 0; // TCN publishing base time uint64_t nanos; // time length for sampling hpn_timestamp_t delay = 1e7; // wait for publishing (10ms) char buf[ISO_8601_LEN]; uint64_t tBase0 = 0; // Operation tmp parameter int result; // For result values. int exValue; bool toterminate = false; int retval; bool daq_start = false; int testcounter = 10000; // Connected EPCIS PV // DAQ config PVs chid daq_smpl_rate_id; chtype daq_smpl_rate_type; int daq_smpl_rate; chid daq_smpl_rate_rb_id; chtype daq_smpl_rate_rb_type; int daq_smpl_rate_rb; chid daq_mode_id; chtype daq_mode_type; int daq_mode; chid daq_mode_rb_id; chtype daq_mode_rb_type; int daq_mode_rb; chid daq_sw_trig_id; chtype daq_sw_trig_type; int daq_sw_trig; chid daq_smpl_st_dly_id; chtype daq_smpl_st_dly_type; double daq_smpl_st_dly; chid daq_smpl_st_dly_rb_id; chtype daq_smpl_st_dly_rb_type; double daq_smpl_st_dly_rb; chid daq_len_id; chtype daq_len_type; double daq_len; chid daq_len_rb_id; chtype daq_len_rb_type; double daq_len_rb; chid daq_reconf_id; chtype daq_reconf_type; int daq_reconf; chid daq_pub_dly_id; chtype daq_pub_dly_type; double daq_pub_dly; chid daq_pub_dly_rb_id; chtype daq_pub_dly_rb_type; double daq_pub_dly_rb; chid daq_stat_id; chtype daq_stat_type; int daq_stat; chid daq_conf_stat_id; chtype daq_conf_stat_type; int daq_conf_stat; daq_parameters daq_p = { 0 }; // = {daq_smpl_rate, daq_smpl_rate_rb, daq_mode, daq_mode_rb}; // ---------------------------------------------------------------------------------------------------------------------------------------------- // EPICS PV connection // ---------------------------------------------------------------------------------------------------------------------------------------------- //Initialize ChannelAccess interface CAInterface_Initialize(); // Connect to EPICS PVs CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-SMPL-RATE", daq_smpl_rate_id); daq_smpl_rate_type = DBR_LONG; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-SMPL-RATE-RB", daq_smpl_rate_rb_id); daq_smpl_rate_rb_type = DBR_LONG; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-MODE", daq_mode_id); daq_mode_type = DBR_ENUM; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-MODE-RB", daq_mode_rb_id); daq_mode_rb_type = DBR_ENUM; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-SW-TRIG", daq_sw_trig_id); daq_sw_trig_type = DBR_ENUM; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-SMPL-ST-DLY", daq_smpl_st_dly_id); daq_smpl_st_dly_type = DBR_DOUBLE; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-SMPL-ST-DLY-RB", daq_smpl_st_dly_rb_id); daq_smpl_st_dly_rb_type = DBR_DOUBLE; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-LEN", daq_len_id); daq_len_type = DBR_DOUBLE; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-LEN-RB", daq_len_rb_id); daq_len_rb_type = DBR_DOUBLE; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-RECONF", daq_reconf_id); daq_reconf_type = DBR_ENUM; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-PUB-DLY", daq_pub_dly_id); daq_pub_dly_type = DBR_DOUBLE; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-PUB-DLY-RB", daq_pub_dly_rb_id); daq_pub_dly_rb_type = DBR_DOUBLE; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-STAT", daq_stat_id); daq_stat_type = DBR_ENUM; CAInterface_ConnectVariable("EC-GN-P01-GPF:STAT-DAQ-CONF-STAT", daq_conf_stat_id); daq_conf_stat_type = DBR_ENUM; tcn_sleep(3e9);// Wait for a while. // ---------------------------------------------------------------------------------------------------------------- // Initialize tcn library // ---------------------------------------------------------------------------------------------------------------- int tcn_err; tcn_err = tcn_init(); if (tcn_err != TCN_SUCCESS) { log_error("TCN Initialization failed.\n"); exValue = 1; goto END; } // ---------------------------------------------------------------------------------------------------------------- // pxie-6368 settings // ---------------------------------------------------------------------------------------------------------------- // Open ai segment---------------------------------------------------------------------- aifd = open(pxie6368_0_ai_fd, O_RDWR); if (aifd <= 0) { log_error("Open PXIe6368 AI fd failed.\n"); exValue = -1; goto END; } // wait ai segment setup start do { CAInterface_ReadVariable(daq_reconf_id, daq_reconf_type, (void*) &daq_reconf); } while (!daq_reconf and !__terminate); // read parameter result = CAInterface_ReadVariable(daq_smpl_rate_id, daq_smpl_rate_type, (void *) &daq_p.daq_smpl_rate); if (!result) { log_error("CA_READ failed.\n"); } // read parameter result = CAInterface_ReadVariable(daq_mode_id, daq_mode_type, (void *) &daq_p.daq_mode); if (!result) { log_error("CA_READ failed.\n"); } // read parameter result = CAInterface_ReadVariable(daq_smpl_st_dly_id, daq_smpl_st_dly_type, (void *) &daq_p.daq_smpl_st_dly); if (!result) { log_error("CA_READ failed.\n"); } // read parameter result = CAInterface_ReadVariable(daq_len_id, daq_len_type, (void *) &daq_p.daq_len); if (!result) { log_error("CA_READ failed.\n"); } // read parameter result = CAInterface_ReadVariable(daq_pub_dly_id, daq_pub_dly_type, (void *) &daq_p.daq_pub_dly); if (!result) { log_error("CA_READ failed.\n"); } std::cout << "SAMPLE RATE:" << daq_p.daq_smpl_rate << endl; std::cout << "MODE :" << daq_p.daq_mode << endl; std::cout << "START DELAY:" <ai.count * sampleSize, 4096); //dan_DataCore, ds_name, devName, enum_daq_type refType, long refSize, long refOffset if (ds == NULL) { log_error("Error while publishing DAN source %s ", dan_source_name); exValue = 1; goto END; } n_channels = dan_publisher_getNumberOfChannels(ds); // ------------------------------------------------------------------------------------------------------------------ // ----- DAN Streamer. // ------------------------------------------------------------------------------------------------------------------ // ----- Open a new stream --------------------------------------------------------------------- dan_publisher_openStream(ds, daq_p.daq_smpl_rate, 0); sleep(1); // ------------------------------------------------------------------------------------------------------------------ // ----- Main DAN Loop. // ------------------------------------------------------------------------------------------------------------------ while (!__terminate) { // Wait for the master trigger.---------------------------------------------------------------------------- daq_stat = 1; //0:Not Ready, 1: Waiting trigger, 2:Acquiring 3:Error CAInterface_WriteVariable(daq_stat_id, daq_stat_type, &daq_stat); daq_conf_stat = 1; //0:Not ready, 1: Ready CAInterface_WriteVariable(daq_conf_stat_id, daq_conf_stat_type, &daq_conf_stat); // Wait DAQ Start Software Trigger. do { // check daq_sw_trigger to start DAQ sequence. CAInterface_ReadVariable(daq_sw_trig_id, daq_sw_trig_type, (void*) &daq_sw_trig); tcn_sleep(1e7); // wait 0.01 s if (daq_sw_trig) { daq_start = true; } } while (daq_start != true and !__terminate); daq_start = false; //reset daq_start flag. delay = (long) (1e6 * daq_p.daq_pub_dly); //check publish period. // Wait a time to start DAQ. ---------------------------------------------------------------------------------------------------------------------- tcn_sleep(daq_p.daq_smpl_st_dly * 1e6); // in ms // After the wating, trigger DAQ ------------------------------------------------------------------------------------------------------------------ retval = xseries_pulse_ai(aifd, XSERIES_START_TRIGGER); daq_stat = 2; CAInterface_WriteVariable(daq_stat_id, daq_stat_type, &daq_stat); if (retval) { std::cout << "Cannot generate start trigger!\n"; goto END; } else { tcn_get_time(&tBase); // get DAQ start time. tBase0 = tBase; // save DAQ start time to tBase0; tBase_old = tBase; } // DAQ Publish Loop. ---------------------------------------------------------------------------------------------------------------------------- // DAN data publish is executed every delay time interval. while (!__terminate && (tcn_wait_until_hr((tBase + delay), &tBase, 0) == TCN_SUCCESS)) { // Get the number of available samples in PXIe6368 buffer. n_samples = xsereis_ai_dma_samples_in_buffer(dma); // samples if (n_samples > dma->ai.count) { //log_error("DMA Buffer overflow: Number of new samples in buffer = %ld, AI buffer size = %ld,\n", n_samples, dma->ai.count); } else if (n_samples > 0) { //log_info("Current Time:\n%s\n", tcn_strftime(tBase, buf, ISO_8601_LEN)); if (tBase == 0) { // "tBase was reset.------------------------------------------------------\n"; tcn_get_time(&tBase); tBase -= n_samples * 100000000 / pxie6368_sampling_rate; nanos = 0; } else { // update time offset value. nanos = n_samples * 100000000 / daq_p.daq_smpl_rate; } n_sample_quotient = floor(n_samples / chan_num); n_samples = n_sample_quotient * chan_num; // Publish a new data block -------------------------------------------------------------------------------------------------------------------------- result = dan_publisher_putBlockReference(ds, tBase_old + nanos, // timestamp in epoch nanoseconds n_samples * sampleSize, // datablock size in bytes offset_ai * sampleSize, // Offset in DAQ buffer NULL); // No datablock header.... // Detected overflow in pass datablock reference queue if (result == -1) { log_info("%s, Queue overflow with policy %d\n", dan_source_name, dan_publisher_getCheckPolicy(ds)); } else if (result == -2) { log_info("%s, DAQ buffer overflow with policy %d\n", dan_source_name, dan_publisher_getCheckPolicy(ds)); } } samplesCounter += n_samples; // Increment total of published sampes offset_ai = (offset_ai + n_samples) % dma->ai.count; // Update offset of memory dma->ai.last_transfer_count = samplesCounter; // Update dma last_transfer_count // Check exit condition. if ((daq_p.daq_len * 1e6 <= (tBase - tBase0))) { retval = xseries_stop_ai(aifd); if (retval) { std::cout << "Stop AI segment failed.\n"; exit (EXIT_FAILURE); } //restart ai segment. tcn_sleep(1e9); // wait retval = xseries_start_ai(aifd); if (retval) { std::cout << "Start AI segment failed.\n"; exit (EXIT_FAILURE); } //debug tcn_sleep(1e8); n_samples = xsereis_ai_dma_samples_in_buffer(dma); cout << "n_samples check : " << n_samples << endl; break; } tBase_old = tBase; } // End of DAQ publish loop. break; } // End of DAN main loop. // ------------------------------------------------------------------------------------------------------------------ // ----- Closing program. // ------------------------------------------------------------------------------------------------------------------ log_info("DAN end of acquisition, closing all resources"); //Closing stream dan_publisher_closeStream(ds); exValue = 0; // Close all channels for (int channel = 0; channel < chan_num; channel++) { close(ai_chan_fd[channel]); } goto END; END: daq_conf_stat = 0; CAInterface_WriteVariable(daq_conf_stat_id, daq_conf_stat_type, &daq_conf_stat); daq_stat = 0; CAInterface_WriteVariable(daq_stat_id, daq_stat_type, &daq_stat); // Destroy CA context CAInterface_Finalize(); // Close pxie6368 if (dma != NULL) { xseries_dma_close(dma); cout << "pxie-6368 dma was clesed.\n"; } close(aifd); // Unpublishing source from DAN API if (ds != NULL) { dan_publisher_unpublishSource(dc, ds); } // Closing DAN API library if (dc != NULL) { dan_closeLibrary(dc); } // Closing TCN library result = tcn_finalize(); if (result != TCN_SUCCESS) { //log_error("Error finalizing TCN lib.\n"); } } // loop end from initialization return (0); }