Files
ec-gn-ja-pcf/EC-GN-JA-PCF/.svn/pristine/8d/8d0751151d2aceecb03307dd3eb27e2956a4c14c.svn-base

640 lines
24 KiB
Plaintext

/******************************************************************************
* $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 <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <error.h>
//#include <xseries-lib.h>
#define float32_t float32_t1
#include <xseries-lib.h>
#undef float32_t
#include <iostream>
#include <dan.h>
#include <time.h>
#include <ca-if.h>
#include <math.h>
#include <tcn.h>
#include <log.h>
// 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:" <<daq_p.daq_smpl_st_dly << endl;
std::cout << "DAQ LENGTH:" << daq_p.daq_len << endl;
std::cout << "PUB DELAY :" << daq_p.daq_pub_dly << endl;
// Configure ai segment and dan parameter by using EPICS PV.
result = reload_daq_conf(&aifd, ai_chan_fd, &daq_p);
if (result < 0) {
log_error("Load DAQ CONF failed.\n");
daq_stat = 3; // 0:Not ready, 1:Waiting trigger, 2:Aquiring, 3:Error
CAInterface_WriteVariable(daq_stat_id, daq_stat_type, &daq_stat);
daq_conf_stat = 0; // 0:Not Ready, 1: Ready
CAInterface_WriteVariable(daq_conf_stat_id, daq_conf_stat_type, &daq_conf_stat);
goto END;
} else {
// All parameters were configured correctly, update readback PV
CAInterface_WriteVariable(daq_smpl_rate_rb_id, daq_smpl_rate_rb_type, &daq_p.daq_smpl_rate);
CAInterface_WriteVariable(daq_mode_rb_id, daq_mode_rb_type, &daq_p.daq_mode);
CAInterface_WriteVariable(daq_smpl_st_dly_rb_id, daq_smpl_st_dly_rb_type, &daq_p.daq_smpl_st_dly);
CAInterface_WriteVariable(daq_len_rb_id, daq_len_rb_type, &daq_p.daq_len);
CAInterface_WriteVariable(daq_pub_dly_rb_id, daq_pub_dly_rb_type, &daq_p.daq_pub_dly);
daq_conf_stat = 1;
CAInterface_WriteVariable(daq_conf_stat_id, daq_conf_stat_type, &daq_conf_stat);
}
// ------------------------------------------------------------------------------------------------------------------
// ----- DAN Publisher.
// ------------------------------------------------------------------------------------------------------------------
// Initialize DAN DataCore
dc = dan_initLibrary();
if (dc == NULL) {
log_error("dan_init failed.\n");
exValue = 1;
goto END;
}
// ----- DMA initialization
dma = xseries_dma_init(pxie6368_0_device_number, 1); // (devid, dma_mode) mode 0:mapping all dma mem, 1:AI only.
if (dma == NULL) {
cout << "Failed to connect to samples buffer.\n go to END.\n";
exValue = -1;
goto END;
}
// Push a new data block into source.
ds = dan_publisher_publishSource(dc, dan_source_name, pxie6368_0_device,
DAN_DAQ_MMAP, dma->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);
}