#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#define DATEFMT "YYYY.MM.DD//hh:mm:ss//MMM"
#include "l502api.h"
#include "e502api.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <errno.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 1
/* частота сбора АЦП в Гц*/
#define ADC_FREQ 50000
/* частота кадров (на логический канал). При ADC_FREQ/ADC_LCH_CNT - межкадровой задержки нет */
#define ADC_FRAME_FREQ (ADC_FREQ/ADC_LCH_CNT)
/* частота синхронного ввода в Гц*/
#define DIN_FREQ 1000000
#define TCP_CONNECTION_TOUT 5000
/* сколько отсчетов считываем за блок */
#define READ_BLOCK_SIZE 5000
/* таймаут на прием блока (мс) */
#define READ_TIMEOUT 100
/* номера используемых физических каналов */
static uint32_t f_channels[ADC_LCH_CNT] = {17};
/* режимы измерения для каналов */
static uint32_t f_ch_modes[ADC_LCH_CNT] = {X502_LCH_MODE_COMM};
/* диапазоны измерения для каналов */
static uint32_t f_ch_ranges[ADC_LCH_CNT] = {X502_ADC_RANGE_10};
/* признак небходимости завершить сбор данных */
static int f_out = 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) {
t_x502_hnd hnd = NULL;
uint32_t fnd_devcnt,i, dev_ind;
t_x502_devrec *devrec_list = NULL;
uint32_t *ip_addr_list = NULL;
uint32_t ip_cnt = 0;
/* если есть аргументы командной строки, то предполагаем, что это могут быть
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], "Oshibka vy`deleniya pamyati!%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("Ne najdeno ni odnogo modulya\n");
} else {
/* выводим информацию по списку модулей */
printf("Dostupny` sleduyushhie moduli:\n");
for (i=0; i < fnd_devcnt; i++) {
printf("Modul` # %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("Ser. nomer: %s\n", devrec_list[i].serial);
} else {
printf("Adres: %s\n", devrec_list[i].location);
}
}
/* выбираем нужный по введенному номеру модуля по порядку с клавиатуры */
printf("Vvedite nomer modulya, s kotory`m khotite rabotat` (ot 0 do %d)\n", fnd_devcnt-1);
fflush(stdout);
scanf("%d", &dev_ind);
if (dev_ind >= fnd_devcnt) {
printf("Neverno ukazan nomer modulya...\n");
} else {
/* если ввели номер правильно - создаем описатель */
hnd = X502_Create();
if (hnd==NULL) {
fprintf(stderr, "Oshibka sozdaniya opisatelya modulya!");
} else {
/* устанавливаем связь с модулем по записи */
int32_t err = X502_OpenByDevRecord(hnd, &devrec_list[dev_ind]);
if (err != X502_ERR_OK) {
fprintf(stderr, "Oshibka ustanovleniya svyazi s modulem %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("Ustanovleny` chastoty`:\n Chastota sbora ACzP = %0.0f\n"
" Chastota na log. kanal = %0.0f\n Chastota czifrovogo vvoda = %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);
}
return err;
}
int main(int argc, char** argv) {
int32_t err = X502_ERR_OK;
uint32_t ver;
t_x502_hnd hnd = NULL;
static char stroka;
#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("Versiya biblioteki %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, "Oshibka polucheniya serijnogo informaczii o module %s!", X502_GetErrorString(err));
} else {
/* выводим полученную информацию */
printf("Ustanovlena svyaz` so sleduyushhim modulem:\n");
printf(" Serijny`j nomer : %s\n", info.serial);
printf(" Nalichie CzAP : %s\n", info.devflags & X502_DEVFLAGS_DAC_PRESENT ? "Да" : "Нет");
printf(" Nalichie BlackFin : %s\n", info.devflags & X502_DEVFLAGS_BF_PRESENT ? "Да" : "Нет");
printf(" Nalichie gal`vanorazvyazki: %s\n", info.devflags & X502_DEVFLAGS_GAL_PRESENT ? "Да" : "Нет");
printf(" Industrial`noe isp. : %s\n", info.devflags & X502_DEVFLAGS_INDUSTRIAL ? "Да" : "Нет");
printf(" Nalichie interf. PCI/PCIe: %s\n", info.devflags & X502_DEVFLAGS_IFACE_SUPPORT_PCI ? "Да" : "Нет");
printf(" Nalichie interf. USB : %s\n", info.devflags & X502_DEVFLAGS_IFACE_SUPPORT_USB ? "Да" : "Нет");
printf(" Nalichie interf. Ethernet: %s\n", info.devflags & X502_DEVFLAGS_IFACE_SUPPORT_ETH ? "Да" : "Нет");
printf(" Versiya PLIS : %d.%d\n", (info.fpga_ver >> 8) & 0xFF, info.fpga_ver & 0xFF);
printf(" Versiya PLDA : %d\n", info.plda_ver);
if (info.mcu_firmware_ver != 0) {
printf(" Versiya proshivki 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, "Oshibka nastrojki modulya: %s!", X502_GetErrorString(err));
}
/* запуск синхронного ввода-вывода */
if (err == X502_ERR_OK) {
err = X502_StreamsStart(hnd);
if (err != X502_ERR_OK)
fprintf(stderr, "Oshibka zapuska sbora danny`kh: %s!\n", X502_GetErrorString(err));
}
if (err == X502_ERR_OK) {
int block;
int32_t stop_err;
printf("Sbor danny`kh zapushhen. Dlya ostanova nazhmite %s\n",
#ifdef _WIN32
"lyubuyu klavishu"
#else
"CTRL+C"
#endif
);
fflush(stdout);
for (block = 0; (err == X502_ERR_OK) && !f_out && block!=90; 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, "Oshibka priema danny`kh: %s\n", X502_GetErrorString(err));
} else if (rcv_size > 0) {
uint32_t first_lch;
/* получаем номер логического канала, которому соответствует первый отсчет АЦП в массиве */
X502_GetNextExpectedLchNum(hnd, &first_lch);
adc_size = 1000;
din_size = 0;
/* обрабатываем принятые данные, распределяя их на данные АЦП и цифровых входов */
err = X502_ProcessData(hnd, rcv_buf, rcv_size, X502_PROC_FLAGS_VOLT,
adc_data, &adc_size, din_data, &din_size);
{
FILE *mf;
int posix_code;
struct timeval tv;
struct timezone tz;
struct tm tm;
char yu="/media/pi/Elements/";
gettimeofday(&tv, &tz); // вместо tz можно 0, если сами не собираетесь с TZ играться
// gmtime_r(&tv.tv_sec, &tm); // UTC
localtime_r(&tv.tv_sec, &tm);
char now[sizeof(DATEFMT) + 16] = "strftime() error";
size_t l = strftime(now, sizeof(now), "/media/pi/Elements/%g_%m_%d_%H-%M-%S-", &tm );
sprintf(now + l, "%03d.dat", (int)tv.tv_usec / 1000); // я думаю, что в таких задачах округление излишне
//const char filename_format[] = "/home/pi/Desktop/testmat.bin";
//char filename_buffer[256];
//snprintf(filename_buffer, sizeof(filename_buffer), "/home/pi/Desktop/%d:%d:%d,%03.3d",now[0],2,3,4);
if (block==0){
mf=fopen(now,"a+b");
}
if (!mf){
printf("oshibka posix %d (%s)", errno, strerror(errno));
goto file_done;
}
if (fwrite(adc_data, sizeof(uint32_t), adc_size,mf)!=adc_size)
printf("oshibka posix %d (%s)", errno, strerror(errno));
if (block==89){
fclose (mf);
}
}
file_done:
if (err != X502_ERR_OK) {
fprintf(stderr, "Oshibka obrabotki danny`kh: %s\n", X502_GetErrorString(err), err);
} else {
uint32_t lch;
printf("Blok %3d. Obrabotano danny`kh ACzP =%d, czifrovy`kh vkhodov =%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 (block==89){
block=-1;
}
}
/* останавливаем поток сбора данных (независимо от того, была ли ошибка) */
stop_err = X502_StreamsStop(hnd);
if (stop_err != X502_ERR_OK) {
fprintf(stderr, "Oshibka ostanova sbora danny`kh: %s\n", X502_GetErrorString(err));
if (err == X502_ERR_OK)
err = stop_err;
} else {
printf("Sbor danny`kh ostanovlen uspeshno\n");
}
}
/* закрываем связь с модулем */
X502_Close(hnd);
/* освобождаем описатель */
X502_Free(hnd);
}
return err;
}