manually merged with ARM version

This commit is contained in:
2025-11-13 17:43:55 +03:00
parent f978759ae0
commit 04015fb4cb
463 changed files with 119514 additions and 45 deletions

View 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)

View 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, &eth_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;
}

View 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__

View 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));
}

View 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__

View File

@ -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)

View 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;
}

View 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;
}

View 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));
}

View 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__

View 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 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)

View 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
а 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;
}

View 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

View File

@ -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)

View 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;
}

View File

@ -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)

View File

@ -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

View File

@ -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>

View 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;
}

View 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

View File

@ -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)

View 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;
}

View 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)

View 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;
}

View 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)

View 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
а 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;
}

View 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

View File

@ -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

View File

@ -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>

View File

@ -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)

View 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;
}

View File

@ -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)

View 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;
}

View File

@ -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)

View 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;
}

View 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

View File

@ -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

View File

@ -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>