/* Данный пример представляет из себя консольную программу на языке 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 //for namigs of saved files #include #include "e502api.h" //#include "dev_funcs.h" #ifdef _WIN32 #include #include #else #include #include #include #endif #include #include #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; }