Files
E502_ADC_BF_PC_companion/main.c

1308 lines
51 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Данный пример представляет из себя консольную программу на языке C,
демонстрирующую работу с модулями E16, L502 и E502 на примере синхронного
ввода данных с АЦП и цифровых линий.
Перед сбором в примере идет поиск модулей, подключенных по интерфейсам PCI-Express и USB,
и предоставляется список для выбора модуля, с которым нужно работать.
Для подключения по Ethernet нужно указать IP-адреса интересующих модулей
в качестве аргументов командной строки при вызове примера, тогда эти адреса
будут добавлены в конец списка выбора модуля.
Например, если интересуют модули с адресами 192.168.1.5 и 192.168.1.6,
то пример можно вызвать:
x502_stream_read 192.168.1.5 E16:192.168.1.6
и две дополнительные строки с этими адресами появятся в списке выбора.
Для указания что ip адрес принадлежит модулю E16, адрес надо указать с префиксом, пример: E16:192.168.1.6
Настройки частот, количества принимаемых данных и т.д. задаются с помощью макросов в
начале программы.
Настройки логических каналов - с помощью таблиц f_channels/f_ch_modes/f_ch_ranges.
Пример выполняет прием блоков данных заданного размера.
Сбор идет до нажатия любой клавиши на Windows или CTRL+C на Linux.
Пример также показывает как выполнять обработку данных и определять начало кадра,
в случае если в X502_ProcessData() передается не целое число кадров.
Данный пример содержит проект для Visual Studio 2008, а также может быть собран
gcc в Linux или mingw в Windows через makefile или с помощью cmake (подробнее
в комментариях в соответствующих файлах).
Для того чтобы собрать проект в Visual Studio, измените путь к заголовочным файлам
(Проект (Project) -> Свойства (Properties) -> Свойства конфигурации (Configuration Properties)
-> С/С++ -> Общие (General) -> Дополнительные каталоги включения (Additional Include Directories))
на тот, где у вас лежат заголовочный файлы x502api.h, l502api.h и e502api.h и измените путь к библиотекам
(Проект (Project) -> Свойства (Properties) -> Свойства конфигурации (Configuration Properties) ->
Компановщик (Linker) -> Общие (General) -> Дополнительные катологи библиотек (Additional Library Directories)).
Внимание!!: Если Вы собираете проект под Visual Studio и взяли проект с сайта (а не из SDK),
то для корректного отображения русских букв в программе нужно изменить кодировку
или указать сохранение с сигнатурой кодировки для UTF-8:
выберите Файл (File) -> Дополнительные параметры сохранения (Advanced Save Options)...
и в поле Кодировка (Encoding) выберите Юникод (UTF8, с сигнатурой)/Unicode (UTF-8 with signature)
и сохраните изменения в файле.
*/
//#include "dislin.h" //graphics library
#include <time.h> //for namigs of saved files
#include <l502api.h>
#include "e502api.h"
//#include "dev_funcs.h"
#ifdef _WIN32
#include <locale.h>
#include <conio.h>
#else
#include <signal.h>
#include <unistd.h>
#include <string.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include "l502_BF_enums.h"
#include "l502_fpga_regs.h"
typedef enum {
unknown = 0x00,
ADC_data =0x01,
USR_data,
DIN_data,
FFT_val_re,
FFT_val_im,
FFT_val_f,
LFSM_val_ON,
LFSM_val_OFF,
LFSM_val_X,
USR_msg,
LFSM_started,
} BF_msg_parsed_type;
typedef struct BF_msg_parsed_typedef {
BF_msg_parsed_type type;
uint8_t chan;
uint8_t flags;
uint8_t raw_header;
uint32_t raw_data;
uint32_t raw_value;
int value_int;
double value;
};
typedef struct LFSM_typedef{ //Linear Frequency Sweep Modulation
int * X;
int * Y_on; //intensity while Mach-Zander modulator is "opened"
int * Y_off;//intensity while Mach-Zander modulator is "closed"
int ID;
uint8_t rcv_state;
int max_N; //max number of data points
int curr_I;
uint8_t description;
};
typedef struct FFT_res_typedef{
int * vals_Re;
int * vals_Im;
int * vals_F;
int values_N;
uint8_t rcv_state;
int max_N;
//int timestamp;
int ID;
uint8_t description;
int curr_I; //current index of value and corresponding frequency
} ;
const int FFT_length = 1000;
// количество используемых логических каналов //
#define ADC_LCH_CNT 4
// частота сбора АЦП в Гц//
#define ADC_FREQ 2000000
// частота кадров (на логический канал). При ADC_FREQ/ADC_LCH_CNT - межкадровой задержки нет //
#define ADC_FRAME_FREQ (ADC_FREQ/ADC_LCH_CNT)
// частота синхронного ввода в Гц//
#define DIN_FREQ 500000
#define TCP_CONNECTION_TOUT 5000
// сколько отсчетов считываем за блок //
#define READ_BLOCK_SIZE 4096*200
// таймаут на прием блока (мс) //
#define READ_TIMEOUT 2000
#define BF_CMD_USER_MULT 0x8001U
// номера используемых физических каналов //
static uint32_t f_channels[ADC_LCH_CNT] = {0, 0, 1, 0};
// режимы измерения для каналов //
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_COMM, X502_LCH_MODE_COMM,X502_LCH_MODE_COMM,X502_LCH_MODE_COMM};
// диапазоны измерения для каналов //
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_1, X502_ADC_RANGE_1,X502_ADC_RANGE_1,X502_ADC_RANGE_1};
// признак необходимости завершить сбор данных //
static int f_out = 0;
#ifndef _WIN32
// Обработчик сигнала завершения для Linux //
static void f_abort_handler(int sig) {
f_out = 1;
}
#endif
char const *DEV_E502 = "E502";
char const *DEV_E16 = "E16";
typedef struct {
uint32_t ip_addr;
char const *devname;
} ip_dev_list_t;
/* Функция находит все подключенные модули по интерфейсам PCI-Express и USB и
* сохраняет записи о этих устройствах в выделенный массив.
* Также создаются записи по переданным IP-адресам модулей и добавляются в конец
* массива.
* Указатель на выделенный массив, который должен быть потом очищен, сохраняется
* в pdevrec_list, а количество действительных элементов (память которых должна
* быть в дальнейшем освобождена с помощью X502_FreeDevRecordList()) возвращается
* как результат функции */
static uint32_t f_get_all_devrec(t_x502_devrec **pdevrec_list, ip_dev_list_t *ip_dev_list, unsigned ip_cnt) {
int32_t fnd_devcnt = 0;
uint32_t pci_devcnt = 0;
uint32_t usb_devcnt = 0;
uint32_t e16_usb_devcnt = 0;
t_x502_devrec *rec_list = NULL;
// получаем количество подключенных устройств по интерфейсам PCI и USB //
L502_GetDevRecordsList(NULL, 0, 0, &pci_devcnt);
E502_UsbGetDevRecordsList(NULL, 0, 0, &usb_devcnt);
// E16_UsbGetDevRecordsList(NULL, 0, 0, &e16_usb_devcnt);
if ((pci_devcnt+usb_devcnt + e16_usb_devcnt + ip_cnt) != 0) {
// выделяем память для массива для сохранения найденного количества записей //
rec_list = malloc((pci_devcnt + usb_devcnt +e16_usb_devcnt + ip_cnt) * sizeof(t_x502_devrec));
if (rec_list != NULL) {
unsigned i;
// получаем записи о модулях L502, но не больше pci_devcnt //
if (pci_devcnt!=0) {
int32_t res = L502_GetDevRecordsList(&rec_list[fnd_devcnt], pci_devcnt, 0, NULL);
if (res >= 0) {
fnd_devcnt += res;
}
}
// добавляем записи о модулях E502, подключенных по USB, в конец массива //
if (usb_devcnt!=0) {
int32_t res = E502_UsbGetDevRecordsList(&rec_list[fnd_devcnt], usb_devcnt, 0, NULL);
if (res >= 0) {
fnd_devcnt += res;
}
}
// добавляем записи о модулях E16, подключенных по USB, в конец массива //
// if (e16_usb_devcnt!=0) {
// int32_t res = E16_UsbGetDevRecordsList(&rec_list[fnd_devcnt], e16_usb_devcnt, 0, NULL);
// if (res >= 0) {
// fnd_devcnt += res;
// }
// }
// создаем записи для переданного массива ip-адресов //
}
}
if (fnd_devcnt != 0) {
// если создана хотя бы одна запись, то сохраняем указатель на выделенный массив //
*pdevrec_list = rec_list;
} else {
*pdevrec_list = NULL;
free(rec_list);
}
return fnd_devcnt;
}
static t_x502_hnd f_dev_select_open(int argc, char** argv) {
t_x502_hnd hnd = NULL;
uint32_t fnd_devcnt,i, dev_ind;
t_x502_devrec *devrec_list = NULL;
ip_dev_list_t *ip_dev_list = NULL;
uint32_t ip_cnt = 0;
// если есть аргументы командной строки, то предполагаем, что это могут быть
// ip-адреса интересующих устройств. //
if (argc > 1) {
ip_dev_list = malloc((argc - 1) * sizeof(ip_dev_list[0]));
if (ip_dev_list == NULL) {
fprintf(stderr, "Ошибка выделения памяти!\n");
} else {
for (i=1; (int)i < argc; i++) {
int a[4];
if (sscanf(argv[i], "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3])==4) {
ip_dev_list[ip_cnt].devname = DEV_E502;
ip_dev_list[ip_cnt++].ip_addr = ((a[0] & 0xFF) << 24) |
((a[1] & 0xFF) << 16) |
((a[2] & 0xFF) << 8) |
(a[3] & 0xFF);
} else
if (sscanf(argv[i], "E16:%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3])==4) {
ip_dev_list[ip_cnt].devname = DEV_E16;
ip_dev_list[ip_cnt++].ip_addr = ((a[0] & 0xFF) << 24) |
((a[1] & 0xFF) << 16) |
((a[2] & 0xFF) << 8) |
(a[3] & 0xFF);
}
}
}
}
// получаем список модулей для выбора //
fnd_devcnt = f_get_all_devrec(&devrec_list, ip_dev_list, ip_cnt);
if (fnd_devcnt == 0) {
printf("Не найдено ни одного модуля\n");
} else {
// выводим информацию по списку модулей //
printf("Доступны следующие модули:\n");
for (i=0; i < fnd_devcnt; i++) {
printf("Модуль № %d: %s, %-9s", i, devrec_list[i].devname,
devrec_list[i].iface == X502_IFACE_PCI ? "PCI/PCIe" :
devrec_list[i].iface == X502_IFACE_USB ? "USB" :
devrec_list[i].iface == X502_IFACE_ETH ? "Ethernet" : "?");
// при подключении по сети по IP-адресу серийный номер можно узнать
// только после открытия соединения. При этом поле location
// содержит строку с описанием адреса устройства //
if (devrec_list[i].iface != X502_IFACE_ETH) {
printf("Сер. номер: %s\n", devrec_list[i].serial);
} else {
printf("Адрес: %s\n", devrec_list[i].location);
}
}
// выбираем нужный по введенному номеру модуля по порядку с клавиатуры //
//printf("Введите номер модуля, с которым хотите работать (от 0 до %d)\n", fnd_devcnt-1);
//fflush(stdout);
//scanf("%d", &dev_ind);
dev_ind = 0;
if (dev_ind >= fnd_devcnt) {
printf("Неверно указан номер модуля...\n");
} else {
// если ввели номер правильно - создаем описатель //
hnd = X502_Create();
if (hnd==NULL) {
fprintf(stderr, "Ошибка создания описателя модуля!");
} else {
// устанавливаем связь с модулем по записи //
int32_t err = X502_OpenByDevRecord(hnd, &devrec_list[dev_ind]);
if (err != X502_ERR_OK) {
fprintf(stderr, "Ошибка установления связи с модулем: %s!", X502_GetErrorString(err));
X502_Free(hnd);
hnd = NULL;
}
}
}
// освобождение ресурсов действительных записей из списка //
X502_FreeDevRecordList(devrec_list, fnd_devcnt);
// очистка памяти самого массива //
free(devrec_list);
}
// освобождаем выделенный массив под IP-адреса (если был выделен) //
free(ip_dev_list);
return hnd;
}
// настройка параметров модуля //
int32_t f_setup_params(t_x502_hnd hnd) {
int32_t err = X502_ERR_OK, i;
// устанавливаем параметры логической таблицы АЦП //
err = X502_SetLChannelCount(hnd, ADC_LCH_CNT);
for (i=0; (i < ADC_LCH_CNT) && (err == X502_ERR_OK); i++)
err = X502_SetLChannel(hnd, i, f_channels[i], f_ch_modes[i], f_ch_ranges[i], 0);
// // устанавливаем частоты ввода для АЦП и цифровых входов //
// if (err == X502_ERR_OK) {
// double f_adc = ADC_FREQ, f_frame = ADC_FRAME_FREQ, f_din = DIN_FREQ;
// err = X502_SetAdcFreq(hnd, &f_adc, &f_frame);
// if (err == X502_ERR_OK)
// err = X502_SetDinFreq(hnd, &f_din);
// if (err == X502_ERR_OK) {
// // выводим реально установленные значения - те что вернули функции //
// printf("Установлены частоты:\n Частота сбора АЦП = %0.0f\n"
// " Частота на лог. канал = %0.0f\n Частота цифрового ввода = %0.0f\n",
// f_adc, f_frame, f_din);
// }
// }
//double f_din = DIN_FREQ;
//err = X502_SetDinFreq(hnd, &f_din);
//printf();
//set ADC sample frequency from internal generator with frequency 2 MHz
X502_SetRefFreq(hnd, X502_REF_FREQ_2000KHZ);
//=======================================================//
//for real work with Radar
//X502_SetSyncMode(hnd, X502_SYNC_DI_SYN1_FALL);
//X502_SetSyncStartMode(hnd, X502_SYNC_DI_SYN2_RISE); //start ADC sampling by external trigger
//=======================================================//
//for debug purposes:
X502_SetRefFreq(hnd, X502_REF_FREQ_2000KHZ);
X502_SetSyncMode(hnd, X502_SYNC_DI_SYN1_FALL);
//X502_SetSyncMode(hnd, X502_SYNC_INTERNAL);
//X502_SetSyncStartMode(hnd, X502_SYNC_INTERNAL); //start ADC samping after executing X502_StreamsStart()
X502_SetSyncStartMode(hnd, X502_SYNC_DI_SYN2_RISE); //start ADC sampling by external trigger
// записываем настройки в модуль //
if (err == X502_ERR_OK)
err = X502_Configure(hnd, 0);
// разрешаем синхронные потоки //
if (err == X502_ERR_OK) {
err = X502_StreamsEnable(hnd, X502_STREAM_ADC);
}
return err;
}
void uin32_t_to_bin(uint32_t val, char* string){
for (int i = 0; i < 8; ++i){
if (val & (0b1 << i)){
string[i] = '1';
}else{
string[i] = '0';
}
}
}
uint32_t BF_exec_cmd_simple(t_x502_hnd hnd, uint16_t cmd_code, uint32_t cmd_par, uint8_t verbosity_lvl){
uint32_t BF_cmd_receive_code = 0;
//uint16_t cmd_code = 0x8001; //read ADC data
//uint32_t cmd_par = 87;
const uint32_t snd_data[1] = {0,};
uint32_t snd_size = 0;
uint32_t rcv_data[100] = {0,};
uint32_t rcv_size = 100;
uint32_t tout = 1;
uint32_t recvd_size = 0;
//*/
if (verbosity_lvl == 2){
printf("\n\n");
printf("TX cmd_code: 0x%X\n", cmd_code);
printf("TX tout: %u\n", tout);
printf("TX par: %u\n", cmd_par);
printf("TX snd_data size: %u\n", snd_size);
for (int i = 0; i < snd_size; ++i){
printf(" 0x%0X,", snd_data[i]);
}
printf("\n");
printf("TX rcv_size: %u\n", rcv_size);
}
BF_cmd_receive_code = X502_BfExecCmd (hnd,
cmd_code,
cmd_par,
snd_data,
snd_size,
rcv_data,
rcv_size,
tout,
&recvd_size);
if (verbosity_lvl == 2){
printf("\n======================\n\n");
printf("RX received code dec: %u hex: 0x%3X, %d\n", BF_cmd_receive_code, BF_cmd_receive_code,BF_cmd_receive_code);
printf("RX recvd_size: %u\n", recvd_size);
printf("RX received_data:\n" );
for (int i = 0; i < recvd_size; ++i){
printf(" 0x%0X,", rcv_data[i]);
}
printf("\n\n\n\n");
}
if (verbosity_lvl == 1){
printf("\ncmd: 0x%0X, par: %d, rcv_code: %d, result[0]: %d (0x%0X) , result_L: %d\n", cmd_code, cmd_par, BF_cmd_receive_code, rcv_data[0],rcv_data[0], recvd_size);
}
return BF_cmd_receive_code;
}
uint32_t BF_exec_cmd_with_arr(t_x502_hnd hnd, uint16_t cmd_code, uint32_t cmd_par, uint32_t* snd_data, uint32_t snd_data_size, uint8_t verbosity_lvl){
uint32_t BF_cmd_receive_code = 0;
//uint16_t cmd_code = 0x8001; //read ADC data
//uint32_t cmd_par = 87;
//const uint32_t snd_data[1] = {0,};
//uint32_t snd_data_size = 0;
uint32_t rcv_data[100] = {0,};
uint32_t rcv_size = 100;
uint32_t tout = 1;
uint32_t recvd_size = 0;
//*/
if (verbosity_lvl == 2){
printf("\n\n");
printf("TX cmd_code: 0x%X\n", cmd_code);
printf("TX tout: %u\n", tout);
printf("TX par: %u\n", cmd_par);
printf("TX snd_data size: %u\n", snd_data_size);
for (int i = 0; i < snd_data_size; ++i){
printf(" 0x%0X,", snd_data[i]);
}
printf("\n");
printf("TX rcv_size: %u\n", rcv_size);
}
BF_cmd_receive_code = X502_BfExecCmd (hnd,
cmd_code,
cmd_par,
snd_data,
snd_data_size,
rcv_data,
rcv_size,
tout,
&recvd_size);
if (verbosity_lvl == 2){
printf("\n======================\n\n");
printf("RX received code dec: %u hex: 0x%3X, %d\n", BF_cmd_receive_code, BF_cmd_receive_code,BF_cmd_receive_code);
printf("RX recvd_size: %u\n", recvd_size);
printf("RX received_data:\n" );
for (int i = 0; i < recvd_size; ++i){
printf(" 0x%0X,", rcv_data[i]);
}
printf("\n\n\n\n");
}
if (verbosity_lvl == 1){
printf("\n");
printf("cmd: 0x%0X, par: %d, rcv_code: %d, result[0]: %d (0x%0X) , result_L: %d\n", cmd_code, cmd_par, BF_cmd_receive_code, rcv_data[0],rcv_data[0], recvd_size);
printf(" TX arr: ");
for (int i = 0; i < snd_data_size; ++i){
printf(" 0x%0X,", snd_data[i]);
}
printf("\n");
printf(" RX arr: ");
int values_in_line = 0;
for (int i = 0; i < recvd_size; ++i){
printf(" 0x%08X,", rcv_data[i]);
++values_in_line;
if (values_in_line == 10){
printf("\n");
values_in_line = 0;
}
}
printf("\n");
}
if (verbosity_lvl == 3){
printf("\n");
printf("cmd: 0x%0X, par: %d, rcv_code: %d, result[0]: %d (0x%0X) , result_L: %d\n", cmd_code, cmd_par, BF_cmd_receive_code, rcv_data[0],rcv_data[0], recvd_size);
printf(" TX arr: ");
for (int i = 0; i < snd_data_size; ++i){
printf(" 0x%0X,", snd_data[i]);
}
printf("\n");
printf(" RX arr: ");
int values_in_line = 0;
for (int i = 0; i < recvd_size; ++i){
char bin_str_val[9] = {0,};
uin32_t_to_bin(rcv_data[i], bin_str_val);
//printf(" 0x%0X,", rcv_data[i]);
printf(" 0b%s,", bin_str_val);
++values_in_line;
if (values_in_line == 10){
printf("\n");
values_in_line = 0;
}
}
printf("\n");
}
return BF_cmd_receive_code;
}
long int X502_Raw_User_Data_Parser(uint32_t *inp_buff, uint32_t inp_values_N,
double *adc_data, uint32_t *adc_chans_N, uint32_t *adc_readouts_N,
struct LFSM_typedef ** LFSM_data, struct LFSM_typedef ** LFSM_data_done,
struct FFT_res_typedef ** FFT_data, struct FFT_res_typedef ** FFT_data_done){
long int return_res = 0;
//printf("inp_values_N: %d, adc_chans_N: %d, adc_readouts_N: %d, user_data_chans_N: %d, user_data_readouts_N: %d\n", inp_values_N, adc_chans_N, adc_readouts_N, user_data_chans_N, user_data_readouts_N);
/*
for (int I = 0; I < adc_readouts_N; ++I){
adc_data[I] = 0.0;
}
for (int I = 0; I < user_data_readouts_N; ++I){
user_data[I] = 0.0;
}
*/
/*
(*(*(*(*(*(*(*(*FFT_data))))))))-> values_N = 0;
(*FFT_data)-> ID = 0;
(*FFT_data)-> description = 0;
(*FFT_data)-> curr_I = 0; //current index of value and corresponding frequency
for (int I = 0; I < adc_readouts_N; ++I){
(*FFT_data)->vals_Re [I] = 0;
(*FFT_data)-> vals_Im [I] = 0;
(*FFT_data)-> vals_F [I] = 0;
}
*/
struct BF_msg_parsed_typedef BF_msg;
for (uint32_t inp_buff_I = 0; inp_buff_I < inp_values_N; ++inp_buff_I){
BF_msg.raw_data = inp_buff[inp_buff_I];
BF_msg.raw_header = (uint8_t) (BF_msg.raw_data >> 24);
BF_msg.flags = 0;
BF_msg.type = 0;
BF_msg.chan = 0;
//BF_msg.raw_data = 0;
BF_msg.raw_value = BF_msg.raw_data & 0xFFFFFF;
BF_msg.value_int = 0;
BF_msg.value = 0;
if (BF_msg.raw_header & 0b10000000){ // ADC data
BF_msg.type = ADC_data;
BF_msg.chan = BF_msg.raw_header & 0b00001111;
BF_msg.flags = (BF_msg.raw_header >> 4);
BF_msg.value_int = BF_msg.raw_value & 0x7FFFFF;
if (BF_msg.raw_value & 0x800000){ // if first bit is nonzero -- it is negative value
BF_msg.value_int *= -1;
}
BF_msg.value = 0.0;// TODO conversion from int to double with respect to ADC channel voltage range
}else if (BF_msg.raw_header & 0b01000000){ //user data (FFT,)
if (BF_msg.raw_header & 0x0F == FFT_val_re){
BF_msg.type = FFT_val_re;
}else if (BF_msg.raw_header & 0x0F == FFT_val_im){
BF_msg.type = FFT_val_im;
}else if (BF_msg.raw_header & 0x0F == FFT_val_f){
BF_msg.type = FFT_val_f;
}else{
BF_msg.type = USR_data;
}
BF_msg.chan = 0;
//BF_msg.chan == BF_msg.raw_header & 0b00111111;
BF_msg.value_int = BF_msg.raw_value & 0x7FFFFF;
if (BF_msg.raw_value & 0x800000){ // if first bit is nonzero -- it is negative value
BF_msg.value_int *= -1;
}
if (! (((*FFT_data)-> rcv_state) & (0b1 << 7 ))){
if (BF_msg.type == FFT_val_re){
(*FFT_data)->rcv_state |= 0b1 << 0;
(*FFT_data)-> vals_Re[(*FFT_data)->curr_I] = BF_msg.value_int;
}else if (BF_msg.type == FFT_val_im){
(*FFT_data)->rcv_state |= 0b1 << 1;
(*FFT_data)-> vals_Im[(*FFT_data)->curr_I] = BF_msg.value_int;
}else if (BF_msg.type == FFT_val_f){
(*FFT_data)->rcv_state |= 0b1 << 2;
(*FFT_data)-> vals_F[(*FFT_data)->curr_I] = BF_msg.value_int;
}
if ((*FFT_data)-> rcv_state == 0b111){
(*FFT_data)-> rcv_state = 0;
++(*FFT_data)->curr_I;
if ((*FFT_data)->curr_I >= (*FFT_data)->max_N){
(*FFT_data)-> rcv_state |= 0b1 << 7;
printf("received more FFT values than allowed. <========================== ERROR\n");
}
}
}
}else if (BF_msg.raw_header & 0b01100000){ //user data LFSM)
if (BF_msg.raw_header & 0x0F == LFSM_val_ON){
BF_msg.type = LFSM_val_ON;
}else if (BF_msg.raw_header & 0x0F == LFSM_val_OFF){
BF_msg.type = LFSM_val_OFF;
}else if (BF_msg.raw_header & 0x0F == LFSM_val_X){
BF_msg.type = LFSM_val_X;
}else{
BF_msg.type = USR_data;
}
BF_msg.chan = 0;
//BF_msg.chan == BF_msg.raw_header & 0b00111111;
BF_msg.value_int = BF_msg.raw_value & 0x7FFFFF;
if (BF_msg.raw_value & 0x800000){ // if first bit is nonzero -- it is negative value
BF_msg.value_int *= -1;
}
if (! (((*LFSM_data) -> rcv_state) & (0b1 << 7 ))){
if (BF_msg.type == LFSM_val_ON){
(*LFSM_data) ->rcv_state |= 0b1 << 0;
(*LFSM_data) -> Y_on[(*LFSM_data) ->curr_I] = BF_msg.value_int;
}else if (BF_msg.type == LFSM_val_OFF){
(*LFSM_data) ->rcv_state |= 0b1 << 1;
(*LFSM_data) -> Y_off[(*LFSM_data) ->curr_I] = BF_msg.value_int;
}else if (BF_msg.type == LFSM_val_X){
(*LFSM_data) ->rcv_state |= 0b1 << 2;
(*LFSM_data) -> X[(*LFSM_data) ->curr_I] = BF_msg.value_int;
}
if ((*LFSM_data) -> rcv_state == 0b011){
(*LFSM_data) -> rcv_state = 0;
++(*LFSM_data) ->curr_I;
if ((*LFSM_data) ->curr_I >= (*LFSM_data) ->max_N){
(*LFSM_data) -> rcv_state |= 0b1 << 7;
printf("received more LFSM values than allowed. <========================== ERROR\n");
}
}
}
}else if (BF_msg.raw_header & 0b01100000 == 0b01100000){ //user message
BF_msg.type = USR_msg;
BF_msg.chan = BF_msg.raw_header & 0b00011111;
BF_msg.value_int = BF_msg.raw_value & 0x7FFFFF;
if (BF_msg.raw_value & 0x800000){ // if first bit is nonzero -- it is negative value
BF_msg.value_int *= -1;
}
printf("Received USR msg: 0x%06H\n", BF_msg.raw_value);
//}else if (raw_header & 0b01100000 == 0b01100000){ //
}else if (BF_msg.raw_header & 0b01101010 == 0b01101010){ //new Frequency Sweep Started. So save old (*FFT_data)to FFT_data_done and start working with new FFT_data
//FFT
printf("Received: new LFSM started. msg payload: 0x%06H\n", BF_msg.raw_value);
(*FFT_data)-> rcv_state = 0xFF; // data filled
int FFT_last_ID = (*FFT_data)-> ID;
int FFT_points_max_N = (*FFT_data)-> max_N;
struct FFT_res_typedef ** FFT_tmp = *FFT_data_done;
*FFT_data_done = *FFT_data;
*FFT_data = *FFT_tmp;
//(*FFT_data)-> values_N = 0;
(*FFT_data)-> rcv_state = 0;
(*FFT_data)-> ID = FFT_last_ID + 1;
(*FFT_data)-> max_N = FFT_points_max_N;
(*FFT_data)-> description = 0;
(*FFT_data)-> curr_I = 0; //current index of value and corresponding frequency
for (int I = 0; I < (*FFT_data)-> max_N; ++I){
(*FFT_data)->vals_Re [I] = 0;
(*FFT_data)-> vals_Im [I] = 0;
(*FFT_data)-> vals_F [I] = 0;
}
free(FFT_tmp);
free(FFT_last_ID);
free(FFT_points_max_N);
//LFSM
(*LFSM_data) -> rcv_state = 0xFF; // data filled
int LFSM_last_ID = (*LFSM_data) -> ID;
int LFSM_points_max_N = (*LFSM_data) -> max_N;
struct LFSM_typedef ** LFSM_tmp = *LFSM_data_done;
*LFSM_data_done = *LFSM_data;
*LFSM_data = *LFSM_tmp;
//(*LFSM_data) -> values_N = 0;
(*LFSM_data) -> rcv_state = 0;
(*LFSM_data) -> ID = LFSM_last_ID + 1;
(*LFSM_data) -> max_N = LFSM_points_max_N;
(*LFSM_data) -> description = 0;
(*LFSM_data) -> curr_I = 0; //current index of value and corresponding frequency
for (int I = 0; I < (*LFSM_data) -> max_N; ++I){
(*LFSM_data) -> X [I] = 0;
(*LFSM_data) -> Y_on [I] = 0;
(*LFSM_data) -> Y_off [I] = 0;
}
free(LFSM_tmp);
free(LFSM_last_ID);
free(LFSM_points_max_N);
}else{
BF_msg.type = unknown;
BF_msg.chan = 0;
BF_msg.value_int = BF_msg.raw_value & 0x7FFFFF;
if (BF_msg.raw_value & 0x800000){ // if first bit is nonzero -- it is negative value
BF_msg.value_int *= -1;
}
}
}
}
int main(int argc, char** argv) {
int32_t err = X502_ERR_OK;
uint32_t ver;
t_x502_hnd hnd = NULL;
#ifndef _WIN32
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
// В ОС Linux устанавливаем свой обработчик на сигнал закрытия,
// чтобы завершить сбор корректно //
sa.sa_handler = f_abort_handler;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);
#endif
#ifdef _WIN32
// для вывода русских букв в консоль для ОС Windows в CP1251 без перевода в OEM //
setlocale(LC_CTYPE, "");
#endif
// получаем версию библиотеки //
ver = X502_GetLibraryVersion();
printf("Версия библиотеки: %d.%d.%d\n", (ver >> 24)&0xFF, (ver>>16)&0xFF, (ver>>8)&0xFF);
//*
uint32_t inp_buff[2] = {0,};
double adc_data[1] = {0,};
double user_data[1] = {0,};
uint32_t inp_values_N = 0;
uint32_t adc_chans_N = 1;
uint32_t adc_readouts_N= 2;
uint32_t user_data_chans_N = 3;
uint32_t user_data_readouts_N = 4;
//uint32_t FFT_data_readouts_N = 5;
struct FFT_res_typedef FFT_res_tmp;
FFT_res_tmp.max_N = 1000;
FFT_res_tmp.vals_Re = malloc(FFT_res_tmp.max_N * sizeof(int));
FFT_res_tmp.vals_Im = malloc(FFT_res_tmp.max_N *sizeof(int));
FFT_res_tmp.vals_F = malloc(FFT_res_tmp.max_N * sizeof(int));
FFT_res_tmp.curr_I = 0;
FFT_res_tmp.description = 0;
FFT_res_tmp.rcv_state = 0;
FFT_res_tmp.ID = 0;
struct FFT_res_typedef FFT_res;
FFT_res.ID = 0;
struct LFSM_typedef LFSM_res_tmp;
LFSM_res_tmp.max_N = 1000;
LFSM_res_tmp.X = malloc(LFSM_res_tmp.max_N * sizeof(int));
LFSM_res_tmp.Y_on = malloc(LFSM_res_tmp.max_N *sizeof(int));
LFSM_res_tmp.Y_off = malloc(LFSM_res_tmp.max_N * sizeof(int));
LFSM_res_tmp.curr_I = 0;
LFSM_res_tmp.description = 0;
LFSM_res_tmp.rcv_state = 0;
LFSM_res_tmp.ID = 0;
struct LFSM_typedef LFSM_res;
LFSM_res.ID = 0;
/*
X502_Raw_User_Data_Parser(inp_buff, inp_values_N,
adc_data, adc_chans_N, adc_readouts_N,
&LFSM_res_tmp, &LFSM_res,
&FFT_res_tmp, &FFT_res);
*/
//*/
/*
X502_Raw_User_Data_Parser(inp_buff, inp_values_N,
adc_data, adc_chans_N, adc_readouts_N,
user_data, user_data_chans_N, user_data_readouts_N);
*/
////******* Получение списка устройств и выбор, с каким будем работать *****************//
hnd = f_dev_select_open(argc, argv);
////******************************* Работа с модулем *************************//
// если успешно выбрали модуль и установили с ним связь - продолжаем работу //
if (hnd != NULL) {
// получаем информацию //
t_x502_info info;
err = X502_GetDevInfo(hnd, &info);
if (err != X502_ERR_OK) {
fprintf(stderr, "Ошибка получения серийного информации о модуле: %s!", X502_GetErrorString(err));
} else {
// выводим полученную информацию //
printf("Установлена связь со следующим модулем:\n");
printf(" Серийный номер : %s\n", info.serial);
printf(" Наличие ЦАП : %s\n", info.devflags & X502_DEVFLAGS_DAC_PRESENT ? "Да" : "Нет");
printf(" Наличие BlackFin : %s\n", info.devflags & X502_DEVFLAGS_BF_PRESENT ? "Да" : "Нет");
printf(" Наличие гальваноразвязки: %s\n", info.devflags & X502_DEVFLAGS_GAL_PRESENT ? "Да" : "Нет");
printf(" Индустриальное исп. : %s\n", info.devflags & X502_DEVFLAGS_INDUSTRIAL ? "Да" : "Нет");
printf(" Наличие интерф. PCI/PCIe: %s\n", info.devflags & X502_DEVFLAGS_IFACE_SUPPORT_PCI ? "Да" : "Нет");
printf(" Наличие интерф. USB : %s\n", info.devflags & X502_DEVFLAGS_IFACE_SUPPORT_USB ? "Да" : "Нет");
printf(" Наличие интерф. Ethernet: %s\n", info.devflags & X502_DEVFLAGS_IFACE_SUPPORT_ETH ? "Да" : "Нет");
printf(" Версия ПЛИС : %d.%d\n", (info.fpga_ver >> 8) & 0xFF, info.fpga_ver & 0xFF);
printf(" Версия PLDA : %d\n", info.plda_ver);
if (info.mcu_firmware_ver != 0) {
printf(" Версия прошивки ARM : %d.%d.%d.%d\n",
(info.mcu_firmware_ver >> 24) & 0xFF,
(info.mcu_firmware_ver >> 16) & 0xFF,
(info.mcu_firmware_ver >> 8) & 0xFF,
info.mcu_firmware_ver & 0xFF);
}
}
X502_StreamsStop(hnd); //stop all streams. We need it because we can connect to module that is already sampling. And sampling blocks any setup trials.
if (err == X502_ERR_OK) {
// настраиваем параметры модуля //
err = f_setup_params(hnd);
if (err != X502_ERR_OK)
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
}
char* BF_firmware_filename = "l502-BFfirmware0.ldr";
printf("loading Blackfin firmware file: %s\n", BF_firmware_filename);
uint32_t bf_firmware_load_state = X502_BfLoadFirmware(hnd, BF_firmware_filename); //load firmware from l502-BFfirmware0.ldr file to BlackFin
printf("load state: %u \n", bf_firmware_load_state);
printf("setup module again");
if (err == X502_ERR_OK) {
// настраиваем параметры модуля //
err = f_setup_params(hnd);
if (err != X502_ERR_OK)
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
}
uint32_t BF_cmd_receive_code = 0;
/*//working executing remote cmd
uint16_t cmd_code = 3;
uint32_t par = 87;
const uint32_t snd_data[] = {1,1,2,2,3,4,5,56,67,23,1};
uint32_t snd_size = 11;
uint32_t rcv_data[13] = {0,};
uint32_t rcv_size = 13;
uint32_t tout = 1;
uint32_t recvd_size = 0;
*/
printf("\n\n\n");
//setup ADC:
//t_x502_hnd hnd, uint16_t cmd_code, uint32_t cmd_arg, uint8_t verbosity_lvl
//BF_exec_cmd_simple(hnd, L502_BF_CMD_CODE_GET_PARAM, 87, 2);
//BF_exec_cmd_simple(hnd, L502_BF_CMD_CODE_GET_PARAM, 87, 1);
//BF_exec_cmd_simple(hnd, L502_BF_CMD_CODE_GET_PARAM, 87, 0);
//BF_exec_cmd_simple(hnd, L502_BF_USR_CMD_CODE_ECHO, 87, 1);
//BF_exec_cmd_simple(hnd, L502_BF_USR_CMD_CODE_DATA_ECHO, 87, 1);
//BF_exec_cmd_with_arr(t_x502_hnd hnd, uint16_t cmd_code, uint32_t cmd_par, uint32_t* snd_data, uint32_t snd_data_size, uint8_t verbosity_lvl);
//uint32_t tx_data[] = {0,1,2,3,4,53,4,2,2,1,0};
//uint32_t tx_data_size = 11;
//BF_exec_cmd_with_arr(hnd, L502_BF_USR_CMD_CODE_DATA_ECHO, 328, tx_data, tx_data_size, 2);
//BF_exec_cmd_with_arr(hnd, L502_BF_USR_CMD_CODE_DATA_ECHO, 328, tx_data, tx_data_size, 1);
//setup ADC:
uint32_t tx_data[] = {0,1,2,3,4,53,4,2,2,1,0};
//set ADC Установка значения опорной частоты
uint32_t tx_data_size = 1;
tx_data[0] = 2000000; //valid values: 2000000, 1500000 Hz
//printf("\n");
//BF_exec_cmd_with_arr(hnd, L502_BF_CMD_CODE_SET_PARAM, L502_BF_PARAM_REF_FREQ_SRC, tx_data, tx_data_size, 2);
//printf("run tests\n");
//BF_exec_cmd_simple(hnd, 0x8010, 17, 1); //test SPORT0
//BF_exec_cmd_simple(hnd, 0x8003U, 0, 1);
//printf("setup ADC\n");
//BF_exec_cmd_with_arr(hnd, 0x8003U, 0, NULL, 0, 1); //setup ADC. Values in array are configuring functions return codes
//some delay to allow ADC to acquire some data
//printf("L502_REGS_IOHARD_OUTSWAP_BFCTL reg:");
//BF_exec_cmd_simple(hnd, 0x8006, L502_REGS_IOHARD_OUTSWAP_BFCTL, 1); //reaf fpga reg
uint32_t streams_enable_Err = 0;
streams_enable_Err = X502_StreamsEnable(hnd, X502_STREAM_ADC | X502_STREAM_DIN );
printf("Streams start err: %d \n", streams_enable_Err);
uint32_t streams_start_Err = 0;
streams_start_Err = X502_StreamsStart(hnd);
printf("Streams start err: %d \n", streams_start_Err);
printf("\n");
//printf("start streams sampling\n");
//BF_exec_cmd_with_arr(hnd, 0x8004U, 0, NULL, 0, 1); //setup and start streams
uint32_t waiting_cnt = 1;
waiting_cnt = 100000;
printf("\nwaiting %d ...", waiting_cnt);
while(--waiting_cnt){;}
//for(uint32_t timeout = 100000000; timeout; --timeout){;}
printf("done\n");
printf("\n\nget counters of calls of SPORT_RX, SPORT_TX, HDMA_RX, HDMA_TX\n");
BF_exec_cmd_with_arr(hnd, 0x8005U, 100, NULL, 0, 1);
printf("\n\nget a some data made by sport isr handler\n");
BF_exec_cmd_with_arr(hnd, 0x8006U, 100, NULL, 0, 1);
//BF_exec_cmd_with_arr(hnd, 0x8006U, 100, NULL, 0, 3);
printf("receiving data...\n");
uint32_t *inp_buff = malloc(1024*100*1024*2*4);
double *adc_data = malloc(1024*1024*sizeof(double));
//uint32_t inp_buff[1024*2048] = {0,};
uint32_t ready_cnt = 0;
uint32_t ready_cnt_Err = 0;
uint32_t recv_Err_code = 0;
ready_cnt_Err = X502_GetRecvReadyCount(hnd, &ready_cnt);
recv_Err_code = X502_Recv(hnd, inp_buff, 1024, 10);
printf("Ready count: %d, Err: %d \n", ready_cnt, ready_cnt_Err);
printf("Recv Err code (<0 -- err, >= 0 -- number of received words(32bit)): %d\n", recv_Err_code);
if (recv_Err_code > 0){
ready_cnt = recv_Err_code;
}
FILE *logfile_ptr;
time_t seconds;
time(&seconds);
char logfilename[] = " ";
sprintf(&logfilename, "received_data_%ld.csv", seconds);
logfile_ptr = fopen(logfilename, "w");
printf("dumping to file: %c\n", logfilename);
printf("\n\nreceived data:\n");
int values_in_line = 0;
//for (int i = 0; i < 1024; ++i){
for (int i = 0; i < ready_cnt; ++i){
char bin_str_val[9] = {0,};
uin32_t_to_bin(inp_buff[i], bin_str_val);
printf(" 0x%08X,", inp_buff[i]);
fprintf(logfile_ptr, "0x%08X \n", inp_buff[i]);
//printf(" 0b%s,", bin_str_val);
++values_in_line;
if (values_in_line == 10){
printf("\n");
values_in_line = 0;
}
}
printf("\n");
printf("\n\nget counters of calls of SPORT_RX, SPORT_TX, HDMA_RX, HDMA_TX\n");
BF_exec_cmd_with_arr(hnd, 0x8005U, 100, NULL, 0, 1);
//fprintf(logfile_ptr, "value number; time, sec; adc_value, V\n");
int data_receive_trys_counter = 1000;
while(--data_receive_trys_counter){
ready_cnt_Err = X502_GetRecvReadyCount(hnd, &ready_cnt);
recv_Err_code = X502_Recv(hnd, inp_buff, ready_cnt, 10);
printf("\n\nget counters of calls of SPORT_RX, SPORT_TX, HDMA_RX, HDMA_TX\n");
BF_exec_cmd_with_arr(hnd, 0x8005U, 100, NULL, 0, 1);
if (ready_cnt){
printf("Ready count: %d, Err: %d \n", ready_cnt, ready_cnt_Err);
for (int i = 0; i < ready_cnt; ++i){
char bin_str_val[9] = {0,};
uin32_t_to_bin(inp_buff[i], bin_str_val);
printf(" 0x%08X,", inp_buff[i]);
fprintf(logfile_ptr, "0x%08X \n", inp_buff[i]);
//printf(" 0b%s,", bin_str_val);
++values_in_line;
if (values_in_line == 10){
printf("\n");
values_in_line = 0;
}
}
/*
uint32_t process_data_Err = 0;
uint32_t adc_data_size = ready_cnt;
X502_Raw_User_Data_Parser(inp_buff, inp_values_N,
adc_data, adc_chans_N, adc_readouts_N,
&LFSM_res_tmp, &LFSM_res,
&FFT_res_tmp, &FFT_res);
//process_data_Err = X502_ProcessData(hnd, inp_buff, ready_cnt, X502_PROC_FLAGS_VOLT, adc_data, &adc_data_size, NULL, NULL);
uint64_t data_sum = 0;
for (int i = 0; i < ready_cnt; ++i){
data_sum += inp_buff[i];
if (i % 1000 == 1){
//printf(" %e\n", adc_data[i]);
}
}
*/
}
//printf("try: %04d, words ready: %06d, receive_error_code: %05d, data_sum: %d \n", data_receive_trys_counter, ready_cnt, recv_Err_code, data_sum);
}
fclose(logfile_ptr);
X502_Close(hnd);
// освобождаем описатель
X502_Free(hnd);
return 0;
f_out = 1;
struct timespec time_started;
struct timespec time_ended;
timespec_get(&time_started, TIME_UTC);
float total_runs = 0.0;
long double delta_time = 0.0;
while(f_out != 1){
total_runs += 1.0;
X502_StreamsStart(hnd); //wait for trigger and start sampling
int32_t rcv_size;
uint32_t adc_size, din_size;
// массив для приема необработанных данных //
static uint32_t rcv_buf[READ_BLOCK_SIZE];
static double adc_data[READ_BLOCK_SIZE];
static uint32_t din_data[READ_BLOCK_SIZE];
// принимаем данные (по таймауту) //
rcv_size = X502_Recv(hnd, rcv_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
timespec_get(&time_ended, TIME_UTC);
// результат меньше нуля означает ошибку //
if (rcv_size < 0) {
err = rcv_size;
fprintf(stderr, "Ошибка приема данных: %s\n", X502_GetErrorString(err));
} else if (rcv_size > 0) {
uint32_t first_lch;
// получаем номер логического канала, которому соответствует первый отсчет АЦП в массиве //
X502_GetNextExpectedLchNum(hnd, &first_lch);
adc_size = sizeof(adc_data)/sizeof(adc_data[0]);
din_size = sizeof(din_data)/sizeof(din_data[0]);
// обрабатываем принятые данные, распределяя их на данные АЦП и цифровых входов //
err = X502_ProcessData(hnd, rcv_buf, rcv_size, X502_PROC_FLAGS_VOLT,
adc_data, &adc_size, din_data, &din_size);
if (err != X502_ERR_OK) {
fprintf(stderr, "Ошибка обработки данных: %s\n", X502_GetErrorString(err));
} else {
uint32_t lch;
printf("Обработано данных АЦП = %d, цифровых входов = %d\n",
adc_size, din_size);
long double t_started = (long double)time_started.tv_sec + 1e-9*(long double)time_started.tv_nsec;
printf("started at %jd.%09ld or %Lg\n", (intmax_t)time_started.tv_sec, time_started.tv_nsec, t_started);
printf("received at %jd.%09ld \n", (intmax_t)time_ended.tv_sec, time_ended.tv_nsec);
delta_time = ((long double) time_ended.tv_sec - time_started.tv_sec ) + (((long double) time_ended.tv_nsec) * 1e-9 ) - (((long double) time_started.tv_nsec) * 1e-9 );
printf("delta time %Lg sec\n", delta_time);
// если приняли цифровые данные - выводим первый отсчет //
if (din_size != 0)
printf(" din_data = 0x%05X\n", din_data[0]);
// выводим по одному отсчету на канал. если обработанный блок
// начинается не с начала кадра, то в данном примере для
// вывода берем конец неполного кадра и начало следующего
for (lch=0; lch < ADC_LCH_CNT; lch++) {
// определяем позицию первого отсчета, соответствующего заданному логическому каналу:
// либо с конца не полного кадра, либо из начала следующего //
uint32_t pos = lch >= first_lch ? lch - first_lch : ADC_LCH_CNT-first_lch + lch;
if (pos <= adc_size) {
printf(" lch[%d]=%6.4f\n, pos=%d, adc_size=%d", lch, adc_data[pos], pos, adc_size);
time_t seconds;
time(&seconds);
FILE *fptr;
char filename[] = " ";
sprintf(&filename, "adc data %ld.csv", seconds);
fptr = fopen(filename, "w");
fprintf(fptr, "value number; time, sec; adc_value, V\n");
for (uint32_t data_pos; data_pos < adc_size; ++data_pos){
fprintf(fptr, "%d %6.7f %6.7f \n", data_pos, (double)data_pos / X502_REF_FREQ_2000KHZ , adc_data[data_pos]); //print whole data
//printf("%d %6.7f %6.7f \n", data_pos, (double)data_pos / X502_REF_FREQ_2000KHZ , adc_data[data_pos]); //print whole data
}
fclose(fptr);
} else {
printf(" lch[%d]= ---- \n", lch);
}
}
printf("\n");
fflush(stdout);
}
}
X502_StreamsStop(hnd);
/*
xray =
//plot results. plotter code from: https://www.mps.mpg.de/1757268/exa_c#section_1
metafl ("cons");
scrmod ("revers");
disini ();
pagera ();
complx ();
axspos (450, 1800);
axslen (2200, 1200);
name ("X-axis", "x");
name ("Y-axis", "y");
labdig (-1, "x");
ticks (9, "x");
ticks (10, "y");
titlin ("Demonstration of CURVE", 1);
titlin ("SIN(X), COS(X)", 3);
ic = intrgb (0.95,0.95,0.95);
axsbgd (ic);
graf (0.0, 360.0, 0.0, 90.0, -1.0, 1.0, -1.0, 0.5);
setrgb (0.7, 0.7, 0.7);
grid (1, 1);
color ("fore");
height (50);
title ();
color ("red");
curve (xray, y1ray, n);
color ("green");
curve (xray, y2ray, n);
disfin ();
*/
--f_out;
#ifdef _WIN32
/* проверка нажатия клавиши для выхода */
if (err == X502_ERR_OK) {
if (_kbhit())
f_out = 1;
}
#else
{
// по нажатию Enter включаем/выключаем поток ADC
fd_set fds;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
if (select(1, &fds, NULL, NULL, &tv) == 1) {
int x;
static int adc_disabled = 0;
int ch;
if (adc_disabled) {
X502_StreamsEnable(hnd, X502_STREAM_ADC);
} else {
X502_StreamsDisable(hnd, X502_STREAM_ADC);
}
adc_disabled = !adc_disabled;
while(select(1, &fds, NULL, NULL, &tv) == 1) {
read(STDIN_FILENO, &ch, 1);
}
}
}
#endif
}
printf("delta time %Lg sec\n", delta_time);
printf("average run time %Lg sec\n", delta_time/total_runs);
// закрываем связь с модулем
X502_Close(hnd);
// освобождаем описатель
X502_Free(hnd);
}
return err;
}