/* Данный пример представляет из себя консольную программу на языке 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" /* Remove unused enums/structs and constants that are not referenced anywhere */ // количество используемых логических каналов // #define ADC_LCH_CNT 1 /* Unused frequency/timing defines removed */ // сколько отсчетов считываем за блок // #define READ_BLOCK_SIZE 4096*200 // таймаут на прием блока (мс) // #define READ_TIMEOUT 2000 /* Unused BF user command define removed */ // номера используемых физических каналов // 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_modes[ADC_LCH_CNT] = {X502_LCH_MODE_COMM}; //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,X502_LCH_MODE_COMM,X502_LCH_MODE_COMM,X502_LCH_MODE_COMM,X502_LCH_MODE_COMM,X502_LCH_MODE_COMM,X502_LCH_MODE_COMM}; //static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_COMM, X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO,X502_LCH_MODE_ZERO}; //X502_LCH_MODE_COMM0 //X502_LCH_MODE_DIFF //X502_LCH_MODE_ZERO // диапазоны измерения для каналов // static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_02, X502_ADC_RANGE_5,X502_ADC_RANGE_5,X502_ADC_RANGE_5}; //static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_1}; //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,X502_ADC_RANGE_1,X502_ADC_RANGE_1, X502_ADC_RANGE_1,X502_ADC_RANGE_1,X502_ADC_RANGE_1,X502_ADC_RANGE_1}; //static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_5, X502_ADC_RANGE_5,X502_ADC_RANGE_5,X502_ADC_RANGE_5,X502_ADC_RANGE_5,X502_ADC_RANGE_5, X502_ADC_RANGE_5,X502_ADC_RANGE_5,X502_ADC_RANGE_5,X502_ADC_RANGE_5}; //X502_ADC_RANGE_10 Диапазон +/-10V //X502_ADC_RANGE_5 Диапазон +/-5V //X502_ADC_RANGE_2 Диапазон +/-2V //X502_ADC_RANGE_1 Диапазон +/-1V //X502_ADC_RANGE_05 Диапазон +/-0.5V //X502_ADC_RANGE_02 Диапазон +/-0.2V #define SYNC_FREC_SOURCE X502_SYNC_DI_SYN1_RISE #define SYNC_START_SOURCE X502_SYNC_DI_SYN2_RISE //X502_SYNC_INTERNAL //X502_SYNC_EXTERNAL_MASTER1 //X502_SYNC_DI_SYN1_RISE //X502_SYNC_DI_SYN1_FALL //X502_SYNC_DI_SYN2_RISE //X502_SYNC_DI_SYN2_FALL // признак необходимости завершить сбор данных // 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; typedef enum { RUN_MODE_TEST = 0, RUN_MODE_FINITE = 1, RUN_MODE_INF = 2 } run_mode_t; typedef enum { BF_MODE_TRANSPARENT = 0, BF_MODE_AVG = 1, BF_MODE_FFT = 2 } bf_mode_t; typedef enum { BFMODE_TRANSPARENT = 0, BFMODE_AVG = 1, BFMODE_FFT = 2 } blackfin_mode_t; typedef struct main_state_typedef{ run_mode_t run_mode; // TEST, FINITE_RUN, INF_RUN bf_mode_t BF_mode; // TRANSPARENT, AVG blackfin_mode_t BlackFin_mode; // TRANSPARENT, AVG, FFT uint32_t run_length; // in ms. Used as timeout for receive_to_file uint32_t run_I; // № current run uint32_t runs_N; // total number of runs char data_path[200]; // base directory for data files } main_state; static void main_state_set_defaults(main_state* st) { st->run_mode = RUN_MODE_TEST; st->BF_mode = BF_MODE_TRANSPARENT; st->BlackFin_mode = BFMODE_TRANSPARENT; st->run_length = 1000; st->run_I = 0; st->runs_N = 1; strncpy(st->data_path, "data", sizeof(st->data_path)); st->data_path[sizeof(st->data_path)-1] = '\0'; } static char* f_trim(char* s) { char* end; while (*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++; if (*s == 0) return s; end = s + strlen(s) - 1; while (end > s && (*end==' ' || *end=='\t' || *end=='\r' || *end=='\n')) end--; end[1] = '\0'; return s; } static void parse_cmd_file(const char* filename, main_state* st) { FILE* f = fopen(filename, "r"); if (f == NULL) { printf("Command file '%s' not found. Using defaults.\n", filename); return; } char line[512]; while (fgets(line, sizeof(line), f)) { char* p = line; char* comment = strstr(p, "//"); if (comment) *comment = '\0'; p = f_trim(p); if (*p == '\0') continue; char* field = strtok(p, "\t \r\n"); char* value = strtok(NULL, "\t \r\n"); if (!field || !value) continue; if (strcmp(field, "run_mode") == 0) { if (strcmp(value, "FINITE_RUN") == 0) { st->run_mode = RUN_MODE_FINITE; } else if (strcmp(value, "INF_RUN") == 0) { st->run_mode = RUN_MODE_INF; } else if (strcmp(value, "TEST") == 0) { st->run_mode = RUN_MODE_TEST; } else { st->run_mode = RUN_MODE_TEST; // default on mismatch } } else if (strcmp(field, "BF_mode") == 0) { if (strcmp(value, "TRANSPARENT") == 0) { st->BF_mode = BF_MODE_TRANSPARENT; } else if (strcmp(value, "AVG") == 0) { st->BF_mode = BF_MODE_AVG; } else if (strcmp(value, "FFT") == 0) { st->BF_mode = BF_MODE_FFT; } else { st->BF_mode = BF_MODE_TRANSPARENT; // default on mismatch } } else if (strcmp(field, "BlackFin_mode") == 0) { if (strcmp(value, "TRANSPARENT") == 0) { st->BlackFin_mode = BFMODE_TRANSPARENT; } else if (strcmp(value, "AVG") == 0) { st->BlackFin_mode = BFMODE_AVG; } else if (strcmp(value, "FFT") == 0) { st->BlackFin_mode = BFMODE_FFT; } else { st->BlackFin_mode = BFMODE_TRANSPARENT; // default on mismatch } } else if (strcmp(field, "run_length") == 0) { char* endp = NULL; unsigned long v = strtoul(value, &endp, 0); if (endp != value) st->run_length = (uint32_t)v; } else if (strcmp(field, "runs_N") == 0) { char* endp = NULL; unsigned long v = strtoul(value, &endp, 0); if (endp != value) st->runs_N = (uint32_t)v; } else if (strcmp(field, "run_I") == 0) { char* endp = NULL; unsigned long v = strtoul(value, &endp, 0); if (endp != value) st->run_I = (uint32_t)v; } else if (strcmp(field, "data_path") == 0) { strncpy(st->data_path, value, sizeof(st->data_path)); st->data_path[sizeof(st->data_path)-1] = '\0'; } } fclose(f); } /* Unused SIGINT handler and flag removed */ /* Функция находит все подключенные модули по интерфейсам 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 X502_SetSyncMode(hnd, SYNC_FREC_SOURCE); //X502_SetSyncMode(hnd, X502_SYNC_INTERNAL); X502_SetSyncStartMode(hnd, SYNC_START_SOURCE); //X502_SYNC_INTERNAL //X502_SYNC_EXTERNAL_MASTER1 //X502_SYNC_DI_SYN1_RISE //X502_SYNC_DI_SYN1_FALL //X502_SYNC_DI_SYN2_RISE //X502_SYNC_DI_SYN2_FALL //set ADC sample frequency from internal generator with frequency 2 MHz //X502_SetRefFreq(hnd, X502_REF_FREQ_1500KHZ); //X502_REF_FREQ_1500KHZ //X502_REF_FREQ_2000KHZ // записываем настройки в модуль // 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; } uint32_t X502_FlushRcv_buff(t_x502_hnd hnd){ uint32_t ready; X502_GetRecvReadyCount(hnd, &ready); if (ready > 0) { uint32_t *tmp = malloc(ready * sizeof(uint32_t)); X502_Recv(hnd, tmp, ready, 0); // вычитываем и отбрасываем free(tmp); } return ready; } void insert_marker_to_file(char* logfilename, char* marker_text){ printf("marker %s <======================================\n", marker_text); FILE* logfile_ptr = fopen(logfilename, "a"); fprintf(logfile_ptr, "marker %s \n", marker_text); fclose(logfile_ptr); } void receive_to_file(t_x502_hnd hnd, char* logfilename, uint32_t* inp_buff, uint32_t max_total_words, uint32_t timeout){ // fprintf(logfile_ptr, "0xFF00000 \n"); // fprintf(logfile_ptr, "0xFFFFFFF \n"); // fprintf(logfile_ptr, "0xFF00000 \n"); // uint32_t timeout = 100; int32_t recv_Err_code = X502_Recv(hnd, inp_buff, max_total_words, timeout); printf("receive code: %d\n", recv_Err_code); if (recv_Err_code > 0){ char logfilename_tmp[300]; snprintf(logfilename_tmp, sizeof(logfilename_tmp), "%s.tmp", logfilename); printf("tmp file: %s ",logfilename_tmp); FILE* logfile_ptr = fopen(logfilename_tmp, "a"); //uint32_t recv_Err_code = X502_Recv(hnd, inp_buff, max_total_words, 20000); uint32_t received_words = recv_Err_code; for (uint32_t word_I = 0; word_I < received_words; word_I ++){ //printf("%06d 0x%08X\n", word_I, inp_buff[word_I]); fprintf(logfile_ptr, "0x%08X \n", inp_buff[word_I]); } printf("received %ld words\n", received_words); fclose(logfile_ptr); rename(logfilename_tmp, logfilename); }else if (recv_Err_code == 0){ printf("no data received. timeout\n"); }else{ sleep(1); printf("receive error: %d\n======================\n", recv_Err_code); } } /* void receive_to_file(t_x502_hnd hnd, char* logfilename, uint32_t* inp_buff, uint32_t max_total_words, uint32_t timeout){ char logfilename_tmp[300]; snprintf(logfilename_tmp, sizeof(logfilename_tmp), "%s.tmp", logfilename); printf("tmp file: %s ",logfilename_tmp); FILE* logfile_ptr = fopen(logfilename_tmp, "a"); // fprintf(logfile_ptr, "0xFF00000 \n"); // fprintf(logfile_ptr, "0xFFFFFFF \n"); // fprintf(logfile_ptr, "0xFF00000 \n"); // uint32_t timeout = 100; uint32_t recv_Err_code = X502_Recv(hnd, inp_buff, max_total_words, timeout); //uint32_t recv_Err_code = X502_Recv(hnd, inp_buff, max_total_words, 20000); if (recv_Err_code > 0){ uint32_t received_words = recv_Err_code; for (uint32_t word_I = 0; word_I < received_words; word_I ++){ //printf("%06d 0x%08X\n", word_I, inp_buff[word_I]); fprintf(logfile_ptr, "0x%08X \n", inp_buff[word_I]); } printf("received %ld words\n", received_words); }else{ printf("receive error: %d\n======================\n", recv_Err_code); } fclose(logfile_ptr); rename(logfilename_tmp, logfilename); } */ int main(int argc, char** argv) { int32_t err = X502_ERR_OK; uint32_t ver; t_x502_hnd hnd = NULL; // читаем имя командного файла из аргументов CLI const char* cmd_filename = "default.cmd"; if (argc > 1 && argv[1] != NULL && argv[1][0] != '\0') { cmd_filename = argv[1]; } // получаем версию библиотеки // ver = X502_GetLibraryVersion(); printf("Версия библиотеки: %d.%d.%d\n", (ver >> 24)&0xFF, (ver>>16)&0xFF, (ver>>8)&0xFF); printf("Command file: %s\n", cmd_filename); // загружаем состояние из командного файла main_state state; main_state_set_defaults(&state); parse_cmd_file(cmd_filename, &state); // отладочный вывод принятых значений printf("Parsed state: run_mode=%d, BF_mode=%d, BlackFin_mode=%d, run_length=%u, runs_N=%u, run_I=%u, data_path=%s\n", (int)state.run_mode, (int)state.BF_mode, (int)state.BlackFin_mode, state.run_length, state.runs_N, state.run_I, state.data_path); /* Removed unused temporary buffers and FFT/LFSM placeholders */ ////******* Получение списка устройств и выбор, с каким будем работать *****************// 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"; if (1){ 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: %d \n", bf_firmware_load_state); }else{ printf("No BF firmware loaded\n"); } 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)); } printf("\n\n\n"); //setup ADC: uint32_t streams_enable_Err = 0; streams_enable_Err = X502_StreamsEnable(hnd, X502_STREAM_ADC | X502_STREAM_DIN ); printf("Streams enable 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); if (state.run_mode == RUN_MODE_FINITE){ if (state.BF_mode == BF_MODE_TRANSPARENT){ printf("\nStart transparent mode\n"); BF_exec_cmd_simple(hnd, 0x8007, 10, 1); //start transparent }else if(state.BF_mode == BF_MODE_FFT){ printf("\nStart FFt mode\n"); BF_exec_cmd_simple(hnd, 0x8008, 2, 1); //start averaging }else if(state.BF_mode == BF_MODE_AVG){ printf("\nStart AVG mode\n"); BF_exec_cmd_simple(hnd, 0x8009, 2, 1); //start averaging } X502_StreamsStop(hnd); X502_StreamsStart(hnd); // for(uint32_t wait_i = 1e6; wait_i; --wait_i){;} printf("\nFlushed from receiving buff: %d\n", X502_FlushRcv_buff(hnd)); state.run_I = 0; char tmp_data_filename[256]; struct timespec ts; uint32_t max_total_words = 1000000; uint32_t *inp_buff = malloc(1024*100*1024*2*4); uint32_t runs_since_streams_clean = 0; while(state.run_I < state.runs_N){ max_total_words = 10000000; timespec_get(&ts, TIME_UTC); // sprintf(&tmp_data_filename, "tmp/received_data_%ld.%ld.csv", ts.tv_sec, ts.tv_nsec); // sprintf(&logfilename, "tmp/received_data_%ld.%ld.csv", ts.tv_sec, ts.tv_nsec); //sprintf(&logfilename, "data/received_data_%ld.csv", seconds); snprintf(tmp_data_filename, sizeof(tmp_data_filename), "%s/received_data_%ld.%ld.csv", state.data_path, ts.tv_sec, ts.tv_nsec); printf("%u/%u dumping to file: %s\n", (unsigned)state.run_I, (unsigned)state.runs_N, tmp_data_filename); receive_to_file(hnd, tmp_data_filename, inp_buff, max_total_words, state.run_length); if (runs_since_streams_clean >= 10){ runs_since_streams_clean = 0; X502_StreamsStop(hnd); X502_StreamsStart(hnd); } state.run_I++; runs_since_streams_clean++; } free(inp_buff); X502_Close(hnd); // освобождаем описатель X502_Free(hnd); return 0; }else if (state.run_mode == RUN_MODE_INF){ if (state.BF_mode == BF_MODE_TRANSPARENT){ printf("\nStart transparent mode\n"); BF_exec_cmd_simple(hnd, 0x8007, 10, 1); //start transparent }else if(state.BF_mode == BF_MODE_FFT){ printf("\nStart FFt mode\n"); BF_exec_cmd_simple(hnd, 0x8008, 2, 1); //start averaging }else if(state.BF_mode == BF_MODE_AVG){ printf("\nStart AVG mode\n"); BF_exec_cmd_simple(hnd, 0x8009, 2, 1); //start averaging } X502_StreamsStop(hnd); X502_StreamsStart(hnd); // for(uint32_t wait_i = 1e6; wait_i; --wait_i){;} printf("\nFlushed from receiving buff: %d\n", X502_FlushRcv_buff(hnd)); state.run_I = 0; char tmp_data_filename[256]; struct timespec ts; uint32_t max_total_words = 10000000; uint32_t *inp_buff = malloc(1024*100*1024*2*4); uint32_t runs_since_streams_clean = 0; while (1){ //should be infinite. because it is RUN_MODE_INF //while(state.run_I < state.runs_N){ max_total_words = 10000000; timespec_get(&ts, TIME_UTC); // sprintf(&tmp_data_filename, "tmp/received_data_%ld.%ld.csv", ts.tv_sec, ts.tv_nsec); // sprintf(&logfilename, "tmp/received_data_%ld.%ld.csv", ts.tv_sec, ts.tv_nsec); //sprintf(&logfilename, "data/received_data_%ld.csv", seconds); snprintf(tmp_data_filename, sizeof(tmp_data_filename), "%s/received_data_%ld.%ld.csv", state.data_path, ts.tv_sec, ts.tv_nsec); printf("%u dumping to file: %s\n", (unsigned)state.run_I, tmp_data_filename); receive_to_file(hnd, tmp_data_filename, inp_buff, max_total_words, state.run_length); if (runs_since_streams_clean >= 10){ runs_since_streams_clean = 0; X502_StreamsStop(hnd); X502_StreamsStart(hnd); } state.run_I++; runs_since_streams_clean++; } free(inp_buff); X502_Close(hnd); // освобождаем описатель X502_Free(hnd); return 0; }else{ //TEST mode as default time_t seconds; time(&seconds); char logfilename[256]; snprintf(logfilename, sizeof(logfilename), "%s/received_data_%ld.csv", state.data_path, (long)seconds); //logfile_ptr = fopen(logfilename, "w"); FILE *logfile_ptr; logfile_ptr = fopen(logfilename, "a"); fprintf(logfile_ptr, "sync_frec_source: %d \nsync_start_source: %d \n", SYNC_FREC_SOURCE, SYNC_START_SOURCE); for (int chan_I = 0; chan_I < ADC_LCH_CNT; chan_I++){ fprintf(logfile_ptr, "chan: %d, mode: %d, range: %d \n", chan_I, f_ch_modes[chan_I], f_ch_ranges[chan_I]); } fclose(logfile_ptr); // printf("dumping to file: %s\n", logfilename); 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); 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,}; /* Removed unused counters */ insert_marker_to_file(logfilename, "start transparent"); printf("\nStart transparent mode\n"); BF_exec_cmd_simple(hnd, 0x8007, 10, 1); //start transparent printf("\nFlushed from receiving buff: %d\n", X502_FlushRcv_buff(hnd)); printf("receiving data...\n"); /* Removed unused readiness checks */ uint32_t max_total_words = 100000; /* Removed unused data_receive_trys_counter */ // printf("\nflush TX buff. \n Number of free TX descriptors before flushing:"); // BF_exec_cmd_simple(hnd, 0x8010, 10, 1); // receive_to_file(hnd, logfilename, inp_buff, max_total_words, 10000); 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); //* insert_marker_to_file(logfilename, "start AVG"); printf("\nStart AVG mode\n"); BF_exec_cmd_simple(hnd, 0x8008, 2, 1); //start averaging // printf("\nflush TX buff. \n Number of free TX descriptors before flushing:"); // BF_exec_cmd_simple(hnd, 0x8010, 10, 1); X502_StreamsStop(hnd); X502_StreamsStart(hnd); // for(uint32_t wait_i = 1e6; wait_i; --wait_i){;} printf("\nFlushed from receiving buff: %d\n", X502_FlushRcv_buff(hnd)); // 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"); max_total_words = 100000; //printf("\n dbg value: "); //BF_exec_cmd_simple(hnd, 0x800A, 10, 1); struct timespec time_receive_started, time_receive_ended; clock_gettime(CLOCK_MONOTONIC, &time_receive_started); receive_to_file(hnd, logfilename, inp_buff, max_total_words, 10000); clock_gettime(CLOCK_MONOTONIC, &time_receive_ended); double receive_time = (time_receive_ended.tv_sec - time_receive_started.tv_sec); receive_time += time_receive_ended.tv_nsec*1e-9; receive_time += time_receive_started.tv_nsec*1e-9; printf("\n Receive time: %g, %g sec/value \n", receive_time, receive_time/max_total_words); insert_marker_to_file(logfilename, "start transparent"); printf("\nStart transparent mode\n"); BF_exec_cmd_simple(hnd, 0x8007, 2, 1); //start transparent X502_StreamsStop(hnd); X502_StreamsStart(hnd); printf("\nflush TX buff. \n Number of free TX descriptors before flushing:"); BF_exec_cmd_simple(hnd, 0x8010, 10, 1); printf("\nFlushed from receiving buff: %d\n", X502_FlushRcv_buff(hnd)); // printf("\n dbg value: "); // BF_exec_cmd_simple(hnd, 0x800A, 10, 1); receive_to_file(hnd, logfilename, inp_buff, max_total_words, 10000); printf("\n dbg value: "); BF_exec_cmd_simple(hnd, 0x800A, 10, 1); //*/ printf("\n\nreceive done. Exiting...\n\n\n"); //logfile_ptr = fopen(logfilename, "w"); printf("dumped to file: %s\n", logfilename); fprintf(stderr, "%s\n", logfilename); X502_Close(hnd); // освобождаем описатель X502_Free(hnd); return 0; } } return -1; }