moved libs to the lib directory
This commit is contained in:
11
lib/x502api-1.1.34/examples/c/CMakeLists.txt
Normal file
11
lib/x502api-1.1.34/examples/c/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
add_subdirectory(x502_stream_read)
|
||||
add_subdirectory(x502_dac_cntr_test)
|
||||
add_subdirectory(e16_dac_cntr_test)
|
||||
add_subdirectory(e16_overflow_test)
|
||||
add_subdirectory(x502_ring_mode0_test)
|
||||
add_subdirectory(x502_cycle_out)
|
||||
add_subdirectory(e502_eth_svc_browse)
|
||||
add_subdirectory(e502_timestamp_stream)
|
||||
add_subdirectory(e16_dac_shift_test)
|
||||
274
lib/x502api-1.1.34/examples/c/common/dev_funcs.c
Normal file
274
lib/x502api-1.1.34/examples/c/common/dev_funcs.c
Normal file
@ -0,0 +1,274 @@
|
||||
#include "l502api.h"
|
||||
#include "e502api.h"
|
||||
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
#include "dev_funcs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
#define EVENT_CONNECTION_TOUT 100
|
||||
|
||||
#define DEV_E502_DEF "E502"
|
||||
#define DEV_E16_DEF "E16"
|
||||
#define DEV_LTA37_DEF "LTA37"
|
||||
|
||||
static char const *DEV_E502 = DEV_E502_DEF;
|
||||
static char const *DEV_E16 = DEV_E16_DEF;
|
||||
static char const *DEV_LTA37 = DEV_LTA37_DEF;
|
||||
|
||||
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;
|
||||
uint32_t eth_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);
|
||||
E502_SearchEthForDevicesIPv4Addr(NULL, 0, 0, ð_devcnt, EVENT_CONNECTION_TOUT, TCP_CONNECTION_TOUT);
|
||||
|
||||
if ((pci_devcnt+usb_devcnt + e16_usb_devcnt + ip_cnt + eth_devcnt) != 0) {
|
||||
/* выделяем память для массива для сохранения найденного количества записей */
|
||||
rec_list = malloc((pci_devcnt + usb_devcnt +e16_usb_devcnt + ip_cnt + eth_devcnt) * 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;
|
||||
}
|
||||
}
|
||||
|
||||
if(eth_devcnt != 0) {
|
||||
int32_t res = E502_SearchEthForDevicesIPv4Addr(&rec_list[fnd_devcnt], 0, eth_devcnt, NULL, EVENT_CONNECTION_TOUT, TCP_CONNECTION_TOUT);
|
||||
if (res >= 0) {
|
||||
fnd_devcnt += res;
|
||||
}
|
||||
}
|
||||
|
||||
/* создаем записи для переданного массива ip-адресов */
|
||||
for (i=0; i < ip_cnt; i++) {
|
||||
if (E502_MakeDevRecordByIpAddr2(&rec_list[fnd_devcnt], ip_dev_list[i].ip_addr, 0, TCP_CONNECTION_TOUT, ip_dev_list[i].devname) == X502_ERR_OK) {
|
||||
fnd_devcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, uint32_t flags_clear) {
|
||||
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 ||
|
||||
sscanf(argv[i], DEV_E502_DEF":%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], DEV_E16_DEF":%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);
|
||||
} else
|
||||
if (sscanf(argv[i], DEV_LTA37_DEF":%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3])==4) {
|
||||
ip_dev_list[ip_cnt].devname = DEV_LTA37;
|
||||
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);
|
||||
|
||||
if (dev_ind >= fnd_devcnt) {
|
||||
printf("Неверно указан номер модуля...\n");
|
||||
} else {
|
||||
/* если ввели номер правильно - создаем описатель */
|
||||
hnd = X502_Create();
|
||||
if (hnd==NULL) {
|
||||
fprintf(stderr, "Ошибка создания описателя модуля!");
|
||||
} else {
|
||||
devrec_list[dev_ind].flags &= ~flags_clear;
|
||||
/* устанавливаем связь с модулем по записи */
|
||||
int32_t err = X502_OpenByDevRecord(hnd, &devrec_list[dev_ind]);
|
||||
if (err != X502_ERR_OK && err != X502_ERR_FPGA_NOT_LOADED) {
|
||||
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;
|
||||
}
|
||||
|
||||
t_x502_hnd select_dev_from_list(int argc, char** argv, uint32_t flags_clear) {
|
||||
t_x502_hnd hnd;
|
||||
uint32_t ver;
|
||||
int32_t err = X502_ERR_OK;
|
||||
/* получаем версию библиотеки */
|
||||
ver = X502_GetLibraryVersion();
|
||||
printf("Версия библиотеки: %d.%d.%d\n", (ver >> 24)&0xFF, (ver>>16)&0xFF, (ver>>8)&0xFF);
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
hnd = f_dev_select_open(argc, argv, flags_clear);
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (hnd == NULL) {
|
||||
return 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);
|
||||
}
|
||||
}
|
||||
|
||||
if(err && hnd) {
|
||||
X502_Free(hnd);
|
||||
hnd = NULL;
|
||||
}
|
||||
return hnd;
|
||||
}
|
||||
|
||||
8
lib/x502api-1.1.34/examples/c/common/dev_funcs.h
Normal file
8
lib/x502api-1.1.34/examples/c/common/dev_funcs.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef __DEV_FUNCS_H__
|
||||
#define __DEV_FUNCS_H__
|
||||
|
||||
#include "x502api.h"
|
||||
|
||||
t_x502_hnd select_dev_from_list(int argc, char** argv, uint32_t flags_clear);
|
||||
|
||||
#endif //__DEV_FUNCS_H__
|
||||
41
lib/x502api-1.1.34/examples/c/common/timespec_funcs.c
Normal file
41
lib/x502api-1.1.34/examples/c/common/timespec_funcs.c
Normal file
@ -0,0 +1,41 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int clock_gettime(int a, struct timespec *spec) {
|
||||
__int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
|
||||
wintime -=116444736000000000i64; //1jan1601 to 1jan1970
|
||||
spec->tv_sec =wintime / 10000000i64; //seconds
|
||||
spec->tv_nsec =wintime % 10000000i64 *100; //nano-seconds
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *result) {
|
||||
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||
result->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
if (result->tv_nsec < 0) {
|
||||
--result->tv_sec;
|
||||
result->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
double timespec_to_double(struct timespec *ts)
|
||||
{
|
||||
return ((double)(ts->tv_sec) + ((double)(ts->tv_nsec) / NSEC_PER_SEC));
|
||||
}
|
||||
15
lib/x502api-1.1.34/examples/c/common/timespec_funcs.h
Normal file
15
lib/x502api-1.1.34/examples/c/common/timespec_funcs.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef __TIMESPEC_FUNCS_H__
|
||||
#define __TIMESPEC_FUNCS_H__
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CLOCK_MONOTONIC 1
|
||||
int clock_gettime(int a, struct timespec *spec);
|
||||
|
||||
#endif //_WIN32
|
||||
|
||||
void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *result);
|
||||
double timespec_to_double(struct timespec *ts);
|
||||
|
||||
#endif //__TIMESPEC_FUNCS_H__
|
||||
@ -0,0 +1,30 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
set(PROJECT e16_dac_cntr_test)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c ../common/dev_funcs.c ../common/timespec_funcs.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR} ../common)
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
230
lib/x502api-1.1.34/examples/c/e16_dac_cntr_test/dev_funcs.c
Normal file
230
lib/x502api-1.1.34/examples/c/e16_dac_cntr_test/dev_funcs.c
Normal file
@ -0,0 +1,230 @@
|
||||
#include "l502api.h"
|
||||
#include "e502api.h"
|
||||
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
|
||||
int32_t f_setup_params(t_x502_hnd hnd);
|
||||
|
||||
/* Функция находит все подключенные модули по интерфейсам PCI-Express и USB и
|
||||
* сохраняет записи о этих устройствах в выделенный массив.
|
||||
* Также создаются записи по переданным IP-адресам модулей и добавляются в конец
|
||||
* массива.
|
||||
* Указатель на выделенный массив, который должен быть потом очищен, сохраняется
|
||||
* в pdevrec_list, а количество действительных элементов (память которых должна
|
||||
* быть в дальнейшем освобождена с помощью X502_FreeDevRecordList()) возвращается
|
||||
* как результат функции */
|
||||
static uint32_t f_get_all_devrec(t_x502_devrec **pdevrec_list, uint32_t *ip_addr_list, unsigned ip_cnt) {
|
||||
int32_t fnd_devcnt = 0;
|
||||
uint32_t pci_devcnt = 0;
|
||||
uint32_t usb_devcnt = 0;
|
||||
|
||||
t_x502_devrec *rec_list = NULL;
|
||||
|
||||
/* получаем количество подключенных устройств по интерфейсам PCI и USB */
|
||||
//L502_GetDevRecordsList(NULL, 0, 0, &pci_devcnt);
|
||||
E16_UsbGetDevRecordsList(NULL, 0, 0, &usb_devcnt);
|
||||
|
||||
if ((pci_devcnt + usb_devcnt + ip_cnt) != 0) {
|
||||
/* выделяем память для массива для сохранения найденного количества записей */
|
||||
rec_list = malloc((pci_devcnt + 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 = E16_UsbGetDevRecordsList(&rec_list[fnd_devcnt], usb_devcnt, 0, NULL);
|
||||
if (res >= 0) {
|
||||
fnd_devcnt += res;
|
||||
}
|
||||
}
|
||||
|
||||
/* создаем записи для переданного массива ip-адресов */
|
||||
for (i=0; i < ip_cnt; i++) {
|
||||
if (E502_MakeDevRecordByIpAddr(&rec_list[fnd_devcnt], ip_addr_list[i],0, TCP_CONNECTION_TOUT) == X502_ERR_OK) {
|
||||
fnd_devcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
uint32_t fnd_devcnt,i, dev_ind;
|
||||
t_x502_devrec *devrec_list = NULL;
|
||||
uint32_t *ip_addr_list = NULL;
|
||||
uint32_t ip_cnt = 0;
|
||||
t_x502_hnd hnd = NULL;
|
||||
|
||||
/* если есть аргументы командной строки, то предполагаем, что это могут быть
|
||||
ip-адреса интересующих устройств. */
|
||||
if (argc > 1) {
|
||||
ip_addr_list = malloc((argc-1) * sizeof(ip_addr_list[0]));
|
||||
if (ip_addr_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_addr_list[ip_cnt++] = ((a[0] & 0xFF) << 24) |
|
||||
((a[1] & 0xFF) << 16) |
|
||||
((a[2] & 0xFF) << 8) |
|
||||
(a[3] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* получаем список модулей для выбора */
|
||||
fnd_devcnt = f_get_all_devrec(&devrec_list, ip_addr_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);
|
||||
|
||||
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_addr_list);
|
||||
|
||||
return hnd;
|
||||
}
|
||||
|
||||
t_x502_hnd select_dev_from_list(int argc, char** argv) {
|
||||
t_x502_hnd hnd;
|
||||
uint32_t ver;
|
||||
int32_t err = X502_ERR_OK;
|
||||
/* получаем версию библиотеки */
|
||||
ver = X502_GetLibraryVersion();
|
||||
printf("Версия библиотеки: %d.%d.%d\n", (ver >> 24)&0xFF, (ver>>16)&0xFF, (ver>>8)&0xFF);
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
hnd = f_dev_select_open(argc, argv);
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (hnd == NULL) {
|
||||
return 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
/* настраиваем параметры модуля */
|
||||
err = f_setup_params(hnd);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
|
||||
}
|
||||
if(err && hnd) {
|
||||
X502_Free(hnd);
|
||||
hnd = NULL;
|
||||
}
|
||||
return hnd;
|
||||
}
|
||||
|
||||
489
lib/x502api-1.1.34/examples/c/e16_dac_cntr_test/main.c
Normal file
489
lib/x502api-1.1.34/examples/c/e16_dac_cntr_test/main.c
Normal file
@ -0,0 +1,489 @@
|
||||
/*
|
||||
При использовании заглушки соединяющей DOUT -> DIN есть возмость проверить корректность приема/передачи цифровых каналов в петле
|
||||
|
||||
При использовании флага DCI_TEST_MODE по каналу АЦП должен приниматься 32-битный счетчик
|
||||
*/
|
||||
|
||||
/*
|
||||
Данный пример представляет из себя консольную программу на языке C,
|
||||
демонстрирующую работу с модулями L502 и E502 на примере синхронного
|
||||
ввода данных с АЦП и цифровых линий.
|
||||
|
||||
Перед сбором в примере идет поиск модулей, подключенных по интерфейсам PCI-Express и USB,
|
||||
и предоставляется список для выбора модуля, с которым нужно работать.
|
||||
Для подключения по Ethernet нужно указать IP-адреса интересующих модулей
|
||||
в качестве аргументов командной строки при вызове примера, тогда эти адреса
|
||||
будут добавлены в конец списка выбора модуля.
|
||||
Например, если интересуют модули с адресами 192.168.1.5 и 192.168.1.6,
|
||||
то пример можно вызвать:
|
||||
x502_stream_read 192.168.1.5 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 "l502api.h"
|
||||
#include "e502api.h"
|
||||
#include "dev_funcs.h"
|
||||
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "timespec_funcs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "x502api_private.h"
|
||||
|
||||
#define STREAM_IN_WRD_TYPE(wrd) wrd & 0x80000000 ? STREAM_IN_WRD_ADC : \
|
||||
(wrd & 0xFF000000) == 0x0 ? STREAM_IN_WRD_DIN : \
|
||||
((wrd & 0xFF000000)>>24) == 0x01 ? STREAM_IN_WRD_MSG : STREAM_IN_WRD_USR
|
||||
|
||||
|
||||
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
static volatile int f_out = 0;
|
||||
|
||||
/* количество используемых логических каналов */
|
||||
#define ADC_LCH_CNT 3
|
||||
|
||||
/* частота сбора АЦП в Гц*/
|
||||
//#define ADC_FREQ 2000000
|
||||
#define ADC_FREQ 400000
|
||||
/* частота кадров (на логический канал). При ADC_FREQ/ADC_LCH_CNT - межкадровой задержки нет */
|
||||
#define ADC_FRAME_FREQ (ADC_FREQ/ADC_LCH_CNT)
|
||||
/* частота синхронного ввода в Гц*/
|
||||
#define DIN_FREQ 20000
|
||||
//#define DIN_FREQ 50000
|
||||
#define DOUT_FREQ 20000
|
||||
|
||||
#define ENABLE_DOUT
|
||||
//#define ENABLE_DAC1
|
||||
//#define ENABLE_DAC2
|
||||
|
||||
//#define STREAM_IN_ENABLE (X502_STREAM_ADC | X502_STREAM_DIN)
|
||||
#define STREAM_IN_ENABLE (X502_STREAM_DIN)
|
||||
//#define STREAM_IN_ENABLE (X502_STREAM_ADC)
|
||||
//#define STREAM_IN_ENABLE (0)
|
||||
//#define STREAM_IN_ENABLE (X502_STREAM_ADC)
|
||||
|
||||
#define TEST_ADC_CNTR_FLAG (1 << 7)
|
||||
#define TEST_WR_DISABLE_FLAG (1 << 6)
|
||||
#define TEST_RING_MODE_FLAG (1 << 5)
|
||||
|
||||
//#define WRD_MASK 0x3ffff
|
||||
//#define WRD_MASK 0xffffff
|
||||
#define WRD_MASK 0xffff
|
||||
//#define WRD_MASK 0x3ff
|
||||
|
||||
//#define ENABLE_DCI_TEST_MODE (TEST_RING_MODE_FLAG)
|
||||
//#define ENABLE_DCI_TEST_MODE (TEST_ADC_CNTR_FLAG | TEST_WR_DISABLE_FLAG | TEST_RING_MODE_FLAG)
|
||||
//#define ENABLE_DCI_TEST_MODE TEST_ADC_CNTR_FLAG
|
||||
//#define ENABLE_DCI_TEST_MODE (TEST_ADC_CNTR_FLAG | TEST_WR_DISABLE_FLAG)
|
||||
//#define ENABLE_DCI_TEST_MODE TEST_WR_DISABLE_FLAG
|
||||
|
||||
|
||||
#define TEST_MODE 0
|
||||
//#define TEST_MODE TEST_ADC_CNTR_FLAG
|
||||
|
||||
// при ADC_FREQ==2000000 и DIN_FREQ==1000000 через Ethernet обязательно будет X502_STREAM_IN_MSG_OVERFLOW
|
||||
|
||||
|
||||
|
||||
|
||||
/* сколько отсчетов считываем за блок */
|
||||
#define READ_BLOCK_SIZE 4096*66*3
|
||||
|
||||
/* таймаут на прием блока (мс) */
|
||||
#define READ_TIMEOUT 500
|
||||
|
||||
|
||||
uint32_t tstCntr = 0x7788;
|
||||
uint32_t tstCntr24 = 0x7788;
|
||||
|
||||
int dac2_once = 1;
|
||||
volatile int stream_ingibit_cntr = 1;
|
||||
|
||||
int g_test_mode;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI ThreadFunc(void* arg)
|
||||
#else
|
||||
void * threadFunc(void * arg)
|
||||
#endif
|
||||
{
|
||||
t_x502_hnd hnd = (t_x502_hnd)arg;
|
||||
int32_t g_snd_cnt = 0;
|
||||
static uint32_t snd_buf[READ_BLOCK_SIZE];
|
||||
struct timespec start_time;
|
||||
struct timespec cur_time;
|
||||
struct timespec spent_time;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
while(!f_out) {
|
||||
int32_t snd_cnt = 0;
|
||||
uint32_t to_send = READ_BLOCK_SIZE;
|
||||
uint32_t *to_send_ptr = snd_buf;
|
||||
|
||||
for (int i = 0; i < READ_BLOCK_SIZE; ) {
|
||||
if (g_test_mode == TEST_RING_MODE_FLAG) {
|
||||
snd_buf[i] = (tstCntr | ((tstCntr << 14) & 0xC0000000));
|
||||
i++;
|
||||
} else {
|
||||
|
||||
#ifdef ENABLE_DOUT
|
||||
snd_buf[i] = tstCntr24 & 0xffff;
|
||||
i++;
|
||||
#endif
|
||||
#ifdef ENABLE_DAC1
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC1;
|
||||
i++;
|
||||
#endif
|
||||
#ifdef ENABLE_DAC2
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC2;
|
||||
i++;
|
||||
#endif
|
||||
}
|
||||
tstCntr++;
|
||||
tstCntr24++;
|
||||
}
|
||||
|
||||
while (to_send && !f_out) {
|
||||
snd_cnt = X502_Send(hnd, to_send_ptr, to_send, READ_TIMEOUT);
|
||||
if (snd_cnt < 0 || f_out) {
|
||||
printf("thread exiting X502_Send err=%d\n", snd_cnt);
|
||||
return 0;
|
||||
}
|
||||
to_send -= snd_cnt;
|
||||
to_send_ptr += snd_cnt;
|
||||
if (stream_ingibit_cntr > 0) {
|
||||
stream_ingibit_cntr -=snd_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
g_snd_cnt += READ_BLOCK_SIZE;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5)
|
||||
{
|
||||
timespec_diff(&cur_time, &start_time, &spent_time);
|
||||
|
||||
printf("cnt=%d sec=%f snd speed=%f wrds/sec\n", g_snd_cnt, timespec_to_double(&spent_time), g_snd_cnt / timespec_to_double(&spent_time));
|
||||
start_time = cur_time;
|
||||
g_snd_cnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* номера используемых физических каналов */
|
||||
static uint32_t f_channels[ADC_LCH_CNT] = {0,4,6};
|
||||
/* режимы измерения для каналов */
|
||||
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_ZERO, X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF};
|
||||
/* диапазоны измерения для каналов */
|
||||
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_10, X502_ADC_RANGE_10, X502_ADC_RANGE_10};
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Обработчик сигнала завершения для Linux */
|
||||
static void f_abort_handler(int sig) {
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* настройка параметров модуля */
|
||||
int32_t f_setup_params(t_x502_hnd hnd) {
|
||||
int32_t err = X502_ERR_OK, i;
|
||||
int ch_cnt = 1;//ADC_LCH_CNT;
|
||||
|
||||
X502_SetSyncMode(hnd, X502_SYNC_INTERNAL);
|
||||
//X502_SetSyncMode(hnd, X502_SYNC_DI_SYN1_FALL);
|
||||
X502_StreamsStop(hnd);
|
||||
|
||||
/* устанавливаем параметры логической таблицы АЦП */
|
||||
err = X502_SetLChannelCount(hnd, ch_cnt);
|
||||
for (i=0; (i < ch_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_din = DIN_FREQ;
|
||||
|
||||
err = X502_SetAdcFreq(hnd, &f_adc, NULL);
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_SetDinFreq(hnd, &f_din);
|
||||
if (err == X502_ERR_OK) {
|
||||
/* выводим реально установленные значения - те что вернули функции */
|
||||
printf("Установлены частоты:\n Частота сбора АЦП = %0.0f\n"
|
||||
" Частота цифрового ввода = %0.0f\n",
|
||||
f_adc, f_din);
|
||||
}
|
||||
}
|
||||
|
||||
double dout_freq = DOUT_FREQ;
|
||||
|
||||
err = X502_SetOutFreq(hnd, &dout_freq);
|
||||
printf("X502_SetOutFreq err=%d dout_freq = %.1f\n", err, dout_freq);
|
||||
|
||||
/* записываем настройки в модуль */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_Configure(hnd, 0);
|
||||
|
||||
/* разрешаем синхронные потоки */
|
||||
if (err == X502_ERR_OK) {
|
||||
int streams = 0;
|
||||
#if defined(STREAM_IN_ENABLE)
|
||||
streams |= STREAM_IN_ENABLE;
|
||||
#endif
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
streams |= X502_STREAM_ALL_OUT;
|
||||
#endif
|
||||
err = X502_StreamsEnable(hnd, streams);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void recv_proc(t_x502_hnd hnd) {
|
||||
struct timespec start_time;
|
||||
int32_t err = X502_ERR_OK;
|
||||
int32_t g_rcv_cnt = 0;
|
||||
int cntr = 0;
|
||||
int rcv_cntr = 1;//0x02000000;
|
||||
int din_rcv_cntr = 1;//0x02000000;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
#if !defined(STREAM_IN_ENABLE)
|
||||
if(1) {
|
||||
while(!f_out) {}
|
||||
} else
|
||||
#endif
|
||||
|
||||
while (err == X502_ERR_OK && !f_out) {
|
||||
int32_t rcv_size;
|
||||
uint32_t adc_size, din_size;
|
||||
/* массив для приема необработанных данных */
|
||||
static uint32_t rcv_buf[READ_BLOCK_SIZE];
|
||||
int i;
|
||||
struct timespec cur_time;
|
||||
|
||||
/* принимаем данные (по таймауту) */
|
||||
rcv_size = X502_Recv(hnd, rcv_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
//printf("rcv_size=%d\n", rcv_size);
|
||||
g_rcv_cnt += rcv_size;
|
||||
int error = 0;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5) {
|
||||
printf("rcv speed=%ld wrds/sec adc_cntr=%x din_cntr=%x\n", (g_rcv_cnt) / (cur_time.tv_sec - start_time.tv_sec), rcv_cntr, din_rcv_cntr);
|
||||
start_time.tv_sec = cur_time.tv_sec;
|
||||
g_rcv_cnt = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rcv_size; i++) {
|
||||
|
||||
// тест с заглушкой DOUT -> DIN
|
||||
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(rcv_buf[i]);
|
||||
/* проверяем - это данные от АЦП или цифровых входов */
|
||||
#define INC_VAL 1
|
||||
#define ADC_WRD_MASK 0xFFFFFF
|
||||
if (g_test_mode == TEST_ADC_CNTR_FLAG) {
|
||||
if (rcv_buf[i] != din_rcv_cntr)
|
||||
{
|
||||
printf("DIN %x[%i] %x expected\n", rcv_buf[i], i, din_rcv_cntr);
|
||||
din_rcv_cntr = rcv_buf[i];
|
||||
error = 1;
|
||||
}
|
||||
din_rcv_cntr += INC_VAL;
|
||||
} else
|
||||
if (rcv_buf[i] == X502_STREAM_IN_MSG_OVERFLOW) {
|
||||
printf("overflow msg received!\n");
|
||||
}
|
||||
#if 1
|
||||
else
|
||||
if (type == STREAM_IN_WRD_ADC) {
|
||||
if ((rcv_buf[i] & ADC_WRD_MASK) != (rcv_cntr & WRD_MASK ))
|
||||
{
|
||||
printf("ADC %x[%i] %x expected\n", rcv_buf[i], i, rcv_cntr);
|
||||
rcv_cntr = rcv_buf[i];
|
||||
error = 1;
|
||||
}
|
||||
rcv_cntr += INC_VAL;
|
||||
} else
|
||||
if (type == STREAM_IN_WRD_DIN) {
|
||||
if ((rcv_buf[i] & WRD_MASK)!= (din_rcv_cntr & WRD_MASK))
|
||||
{
|
||||
printf("DIN %x[%i] %x expected\n", rcv_buf[i], i, din_rcv_cntr);
|
||||
din_rcv_cntr = rcv_buf[i];
|
||||
error = 1;
|
||||
}
|
||||
din_rcv_cntr += INC_VAL;
|
||||
} else {
|
||||
printf("unknown wrd %x[%i]\n", rcv_buf[i], i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* проверка нажатия клавиши для выхода */
|
||||
if (err == X502_ERR_OK) {
|
||||
if (_kbhit())
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
t_x502_hnd hnd;
|
||||
int32_t err = X502_ERR_OK;
|
||||
#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
|
||||
|
||||
hnd = select_dev_from_list(argc, argv, 0);
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (hnd == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* настраиваем параметры модуля */
|
||||
err = f_setup_params(hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define E502_REGS_ARM_DCI_TEST_MODE 0x10C
|
||||
|
||||
g_test_mode = TEST_MODE;
|
||||
// включаем режим когда по DCI должен передаваться счетчик начиная с 1
|
||||
X502_FpgaRegWrite(hnd, E502_REGS_ARM_DCI_TEST_MODE, g_test_mode);
|
||||
fprintf(stderr, "TEST_MODE = %x\n", g_test_mode);
|
||||
|
||||
X502_FpgaRegWrite(hnd, E502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
X502_FpgaRegWrite(hnd, E502_REGS_BF_CTL, X502_REGBIT_BF_CTL_BF_RESET_Msk);
|
||||
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
HANDLE thread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
|
||||
while(stream_ingibit_cntr > 0);
|
||||
Sleep(2);
|
||||
#else
|
||||
pthread_t threadId;
|
||||
// Create a thread that will function threadFunc()
|
||||
err = pthread_create(&threadId, NULL, &threadFunc, hnd);
|
||||
while(stream_ingibit_cntr > 0);
|
||||
sleep(2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* запуск синхронного ввода-вывода */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsStart(hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка запуска сбора данных: %s!\n", X502_GetErrorString(err));
|
||||
}
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int block;
|
||||
int32_t stop_err;
|
||||
|
||||
printf("Сбор данных запущен. Для останова нажмите %s\n",
|
||||
#ifdef _WIN32
|
||||
"любую клавишу"
|
||||
#else
|
||||
"CTRL+C"
|
||||
#endif
|
||||
);
|
||||
fflush(stdout);
|
||||
|
||||
recv_proc(hnd);
|
||||
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
|
||||
#ifdef _WIN32
|
||||
//TODO: pthread_join
|
||||
#else
|
||||
pthread_join(threadId, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* останавливаем поток сбора данных (независимо от того, была ли ошибка) */
|
||||
stop_err = X502_StreamsStop(hnd);
|
||||
if (stop_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова сбора данных: %s\n", X502_GetErrorString(err));
|
||||
if (err == X502_ERR_OK)
|
||||
err = stop_err;
|
||||
} else {
|
||||
printf("Сбор данных остановлен успешно\n");
|
||||
}
|
||||
}
|
||||
|
||||
// выключаем режим когда по DCI должен передаваться счетчик начиная с 1
|
||||
X502_FpgaRegWrite(hnd, E502_REGS_ARM_DCI_TEST_MODE, 0);
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(hnd);
|
||||
return err;
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int clock_gettime(int a, struct timespec *spec) {
|
||||
__int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
|
||||
wintime -=116444736000000000i64; //1jan1601 to 1jan1970
|
||||
spec->tv_sec =wintime / 10000000i64; //seconds
|
||||
spec->tv_nsec =wintime % 10000000i64 *100; //nano-seconds
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *result) {
|
||||
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||
result->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
if (result->tv_nsec < 0) {
|
||||
--result->tv_sec;
|
||||
result->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
double timespec_to_double(struct timespec *ts)
|
||||
{
|
||||
return ((double)(ts->tv_sec) + ((double)(ts->tv_nsec) / NSEC_PER_SEC));
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
#ifndef __TIMESPEC_FUNCS_H__
|
||||
#define __TIMESPEC_FUNCS_H__
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CLOCK_MONOTONIC 1
|
||||
int clock_gettime(int a, struct timespec *spec);
|
||||
|
||||
#endif //_WIN32
|
||||
|
||||
void timespec_diff(struct timespec *a, struct timespec *b, struct timespec *result);
|
||||
double timespec_to_double(struct timespec *ts);
|
||||
|
||||
#endif //__TIMESPEC_FUNCS_H__
|
||||
@ -0,0 +1,34 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DL502API_INCLUDE_DIR=<путь к заголовочным файлам l502api> -DL502API_LIBRARIES_DIR=<путь к файлу линкера l502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DL502API_INCLUDE_DIR и -DL502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
set(PROJECT e16_dac_shift_test)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c ../common/dev_funcs.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR} ../common)
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
target_link_libraries(${PROJECT} m)
|
||||
endif(CMAKE_COMPILER_IS_GNUCC)
|
||||
458
lib/x502api-1.1.34/examples/c/e16_dac_shift_test/main.c
Normal file
458
lib/x502api-1.1.34/examples/c/e16_dac_shift_test/main.c
Normal file
@ -0,0 +1,458 @@
|
||||
/* Данный пример демонстрирует возможность установки циклического сигнала на
|
||||
вывод в модуль E16 / E502 / L502 (ввод не используется вообще).
|
||||
|
||||
В примере определена таблица сигналов, которая задает несколько
|
||||
комбинаций сигналов для примера. Каждый сигнал задается количеством точек
|
||||
на период (общее значение для всех трех сигналов), амплитудой для ЦАП'ов и
|
||||
функцией для генерации очередного отсчета по его номеру и полному размеру.
|
||||
|
||||
Пользовтель может ввести номер сигнала, которых он хочет выставить и нажать Enter - и этот
|
||||
сигнал будет выставлен на выходе.
|
||||
|
||||
Смена сигнала происходит по концу периода предыдущего.
|
||||
Надо также помнить, что хотя мы можем загружать новый сигнал на фоне вывода
|
||||
предыдущего, однако сразу после выполнения L502_OutCycleSetup() до того
|
||||
времени как реально произойдет смена старого сигнала на новый нельзя
|
||||
начинать загружать еще один новый сигнал.
|
||||
|
||||
|
||||
Данный пример содержит проект для Visual Studio 2008, а также может быть собран
|
||||
gcc в Linux или mingw в Windows через makefile или с помощью cmake (подробнее
|
||||
в коментариях в соответствующих файлах).
|
||||
|
||||
Для того чтобы собрать проект в Visual Studio, измените путь к заголовочным файлам
|
||||
(Проект (Project) -> Свойства (Properties) -> Свойства конфигурации (Configuration Properties)
|
||||
-> С/С++ -> Общие (General) -> Дополнительные каталоги включения (Additional Include Directories))
|
||||
на тот, где у вас лежат заголовочный файл l502api.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 "l502api.h"
|
||||
#include "e502api.h"
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "dev_funcs.h"
|
||||
|
||||
#define ADC_FREQ 2000000
|
||||
#define ADC_LCH_CNT 1
|
||||
#define READ_BLOCK_SIZE 4096*66*3
|
||||
#define READ_TIMEOUT 2000
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
#define OUT_SIGNAL_SIZE 2000
|
||||
#define OUT_BLOCK_SIZE 256
|
||||
#define SEND_TOUT 500
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
uint16_t random_hex[] = {
|
||||
0x93f8,
|
||||
0x05f4,
|
||||
0x9bf6,
|
||||
0x7ffe,
|
||||
0x161e,
|
||||
0xe7ba,
|
||||
0xf1af,
|
||||
0x1e0f,
|
||||
0x5ec0,
|
||||
0xc8ff,
|
||||
0x55e2,
|
||||
0x9df0,
|
||||
0x6a6c,
|
||||
0xa649,
|
||||
0x1ade,
|
||||
0x1b24,
|
||||
0x343d,
|
||||
0x7b6b,
|
||||
0x76b9,
|
||||
0xc8fc,
|
||||
0x2e3a,
|
||||
0x24d9,
|
||||
0xf189,
|
||||
0xf1d1,
|
||||
0xff71,
|
||||
0xe23c,
|
||||
0xa77f,
|
||||
0x4d8e,
|
||||
0x2858,
|
||||
0xa96d,
|
||||
0xf289,
|
||||
0x7337,
|
||||
0x640b,
|
||||
0x57e9,
|
||||
0x39ce,
|
||||
0xdbd9,
|
||||
0xb832,
|
||||
0x315d,
|
||||
0x441c,
|
||||
0x863e,
|
||||
0xf7b9,
|
||||
0x8ecf,
|
||||
0x1010,
|
||||
0x88da,
|
||||
0xeb76,
|
||||
0x9302,
|
||||
0xc160,
|
||||
0x7238,
|
||||
0xdda0,
|
||||
0x4f94
|
||||
|
||||
};
|
||||
|
||||
typedef double (*f_gen_sig_word)(uint32_t cntr, uint32_t total_size, double amp);
|
||||
typedef uint32_t (*f_gen_dout_word)(uint32_t cntr, uint32_t total_size);
|
||||
/* структура, задающая сигналы на 2-х каналах ЦАП и/или1
|
||||
1на DOUT */
|
||||
typedef struct {
|
||||
uint32_t size; /* количество точек в сигнале */
|
||||
double amp_dac1; /* амплитуда сигнала для ЦАП1 */
|
||||
f_gen_sig_word gen_func_dac1; /* функция для генерации отсчета для ЦАП1 */
|
||||
double amp_dac2; /* амплитуда сигнала для ЦАП2 */
|
||||
f_gen_sig_word gen_func_dac2; /* функция для генерации отсчета для ЦАП2 */
|
||||
f_gen_dout_word gen_dout; /* функция для генерации слова на цифровой вывод */
|
||||
} t_sig_struct;
|
||||
|
||||
/* номера используемых физических каналов */
|
||||
static uint32_t f_channels[] = {1};
|
||||
/* режимы измерения для каналов */
|
||||
static uint32_t f_ch_modes[] = {X502_LCH_MODE_COMM, X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF};
|
||||
/* диапазоны измерения для каналов */
|
||||
static uint32_t f_ch_ranges[] = {X502_ADC_RANGE_10, X502_ADC_RANGE_10, X502_ADC_RANGE_02};
|
||||
|
||||
/* генерация пилы на весь период */
|
||||
static double f_gen_saw(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return amp*( (int32_t)(cntr%total_size)-(int32_t)total_size/2)/(total_size/2);
|
||||
}
|
||||
|
||||
/* генерация синуса на весь период */
|
||||
static double f_gen_sin(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return amp*sin(2*M_PI*cntr/total_size);
|
||||
}
|
||||
|
||||
/* генерация тестового счетчика */
|
||||
static double f_gen_cntr(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return cntr + 0x123;
|
||||
}
|
||||
|
||||
/* генерация синуса с периодом в два раза меньше периоду определяемому размером буфера */
|
||||
static double f_gen_sin2(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return amp*sin(2*2*M_PI*cntr/total_size);
|
||||
}
|
||||
|
||||
static double f_gen_meander(uint32_t cntr, uint32_t total_size) {
|
||||
return cntr < total_size/2 ? 5 : -1;
|
||||
}
|
||||
|
||||
/* генерация меандра на всех выходах путем выдачи в первой половине на выходы 0xAA, а на второй 0x55 */
|
||||
static uint32_t f_gen_dout_meander(uint32_t cntr, uint32_t total_size) {
|
||||
return cntr < total_size/2 ? 0xAA : 0x55;
|
||||
}
|
||||
|
||||
/* генерация счетчика на цифроых выхоах*/
|
||||
static uint32_t f_gen_dout_cntr(uint32_t cntr, uint32_t total_size) {
|
||||
return cntr;
|
||||
}
|
||||
|
||||
|
||||
/* таблица, задающая сигналы для выдачи на вход */
|
||||
/* для модуля E16 частота выходного сигнала будет в 2 раза меньше, т.к. частота ЦАП 500КГц против 1МГц у E502 */
|
||||
static t_sig_struct f_sig_tbl[] = {
|
||||
{1000, X502_DAC_RANGE, f_gen_saw, 0, NULL, NULL}, /* пила на одном канале с частотой 250?? Гц */
|
||||
{2000, 2.5, f_gen_meander, 0, NULL, NULL}, /* синусоидальный сигнал на одном канале с частотой 500 Гц */
|
||||
{100, X502_DAC_RANGE/2, f_gen_sin, X502_DAC_RANGE, f_gen_saw, NULL}, /* синус ампл. 2.5 и пила по 10 КГц */
|
||||
{50, 0, NULL, X502_DAC_RANGE, f_gen_sin, f_gen_dout_cntr}, /* синус только на втором канале с частотой 20 КГц */
|
||||
{2550, 1.5, f_gen_sin, 2.5, f_gen_sin2, f_gen_dout_meander}, /* на втором канале синус с частотой в 2 раза больше. меандр на цифровых линиях */
|
||||
};
|
||||
|
||||
|
||||
/* Запись в буфер драйвера блока данных от сигнала
|
||||
cntr - номер отчета, соответствующего первому отсчету блока
|
||||
size - количество отсчетов на канал (т.е. записывается ch_cnt*size отсчетов)
|
||||
sig - номер сигнала
|
||||
ch_cnt - кол-во используемых каналов (это кол-во можно определить по f_sig_tbl[sig],
|
||||
но так как мы его уже определили, то передаем сюда, чтобы опять не определять */
|
||||
static int32_t f_load_block(t_x502_hnd hnd, uint32_t cntr, uint32_t size, uint32_t sig, uint32_t ch_cnt) {
|
||||
static double dac_data1[OUT_BLOCK_SIZE], dac_data2[OUT_BLOCK_SIZE];
|
||||
static uint32_t dout_data[OUT_BLOCK_SIZE];
|
||||
/* массив слов на запись в модуль - содержит смешенные подготовленные данные
|
||||
для всех каналов (максимум для 3-х - 2 ЦАП + DOUT) */
|
||||
static uint32_t sbuf[3*OUT_BLOCK_SIZE];
|
||||
uint32_t i;
|
||||
int32_t err = 0;
|
||||
|
||||
/* заполняем массив на вывод */
|
||||
for (i=0; i < size; i++) {
|
||||
if (f_sig_tbl[sig].gen_func_dac1 != NULL) {
|
||||
dac_data1[i] = f_sig_tbl[sig].gen_func_dac1(cntr+i, f_sig_tbl[sig].size, f_sig_tbl[sig].amp_dac1);
|
||||
}
|
||||
if (f_sig_tbl[sig].gen_func_dac2 != NULL) {
|
||||
dac_data2[i] = f_sig_tbl[sig].gen_func_dac2(cntr+i, f_sig_tbl[sig].size, f_sig_tbl[sig].amp_dac2);
|
||||
}
|
||||
if (f_sig_tbl[sig].gen_dout != NULL) {
|
||||
dout_data[i] = f_sig_tbl[sig].gen_dout(cntr+i, f_sig_tbl[sig].size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Если нужная функция определена, значит мы испоьлзуем этот канал, и
|
||||
* подаем на вход сформированный массив. Иначе - канал не используется
|
||||
* и передаем на вход NULL */
|
||||
err = X502_PrepareData(hnd,
|
||||
f_sig_tbl[sig].gen_func_dac1 ? dac_data1 : NULL,
|
||||
f_sig_tbl[sig].gen_func_dac2 ? dac_data2 : NULL,
|
||||
f_sig_tbl[sig].gen_dout ? dout_data : NULL,
|
||||
size, X502_DAC_FLAGS_VOLT | X502_DAC_FLAGS_CALIBR,
|
||||
sbuf);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка подкотовки данных на передачу: %s\n",
|
||||
X502_GetErrorString(err));
|
||||
} else {
|
||||
/* посылаем данные */
|
||||
int32_t snd_cnt = X502_Send(hnd, sbuf, size*ch_cnt, SEND_TOUT);
|
||||
if (snd_cnt < 0) {
|
||||
err = snd_cnt;
|
||||
fprintf(stderr, "Ошибка передачи данных: %s\n", X502_GetErrorString(err));
|
||||
} else if ((uint32_t)snd_cnt != size*ch_cnt) {
|
||||
/* так как мы шлем всегда не больше чем готово, то должны
|
||||
всегда передать все */
|
||||
fprintf(stderr, "Переданно недостаточно данных: передавали = %d, передано = %d\n",
|
||||
size*ch_cnt, snd_cnt);
|
||||
err = X502_ERR_SEND_INSUFFICIENT_WORDS;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int32_t f_load_cycle_signal(t_x502_hnd hnd, int sig) {
|
||||
int32_t err = 0;
|
||||
uint32_t cntr = 0;
|
||||
uint32_t ch_cnt=0;
|
||||
|
||||
/* определяем, сколько каналов используем */
|
||||
if (f_sig_tbl[sig].gen_func_dac1)
|
||||
ch_cnt++;
|
||||
if (f_sig_tbl[sig].gen_func_dac2)
|
||||
ch_cnt++;
|
||||
if (f_sig_tbl[sig].gen_dout)
|
||||
ch_cnt++;
|
||||
|
||||
|
||||
/* задаем размер буфера под все каналы! */
|
||||
err = X502_OutCycleLoadStart(hnd, f_sig_tbl[sig].size*ch_cnt);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка старта загрузки данных: %s!", X502_GetErrorString(err));
|
||||
|
||||
/* в примере показано, что загружать можно поблочно, чтобы не выделять
|
||||
* большой размер памяти на весь сигнал в программе. Но можно записать
|
||||
* весь сигнал и за один L502_Send() */
|
||||
while ((cntr != f_sig_tbl[sig].size) && (err == X502_ERR_OK)) {
|
||||
uint32_t block_size = OUT_BLOCK_SIZE;
|
||||
/* последний блок может быть меньшего размера, если размер буфера не кратен
|
||||
* блоку */
|
||||
if (block_size >(f_sig_tbl[sig].size-cntr))
|
||||
block_size=f_sig_tbl[sig].size-cntr;
|
||||
|
||||
err = f_load_block(hnd, cntr, block_size, sig, ch_cnt);
|
||||
if (!err)
|
||||
cntr+=block_size;
|
||||
}
|
||||
|
||||
/* делаем активным загруженный сигнал */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_OutCycleSetup(hnd, X502_OUT_CYCLE_FLAGS_WAIT_DONE);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка установки циклического сигнала: %s!", X502_GetErrorString(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
err = X502_SetAdcFreq(hnd, &f_adc, NULL);
|
||||
if (err == X502_ERR_OK) {
|
||||
/* выводим реально установленные значения - те что вернули функции */
|
||||
printf("Установлены частоты:\n Частота сбора АЦП = %0.0f\n", f_adc);
|
||||
}
|
||||
}
|
||||
|
||||
/* записываем настройки в модуль */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_Configure(hnd, 0);
|
||||
}
|
||||
|
||||
#define VAL_TOLERANCE 0.01
|
||||
#define LEN_TOLERANCE 10
|
||||
|
||||
|
||||
int f_test_length(const double *data, const size_t size, const int print){
|
||||
uint32_t len = 0;
|
||||
uint32_t old_len = 0;
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < size - 1; i++){
|
||||
if( abs(data[i] - data[i + 1]) > VAL_TOLERANCE) {
|
||||
if(print){
|
||||
printf("Front: %d, Length: %d\n", count, len);
|
||||
}
|
||||
|
||||
if ((count > 1) && (abs(old_len - len) > LEN_TOLERANCE) ){
|
||||
return 1;
|
||||
}
|
||||
|
||||
i++;
|
||||
count++;
|
||||
old_len = len;
|
||||
len = 0;
|
||||
} else {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int32_t err = 0;
|
||||
uint32_t ver;
|
||||
t_x502_hnd hnd = NULL;
|
||||
|
||||
int flag_verbose = 0;
|
||||
int flag_exit_on_err = 1;
|
||||
|
||||
int32_t rcv_size;
|
||||
uint32_t adc_size;
|
||||
static uint32_t rcv_buf[READ_BLOCK_SIZE];
|
||||
static double adc_data[READ_BLOCK_SIZE];
|
||||
|
||||
#ifdef _WIN32
|
||||
/* устанавливаем локаль, чтобы можно было выводить по-русски в CP1251 без перевода в OEM */
|
||||
setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < argc; i++){
|
||||
if (!strcmp(argv[i], "verbose")){
|
||||
flag_verbose = 1;
|
||||
}
|
||||
if(!strcmp(argv[i], "continue-on-err")){
|
||||
flag_exit_on_err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
hnd = select_dev_from_list(argc, argv, 0);
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (hnd != NULL) {
|
||||
|
||||
/* Разрешаем dac1 на вывод and enable adc input */
|
||||
err = X502_StreamsEnable(hnd, X502_STREAM_ADC | X502_STREAM_DAC1);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка разрешения потоков (%d): %s!", err,
|
||||
X502_GetErrorString(err));
|
||||
} else {
|
||||
err = f_setup_params(hnd);
|
||||
if (err != X502_ERR_OK){
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!\n", X502_GetErrorString(err));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
/* если хотим, то можем загрузить синхнал до разрешения
|
||||
* синхронного ввода. Тогда мы могли бы его запустить, наприемер,
|
||||
всесте с АЦП по L502_StreamsStart() */
|
||||
err = f_load_cycle_signal(hnd, 1);
|
||||
|
||||
/* разрешаем синхронный ввод. В принципе можно его разрешить только
|
||||
* после загрузки первого синала в нашем примере. Но данный пример
|
||||
* показывает что мы можем сделать это и до выставления сигнала,
|
||||
* например если захотим запустить ввод АЦП до того как будет нужно
|
||||
* подать циклический сигнал на вывод */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_StreamsStart(hnd);
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int exit = 0;
|
||||
|
||||
uint32_t err_cnt = 0;
|
||||
/* Цикл ввода команд */
|
||||
for (int block = 0; (err == X502_ERR_OK); block++) {
|
||||
X502_AsyncOutDig(hnd, random_hex[block % sizeof(random_hex)], 0);
|
||||
// printf("0x%x\n", random_hex[block % sizeof(random_hex)]);
|
||||
rcv_size = X502_Recv(hnd, rcv_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
if (rcv_size < 0) {
|
||||
err = rcv_size;
|
||||
fprintf(stderr, "Ошибка приема данных: %s\n", X502_GetErrorString(err));
|
||||
}
|
||||
if (rcv_size > 0) {
|
||||
uint32_t first_lch;
|
||||
/* получаем номер логического канала, которому соответствует первый отсчет АЦП в массиве */
|
||||
X502_GetNextExpectedLchNum(hnd, &first_lch);
|
||||
|
||||
adc_size = sizeof(adc_data)/sizeof(adc_data[0]);
|
||||
|
||||
/* обрабатываем принятые данные, распределяя их на данные АЦП и цифровых входов */
|
||||
err = X502_ProcessData(hnd, rcv_buf, rcv_size, X502_PROC_FLAGS_VOLT, adc_data, &adc_size, NULL, NULL);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка обработки данных: %s\n", X502_GetErrorString(err));
|
||||
} else {
|
||||
uint32_t lch;
|
||||
|
||||
printf("Блок %3d. Обработано данных АЦП =%d\n", block, adc_size);
|
||||
|
||||
int ret = f_test_length(adc_data, adc_size, flag_verbose);
|
||||
if (ret) {
|
||||
err_cnt++;
|
||||
printf("Cycle shifted %d times!\n", err_cnt);
|
||||
if (flag_exit_on_err) {
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// for (uint32_t i = 0; i < adc_size; i++){
|
||||
// printf("%6.4f\n", adc_data[i]);
|
||||
// }
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
X502_StreamsStop(hnd);
|
||||
}
|
||||
}
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(hnd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
48
lib/x502api-1.1.34/examples/c/e16_dac_shift_test/makefile
Normal file
48
lib/x502api-1.1.34/examples/c/e16_dac_shift_test/makefile
Normal file
@ -0,0 +1,48 @@
|
||||
# makefile для сборки примера с помощью компиляторов mingw (под Windows)
|
||||
# или GCC (под Linux). Необходимо определить 3 переменные:
|
||||
#
|
||||
# CC - имя команды для вызова компилятора
|
||||
# X502API_LIBRARIES_DIR - путь к файлм .a или .so библиотек l502api, e502api, x502api (если не стандартный)
|
||||
# X502API_INCLUDE_DIR - путь к заголовочным файлам l502api.h, e502api.h, x502api.h
|
||||
#
|
||||
# Ниже приведено несколько примеров в закоментированном виде
|
||||
|
||||
#--- Linux с заголовками и библиотекой в стандартных директориях: компилятор GCC
|
||||
#CC = gcc
|
||||
|
||||
#--- Вариант запуска из MSYS со стандартным 32-битным mingw
|
||||
#CC = gcc
|
||||
#X502API_LIBRARIES_DIR = "/c/Program Files/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/c/Program Files/L-Card/lpcie/include"
|
||||
|
||||
|
||||
#--- 64-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = x86_64-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw64"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = i686-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw, идущий вместе с cygwin --------
|
||||
#CC = i686-pc-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
|
||||
FLAGS =
|
||||
|
||||
ifdef X502API_LIBRARIES_DIR
|
||||
FLAGS += -L $(X502API_LIBRARIES_DIR)
|
||||
endif
|
||||
|
||||
ifdef X502API_INCLUDE_DIR
|
||||
FLAGS += -I $(X502API_INCLUDE_DIR)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
all:
|
||||
$(CC) main.c $(FLAGS) -ll502api -le502api -lx502api -o e16_dac_shift_test
|
||||
@ -0,0 +1,34 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
set(PROJECT e16_overflow_test)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:CONSOLE,5.01")
|
||||
endif(MSVC)
|
||||
set(SOURCES main.c ../common/dev_funcs.c ../common/timespec_funcs.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR} ../common)
|
||||
#include_directories(${LTEST_SOURCE_DIR}/../)
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
568
lib/x502api-1.1.34/examples/c/e16_overflow_test/main.c
Normal file
568
lib/x502api-1.1.34/examples/c/e16_overflow_test/main.c
Normal file
@ -0,0 +1,568 @@
|
||||
#include "l502api.h"
|
||||
#include "e502api.h"
|
||||
#include "dev_funcs.h"
|
||||
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "timespec_funcs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "x502api_private.h"
|
||||
|
||||
#include "../../devs/e502/e502_cm4_defs.h"
|
||||
|
||||
#define STREAM_IN_WRD_TYPE(wrd) wrd & 0x80000000 ? STREAM_IN_WRD_ADC : \
|
||||
(wrd & 0xFF000000) == 0x0 ? STREAM_IN_WRD_DIN : \
|
||||
((wrd & 0xFF000000)>>24) == 0x01 ? STREAM_IN_WRD_MSG : STREAM_IN_WRD_USR
|
||||
|
||||
|
||||
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
static volatile int f_out = 0;
|
||||
|
||||
/* количество используемых логических каналов */
|
||||
#define ADC_LCH_CNT 3
|
||||
|
||||
/* частота сбора АЦП в Гц*/
|
||||
//#define ADC_FREQ 2000000
|
||||
#define ADC_FREQ 400000
|
||||
/* частота кадров (на логический канал). При ADC_FREQ/ADC_LCH_CNT - межкадровой задержки нет */
|
||||
#define ADC_FRAME_FREQ (ADC_FREQ/ADC_LCH_CNT)
|
||||
/* частота синхронного ввода в Гц*/
|
||||
#define DIGIN_FREQ 20000
|
||||
#define DIGOUT_FREQ 400000
|
||||
|
||||
//#define ENABLE_DAC1
|
||||
//#define ENABLE_DAC2
|
||||
|
||||
#define E16_REG_TEST_ADC_CNTR_BIT 0
|
||||
#define E16_REG_TEST_WR_DISABLE_BIT 6
|
||||
#define E16_REG_TEST_RING_MODE_BIT 5
|
||||
|
||||
#define DIN_WRD_MASK 0xffff
|
||||
|
||||
/* сколько отсчетов считываем за блок */
|
||||
#define READ_BLOCK_SIZE 4096*66*3
|
||||
|
||||
/* таймаут на прием блока (мс) */
|
||||
#define READ_TIMEOUT 500
|
||||
|
||||
|
||||
uint32_t tstCntr = 0x7788;
|
||||
uint32_t tstCntr24 = 0x7788;
|
||||
|
||||
int dac2_once = 1;
|
||||
|
||||
typedef struct {
|
||||
t_x502_hnd hnd;
|
||||
// частота дискретизации АЦП
|
||||
double adc_freq;
|
||||
bool ring_mode;
|
||||
bool verbose;
|
||||
bool status_mode;
|
||||
bool is_e502;
|
||||
double digout_freq;
|
||||
double digin_freq;
|
||||
int streams_en;
|
||||
} t_test_par;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI ThreadFunc(void *arg)
|
||||
#else
|
||||
void * threadFunc(void *arg)
|
||||
#endif
|
||||
{
|
||||
t_test_par *par = (t_test_par*)arg;
|
||||
int32_t g_snd_cnt = 0;
|
||||
static uint32_t snd_buf[READ_BLOCK_SIZE];
|
||||
struct timespec start_time;
|
||||
struct timespec cur_time;
|
||||
struct timespec spent_time;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
while(!f_out) {
|
||||
int32_t snd_cnt = 0;
|
||||
uint32_t to_send = READ_BLOCK_SIZE;
|
||||
uint32_t *to_send_ptr = snd_buf;
|
||||
|
||||
for (int i = 0; i < READ_BLOCK_SIZE; ) {
|
||||
snd_buf[i] = tstCntr24 & 0xffff;
|
||||
i++;
|
||||
#ifdef ENABLE_DAC1
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC1;
|
||||
i++;
|
||||
#endif
|
||||
#ifdef ENABLE_DAC2
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC2;
|
||||
i++;
|
||||
#endif
|
||||
tstCntr++;
|
||||
tstCntr24++;
|
||||
}
|
||||
|
||||
while (to_send && !f_out) {
|
||||
snd_cnt = X502_Send(par->hnd, to_send_ptr, to_send, READ_TIMEOUT);
|
||||
if (snd_cnt < 0 || f_out) {
|
||||
printf("thread exiting X502_Send err=%d\n", snd_cnt);
|
||||
return snd_cnt;
|
||||
}
|
||||
to_send -= snd_cnt;
|
||||
to_send_ptr += snd_cnt;
|
||||
}
|
||||
|
||||
g_snd_cnt += READ_BLOCK_SIZE;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5)
|
||||
{
|
||||
timespec_diff(&cur_time, &start_time, &spent_time);
|
||||
|
||||
printf("cnt=%d sec=%f snd speed=%f wrds/sec\n", g_snd_cnt, timespec_to_double(&spent_time), g_snd_cnt / timespec_to_double(&spent_time));
|
||||
start_time = cur_time;
|
||||
g_snd_cnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* номера используемых физических каналов */
|
||||
static uint32_t f_channels[ADC_LCH_CNT] = {0,4,6};
|
||||
/* режимы измерения для каналов */
|
||||
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_ZERO, X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF};
|
||||
/* диапазоны измерения для каналов */
|
||||
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_10, X502_ADC_RANGE_10, X502_ADC_RANGE_10};
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Обработчик сигнала завершения для Linux */
|
||||
static void f_abort_handler(int sig) {
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* настройка параметров модуля */
|
||||
int32_t f_setup_params(t_test_par *par) {
|
||||
int32_t err = X502_ERR_OK, i;
|
||||
int ch_cnt = 1;//ADC_LCH_CNT;
|
||||
|
||||
X502_SetSyncMode(par->hnd, X502_SYNC_INTERNAL);
|
||||
//X502_SetSyncMode(par->hnd, X502_SYNC_DI_SYN1_FALL);
|
||||
X502_StreamsStop(par->hnd);
|
||||
X502_StreamsDisable(par->hnd, X502_STREAM_ALL_IN | X502_STREAM_ALL_OUT);
|
||||
|
||||
/* устанавливаем параметры логической таблицы АЦП */
|
||||
err = X502_SetLChannelCount(par->hnd, ch_cnt);
|
||||
for (i=0; (i < ch_cnt) && (err == X502_ERR_OK); i++)
|
||||
err = X502_SetLChannel(par->hnd, i, f_channels[i], f_ch_modes[i], f_ch_ranges[i], 0);
|
||||
|
||||
/* устанавливаем частоты ввода для АЦП и цифровых входов */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_SetAdcFreq(par->hnd, &par->adc_freq, NULL);
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_SetDinFreq(par->hnd, &par->digin_freq);
|
||||
if (err == X502_ERR_OK) {
|
||||
/* выводим реально установленные значения - те что вернули функции */
|
||||
printf("Установлены частоты:\n Частота сбора АЦП = %0.0f\n"
|
||||
" Частота цифрового ввода = %0.0f\n",
|
||||
par->adc_freq, par->digin_freq);
|
||||
}
|
||||
}
|
||||
|
||||
err = X502_SetOutFreq(par->hnd, &par->digout_freq);
|
||||
printf("X502_SetOutFreq err=%d dout_freq = %.1f\n", err, par->digout_freq);
|
||||
|
||||
/* разрешаем синхронные потоки */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsEnable(par->hnd, par->streams_en);
|
||||
}
|
||||
/* записываем настройки в модуль */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_Configure(par->hnd, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
void recv_proc(t_test_par *par) {
|
||||
struct timespec start_time;
|
||||
int32_t err = X502_ERR_OK;
|
||||
int32_t g_rcv_cnt = 0;
|
||||
int cntr = 0;
|
||||
int rcv_cntr = 1;//0x02000000;
|
||||
int last_good_rcv_cntr = 1;//0x02000000;
|
||||
int din_rcv_cntr = 1;//0x02000000;
|
||||
int din_error_cntr = 0;
|
||||
uint32_t ADC_WRD_MASK = 0xFFFFFF;
|
||||
|
||||
if (par->ring_mode) {
|
||||
// если включен режим E16_REG_TEST_RING_MODE_BIT то проверяем только 16 бит
|
||||
// 32бит 31бит - из потока ЦАП переходят 18 и 17 бит потока АЦП при включенном ring mode
|
||||
ADC_WRD_MASK = 0xFFFF;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
if ((par->streams_en & (X502_STREAM_ADC | X502_STREAM_DIN)) == 0) {
|
||||
while(!f_out) {}
|
||||
} else
|
||||
|
||||
while (err == X502_ERR_OK && !f_out) {
|
||||
int32_t rcv_size;
|
||||
uint32_t adc_size, din_size;
|
||||
/* массив для приема необработанных данных */
|
||||
static uint32_t rcv_buf[READ_BLOCK_SIZE];
|
||||
int i;
|
||||
struct timespec cur_time;
|
||||
|
||||
/* принимаем данные (по таймауту) */
|
||||
rcv_size = X502_Recv(par->hnd, rcv_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
if (rcv_size < 0) {
|
||||
fprintf(stderr, "Recv(%d) = %d\n", READ_BLOCK_SIZE, rcv_size);
|
||||
break;
|
||||
}
|
||||
g_rcv_cnt += rcv_size;
|
||||
int error = 0;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5 && par->verbose) {
|
||||
printf("rcv speed=%ld wrds/sec adc_cntr=%x din_cntr=%x din_error_cntr=%d\n", (g_rcv_cnt) / (cur_time.tv_sec - start_time.tv_sec), rcv_cntr, din_rcv_cntr, din_error_cntr);
|
||||
start_time.tv_sec = cur_time.tv_sec;
|
||||
g_rcv_cnt = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rcv_size; i++) {
|
||||
|
||||
// тест с заглушкой DOUT -> DIN
|
||||
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(rcv_buf[i]);
|
||||
/* проверяем - это данные от АЦП или цифровых входов */
|
||||
#define INC_VAL 1
|
||||
if (rcv_buf[i] == X502_STREAM_IN_MSG_OVERFLOW) {
|
||||
if (rcv_buf[i] == rcv_cntr) {
|
||||
// в E502 и E16 есть различие в режиме E16_REG_TEST_ADC_CNTR_BIT
|
||||
// в E502 сырой счетчик 32 бит
|
||||
// в E16 счетчик 24 бит, и чередование признака каналов какой был задан
|
||||
rcv_cntr += INC_VAL;
|
||||
} else {
|
||||
printf("overflow msg received!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
if (par->is_e502 || type == STREAM_IN_WRD_ADC) {
|
||||
if ((rcv_buf[i] & ADC_WRD_MASK) != (rcv_cntr & ADC_WRD_MASK ))
|
||||
{
|
||||
printf("ADC %x[%i] %x expected\n", rcv_buf[i], i, rcv_cntr);
|
||||
printf("diff %d\n", (rcv_buf[i] & ADC_WRD_MASK) - (rcv_cntr & ADC_WRD_MASK));
|
||||
rcv_cntr = rcv_buf[i];
|
||||
error = 1;
|
||||
}
|
||||
rcv_cntr += INC_VAL;
|
||||
} else
|
||||
if (type == STREAM_IN_WRD_DIN) {
|
||||
if ((rcv_buf[i] & DIN_WRD_MASK)!= (din_rcv_cntr & DIN_WRD_MASK))
|
||||
{
|
||||
if (!din_error_cntr) {
|
||||
printf("DIN %x[%i] %x expected\n", rcv_buf[i], i, din_rcv_cntr);
|
||||
printf("diff %d\n", (rcv_buf[i] & DIN_WRD_MASK) - (din_rcv_cntr & DIN_WRD_MASK));
|
||||
}
|
||||
din_rcv_cntr = rcv_buf[i];
|
||||
din_error_cntr++;
|
||||
} else {
|
||||
if (din_error_cntr) {
|
||||
printf("DIN error cntr: %d, rcv_val = %x\n", din_error_cntr, rcv_buf[i]);
|
||||
printf("din_cntr - last_good = %d\n", (rcv_buf[i] & DIN_WRD_MASK) - (last_good_rcv_cntr & DIN_WRD_MASK));
|
||||
}
|
||||
last_good_rcv_cntr = rcv_buf[i];
|
||||
din_error_cntr = 0;
|
||||
}
|
||||
din_rcv_cntr += INC_VAL;
|
||||
} else {
|
||||
if ((rcv_buf[i] & ADC_WRD_MASK) != (rcv_cntr & ADC_WRD_MASK ))
|
||||
{
|
||||
printf("unknown wrd %x[%i] %x expected\n", rcv_buf[i], i, rcv_cntr);
|
||||
rcv_cntr = rcv_buf[i];
|
||||
}
|
||||
rcv_cntr += INC_VAL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* проверка нажатия клавиши для выхода */
|
||||
if (err == X502_ERR_OK) {
|
||||
if (_kbhit())
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#define ADC_FREQ_KEY "adc_freq"
|
||||
#define RING_MODE_KEY "ring"
|
||||
#define DIGOUT_FREQ_KEY "digout_freq"
|
||||
#define DIGIN_FREQ_KEY "digin_freq"
|
||||
#define VERBOSE_KEY "verbose"
|
||||
|
||||
void print_usage(char** argv) {
|
||||
fprintf(stderr, "Опции:\n");
|
||||
fprintf(stderr, " " ADC_FREQ_KEY ":частота АЦП в Гц, если не задано - выключен\n");
|
||||
fprintf(stderr, " " DIGOUT_FREQ_KEY ":частота цифрового вывода Гц, если не задано - выключен\n");
|
||||
fprintf(stderr, " " DIGIN_FREQ_KEY ":частота цифрового ввода Гц, если не задано - выключен\n");
|
||||
fprintf(stderr, " " RING_MODE_KEY "\tкольцевой тест: ЦАП -> АЦП, иначе тестовый счетчик по каналу АЦП\n");
|
||||
fprintf(stderr, " " VERBOSE_KEY "\tвыводить скорость\n");
|
||||
fprintf(stderr, "\nПример: использовать E16 по адресу 192.168.12.152 и установить частоту сбора 1000000 Гц:\n");
|
||||
fprintf(stderr, " %s E16:192.168.12.152 " ADC_FREQ_KEY ":1000000\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void parse_test_params(int argc, char** argv, t_test_par *par) {
|
||||
int i;
|
||||
|
||||
par->adc_freq = ADC_FREQ;
|
||||
par->ring_mode = false;
|
||||
par->digout_freq = DIGOUT_FREQ;
|
||||
par->digin_freq = DIGIN_FREQ;
|
||||
par->verbose = false;
|
||||
par->streams_en = 0;
|
||||
par->status_mode = false;
|
||||
|
||||
for (i=1; (int)i < argc; i++) {
|
||||
if (sscanf(argv[i], ADC_FREQ_KEY":%lf", &par->adc_freq) == 1) {
|
||||
par->streams_en |= X502_STREAM_ADC;
|
||||
} else
|
||||
if (sscanf(argv[i], DIGOUT_FREQ_KEY":%lf", &par->digout_freq) == 1) {
|
||||
par->streams_en |= X502_STREAM_ALL_OUT;
|
||||
} else
|
||||
if (sscanf(argv[i], DIGIN_FREQ_KEY":%lf", &par->digin_freq) == 1) {
|
||||
par->streams_en |= X502_STREAM_DIN;
|
||||
} else
|
||||
if (strcmp(argv[i], RING_MODE_KEY) == 0) {
|
||||
par->ring_mode = true;
|
||||
continue;
|
||||
} else
|
||||
if (strcmp(argv[i], VERBOSE_KEY) == 0) {
|
||||
par->verbose = true;
|
||||
} else
|
||||
if (strcmp("/?", argv[i]) == 0) {
|
||||
print_usage(argv);
|
||||
} else
|
||||
if (strcmp("--help", argv[i]) == 0) {
|
||||
print_usage(argv);
|
||||
} else
|
||||
if (strcmp("status", argv[i]) == 0) {
|
||||
par->status_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (par->ring_mode) {
|
||||
// если кольцевой тест, то включаем поток на вывод
|
||||
par->streams_en |= X502_STREAM_ALL_OUT | X502_STREAM_ADC;
|
||||
}
|
||||
}
|
||||
|
||||
int e502_lpc_tst_start(t_x502_hnd hnd, uint16_t test, uint16_t flags) {
|
||||
int err = E502_CortexExecCmd(hnd, E502_CM4_CMD_TEST_START,
|
||||
test | ((uint32_t)flags << 16),
|
||||
NULL, 0, NULL, 0, 0, NULL);
|
||||
return err ;
|
||||
}
|
||||
|
||||
int e502_lpc_tst_stop(t_x502_hnd hnd) {
|
||||
int err = E502_CortexExecCmd(hnd, E502_CM4_CMD_TEST_STOP,
|
||||
0, NULL, 0, NULL, 0, 0, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define E502_REGS_ARM_DCI_TEST_MODE 0x10C
|
||||
|
||||
t_x502_info dev_info;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
#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
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE thread;
|
||||
#else
|
||||
pthread_t thread;
|
||||
#endif
|
||||
|
||||
t_test_par par;
|
||||
|
||||
parse_test_params(argc, argv, &par);
|
||||
|
||||
// HACK:
|
||||
// сбрасываем флаг X502_DEVFLAGS_FPGA_LOADED,
|
||||
// таким образом никаких манипуляций с регистрами не происходит
|
||||
// и мы не нарушаем работу с уже запущенным потоком в другом экземпляре процесса
|
||||
par.hnd = select_dev_from_list(argc, argv, par.status_mode ? X502_DEVFLAGS_FPGA_LOADED : 0);
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (par.hnd == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = X502_GetDevInfo(par.hnd, &dev_info);
|
||||
par.is_e502 = strcmp(dev_info.name, "E502") ? false: true;
|
||||
printf("is_e502=%d\n", par.is_e502);
|
||||
|
||||
if (!err && par.status_mode) {
|
||||
// Специальный режим:
|
||||
// по usb проверяем исчерпание буфера на вывод и переполнение буфера на ввода
|
||||
// при этом поток идет по ethernet, через другой экземпляр данной утилиты (надо запустить отдельно и указать IP адрес!)
|
||||
uint32_t status;
|
||||
struct timespec start_time;
|
||||
struct timespec cur_time;
|
||||
struct timespec spent_time;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
while (!f_out) {
|
||||
err = X502_OutGetStatusFlags(par.hnd, &status);
|
||||
if (err) {
|
||||
fprintf(stderr, "X502_OutGetStatusFlags error: %s\n", X502_GetErrorString(err));
|
||||
break;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
timespec_diff(&cur_time, &start_time, &spent_time);
|
||||
|
||||
if (status & X502_OUT_STATUS_FLAG_BUF_WAS_EMPTY) {
|
||||
fprintf(stderr, "%f sec: BUF_WAS_EMPTY\n", timespec_to_double(&spent_time));
|
||||
}
|
||||
#ifdef _WIN32
|
||||
Sleep(10);
|
||||
#else
|
||||
sleep(10);
|
||||
#endif
|
||||
}
|
||||
goto close_module;
|
||||
}
|
||||
|
||||
if (!par.streams_en) {
|
||||
fprintf(stderr, "Потоки на ввод или вывод не включены!\n");
|
||||
print_usage(argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* настраиваем параметры модуля */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = f_setup_params(&par);
|
||||
}
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (par.ring_mode) {
|
||||
// такого режима для E502 нет!
|
||||
// вместо данных АЦП получаем данные которые выслали на DOUT
|
||||
err = X502_FpgaRegWrite(par.hnd, E502_REGS_ARM_DCI_TEST_MODE, (1 << E16_REG_TEST_RING_MODE_BIT));
|
||||
} else {
|
||||
// вместо данных АЦП получаем счетчик
|
||||
err = X502_FpgaRegWrite(par.hnd, E502_REGS_ARM_DCI_TEST_MODE, (1 << E16_REG_TEST_ADC_CNTR_BIT));
|
||||
}
|
||||
|
||||
//err = e502_lpc_tst_start(par.hnd, E502_CM4_TEST_DCI_CNTR, 0);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
X502_FpgaRegWrite(par.hnd, E502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
X502_FpgaRegWrite(par.hnd, E502_REGS_BF_CTL, X502_REGBIT_BF_CTL_BF_RESET_Msk);
|
||||
|
||||
if (par.streams_en & X502_STREAM_ALL_OUT) {
|
||||
#ifdef _WIN32
|
||||
thread = CreateThread(NULL, 0, ThreadFunc, &par, 0, NULL);
|
||||
#else
|
||||
// Create a thread that will function threadFunc()
|
||||
err = pthread_create(&thread, NULL, threadFunc, &par);
|
||||
#endif
|
||||
{
|
||||
uint32_t status = 0;
|
||||
do {
|
||||
err = X502_OutGetStatusFlags(par.hnd, &status);
|
||||
} while (!f_out && err == X502_ERR_OK && (status & X502_OUT_STATUS_FLAG_BUF_IS_EMPTY));
|
||||
}
|
||||
}
|
||||
|
||||
/* запуск синхронного ввода-вывода */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsStart(par.hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка запуска сбора данных: %s!\n", X502_GetErrorString(err));
|
||||
}
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int block;
|
||||
int32_t stop_err;
|
||||
|
||||
printf("Сбор данных запущен. Для останова нажмите %s\n",
|
||||
#ifdef _WIN32
|
||||
"любую клавишу"
|
||||
#else
|
||||
"CTRL+C"
|
||||
#endif
|
||||
);
|
||||
fflush(stdout);
|
||||
|
||||
recv_proc(&par);
|
||||
|
||||
if (par.streams_en & X502_STREAM_ALL_OUT) {
|
||||
#ifdef _WIN32
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
#else
|
||||
pthread_join(thread, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* останавливаем поток сбора данных (независимо от того, была ли ошибка) */
|
||||
stop_err = X502_StreamsStop(par.hnd);
|
||||
if (stop_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова сбора данных: %s\n", X502_GetErrorString(err));
|
||||
if (err == X502_ERR_OK)
|
||||
err = stop_err;
|
||||
} else {
|
||||
printf("Сбор данных остановлен успешно\n");
|
||||
}
|
||||
}
|
||||
close_module:
|
||||
|
||||
// выключаем режим когда по DCI должен передаваться счетчик начиная с 1
|
||||
X502_FpgaRegWrite(par.hnd, E502_REGS_ARM_DCI_TEST_MODE, 0);
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(par.hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(par.hnd);
|
||||
return err;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
set(PROJECT e502_eth_svc_browse)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR})
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api e502api)
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "e502_eth_svc_browse", "e502_eth_svc_browse.vcproj", "{D9460CE1-B571-4A69-A4C1-0676BF57EB04}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="e502_eth_svc_browse"
|
||||
ProjectGUID="{D9460CE1-B571-4A69-A4C1-0676BF57EB04}"
|
||||
RootNamespace="e502_eth_svc_browse"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="c:\Program Files (x86)\L-Card\lpcie\include\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="x502api.lib e502api.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="c:\Program Files (x86)\L-Card\lpcie\lib\msvc"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="c:\Program Files (x86)\L-Card\lpcie\include\"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="x502api.lib e502api.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="c:\Program Files (x86)\L-Card\lpcie\lib\msvc"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\main.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
205
lib/x502api-1.1.34/examples/c/e502_eth_svc_browse/main.c
Normal file
205
lib/x502api-1.1.34/examples/c/e502_eth_svc_browse/main.c
Normal file
@ -0,0 +1,205 @@
|
||||
/* Данный пример представляет из себя консольную программу на языке C,
|
||||
демонстрирующую, как можно выполнить поиск устройств E502 в локальной сети.
|
||||
|
||||
Пример запускается и непрерывно отслеживает появление (или исчезновение)
|
||||
устройств в локальной сети, выводя информацию на консоль.
|
||||
|
||||
Поиск выполняется до нажатия любой клавиши на Windows или CTRL+C на Linux.
|
||||
|
||||
Данный пример содержит проект для Visual Studio 2008, а также может быть собран
|
||||
gcc в Linux или mingw в Windows через makefile или с помощью cmake (подробнее
|
||||
в комментариях в соответствующих файлах).
|
||||
|
||||
Для того чтобы собрать проект в Visual Studio, измените путь к заголовочным файлам
|
||||
(Проект (Project) -> Свойства (Properties) -> Свойства конфигурации (Configuration Properties)
|
||||
-> С/С++ -> Общие (General) -> Дополнительные каталоги включения (Additional Include Directories))
|
||||
на тот, где у вас лежат заголовочный файлы x502api.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 "e502api.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define INST_NAME_PRINT_FMT "%ls"
|
||||
#else
|
||||
#define INST_NAME_PRINT_FMT "%s"
|
||||
#endif
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
static int f_out = 0;
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Обработчик сигнала завершения для Linux */
|
||||
static void f_abort_handler(int sig) {
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
int32_t stop_err;
|
||||
uint32_t ver;
|
||||
t_e502_eth_svc_browse_hnd browse_hnd;
|
||||
#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);
|
||||
|
||||
|
||||
/* Начинаем процесс поиска устройств в локальной сети */
|
||||
err = E502_EthSvcBrowseStart(&browse_hnd, 0);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка запуска поиска устройств в сети (%d): %s\n",
|
||||
err, X502_GetErrorString(err));
|
||||
} else {
|
||||
printf("Запущен поиск устройств в локальной сети. Для останова нажмите %s\n",
|
||||
#ifdef _WIN32
|
||||
"любую клавишу"
|
||||
#else
|
||||
"CTRL+C"
|
||||
#endif
|
||||
);
|
||||
while (!f_out && (err == X502_ERR_OK)) {
|
||||
t_e502_eth_svc_record_hnd svc_rec;
|
||||
uint32_t event;
|
||||
/* пробуем получить запись, сообщающую о изменении информации о подулюенных
|
||||
* устройтсвах */
|
||||
err = E502_EthSvcBrowseGetEvent(browse_hnd, &svc_rec, &event, NULL, 300);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка получения записи о найденном устройстве (%d): %s\n",
|
||||
err, X502_GetErrorString(err));
|
||||
} else if (event != E502_ETH_SVC_EVENT_NONE) {
|
||||
char inst_name[X502_INSTANCE_NAME_SIZE];
|
||||
char dev_serial[X502_SERIAL_SIZE];
|
||||
uint32_t addr;
|
||||
int32_t cur_err;
|
||||
#ifdef _WIN32
|
||||
WCHAR inst_name_w[X502_INSTANCE_NAME_SIZE];
|
||||
#endif
|
||||
|
||||
/* значение события, отличное от E502_ETH_SVC_EVENT_NONE, говорит
|
||||
* о том, что изменение произошло. Для каждого события мы можем
|
||||
* получить имя экземпляра и сер. номер устройства, для которого
|
||||
* произошло событие */
|
||||
cur_err = E502_EthSvcRecordGetInstanceName(svc_rec, inst_name);
|
||||
if (cur_err == X502_ERR_OK)
|
||||
cur_err = E502_EthSvcRecordGetDevSerial(svc_rec, dev_serial);
|
||||
#ifdef _WIN32
|
||||
if (cur_err == X502_ERR_OK) {
|
||||
/* Имя устройства всегда в кодировке UTF-8. В Windows для
|
||||
* представления юникодных строк используется формат UTF16
|
||||
* и строка представляется в виде массива WCHAR.
|
||||
* Для перевода используем функцию преобразования */
|
||||
if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, inst_name,
|
||||
-1, inst_name_w, X502_INSTANCE_NAME_SIZE)==0) {
|
||||
cur_err = X502_ERR_INSTANCE_NAME_ENCODING;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cur_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка получения параметров устройства (%d): %s\n",
|
||||
cur_err, X502_GetErrorString(cur_err));
|
||||
} else {
|
||||
if ((event == E502_ETH_SVC_EVENT_ADD) ||
|
||||
(event == E502_ETH_SVC_EVENT_CHANGED)) {
|
||||
/* События ADD и CHANGE означают, что устройство присутствует,
|
||||
* и мы можем получить IP-адрес устройства */
|
||||
cur_err = E502_EthSvcRecordResolveIPv4Addr(svc_rec, &addr, 4000);
|
||||
|
||||
if (cur_err == X502_ERR_OK) {
|
||||
printf("%s: " INST_NAME_PRINT_FMT ", S/N: %s, Адрес = %d.%d.%d.%d\n",
|
||||
event == E502_ETH_SVC_EVENT_ADD ? "Новое устройтсво" : "Изм. параметров",
|
||||
#ifdef _WIN32
|
||||
inst_name_w,
|
||||
#else
|
||||
inst_name,
|
||||
#endif
|
||||
dev_serial,
|
||||
(addr >> 24) & 0xFF, (addr >> 16) & 0xFF,
|
||||
(addr >> 8) & 0xFF, addr & 0xFF
|
||||
);
|
||||
|
||||
fflush(stdout);
|
||||
} else {
|
||||
fprintf(stderr, "Ошибка получения адреса устройства (%d): %s\n",
|
||||
cur_err, X502_GetErrorString(cur_err));
|
||||
}
|
||||
} else if (event == E502_ETH_SVC_EVENT_REMOVE) {
|
||||
printf("Устройство отключено: " INST_NAME_PRINT_FMT ", S/N: %s\n",
|
||||
#ifdef _WIN32
|
||||
inst_name_w,
|
||||
#else
|
||||
inst_name,
|
||||
#endif
|
||||
dev_serial);
|
||||
}
|
||||
}
|
||||
|
||||
/* Для всех событий, кроме NONE, выделяется запись, которую
|
||||
* нужно освободить вручную */
|
||||
E502_EthSvcRecordFree(svc_rec);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* проверка нажатия клавиши для выхода */
|
||||
if (err == X502_ERR_OK) {
|
||||
if (_kbhit())
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
stop_err = E502_EthSvcBrowseStop(browse_hnd);
|
||||
if (stop_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова поиска сервисов (%d): %s\n",
|
||||
stop_err, X502_GetErrorString(stop_err));
|
||||
if (err == X502_ERR_OK)
|
||||
err = stop_err;
|
||||
} else {
|
||||
printf("Останов поиска сервисов выполнен успешно!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
48
lib/x502api-1.1.34/examples/c/e502_eth_svc_browse/makefile
Normal file
48
lib/x502api-1.1.34/examples/c/e502_eth_svc_browse/makefile
Normal file
@ -0,0 +1,48 @@
|
||||
# makefile для сборки примера с помощью компиляторов mingw (под Windows)
|
||||
# или GCC (под Linux). Необходимо определить 3 переменные:
|
||||
#
|
||||
# CC - имя команды для вызова компилятора
|
||||
# X502API_LIBRARIES_DIR - путь к файлм .a или .so библиотек l502api, e502api, x502api (если не стандартный)
|
||||
# X502API_INCLUDE_DIR - путь к заголовочным файлам l502api.h, e502api.h, x502api.h
|
||||
#
|
||||
# Ниже приведено несколько примеров в закоментированном виде
|
||||
|
||||
#--- Linux с заголовками и библиотекой в стандартных директориях: компилятор GCC
|
||||
#CC = gcc
|
||||
|
||||
#--- Вариант запуска из MSYS со стандартным 32-битным mingw
|
||||
#CC = gcc
|
||||
#X502API_LIBRARIES_DIR = "/c/Program Files/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/c/Program Files/L-Card/lpcie/include"
|
||||
|
||||
|
||||
#--- 64-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = x86_64-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw64"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = i686-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw, идущий вместе с cygwin --------
|
||||
#CC = i686-pc-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
|
||||
FLAGS =
|
||||
|
||||
ifdef X502API_LIBRARIES_DIR
|
||||
FLAGS += -L $(X502API_LIBRARIES_DIR)
|
||||
endif
|
||||
|
||||
ifdef X502API_INCLUDE_DIR
|
||||
FLAGS += -I $(X502API_INCLUDE_DIR)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
all:
|
||||
$(CC) main.c $(FLAGS) -lx502api -le502api -o e502_eth_svc_browse
|
||||
@ -0,0 +1,30 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
set(PROJECT e502_timestamp_stream)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR})
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
681
lib/x502api-1.1.34/examples/c/e502_timestamp_stream/main.c
Normal file
681
lib/x502api-1.1.34/examples/c/e502_timestamp_stream/main.c
Normal file
@ -0,0 +1,681 @@
|
||||
/*
|
||||
Пример работы с модулями E502-P1 поддерживающими механизм синхронизации времени по протоколу PTP.
|
||||
|
||||
Данный пример представляет из себя консольную программу на языке C,
|
||||
демонстрирующую работу синхронного
|
||||
ввода данных с АЦП и цифровых линий, а также работу с потоком данных включающим в себя метки времени.
|
||||
|
||||
Перед сбором в примере идет поиск модулей, подключенных по интерфейсам USB,
|
||||
и предоставляется список для выбора модуля, с которым нужно работать.
|
||||
Для подключения по Ethernet нужно указать IP-адреса интересующих модулей
|
||||
в качестве аргументов командной строки при вызове примера, тогда эти адреса
|
||||
будут добавлены в конец списка выбора модуля.
|
||||
Например, если интересуют модули с адресами 192.168.1.5 и 192.168.1.6,
|
||||
то пример можно вызвать:
|
||||
x502_stream_read 192.168.1.5 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 "l502api.h"
|
||||
#include "e502api.h"
|
||||
#include "x502tstp.h"
|
||||
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "x502api_private.h"
|
||||
|
||||
#define STREAM_IN_WRD_TYPE(wrd) wrd & 0x80000000 ? STREAM_IN_WRD_ADC : \
|
||||
(wrd & 0xFF000000) == 0x0 ? STREAM_IN_WRD_DIN : \
|
||||
(wrd & 0xF0000000) == 0x40000000 ? STREAM_IN_WRD_TSP : \
|
||||
((wrd & 0xFF000000)>>24) == 0x01 ? STREAM_IN_WRD_MSG : STREAM_IN_WRD_USR
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CLOCK_MONOTONIC 1
|
||||
|
||||
int clock_gettime(int a, struct timespec *spec) {
|
||||
__int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
|
||||
wintime -=116444736000000000i64; //1jan1601 to 1jan1970
|
||||
spec->tv_sec =wintime / 10000000i64; //seconds
|
||||
spec->tv_nsec =wintime % 10000000i64 *100; //nano-seconds
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
void timespec_diff(struct timespec *a, struct timespec *b,
|
||||
struct timespec *result) {
|
||||
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||
result->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
if (result->tv_nsec < 0) {
|
||||
--result->tv_sec;
|
||||
result->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
double timespec_to_double(struct timespec *ts)
|
||||
{
|
||||
return ((double)(ts->tv_sec) + ((double)(ts->tv_nsec) / NSEC_PER_SEC));
|
||||
}
|
||||
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
static int f_out = 0;
|
||||
|
||||
/* количество используемых логических каналов */
|
||||
#define ADC_LCH_CNT 1
|
||||
|
||||
/* частота сбора АЦП в Гц*/
|
||||
#define ADC_FREQ 1000000
|
||||
#define ADC_FRAME_FREQ (ADC_FREQ/ADC_LCH_CNT)
|
||||
/* частота синхронного ввода в Гц*/
|
||||
#define DIN_FREQ 1000000
|
||||
|
||||
#define ENABLE_ADC
|
||||
#define ENABLE_DIN
|
||||
|
||||
// при ADC_FREQ==2000000 и DIN_FREQ==1000000 через Ethernet обязательно будет X502_STREAM_IN_MSG_OVERFLOW
|
||||
|
||||
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
|
||||
|
||||
/* сколько отсчетов считываем за блок */
|
||||
#define READ_BLOCK_SIZE 4096*66*3
|
||||
/* таймаут на прием блока (мс) */
|
||||
#define READ_TIMEOUT 2000
|
||||
|
||||
|
||||
/* номера используемых физических каналов */
|
||||
static uint32_t f_channels[ADC_LCH_CNT] = {0};
|
||||
/* режимы измерения для каналов */
|
||||
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_DIFF};
|
||||
/* диапазоны измерения для каналов */
|
||||
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_10};
|
||||
|
||||
|
||||
t_x502_hnd g_hnd = NULL;
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Обработчик сигнала завершения для Linux */
|
||||
static void f_abort_handler(int sig) {
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Функция находит все подключенные модули по интерфейсам PCI-Express и USB и
|
||||
* сохраняет записи о этих устройствах в выделенный массив.
|
||||
* Также создаются записи по переданным IP-адресам модулей и добавляются в конец
|
||||
* массива.
|
||||
* Указатель на выделенный массив, который должен быть потом очищен, сохраняется
|
||||
* в pdevrec_list, а количество действительных элементов (память которых должна
|
||||
* быть в дальнейшем освобождена с помощью X502_FreeDevRecordList()) возвращается
|
||||
* как результат функции */
|
||||
static uint32_t f_get_all_devrec(t_x502_devrec **pdevrec_list, uint32_t *ip_addr_list, unsigned ip_cnt) {
|
||||
int32_t fnd_devcnt = 0;
|
||||
uint32_t pci_devcnt = 0;
|
||||
uint32_t 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);
|
||||
|
||||
if ((pci_devcnt + usb_devcnt + ip_cnt) != 0) {
|
||||
/* выделяем память для массива для сохранения найденного количества записей */
|
||||
rec_list = malloc((pci_devcnt + 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* создаем записи для переданного массива ip-адресов */
|
||||
for (i=0; i < ip_cnt; i++) {
|
||||
if (E502_MakeDevRecordByIpAddr(&rec_list[fnd_devcnt], ip_addr_list[i],0, TCP_CONNECTION_TOUT) == X502_ERR_OK) {
|
||||
fnd_devcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
uint32_t fnd_devcnt,i, dev_ind;
|
||||
t_x502_devrec *devrec_list = NULL;
|
||||
uint32_t *ip_addr_list = NULL;
|
||||
uint32_t ip_cnt = 0;
|
||||
t_x502_hnd hnd = NULL;
|
||||
|
||||
/* если есть аргументы командной строки, то предполагаем, что это могут быть
|
||||
ip-адреса интересующих устройств. */
|
||||
if (argc > 1) {
|
||||
ip_addr_list = malloc((argc-1) * sizeof(ip_addr_list[0]));
|
||||
if (ip_addr_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_addr_list[ip_cnt++] = ((a[0] & 0xFF) << 24) |
|
||||
((a[1] & 0xFF) << 16) |
|
||||
((a[2] & 0xFF) << 8) |
|
||||
(a[3] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* получаем список модулей для выбора */
|
||||
fnd_devcnt = f_get_all_devrec(&devrec_list, ip_addr_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);
|
||||
|
||||
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_addr_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);
|
||||
}
|
||||
}
|
||||
|
||||
/* записываем настройки в модуль */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_Configure(hnd, 0);
|
||||
|
||||
/* разрешаем синхронные потоки */
|
||||
if (err == X502_ERR_OK) {
|
||||
int streams = 0;
|
||||
#ifdef ENABLE_ADC
|
||||
streams |= X502_STREAM_ADC;
|
||||
#endif
|
||||
#ifdef ENABLE_DIN
|
||||
streams |= X502_STREAM_DIN;
|
||||
#endif
|
||||
err = X502_StreamsEnable(hnd, streams);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
uint32_t ver;
|
||||
#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);
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
g_hnd = f_dev_select_open(argc, argv);
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (g_hnd != NULL) {
|
||||
/* получаем информацию */
|
||||
t_x502_info info;
|
||||
err = X502_GetDevInfo(g_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);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
/* настраиваем параметры модуля */
|
||||
err = f_setup_params(g_hnd);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
|
||||
}
|
||||
|
||||
/*err = X502_FpgaRegRead(g_hnd, E502_REGS_ARM_BLOCK, &val);
|
||||
if (err) {
|
||||
printf("X502_FpgaRegRead err=%d\n", err);
|
||||
} else {
|
||||
printf("X502_FpgaRegRead(E502_REGS_ARM_BLOCK) = %d\n", val);
|
||||
} */
|
||||
|
||||
// Включаем метки времени в потоке
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_TIME_CTRL, 1);
|
||||
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_BF_CTL, X502_REGBIT_BF_CTL_BF_RESET_Msk);
|
||||
|
||||
X502_SetSyncMode(g_hnd, X502_SYNC_INTERNAL);
|
||||
|
||||
/* запуск синхронного ввода-вывода */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsStart(g_hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка запуска сбора данных: %s!\n", X502_GetErrorString(err));
|
||||
}
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int block;
|
||||
int32_t stop_err;
|
||||
|
||||
printf("Сбор данных запущен. Для останова нажмите %s\n",
|
||||
#ifdef _WIN32
|
||||
"любую клавишу"
|
||||
#else
|
||||
"CTRL+C"
|
||||
#endif
|
||||
);
|
||||
fflush(stdout);
|
||||
|
||||
struct timespec start_time;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
int32_t g_rcv_cnt = 0;
|
||||
int cntr = 0;
|
||||
int rcv_cntr = 0;
|
||||
|
||||
t_x502_tstp_state tstp_state;
|
||||
|
||||
X502_tstp_init(&tstp_state, ADC_FREQ, DIN_FREQ);
|
||||
|
||||
|
||||
for (block = 0; (err == X502_ERR_OK) && !f_out; block++) {
|
||||
int32_t rcv_size;
|
||||
uint32_t adc_size, din_size;
|
||||
uint32_t adc_wrd_num = 0;
|
||||
uint32_t din_wrd_num = 0;
|
||||
|
||||
/* массив для приема необработанных данных */
|
||||
static uint32_t rcv_buf[READ_BLOCK_SIZE];
|
||||
static uint32_t snd_buf[READ_BLOCK_SIZE];
|
||||
static double adc_data[READ_BLOCK_SIZE];
|
||||
static uint32_t din_data[READ_BLOCK_SIZE];
|
||||
|
||||
int i;
|
||||
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
|
||||
/* принимаем данные (по таймауту) */
|
||||
rcv_size = X502_Recv(g_hnd, rcv_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
if (rcv_size < 0) {
|
||||
err = rcv_size;
|
||||
fprintf(stderr, "Ошибка приема данных: %s\n", X502_GetErrorString(err));
|
||||
continue;
|
||||
}
|
||||
adc_size = sizeof(adc_data)/sizeof(adc_data[0]);
|
||||
din_size = sizeof(din_data)/sizeof(din_data[0]);
|
||||
|
||||
/* обрабатываем принятые данные, распределяя их на данные АЦП и цифровых входов */
|
||||
err = X502_ProcessData(g_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));
|
||||
continue;
|
||||
}
|
||||
|
||||
g_rcv_cnt += rcv_size;
|
||||
int error = 0;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5) {
|
||||
//printf("rcv speed=%lld wrds/sec cntr=%x\n", (g_rcv_cnt) / (cur_time.tv_sec - start_time.tv_sec), rcv_cntr);
|
||||
start_time.tv_sec = cur_time.tv_sec;
|
||||
g_rcv_cnt = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rcv_size; i++) {
|
||||
uint32_t cur_wrd = rcv_buf[i];
|
||||
uint64_t cur_wrd_time;
|
||||
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(cur_wrd);
|
||||
|
||||
X502_tstp_process_wrd(&tstp_state, cur_wrd);
|
||||
X502_tstp_get_curwrd_time(&tstp_state, &cur_wrd_time) ;
|
||||
|
||||
/* проверяем - это данные от АЦП или цифровых входов */
|
||||
if (type == STREAM_IN_WRD_DIN) {
|
||||
uint16_t din_wrd;
|
||||
static bool last_din_wrd_initialized = false;
|
||||
static uint16_t last_din_wrd;
|
||||
|
||||
if (!tstp_state.tstp_mark_rcvd) {
|
||||
fprintf(stderr, "No timestamp received, DIN wrd unexpected!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
din_wrd = din_data[din_wrd_num];
|
||||
din_wrd_num++;
|
||||
|
||||
#define DIN_PPS_MASK 1
|
||||
|
||||
if (!last_din_wrd_initialized) {
|
||||
last_din_wrd = din_wrd;
|
||||
last_din_wrd_initialized = true;
|
||||
} else
|
||||
if ((din_wrd & DIN_PPS_MASK) != (last_din_wrd & DIN_PPS_MASK) && (din_wrd & DIN_PPS_MASK)) {
|
||||
// дождались положительный фронт сигнала PPS на ножке DI1
|
||||
static bool last_pps_edge_time_initialized = false;
|
||||
static uint64_t last_pps_edge_time = 0;
|
||||
|
||||
X502_tstp_get_curwrd_time(&tstp_state, &cur_wrd_time);
|
||||
|
||||
{
|
||||
static uint32_t nsec_max = 0;
|
||||
static uint32_t nsec_min = -1;
|
||||
uint64_t sec_time;
|
||||
uint64_t ns_time;
|
||||
sec_time = cur_wrd_time - TSTP_SEC_TO_SSEC(TSTP_SECSSEC_TO_SEC(cur_wrd_time));
|
||||
ns_time = TSTP_SSEC_TO_NSEC(sec_time);
|
||||
if (ns_time > 500000000) {
|
||||
ns_time = NSEC_PER_SEC - ns_time;
|
||||
}
|
||||
if (ns_time > nsec_max) {
|
||||
nsec_max = ns_time;
|
||||
}
|
||||
if (ns_time < nsec_min) {
|
||||
nsec_min = ns_time;
|
||||
}
|
||||
printf("DIN PPS positive edge: %ld ns (max - min = %d)\n", ns_time, nsec_max - nsec_min);
|
||||
}
|
||||
|
||||
if (last_pps_edge_time_initialized ) {
|
||||
uint64_t pps_period;
|
||||
pps_period = cur_wrd_time - last_pps_edge_time;
|
||||
printf("DIN PPS positive edge pediod = %d.%09d\n", TSTP_SECSSEC_TO_SEC(pps_period), TSTP_SSEC_TO_NSEC(pps_period));
|
||||
} else {
|
||||
last_pps_edge_time_initialized = true;
|
||||
}
|
||||
|
||||
last_pps_edge_time = cur_wrd_time;
|
||||
}
|
||||
last_din_wrd = din_wrd;
|
||||
} else
|
||||
if (type == STREAM_IN_WRD_ADC) {
|
||||
static uint16_t last_adc_wrd;
|
||||
register uint32_t wrd = rcv_buf[i];
|
||||
double adc_val;
|
||||
static bool adc_wait_for_edge = false;
|
||||
|
||||
if (!tstp_state.tstp_mark_rcvd) {
|
||||
fprintf(stderr, "No timestamp received, ADC wrd unexpected!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
adc_val = adc_data[adc_wrd_num];
|
||||
adc_wrd_num++;
|
||||
|
||||
X502_tstp_get_curwrd_time(&tstp_state, &cur_wrd_time);
|
||||
|
||||
if (adc_wait_for_edge) {
|
||||
if (adc_val > 2.4) {
|
||||
// дождались положительный фронт сигнала PPS на 1 канале ADC
|
||||
static bool last_pps_edge_time_initialized = false;
|
||||
static uint64_t last_pps_edge_time = 0;
|
||||
|
||||
adc_wait_for_edge = false;
|
||||
|
||||
{
|
||||
static uint32_t nsec_max = 0;
|
||||
static uint32_t nsec_min = -1;
|
||||
uint64_t sec_time;
|
||||
uint64_t ns_time;
|
||||
sec_time = cur_wrd_time - TSTP_SEC_TO_SSEC(TSTP_SECSSEC_TO_SEC(cur_wrd_time));
|
||||
ns_time = TSTP_SSEC_TO_NSEC(sec_time);
|
||||
if (ns_time > 500000000) {
|
||||
ns_time = NSEC_PER_SEC - ns_time;
|
||||
}
|
||||
if (ns_time > nsec_max) {
|
||||
nsec_max = ns_time;
|
||||
}
|
||||
if (ns_time < nsec_min) {
|
||||
nsec_min = ns_time;
|
||||
}
|
||||
printf("ADC PPS positive edge: %ld ns (max - min = %d)\n", ns_time, nsec_max - nsec_min);
|
||||
}
|
||||
|
||||
if (last_pps_edge_time_initialized ) {
|
||||
uint64_t pps_period;
|
||||
pps_period = cur_wrd_time - last_pps_edge_time;
|
||||
|
||||
printf("ADC PPS positive edge period = %d.%09d\n", TSTP_SECSSEC_TO_SEC(pps_period),
|
||||
TSTP_SSEC_TO_NSEC(pps_period));
|
||||
|
||||
} else {
|
||||
last_pps_edge_time_initialized = true;
|
||||
}
|
||||
|
||||
last_pps_edge_time = cur_wrd_time;
|
||||
}
|
||||
} else
|
||||
if (adc_val < 2.3) {
|
||||
adc_wait_for_edge = true;
|
||||
}
|
||||
}
|
||||
|
||||
rcv_cntr++;
|
||||
}
|
||||
#if 0
|
||||
adc_size = sizeof(adc_data)/sizeof(adc_data[0]);
|
||||
din_size = sizeof(din_data)/sizeof(din_data[0]);
|
||||
int adc_data_num = 0;
|
||||
|
||||
/* обрабатываем принятые данные, распределяя их на данные АЦП и цифровых входов */
|
||||
err = X502_ProcessData(g_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));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((tstp_state.dinwrds_after_tstp / DIN_FREQ) > 2)
|
||||
{
|
||||
printf("Warning: timestamp mark undetected after %d seconds\n", tstp_state.dinwrds_after_tstp / DIN_FREQ);
|
||||
}
|
||||
if ((tstp_state.adcwrds_after_tstp / ADC_FREQ) > 2)
|
||||
{
|
||||
printf("Warning: timestamp mark undetected after %d seconds\n", tstp_state.adcwrds_after_tstp / ADC_FREQ);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* проверка нажатия клавиши для выхода */
|
||||
if (_kbhit())
|
||||
f_out = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* останавливаем поток сбора данных (независимо от того, была ли ошибка) */
|
||||
stop_err = X502_StreamsStop(g_hnd);
|
||||
if (stop_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова сбора данных: %s\n", X502_GetErrorString(err));
|
||||
if (err == X502_ERR_OK)
|
||||
err = stop_err;
|
||||
} else {
|
||||
printf("Сбор данных остановлен успешно\n");
|
||||
}
|
||||
|
||||
// Выключаем метки времени в потоке
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_TIME_CTRL, 0);
|
||||
}
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(g_hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(g_hnd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
29
lib/x502api-1.1.34/examples/c/fw_update/CMakeLists.txt
Normal file
29
lib/x502api-1.1.34/examples/c/fw_update/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
set(PROJECT fw_update)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR})
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
293
lib/x502api-1.1.34/examples/c/fw_update/main.c
Normal file
293
lib/x502api-1.1.34/examples/c/fw_update/main.c
Normal file
@ -0,0 +1,293 @@
|
||||
#include "l502api.h"
|
||||
#include "e502api.h"
|
||||
#include "../../../devs/e502/e502_fpga_regs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "x502api_private.h"
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
static int f_out = 0;
|
||||
t_x502_hnd g_hnd = NULL;
|
||||
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Обработчик сигнала завершения для Linux */
|
||||
static void f_abort_handler(int sig) {
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Функция находит все подключенные модули по интерфейсам PCI-Express и USB и
|
||||
* сохраняет записи о этих устройствах в выделенный массив.
|
||||
* Также создаются записи по переданным IP-адресам модулей и добавляются в конец
|
||||
* массива.
|
||||
* Указатель на выделенный массив, который должен быть потом очищен, сохраняется
|
||||
* в pdevrec_list, а количество действительных элементов (память которых должна
|
||||
* быть в дальнейшем освобождена с помощью X502_FreeDevRecordList()) возвращается
|
||||
* как результат функции */
|
||||
static uint32_t f_get_all_devrec(t_x502_devrec **pdevrec_list, uint32_t *ip_addr_list, unsigned ip_cnt) {
|
||||
int32_t fnd_devcnt = 0;
|
||||
uint32_t pci_devcnt = 0;
|
||||
uint32_t 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);
|
||||
|
||||
if ((pci_devcnt + usb_devcnt + ip_cnt) != 0) {
|
||||
/* выделяем память для массива для сохранения найденного количества записей */
|
||||
rec_list = malloc((pci_devcnt + 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* создаем записи для переданного массива ip-адресов */
|
||||
for (i=0; i < ip_cnt; i++) {
|
||||
if (E502_MakeDevRecordByIpAddr(&rec_list[fnd_devcnt], ip_addr_list[i],0, TCP_CONNECTION_TOUT) == X502_ERR_OK) {
|
||||
fnd_devcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
uint32_t fnd_devcnt,i, dev_ind;
|
||||
t_x502_devrec *devrec_list = NULL;
|
||||
uint32_t *ip_addr_list = NULL;
|
||||
uint32_t ip_cnt = 0;
|
||||
t_x502_hnd hnd = NULL;
|
||||
|
||||
/* если есть аргументы командной строки, то предполагаем, что это могут быть
|
||||
ip-адреса интересующих устройств. */
|
||||
if (argc > 1) {
|
||||
ip_addr_list = malloc((argc-1) * sizeof(ip_addr_list[0]));
|
||||
if (ip_addr_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_addr_list[ip_cnt++] = ((a[0] & 0xFF) << 24) |
|
||||
((a[1] & 0xFF) << 16) |
|
||||
((a[2] & 0xFF) << 8) |
|
||||
(a[3] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* получаем список модулей для выбора */
|
||||
fnd_devcnt = f_get_all_devrec(&devrec_list, ip_addr_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);
|
||||
|
||||
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) && (err != X502_ERR_FPGA_NOT_LOADED) && (err != X502_ERR_REF_FREQ_NOT_LOCKED)) {
|
||||
fprintf(stderr, "Ошибка установления связи с модулем: %s!", X502_GetErrorString(err));
|
||||
X502_Free(hnd);
|
||||
hnd = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* освобождение ресурсов действительных записей из списка */
|
||||
X502_FreeDevRecordList(devrec_list, fnd_devcnt);
|
||||
/* очистка памяти самого массива */
|
||||
free(devrec_list);
|
||||
}
|
||||
|
||||
/* освобождаем выделенный массив под IP-адреса (если был выделен) */
|
||||
free(ip_addr_list);
|
||||
|
||||
return hnd;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <sys/stat.h> // stat
|
||||
#include <stdbool.h> // bool type
|
||||
#include <errno.h>
|
||||
|
||||
int update_firmware(char** args) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
|
||||
struct stat statbuf;
|
||||
if ((stat(args[0], &statbuf)) != 0) {
|
||||
err = errno;
|
||||
fprintf(stderr, "Error (%d): file (%s) not found!\n", err, args[0]);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = E502_SwitchToBootloader(g_hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "E502_SwitchToBootloader err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
X502_Close(g_hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(g_hnd);
|
||||
|
||||
//char *args[] = { "./lboot", "-v", "-d", "E502", "usb", "--hash", "--con-time=5000", "/home/ruslan/vbox_share/e502-riscv.bin", NULL };
|
||||
//-r" << "--recovery" << "--hash" << "--con-time=5000" << "--devname=E502
|
||||
err = execve(args[0], args, NULL);
|
||||
|
||||
if (err == -1) {
|
||||
err = errno;
|
||||
fprintf(stderr, "execve error=%d\n", err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#else
|
||||
#define update_firmware(...) 0
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
uint32_t ver;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Insufficient arguments\n");
|
||||
return -2;
|
||||
}
|
||||
#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);
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
g_hnd = f_dev_select_open(argc, argv);
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (g_hnd != NULL) {
|
||||
/* получаем информацию */
|
||||
t_x502_info info;
|
||||
err = X502_GetDevInfo(g_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);
|
||||
}
|
||||
}
|
||||
err = update_firmware(argv + 1);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(g_hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(g_hnd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
34
lib/x502api-1.1.34/examples/c/x502_cycle_out/CMakeLists.txt
Normal file
34
lib/x502api-1.1.34/examples/c/x502_cycle_out/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DL502API_INCLUDE_DIR=<путь к заголовочным файлам l502api> -DL502API_LIBRARIES_DIR=<путь к файлу линкера l502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DL502API_INCLUDE_DIR и -DL502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
set(PROJECT x502_cycle_out)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c ../common/dev_funcs.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR} ../common)
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
target_link_libraries(${PROJECT} m)
|
||||
endif(CMAKE_COMPILER_IS_GNUCC)
|
||||
296
lib/x502api-1.1.34/examples/c/x502_cycle_out/main.c
Normal file
296
lib/x502api-1.1.34/examples/c/x502_cycle_out/main.c
Normal file
@ -0,0 +1,296 @@
|
||||
/* Данный пример демонстрирует возможность установки циклического сигнала на
|
||||
вывод в модуль E16 / E502 / L502 (ввод не используется вообще).
|
||||
|
||||
В примере определена таблица сигналов, которая задает несколько
|
||||
комбинаций сигналов для примера. Каждый сигнал задается количеством точек
|
||||
на период (общее значение для всех трех сигналов), амплитудой для ЦАП'ов и
|
||||
функцией для генерации очередного отсчета по его номеру и полному размеру.
|
||||
|
||||
Пользовтель может ввести номер сигнала, которых он хочет выставить и нажать Enter - и этот
|
||||
сигнал будет выставлен на выходе.
|
||||
|
||||
Смена сигнала происходит по концу периода предыдущего.
|
||||
Надо также помнить, что хотя мы можем загружать новый сигнал на фоне вывода
|
||||
предыдущего, однако сразу после выполнения L502_OutCycleSetup() до того
|
||||
времени как реально произойдет смена старого сигнала на новый нельзя
|
||||
начинать загружать еще один новый сигнал.
|
||||
|
||||
|
||||
Данный пример содержит проект для Visual Studio 2008, а также может быть собран
|
||||
gcc в Linux или mingw в Windows через makefile или с помощью cmake (подробнее
|
||||
в коментариях в соответствующих файлах).
|
||||
|
||||
Для того чтобы собрать проект в Visual Studio, измените путь к заголовочным файлам
|
||||
(Проект (Project) -> Свойства (Properties) -> Свойства конфигурации (Configuration Properties)
|
||||
-> С/С++ -> Общие (General) -> Дополнительные каталоги включения (Additional Include Directories))
|
||||
на тот, где у вас лежат заголовочный файл l502api.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 "l502api.h"
|
||||
#include "e502api.h"
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "dev_funcs.h"
|
||||
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
#define OUT_SIGNAL_SIZE 2000
|
||||
#define OUT_BLOCK_SIZE 256
|
||||
#define SEND_TOUT 500
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
typedef double (*f_gen_sig_word)(uint32_t cntr, uint32_t total_size, double amp);
|
||||
typedef uint32_t (*f_gen_dout_word)(uint32_t cntr, uint32_t total_size);
|
||||
/* структура, задающая сигналы на 2-х каналах ЦАП и/или1
|
||||
1на DOUT */
|
||||
typedef struct {
|
||||
uint32_t size; /* количество точек в сигнале */
|
||||
double amp_dac1; /* амплитуда сигнала для ЦАП1 */
|
||||
f_gen_sig_word gen_func_dac1; /* функция для генерации отсчета для ЦАП1 */
|
||||
double amp_dac2; /* амплитуда сигнала для ЦАП2 */
|
||||
f_gen_sig_word gen_func_dac2; /* функция для генерации отсчета для ЦАП2 */
|
||||
f_gen_dout_word gen_dout; /* функция для генерации слова на цифровой вывод */
|
||||
} t_sig_struct;
|
||||
|
||||
|
||||
/* генерация пилы на весь период */
|
||||
static double f_gen_saw(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return amp*( (int32_t)(cntr%total_size)-(int32_t)total_size/2)/(total_size/2);
|
||||
}
|
||||
|
||||
/* генерация синуса на весь период */
|
||||
static double f_gen_sin(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return amp*sin(2*M_PI*cntr/total_size);
|
||||
}
|
||||
|
||||
/* генерация тестового честчика */
|
||||
static double f_gen_cntr(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return cntr + 0x123;
|
||||
}
|
||||
|
||||
/* генерация синуса с периодом в два раза меньше периоду определяемому размером буфера */
|
||||
static double f_gen_sin2(uint32_t cntr, uint32_t total_size, double amp) {
|
||||
return amp*sin(2*2*M_PI*cntr/total_size);
|
||||
}
|
||||
|
||||
/* генерация меандра на всех выходах путем выдачи в первой половине на выходы 0xAA, а на второй 0x55 */
|
||||
static uint32_t f_gen_dout_meander(uint32_t cntr, uint32_t total_size) {
|
||||
return cntr < total_size/2 ? 0xAA : 0x55;
|
||||
}
|
||||
|
||||
/* генерация счетчика на цифроых выхоах*/
|
||||
static uint32_t f_gen_dout_cntr(uint32_t cntr, uint32_t total_size) {
|
||||
return cntr;
|
||||
}
|
||||
|
||||
|
||||
/* таблица, задающая сигналы для выдачи на вход */
|
||||
/* для модуля E16 частота выходного сигнала будет в 2 раза меньше, т.к. частота ЦАП 500КГц протип 1МГц у E502 */
|
||||
static t_sig_struct f_sig_tbl[] = {
|
||||
{100000, X502_DAC_RANGE, f_gen_saw, 0, NULL, NULL}, /* пила на одном канале с частотой 10 Гц */
|
||||
{2000, X502_DAC_RANGE, f_gen_sin, 0, NULL, NULL}, /* синусоидальный сигнал на одном канале с частотой 500 Гц */
|
||||
{100, X502_DAC_RANGE/2, f_gen_sin, X502_DAC_RANGE, f_gen_saw, NULL}, /* синус ампл. 2.5 и пила по 10 КГц */
|
||||
{50, 0, NULL, X502_DAC_RANGE, f_gen_sin, f_gen_dout_cntr}, /* синус только на втором канале с частотой 20 КГц */
|
||||
{2550, 1.5, f_gen_sin, 2.5, f_gen_sin2, f_gen_dout_meander}, /* на втором канале синус с частотой в 2 раза больше. меандр на цифровых линиях */
|
||||
};
|
||||
|
||||
|
||||
/* Запись в буфер драйвера блока данных от сигнала
|
||||
cntr - номер отчета, соответствующего первому отсчету блока
|
||||
size - количество отсчетов на канал (т.е. записывается ch_cnt*size отсчетов)
|
||||
sig - номер сигнала
|
||||
ch_cnt - кол-во используемых каналов (это кол-во можно определить по f_sig_tbl[sig],
|
||||
но так как мы его уже определили, то передаем сюда, чтобы опять не определять */
|
||||
static int32_t f_load_block(t_x502_hnd hnd, uint32_t cntr, uint32_t size, uint32_t sig, uint32_t ch_cnt) {
|
||||
static double dac_data1[OUT_BLOCK_SIZE], dac_data2[OUT_BLOCK_SIZE];
|
||||
static uint32_t dout_data[OUT_BLOCK_SIZE];
|
||||
/* массив слов на запись в модуль - содержит смешенные подготовленные данные
|
||||
для всех каналов (максимум для 3-х - 2 ЦАП + DOUT) */
|
||||
static uint32_t sbuf[3*OUT_BLOCK_SIZE];
|
||||
uint32_t i;
|
||||
int32_t err = 0;
|
||||
|
||||
/* заполняем массив на вывод */
|
||||
for (i=0; i < size; i++) {
|
||||
if (f_sig_tbl[sig].gen_func_dac1 != NULL) {
|
||||
dac_data1[i] = f_sig_tbl[sig].gen_func_dac1(cntr+i, f_sig_tbl[sig].size, f_sig_tbl[sig].amp_dac1);
|
||||
}
|
||||
if (f_sig_tbl[sig].gen_func_dac2 != NULL) {
|
||||
dac_data2[i] = f_sig_tbl[sig].gen_func_dac2(cntr+i, f_sig_tbl[sig].size, f_sig_tbl[sig].amp_dac2);
|
||||
}
|
||||
if (f_sig_tbl[sig].gen_dout != NULL) {
|
||||
dout_data[i] = f_sig_tbl[sig].gen_dout(cntr+i, f_sig_tbl[sig].size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Если нужная функция определена, значит мы испоьлзуем этот канал, и
|
||||
* подаем на вход сформированный массив. Иначе - канал не используется
|
||||
* и передаем на вход NULL */
|
||||
err = X502_PrepareData(hnd,
|
||||
f_sig_tbl[sig].gen_func_dac1 ? dac_data1 : NULL,
|
||||
f_sig_tbl[sig].gen_func_dac2 ? dac_data2 : NULL,
|
||||
f_sig_tbl[sig].gen_dout ? dout_data : NULL,
|
||||
size, X502_DAC_FLAGS_VOLT | X502_DAC_FLAGS_CALIBR,
|
||||
sbuf);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка подкотовки данных на передачу: %s\n",
|
||||
X502_GetErrorString(err));
|
||||
} else {
|
||||
/* посылаем данные */
|
||||
int32_t snd_cnt = X502_Send(hnd, sbuf, size*ch_cnt, SEND_TOUT);
|
||||
if (snd_cnt < 0) {
|
||||
err = snd_cnt;
|
||||
fprintf(stderr, "Ошибка передачи данных: %s\n", X502_GetErrorString(err));
|
||||
} else if ((uint32_t)snd_cnt != size*ch_cnt) {
|
||||
/* так как мы шлем всегда не больше чем готово, то должны
|
||||
всегда передать все */
|
||||
fprintf(stderr, "Переданно недостаточно данных: передавали = %d, передано = %d\n",
|
||||
size*ch_cnt, snd_cnt);
|
||||
err = X502_ERR_SEND_INSUFFICIENT_WORDS;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int32_t f_load_cycle_signal(t_x502_hnd hnd, int sig) {
|
||||
int32_t err = 0;
|
||||
uint32_t cntr = 0;
|
||||
uint32_t ch_cnt=0;
|
||||
|
||||
/* определяем, сколько каналов используем */
|
||||
if (f_sig_tbl[sig].gen_func_dac1)
|
||||
ch_cnt++;
|
||||
if (f_sig_tbl[sig].gen_func_dac2)
|
||||
ch_cnt++;
|
||||
if (f_sig_tbl[sig].gen_dout)
|
||||
ch_cnt++;
|
||||
|
||||
|
||||
/* задаем размер буфера под все каналы! */
|
||||
err = X502_OutCycleLoadStart(hnd, f_sig_tbl[sig].size*ch_cnt);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка старта загрузки данных: %s!", X502_GetErrorString(err));
|
||||
|
||||
/* в примере показано, что загружать можно поблочно, чтобы не выделять
|
||||
* большой размер памяти на весь сигнал в программе. Но можно записать
|
||||
* весь сигнал и за один L502_Send() */
|
||||
while ((cntr != f_sig_tbl[sig].size) && (err == X502_ERR_OK)) {
|
||||
uint32_t block_size = OUT_BLOCK_SIZE;
|
||||
/* последний блок может быть меньшего размера, если размер буфера не кратен
|
||||
* блоку */
|
||||
if (block_size >(f_sig_tbl[sig].size-cntr))
|
||||
block_size=f_sig_tbl[sig].size-cntr;
|
||||
|
||||
err = f_load_block(hnd, cntr, block_size, sig, ch_cnt);
|
||||
if (!err)
|
||||
cntr+=block_size;
|
||||
}
|
||||
|
||||
/* делаем активным загруженный сигнал */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_OutCycleSetup(hnd, X502_OUT_CYCLE_FLAGS_WAIT_DONE);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка установки циклического сигнала: %s!", X502_GetErrorString(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int32_t err = 0;
|
||||
uint32_t ver;
|
||||
t_x502_hnd hnd = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* устанавливаем локаль, чтобы можно было выводить по-русски в CP1251 без перевода в OEM */
|
||||
setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
hnd = select_dev_from_list(argc, argv, 0);
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (hnd != NULL) {
|
||||
/* Разрешаем все каналы на вывод (в этом примере мы не будем
|
||||
использовать асинхронный вывод), а какие каналы реально будут
|
||||
использованы определяем когда подаем данные в L502_PrepareData */
|
||||
err = X502_StreamsEnable(hnd, X502_STREAM_ALL_OUT);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка разрешения потоков (%d): %s!", err,
|
||||
X502_GetErrorString(err));
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
/* если хотим, то можем загрузить синхнал до разрешения
|
||||
* синхронного ввода. Тогда мы могли бы его запустить, наприемер,
|
||||
всесте с АЦП по L502_StreamsStart() */
|
||||
err = f_load_cycle_signal(hnd, 1);
|
||||
|
||||
/* разрешаем синхронный ввод. В принципе можно его разрешить только
|
||||
* после загрузки первого синала в нашем примере. Но данный пример
|
||||
* показывает что мы можем сделать это и до выставления сигнала,
|
||||
* например если захотим запустить ввод АЦП до того как будет нужно
|
||||
* подать циклический сигнал на вывод */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_StreamsStart(hnd);
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int exit = 0;
|
||||
|
||||
printf("Введите одно из следующего:\n");
|
||||
printf(" число от 1 до %d - установить сигнал с указанным номером\n",
|
||||
(int)(sizeof(f_sig_tbl)/sizeof(f_sig_tbl[0])));
|
||||
printf(" s или stop - останов генерации сигнала\n");
|
||||
printf(" e или exit - выход из программы\n");
|
||||
|
||||
/* Цикл ввода команд */
|
||||
while (!err && !exit) {
|
||||
char cmd[512];
|
||||
printf(">");
|
||||
fflush(stdout);
|
||||
scanf("%s", cmd);
|
||||
if (!strcmp(cmd, "exit") || !strcmp(cmd,"e")) {
|
||||
exit=1;
|
||||
} else if (!strcmp(cmd, "stop")||!strcmp(cmd,"s")) {
|
||||
err = X502_OutCycleStop(hnd, X502_OUT_CYCLE_FLAGS_WAIT_DONE);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова циклического сигнала (%d): %s\n",
|
||||
err, X502_GetErrorString(err));
|
||||
}
|
||||
} else {
|
||||
int sig = atoi(cmd);
|
||||
if ((sig <= 0) || (sig > (int)(sizeof(f_sig_tbl)/sizeof(f_sig_tbl[0])))) {
|
||||
fprintf(stderr, "Неверный номер сигнала или неизвестная команда\n");
|
||||
} else {
|
||||
err = f_load_cycle_signal(hnd, sig-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
X502_StreamsStop(hnd);
|
||||
}
|
||||
}
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(hnd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
48
lib/x502api-1.1.34/examples/c/x502_cycle_out/makefile
Normal file
48
lib/x502api-1.1.34/examples/c/x502_cycle_out/makefile
Normal file
@ -0,0 +1,48 @@
|
||||
# makefile для сборки примера с помощью компиляторов mingw (под Windows)
|
||||
# или GCC (под Linux). Необходимо определить 3 переменные:
|
||||
#
|
||||
# CC - имя команды для вызова компилятора
|
||||
# X502API_LIBRARIES_DIR - путь к файлм .a или .so библиотек l502api, e502api, x502api (если не стандартный)
|
||||
# X502API_INCLUDE_DIR - путь к заголовочным файлам l502api.h, e502api.h, x502api.h
|
||||
#
|
||||
# Ниже приведено несколько примеров в закоментированном виде
|
||||
|
||||
#--- Linux с заголовками и библиотекой в стандартных директориях: компилятор GCC
|
||||
#CC = gcc
|
||||
|
||||
#--- Вариант запуска из MSYS со стандартным 32-битным mingw
|
||||
#CC = gcc
|
||||
#X502API_LIBRARIES_DIR = "/c/Program Files/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/c/Program Files/L-Card/lpcie/include"
|
||||
|
||||
|
||||
#--- 64-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = x86_64-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw64"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = i686-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw, идущий вместе с cygwin --------
|
||||
#CC = i686-pc-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
|
||||
FLAGS =
|
||||
|
||||
ifdef X502API_LIBRARIES_DIR
|
||||
FLAGS += -L $(X502API_LIBRARIES_DIR)
|
||||
endif
|
||||
|
||||
ifdef X502API_INCLUDE_DIR
|
||||
FLAGS += -I $(X502API_INCLUDE_DIR)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
all:
|
||||
$(CC) main.c $(FLAGS) -ll502api -le502api -lx502api -o x502_cycle_out
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x502_cycle_out", "x502_cycle_out.vcproj", "{CA9882D8-F21E-47DD-87A6-44AD55ED0ED2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CA9882D8-F21E-47DD-87A6-44AD55ED0ED2}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{CA9882D8-F21E-47DD-87A6-44AD55ED0ED2}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{CA9882D8-F21E-47DD-87A6-44AD55ED0ED2}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{CA9882D8-F21E-47DD-87A6-44AD55ED0ED2}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="x502_cycle_out"
|
||||
ProjectGUID="{CA9882D8-F21E-47DD-87A6-44AD55ED0ED2}"
|
||||
RootNamespace="x502_cycle_out"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="c:\Program Files (x86)\L-Card\lpcie\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="l502api.lib e502api.lib x502api.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="c:\Program Files (x86)\L-Card\lpcie\lib\msvc"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="c:\Program Files (x86)\L-Card\lpcie\include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="l502api.lib e502api.lib x502api.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="c:\Program Files (x86)\L-Card\lpcie\lib\msvc"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\main.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@ -0,0 +1,30 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
set(PROJECT x502_dac_cntr_test)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR})
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
891
lib/x502api-1.1.34/examples/c/x502_dac_cntr_test/main.c
Normal file
891
lib/x502api-1.1.34/examples/c/x502_dac_cntr_test/main.c
Normal file
@ -0,0 +1,891 @@
|
||||
/*
|
||||
При использовании заглушки соединяющей DOUT -> DIN есть возмость проверить корректность приема/передачи цифровых каналов в петле
|
||||
|
||||
При использовании флага DCI_TEST_MODE по каналу АЦП должен приниматься 32-битный счетчик
|
||||
*/
|
||||
|
||||
/*
|
||||
Данный пример представляет из себя консольную программу на языке C,
|
||||
демонстрирующую работу с модулями L502 и E502 на примере синхронного
|
||||
ввода данных с АЦП и цифровых линий.
|
||||
|
||||
Перед сбором в примере идет поиск модулей, подключенных по интерфейсам PCI-Express и USB,
|
||||
и предоставляется список для выбора модуля, с которым нужно работать.
|
||||
Для подключения по Ethernet нужно указать IP-адреса интересующих модулей
|
||||
в качестве аргументов командной строки при вызове примера, тогда эти адреса
|
||||
будут добавлены в конец списка выбора модуля.
|
||||
Например, если интересуют модули с адресами 192.168.1.5 и 192.168.1.6,
|
||||
то пример можно вызвать:
|
||||
x502_stream_read 192.168.1.5 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 "l502api.h"
|
||||
#include "e502api.h"
|
||||
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "x502api_private.h"
|
||||
|
||||
#define STREAM_IN_WRD_TYPE(wrd) wrd & 0x80000000 ? STREAM_IN_WRD_ADC : \
|
||||
(wrd & 0xFF000000) == 0x0 ? STREAM_IN_WRD_DIN : \
|
||||
((wrd & 0xFF000000)>>24) == 0x01 ? STREAM_IN_WRD_MSG : STREAM_IN_WRD_USR
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CLOCK_MONOTONIC 1
|
||||
|
||||
int clock_gettime(int a, struct timespec *spec) {
|
||||
__int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
|
||||
wintime -=116444736000000000i64; //1jan1601 to 1jan1970
|
||||
spec->tv_sec =wintime / 10000000i64; //seconds
|
||||
spec->tv_nsec =wintime % 10000000i64 *100; //nano-seconds
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
static int f_out = 0;
|
||||
|
||||
/* количество используемых логических каналов */
|
||||
#define ADC_LCH_CNT 3
|
||||
|
||||
/* частота сбора АЦП в Гц*/
|
||||
#define ADC_FREQ 2000000
|
||||
/* частота кадров (на логический канал). При ADC_FREQ/ADC_LCH_CNT - межкадровой задержки нет */
|
||||
#define ADC_FRAME_FREQ (ADC_FREQ/ADC_LCH_CNT)
|
||||
/* частота синхронного ввода в Гц*/
|
||||
#define DIN_FREQ 500000
|
||||
//#define DIN_FREQ 50000
|
||||
#define DOUT_FREQ 1000000
|
||||
#define DOUT_FREQ 1000000
|
||||
|
||||
//#define ENABLE_DOUT
|
||||
//#define ENABLE_DAC1
|
||||
//#define ENABLE_DAC2
|
||||
|
||||
#define ENABLE_ADC
|
||||
|
||||
#define ENABLE_DCI_TEST_MODE
|
||||
|
||||
// при ADC_FREQ==2000000 и DIN_FREQ==1000000 через Ethernet обязательно будет X502_STREAM_IN_MSG_OVERFLOW
|
||||
|
||||
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
|
||||
|
||||
/* сколько отсчетов считываем за блок */
|
||||
#define READ_BLOCK_SIZE 4096*66*3
|
||||
//#define READ_BLOCK_SIZE ((1024*2) + 3)
|
||||
//200
|
||||
/* таймаут на прием блока (мс) */
|
||||
#define READ_TIMEOUT 2000
|
||||
|
||||
|
||||
/* номера используемых физических каналов */
|
||||
static uint32_t f_channels[ADC_LCH_CNT] = {0,4,6};
|
||||
/* режимы измерения для каналов */
|
||||
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF};
|
||||
/* диапазоны измерения для каналов */
|
||||
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_10, X502_ADC_RANGE_10, X502_ADC_RANGE_10};
|
||||
|
||||
|
||||
t_x502_hnd g_hnd = NULL;
|
||||
|
||||
uint32_t tstCntr = 0x00000001;
|
||||
uint32_t tstCntr24 = 0x00000001;
|
||||
|
||||
int dac2_once = 1;
|
||||
volatile int stream_ingibit_cntr = (2 * 1024 * 1024);
|
||||
volatile int start_stream_ingibit = 1;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
void timespec_diff(struct timespec *a, struct timespec *b,
|
||||
struct timespec *result) {
|
||||
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||
result->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
if (result->tv_nsec < 0) {
|
||||
--result->tv_sec;
|
||||
result->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
double timespec_to_double(struct timespec *ts)
|
||||
{
|
||||
return ((double)(ts->tv_sec) + ((double)(ts->tv_nsec) / NSEC_PER_SEC));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI ThreadFunc(void* arg)
|
||||
#else
|
||||
void * threadFunc(void * arg)
|
||||
#endif
|
||||
{
|
||||
int32_t g_snd_cnt = 0;
|
||||
static uint32_t snd_buf[READ_BLOCK_SIZE];
|
||||
|
||||
int i;
|
||||
struct timespec start_time;
|
||||
struct timespec cur_time;
|
||||
struct timespec spent_time;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
while(!f_out) {
|
||||
#define DAC_SEND_TEST_CNTR
|
||||
#ifdef DAC_SEND_TEST_CNTR
|
||||
for (i = 0; i < READ_BLOCK_SIZE; ) {
|
||||
#ifdef ENABLE_DOUT
|
||||
//snd_buf[i] = ((tstCntr24 & 0xff) << 16) | ((tstCntr24 & 0xff00)) | ((tstCntr24 & 0xff0000) >> 16);
|
||||
snd_buf[i] = tstCntr24 & 0xffff;
|
||||
/*if (i & 8) {
|
||||
snd_buf[i] = 0x30000;
|
||||
} else {
|
||||
snd_buf[i] = 0x33412;
|
||||
}*/
|
||||
i++;
|
||||
#endif
|
||||
#ifdef ENABLE_DAC1
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC1;
|
||||
i++;
|
||||
#endif
|
||||
#ifdef ENABLE_DAC2
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC2;
|
||||
i++;
|
||||
#endif
|
||||
tstCntr++;
|
||||
tstCntr24++;
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < READ_BLOCK_SIZE; i++) {
|
||||
snd_buf[i] = tstCntr;
|
||||
tstCntr++;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int32_t snd_cnt = 0;
|
||||
//printf("to send %x\n", snd_buf[0]);
|
||||
uint32_t to_send = READ_BLOCK_SIZE;
|
||||
uint32_t *to_send_ptr = snd_buf;
|
||||
|
||||
while (to_send && !f_out) {
|
||||
snd_cnt = X502_Send(g_hnd, to_send_ptr, to_send, READ_TIMEOUT);
|
||||
if (snd_cnt < 0 || f_out) {
|
||||
printf("thread exiting\n");
|
||||
return 0;
|
||||
}
|
||||
to_send -= snd_cnt;
|
||||
to_send_ptr += snd_cnt;
|
||||
stream_ingibit_cntr -=snd_cnt;
|
||||
if(stream_ingibit_cntr <= 0) {
|
||||
start_stream_ingibit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
g_snd_cnt += READ_BLOCK_SIZE;
|
||||
/*g_snd_cnt += snd_cnt;
|
||||
if (snd_cnt != READ_BLOCK_SIZE) {
|
||||
printf("snd_cnt=%d %d expected!\n", snd_cnt, READ_BLOCK_SIZE);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// infinite loop
|
||||
|
||||
//printf("snd_cnt=%d\n", snd_cnt);
|
||||
//while(1);
|
||||
//while(!f_out);
|
||||
//return 0;
|
||||
|
||||
//sleep(3);
|
||||
|
||||
//tstCntr += snd_cnt;
|
||||
|
||||
if(g_snd_cnt >= 128*3) {
|
||||
|
||||
///while (!f_out) {}
|
||||
//sleep(5);
|
||||
//g_snd_cnt = 0;
|
||||
}
|
||||
|
||||
/*if(g_snd_cnt>=3) {
|
||||
printf("data sent ok\n");
|
||||
while(!f_out){}
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5)
|
||||
{
|
||||
timespec_diff(&cur_time, &start_time, &spent_time);
|
||||
double spent_secs = timespec_to_double(&spent_time);
|
||||
printf("cnt=%d sec=%f snd speed=%f wrds/sec\n", g_snd_cnt, spent_secs, (g_snd_cnt) / (spent_secs));
|
||||
start_time = cur_time;
|
||||
g_snd_cnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Обработчик сигнала завершения для Linux */
|
||||
static void f_abort_handler(int sig) {
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Функция находит все подключенные модули по интерфейсам PCI-Express и USB и
|
||||
* сохраняет записи о этих устройствах в выделенный массив.
|
||||
* Также создаются записи по переданным IP-адресам модулей и добавляются в конец
|
||||
* массива.
|
||||
* Указатель на выделенный массив, который должен быть потом очищен, сохраняется
|
||||
* в pdevrec_list, а количество действительных элементов (память которых должна
|
||||
* быть в дальнейшем освобождена с помощью X502_FreeDevRecordList()) возвращается
|
||||
* как результат функции */
|
||||
static uint32_t f_get_all_devrec(t_x502_devrec **pdevrec_list, uint32_t *ip_addr_list, unsigned ip_cnt) {
|
||||
int32_t fnd_devcnt = 0;
|
||||
uint32_t pci_devcnt = 0;
|
||||
uint32_t 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);
|
||||
|
||||
if ((pci_devcnt + usb_devcnt + ip_cnt) != 0) {
|
||||
/* выделяем память для массива для сохранения найденного количества записей */
|
||||
rec_list = malloc((pci_devcnt + 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* создаем записи для переданного массива ip-адресов */
|
||||
for (i=0; i < ip_cnt; i++) {
|
||||
if (E502_MakeDevRecordByIpAddr(&rec_list[fnd_devcnt], ip_addr_list[i],0, TCP_CONNECTION_TOUT) == X502_ERR_OK) {
|
||||
fnd_devcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
uint32_t fnd_devcnt,i, dev_ind;
|
||||
t_x502_devrec *devrec_list = NULL;
|
||||
uint32_t *ip_addr_list = NULL;
|
||||
uint32_t ip_cnt = 0;
|
||||
t_x502_hnd hnd = NULL;
|
||||
|
||||
/* если есть аргументы командной строки, то предполагаем, что это могут быть
|
||||
ip-адреса интересующих устройств. */
|
||||
if (argc > 1) {
|
||||
ip_addr_list = malloc((argc-1) * sizeof(ip_addr_list[0]));
|
||||
if (ip_addr_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_addr_list[ip_cnt++] = ((a[0] & 0xFF) << 24) |
|
||||
((a[1] & 0xFF) << 16) |
|
||||
((a[2] & 0xFF) << 8) |
|
||||
(a[3] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* получаем список модулей для выбора */
|
||||
fnd_devcnt = f_get_all_devrec(&devrec_list, ip_addr_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);
|
||||
|
||||
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_addr_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_din = DIN_FREQ;
|
||||
|
||||
err = X502_SetAdcFreq(hnd, &f_adc, NULL);
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_SetDinFreq(hnd, &f_din);
|
||||
if (err == X502_ERR_OK) {
|
||||
/* выводим реально установленные значения - те что вернули функции */
|
||||
printf("Установлены частоты:\n Частота сбора АЦП = %0.0f\n"
|
||||
" Частота цифрового ввода = %0.0f\n",
|
||||
f_adc, f_din);
|
||||
}
|
||||
}
|
||||
|
||||
double dout_freq = DOUT_FREQ;
|
||||
|
||||
err = X502_SetOutFreq(hnd, &dout_freq);
|
||||
printf("X502_SetOutFreq err=%d dout_freq = %.1f\n", err, dout_freq);
|
||||
|
||||
/* записываем настройки в модуль */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_Configure(hnd, 0);
|
||||
|
||||
/* разрешаем синхронные потоки */
|
||||
if (err == X502_ERR_OK) {
|
||||
int streams = 0;
|
||||
#if defined(ENABLE_ADC)
|
||||
streams |= X502_STREAM_ALL_IN;
|
||||
#endif
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
streams |= X502_STREAM_ALL_OUT;
|
||||
#endif
|
||||
err = X502_StreamsEnable(hnd, streams);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
uint32_t ver;
|
||||
#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);
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
g_hnd = f_dev_select_open(argc, argv);
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (g_hnd != NULL) {
|
||||
/* получаем информацию */
|
||||
t_x502_info info;
|
||||
err = X502_GetDevInfo(g_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);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
/* настраиваем параметры модуля */
|
||||
err = f_setup_params(g_hnd);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
|
||||
}
|
||||
|
||||
|
||||
#define E502_REGS_ARM_DCI_TEST_MODE 0x10C
|
||||
#ifdef ENABLE_DCI_TEST_MODE
|
||||
// включаем режим когда по DCI должен передаваться счетчик начиная с 1
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_DCI_TEST_MODE, 1);
|
||||
#else
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_DCI_TEST_MODE, 0);
|
||||
#endif
|
||||
|
||||
//#define TEST_MODE DCI_TEST_MODE
|
||||
#define TEST_MODE 0
|
||||
#if 0
|
||||
|
||||
#ifdef ENABLE_DOUT
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN | SYN_DIGOUT_EN);
|
||||
#else
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN);
|
||||
#endif
|
||||
#endif
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_BF_CTL, X502_REGBIT_BF_CTL_BF_RESET_Msk);
|
||||
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
HANDLE thread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
|
||||
while(start_stream_ingibit);
|
||||
Sleep(2);
|
||||
#else
|
||||
pthread_t threadId;
|
||||
// Create a thread that will function threadFunc()
|
||||
err = pthread_create(&threadId, NULL, &threadFunc, g_hnd);
|
||||
while(start_stream_ingibit);
|
||||
sleep(2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
X502_SetSyncMode(g_hnd, X502_SYNC_INTERNAL);
|
||||
|
||||
/* запуск синхронного ввода-вывода */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsStart(g_hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка запуска сбора данных: %s!\n", X502_GetErrorString(err));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
#ifdef ENABLE_DOUT
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, DCI_TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN | SYN_DIGOUT_EN);
|
||||
#else
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, DCI_TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN);
|
||||
#endif
|
||||
|
||||
//X502_PreloadStart(g_hnd);
|
||||
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_IOHARD_GO_SYNC_IO, 1);
|
||||
#endif
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int block;
|
||||
int32_t stop_err;
|
||||
|
||||
printf("Сбор данных запущен. Для останова нажмите %s\n",
|
||||
#ifdef _WIN32
|
||||
"любую клавишу"
|
||||
#else
|
||||
"CTRL+C"
|
||||
#endif
|
||||
);
|
||||
fflush(stdout);
|
||||
|
||||
struct timespec start_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
int32_t g_rcv_cnt = 0;
|
||||
int cntr = 0;
|
||||
int rcv_cntr = 1;//0x02000000;
|
||||
|
||||
//threadFunc(NULL);
|
||||
//return;
|
||||
|
||||
|
||||
#if !defined(ENABLE_ADC)
|
||||
if(1) {
|
||||
while(!f_out) {}
|
||||
} else
|
||||
#endif
|
||||
for (block = 0; (err == X502_ERR_OK) && !f_out; block++) {
|
||||
int32_t rcv_size;
|
||||
uint32_t adc_size, din_size;
|
||||
|
||||
/* массив для приема необработанных данных */
|
||||
static uint32_t rcv_buf[READ_BLOCK_SIZE];
|
||||
static uint32_t snd_buf[READ_BLOCK_SIZE];
|
||||
static double adc_data[READ_BLOCK_SIZE];
|
||||
static uint32_t din_data[READ_BLOCK_SIZE];
|
||||
|
||||
int i;
|
||||
#if 0
|
||||
for(i=0;i<READ_BLOCK_SIZE;i++) {
|
||||
snd_buf[i] = i + cntr;
|
||||
snd_buf[i] &= ~0xff000000;
|
||||
snd_buf[i] |= 0x02000000;
|
||||
}
|
||||
|
||||
int32_t snd_cnt = 0;
|
||||
snd_cnt = X502_Send(hnd, snd_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
cntr += snd_cnt;
|
||||
g_snd_cnt += snd_cnt;
|
||||
|
||||
#endif
|
||||
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
#if 0
|
||||
if (cur_time.tv_sec - start_time.tv_sec != 0) {
|
||||
printf("snd_cnt=%d speed=%d wrds/sec\n", snd_cnt, (g_snd_cnt) / (cur_time.tv_sec - start_time.tv_sec));
|
||||
printf("g_snd_cnt=%d secs=%d\n", g_snd_cnt, cur_time.tv_sec - start_time.tv_sec);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
if (g_snd_cnt > READ_BLOCK_SIZE * 10) {
|
||||
g_snd_cnt=0;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
}
|
||||
#endif
|
||||
//continue;
|
||||
|
||||
/* принимаем данные (по таймауту) */
|
||||
rcv_size = X502_Recv(g_hnd, rcv_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
//printf("rcv_size=%d\n", rcv_size);
|
||||
g_rcv_cnt += rcv_size;
|
||||
int error = 0;
|
||||
|
||||
if(1) {
|
||||
uint32_t val;
|
||||
static int dout_once = 1;
|
||||
static int once = 1;
|
||||
|
||||
if(dout_once) {
|
||||
dout_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, E502_REGS_ARM_DAC_ERR, &val);
|
||||
if (val & DIGOUT_ERROR) {
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
X502_FpgaRegRead(g_hnd, 0x104, &err_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x105, &exp_val);
|
||||
printf("dout error: %x %x expected\n", err_val, exp_val);
|
||||
}
|
||||
}
|
||||
if(once) {
|
||||
X502_FpgaRegRead(g_hnd, E502_REGS_ARM_DAC_ERR, &val);
|
||||
if (val & DAC1_ERROR) {
|
||||
once = 0;
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
X502_FpgaRegRead(g_hnd, 0x106, &err_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x107, &exp_val);
|
||||
printf("dac1 error: %x %x expected\n", err_val, exp_val);
|
||||
}
|
||||
if (val & DAC2_ERROR) {
|
||||
once = 0;
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
X502_FpgaRegRead(g_hnd, 0x108, &err_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x109, &exp_val);
|
||||
printf("dac2 error: %x %x expected\n", err_val, exp_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(0){
|
||||
static int dout_once = 1;
|
||||
static int dac1_once = 1;
|
||||
static int dac2_once = 1;
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
uint32_t next_val;
|
||||
|
||||
if(dout_once) {
|
||||
X502_FpgaRegRead(g_hnd, 0x120, &err_val);
|
||||
if (err_val) {
|
||||
dout_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, 0x121, &exp_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x122, &next_val);
|
||||
printf("GD32 dout error: %x %x expected\n", err_val & 0xffffff, exp_val & 0xffffff);
|
||||
}
|
||||
}
|
||||
if (dac1_once) {
|
||||
X502_FpgaRegRead(g_hnd, 0x123, &err_val);
|
||||
if (err_val) {
|
||||
dac1_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, 0x124, &exp_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x125, &next_val);
|
||||
printf("GD32 dac1 error: %x %x expected\n", err_val & 0xffff, exp_val & 0xffff);
|
||||
}
|
||||
}
|
||||
if (dac2_once) {
|
||||
X502_FpgaRegRead(g_hnd, 0x126, &err_val);
|
||||
if (err_val) {
|
||||
dac2_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, 0x127, &exp_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x128, &next_val);
|
||||
printf("GD32 dac2 error: %x %x expected\n", err_val & 0xffff, exp_val & 0xffff);
|
||||
}
|
||||
}
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
#if 0
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5) {
|
||||
printf("rcv speed=%lld wrds/sec\n", (g_rcv_cnt) / (cur_time.tv_sec - start_time.tv_sec));
|
||||
start_time.tv_sec = cur_time.tv_sec;
|
||||
g_rcv_cnt = 0;
|
||||
}
|
||||
#else
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5) {
|
||||
printf("rcv speed=%lld wrds/sec cntr=%x\n", (g_rcv_cnt) / (cur_time.tv_sec - start_time.tv_sec), rcv_cntr);
|
||||
start_time.tv_sec = cur_time.tv_sec;
|
||||
g_rcv_cnt = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rcv_size; i++) {
|
||||
|
||||
#ifndef ENABLE_DCI_TEST_MODE
|
||||
// тест с заглушкой DOUT -> DIN
|
||||
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(rcv_buf[i]);
|
||||
/* проверяем - это данные от АЦП или цифровых входов */
|
||||
if (type != STREAM_IN_WRD_DIN) {
|
||||
continue;
|
||||
}
|
||||
if ((rcv_buf[i] & 0xFFFF) != (rcv_cntr & 0xFFFF))
|
||||
{
|
||||
printf("%x[%i] %x expected\n", rcv_buf[i], i, rcv_cntr);
|
||||
rcv_cntr = rcv_buf[i] & 0xFFFF;
|
||||
error = 1;
|
||||
}
|
||||
rcv_cntr++;
|
||||
#else
|
||||
|
||||
// проверка для DCI_TEST_MODE
|
||||
if (rcv_buf[i] != rcv_cntr) {
|
||||
printf("%x[%i] %x expected\n", rcv_buf[i], i, rcv_cntr);
|
||||
rcv_cntr = rcv_buf[i];
|
||||
error = 1;
|
||||
}
|
||||
rcv_cntr++;
|
||||
//rcv_cntr &= ~0xff000000;
|
||||
//rcv_cntr |= 0x02000000;
|
||||
/*if (rcv_cntr >= 0x02000400) {
|
||||
rcv_cntr = 0x02000000;
|
||||
}*/
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
continue;
|
||||
|
||||
if(error) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
/* результат меньше нуля означает ошибку */
|
||||
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(g_hnd, &first_lch);
|
||||
|
||||
adc_size = sizeof(adc_data)/sizeof(adc_data[0]);
|
||||
din_size = sizeof(din_data)/sizeof(din_data[0]);
|
||||
|
||||
/* обрабатываем принятые данные, распределяя их на данные АЦП и цифровых входов */
|
||||
err = X502_ProcessData(g_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("Блок %3d. Обработано данных АЦП =%d, цифровых входов =%d\n",
|
||||
block, adc_size, din_size);
|
||||
/* если приняли цифровые данные - выводим первый отсчет */
|
||||
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", lch, adc_data[pos]);
|
||||
} else {
|
||||
printf(" lch[%d]= ---- \n", lch);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
/* проверка нажатия клавиши для выхода */
|
||||
if (err == X502_ERR_OK) {
|
||||
if (_kbhit())
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
|
||||
#ifdef _WIN32
|
||||
//TODO: pthread_join
|
||||
#else
|
||||
pthread_join(threadId, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* останавливаем поток сбора данных (независимо от того, была ли ошибка) */
|
||||
stop_err = X502_StreamsStop(g_hnd);
|
||||
if (stop_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова сбора данных: %s\n", X502_GetErrorString(err));
|
||||
if (err == X502_ERR_OK)
|
||||
err = stop_err;
|
||||
} else {
|
||||
printf("Сбор данных остановлен успешно\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DCI_TEST_MODE
|
||||
// выключаем режим когда по DCI должен передаваться счетчик начиная с 1
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_DCI_TEST_MODE, 0);
|
||||
#endif
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(g_hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(g_hnd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
set(PROJECT x502_ring_mode0_test)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR})
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
910
lib/x502api-1.1.34/examples/c/x502_ring_mode0_test/main.c
Normal file
910
lib/x502api-1.1.34/examples/c/x502_ring_mode0_test/main.c
Normal file
@ -0,0 +1,910 @@
|
||||
/*
|
||||
При использовании заглушки соединяющей DOUT -> DIN есть возмость проверить корректность приема/передачи цифровых каналов в петле
|
||||
|
||||
При использовании флага DCI_TEST_MODE по каналу АЦП должен приниматься 32-битный счетчик
|
||||
*/
|
||||
|
||||
/*
|
||||
Данный пример представляет из себя консольную программу на языке C,
|
||||
демонстрирующую работу с модулями L502 и E502 на примере синхронного
|
||||
ввода данных с АЦП и цифровых линий.
|
||||
|
||||
Перед сбором в примере идет поиск модулей, подключенных по интерфейсам PCI-Express и USB,
|
||||
и предоставляется список для выбора модуля, с которым нужно работать.
|
||||
Для подключения по Ethernet нужно указать IP-адреса интересующих модулей
|
||||
в качестве аргументов командной строки при вызове примера, тогда эти адреса
|
||||
будут добавлены в конец списка выбора модуля.
|
||||
Например, если интересуют модули с адресами 192.168.1.5 и 192.168.1.6,
|
||||
то пример можно вызвать:
|
||||
x502_stream_read 192.168.1.5 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 "l502api.h"
|
||||
#include "e502api.h"
|
||||
|
||||
#include "../../devs/e502/e502_fpga_regs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <locale.h>
|
||||
#include <conio.h>
|
||||
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "x502api_private.h"
|
||||
|
||||
#define STREAM_IN_WRD_TYPE(wrd) wrd & 0x80000000 ? STREAM_IN_WRD_ADC : \
|
||||
(wrd & 0xFF000000) == 0x0 ? STREAM_IN_WRD_DIN : \
|
||||
((wrd & 0xFF000000)>>24) == 0x01 ? STREAM_IN_WRD_MSG : STREAM_IN_WRD_USR
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CLOCK_MONOTONIC 1
|
||||
|
||||
int clock_gettime(int a, struct timespec *spec) {
|
||||
__int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
|
||||
wintime -=116444736000000000i64; //1jan1601 to 1jan1970
|
||||
spec->tv_sec =wintime / 10000000i64; //seconds
|
||||
spec->tv_nsec =wintime % 10000000i64 *100; //nano-seconds
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
static int f_out = 0;
|
||||
|
||||
/* количество используемых логических каналов */
|
||||
#define ADC_LCH_CNT 3
|
||||
|
||||
/* частота сбора АЦП в Гц*/
|
||||
#define ADC_FREQ 1000000
|
||||
/* частота кадров (на логический канал). При ADC_FREQ/ADC_LCH_CNT - межкадровой задержки нет */
|
||||
#define ADC_FRAME_FREQ (ADC_FREQ/ADC_LCH_CNT)
|
||||
/* частота синхронного ввода в Гц*/
|
||||
#define DIN_FREQ 1000000
|
||||
//#define DIN_FREQ 50000
|
||||
#define DOUT_FREQ 1000000
|
||||
#define DOUT_FREQ 1000000
|
||||
|
||||
// при ADC_FREQ==2000000 и DIN_FREQ==1000000 через Ethernet обязательно будет X502_STREAM_IN_MSG_OVERFLOW
|
||||
|
||||
|
||||
#define TCP_CONNECTION_TOUT 5000
|
||||
|
||||
|
||||
/* сколько отсчетов считываем за блок */
|
||||
#define READ_BLOCK_SIZE 4096*66*3
|
||||
//#define READ_BLOCK_SIZE ((1024*2) + 3)
|
||||
//200
|
||||
/* таймаут на прием блока (мс) */
|
||||
#define READ_TIMEOUT 2000
|
||||
|
||||
|
||||
/* номера используемых физических каналов */
|
||||
static uint32_t f_channels[ADC_LCH_CNT] = {0,4,6};
|
||||
/* режимы измерения для каналов */
|
||||
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF};
|
||||
/* диапазоны измерения для каналов */
|
||||
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_10, X502_ADC_RANGE_10, X502_ADC_RANGE_10};
|
||||
|
||||
|
||||
t_x502_hnd g_hnd = NULL;
|
||||
|
||||
uint32_t tstCntr = 0x00000001;
|
||||
uint32_t tstCntr24 = 0x00000001;
|
||||
|
||||
int dac2_once = 1;
|
||||
volatile int stream_ingibit_cntr = (2 * 1024 * 1024);
|
||||
volatile int start_stream_ingibit = 1;
|
||||
|
||||
#define ENABLE_DOUT
|
||||
#define ENABLE_DAC1
|
||||
#define ENABLE_DAC2
|
||||
|
||||
#define ENABLE_ADC
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
void timespec_diff(struct timespec *a, struct timespec *b,
|
||||
struct timespec *result) {
|
||||
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||
result->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
if (result->tv_nsec < 0) {
|
||||
--result->tv_sec;
|
||||
result->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
double timespec_to_double(struct timespec *ts)
|
||||
{
|
||||
return ((double)(ts->tv_sec) + ((double)(ts->tv_nsec) / NSEC_PER_SEC));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI ThreadFunc(void* arg)
|
||||
#else
|
||||
void * threadFunc(void * arg)
|
||||
#endif
|
||||
{
|
||||
int32_t g_snd_cnt = 0;
|
||||
static uint32_t snd_buf[READ_BLOCK_SIZE];
|
||||
|
||||
int i;
|
||||
struct timespec start_time;
|
||||
struct timespec cur_time;
|
||||
struct timespec spent_time;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
while(!f_out) {
|
||||
#define DAC_SEND_TEST_CNTR
|
||||
#ifdef DAC_SEND_TEST_CNTR
|
||||
for (i = 0; i < READ_BLOCK_SIZE; ) {
|
||||
#ifdef ENABLE_DOUT
|
||||
//snd_buf[i] = ((tstCntr24 & 0xff) << 16) | ((tstCntr24 & 0xff00)) | ((tstCntr24 & 0xff0000) >> 16);
|
||||
snd_buf[i] = tstCntr24 & 0xffff;
|
||||
/*if (i & 8) {
|
||||
snd_buf[i] = 0x30000;
|
||||
} else {
|
||||
snd_buf[i] = 0x33412;
|
||||
}*/
|
||||
i++;
|
||||
#endif
|
||||
#ifdef ENABLE_DAC1
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC1;
|
||||
i++;
|
||||
#endif
|
||||
#ifdef ENABLE_DAC2
|
||||
snd_buf[i] = (tstCntr & 0xffff) | X502_STREAM_OUT_WORD_TYPE_DAC2;
|
||||
i++;
|
||||
#endif
|
||||
tstCntr++;
|
||||
tstCntr24++;
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < READ_BLOCK_SIZE; i++) {
|
||||
snd_buf[i] = tstCntr;
|
||||
tstCntr++;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int32_t snd_cnt = 0;
|
||||
//printf("to send %x\n", snd_buf[0]);
|
||||
uint32_t to_send = READ_BLOCK_SIZE;
|
||||
uint32_t *to_send_ptr = snd_buf;
|
||||
|
||||
while (to_send) {
|
||||
snd_cnt = X502_Send(g_hnd, to_send_ptr, to_send, READ_TIMEOUT);
|
||||
if (snd_cnt < 0 || f_out) {
|
||||
printf("thread exiting\n");
|
||||
return 0;
|
||||
}
|
||||
to_send -= snd_cnt;
|
||||
to_send_ptr += snd_cnt;
|
||||
stream_ingibit_cntr -=snd_cnt;
|
||||
if(stream_ingibit_cntr <= 0) {
|
||||
start_stream_ingibit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
g_snd_cnt += READ_BLOCK_SIZE;
|
||||
/*g_snd_cnt += snd_cnt;
|
||||
if (snd_cnt != READ_BLOCK_SIZE) {
|
||||
printf("snd_cnt=%d %d expected!\n", snd_cnt, READ_BLOCK_SIZE);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// infinite loop
|
||||
|
||||
//printf("snd_cnt=%d\n", snd_cnt);
|
||||
//while(1);
|
||||
//while(!f_out);
|
||||
//return 0;
|
||||
|
||||
//sleep(3);
|
||||
|
||||
//tstCntr += snd_cnt;
|
||||
|
||||
if(g_snd_cnt >= 128*3) {
|
||||
|
||||
///while (!f_out) {}
|
||||
//sleep(5);
|
||||
//g_snd_cnt = 0;
|
||||
}
|
||||
|
||||
/*if(g_snd_cnt>=3) {
|
||||
printf("data sent ok\n");
|
||||
while(!f_out){}
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5)
|
||||
{
|
||||
timespec_diff(&cur_time, &start_time, &spent_time);
|
||||
double spent_secs = timespec_to_double(&spent_time);
|
||||
printf("cnt=%d sec=%f snd speed=%f wrds/sec\n", g_snd_cnt, spent_secs, (g_snd_cnt) / (spent_secs));
|
||||
start_time = cur_time;
|
||||
g_snd_cnt = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Обработчик сигнала завершения для Linux */
|
||||
static void f_abort_handler(int sig) {
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Функция находит все подключенные модули по интерфейсам PCI-Express и USB и
|
||||
* сохраняет записи о этих устройствах в выделенный массив.
|
||||
* Также создаются записи по переданным IP-адресам модулей и добавляются в конец
|
||||
* массива.
|
||||
* Указатель на выделенный массив, который должен быть потом очищен, сохраняется
|
||||
* в pdevrec_list, а количество действительных элементов (память которых должна
|
||||
* быть в дальнейшем освобождена с помощью X502_FreeDevRecordList()) возвращается
|
||||
* как результат функции */
|
||||
static uint32_t f_get_all_devrec(t_x502_devrec **pdevrec_list, uint32_t *ip_addr_list, unsigned ip_cnt) {
|
||||
int32_t fnd_devcnt = 0;
|
||||
uint32_t pci_devcnt = 0;
|
||||
uint32_t 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);
|
||||
|
||||
if ((pci_devcnt + usb_devcnt + ip_cnt) != 0) {
|
||||
/* выделяем память для массива для сохранения найденного количества записей */
|
||||
rec_list = malloc((pci_devcnt + 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* создаем записи для переданного массива ip-адресов */
|
||||
for (i=0; i < ip_cnt; i++) {
|
||||
if (E502_MakeDevRecordByIpAddr(&rec_list[fnd_devcnt], ip_addr_list[i],0, TCP_CONNECTION_TOUT) == X502_ERR_OK) {
|
||||
fnd_devcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
uint32_t fnd_devcnt,i, dev_ind;
|
||||
t_x502_devrec *devrec_list = NULL;
|
||||
uint32_t *ip_addr_list = NULL;
|
||||
uint32_t ip_cnt = 0;
|
||||
t_x502_hnd hnd = NULL;
|
||||
|
||||
/* если есть аргументы командной строки, то предполагаем, что это могут быть
|
||||
ip-адреса интересующих устройств. */
|
||||
if (argc > 1) {
|
||||
ip_addr_list = malloc((argc-1) * sizeof(ip_addr_list[0]));
|
||||
if (ip_addr_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_addr_list[ip_cnt++] = ((a[0] & 0xFF) << 24) |
|
||||
((a[1] & 0xFF) << 16) |
|
||||
((a[2] & 0xFF) << 8) |
|
||||
(a[3] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* получаем список модулей для выбора */
|
||||
fnd_devcnt = f_get_all_devrec(&devrec_list, ip_addr_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);
|
||||
|
||||
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_addr_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) {
|
||||
err = X502_SetOutFreqDivider(hnd, 8);
|
||||
if(err) {
|
||||
printf("X502_SetOutFreqDivider err=%d\n", err);
|
||||
}
|
||||
}
|
||||
if (err == X502_ERR_OK) {
|
||||
/* выводим реально установленные значения - те что вернули функции */
|
||||
printf("Установлены частоты:\n Частота сбора АЦП = %0.0f\n"
|
||||
" Частота на лог. канал = %0.0f\n Частота цифрового ввода = %0.0f\n",
|
||||
f_adc, f_frame, f_din);
|
||||
}
|
||||
}
|
||||
|
||||
double dout_freq = DOUT_FREQ;
|
||||
|
||||
err = X502_SetOutFreq(hnd, &dout_freq);
|
||||
printf("X502_SetOutFreq err=%d dout_freq = %.1f\n", err, dout_freq);
|
||||
|
||||
/* записываем настройки в модуль */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_Configure(hnd, 0);
|
||||
|
||||
/* разрешаем синхронные потоки */
|
||||
if (err == X502_ERR_OK) {
|
||||
int streams = 0;
|
||||
#if defined(ENABLE_ADC)
|
||||
streams |= X502_STREAM_ALL_IN;
|
||||
#endif
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
streams |= X502_STREAM_ALL_OUT;
|
||||
#endif
|
||||
err = X502_StreamsEnable(hnd, streams);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void update_firmware(void) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
err = E502_SwitchToBootloader(g_hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
printf("E502_SwitchToBootloader err=%d\n", err);
|
||||
}
|
||||
X502_Close(g_hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(g_hnd);
|
||||
|
||||
char *args[] = { "./lboot", "-v", "-d", "E502", "usb", "--hash", "--con-time=5000", "/home/ruslan/vbox_share/e502-riscv.bin", NULL };
|
||||
//-r" << "--recovery" << "--hash" << "--con-time=5000" << "--devname=E502
|
||||
int ret = execve(args[0], args, NULL);
|
||||
|
||||
if (ret == -1) {
|
||||
perror("execve error");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
#define update_firmware() ((void*)0)
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int32_t err = X502_ERR_OK;
|
||||
uint32_t ver;
|
||||
#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);
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
g_hnd = f_dev_select_open(argc, argv);
|
||||
|
||||
/********************************** Работа с модулем **************************/
|
||||
/* если успешно выбрали модуль и установили с ним связь - продолжаем работу */
|
||||
if (g_hnd != NULL) {
|
||||
/* получаем информацию */
|
||||
t_x502_info info;
|
||||
err = X502_GetDevInfo(g_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);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
//update_firmware();
|
||||
}
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
/* настраиваем параметры модуля */
|
||||
err = f_setup_params(g_hnd);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
|
||||
}
|
||||
|
||||
//#define TEST_MODE DCI_TEST_MODE
|
||||
#define TEST_MODE 0
|
||||
#if 0
|
||||
|
||||
#ifdef ENABLE_DOUT
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN | SYN_DIGOUT_EN);
|
||||
#else
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN);
|
||||
#endif
|
||||
#endif
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, RING_MODE(1) | E502_REGBIT_ARM_DMA_DAC_BUF_CLR_Msk | E502_REGBIT_ARM_DMA_ADC_BUF_CLR_Msk);
|
||||
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_BF_CTL, X502_REGBIT_BF_CTL_BF_RESET_Msk);
|
||||
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
HANDLE thread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
|
||||
while(start_stream_ingibit);
|
||||
Sleep(2);
|
||||
#else
|
||||
pthread_t threadId;
|
||||
// Create a thread that will function threadFunc()
|
||||
err = pthread_create(&threadId, NULL, &threadFunc, g_hnd);
|
||||
while(start_stream_ingibit);
|
||||
sleep(2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
X502_SetSyncMode(g_hnd, X502_SYNC_INTERNAL);
|
||||
|
||||
/* запуск синхронного ввода-вывода */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsStart(g_hnd);
|
||||
if (err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка запуска сбора данных: %s!\n", X502_GetErrorString(err));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_IOHARD_GO_SYNC_IO, 0);
|
||||
#ifdef ENABLE_DOUT
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, DCI_TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN | SYN_DIGOUT_EN);
|
||||
#else
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_ARM_BLOCK, DCI_TEST_MODE | E502_REGS_ARM_BLOCK_BUF_CLEAN | SYN_DAC1_EN | SYN_DAC2_EN);
|
||||
#endif
|
||||
|
||||
//X502_PreloadStart(g_hnd);
|
||||
|
||||
X502_FpgaRegWrite(g_hnd, E502_REGS_IOHARD_GO_SYNC_IO, 1);
|
||||
#endif
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int block;
|
||||
int32_t stop_err = 0;
|
||||
|
||||
printf("Сбор данных запущен. Для останова нажмите %s\n",
|
||||
#ifdef _WIN32
|
||||
"любую клавишу"
|
||||
#else
|
||||
"CTRL+C"
|
||||
#endif
|
||||
);
|
||||
fflush(stdout);
|
||||
|
||||
struct timespec start_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
||||
int32_t g_rcv_cnt = 0;
|
||||
int cntr = 0;
|
||||
int rcv_cntr = 1;//0x02000000;
|
||||
|
||||
//threadFunc(NULL);
|
||||
//return;
|
||||
|
||||
|
||||
#if !defined(ENABLE_ADC)
|
||||
if(1) {
|
||||
while(!f_out) {}
|
||||
} else
|
||||
#endif
|
||||
for (block = 0; (err == X502_ERR_OK) && !f_out; block++) {
|
||||
int32_t rcv_size;
|
||||
uint32_t adc_size, din_size;
|
||||
|
||||
/* массив для приема необработанных данных */
|
||||
static uint32_t rcv_buf[READ_BLOCK_SIZE];
|
||||
static uint32_t snd_buf[READ_BLOCK_SIZE];
|
||||
static double adc_data[READ_BLOCK_SIZE];
|
||||
static uint32_t din_data[READ_BLOCK_SIZE];
|
||||
|
||||
#if 0
|
||||
int i;
|
||||
for(i=0;i<READ_BLOCK_SIZE;i++) {
|
||||
snd_buf[i] = i + cntr;
|
||||
snd_buf[i] &= ~0xff000000;
|
||||
snd_buf[i] |= 0x02000000;
|
||||
}
|
||||
|
||||
int32_t snd_cnt = 0;
|
||||
snd_cnt = X502_Send(hnd, snd_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
cntr += snd_cnt;
|
||||
g_snd_cnt += snd_cnt;
|
||||
|
||||
#endif
|
||||
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
#if 0
|
||||
if (cur_time.tv_sec - start_time.tv_sec != 0) {
|
||||
printf("snd_cnt=%d speed=%d wrds/sec\n", snd_cnt, (g_snd_cnt) / (cur_time.tv_sec - start_time.tv_sec));
|
||||
printf("g_snd_cnt=%d secs=%d\n", g_snd_cnt, cur_time.tv_sec - start_time.tv_sec);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
if (g_snd_cnt > READ_BLOCK_SIZE * 10) {
|
||||
g_snd_cnt=0;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
}
|
||||
#endif
|
||||
//continue;
|
||||
|
||||
/* принимаем данные (по таймауту) */
|
||||
rcv_size = X502_Recv(g_hnd, rcv_buf, READ_BLOCK_SIZE, READ_TIMEOUT);
|
||||
//printf("rcv_size=%d\n", rcv_size);
|
||||
g_rcv_cnt += rcv_size;
|
||||
int error = 0;
|
||||
|
||||
if(1) {
|
||||
uint32_t val;
|
||||
static int dout_once = 1;
|
||||
static int once = 1;
|
||||
|
||||
if(dout_once) {
|
||||
dout_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, E502_REGS_ARM_DAC_ERR, &val);
|
||||
if (val & DIGOUT_ERROR) {
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
X502_FpgaRegRead(g_hnd, 0x104, &err_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x105, &exp_val);
|
||||
printf("dout error: %x %x expected\n", err_val, exp_val);
|
||||
}
|
||||
}
|
||||
if(once) {
|
||||
X502_FpgaRegRead(g_hnd, E502_REGS_ARM_DAC_ERR, &val);
|
||||
if (val & DAC1_ERROR) {
|
||||
once = 0;
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
X502_FpgaRegRead(g_hnd, 0x106, &err_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x107, &exp_val);
|
||||
printf("dac1 error: %x %x expected\n", err_val, exp_val);
|
||||
}
|
||||
if (val & DAC2_ERROR) {
|
||||
once = 0;
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
X502_FpgaRegRead(g_hnd, 0x108, &err_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x109, &exp_val);
|
||||
printf("dac2 error: %x %x expected\n", err_val, exp_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(0){
|
||||
static int dout_once = 1;
|
||||
static int dac1_once = 1;
|
||||
static int dac2_once = 1;
|
||||
uint32_t err_val;
|
||||
uint32_t exp_val;
|
||||
uint32_t next_val;
|
||||
|
||||
if(dout_once) {
|
||||
X502_FpgaRegRead(g_hnd, 0x120, &err_val);
|
||||
if (err_val) {
|
||||
dout_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, 0x121, &exp_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x122, &next_val);
|
||||
printf("GD32 dout error: %x %x expected\n", err_val & 0xffffff, exp_val & 0xffffff);
|
||||
}
|
||||
}
|
||||
if (dac1_once) {
|
||||
X502_FpgaRegRead(g_hnd, 0x123, &err_val);
|
||||
if (err_val) {
|
||||
dac1_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, 0x124, &exp_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x125, &next_val);
|
||||
printf("GD32 dac1 error: %x %x expected\n", err_val & 0xffff, exp_val & 0xffff);
|
||||
}
|
||||
}
|
||||
if (dac2_once) {
|
||||
X502_FpgaRegRead(g_hnd, 0x126, &err_val);
|
||||
if (err_val) {
|
||||
dac2_once = 0;
|
||||
X502_FpgaRegRead(g_hnd, 0x127, &exp_val);
|
||||
X502_FpgaRegRead(g_hnd, 0x128, &next_val);
|
||||
printf("GD32 dac2 error: %x %x expected\n", err_val & 0xffff, exp_val & 0xffff);
|
||||
}
|
||||
}
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
#if 1
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5) {
|
||||
printf("rcv speed=%lld wrds/sec\n", (g_rcv_cnt) / (cur_time.tv_sec - start_time.tv_sec));
|
||||
start_time.tv_sec = cur_time.tv_sec;
|
||||
g_rcv_cnt = 0;
|
||||
}
|
||||
#else
|
||||
if (cur_time.tv_sec - start_time.tv_sec >= 5) {
|
||||
printf("rcv speed=%lld wrds/sec cntr=%x\n", (g_rcv_cnt) / (cur_time.tv_sec - start_time.tv_sec), rcv_cntr);
|
||||
start_time.tv_sec = cur_time.tv_sec;
|
||||
g_rcv_cnt = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rcv_size; i++) {
|
||||
|
||||
#if 1
|
||||
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(rcv_buf[i]);
|
||||
/* проверяем - это данные от АЦП или цифровых входов */
|
||||
if (type != STREAM_IN_WRD_DIN) {
|
||||
continue;
|
||||
}
|
||||
if ((rcv_buf[i] & 0xFFFF) != (rcv_cntr & 0xFFFF))
|
||||
{
|
||||
printf("%x[%i] %x expected\n", rcv_buf[i], i, rcv_cntr);
|
||||
rcv_cntr = rcv_buf[i] & 0xFFFF;
|
||||
error = 1;
|
||||
}
|
||||
rcv_cntr++;
|
||||
#else
|
||||
|
||||
// проверка для DCI_TEST_MODE
|
||||
if (rcv_buf[i] != rcv_cntr) {
|
||||
printf("%x[%i] %x expected\n", rcv_buf[i], i, rcv_cntr);
|
||||
rcv_cntr = rcv_buf[i];
|
||||
error = 1;
|
||||
}
|
||||
rcv_cntr++;
|
||||
//rcv_cntr &= ~0xff000000;
|
||||
//rcv_cntr |= 0x02000000;
|
||||
/*if (rcv_cntr >= 0x02000400) {
|
||||
rcv_cntr = 0x02000000;
|
||||
}*/
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
continue;
|
||||
|
||||
if(error) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
/* результат меньше нуля означает ошибку */
|
||||
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(g_hnd, &first_lch);
|
||||
|
||||
adc_size = sizeof(adc_data)/sizeof(adc_data[0]);
|
||||
din_size = sizeof(din_data)/sizeof(din_data[0]);
|
||||
|
||||
/* обрабатываем принятые данные, распределяя их на данные АЦП и цифровых входов */
|
||||
err = X502_ProcessData(g_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("Блок %3d. Обработано данных АЦП =%d, цифровых входов =%d\n",
|
||||
block, adc_size, din_size);
|
||||
/* если приняли цифровые данные - выводим первый отсчет */
|
||||
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", lch, adc_data[pos]);
|
||||
} else {
|
||||
printf(" lch[%d]= ---- \n", lch);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
/* проверка нажатия клавиши для выхода */
|
||||
if (err == X502_ERR_OK) {
|
||||
if (_kbhit())
|
||||
f_out = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ENABLE_DOUT) || defined(ENABLE_DAC1) || defined(ENABLE_DAC2)
|
||||
|
||||
#ifdef _WIN32
|
||||
//TODO: pthread_join
|
||||
#else
|
||||
pthread_join(threadId, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* останавливаем поток сбора данных (независимо от того, была ли ошибка) */
|
||||
//stop_err = X502_StreamsStop(g_hnd);
|
||||
if (stop_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова сбора данных: %s\n", X502_GetErrorString(err));
|
||||
if (err == X502_ERR_OK)
|
||||
err = stop_err;
|
||||
} else {
|
||||
printf("Сбор данных остановлен успешно\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(g_hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(g_hnd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
# Данный файл описывает проект для системы сборки cmake.
|
||||
# С помощью cmake из этого файла можно получить нужный make-файл
|
||||
# для нужно родной системы сборки или проект для нужной среды.
|
||||
#
|
||||
# Для этого, из созданной директории для сборки нужно вызвать:
|
||||
#
|
||||
# cmake -DX502API_INCLUDE_DIR=<путь к заголовочным файлам x502api> -DX502API_LIBRARIES_DIR=<путь к файлу линкера x502api (.lib, .a или .so)> -G <имя генератора проекта> <путь к исходникам (данному файлу)>
|
||||
#
|
||||
# списко поддерживаемых генераторов можно получить вызвав cmake без аргументов
|
||||
#
|
||||
# Если заголовки и библиотека/файл линкера лежат в стандартных директориях,
|
||||
# то -DX502API_INCLUDE_DIR и -DX502API_LIBRARIES_DIR можно соответственно не указывать
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
set(PROJECT x502_stream_read)
|
||||
|
||||
project(${PROJECT} C)
|
||||
|
||||
set(SOURCES main.c)
|
||||
set(HEADERS )
|
||||
|
||||
include_directories(${X502API_INCLUDE_DIR} ../common)
|
||||
link_directories(${X502API_LIBRARIES_DIR})
|
||||
|
||||
add_executable(${PROJECT} ${HEADERS} ${SOURCES})
|
||||
install(TARGETS ${PROJECT} DESTINATION .)
|
||||
|
||||
target_link_libraries(${PROJECT} x502api l502api e502api)
|
||||
501
lib/x502api-1.1.34/examples/c/x502_stream_read/main.c
Normal file
501
lib/x502api-1.1.34/examples/c/x502_stream_read/main.c
Normal file
@ -0,0 +1,501 @@
|
||||
/* Данный пример представляет из себя консольную программу на языке 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 "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>
|
||||
|
||||
/* количество используемых логических каналов */
|
||||
#define ADC_LCH_CNT 3
|
||||
|
||||
/* частота сбора АЦП в Гц*/
|
||||
#define ADC_FREQ 500000
|
||||
/* частота кадров (на логический канал). При 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
|
||||
|
||||
|
||||
/* номера используемых физических каналов */
|
||||
static uint32_t f_channels[ADC_LCH_CNT] = {0,4,6};
|
||||
/* режимы измерения для каналов */
|
||||
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF, X502_LCH_MODE_DIFF};
|
||||
/* диапазоны измерения для каналов */
|
||||
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_10, X502_ADC_RANGE_10, X502_ADC_RANGE_10};
|
||||
|
||||
|
||||
|
||||
/* признак необходимости завершить сбор данных */
|
||||
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-адресов */
|
||||
for (i=0; i < ip_cnt; i++) {
|
||||
if (E502_MakeDevRecordByIpAddr2(&rec_list[fnd_devcnt], ip_dev_list[i].ip_addr, 0, TCP_CONNECTION_TOUT, ip_dev_list[i].devname) == X502_ERR_OK) {
|
||||
fnd_devcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* записываем настройки в модуль */
|
||||
if (err == X502_ERR_OK)
|
||||
err = X502_Configure(hnd, 0);
|
||||
|
||||
/* разрешаем синхронные потоки */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsEnable(hnd, X502_STREAM_ADC | X502_STREAM_DIN);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/********** Получение списка устройств и выбор, с каким будем работать ******************/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
/* настраиваем параметры модуля */
|
||||
err = f_setup_params(hnd);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка настройки модуля: %s!", X502_GetErrorString(err));
|
||||
}
|
||||
|
||||
|
||||
/* запуск синхронного ввода-вывода */
|
||||
if (err == X502_ERR_OK) {
|
||||
err = X502_StreamsStart(hnd);
|
||||
if (err != X502_ERR_OK)
|
||||
fprintf(stderr, "Ошибка запуска сбора данных: %s!\n", X502_GetErrorString(err));
|
||||
}
|
||||
|
||||
|
||||
if (err == X502_ERR_OK) {
|
||||
int block;
|
||||
int32_t stop_err;
|
||||
|
||||
printf("Сбор данных запущен. Для останова нажмите %s\n",
|
||||
#ifdef _WIN32
|
||||
"любую клавишу"
|
||||
#else
|
||||
"CTRL+C"
|
||||
#endif
|
||||
);
|
||||
fflush(stdout);
|
||||
|
||||
|
||||
|
||||
for (block = 0; (err == X502_ERR_OK) && !f_out; block++) {
|
||||
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);
|
||||
/* результат меньше нуля означает ошибку */
|
||||
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("Блок %3d. Обработано данных АЦП = %d, цифровых входов = %d\n",
|
||||
block, adc_size, din_size);
|
||||
/* если приняли цифровые данные - выводим первый отсчет */
|
||||
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", lch, adc_data[pos]);
|
||||
} else {
|
||||
printf(" lch[%d]= ---- \n", lch);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#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
|
||||
}
|
||||
|
||||
/* останавливаем поток сбора данных (независимо от того, была ли ошибка) */
|
||||
stop_err = X502_StreamsStop(hnd);
|
||||
if (stop_err != X502_ERR_OK) {
|
||||
fprintf(stderr, "Ошибка останова сбора данных: %s\n", X502_GetErrorString(err));
|
||||
if (err == X502_ERR_OK)
|
||||
err = stop_err;
|
||||
} else {
|
||||
printf("Сбор данных остановлен успешно\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* закрываем связь с модулем */
|
||||
X502_Close(hnd);
|
||||
/* освобождаем описатель */
|
||||
X502_Free(hnd);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
48
lib/x502api-1.1.34/examples/c/x502_stream_read/makefile
Normal file
48
lib/x502api-1.1.34/examples/c/x502_stream_read/makefile
Normal file
@ -0,0 +1,48 @@
|
||||
# makefile для сборки примера с помощью компиляторов mingw (под Windows)
|
||||
# или GCC (под Linux). Необходимо определить 3 переменные:
|
||||
#
|
||||
# CC - имя команды для вызова компилятора
|
||||
# X502API_LIBRARIES_DIR - путь к файлм .a или .so библиотек l502api, e502api, x502api (если не стандартный)
|
||||
# X502API_INCLUDE_DIR - путь к заголовочным файлам l502api.h, e502api.h, x502api.h
|
||||
#
|
||||
# Ниже приведено несколько примеров в закоментированном виде
|
||||
|
||||
#--- Linux с заголовками и библиотекой в стандартных директориях: компилятор GCC
|
||||
#CC = gcc
|
||||
|
||||
#--- Вариант запуска из MSYS со стандартным 32-битным mingw
|
||||
#CC = gcc
|
||||
#X502API_LIBRARIES_DIR = "/c/Program Files/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/c/Program Files/L-Card/lpcie/include"
|
||||
|
||||
|
||||
#--- 64-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = x86_64-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw64"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw w64, идущий вместе с cygwin --------
|
||||
#CC = i686-w64-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
#--- 32-битный вариант mingw, идущий вместе с cygwin --------
|
||||
#CC = i686-pc-mingw32-gcc
|
||||
#X502API_LIBRARIES_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/lib/mingw"
|
||||
#X502API_INCLUDE_DIR = "/cygdrive/c/Program Files (x86)/L-Card/lpcie/include"
|
||||
|
||||
|
||||
FLAGS =
|
||||
|
||||
ifdef X502API_LIBRARIES_DIR
|
||||
FLAGS += -L $(X502API_LIBRARIES_DIR)
|
||||
endif
|
||||
|
||||
ifdef X502API_INCLUDE_DIR
|
||||
FLAGS += -I $(X502API_INCLUDE_DIR)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
all:
|
||||
$(CC) main.c $(FLAGS) -ll502api -le502api -lx502api -o x502_stream_read
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x502_stream_read", "x502_stream_read.vcproj", "{D9460CE1-B571-4A69-A4C1-0676BF57EB04}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D9460CE1-B571-4A69-A4C1-0676BF57EB04}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="x502_stream_read"
|
||||
ProjectGUID="{D9460CE1-B571-4A69-A4C1-0676BF57EB04}"
|
||||
RootNamespace="x502_stream_read"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="c:\Program Files (x86)\L-Card\lpcie\include\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="x502api.lib l502api.lib e502api.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="c:\Program Files (x86)\L-Card\lpcie\lib\msvc"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="c:\Program Files (x86)\L-Card\lpcie\include\"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="x502api.lib l502api.lib e502api.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="c:\Program Files (x86)\L-Card\lpcie\lib\msvc"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\main.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
Reference in New Issue
Block a user