moved libs to the lib directory

This commit is contained in:
2025-11-13 18:40:06 +03:00
parent 4d1f7fdbe9
commit b80ad585da
634 changed files with 3 additions and 2 deletions

31
lib/x502/fast_crc_cfg.h Normal file
View File

@ -0,0 +1,31 @@
/*================================================================================================*
* Конфигурация библиотеки FAST_CRC
*================================================================================================*/
#ifndef FAST_CRC_CFG_H_
#define FAST_CRC_CFG_H_
#include "lcard_pstdint.h"
/*================================================================================================*/
/* Типы */
#define FASTCRC_U8_TYPE uint8_t
#define FASTCRC_U16_TYPE uint16_t
#define FASTCRC_U32_TYPE uint32_t
#define FASTCRC_SIZE_TYPE size_t
/* Начальные значения CRC */
#define CRC16_START_VAL 0
#define CRC32_START_VAL 0
/*================================================================================================*/
/*================================================================================================*/
/* Разрешение компиляции отдельных функций */
#define FASTCRC_CRC16_ADD8 1 /* добавление в CRC16 байта */
#define FASTCRC_CRC16_ADD16 1 /* добавление в CRC16 16-битного слова */
#define FASTCRC_CRC16_BLOCK8 1 /* Вычисление CRC16 блока байтов */
#define FASTCRC_CRC16_BLOCK16 1 /* Вычисление CRC16 блока 16-битных слов */
#define FASTCRC_CRC32_BLOCK8 1 /* Вычисление CRC32 блока байтов */
/*================================================================================================*/
#endif /* FAST_CRC_CFG_H_ */

167
lib/x502/l502_bf_cmd_defs.h Normal file
View File

@ -0,0 +1,167 @@
/*********************************************************************//**
@addtogroup cmd_process
@{
@file l502_bf_cmd_defs.h Файл содержит определения,
которые используются для передачи команд от ПК в DSP
(определения команд, их параметров, результатов выполнения)
@date 28.03.2012
@author Borisov Alexey <borisov@lcard.ru>
*************************************************************************/
#ifndef L502_BF_CMD_DEFS_H_
#define L502_BF_CMD_DEFS_H_
/** Максимальный размер данных, передавемых с командой в 32-битных словах */
#define L502_BF_CMD_DATA_SIZE_MAX (1024)
/** Статус команд управления сигнальным процессором */
typedef enum {
L502_BF_CMD_STATUS_IDLE = 0x0, /**< Начальное состояние (команда вообщен не выполнялась) */
L502_BF_CMD_STATUS_REQ = 0x5A01, /**< Передан запрос на обработку команды от ПК*/
L502_BF_CMD_STATUS_PROGRESS = 0x5A02, /**< Сигнальный процессор начал обработку команды */
L502_BF_CMD_STATUS_DONE = 0x5A03 /**< Команда выполнена. Результат выполнения в поле ret_code */
} t_l502_bf_cmd_status;
/** Коды команд управления сигнальным процессором */
typedef enum {
L502_BF_CMD_CODE_TEST = 0x01, /**< Запуск теста (параметр определяет тип теста) */
L502_BF_CMD_CODE_SET_PARAM = 0x02, /**< Установить параметр (код параметра в поле param) */
L502_BF_CMD_CODE_GET_PARAM = 0x03, /**< Прочитать текущее значение параметра */
L502_BF_CMD_CODE_CONFIGURE = 0x04, /**< Сконфигурировать модуль в соответствии с ранее установленными параметрами */
L502_BF_CMD_CODE_STREAM_EN = 0x05, /**< Разрешение потоков ввода/вывода */
L502_BF_CMD_CODE_STREAM_DIS = 0x06, /**< Запрещение потоков ввода/вывода */
L502_BF_CMD_CODE_STREAM_START = 0x07, /**< Запуск потоков ввода/вывода */
L502_BF_CMD_CODE_STREAM_STOP = 0x08, /**< Останов потоков ввода/вывода */
L502_BF_CMD_CODE_PRELOAD = 0x09, /**< Предзагрузка данных на ЦАП */
L502_BF_CMD_CODE_ASYNC_OUT = 0x10, /**< Асинхронный вывод (куда - зависит от параметра) */
L502_BF_CMD_CODE_ASYNC_DIG_IN = 0x11, /**< Асинхронный ввод с цифровых линий */
L502_BF_CMD_CODE_ADC_GET_FRAME = 0x12, /**< Асинхронный ввод карда АЦП */
L502_BF_CMD_CODE_FPGA_REG_WR = 0x13, /**< Запись в регистр FPGA (param --- адрес регистра, data0 --- значение) */
L502_BF_CMD_CODE_FPGA_REG_RD = 0x14, /**< Чтение из регистра FPGA (param --- адрес регистра, ответ: resp0 --- значение) */
L502_BF_CMD_CODE_GET_OUT_STATUS= 0x15, /**< Получение флагов статуса вывода */
} t_l502_bf_cmd_code;
#define L502_BF_CMD_CODE_USER 0x8000U /**< Код, с которого начинаются пользовательские команды */
/** @brief Варианты тестов
Коды тестов, передающиеся в параметре команды #L502_BF_CMD_CODE_TEST */
typedef enum {
L502_BF_CMD_TEST_STOP = 0x00, /**< Останов выполняемого теста */
L502_BF_CMD_TEST_GET_RESULT = 0x01, /**< Получение результата теста */
L502_BF_CMD_TEST_ECHO = 0x10, /**< Тест эхо - возвращает те же данные что передавались */
L502_BF_CMD_TEST_SPORT = 0x11, /**< Тест интерфейса SPORT в кольцевом режиме */
L502_BF_CMD_TEST_SDRAM = 0x12, /**< Тест SDRAM памяти */
L502_BF_CMD_TEST_SPI = 0x13 /**< Тест интерфейса SPI */
} t_l502_bf_test_code;
/** @brief Устанавливаемые параметры
Коды пареметров, устанавливаемых командой #L502_BF_CMD_CODE_SET_PARAM или
получаемых с помщью команды #L502_BF_CMD_CODE_GET_PARAM */
typedef enum {
L502_BF_PARAM_FIRM_VERSION = 0x00, /**< Версия прошивки - 4 байта */
L502_BF_PARAM_STREAM_MODE = 0x01, /**< Режим работы (запущен поток или нет) */
L502_BF_PARAM_ENABLED_STREAMS = 0x02, /**< Какие потоки разрешены */
L502_BF_PARAM_MODULE_INFO = 0x03, /**< Запись информации о модуле */
L502_BF_PARAM_IN_BUF_SIZE = 0x10, /**< Размер буфера на преием */
L502_BF_PARAM_CYCLE_BUF_SIZE = 0x11, /**< Размер буфера для записи циклического сигнала */
L502_BF_PARAM_LCH_CNT = 0x20, /**< Количество логических каналов в таблице */
L502_BF_PARAM_LCH = 0x21, /**< Параметры логического канала */
L502_BF_PARAM_ADC_FREQ_DIV = 0x22, /**< Делитель частоты АЦП */
L502_BF_PARAM_REF_FREQ_SRC = 0x23, /**< Выбор опорной частоты */
L502_BF_PARAM_ADC_FRAME_DELAY = 0x24, /**< Значение межкадровой задержки */
L502_BF_PARAM_SYNC_MODE = 0x25, /**< Режим синхронизации */
L502_BF_PARAM_SYNC_START_MODE = 0x26, /**< Условие запуска синхронных потоков сбора данных */
L502_BF_PARAM_ADC_COEF = 0x27, /**< Установка коэффициентов для заданного диапазона АЦП */
L502_BF_PARAM_DAC_COEF = 0x28, /**< Установка коэффициентов для заданного канала ЦАП */
L502_BF_PARAM_DIN_FREQ_DIV = 0x30, /**< Делитель частоты цифрового ввода */
L502_BF_PARAM_DAC_FREQ_DIV = 0x31, /**< Делитель частоты вывода на ЦАП */
L502_BF_PARAM_IN_STEP_SIZE = 0x32, /**< Шаг для обработки входных данных */
L502_BF_PARAM_IN_STREAM_MODE = 0x100 /**< Режим работы потока на ввод */
} t_l502_bf_params;
/** @brief Тип асинхронного вывода
Код, задающий в параметре команды команды #L502_BF_CMD_CODE_ASYNC_OUT,
куда должно выводится передаваемое значение */
typedef enum {
L502_BF_CMD_ASYNC_TYPE_DOUT = 0x0, /**< Вывод на цифровые линии */
L502_BF_CMD_ASYNC_TYPE_DAC1 = 0x1, /**< Вывод на первый канал ЦАП */
L502_BF_CMD_ASYNC_TYPE_DAC2 = 0x2 /**< Вывод на второй канал ЦАП */
} t_l502_bf_cmd_async_type;
/** Коды завершения команд */
typedef enum {
L502_BF_ERR_SUCCESS = 0, /**< Команда выполнена успешно */
L502_BF_ERR_FIRST_CODE = -512, /**< Код ошибки, с которого начинаются отсальные коды.
Используется, чтобы разделить на верхнем уровне ошибки библиотеки и
возвращенные сигнальным процессором */
L502_BF_ERR_UNSUP_CMD = -512, /**< Неизвестный код команды */
L502_BF_ERR_CMD_OVERRUN = -513, /**< Пришла команда до того, как была завершена предыдущая */
L502_BF_ERR_INVALID_CMD_PARAMS = -514, /**< Неверное значение параметра команды */
L502_BF_ERR_INSUF_CMD_DATA = -515, /**< Недостаточное кол-во данных передано с командой */
L502_BF_ERR_STREAM_RUNNING = -516, /**< Команда не допустима при запущеном сборе, а сбор запущен */
L502_BF_ERR_STREAM_STOPPED = -517, /**< Команда допустима только при запущеном сборе, а сбор остановлен */
L502_BF_ERR_NO_TEST_IN_PROGR = -518, /**< Сейчас не выполняется никакого теста */
L502_BF_ERR_TEST_VALUE = -519 /**< Считано неверное значение при выполнении теста */
} t_l502_bf_err_code;
/** Режим работы сигнального процессора */
typedef enum {
L502_BF_MODE_IDLE = 0, /**< Ждущий режим, поток не запущен */
L502_BF_MODE_STREAM = 1, /**< Запущены потоки ввода-вывода */
L502_BF_MODE_TEST = 2 /**< Тестовый режим */
} t_l502_bf_mode;
/** Возможности, поддерживаемые прошивкой blackfin */
typedef enum {
L502_BF_FEATURE_FPGA_REG_ACCESS = 0x1, /**< Признак, что реализованы команды
прямого доступа к регистрам FPGA */
L502_BF_FEATURE_OUT_STATUS_FLAGS = 0x2 /**< Признак, что реализована команда
#L502_BF_CMD_CODE_GET_OUT_STATUS */
} t_l502_bf_features;
/** @brief Параметры команды
Структура описывает расположение полей в области памяти BlackFin, используемой
для передачи команд между персональным компьютером и сигнальным процессором */
typedef struct {
uint16_t code; /**< Код команды из #t_l502_bf_cmd_code */
uint16_t status; /**< Статус выполнения - в обработчике не изменяется */
uint32_t param; /**< Параметр команды */
int32_t result; /**< Код результата выполнения команды */
uint32_t data_size; /**< Количество данных, переданных с командой или возвращенных с ответом в 32-битных словах */
uint32_t data[L502_BF_CMD_DATA_SIZE_MAX]; /**< Данные, передаваемые с командой и/или в качестве результата */
} t_l502_bf_cmd;
/** @brief Результат выполнения теста
Структура описывает параметры выполняемого теста, возвращаемые в качестве
данных на команду #L502_BF_CMD_CODE_TEST с параметром
#L502_BF_CMD_TEST_GET_RESULT */
typedef struct {
uint32_t test; /**< Номер выполняемого теста */
uint32_t run; /**< Признак, запущен ли сейчас тест */
uint32_t stage; /**< Этап выполнения теста */
uint32_t cntr; /**< Счетчик - сколько раз прошел тест */
int32_t err; /**< Код ошибки выполнения теста */
uint32_t last_addr; /**< Последний используемый адрес */
uint32_t last_wr; /**< Последнее записанное значение */
uint32_t last_rd; /**< Последнее считанное значение */
} t_l502_bf_test_res;
/** @} */
#endif

270
lib/x502/lboot_req.h Normal file
View File

@ -0,0 +1,270 @@
/***************************************************************************//**
@file lcspec.h
Файл содержит константы и типы, которые использует как загрузчик lboot,
так и приложение:
- константы и типы для запроса на перепрошивку со стороны application
- константы и типы для определения информации о прошивке, которая хранится
внутри прошивки и проверяется bootloader'ом
!!Файл должен быть один (или одинаковый) для обоих проектов!!
@date 16.11.2010
@author: Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LBOOT_REQ_H_
#define LBOOT_REQ_H_
/** адрес, по которому должен быть сформирован запрос на перепрошивку */
#define LBOOT_REQ_ADDR 0x10000000
/** Адрес, начиная с кторого хранится информация о загрузчике */
#define LBOOT_INFO_ADDR 0x200
/******************* размеры полей ***************************************/
#define LBOOT_DEVNAME_SIZE 32
#define LBOOT_SERIAL_SIZE 32
#define LBOOT_SOFTVER_SIZE 32
#define LBOOT_REVISION_SIZE 16
#define LBOOT_IMPLEMENTATION_SIZE 16
#define LBOOT_SPECINFO_SIZE 64
#define LBOOT_MAC_ADDR_SIZE 6
#define LBOOT_REQ_MAX_FILENAME_SIZE 256
#define LBOOT_REQ_MAX_SIZE 4096
/** различные коды режимов загрузки */
#define LBOOT_BOOTMODE_MODBUS_RTU 0x100
#define LBOOT_BOOTMODE_TFTP_CLIENT 0x200
#define LBOOT_BOOTMODE_TFTP_SERVER 0x201
#define LBOOT_BOOTMODE_USB 0x300
#define LBOOT_BOOTMODE_CAN_LSS 0x400
#define LBOOT_BOOTMODE_TFTP LBOOT_BOOTMODE_TFTP_CLIENT
//режим работы устройства (application/bootloader) - в modbus сразу за device info
#define LBOOT_MODE_BOOT 0x1
#define LBOOT_MODE_APPL 0x2
#define LBOOT_TFTP_FLAGS_PACKED 0x2
#define LBOOT_SEED_CODE_NOSIGN 0xFFAA5500
/** признак, находящийся в информации о прошивке, по которому можно узнать
наличие этой информации. Признак означает, что поддерживается защита этой
информации CRC */
#define LBOOT_INFO_SIGNATURE 0x4C42A55A
/** общие для всех интерфейсов флаги, определяющие поведение загрузчика */
typedef enum {
/** - при активном запросе прошивки (tftp) - признак,
что перезависывется резервная копия, а не основная прошивка
- при пассивном приеме (mbrtu, usb, can_lss) - признак,
что разрешено перезаписывать резервную копию */
LBOOT_REQ_FLAGS_RECOVERY_WR = 0x01,
/** признак, что не нужно сверять имя устройства в прошивке */
LBOOT_REQ_FLAGS_DONT_CHECK_NAME = 0x02,
/** не проверять, что записывается стабильная прошивка (установлен флаг
#LBOOT_APP_FLAGS_STABLE в информации о прошивке)*/
LBOOT_REQ_FLAGS_DONT_CHECK_STABLE = 0x04,
/** разрешение записывать прошивку для разработчика (с установленным флагом
#LBOOT_APP_FLAGS_DEVELOP в информации о прошивке)*/
LBOOT_REQ_FLAGS_ENABLE_DEVELOP = 0x08,
/** разрешение записи прошивки без подписи (если поддерживается загрузчиком) */
LBOOT_REQ_FLAGS_ENABLE_NO_SIGN = 0x10
} t_lboot_req_flags;
/** флаги из #t_app_info */
typedef enum {
/** признак, что прошивка стабильная */
LBOOT_APP_FLAGS_STABLE = 0x1,
/** признак, что это прошивка для разработчиков */
LBOOT_APP_FLAGS_DEVELOP = 0x2
} t_lboot_app_flags;
#pragma pack(1)
/** Информация о программе, содержащаяся в прошивке */
struct st_app_info {
uint32_t size; /**< размер информции о прошивке */
uint32_t flags; /**< флаги */
/** название устройства, для которого предназначена прошивка*/
char devname[LBOOT_DEVNAME_SIZE];
};
typedef struct st_app_info t_app_info;
/** Информация о загрузчике, находящаяся непосредственно
в коде самого загрузчика */
struct lboot_info_st {
/** версия загрузчика (младший байт - минорная, старший - мажорная) */
uint16_t ver;
uint16_t flags; /**< флаги - резерв */
/** серийный номер устройства */
char serial[LBOOT_SERIAL_SIZE];
uint8_t mac[6]; /**< mac-адрес устройства */
/** ревизия платы (если вшита в загрузчик)*/
char brd_revision[LBOOT_REVISION_SIZE];
/** модификация (если вшита в загрузчик)*/
char brd_impl[LBOOT_IMPLEMENTATION_SIZE];
char creation_date[18]; /**< дата создания загрузчика */
/** признак, что эта структура действительна (только с v1.3) */
uint32_t sign;
/** размер структуры (включая два байта crc)
- для определения положения crc */
uint32_t size;
char devname[LBOOT_DEVNAME_SIZE];
/** поддерживаемые возможности загрузчика */
uint32_t features;
uint32_t reserv;
uint8_t ip_addr[4]; /**< ip-адрес устройства по-умолчанию */
uint8_t ip_mask[4]; /**< маска устройства по-умолчанию */
uint8_t gate[4]; /**< адрес шлюза по-умолчанию */
/** crc (но при проверке следует брать ее не отсюда,
а по адресу = адрес начала структуры + size - 2) */
uint16_t crc;
};
typedef struct lboot_info_st t_lboot_info;
/** информация о устройстве и прошивке */
struct lboot_devinfo_st {
char devname[LBOOT_DEVNAME_SIZE]; /**< название устройства */
char serial[LBOOT_SERIAL_SIZE]; /**< серийный номер */
char soft_ver[LBOOT_SOFTVER_SIZE]; /**< версия прошивки */
char brd_revision[LBOOT_REVISION_SIZE]; /**< ревизия платы */
char brd_impl[LBOOT_IMPLEMENTATION_SIZE]; /**< опции платы */
char spec_info[LBOOT_SPECINFO_SIZE]; /**< резерв */
};
typedef struct lboot_devinfo_st t_lboot_devinfo;
/** стандартный заголовок запроса на перепрошивку */
struct lboot_params_hdr_st {
uint32_t size; /**< размер структуры запроса (включая
специфические для интерфейса данные и crc) */
uint32_t bootmode; /**< режим загрузки - определяет интерфейс */
uint32_t flags; /**< общие флаги */
uint32_t timeout; /**< таймаут в мс - сколько загрузчик будет ожидать
запроса на перепрошивку (0 - бесконечно) */
uint32_t reserv[2]; /**< резерв */
t_lboot_devinfo devinfo; /**< информация о устройстве и прошивке */
};
typedef struct lboot_params_hdr_st t_lboot_params_hdr;
//специфические для tftp параметры
struct st_lboot_specpar_tftp {
uint16_t flags; //спец флаги (резерв)
uint16_t server_port;
uint8_t mac[6]; //mac-адрес
uint8_t l_ip[4]; //свой ip-адрес
uint8_t mask[4]; //mask - маска сети
uint8_t gate[4]; //адрес шлюза
uint8_t r_ip[4]; //адрес сервера tftp
char filename[LBOOT_REQ_MAX_FILENAME_SIZE]; //имя файла с прошивкой
uint16_t crc;
};
typedef struct st_lboot_specpar_tftp t_lboot_specpar_tftp;
//параметры для запроса прошивки по tftp
struct st_lboot_params_tftp {
t_lboot_params_hdr hdr;
uint16_t tftp_flags; //спец флаги (резерв)
uint16_t server_port;
uint8_t mac[6]; //mac-адрес
uint8_t l_ip[4]; //свой ip-адрес
uint8_t mask[4]; //mask - маска сети
uint8_t gate[4]; //адрес шлюза
uint8_t r_ip[4]; //адрес сервера tftp
char filename[LBOOT_REQ_MAX_FILENAME_SIZE]; //имя файла с прошивкой
uint16_t crc;
};
typedef struct st_lboot_params_tftp t_lboot_params_tftp;
struct st_lboot_specpar_modbus_rtu {
uint16_t flags ; //спец флаги
uint8_t addr ; //адрес устройства в modbus сети
uint8_t parity ;
uint16_t res ;
uint32_t baud_rate; //скорость передачи по rs-485/232
uint16_t crc;
};
typedef struct st_lboot_specpar_modbus_rtu t_lboot_specpar_modbus_rtu;
//параметры для перепрошивки по Modbus RTU
struct st_lboot_params_modbus_rtu {
t_lboot_params_hdr hdr ;
uint16_t flags ; //спец флаги
uint8_t addr ; //адрес устройства в modbus сети
uint8_t parity ;
uint16_t res ;
uint32_t baud_rate; //скорость передачи по rs-485/232
uint16_t crc;
};
typedef struct st_lboot_params_modbus_rtu t_lboot_params_modbus_rtu;
struct st_lboot_specpar_usb {
uint16_t flags ; //спец флаги
uint16_t crc;
};
typedef struct st_lboot_specpar_usb t_lboot_specpar_usb;
//параметры для перепрошивки по USB
struct st_lboot_params_usb {
t_lboot_params_hdr hdr ;
uint16_t flags ; //спец флаги
uint16_t crc;
};
typedef struct st_lboot_params_usb t_lboot_params_usb;
struct st_lboot_specpar_can_lss {
uint16_t flags;
uint8_t br_index; /* BaudRate Index */
uint8_t res;
uint32_t vid;
uint32_t pid;
uint32_t rev;
uint16_t crc;
};
typedef struct st_lboot_specpar_can_lss t_lboot_specpar_can_lss;
struct st_lboot_params_can_lss {
t_lboot_params_hdr hdr;
t_lboot_specpar_can_lss can;
};
typedef struct st_lboot_params_can_lss t_lboot_params_can_lss;
struct st_lboot_params {
t_lboot_params_hdr hdr ;
union {
t_lboot_specpar_tftp tftp;
t_lboot_specpar_modbus_rtu mbrtu;
t_lboot_specpar_usb usb;
t_lboot_specpar_can_lss can;
};
};
typedef struct st_lboot_params t_lboot_params;
#pragma pack()
#endif /* LBOOT_REQ_H_ */

810
lib/x502/lcard_pstdint.h Normal file
View File

@ -0,0 +1,810 @@
/* A portable stdint.h
****************************************************************************
* BSD License:
****************************************************************************
*
* Copyright (c) 2005-2011 Paul Hsieh
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************
*
* Version 0.1.12
*
* The ANSI C standard committee, for the C99 standard, specified the
* inclusion of a new standard include file called stdint.h. This is
* a very useful and long desired include file which contains several
* very precise definitions for integer scalar types that is
* critically important for making portable several classes of
* applications including cryptography, hashing, variable length
* integer libraries and so on. But for most developers its likely
* useful just for programming sanity.
*
* The problem is that most compiler vendors have decided not to
* implement the C99 standard, and the next C++ language standard
* (which has a lot more mindshare these days) will be a long time in
* coming and its unknown whether or not it will include stdint.h or
* how much adoption it will have. Either way, it will be a long time
* before all compilers come with a stdint.h and it also does nothing
* for the extremely large number of compilers available today which
* do not include this file, or anything comparable to it.
*
* So that's what this file is all about. Its an attempt to build a
* single universal include file that works on as many platforms as
* possible to deliver what stdint.h is supposed to. A few things
* that should be noted about this file:
*
* 1) It is not guaranteed to be portable and/or present an identical
* interface on all platforms. The extreme variability of the
* ANSI C standard makes this an impossibility right from the
* very get go. Its really only meant to be useful for the vast
* majority of platforms that possess the capability of
* implementing usefully and precisely defined, standard sized
* integer scalars. Systems which are not intrinsically 2s
* complement may produce invalid constants.
*
* 2) There is an unavoidable use of non-reserved symbols.
*
* 3) Other standard include files are invoked.
*
* 4) This file may come in conflict with future platforms that do
* include stdint.h. The hope is that one or the other can be
* used with no real difference.
*
* 5) In the current verison, if your platform can't represent
* int32_t, int16_t and int8_t, it just dumps out with a compiler
* error.
*
* 6) 64 bit integers may or may not be defined. Test for their
* presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.
* Note that this is different from the C99 specification which
* requires the existence of 64 bit support in the compiler. If
* this is not defined for your platform, yet it is capable of
* dealing with 64 bits then it is because this file has not yet
* been extended to cover all of your system's capabilities.
*
* 7) (u)intptr_t may or may not be defined. Test for its presence
* with the test: #ifdef PTRDIFF_MAX. If this is not defined
* for your platform, then it is because this file has not yet
* been extended to cover all of your system's capabilities, not
* because its optional.
*
* 8) The following might not been defined even if your platform is
* capable of defining it:
*
* WCHAR_MIN
* WCHAR_MAX
* (u)int64_t
* PTRDIFF_MIN
* PTRDIFF_MAX
* (u)intptr_t
*
* 9) The following have not been defined:
*
* WINT_MIN
* WINT_MAX
*
* 10) The criteria for defining (u)int_least(*)_t isn't clear,
* except for systems which don't have a type that precisely
* defined 8, 16, or 32 bit types (which this include file does
* not support anyways). Default definitions have been given.
*
* 11) The criteria for defining (u)int_fast(*)_t isn't something I
* would trust to any particular compiler vendor or the ANSI C
* committee. It is well known that "compatible systems" are
* commonly created that have very different performance
* characteristics from the systems they are compatible with,
* especially those whose vendors make both the compiler and the
* system. Default definitions have been given, but its strongly
* recommended that users never use these definitions for any
* reason (they do *NOT* deliver any serious guarantee of
* improved performance -- not in this file, nor any vendor's
* stdint.h).
*
* 12) The following macros:
*
* PRINTF_INTMAX_MODIFIER
* PRINTF_INT64_MODIFIER
* PRINTF_INT32_MODIFIER
* PRINTF_INT16_MODIFIER
* PRINTF_LEAST64_MODIFIER
* PRINTF_LEAST32_MODIFIER
* PRINTF_LEAST16_MODIFIER
* PRINTF_INTPTR_MODIFIER
*
* are strings which have been defined as the modifiers required
* for the "d", "u" and "x" printf formats to correctly output
* (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,
* (u)least32_t, (u)least16_t and (u)intptr_t types respectively.
* PRINTF_INTPTR_MODIFIER is not defined for some systems which
* provide their own stdint.h. PRINTF_INT64_MODIFIER is not
* defined if INT64_MAX is not defined. These are an extension
* beyond what C99 specifies must be in stdint.h.
*
* In addition, the following macros are defined:
*
* PRINTF_INTMAX_HEX_WIDTH
* PRINTF_INT64_HEX_WIDTH
* PRINTF_INT32_HEX_WIDTH
* PRINTF_INT16_HEX_WIDTH
* PRINTF_INT8_HEX_WIDTH
* PRINTF_INTMAX_DEC_WIDTH
* PRINTF_INT64_DEC_WIDTH
* PRINTF_INT32_DEC_WIDTH
* PRINTF_INT16_DEC_WIDTH
* PRINTF_INT8_DEC_WIDTH
*
* Which specifies the maximum number of characters required to
* print the number of that type in either hexadecimal or decimal.
* These are an extension beyond what C99 specifies must be in
* stdint.h.
*
* Compilers tested (all with 0 warnings at their highest respective
* settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32
* bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio
* .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3
*
* This file should be considered a work in progress. Suggestions for
* improvements, especially those which increase coverage are strongly
* encouraged.
*
* Acknowledgements
*
* The following people have made significant contributions to the
* development and testing of this file:
*
* Chris Howie
* John Steele Scott
* Dave Thorup
* John Dill
*
*/
#ifndef LCARD_PSTDINT
#define LCARD_PSTDINT
#include <stddef.h>
#include <limits.h>
/*
* For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and
* do nothing else. On the Mac OS X version of gcc this is _STDINT_H_.
*/
#if ((defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) \
|| (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || (__WATCOMC__ >= 1250))) \
|| (defined(__GNUC__)) \
|| (defined (_MSC_VER) && (_MSC_VER >= 1600)) \
|| (defined (__BORLANDC__) && (__BORLANDC__ >= 0x560))) && !defined (_PSTDINT_H_INCLUDED)
#include <stdint.h>
#define _PSTDINT_H_INCLUDED
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
# endif
# ifndef PRINTF_INT64_HEX_WIDTH
# define PRINTF_INT64_HEX_WIDTH "16"
# endif
# ifndef PRINTF_INT32_HEX_WIDTH
# define PRINTF_INT32_HEX_WIDTH "8"
# endif
# ifndef PRINTF_INT16_HEX_WIDTH
# define PRINTF_INT16_HEX_WIDTH "4"
# endif
# ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
# endif
# ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "20"
# endif
# ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
# endif
# ifndef PRINTF_INT16_DEC_WIDTH
# define PRINTF_INT16_DEC_WIDTH "5"
# endif
# ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
# endif
/*
* Something really weird is going on with Open Watcom. Just pull some of
* these duplicated definitions from Open Watcom's stdint.h file for now.
*/
# if defined (__WATCOMC__) && __WATCOMC__ >= 1250
# if !defined (INT64_C)
# define INT64_C(x) (x + (INT64_MAX - INT64_MAX))
# endif
# if !defined (UINT64_C)
# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
# endif
# if !defined (INT32_C)
# define INT32_C(x) (x + (INT32_MAX - INT32_MAX))
# endif
# if !defined (UINT32_C)
# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX))
# endif
# if !defined (INT16_C)
# define INT16_C(x) (x)
# endif
# if !defined (UINT16_C)
# define UINT16_C(x) (x)
# endif
# if !defined (INT8_C)
# define INT8_C(x) (x)
# endif
# if !defined (UINT8_C)
# define UINT8_C(x) (x)
# endif
# if !defined (UINT64_MAX)
# define UINT64_MAX 18446744073709551615ULL
# endif
# if !defined (INT64_MAX)
# define INT64_MAX 9223372036854775807LL
# endif
# if !defined (UINT32_MAX)
# define UINT32_MAX 4294967295UL
# endif
# if !defined (INT32_MAX)
# define INT32_MAX 2147483647L
# endif
# if !defined (INTMAX_MAX)
# define INTMAX_MAX INT64_MAX
# endif
# if !defined (INTMAX_MIN)
# define INTMAX_MIN INT64_MIN
# endif
# endif
#endif
#ifndef _PSTDINT_H_INCLUDED
#define _PSTDINT_H_INCLUDED
#ifndef SIZE_MAX
# define SIZE_MAX (~(size_t)0)
#endif
/*
* Deduce the type assignments from limits.h under the assumption that
* integer sizes in bits are powers of 2, and follow the ANSI
* definitions.
*/
#ifndef UINT8_MAX
# define UINT8_MAX 0xff
#endif
#ifndef uint8_t
# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
typedef unsigned char uint8_t;
# define UINT8_C(v) ((uint8_t) v)
# else
# error "Platform not supported"
# endif
#endif
#ifndef INT8_MAX
# define INT8_MAX 0x7f
#endif
#ifndef INT8_MIN
# define INT8_MIN INT8_C(0x80)
#endif
#ifndef int8_t
# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
typedef signed char int8_t;
# define INT8_C(v) ((int8_t) v)
# else
# error "Platform not supported"
# endif
#endif
#ifndef UINT16_MAX
# define UINT16_MAX 0xffff
#endif
#ifndef uint16_t
#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
typedef unsigned int uint16_t;
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER ""
# endif
# define UINT16_C(v) ((uint16_t) (v))
#elif (USHRT_MAX == UINT16_MAX)
typedef unsigned short uint16_t;
# define UINT16_C(v) ((uint16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef INT16_MAX
# define INT16_MAX 0x7fff
#endif
#ifndef INT16_MIN
# define INT16_MIN INT16_C(0x8000)
#endif
#ifndef int16_t
#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
typedef signed int int16_t;
# define INT16_C(v) ((int16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER ""
# endif
#elif (SHRT_MAX == INT16_MAX)
typedef signed short int16_t;
# define INT16_C(v) ((int16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef UINT32_MAX
# define UINT32_MAX (0xffffffffUL)
#endif
#ifndef uint32_t
#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
typedef unsigned long uint32_t;
# define UINT32_C(v) v ## UL
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
#elif (UINT_MAX == UINT32_MAX)
typedef unsigned int uint32_t;
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
# define UINT32_C(v) v ## U
#elif (USHRT_MAX == UINT32_MAX)
typedef unsigned short uint32_t;
# define UINT32_C(v) ((unsigned short) (v))
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef INT32_MAX
# define INT32_MAX (0x7fffffffL)
#endif
#ifndef INT32_MIN
# define INT32_MIN INT32_C(0x80000000)
#endif
#ifndef int32_t
#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
typedef signed long int32_t;
# define INT32_C(v) v ## L
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
#elif (INT_MAX == INT32_MAX)
typedef signed int int32_t;
# define INT32_C(v) v
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#elif (SHRT_MAX == INT32_MAX)
typedef signed short int32_t;
# define INT32_C(v) ((short) (v))
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#else
#error "Platform not supported"
#endif
#endif
/*
* The macro stdint_int64_defined is temporarily used to record
* whether or not 64 integer support is available. It must be
* defined for any 64 integer extensions for new platforms that are
* added.
*/
#undef stdint_int64_defined
#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S)
# define stdint_int64_defined
typedef long long int64_t;
typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# endif
#endif
#if !defined (stdint_int64_defined)
# if defined(__GNUC__)
# define stdint_int64_defined
__extension__ typedef long long int64_t;
__extension__ typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)
# define stdint_int64_defined
typedef long long int64_t;
typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)
# define stdint_int64_defined
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
# define UINT64_C(v) v ## UI64
# define INT64_C(v) v ## I64
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "I64"
# endif
# endif
#endif
#if !defined (LONG_LONG_MAX) && defined (INT64_C)
# define LONG_LONG_MAX INT64_C (9223372036854775807)
#endif
#ifndef ULONG_LONG_MAX
# define ULONG_LONG_MAX UINT64_C (18446744073709551615)
#endif
#if !defined (INT64_MAX) && defined (INT64_C)
# define INT64_MAX INT64_C (9223372036854775807)
#endif
#if !defined (INT64_MIN) && defined (INT64_C)
# define INT64_MIN INT64_C (-9223372036854775808)
#endif
#if !defined (UINT64_MAX) && defined (INT64_C)
# define UINT64_MAX UINT64_C (18446744073709551615)
#endif
/*
* Width of hexadecimal for number field.
*/
#ifndef PRINTF_INT64_HEX_WIDTH
# define PRINTF_INT64_HEX_WIDTH "16"
#endif
#ifndef PRINTF_INT32_HEX_WIDTH
# define PRINTF_INT32_HEX_WIDTH "8"
#endif
#ifndef PRINTF_INT16_HEX_WIDTH
# define PRINTF_INT16_HEX_WIDTH "4"
#endif
#ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
#endif
#ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "20"
#endif
#ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
#endif
#ifndef PRINTF_INT16_DEC_WIDTH
# define PRINTF_INT16_DEC_WIDTH "5"
#endif
#ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
#endif
/*
* Ok, lets not worry about 128 bit integers for now. Moore's law says
* we don't need to worry about that until about 2040 at which point
* we'll have bigger things to worry about.
*/
#ifdef stdint_int64_defined
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
# define INTMAX_MAX INT64_MAX
# define INTMAX_MIN INT64_MIN
# define UINTMAX_MAX UINT64_MAX
# define UINTMAX_C(v) UINT64_C(v)
# define INTMAX_C(v) INT64_C(v)
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
# endif
#else
typedef int32_t intmax_t;
typedef uint32_t uintmax_t;
# define INTMAX_MAX INT32_MAX
# define UINTMAX_MAX UINT32_MAX
# define UINTMAX_C(v) UINT32_C(v)
# define INTMAX_C(v) INT32_C(v)
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH
# endif
#endif
/*
* Because this file currently only supports platforms which have
* precise powers of 2 as bit sizes for the default integers, the
* least definitions are all trivial. Its possible that a future
* version of this file could have different definitions.
*/
#ifndef stdint_least_defined
typedef int8_t int_least8_t;
typedef uint8_t uint_least8_t;
typedef int16_t int_least16_t;
typedef uint16_t uint_least16_t;
typedef int32_t int_least32_t;
typedef uint32_t uint_least32_t;
# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER
# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER
# define UINT_LEAST8_MAX UINT8_MAX
# define INT_LEAST8_MAX INT8_MAX
# define UINT_LEAST16_MAX UINT16_MAX
# define INT_LEAST16_MAX INT16_MAX
# define UINT_LEAST32_MAX UINT32_MAX
# define INT_LEAST32_MAX INT32_MAX
# define INT_LEAST8_MIN INT8_MIN
# define INT_LEAST16_MIN INT16_MIN
# define INT_LEAST32_MIN INT32_MIN
# ifdef stdint_int64_defined
typedef int64_t int_least64_t;
typedef uint64_t uint_least64_t;
# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER
# define UINT_LEAST64_MAX UINT64_MAX
# define INT_LEAST64_MAX INT64_MAX
# define INT_LEAST64_MIN INT64_MIN
# endif
#endif
#undef stdint_least_defined
/*
* The ANSI C committee pretending to know or specify anything about
* performance is the epitome of misguided arrogance. The mandate of
* this file is to *ONLY* ever support that absolute minimum
* definition of the fast integer types, for compatibility purposes.
* No extensions, and no attempt to suggest what may or may not be a
* faster integer type will ever be made in this file. Developers are
* warned to stay away from these types when using this or any other
* stdint.h.
*/
typedef int_least8_t int_fast8_t;
typedef uint_least8_t uint_fast8_t;
typedef int_least16_t int_fast16_t;
typedef uint_least16_t uint_fast16_t;
typedef int_least32_t int_fast32_t;
typedef uint_least32_t uint_fast32_t;
#define UINT_FAST8_MAX UINT_LEAST8_MAX
#define INT_FAST8_MAX INT_LEAST8_MAX
#define UINT_FAST16_MAX UINT_LEAST16_MAX
#define INT_FAST16_MAX INT_LEAST16_MAX
#define UINT_FAST32_MAX UINT_LEAST32_MAX
#define INT_FAST32_MAX INT_LEAST32_MAX
#define INT_FAST8_MIN INT_LEAST8_MIN
#define INT_FAST16_MIN INT_LEAST16_MIN
#define INT_FAST32_MIN INT_LEAST32_MIN
#ifdef stdint_int64_defined
typedef int_least64_t int_fast64_t;
typedef uint_least64_t uint_fast64_t;
# define UINT_FAST64_MAX UINT_LEAST64_MAX
# define INT_FAST64_MAX INT_LEAST64_MAX
# define INT_FAST64_MIN INT_LEAST64_MIN
#endif
#undef stdint_int64_defined
/*
* Whatever piecemeal, per compiler thing we can do about the wchar_t
* type limits.
*/
#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
# include <wchar.h>
# ifndef WCHAR_MIN
# define WCHAR_MIN 0
# endif
# ifndef WCHAR_MAX
# define WCHAR_MAX ((wchar_t)-1)
# endif
#endif
/*
* Whatever piecemeal, per compiler/platform thing we can do about the
* (u)intptr_t types and limits.
*/
#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)
# define STDINT_H_UINTPTR_T_DEFINED
#elif defined (_CVI_)
# define STDINT_H_UINTPTR_T_DEFINED
#endif
#ifndef STDINT_H_UINTPTR_T_DEFINED
# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64)
# define stdint_intptr_bits 64
# elif defined (__WATCOMC__) || defined (__TURBOC__)
# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
# define stdint_intptr_bits 16
# else
# define stdint_intptr_bits 32
# endif
# elif defined (__i386__) || defined (_WIN32) || defined (WIN32)
# define stdint_intptr_bits 32
# elif defined (__INTEL_COMPILER)
/* TODO -- what did Intel do about x86-64? */
# endif
# ifdef stdint_intptr_bits
# define stdint_intptr_glue3_i(a,b,c) a##b##c
# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c)
# ifndef PRINTF_INTPTR_MODIFIER
# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)
# endif
# ifndef PTRDIFF_MAX
# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
# endif
# ifndef PTRDIFF_MIN
# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
# endif
# ifndef UINTPTR_MAX
# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)
# endif
# ifndef INTPTR_MAX
# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
# endif
# ifndef INTPTR_MIN
# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
# endif
# ifndef INTPTR_C
# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)
# endif
# ifndef UINTPTR_C
# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)
# endif
typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;
typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t;
# else
/* TODO -- This following is likely wrong for some platforms, and does
nothing for the definition of uintptr_t. */
typedef ptrdiff_t intptr_t;
# endif
# define STDINT_H_UINTPTR_T_DEFINED
#endif
/*
* Assumes sig_atomic_t is signed and we have a 2s complement machine.
*/
#ifndef SIG_ATOMIC_MAX
# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)
#endif
#endif
#if defined (__TEST_PSTDINT_FOR_CORRECTNESS)
/*
* Please compile with the maximum warning settings to make sure macros are not
* defined more than once.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define glue3_aux(x,y,z) x ## y ## z
#define glue3(x,y,z) glue3_aux(x,y,z)
#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,=) glue3(UINT,bits,_C) (0);
#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,=) glue3(INT,bits,_C) (0);
#define DECL(us,bits) glue3(DECL,us,) (bits)
#define TESTUMAX(bits) glue3(u,bits,=) glue3(~,u,bits); if (glue3(UINT,bits,_MAX) glue3(!=,u,bits)) printf ("Something wrong with UINT%d_MAX\n", bits)
int main () {
DECL(I,8)
DECL(U,8)
DECL(I,16)
DECL(U,16)
DECL(I,32)
DECL(U,32)
#ifdef INT64_MAX
DECL(I,64)
DECL(U,64)
#endif
intmax_t imax = INTMAX_C(0);
uintmax_t umax = UINTMAX_C(0);
char str0[256], str1[256];
sprintf (str0, "%d %x\n", 0, ~0);
sprintf (str1, "%d %x\n", i8, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i8 : %s\n", str1);
sprintf (str1, "%u %x\n", u8, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with u8 : %s\n", str1);
sprintf (str1, "%d %x\n", i16, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i16 : %s\n", str1);
sprintf (str1, "%u %x\n", u16, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with u16 : %s\n", str1);
sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i32 : %s\n", str1);
sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with u32 : %s\n", str1);
#ifdef INT64_MAX
sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with i64 : %s\n", str1);
#endif
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with imax : %s\n", str1);
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0);
if (0 != strcmp (str0, str1)) printf ("Something wrong with umax : %s\n", str1);
TESTUMAX(8);
TESTUMAX(16);
TESTUMAX(32);
#ifdef INT64_MAX
TESTUMAX(64);
#endif
return EXIT_SUCCESS;
}
#endif
#endif

27
lib/x502/osspec_cfg.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef OS_SPEC_CFG_H_
#define OS_SPEC_CFG_H_
#include "x502api.h"
//#define OSSPEC_USE_MUTEX
//#define OSSPEC_USE_EVENTS
//#define OSSPEC_USE_THREADS
#define OSSPEC_ERR_MUTEX_INVALID_HANDLE X502_ERR_MUTEX_INVALID_HANDLE
#define OSSPEC_ERR_MUTEX_LOCK_TOUT X502_ERR_MUTEX_LOCK_TOUT
#define OSSPEC_ERR_MUTEX_RELEASE X502_ERR_MUTEX_RELEASE
#define OSSPEC_ERR_EVENT_INVALID_HANDLE OSSPEC_ERR_MUTEX_INVALID_HANDLE
#define OSSPEC_ERR_EVENT_WAIT_TOUT OSSPEC_ERR_MUTEX_LOCK_TOUT
#define OSSPEC_ERR_THREAD_INVALID_HANDLE OSSPEC_ERR_MUTEX_INVALID_HANDLE
#define OSSPEC_ERR_THREAD_WAIT_TOUT X502_ERR_THREAD_STOP
#endif

87
lib/x502/x502_eeprom.h Normal file
View File

@ -0,0 +1,87 @@
/***************************************************************************//**
@file x502_eeprom.h
@author Borisov Alexey <borisov@lcard.ru>
@date 14.03.2011
Файл содержет описание констант и типов, для описание формата информации,
записаной в EEPROM. Эти константы используются только внутри библиотеки и
в специальном софте (для калибровки и обновлениия прошивки ПЛИС) и не
доступны пользователю по-умолчанию
******************************************************************************/
#ifndef X502_EEPROM_H
#define X502_EEPROM_H
#define X502_EEPROM_CBR_SIGN 0x4C434352 //LCBR
#define X502_EEPROM_CBR_FROMAT 2
#define X502_EEPROM_CBR_SRC_ADC 1
#define X502_EEPROM_CBR_SRC_DAC 2
// TODO: это может быть проблемой для поддержки совместимости: E502-P1 флеш в 2 раза больше
//#define X502_EEPROM_SIZE 0x400000UL
// Устаревшая константа с размером внешней флеш памяти в байтах, надо использовать значения переменной из hnd->info.flash_size
#define X502_EEPROM_SIZE 0x200000UL
#define X502_EEPROM_ADDR_DESCR 0x1F0000UL
#define X502_DESCR_MAX_SIZE 0x010000UL
#define X502_EEPROM_FORMAT 1
#define X502_DESCR_MIN_SIZE (sizeof(t_x502_eeprom_hdr)+4)
#define X502_EEPROM_SIGN 0x4C524F4D
typedef struct {
uint32_t cbr_sign;
uint32_t cbr_size;
uint32_t format;
uint32_t src;
uint32_t flags;
uint32_t reserv[3];
uint64_t time;
uint32_t channel_cnt;
uint32_t range_cnt;
} t_x502_eeprom_cbr_hdr;
typedef struct {
t_x502_eeprom_cbr_hdr hdr;
t_x502_cbr_coef coefs[X502_ADC_RANGE_CNT];
} t_x502_eeprom_cbr_adc;
typedef struct {
t_x502_eeprom_cbr_hdr hdr;
t_x502_cbr_coef coefs[X502_DAC_CH_CNT];
} t_x502_eeprom_cbr_dac;
typedef struct {
uint32_t sign;
uint32_t size;
uint32_t format;
char name[X502_DEVNAME_SIZE];
char serial[X502_SERIAL_SIZE];
uint8_t factory_mac[X502_MAC_ADDR_SIZE];
char res[64-18];
} t_x502_eeprom_hdr;
typedef struct {
t_x502_eeprom_hdr hdr;
t_x502_eeprom_cbr_adc cbr_adc;
t_x502_eeprom_cbr_dac cbr_dac;
uint32_t crc;
} t_x502_descr;
typedef enum {
X502_EEPROM_PROT_ALL = 0, /**< Защищена вся область памяти */
X502_EEPROM_PROT_WR_USER = 1, /**< Разрешено изменение только пользовательской части */
X502_EEPROM_PROT_WR_SETTINGS = 2, /**< Кроме пользовательской части, разрешено изменение
области настроек, флага загрузки и второй копии прошивки ПЛИС */
X502_EEPROM_PROT_WR_FPGA_FIRM = 3, /**< Разрешено изменение основной прошивки ПЛИС */
X502_EEPROM_PROT_WR_ALL = 4, /**< Разрешена запись в любую область памяти */
} t_x502_eeprom_prot_state;
#endif // X502_EEPROM_H

118
lib/x502/x502_fpga_regs.h Normal file
View File

@ -0,0 +1,118 @@
#ifndef X502_FPGA_REGS_H
#define X502_FPGA_REGS_H
#define X502_BF_SDRAM_SIZE (32UL*1024*1024)
#define X502_BF_MEMADDR_CMD 0xFF800800
#define X502_BF_CMD_READ 0x0001
#define X502_BF_CMD_WRITE 0x0002
#define X502_BF_CMD_HIRQ 0x0004
#define X502_BF_CMD_HDMA_RST 0x0008
/********************* Адреса регистров блока IOHARD **************************/
#define X502_REGS_IOHARD_BLOCK 0x0200
//Адрес Control Table
#define X502_REGS_IOHARD_LTABLE (X502_REGS_IOHARD_BLOCK+0)
#define X502_REGS_IOHARD_LTABLE_MAX_SIZE 0x100 // Максимальный размер Control Table
#define X502_REGS_IOHARD_LCH_CNT (X502_REGS_IOHARD_BLOCK+0x100)
#define X502_REGS_IOHARD_ADC_FREQ_DIV (X502_REGS_IOHARD_BLOCK+0x102)
#define X502_REGS_IOHARD_ADC_FRAME_DELAY (X502_REGS_IOHARD_BLOCK+0x104)
#define X502_REGS_IOHARD_DIGIN_FREQ_DIV (X502_REGS_IOHARD_BLOCK+0x106)
#define X502_REGS_IOHARD_IO_MODE (X502_REGS_IOHARD_BLOCK+0x108)
#define X502_REGS_IOHARD_GO_SYNC_IO (X502_REGS_IOHARD_BLOCK+0x10A)
#define X502_REGS_IOHARD_PRELOAD_ADC (X502_REGS_IOHARD_BLOCK+0x10C)
#define X502_REGS_IOHARD_ASYNC_OUT (X502_REGS_IOHARD_BLOCK+0x112)
#define X502_REGS_IOHARD_LED (X502_REGS_IOHARD_BLOCK+0x114)
#define X502_REGS_IOHARD_DIGIN_PULLUP (X502_REGS_IOHARD_BLOCK+0x116)
#define X502_REGS_IOHARD_OUTSWAP_BFCTL (X502_REGS_IOHARD_BLOCK+0x118)
#define X502_REGS_IOHARD_OUTSWAP_ERROR (X502_REGS_IOHARD_BLOCK+0x120)
/********************* Адреса регистров блока IOARITH **************************/
#define X502_REGS_IOARITH_BLOCK 0x0400
#define X502_REGS_IOARITH_B10 X502_REGS_IOARITH_BLOCK
#define X502_REGS_IOARITH_B5 (X502_REGS_IOARITH_BLOCK+0x01)
#define X502_REGS_IOARITH_B2 (X502_REGS_IOARITH_BLOCK+0x02)
#define X502_REGS_IOARITH_B1 (X502_REGS_IOARITH_BLOCK+0x03)
#define X502_REGS_IOARITH_B05 (X502_REGS_IOARITH_BLOCK+0x04)
#define X502_REGS_IOARITH_B02 (X502_REGS_IOARITH_BLOCK+0x05)
#define X502_REGS_IOARITH_K10 (X502_REGS_IOARITH_BLOCK+0x08)
#define X502_REGS_IOARITH_K5 (X502_REGS_IOARITH_BLOCK+0x09)
#define X502_REGS_IOARITH_K2 (X502_REGS_IOARITH_BLOCK+0x0A)
#define X502_REGS_IOARITH_K1 (X502_REGS_IOARITH_BLOCK+0x0B)
#define X502_REGS_IOARITH_K05 (X502_REGS_IOARITH_BLOCK+0x0C)
#define X502_REGS_IOARITH_K02 (X502_REGS_IOARITH_BLOCK+0x0D)
#define X502_REGS_IOARITH_ADC_FREQ_DIV (X502_REGS_IOARITH_BLOCK+0x12)
#define X502_REGS_IOARITH_THRESHOLD (X502_REGS_IOARITH_BLOCK+0x15)
#define X502_REGS_IOARITH_N_CHAN_SYN (X502_REGS_IOARITH_BLOCK+0x16)
#define X502_REGS_IOARITH_IN_STREAM_ENABLE (X502_REGS_IOARITH_BLOCK+0x19)
#define X502_REGS_IOARITH_DIN_ASYNC (X502_REGS_IOARITH_BLOCK+0x1A)
#define X502_REGS_IOARITH_SYNC_TYPE (X502_REGS_IOARITH_BLOCK+0x20)
/********************* Адреса регистров блока управления BlackFin'ом **********/
#define X502_REGS_BF_CTL_BLOCK 0
#define X502_REGS_BF_CTL (X502_REGS_BF_CTL_BLOCK+0)
#define X502_REGS_BF_CMD (X502_REGS_BF_CTL_BLOCK+1)
#define X502_REGS_BF_STATUS (X502_REGS_BF_CTL_BLOCK+2)
#define X502_REGS_BF_IRQ (X502_REGS_BF_CTL_BLOCK+3)
#define X502_REGS_BF_IRQ_EN (X502_REGS_BF_CTL_BLOCK+4)
#define X502_REGS_BF_REQ_ADDR (X502_REGS_BF_CTL_BLOCK+5)
#define X502_REGS_BF_REQ_SIZE (X502_REGS_BF_CTL_BLOCK+6)
#define X502_REGS_BF_REQ_DATA (X502_REGS_BF_CTL_BLOCK+128)
#define X502_BF_REQ_DATA_SIZE_MAX 128
#define X502_BF_REQ_DATA_SIZE_MIN 8
/* описание отдельных битов регистров */
#define X502_REGBIT_BF_STATUS_HWAIT_Pos 0
#define X502_REGBIT_BF_STATUS_HWAIT_Msk (1UL << X502_REGBIT_BF_STATUS_HWAIT_Pos)
#define X502_REGBIT_BF_STATUS_BUSY_Pos 1
#define X502_REGBIT_BF_STATUS_BUSY_Msk (1UL << X502_REGBIT_BF_STATUS_BUSY_Pos)
#define X502_REGBIT_BF_CTL_BF_RESET_Pos 1
#define X502_REGBIT_BF_CTL_BF_RESET_Msk (0x1UL << X502_REGBIT_BF_CTL_BF_RESET_Pos)
#define X502_REGBIT_BF_CTL_HOST_WAIT_Pos 3
#define X502_REGBIT_BF_CTL_HOST_WAIT_Msk (0x1UL << X502_REGBIT_BF_CTL_HOST_WAIT_Pos)
#define X502_REGBIT_BF_CTL_DSP_MODE_Pos 4
#define X502_REGBIT_BF_CTL_DSP_MODE_Msk (0x1UL << X502_REGBIT_BF_CTL_DSP_MODE_Pos)
#define X502_REGBIT_BF_CTL_DBG_MODE_Pos 5
#define X502_REGBIT_BF_CTL_DBG_MODE_Msk (0x1UL << X502_REGBIT_BF_CTL_DBG_MODE_Pos)
#define X502_REGBIT_BF_CTL_CLK_DIV_Pos 8
#define X502_REGBIT_BF_CTL_CLK_DIV_Msk (0xFUL << X502_REGBIT_BF_CTL_CLK_DIV_Pos)
#define X502_REGBIT_ADC_SLV_CLK_LOCK_Pos 31
#define X502_REGBIT_ADC_SLV_CLK_LOCK_Msk (0x1UL << X502_REGBIT_ADC_SLV_CLK_LOCK_Pos)
#define X502_REGBIT_IOHARD_OUT_SWAP_Pos 0
#define X502_REGBIT_IOHARD_OUT_SWAP_Msk (0x1UL << X502_REGBIT_IOHARD_OUT_SWAP_Pos)
#define X502_REGBIT_IOHARD_OUT_TFS_EN_Pos 1
#define X502_REGBIT_IOHARD_OUT_TFS_EN_Msk (0x1UL << X502_REGBIT_IOHARD_OUT_TFS_EN_Pos)
#define X502_REGBIT_IOHARD_OUT_RING_Pos 2
#define X502_REGBIT_IOHARD_OUT_RING_Msk (0x1UL << X502_REGBIT_IOHARD_OUT_RING_Pos)
#define X502_REGBIT_IOHARD_OUT_RFS_EN_Pos 3
#define X502_REGBIT_IOHARD_OUT_RFS_EN_Msk (0x1UL << X502_REGBIT_IOHARD_OUT_RFS_EN_Pos)
#endif // E502_FPGA_REGS_H

731
lib/x502/x502api.c Normal file
View File

@ -0,0 +1,731 @@
#include "x502api.h"
#include "x502api_private.h"
#include "x502_fpga_regs.h"
#include <string.h>
#include <stdlib.h>
static const double f_x502_scales[] = {10., 5., 2., 1., 0.5, 0.2};
// В E16 только 4 диапазона!
static const double f_e16_scales[] = {10., 2.5, 0.625, 0.15625, 0., 0.};
X502_EXPORT(double const*) E16_GetAdcRanges(uint32_t *ranges_len) {
if (ranges_len) {
*ranges_len = E16_ADC_RANGE_CNT;
}
return f_e16_scales;
}
X502_EXPORT(double const*) E502_GetAdcRanges(uint32_t *ranges_len) {
if (ranges_len) {
*ranges_len = X502_ADC_RANGE_CNT;
}
return f_x502_scales;
}
X502_EXPORT(double const*) X502_GetAdcRanges(t_x502_hnd hnd, uint32_t *ranges_len) {
int32_t err = X502_CHECK_HND(hnd);
if (err != X502_ERR_OK) {
if (x502_is_E16(hnd)) {
return E16_GetAdcRanges(ranges_len);
} else {
return E502_GetAdcRanges(ranges_len);
}
}
return NULL;
}
X502_EXPORT(t_x502_hnd) X502_Create(void) {
t_x502_hnd hnd = calloc(sizeof(t_x502), 1);
if (hnd != NULL) {
hnd->sign = X502_SIGN;
}
return hnd;
}
X502_EXPORT(int32_t) X502_Free(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND(hnd);
if (err == X502_ERR_OK) {
if (hnd->flags & PRIV_FLAGS_OPENED)
err = X502_Close(hnd);
hnd->sign = 0;
free(hnd);
}
return err;
}
X502_EXPORT(int32_t) X502_Close(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND(hnd);
if ((err == X502_ERR_OK) && (hnd->flags & PRIV_FLAGS_OPENED)) {
int32_t stop_err;
if (hnd->flags & PRIV_FLAGS_STREAM_RUN) {
/* остановка потока */
err = X502_StreamsStop(hnd);
}
hnd->flags &= ~PRIV_FLAGS_OPENED;
stop_err = hnd->iface_hnd->close(hnd);
if (err == X502_ERR_OK)
err = stop_err;
if (hnd->mutex_cfg!=OSSPEC_INVALID_MUTEX) {
stop_err = osspec_mutex_destroy(hnd->mutex_cfg);
hnd->mutex_cfg = OSSPEC_INVALID_MUTEX;
if (err == X502_ERR_OK)
err = stop_err;
}
if (hnd->mutex_bf!=OSSPEC_INVALID_MUTEX) {
stop_err = osspec_mutex_destroy(hnd->mutex_bf);
hnd->mutex_bf = OSSPEC_INVALID_MUTEX;
if (err == X502_ERR_OK)
err = stop_err;
}
}
return err;
}
X502_EXPORT(int32_t) X502_IsOpened(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND(hnd);
if ((err == X502_ERR_OK) && !(hnd->flags & PRIV_FLAGS_OPENED)) {
err = X502_ERR_DEVICE_NOT_OPENED;
}
return err;
}
X502_EXPORT(int32_t) X502_OpenByDevRecord(t_x502* hnd, const t_x502_devrec *devrec) {
int32_t err = X502_CHECK_HND(hnd);
if ((err == X502_ERR_OK) && ((devrec==NULL) || (devrec->sign!=X502_DEVREC_SIGN)))
err = X502_ERR_INVALID_DEVICE_RECORD;
if (X502_IsOpened(hnd) == X502_ERR_OK) {
X502_Close(hnd);
}
if (err == X502_ERR_OK) {
hnd->iface_hnd = (const t_x502_dev_iface *)(devrec->internal->iface);
memcpy(hnd->info.serial, devrec->serial, X502_SERIAL_SIZE);
memcpy(hnd->info.name, devrec->devname, X502_DEVNAME_SIZE);
hnd->iface = devrec->iface;
hnd->info.devflags = devrec->flags;
err = hnd->iface_hnd->open(hnd, devrec);
if (err == X502_ERR_OK) {
X502_SetLChannel(hnd, 0, 0, X502_LCH_MODE_COMM, X502_ADC_RANGE_10, 0);
hnd->set.lch_cnt = 1;
hnd->set.adc_frame_delay = 0;
hnd->set.sync_mode = X502_SYNC_INTERNAL;
hnd->set.sync_start_mode = X502_SYNC_INTERNAL;
hnd->set.ext_ref_freq = 0;
hnd->streams = 0;
if (x502_is_E16(hnd)) {
hnd->set.ref_freq = E16_REF_FREQ_48000KHZ;
hnd->set.dac_range = E16_DAC_RANGE;
hnd->set.dac_code_max = E16_DAC_SCALE_CODE_MAX;
hnd->set.adc_code_max = E16_ADC_SCALE_CODE_MAX;
hnd->set.f_scales = f_e16_scales;
hnd->set.adc_freq_div = E16_REF_FREQ_48000KHZ / E16_ADC_FREQ_DEFAULT;
hnd->set.din_freq_div = E16_REF_FREQ_48000KHZ / E16_DIN_FREQ_DEFAULT;
hnd->set.out_freq_div = E16_REF_FREQ_48000KHZ / E16_OUT_FREQ_DEFAULT;
} else {
hnd->set.ref_freq = X502_REF_FREQ_2000KHZ;
hnd->set.dac_range = X502_DAC_RANGE;
hnd->set.dac_code_max = X502_DAC_SCALE_CODE_MAX;
hnd->set.adc_code_max = X502_ADC_SCALE_CODE_MAX;
hnd->set.f_scales = f_x502_scales;
hnd->set.adc_freq_div = 1;
hnd->set.din_freq_div = 1;
hnd->set.out_freq_div = 2;
}
hnd->flags = PRIV_FLAGS_OPENED;
if (err == X502_ERR_OK) {
hnd->mutex_bf = osspec_mutex_create();
if (hnd->mutex_bf == OSSPEC_INVALID_MUTEX)
err = X502_ERR_MUTEX_CREATE;
} else {
hnd->mutex_bf = OSSPEC_INVALID_MUTEX;
}
if (err == X502_ERR_OK) {
hnd->mutex_cfg = osspec_mutex_create();
if (hnd->mutex_cfg == OSSPEC_INVALID_MUTEX)
err = X502_ERR_MUTEX_CREATE;
}
if (err == X502_ERR_OK) {
if (!(hnd->info.devflags & X502_DEVFLAGS_FPGA_LOADED)) {
err = X502_ERR_FPGA_NOT_LOADED;
} else {
/* определяем - в каком режиме работаем (BF или FPGA) */
uint32_t bf_ctl;
err = hnd->iface_hnd->fpga_reg_read(hnd, X502_REGS_BF_CTL, &bf_ctl);
if (err == X502_ERR_OK) {
uint32_t mode = bf_ctl;
if (mode & X502_REGBIT_BF_CTL_DBG_MODE_Msk) {
hnd->mode = X502_MODE_DEBUG;
} else if (mode & X502_REGBIT_BF_CTL_DSP_MODE_Msk) {
hnd->mode = X502_MODE_DSP;
} else {
hnd->mode = X502_MODE_FPGA;
}
if (hnd->mode==X502_MODE_DSP) {
/* если blackfin находится в состоянии сброса, то возвращаемся в режим
FPGA, т.к. все команды к HostDMA все равно не выполнятся */
if (!(bf_ctl & X502_REGBIT_BF_CTL_BF_RESET_Msk)) {
err = X502_SetMode(hnd, X502_MODE_FPGA);
} else {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_BF_CMD, X502_BF_CMD_HDMA_RST);
/** @todo Для BlackFin проверить наличие прошивки */
}
}
}
/* проверка захвата PLL (сейчас невозможна в режиме DSP) */
if ((err == X502_ERR_OK) && (hnd->mode!=X502_MODE_DSP)) {
uint32_t val;
err = hnd->iface_hnd->fpga_reg_read(hnd, X502_REGS_IOHARD_IO_MODE, &val);
if (err == X502_ERR_OK) {
if (!(val & X502_REGBIT_ADC_SLV_CLK_LOCK_Msk)) {
err = X502_ERR_REF_FREQ_NOT_LOCKED;
}
}
}
/* читаем информацию о версии прошивки ПЛИС'ов и наличии опций */
if (err == X502_ERR_OK) {
uint32_t hard_id=0;
int32_t id_err = hnd->iface_hnd->fpga_reg_read(hnd, hnd->iface_hnd->id_reg_addr, &hard_id);
if (id_err == X502_ERR_OK) {
hnd->info.fpga_ver = (hard_id >> 16) & 0x7FFF;
hnd->info.plda_ver = (hard_id >> 4) & 0xF;
hnd->info.board_rev = (hard_id >> 8) & 0xF;
FILL_HARD_ID_FLAGS(hnd->info.devflags, hard_id);
}
}
/* если был запущен сбор - то останавливаем его */
if ((err == X502_ERR_OK) && (hnd->mode==X502_MODE_FPGA)) {
hnd->last_dout = 0;
if (hnd->iface_hnd->fpga_mode_init != NULL)
err = hnd->iface_hnd->fpga_mode_init(hnd);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_GO_SYNC_IO, 0);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_OUTSWAP_BFCTL, 0);
if ((err == X502_ERR_OK) && (hnd->iface_hnd->stream_running != NULL)) {
int32_t running;
unsigned ch;
for (ch=0; (ch < X502_STREAM_CH_CNT) && (err == X502_ERR_OK); ch++) {
err = hnd->iface_hnd->stream_running(hnd, ch, &running);
if ((err == X502_ERR_OK) && running) {
err = hnd->iface_hnd->stream_stop(hnd, ch, 0);
}
}
}
}
}
}
}
/* читаем информацию из EEPROM (в первую очередь -
калибровочные коэффициенты) */
if (err == X502_ERR_OK || err == X502_ERR_FPGA_NOT_LOADED) {
int i;
for (i=0; i < X502_ADC_RANGE_CNT; i++) {
hnd->info.cbr.adc[i].offs = 0;
hnd->info.cbr.adc[i].k = 1.;
}
for (i=0; i < X502_DAC_CH_CNT; i++) {
hnd->info.cbr.dac[i].offs = 0;
hnd->info.cbr.dac[i].k = 1;
}
x502_check_eeprom(hnd, 0);
}
/* записываем конфигурацию по умолчанию, чтобы быть уверенным,
что установлена нужная конфигурация */
if ((err == X502_ERR_OK) && (hnd->mode==X502_MODE_FPGA))
err = X502_Configure(hnd, 0);
//if (!err)
// err = _fpga_reg_write(hnd, L502_REGS_IOHARD_PRELOAD_ADC, 1);
if ((err != X502_ERR_OK) && (err != X502_ERR_FPGA_NOT_LOADED) && (err != X502_ERR_REF_FREQ_NOT_LOCKED))
X502_Close(hnd);
}
return err;
}
X502_EXPORT(int32_t) X502_Open(t_x502_hnd hnd, const char* serial,
const char *devname, t_x502_get_devinfo_list_cb get_list) {
int32_t err = X502_CHECK_HND(hnd);
int32_t get_info_res = 0;
uint32_t fnd_cnt;
if (err == X502_ERR_OK) {
get_info_res = get_list(NULL, 0, 0, &fnd_cnt);
if (get_info_res < 0) {
err = get_info_res;
} else if (!fnd_cnt) {
err = X502_ERR_DEVICE_NOT_FOUND;
}
}
if (err == X502_ERR_OK) {
t_x502_devrec *info_list = malloc(sizeof(t_x502_devrec)*fnd_cnt);
if (info_list==NULL) {
err = X502_ERR_MEMORY_ALLOC;
} else {
/* получаем информацию по всем устройствам драйвера lpcie */
get_info_res = get_list(info_list, fnd_cnt, 0, NULL);
if (get_info_res < 0) {
err = get_info_res;
} else {
int32_t i, ser_size=0, fnd=0, open_err = 0;
if (serial!=NULL) {
/* если серийный задан - смотрим его размер, отсекая
* все что начинается с признака кноца строки */
for (ser_size=0; (ser_size < X502_SERIAL_SIZE) &&
!((serial[ser_size]=='\0') ||
(serial[ser_size]=='\n') ||
(serial[ser_size]=='\r')); ser_size++)
{}
}
for (i=0; !fnd && (i < get_info_res); i++) {
/* ищем устройство L502 с совпадающим серийным */
if (((devname==NULL) || !strcmp(info_list[i].devname, devname)) &&
((ser_size==0) || !strncmp(serial, info_list[i].serial,
ser_size))) {
/* пробуем открыть устройство */
err = X502_OpenByDevRecord(hnd, &info_list[i]);
/* если серийный номер не был указан, то сохраняем
код ошибки и идем дальше, пробовать открыть
следующее устройство */
if (err && (ser_size==0)) {
open_err = err;
err = 0;
} else {
/* иначе заканчиваем поиск */
fnd = 1;
}
}
}
/* если не нашли устройство - устанавливаем соотвествующий код
ошибки */
if (!fnd) {
err = open_err ? open_err : X502_ERR_DEVICE_NOT_FOUND;
}
}
X502_FreeDevRecordList(info_list, fnd_cnt);
free(info_list);
}
}
return err;
}
X502_EXPORT(int32_t) X502_GetSerialList(char serials[][X502_SERIAL_SIZE], uint32_t size,
uint32_t flags, uint32_t *devcnt, const char *devname,
t_x502_get_devinfo_list_cb get_list) {
uint32_t fnd_cnt=0, put_cnt=0;
/* получаем количество устройств, поддерживаемых драйвером lpcie */
int32_t res = get_list(NULL, 0, flags, &fnd_cnt);
if ((res>=0) && fnd_cnt) {
t_x502_devrec *info_list = malloc(sizeof(t_x502_devrec)*fnd_cnt);
if (info_list==NULL) {
res = X502_ERR_MEMORY_ALLOC;
} else {
/* получаем информацию по всем устройствам драйвера lpcie */
res = get_list(info_list, fnd_cnt, flags, NULL);
if (res>0) {
int32_t i;
for (i=0; i < res; i++) {
/* проверяем, что это устройство - E502 */
if (!strcmp(info_list[i].devname, devname)) {
/* если есть место в списке, то сохраняем серийный номер
устройства */
if (put_cnt < size) {
memcpy(serials[put_cnt], info_list[i].serial,
X502_SERIAL_SIZE);
}
put_cnt++;
}
}
}
X502_FreeDevRecordList(info_list, fnd_cnt);
free(info_list);
}
}
if (devcnt != NULL)
*devcnt = put_cnt;
return res < 0 ? res : put_cnt > size ? (int32_t)size : (int32_t)put_cnt;
}
X502_EXPORT(int32_t) X502_FreeDevRecordList(t_x502_devrec *list, uint32_t size) {
uint32_t i;
int32_t err = X502_ERR_OK;
if (list!=NULL) {
for (i=0; (i < size) && (err==X502_ERR_OK); i++) {
if (list[i].sign!=X502_DEVREC_SIGN) {
err = X502_ERR_INVALID_DEVICE_RECORD;
} else {
t_x502_devrec_inptr *devinfo_ptr = (t_x502_devrec_inptr*)list[i].internal;
if (devinfo_ptr != NULL) {
const t_x502_dev_iface *iface = (const t_x502_dev_iface *)devinfo_ptr->iface;
if (iface!=NULL)
iface->free_devinfo_ptr(devinfo_ptr);
}
list[i].internal = NULL;
}
}
}
return err;
}
X502_EXPORT(int32_t) X502_GetDevInfo(t_x502_hnd hnd, t_x502_info* info) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (info==NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK)
*info = hnd->info;
return err;
}
X502_EXPORT(int32_t) X502_GetNextExpectedLchNum(t_x502_hnd hnd, uint32_t *lch) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (lch==NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK)
*lch = hnd->proc_adc_ch;
return err;
}
#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
X502_EXPORT(int32_t) X502_ProcessAdcData(t_x502_hnd hnd, const uint32_t* src, double *dest,
uint32_t *size, uint32_t flags) {
if (size == NULL)
return X502_ERR_INVALID_POINTER;
return X502_ProcessDataWithUserExt(hnd, src, *size, flags, dest, size,
NULL, NULL, NULL, NULL);
}
X502_EXPORT(int32_t) X502_ProcessData(t_x502_hnd hnd, const uint32_t *src, uint32_t size, uint32_t flags,
double *adc_data, uint32_t *adc_data_size,
uint32_t *din_data, uint32_t *din_data_size) {
return X502_ProcessDataWithUserExt(hnd, src, size, flags, adc_data, adc_data_size,
din_data, din_data_size, NULL, NULL);
}
X502_EXPORT(int32_t) X502_ProcessDataWithUserExt(t_x502_hnd hnd, const uint32_t* src, uint32_t size,
uint32_t flags, double *adc_data,
uint32_t *adc_data_size, uint32_t *din_data, uint32_t *din_data_size,
uint32_t *usr_data, uint32_t *usr_data_size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (adc_data_size==NULL) && (adc_data!=NULL))
err = X502_ERR_INVALID_POINTER;
if ((err == X502_ERR_OK) && (din_data_size==NULL) && (din_data!=NULL))
err = X502_ERR_INVALID_POINTER;
if ((err == X502_ERR_OK) && (usr_data_size==NULL) && (usr_data!=NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK) {
uint32_t adc_cnt = 0, din_cnt=0, usr_cnt = 0;
uint32_t i;
for (i=0; (i<size) && (err == X502_ERR_OK); i++) {
register uint32_t wrd = src[i];
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(wrd);
/* проверяем - это данные от АЦП или цифровых входов */
switch (type) {
case STREAM_IN_WRD_ADC: {
uint32_t ch_num = (wrd >> 24) & 0xF;
uint32_t ch_mode = (wrd >> 28) & 0x3;
int32_t val;
uint32_t range;
/* проверяем совпадение каналов */
switch (ch_mode) {
case 0:
ch_mode = X502_LCH_MODE_DIFF;
break;
case 1:
ch_mode = X502_LCH_MODE_COMM;
break;
case 2:
ch_mode = X502_LCH_MODE_COMM;
ch_num+=16;
break;
case 3:
ch_mode = X502_LCH_MODE_ZERO;
break;
}
if (!(flags & X502_PROC_FLAGS_DONT_CHECK_CH) &&
((hnd->set.lch[hnd->proc_adc_ch].mode != ch_mode) ||
(hnd->set.lch[hnd->proc_adc_ch].ch != ch_num))) {
err = X502_ERR_PROC_INVALID_CH_NUM;
} else {
/* проверяем формат - пришло откалиброванное 24-битное слово,
или неоткалиброванное 16-битное */
if (wrd & 0x40000000) {
val = wrd & 0xFFFFFF;
if (wrd & 0x800000)
val |= 0xFF000000;
range = hnd->set.lch[hnd->proc_adc_ch].range;
} else {
range = (wrd >> 16) & 0x7;
if (!(flags & X502_PROC_FLAGS_DONT_CHECK_CH) &&
(range != hnd->set.lch[hnd->proc_adc_ch].range)) {
err = X502_ERR_PROC_INVALID_CH_RANGE;
} else {
val = wrd & 0xFFFF;
if (wrd & 0x8000)
val |= 0xFFFF0000;
}
}
}
if (err == X502_ERR_OK) {
double res_val = val;
if (flags & X502_PROC_FLAGS_VOLT) {
res_val = hnd->set.f_scales[range]*res_val/hnd->set.adc_code_max;
}
if ((adc_data!=NULL) && (adc_cnt<*adc_data_size)) {
*adc_data++ = res_val;
adc_cnt++;
} else if (adc_data==NULL) {
adc_cnt++;
}
if (++hnd->proc_adc_ch ==hnd->set.lch_cnt)
hnd->proc_adc_ch = 0;
}
}
break;
case STREAM_IN_WRD_DIN:
if ((din_data!=NULL) && (din_cnt<*din_data_size)) {
*din_data++ = wrd & 0x3FFFF;
din_cnt++;
} else if (din_data==NULL) {
din_cnt++;
}
break;
case STREAM_IN_WRD_MSG:
err = wrd==X502_STREAM_IN_MSG_OVERFLOW ? X502_ERR_STREAM_OVERFLOW :
X502_ERR_UNSUP_STREAM_MSG;
break;
case STREAM_IN_WRD_USR:
if ((usr_data!=NULL) && (usr_cnt<*usr_data_size)) {
*usr_data++ = wrd;
usr_cnt++;
} else if (usr_data==NULL) {
usr_cnt++;
}
break;
default:
break;
}
}
if (adc_data_size!=NULL)
*adc_data_size = adc_cnt;
if (din_data_size!=NULL)
*din_data_size = din_cnt;
if (usr_data_size!=NULL)
*usr_data_size = usr_cnt;
}
return err;
}
uint32_t prepare_dac_wrd(t_x502_hnd hnd, double val, uint32_t flags, const t_x502_cbr_coef* coef) {
uint16_t wrd = 0;
if (flags & X502_DAC_FLAGS_VOLT) {
val = (val / hnd->set.dac_range) * hnd->set.dac_code_max;
}
if (flags & X502_DAC_FLAGS_CALIBR) {
val = (val + coef->offs) * coef->k;
}
if (val > SHRT_MAX) {
wrd = SHRT_MAX;
} else
if (val < SHRT_MIN) {
wrd = SHRT_MIN;
} else {
wrd = val;
}
return wrd;
}
X502_EXPORT(int32_t) X502_PrepareData(t_x502_hnd hnd, const double* dac1, const double* dac2,
const uint32_t* digout, uint32_t size, int32_t flags,
uint32_t* out_buf) {
int err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (out_buf==NULL))
err = X502_ERR_INVALID_POINTER;
if ((err == X502_ERR_OK) && ((dac1==NULL) && (dac2==NULL) && (digout==NULL)))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK) {
uint32_t i;
for (i = 0; (i < size) && (err == X502_ERR_OK); i++) {
if ((dac1 != NULL) && (hnd->streams & X502_STREAM_DAC1)) {
uint32_t wrd = prepare_dac_wrd(hnd, *dac1++, flags, &hnd->info.cbr.dac[0]);
*out_buf++ = wrd | X502_STREAM_OUT_WORD_TYPE_DAC1;
}
if ((dac2 != NULL) && (hnd->streams & X502_STREAM_DAC2)) {
uint32_t wrd = prepare_dac_wrd(hnd, *dac2++, flags, &hnd->info.cbr.dac[1]);
*out_buf++ = wrd | X502_STREAM_OUT_WORD_TYPE_DAC2;
}
if ((digout != NULL) && (hnd->streams & X502_STREAM_DOUT)) {
uint32_t wrd = *digout++;
*out_buf++ = (wrd &0x3FFFF)
| X502_STREAM_OUT_WORD_TYPE_DOUT;
}
}
}
return err;
}
X502_EXPORT(int32_t) X502_FpgaRegWrite(t_x502_hnd hnd, uint32_t reg, uint32_t val) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->fpga_reg_write(hnd, reg & 0xFFFF, val);
}
return err;
}
X502_EXPORT(int32_t) X502_FpgaRegRead(t_x502_hnd hnd, uint32_t reg, uint32_t *val) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->fpga_reg_read(hnd, reg, val);
}
return err;
}
X502_EXPORT(uint32_t) X502_GetLibraryVersion(void) {
return (X502API_VER_MAJOR << 24) | (X502API_VER_MINOR<<16) |
(X502API_VER_PATCH << 8);
}
X502_EXPORT(int32_t) X502_DevRecordInit(t_x502_devrec *rec) {
if (rec!=NULL) {
memset(rec, 0, sizeof(t_x502_devrec));
rec->sign = X502_DEVREC_SIGN;
}
return X502_ERR_OK;
}
X502_EXPORT(int32_t) X502_LedBlink(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
int32_t err2;
err = hnd->mode == X502_MODE_DSP ? bf_fpga_reg_wr(hnd, X502_REGS_IOHARD_LED, 0) :
X502_FpgaRegWrite(hnd, X502_REGS_IOHARD_LED, 0);
SLEEP_MS(200);
err2 = hnd->mode == X502_MODE_DSP ? bf_fpga_reg_wr(hnd, X502_REGS_IOHARD_LED, 1) :
X502_FpgaRegWrite(hnd, X502_REGS_IOHARD_LED, 1);
if (err == X502_ERR_OK)
err = err2;
}
return err;
}
X502_EXPORT(int32_t) X502_SetDigInPullup(t_x502_hnd hnd, uint32_t pullups) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
uint32_t val = 0;
if (pullups & X502_PULLUPS_DI_L)
val |= 0x1;
if (pullups & X502_PULLUPS_DI_H)
val |= 0x2;
if (pullups & X502_PULLUPS_DI_SYN1)
val |= 0x4;
if (pullups & X502_PULLUPS_DI_SYN2)
val |= 0x8;
if (pullups & X502_PULLDOWN_CONV_IN)
val |= 0x10;
if (pullups & X502_PULLDOWN_START_IN)
val |= 0x20;
if (pullups & E16_MODE_RELAY_ON)
val |= 0x40;
err = hnd->mode == X502_MODE_DSP ? bf_fpga_reg_wr(hnd, X502_REGS_IOHARD_DIGIN_PULLUP, val) :
X502_FpgaRegWrite(hnd, X502_REGS_IOHARD_DIGIN_PULLUP, val);
}
return err;
}
X502_EXPORT(int32_t) X502_CheckFeature(t_x502_hnd hnd, uint32_t feature) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->check_feature(hnd, feature);
}
return err;
}
#ifdef _WIN32
BOOL WINAPI DllMain(HINSTANCE hmod, DWORD reason, LPVOID resvd) {
switch (reason) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#endif

2700
lib/x502/x502api.h Normal file

File diff suppressed because it is too large Load Diff

143
lib/x502/x502api_async.c Normal file
View File

@ -0,0 +1,143 @@
#include "x502api_private.h"
#include "ltimer.h"
uint32_t prepare_dac_wrd(t_x502_hnd hnd, double val, uint32_t flags, const t_x502_cbr_coef* coef);
X502_EXPORT(int32_t) X502_AsyncOutDac(t_x502_hnd hnd, uint32_t ch, double data, uint32_t flags) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (ch!=X502_DAC_CH1) && (ch!=X502_DAC_CH2))
err = X502_ERR_INVALID_DAC_CHANNEL;
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_DAC_PRESENT))
err = X502_ERR_DAC_NOT_PRESENT;
if (!err) {
uint32_t wr_val = prepare_dac_wrd(hnd, data, flags, &hnd->info.cbr.dac[ch]);
if (ch==X502_DAC_CH1) {
wr_val |= X502_STREAM_OUT_WORD_TYPE_DAC1;
} else {
wr_val |= X502_STREAM_OUT_WORD_TYPE_DAC2;
}
if (hnd->mode == X502_MODE_FPGA) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_ASYNC_OUT, wr_val);
} else if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_ASYNC_OUT, ch==X502_DAC_CH1 ?
L502_BF_CMD_ASYNC_TYPE_DAC1 : L502_BF_CMD_ASYNC_TYPE_DAC2,
(uint32_t*)&wr_val, 1, NULL, 0, X502_BF_CMD_DEFAULT_TOUT, NULL);
} else {
err = X502_ERR_INVALID_MODE;
}
}
return err;
}
X502_EXPORT(int32_t) X502_AsyncOutDig(t_x502_hnd hnd, uint32_t val, uint32_t msk) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err) {
if(hnd->mode == X502_MODE_FPGA) {
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (!err) {
int32_t release_err;
/* маскированные биты берем из последнего выведенного значения */
if (msk) {
val = val & ~msk;
val |= hnd->last_dout & msk;
}
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_ASYNC_OUT,
val | X502_STREAM_OUT_WORD_TYPE_DOUT);
/* сохраняем выведенное значения, для последующего использования
в маске */
if (!err)
hnd->last_dout = val;
release_err = osspec_mutex_release(hnd->mutex_cfg);
if (!err)
err = release_err;
}
} else if (hnd->mode == X502_MODE_DSP) {
uint32_t wrds[2] = {val, msk};
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_ASYNC_OUT, L502_BF_CMD_ASYNC_TYPE_DOUT,
wrds, 2, NULL, 0, X502_BF_CMD_DEFAULT_TOUT, NULL);
} else {
err = X502_ERR_INVALID_MODE;
}
}
return err;
}
static int32_t f_read_digin(t_x502_hnd hnd, uint32_t* din) {
int32_t err = 0;
uint32_t val;
int rdy=0;
t_ltimer tmr;
/* читаем состояние входов, чтобы сбросить флаг готовности */
if (!x502_is_E16(hnd)) {
err = hnd->iface_hnd->fpga_reg_read(hnd, X502_REGS_IOARITH_DIN_ASYNC, &val);
}
/* читаем синхронный ввод до готовности данных или пока не
выйдем по таймауту*/
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(500));
while (!rdy && !ltimer_expired(&tmr) && (err == X502_ERR_OK)) {
err = hnd->iface_hnd->fpga_reg_read(hnd, X502_REGS_IOARITH_DIN_ASYNC, &val);
if (!err && (val & 0x80000000)) {
rdy = 1;
*din = (val & 0x3FFFF);
}
}
if (!err && !rdy)
err = X502_ERR_DIG_IN_NOT_RDY;
return err;
}
X502_EXPORT(int32_t) X502_AsyncInDig(t_x502_hnd hnd, uint32_t* din) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err & (din==NULL))
err = X502_ERR_INVALID_POINTER;
if (!err)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (!err) {
if (x502_is_E16(hnd)) {
err = f_read_digin(hnd, din);
} else if (hnd->mode == X502_MODE_FPGA) {
if (hnd->flags & PRIV_FLAGS_STREAM_RUN) {
err = f_read_digin(hnd, din);
} else {
/* запрещаем прием данных */
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOARITH_IN_STREAM_ENABLE, 0);
if (!err) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_PRELOAD_ADC, 1);
if (!err) {
/* запускаем чтение цифровых входов */
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_GO_SYNC_IO, 1);
}
}
if (!err) {
int32_t stop_err;
err = f_read_digin(hnd, din);
/* останавливаем сбор данных */
stop_err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_GO_SYNC_IO, 0);
if (!err)
err = stop_err;
}
}
} else if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_ASYNC_DIG_IN,
0, NULL, 0, din, 1, X502_BF_CMD_DEFAULT_TOUT, NULL);
} else {
err = X502_ERR_INVALID_MODE;
}
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}

391
lib/x502/x502api_bf.c Normal file
View File

@ -0,0 +1,391 @@
#include "x502api_private.h"
#include "ltimer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BF_LDR_HDR_SIZE (16)
#define BF_LDR_HDRSGN (0xAD)
#define BF_LDR_HDRPOS_SGN (3)
#define BF_LDR_FLAG_SAVE (0x0010) //не используется
#define BF_LDR_FLAG_AUX (0x0020) //не используется
#define BF_LDR_FLAG_FILL (0x0100)
#define BF_LDR_FLAG_QUICKBOOT (0x0200) //не используется
#define BF_LDR_FLAG_CALLBACK (0x0400) //не используется
#define BF_LDR_FLAG_INIT (0x0800) //не используется
#define BF_LDR_FLAG_IGNORE (0x1000)
#define BF_LDR_FLAG_INDIRECT (0x2000) //не используется
#define BF_LDR_FLAG_FIRST (0x4000)
#define BF_LDR_FLAG_FINAL (0x8000)
#define BF_WAIT_LOAD_RDY_TOUT 500
#define BF_MUTEX_LOCK_TOUT 1000
#define LDR_BUFF_SIZE 4096
#define BF_CHECK_ADDR(addr) (((addr) < 0xFFA0C000) && ((addr)>= 0xFFA0000)) || \
(((addr) < 0xFF908000) && ((addr) >=0xFF900000)) || \
(((addr) < 0xFF808000) && ((addr) >=0xFF800000)) || \
(((addr) < 0x2000000)) ? 0 : X502_ERR_BF_INVALID_ADDR
#define BF_CHECK_ADDR_SIZE(addr, size) BF_CHECK_ADDR(addr) ? X502_ERR_BF_INVALID_ADDR : \
BF_CHECK_ADDR(addr+size*4-1) ? X502_ERR_BF_INVALID_ADDR : 0
#define BF_CMD_FIRST_DATA_BLOCK_SIZE ((X502_BF_REQ_DATA_SIZE_MAX-offsetof(t_l502_bf_cmd, data))/4)
typedef struct st_bf_ldr_pkt {
uint8_t res;
uint8_t dma_mode;
uint16_t flags;
uint32_t addr;
uint32_t size;
uint32_t arg;
} t_bf_ldr_pkt;
/* Разбираем заголовок блока LDR-формата из буфера размером BF_LDR_HDR_SIZE
и сохраняем параметры в структуре pkt */
int f_parse_ldr_hdr(const uint8_t* hdr, t_bf_ldr_pkt* pkt) {
int err = 0;
uint32_t* pdw_buff = (uint32_t*)hdr;
uint8_t xor_ch = 0;
int i;
for (i=0; i < BF_LDR_HDR_SIZE; i++) {
xor_ch ^= hdr[i];
}
if ((xor_ch!=0) || (hdr[BF_LDR_HDRPOS_SGN] != BF_LDR_HDRSGN)) {
err = X502_ERR_LDR_FILE_FORMAT;
} else {
pkt->res = 0;
pkt->dma_mode = pdw_buff[0]&0xF;
pkt->flags = pdw_buff[0]&0xFFF0;
pkt->addr = pdw_buff[1];
pkt->size = pdw_buff[2];
pkt->arg = pdw_buff[3];
if ((pkt->flags & BF_LDR_FLAG_INIT) && (pkt->flags & BF_LDR_FLAG_FILL))
err = X502_ERR_LDR_FILE_FORMAT;
else if (pkt->flags & (BF_LDR_FLAG_CALLBACK | BF_LDR_FLAG_INDIRECT | BF_LDR_FLAG_INIT))
err = X502_ERR_LDR_FILE_UNSUP_FEATURE;
else if ((pkt->flags & BF_LDR_FLAG_INIT) && (pkt->addr != 0xFFA00000))
err = X502_ERR_LDR_FILE_UNSUP_STARTUP_ADDR;
}
return err;
}
static int32_t f_bf_mem_wr(t_x502_hnd hnd, uint32_t addr, const uint32_t* regs, uint32_t size) {
int32_t err = 0;
/* данные записываем блоками по L502_BF_REQ_DATA_SIZE */
while (!err && size) {
int put_size = (size < hnd->iface_hnd->bf_mem_block_size) ? size :
hnd->iface_hnd->bf_mem_block_size;
err = hnd->iface_hnd->bf_mem_block_wr(hnd, addr, regs, put_size);
if (!err) {
size -= put_size;
regs += put_size;
addr += put_size*4;
}
}
return err;
}
static int32_t f_bf_mem_rd(t_x502_hnd hnd, uint32_t addr, uint32_t* regs, uint32_t size) {
int err = 0;
while (!err && size) {
int get_size = (size < hnd->iface_hnd->bf_mem_block_size) ? size :
hnd->iface_hnd->bf_mem_block_size;
err = hnd->iface_hnd->bf_mem_block_rd(hnd, addr, regs, get_size);
if (!err) {
size -= get_size;
regs += get_size;
addr += get_size*4;
}
}
return err;
}
int32_t bf_fpga_reg_wr(t_x502_hnd hnd, uint32_t addr, uint32_t val) {
int32_t err = hnd->mode != X502_MODE_DSP ? X502_ERR_INVALID_MODE :
(hnd->bf_features & L502_BF_FEATURE_FPGA_REG_ACCESS) ?
X502_ERR_OK : X502_ERR_NOT_IMPLEMENTED;
if (err == X502_ERR_OK) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_FPGA_REG_WR, addr, &val, 1, NULL, 0,
X502_BF_CMD_DEFAULT_TOUT, NULL);
}
return err;
}
int32_t bf_fpga_reg_rd(t_x502_hnd hnd, uint32_t addr, uint32_t* val) {
int32_t err = hnd->mode != X502_MODE_DSP ? X502_ERR_INVALID_MODE :
(hnd->bf_features & L502_BF_FEATURE_FPGA_REG_ACCESS) ?
X502_ERR_OK : X502_ERR_NOT_IMPLEMENTED;
if (err == X502_ERR_OK) {
uint32_t recvd;
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_FPGA_REG_RD, addr, NULL, 0, val, 1,
X502_BF_CMD_DEFAULT_TOUT, &recvd);
if ((err == X502_ERR_OK) && (recvd < 1)) {
err = X502_ERR_BF_CMD_RETURN_INSUF_DATA;
}
}
return err;
}
static int32_t f_check_bf_firm(t_x502_hnd hnd) {
int32_t err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_BF_CMD, X502_BF_CMD_HDMA_RST);
if (!err) {
uint32_t rcv_wrds[2], recvd;
/* Проверяем версию прошивки BlackFin */
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_GET_PARAM, L502_BF_PARAM_FIRM_VERSION,
NULL, 0, rcv_wrds, 2, X502_BF_CMD_DEFAULT_TOUT, &recvd);
if (!err) {
if (recvd >= 1) {
hnd->bf_ver = rcv_wrds[0];
} else {
err = X502_ERR_BF_CMD_RETURN_INSUF_DATA;
}
hnd->bf_features = recvd >= 2 ? rcv_wrds[1] : 0;
}
}
/* Проверка состояния прошивки (запущен поток сбора или нет) */
if (!err) {
uint32_t mode, streams;
err = x502_bf_get_par(hnd, L502_BF_PARAM_STREAM_MODE, &mode, 1);
if (!err)
err = x502_bf_get_par(hnd, L502_BF_PARAM_ENABLED_STREAMS, &streams, 1);
if (!err) {
err = osspec_mutex_lock(hnd->mutex_cfg, BF_MUTEX_LOCK_TOUT);
if (!err) {
if (mode==L502_BF_MODE_IDLE) {
hnd->flags &= ~PRIV_FLAGS_STREAM_RUN;
} else {
hnd->flags |= PRIV_FLAGS_STREAM_RUN;
}
hnd->streams = streams;
osspec_mutex_release(hnd->mutex_cfg);
}
}
}
/* передаем информацию о модуле */
if (!err && !(hnd->flags & PRIV_FLAGS_STREAM_RUN)) {
uint32_t put_wrds[3];
uint32_t ch;
put_wrds[0] = hnd->info.devflags;
put_wrds[1] = hnd->info.fpga_ver | ((uint32_t)hnd->info.plda_ver<<16);
err = x502_bf_set_par(hnd, L502_BF_PARAM_MODULE_INFO, put_wrds, 2);
for (ch=0; !err && (ch < X502_DAC_CH_CNT); ch++) {
float* pk = (float*)&put_wrds[1];
float* po = (float*)&put_wrds[2];
put_wrds[0] = ch;
*pk = (float)hnd->info.cbr.dac[ch].k;
*po = (float)hnd->info.cbr.dac[ch].offs;
err = x502_bf_set_par(hnd, L502_BF_PARAM_DAC_COEF, put_wrds, 3);
}
}
if (!err && (hnd->mode!=X502_MODE_DSP))
err = X502_SetMode(hnd, X502_MODE_DSP);
return err;
}
X502_EXPORT(int32_t) X502_BfCheckFirmwareIsLoaded(t_x502_hnd hnd, uint32_t *version) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err) {
err = f_check_bf_firm(hnd);
if (!err && version)
*version = hnd->bf_ver;
}
return err;
}
X502_EXPORT(int32_t) X502_BfLoadFirmware(t_x502_hnd hnd, const char* filename) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;
if (!err) {
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
err = hnd->iface_hnd->bf_firm_load(hnd, filename);
osspec_mutex_release(hnd->mutex_bf);
}
}
if (!err) {
SLEEP_MS(100);
err = f_check_bf_firm(hnd);
}
return err;
}
X502_EXPORT(int32_t) X502_BfMemWrite(t_x502_hnd hnd, uint32_t addr,
const uint32_t* regs, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;;
if (!err)
err = BF_CHECK_ADDR_SIZE(addr, size);
if (!err)
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
int32_t release_err;
err = f_bf_mem_wr(hnd, addr, regs, size);
release_err = osspec_mutex_release(hnd->mutex_bf);
if (!err)
err = release_err;
}
return err;
}
X502_EXPORT(int32_t) X502_BfMemRead(t_x502_hnd hnd, uint32_t addr,
uint32_t* regs, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;
if (!err)
err = BF_CHECK_ADDR_SIZE(addr,size);
if (!err)
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
int32_t release_err;
err = f_bf_mem_rd(hnd, addr, regs, size);
release_err = osspec_mutex_release(hnd->mutex_bf);
if (!err)
err = release_err;
}
return err;
}
static int f_bf_start_cmd(t_x502_hnd hnd, uint16_t cmd_code, uint32_t par,
const uint32_t* data, uint32_t size) {
int err = X502_CHECK_HND_OPENED(hnd);
if (!err && !(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT))
err = X502_ERR_BF_NOT_PRESENT;
if (size > L502_BF_CMD_DATA_SIZE_MAX)
err = X502_ERR_BF_INVALID_CMD_DATA_SIZE;
if (!err)
err = osspec_mutex_lock(hnd->mutex_bf, BF_MUTEX_LOCK_TOUT);
if (!err) {
t_l502_bf_cmd cmd;
cmd.code = cmd_code;
cmd.data_size = size;
cmd.param = par;
cmd.result = 0;
cmd.status = L502_BF_CMD_STATUS_REQ;
if (size!=0) {
memcpy(cmd.data, data, size*sizeof(data[0]));
}
/* если размер больше, чем можем записать за раз, то сперва записываем
* хвост, чтобы не получилось, что информация о команде будет записана
* раньше данных */
if (size > BF_CMD_FIRST_DATA_BLOCK_SIZE) {
err = f_bf_mem_wr(hnd, X502_BF_MEMADDR_CMD+X502_BF_REQ_DATA_SIZE_MAX*4,
&cmd.data[BF_CMD_FIRST_DATA_BLOCK_SIZE],
size - BF_CMD_FIRST_DATA_BLOCK_SIZE);
size = BF_CMD_FIRST_DATA_BLOCK_SIZE;
}
if (!err) {
err = f_bf_mem_wr(hnd, X502_BF_MEMADDR_CMD, (const uint32_t*)&cmd,
(offsetof(t_l502_bf_cmd, data))/4 + size);
}
if (err) {
osspec_mutex_release(hnd->mutex_bf);
}
}
return err;
}
static int f_bf_cmd_check(t_x502_hnd hnd, int32_t *res) {
t_l502_bf_cmd cmd;
int err = f_bf_mem_rd(hnd, X502_BF_MEMADDR_CMD, (uint32_t*)&cmd,
X502_BF_REQ_DATA_SIZE_MIN);
if (!err) {
if (cmd.status != L502_BF_CMD_STATUS_DONE) {
err = X502_ERR_BF_CMD_IN_PROGRESS;
} else if (res) {
*res = cmd.result;
}
}
if (err != X502_ERR_BF_CMD_IN_PROGRESS)
osspec_mutex_release(hnd->mutex_bf);
return err;
}
X502_EXPORT(int32_t) X502_BfExecCmd(t_x502_hnd hnd, uint16_t cmd_code, uint32_t par,
const uint32_t* snd_data, uint32_t snd_size,
uint32_t* rcv_data, uint32_t rcv_size, uint32_t tout,
uint32_t* recvd_size) {
t_l502_bf_cmd cmd;
int done = 0;
t_ltimer tmr;
int err;
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout));
err = f_bf_start_cmd(hnd, cmd_code, par, snd_data, snd_size);
while (!err && !done) {
err = f_bf_cmd_check(hnd, &cmd.result);
if (!err) {
done = 1;
if (rcv_size != 0) {
err = X502_BfMemRead(hnd, X502_BF_MEMADDR_CMD, (uint32_t*)&cmd,
(offsetof(t_l502_bf_cmd, data))/4 + rcv_size);
memcpy(rcv_data, cmd.data, rcv_size*sizeof(rcv_data[0]));
if (recvd_size!=NULL)
*recvd_size = cmd.data_size;
}
if (!err)
err = cmd.result;
} else if (err==X502_ERR_BF_CMD_IN_PROGRESS) {
if (ltimer_expired(&tmr)) {
err = X502_ERR_BF_CMD_TIMEOUT;
osspec_mutex_release(hnd->mutex_bf);
} else {
err = 0;
SLEEP_MS(20);
}
}
}
return err;
}

795
lib/x502/x502api_config.c Normal file
View File

@ -0,0 +1,795 @@
#include "x502api_private.h"
#include "x502_fpga_regs.h"
#define SYNC_FREQ_CODE(mode) ((mode == X502_SYNC_DI_SYN2_RISE) ? X502_SYNC_DI_SYN1_FALL : \
(mode == X502_SYNC_DI_SYN1_FALL) ? X502_SYNC_DI_SYN2_RISE : mode)
#define CHECK_SYNC_MODE(mode) (((mode)) != X502_SYNC_INTERNAL) \
&& ((mode)!=X502_SYNC_EXTERNAL_MASTER) \
&& ((mode)!=X502_SYNC_DI_SYN1_RISE) \
&& ((mode)!=X502_SYNC_DI_SYN2_RISE) \
&& ((mode)!=X502_SYNC_DI_SYN1_FALL) \
&& ((mode)!=X502_SYNC_DI_SYN2_FALL) \
? X502_ERR_INVALID_SYNC_MODE : X502_ERR_OK
/** Максимальное значения частоты АЦП для варианта E16*/
#define E16_ADC_FREQ_MAX 1000000
/** Максимальное значения частоты DIN для варианта E16*/
#define E16_DIN_FREQ_MAX 1000000
/** Максимальное значения частоты OUT для варианта E16*/
#define E16_OUT_FREQ_MAX 1000000
static const uint16_t f_regadd_k[X502_ADC_RANGE_CNT] = {X502_REGS_IOARITH_K10,
X502_REGS_IOARITH_K5,
X502_REGS_IOARITH_K2,
X502_REGS_IOARITH_K1,
X502_REGS_IOARITH_K05,
X502_REGS_IOARITH_K02};
static const uint16_t f_regadd_offs[X502_ADC_RANGE_CNT] = {X502_REGS_IOARITH_B10,
X502_REGS_IOARITH_B5,
X502_REGS_IOARITH_B2,
X502_REGS_IOARITH_B1,
X502_REGS_IOARITH_B05,
X502_REGS_IOARITH_B02};
static uint32_t f_get_out_freq_div_min(double ref_freq) {
return ref_freq > X502_OUT_FREQ_REF_LF_VAL ? X502_OUT_FREQ_DIV_MIN : X502_OUT_FREQ_DIV_MIN_REF_LF;
}
X502_EXPORT(int32_t) X502_SetLChannel(t_x502_hnd hnd, uint32_t lch, uint32_t phy_ch,
uint32_t mode, uint32_t range, uint32_t avg) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
/* Для измерения собственного нуля номер канала не имеет значения */
if (mode == X502_LCH_MODE_ZERO)
phy_ch = 0;
if ((mode != X502_LCH_MODE_COMM) && (mode != X502_LCH_MODE_DIFF) &&
(mode != X502_LCH_MODE_ZERO)) {
err = X502_ERR_INVALID_LCH_MODE;
} else if ((phy_ch >= X502_ADC_COMM_CH_CNT) ||
((mode == X502_LCH_MODE_DIFF) && (phy_ch >= X502_ADC_DIFF_CH_CNT))) {
err = X502_ERR_INVALID_LCH_PHY_NUMBER;
} else if (range >= X502_ADC_RANGE_CNT) {
err = X502_ERR_INVALID_LCH_RANGE;
} else if (avg > X502_LCH_AVG_SIZE_MAX) {
err = X502_ERR_INVALID_LCH_AVG_SIZE;
}
if (!err) {
hnd->set.lch[lch].ch = phy_ch;
hnd->set.lch[lch].range = range;
hnd->set.lch[lch].mode = mode;
hnd->set.lch[lch].avg = avg;
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetLChannelCount(t_x502_hnd hnd, uint32_t lch_cnt) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
if (lch_cnt > X502_LTABLE_MAX_CH_CNT) {
err = X502_ERR_INVALID_LTABLE_SIZE;
} else if (x502_is_E16(hnd) && lch_cnt > E16_LTABLE_MAX_CH_CNT) {
err = X502_ERR_INVALID_LTABLE_SIZE;
} else {
hnd->set.lch_cnt = lch_cnt;
}
}
return err;
}
X502_EXPORT(int32_t) X502_GetLChannelCount(t_x502_hnd hnd, uint32_t* lch_cnt) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (lch_cnt==NULL))
err = X502_ERR_INVALID_POINTER;
if (!err)
*lch_cnt = hnd->set.lch_cnt;
return err;
}
X502_EXPORT(int32_t) X502_SetAdcFreqDivider(t_x502_hnd hnd, uint32_t adc_freq_div) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
if ((adc_freq_div==0) ||
(x502_is_E16(hnd) && adc_freq_div > E16_ADC_FREQ_DIV_MAX) ||
(!x502_is_E16(hnd) && adc_freq_div > X502_ADC_FREQ_DIV_MAX)) {
err = X502_ERR_INVALID_ADC_FREQ_DIV;
} else {
hnd->set.adc_freq_div = adc_freq_div;
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetAdcInterframeDelay(t_x502_hnd hnd, uint32_t delay) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err && (delay > X502_ADC_INTERFRAME_DELAY_MAX))
err = X502_ERR_INVALID_INTERFRAME_DELAY;
if (!err) {
hnd->set.adc_frame_delay = delay;
}
return err;
}
X502_EXPORT(int32_t) X502_SetDinFreqDivider(t_x502_hnd hnd, uint32_t din_freq_div) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
if ((din_freq_div==0) ||
(x502_is_E16(hnd) && din_freq_div > E16_DIN_FREQ_DIV_MAX) ||
(!x502_is_E16(hnd) && din_freq_div > X502_DIN_FREQ_DIV_MAX)) {
err = X502_ERR_INVALID_ADC_FREQ_DIV;
} else {
hnd->set.din_freq_div = din_freq_div;
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetOutFreqDivider(t_x502_hnd hnd, uint32_t out_freq_div) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
/* Проверяем, поддерживается ли возможность установить значение, отличное от стандартного */
if (out_freq_div != X502_OUT_FREQ_DIV_DEFAULT) {
err = X502_CheckFeature(hnd, X502_FEATURE_OUT_FREQ_DIV);
}
}
if (!err) {
double ref_freq;
X502_GetRefFreqValue(hnd, &ref_freq);
if ((out_freq_div < f_get_out_freq_div_min(ref_freq)) ||
(x502_is_E16(hnd) && out_freq_div > E16_OUT_FREQ_DIV_MAX) ||
(!x502_is_E16(hnd) && out_freq_div > X502_OUT_FREQ_DIV_MAX)) {
err = X502_ERR_INVALID_OUT_FREQ_DIV;
} else {
hnd->set.out_freq_div = out_freq_div;
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetMode(t_x502_hnd hnd, uint32_t mode) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err && (mode==X502_MODE_DSP) &&
!(hnd->info.devflags & X502_DEVFLAGS_BF_PRESENT)) {
err = X502_ERR_BF_NOT_PRESENT;
}
if (!err) {
uint32_t val;
err = hnd->iface_hnd->fpga_reg_read(hnd, X502_REGS_BF_CTL, &val);
if (!err) {
val &= ~(X502_REGBIT_BF_CTL_CLK_DIV_Msk | X502_REGBIT_BF_CTL_DBG_MODE_Msk | X502_REGBIT_BF_CTL_DSP_MODE_Msk);
if (mode==X502_MODE_DSP) {
/* в DSP режиме сброс должен быть снят с blackfin, иначе не будут работать
команды по HostDMA */
val |= X502_REGBIT_BF_CTL_DSP_MODE_Msk | X502_REGBIT_BF_CTL_BF_RESET_Msk;
} else if (mode==X502_MODE_DEBUG) {
val |= X502_REGBIT_BF_CTL_DBG_MODE_Msk;
} else if (mode!=X502_MODE_FPGA) {
err = X502_ERR_INVALID_MODE;
}
}
if (!err)
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_BF_CTL, val);
/* при переходе в режим DSP сбрасываем автомат HDMA */
if (!err && (mode==X502_MODE_DSP))
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_BF_CMD, X502_BF_CMD_HDMA_RST);
if (!err)
hnd->mode = mode;
}
return err;
}
X502_EXPORT(int32_t) X502_GetMode(t_x502_hnd hnd, uint32_t* mode) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (mode==NULL))
err = X502_ERR_INVALID_POINTER;
if (!err) {
*mode = hnd->mode;
}
return err;
}
#define IS_E16_FREQ(hnd, ref_freq) ((hnd && x502_is_E16(hnd)) || (uint32_t)ref_freq == E16_REF_FREQ_48000KHZ)
X502_EXPORT(int32_t) X502_CalcAdcFreq2(t_x502_hnd hnd, double ref_freq, uint32_t lch_cnt, double *f_acq,
double *f_frame, uint32_t *adc_freq_div, uint32_t *adc_frame_delay) {
int32_t err = (f_acq==NULL) ? X502_ERR_INVALID_POINTER : X502_ERR_OK;
if (err == X502_ERR_OK) {
uint32_t cur_adc_freq_div, cur_frame_delay = 0;
uint32_t div_max = X502_ADC_FREQ_DIV_MAX;
double set_freq = *f_acq;
if (set_freq <= 0) {
if (IS_E16_FREQ(hnd, ref_freq)) {
set_freq = E16_ADC_FREQ_DEFAULT;
} else {
set_freq = ref_freq;
}
}
if (IS_E16_FREQ(hnd, ref_freq)) {
div_max = E16_ADC_FREQ_DIV_MAX;
if (set_freq > E16_ADC_FREQ_MAX) {
set_freq = E16_ADC_FREQ_MAX;
}
}
cur_adc_freq_div = (uint32_t)(ref_freq/set_freq+0.49);
if (cur_adc_freq_div == 0)
cur_adc_freq_div = 1;
if (cur_adc_freq_div > div_max)
cur_adc_freq_div = div_max;
set_freq = ref_freq/cur_adc_freq_div;
*f_acq = set_freq;
if (f_frame==NULL) {
cur_frame_delay = 0;
} else {
if (lch_cnt == 0)
lch_cnt = 1;
if (*f_frame <= 0) {
cur_frame_delay = 0;
} else {
int32_t frame_div = (int32_t)((ref_freq/(*f_frame)
- lch_cnt*ref_freq/set_freq)+0.49);
cur_frame_delay = frame_div <=0 ? 0 :
frame_div > X502_ADC_INTERFRAME_DELAY_MAX ?
X502_ADC_INTERFRAME_DELAY_MAX : frame_div;
}
*f_frame = 1./(lch_cnt/set_freq +
cur_frame_delay/ref_freq);
}
if (adc_freq_div != NULL)
*adc_freq_div = cur_adc_freq_div;
if (adc_frame_delay != NULL)
*adc_frame_delay = cur_frame_delay;
}
return err;
}
X502_EXPORT(int32_t) X502_CalcAdcFreq(double ref_freq, uint32_t lch_cnt, double *f_acq,
double *f_frame, uint32_t *adc_freq_div, uint32_t *adc_frame_delay) {
return X502_CalcAdcFreq2(NULL, ref_freq, lch_cnt, f_acq, f_frame, adc_freq_div, adc_frame_delay);
}
X502_EXPORT(int32_t) X502_SetAdcFreq(t_x502_hnd hnd, double *f_acq, double *f_frame) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
double ref_freq;
X502_GetRefFreqValue(hnd, &ref_freq);
err = X502_CalcAdcFreq2(hnd, ref_freq, hnd->set.lch_cnt, f_acq, f_frame,
&hnd->set.adc_freq_div, &hnd->set.adc_frame_delay);
}
return err;
}
X502_EXPORT(int32_t) X502_GetAdcFreq(t_x502_hnd hnd, double *f_acq, double *f_frame) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (f_acq == NULL) && (f_frame==NULL))
err = X502_ERR_INVALID_POINTER;
if (!err) {
double ref_freq, set_freq;
X502_GetRefFreqValue(hnd, &ref_freq);
set_freq = ref_freq/hnd->set.adc_freq_div;
if (f_acq!=NULL) {
*f_acq = set_freq;
}
if (f_frame!=NULL) {
*f_frame = 1./(hnd->set.lch_cnt/set_freq +
hnd->set.adc_frame_delay/ref_freq);
}
}
return err;
}
X502_EXPORT(int32_t) X502_CalcDinFreq2(t_x502_hnd hnd, double ref_freq, double *f_din, uint32_t *result_freq_div) {
int32_t err = f_din==NULL ? X502_ERR_INVALID_POINTER : X502_ERR_OK;
if (err == X502_ERR_OK) {
uint32_t freq_div;
double set_freq = *f_din;
uint32_t div_max = X502_DIN_FREQ_DIV_MAX;
if (set_freq<=0) {
if (IS_E16_FREQ(hnd, ref_freq)) {
set_freq = E16_DIN_FREQ_DEFAULT;
} else {
set_freq = ref_freq;
}
}
if (IS_E16_FREQ(hnd, ref_freq)) {
div_max = E16_DIN_FREQ_DIV_MAX;
if (set_freq > E16_DIN_FREQ_MAX) {
set_freq = E16_DIN_FREQ_MAX;
}
}
freq_div = (uint32_t)(ref_freq/set_freq+0.49);
if (freq_div == 0)
freq_div = 1;
if (freq_div > div_max)
freq_div = div_max;
set_freq = ref_freq/freq_div;
*f_din = set_freq;
if (result_freq_div != NULL)
*result_freq_div = freq_div;
}
return err;
}
X502_EXPORT(int32_t) X502_CalcDinFreq(double ref_freq, double *f_din, uint32_t *result_freq_div) {
return X502_CalcDinFreq2(NULL, ref_freq, f_din, result_freq_div);
}
X502_EXPORT(int32_t) X502_SetDinFreq(t_x502_hnd hnd, double *f_din) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
double ref_freq;
X502_GetRefFreqValue(hnd, &ref_freq);
err = X502_CalcDinFreq2(hnd, ref_freq, f_din, &hnd->set.din_freq_div);
}
return err;
}
X502_EXPORT(int32_t) X502_CalcOutFreq2(t_x502_hnd hnd, double ref_freq, double *f_dout, uint32_t *result_freq_div) {
int32_t err = f_dout==NULL ? X502_ERR_INVALID_POINTER : X502_ERR_OK;
if (err == X502_ERR_OK) {
const uint32_t out_div_min = f_get_out_freq_div_min(ref_freq);
uint32_t out_freq_div;
uint32_t div_max = X502_OUT_FREQ_DIV_MAX;
double set_freq = *f_dout;
if (set_freq <= 0) {
if (IS_E16_FREQ(hnd, ref_freq)) {
set_freq = E16_OUT_FREQ_DEFAULT;
} else {
set_freq = ref_freq;
}
}
if (IS_E16_FREQ(hnd, ref_freq)) {
div_max = E16_OUT_FREQ_DIV_MAX;
if (set_freq > E16_OUT_FREQ_MAX) {
set_freq = E16_OUT_FREQ_MAX;
}
}
out_freq_div = (uint32_t)(ref_freq/set_freq+0.49);
if (out_freq_div < out_div_min)
out_freq_div = out_div_min;
if (out_freq_div > div_max)
out_freq_div = div_max;
set_freq = ref_freq/out_freq_div;
*f_dout = set_freq;
if (result_freq_div != NULL)
*result_freq_div = out_freq_div;
}
return err;
}
X502_EXPORT(int32_t) X502_CalcOutFreq(double ref_freq, double *f_dout, uint32_t *result_freq_div) {
return X502_CalcOutFreq2(NULL, ref_freq, f_dout, result_freq_div);
}
X502_EXPORT(int32_t) X502_SetOutFreq(t_x502_hnd hnd, double *f_dout) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err && (f_dout==NULL))
err = X502_ERR_INVALID_POINTER;
if (!err) {
double ref_freq;
X502_GetRefFreqValue(hnd, &ref_freq);
/* Если не поддерживается возможность установки нестандартного делителя, то
всегда устанавливаем стандартный */
if (X502_CheckFeature(hnd, X502_FEATURE_OUT_FREQ_DIV) != X502_ERR_OK) {
hnd->set.out_freq_div = X502_OUT_FREQ_DIV_DEFAULT;
*f_dout = ref_freq/hnd->set.out_freq_div;
} else {
err = X502_CalcOutFreq2(hnd, ref_freq, f_dout, &hnd->set.out_freq_div);
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetRefFreq(t_x502_hnd hnd, uint32_t freq) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
if (x502_is_E16(hnd)) {
// для E16 ref freq всегда 48 МГц
hnd->set.ref_freq = E16_REF_FREQ_48000KHZ;
} else {
hnd->set.ref_freq = freq;
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetExtRefFreqValue(t_x502_hnd hnd, double freq) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err)
hnd->set.ext_ref_freq = freq;
return err;
}
X502_EXPORT(int32_t) X502_SetAdcSyncStartValue(t_x502_hnd hnd, uint32_t phy_ch, uint32_t mode, uint32_t range, double value) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
hnd->set.adc_sync_ch = phy_ch;
hnd->set.adc_sync_range = range;
hnd->set.adc_sync_mode = mode;
hnd->set.adc_sync_val = value;
}
return err;
}
X502_EXPORT(int32_t) X502_GetRefFreqValue(t_x502_hnd hnd, double *freq) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err) {
if ((hnd->set.sync_mode == X502_SYNC_INTERNAL) ||
!(hnd->set.ext_ref_freq > 0)) {
*freq = hnd->set.ref_freq;
} else {
*freq = hnd->set.ext_ref_freq;
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetSyncMode(t_x502_hnd hnd, uint32_t sync_mode) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
err = CHECK_SYNC_MODE(sync_mode);
}
if (!err) {
hnd->set.sync_mode = sync_mode;
}
return err;
}
X502_EXPORT(int32_t) X502_SetSyncStartMode(t_x502_hnd hnd, uint32_t sync_start_mode) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
if (sync_start_mode==E16_SYNC_ADC_EDGE_RISE ||
sync_start_mode==E16_SYNC_ADC_EDGE_FALL ||
sync_start_mode==E16_SYNC_ADC_ABOVE_LEVEL ||
sync_start_mode==E16_SYNC_ADC_BELOW_LEVEL) {
if (x502_is_E16(hnd) == false) {
// реализовано только в E16
return X502_ERR_INVALID_SYNC_MODE;
}
} else {
err = CHECK_SYNC_MODE(sync_start_mode);
}
}
if (!err) {
hnd->set.sync_start_mode = sync_start_mode;
}
return err;
}
uint32_t get_ltable_val(t_x502_hnd hnd, uint32_t phy_ch, uint32_t mode, uint32_t range, uint32_t avg) {
uint32_t wrd = ((phy_ch & 0xF) << 3) | (range & 0x7);
if (mode == X502_LCH_MODE_ZERO) {
wrd |= (3 << 7);
} else if (mode == X502_LCH_MODE_COMM) {
wrd |= (phy_ch & 0x10 ? 2 : 1) << 7;
}
if (avg) {
uint32_t avg_val = avg;
if (avg_val > hnd->set.adc_freq_div)
avg_val = hnd->set.adc_freq_div;
wrd |= ((avg_val-1) & 0x7F) << 9;
}
return wrd;
}
X502_EXPORT(int32_t) X502_Configure(t_x502_hnd hnd, uint32_t flags) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
/* Проверяем правильность установленной опорной частоты.
Для внутренней может быть только одно из двух значений,
для внешней главное, чтобы не принимало требуемой */
if ((hnd->set.sync_mode==X502_SYNC_INTERNAL)
&& (hnd->set.ref_freq!=E16_REF_FREQ_48000KHZ)
&& (hnd->set.ref_freq!=X502_REF_FREQ_2000KHZ)
&&(hnd->set.ref_freq!=X502_REF_FREQ_1500KHZ)) {
err = X502_ERR_INVALID_REF_FREQ;
} else if (hnd->set.ext_ref_freq > 2000000) {
err = X502_ERR_INVALID_REF_FREQ;
}
}
if (!err) {
if (hnd->mode == X502_MODE_FPGA) {
uint32_t ch;
/* записываем логическую таблицу */
for (ch=0; (ch < hnd->set.lch_cnt) && !err; ch++) {
uint32_t wrd = get_ltable_val(hnd, hnd->set.lch[ch].ch, hnd->set.lch[ch].mode, hnd->set.lch[ch].range, hnd->set.lch[ch].avg);
err = hnd->iface_hnd->fpga_reg_write(hnd, (X502_REGS_IOHARD_LTABLE +
hnd->set.lch_cnt - 1 - ch) & 0xFFFF, wrd);
}
if (!err) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_LCH_CNT,
hnd->set.lch_cnt-1);
}
if (!err) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_ADC_FREQ_DIV,
hnd->set.adc_freq_div-1);
}
if (!err) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOARITH_ADC_FREQ_DIV,
hnd->set.adc_freq_div-1);
}
if (!err) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_ADC_FRAME_DELAY,
hnd->set.adc_frame_delay);
}
if (!err) {
// для варианта E16 ref_freq будет всегда 48000000
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_IO_MODE,
(SYNC_FREQ_CODE(hnd->set.sync_mode) & 0x7)
| ((hnd->set.sync_start_mode&0xF)<<3)
| ((hnd->set.ref_freq==X502_REF_FREQ_2000KHZ ? X502_MODE_REF_FREQ_2000 :
(hnd->set.ref_freq==X502_REF_FREQ_1500KHZ ? X502_MODE_REF_FREQ_1500: E16_MODE_REF_FREQ_48000)) << 7)
| (((hnd->set.out_freq_div-1) & (x502_is_E16(hnd) ? 0x7FFF : 0x3FF))<<9));
}
if (x502_is_E16(hnd)) {
// старт по аналоговому сигналу реализован только в E16
if (!err) {
uint32_t wrd = get_ltable_val(hnd, hnd->set.adc_sync_ch, hnd->set.adc_sync_mode, hnd->set.adc_sync_range, 0);
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOARITH_N_CHAN_SYN, wrd);
}
if (!err) {
uint32_t threshold;
threshold = hnd->set.adc_sync_val / hnd->set.f_scales[hnd->set.adc_sync_range] * E16_ADC_SCALE_CODE_MAX;
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOARITH_THRESHOLD, threshold);
}
}
if (!err) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_DIGIN_FREQ_DIV,
hnd->set.din_freq_div-1);
}
} else if (hnd->mode == X502_MODE_DSP) {
uint32_t ch;
err = x502_bf_set_par(hnd, L502_BF_PARAM_LCH_CNT, &hnd->set.lch_cnt, 1);
for (ch=0; !err && (ch < hnd->set.lch_cnt); ch++) {
uint32_t ch_par[] = {ch, hnd->set.lch[ch].ch,
hnd->set.lch[ch].mode,
hnd->set.lch[ch].range,
hnd->set.lch[ch].avg > hnd->set.adc_freq_div ?
hnd->set.adc_freq_div : hnd->set.lch[ch].avg} ;
err = x502_bf_set_par(hnd, L502_BF_PARAM_LCH, ch_par,
sizeof(ch_par)/sizeof(ch_par[0]));
}
if (!err) {
err = x502_bf_set_par(hnd, L502_BF_PARAM_ADC_FREQ_DIV,
&hnd->set.adc_freq_div, 1);
}
if (!err) {
err = x502_bf_set_par(hnd, L502_BF_PARAM_ADC_FRAME_DELAY,
&hnd->set.adc_frame_delay, 1);
}
if (!err) {
err = x502_bf_set_par(hnd, L502_BF_PARAM_REF_FREQ_SRC,
&hnd->set.ref_freq, 1);
}
if (!err) {
uint32_t sync_code = SYNC_FREQ_CODE(hnd->set.sync_mode);
err = x502_bf_set_par(hnd, L502_BF_PARAM_SYNC_MODE,
&sync_code, 1);
}
if (!err) {
err = x502_bf_set_par(hnd, L502_BF_PARAM_SYNC_START_MODE,
&hnd->set.sync_start_mode, 1);
}
if (!err) {
err = x502_bf_set_par(hnd, L502_BF_PARAM_DAC_FREQ_DIV,
&hnd->set.out_freq_div, 1);
}
if (!err)
{
err = x502_bf_set_par(hnd, L502_BF_PARAM_DIN_FREQ_DIV,
&hnd->set.din_freq_div, 1);
}
if (!err) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_CONFIGURE, 0, NULL,
0, NULL, 0, X502_BF_CMD_DEFAULT_TOUT, NULL);
}
} else {
err = X502_ERR_INVALID_MODE;
}
}
return err;
}
X502_EXPORT(int32_t) X502_SetAdcCoef(t_x502_hnd hnd, uint32_t range, double k, double offs) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if (!err) {
if (x502_is_E16(hnd)) {
if (range >= E16_ADC_RANGE_CNT) {
err = X502_ERR_INVALID_LCH_RANGE;
}
} else {
if (range >= X502_ADC_RANGE_CNT) {
err = X502_ERR_INVALID_LCH_RANGE;
}
}
}
if (!err) {
uint32_t kval = (uint32_t)(k*0x400000);
uint32_t offs_val = (uint32_t)(-offs);
if (hnd->mode == X502_MODE_FPGA) {
err = hnd->iface_hnd->fpga_reg_write(hnd, f_regadd_k[range], kval);
if (!err)
err = hnd->iface_hnd->fpga_reg_write(hnd, f_regadd_offs[range], offs_val);
} else if (hnd->mode == X502_MODE_DSP) {
uint32_t wrds[3] = {range, kval, offs_val};
err = x502_bf_set_par(hnd, L502_BF_PARAM_ADC_COEF, wrds, 3);
} else {
err = X502_ERR_INVALID_MODE;
}
}
if (!err) {
hnd->info.cbr.adc[range].k = k;
hnd->info.cbr.adc[range].offs = offs;
}
return err;
}
X502_EXPORT(int32_t) X502_GetAdcCoef(t_x502_hnd hnd, uint32_t range, double* k, double* offs) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err) {
if (range >= X502_ADC_RANGE_CNT) {
err = X502_ERR_INVALID_LCH_RANGE;
}
}
if (!err) {
*k = hnd->info.cbr.adc[range].k;
*offs = hnd->info.cbr.adc[range].offs;
}
return err;
}
X502_EXPORT(int32_t) X502_SetDacCoef(t_x502_hnd hnd, uint32_t ch, double k, double offs) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (ch!=X502_DAC_CH1) && (ch!=X502_DAC_CH2)) {
err = X502_ERR_INVALID_DAC_CHANNEL;
}
if (!err) {
hnd->info.cbr.dac[ch].offs = offs;
hnd->info.cbr.dac[ch].k = k;
}
return err;
}
X502_EXPORT(int32_t) X502_GetDacCoef(t_x502_hnd hnd, uint32_t ch, double* k, double* offs) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (!err && (ch!=X502_DAC_CH1) && (ch!=X502_DAC_CH2)) {
err = X502_ERR_INVALID_DAC_CHANNEL;
}
if (!err) {
if (offs!=NULL)
*offs = hnd->info.cbr.dac[ch].offs;
if (k!=NULL)
*k = hnd->info.cbr.dac[ch].k;
}
return err;
}

213
lib/x502/x502api_eeprom.c Normal file
View File

@ -0,0 +1,213 @@
#include "x502api_private.h"
#include "x502_eeprom.h"
#include "fast_crc.h"
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "../devs/e502/e502_fpga_regs.h"
#define X502_CHECK_ADDR(hnd, addr, size) ((addr+size)>hnd->info.flash_size ? \
X502_ERR_FLASH_INVALID_ADDR : (size==0) ? X502_ERR_FLASH_INVALID_SIZE : X502_ERR_OK)
X502_EXPORT(int32_t) X502_FlashRead(t_x502_hnd hnd, uint32_t addr, uint8_t* data,
uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err==X502_ERR_OK) {
err = X502_CHECK_ADDR(hnd, addr, size);
}
if (err==X502_ERR_OK) {
for ( ; (size!=0) && (err==X502_ERR_OK); ) {
uint32_t rd_size = size;
if (rd_size > hnd->iface_hnd->flash_rd_size)
rd_size = hnd->iface_hnd->flash_rd_size;
err = hnd->iface_hnd->flash_rd(hnd, addr, data, rd_size);
if (err==X502_ERR_OK) {
data+=rd_size;
addr+=rd_size;
size-=rd_size;
}
}
}
return err;
}
X502_EXPORT(int32_t) X502_FlashWrite(t_x502_hnd hnd, uint32_t addr,
const uint8_t* data, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err==X502_ERR_OK) {
err = X502_CHECK_ADDR(hnd, addr, size);
}
if (err==X502_ERR_OK) {
for ( ; (size!=0) && (err==X502_ERR_OK); ) {
uint32_t wr_size = size;
if (wr_size > hnd->iface_hnd->flash_wr_size)
wr_size = hnd->iface_hnd->flash_wr_size;
err = hnd->iface_hnd->flash_wr(hnd, addr, data, wr_size);
if (err==X502_ERR_OK) {
data+=wr_size;
addr+=wr_size;
size-=wr_size;
}
}
}
return err;
}
X502_EXPORT(int32_t) X502_FlashErase(t_x502_hnd hnd, uint32_t addr, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err==X502_ERR_OK) {
err = X502_CHECK_ADDR(hnd, addr, size);
}
if (err==X502_ERR_OK) {
err = hnd->iface_hnd->flash_erase(hnd, addr, size);
}
return err;
}
X502_EXPORT(int32_t) X502_FlashWriteEnable(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err==X502_ERR_OK) {
err = hnd->iface_hnd->flash_set_prot(hnd, X502_EEPROM_PROT_WR_USER, NULL, 0);
}
return err;
}
X502_EXPORT(int32_t) X502_FlashWriteDisable(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err==X502_ERR_OK) {
err = hnd->iface_hnd->flash_set_prot(hnd, X502_EEPROM_PROT_ALL, NULL, 0);
}
return err;
}
X502_EXPORT(int32_t) X502_FlashSetProtection(t_x502_hnd hnd, uint32_t prot, uint8_t *prot_data, uint32_t prot_data_size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err==X502_ERR_OK) {
err = hnd->iface_hnd->flash_set_prot(hnd, prot, prot_data, prot_data_size);
}
return err;
}
bool x502_is_E16(t_x502_hnd hnd) {
if (strcmp(hnd->info.name, E16_DEVICE_NAME) == 0) {
return true;
} else {
return false;
}
}
/** Функция проверяет правильность информации о устройстве, записанной в EEPROM.
При наличии верной инофрмации, из EEPROM считывается название устройства и
серийный номер, а так же, при наличии, калибровочные коэффициенты */
int x502_check_eeprom(t_x502_hnd hnd, uint32_t flags) {
int err;
uint32_t sign, size;
if (x502_is_E16(hnd)) {
// в E16 добавился новый регистр и мы можем узнать размер flash-памяти
uint32_t flash_size;
err = hnd->iface_hnd->fpga_reg_read(hnd, E502_REGS_ARM_FLASHSIZE, &flash_size);
if (err != X502_ERR_OK) {
hnd->info.flash_size = 0;
return err;
}
hnd->info.flash_size = flash_size;
} else {
hnd->info.flash_size = X502_EEPROM_SIZE;
}
hnd->info.devflags &= ~(X502_DEVFLAGS_FLASH_DATA_VALID |
((flags & X502_RELOAD_FLAGS_NO_ADC) ? 0 : X502_DEVFLAGS_FLASH_ADC_CALIBR_VALID) |
((flags & X502_RELOAD_FLAGS_NO_DAC) ? 0 : X502_DEVFLAGS_FLASH_DAC_CALIBR_VALID));
/* проверяем признак правильного описателя в EEPROM и его размер */
err = X502_FlashRead(hnd, X502_EEPROM_ADDR_DESCR, (uint8_t*)&sign, (uint32_t)sizeof(sign));
if (err == X502_ERR_OK)
err = X502_FlashRead(hnd, X502_EEPROM_ADDR_DESCR+sizeof(sign), (uint8_t*)&size, (uint32_t)sizeof(size));
if (err == X502_ERR_OK) {
if ((sign == X502_EEPROM_SIGN) && (size >= X502_DESCR_MIN_SIZE) && (size <= X502_DESCR_MAX_SIZE)) {
t_x502_descr* pdescr = (t_x502_descr*)malloc(size);
/* читаем весь описатель */
if (pdescr!=NULL) {
err = X502_FlashRead(hnd, X502_EEPROM_ADDR_DESCR, (uint8_t*)pdescr, size);
} else {
err = X502_ERR_MEMORY_ALLOC;
}
/* сверяем crc */
if (err == X502_ERR_OK) {
uint32_t crc, crc2;
crc = CRC32_Block8(0, (uint8_t*)pdescr, (uint32_t)(size-sizeof(crc)));
memcpy(&crc2, &((uint8_t*)pdescr)[size-4], 4);
if (crc == crc2) {
hnd->info.devflags |= X502_DEVFLAGS_FLASH_DATA_VALID;
memcpy(hnd->info.serial, pdescr->hdr.serial, sizeof(pdescr->hdr.serial));
memcpy(hnd->info.name, pdescr->hdr.name, sizeof(pdescr->hdr.name));
memcpy(hnd->info.factory_mac, pdescr->hdr.factory_mac, sizeof(pdescr->hdr.factory_mac));
if (!(flags & X502_RELOAD_FLAGS_NO_ADC)) {
if ((pdescr->cbr_adc.hdr.cbr_sign == X502_EEPROM_CBR_SIGN) &&
(pdescr->cbr_adc.hdr.format == X502_EEPROM_CBR_FROMAT) &&
(pdescr->cbr_adc.hdr.src == X502_EEPROM_CBR_SRC_ADC) &&
(pdescr->cbr_adc.hdr.range_cnt == X502_ADC_RANGE_CNT || pdescr->cbr_adc.hdr.range_cnt == E16_ADC_RANGE_CNT) &&
(pdescr->cbr_adc.hdr.channel_cnt == 1)) {
unsigned int i;
hnd->info.devflags |= X502_DEVFLAGS_FLASH_ADC_CALIBR_VALID;
for (i=0; (i < pdescr->cbr_adc.hdr.range_cnt) && (err == X502_ERR_OK); i++) {
if (x502_is_E16(hnd)) {
if (i > E16_ADC_RANGE_CNT) {
break;
}
} else {
if (i > X502_ADC_RANGE_CNT) {
break;
}
}
err = X502_SetAdcCoef(hnd, i, pdescr->cbr_adc.coefs[i].k,
pdescr->cbr_adc.coefs[i].offs);
}
}
}
if (!(flags & X502_RELOAD_FLAGS_NO_DAC)) {
if ((pdescr->cbr_dac.hdr.cbr_sign == X502_EEPROM_CBR_SIGN) &&
(pdescr->cbr_dac.hdr.format == X502_EEPROM_CBR_FROMAT) &&
(pdescr->cbr_dac.hdr.src == X502_EEPROM_CBR_SRC_DAC) &&
(pdescr->cbr_dac.hdr.range_cnt == 1) &&
(pdescr->cbr_dac.hdr.channel_cnt == X502_DAC_CH_CNT)) {
unsigned int i;
hnd->info.devflags |= X502_DEVFLAGS_FLASH_DAC_CALIBR_VALID;
for (i=0; (i < pdescr->cbr_dac.hdr.channel_cnt) &&
(i < X502_ADC_RANGE_CNT) && (err == X502_ERR_OK); i++) {
err = X502_SetDacCoef(hnd, i, pdescr->cbr_dac.coefs[i].k,
pdescr->cbr_dac.coefs[i].offs);
}
}
}
}
}
free(pdescr);
}
}
return err;
}
X502_EXPORT(int32_t) X502_ReloadDevInfo(t_x502_hnd hnd, uint32_t flags) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err==X502_ERR_OK) && (hnd->iface_hnd->reload_dev_info!=NULL))
err = hnd->iface_hnd->reload_dev_info(hnd);
if (err==X502_ERR_OK)
err = x502_check_eeprom(hnd, flags);
return err;
}

186
lib/x502/x502api_errs.c Normal file
View File

@ -0,0 +1,186 @@
//---------------------------------------------------------------------------
#include "x502api.h"
#include "l502_bf_cmd_defs.h"
#include "../devs/e502/e502_cm4_defs.h"
static const char* f_unknow_err = "Неизвестная ошибка";
typedef struct {
int32_t err;
const char* str;
}t_err_table;
static const t_err_table f_err_tbl[] = {
{ X502_ERR_OK, "Выполнено без ошибок" },
{ X502_ERR_INVALID_HANDLE, "Недействительный описатель модуля"},
{ X502_ERR_MEMORY_ALLOC, "Ошибка выделения памяти"},
{ X502_ERR_ALREADY_OPENED, "Попытка открыть уже открытое устройство"},
{ X502_ERR_DEVICE_NOT_FOUND, "Устройство с заданными параметрами не найдено в системе"},
{ X502_ERR_DEVICE_ACCESS_DENIED, "Доступ к устройству запрещен"},
{ X502_ERR_DEVICE_OPEN, "Ошибка открытия устройства"},
{ X502_ERR_INVALID_POINTER, "В функцию передан недействительный указатель"},
{ X502_ERR_STREAM_IS_RUNNING, "Функция не может быть выполнена при запущенном потоке сбора данных"},
{ X502_ERR_RECV, "Ошибка чтения данных синхронного ввода"},
{ X502_ERR_SEND, "Ошибка записи данных для синхронного вывода"},
{ X502_ERR_STREAM_OVERFLOW, "Произошло переполнение внутреннего буфера для потока синхронного ввода"},
{ X502_ERR_UNSUP_STREAM_MSG, "Неизвестное сообщение в потоке синхронного ввода"},
{ X502_ERR_MUTEX_CREATE, "Ошибка создания системного мьютекса"},
{ X502_ERR_MUTEX_INVALID_HANDLE, "Неверный описатель мьютекса"},
{ X502_ERR_MUTEX_LOCK_TOUT, "Истекло время ожидания освобождния мьютекса"},
{ X502_ERR_MUTEX_RELEASE, "Ошибка освобождения мьютекса"},
{ X502_ERR_INSUFFICIENT_SYSTEM_RESOURCES, "Недостаточно системных ресурсов"},
{ X502_ERR_NOT_IMPLEMENTED, "Данная возможность еще не реализована"},
{ X502_ERR_INSUFFICIENT_ARRAY_SIZE, "Недостаточный размер массива"},
{ X502_ERR_FPGA_REG_READ, "Ошибка чтения регистра FPGA"},
{ X502_ERR_FPGA_REG_WRITE, "Ошибка записи регистра FPGA"},
{ X502_ERR_STREAM_IS_NOT_RUNNING, "Синхронный сбор уже остановлен"},
{ X502_ERR_INTERFACE_RELEASE, "Ошибка освобождения интерфейса"},
{ X502_ERR_THREAD_START, "Ошибка запуска потока"},
{ X502_ERR_THREAD_STOP, "Ошибка останова потока"},
{ X502_ERR_DEVICE_DISCONNECTED, "Устройство было отключено"},
{ X502_ERR_IOCTL_INVALID_RESP_SIZE, "Неверный размер ответа на управляющий запрос"},
{ X502_ERR_INVALID_DEVICE, "Неверный тип устройства"},
{ X502_ERR_INVALID_DEVICE_RECORD, "Недействительная запись о устройстве"},
{ X502_ERR_INVALID_CONFIG_HANDLE, "Неверный описатель конфигурации модуля"},
{ X502_ERR_DEVICE_NOT_OPENED, "Связь с устройством закрыта или не была установлена"},
{ X502_ERR_INVALID_OP_FOR_IFACE, "Данная операция не доступна для текущего интерфейса связи с устройством"},
{ X502_ERR_FPGA_NOT_LOADED, "Не загружен ПЛИС модуля"},
{ X502_ERR_INVALID_USB_CONFIGURATION,"Неверная конфигурация USB-устройства"},
{ X502_ERR_INVALID_SVC_BROWSE_HANDLE, "Неверный описатель контекста поиска сервисов"},
{ X502_ERR_INVALID_SVC_RECORD_HANDLE,"Неверный описатель записи о сервисе"},
#ifdef _WIN32
{ X502_ERR_DNSSD_NOT_RUNNING, "Не запущена программа обнаружения устройств в локальной сети (Bonjour Service)"},
#else
{ X502_ERR_DNSSD_NOT_RUNNING, "Не запущена программа обнаружения устройств в локальной сети (AVAHI)"},
#endif
{ X502_ERR_DNSSD_COMMUNICATION, "Ошибка при обращении к программе обнаружения устройств в локальной сети"},
{ X502_ERR_INVALID_SVC_BROWSE_HANDLE, "Неверный описатель контекста поиска устройств в сети"},
{ X502_ERR_INVALID_SVC_RECORD_HANDLE, "Неверный описатель записи о сервисе"},
{ X502_ERR_DNSSD_NOT_RUNNING, "Не запущена программа обнаружения устройств в локальной сети"},
{ X502_ERR_DNSSD_COMMUNICATION, "Ошибка при обращении к программе обнаружения устройств в локальной сети"},
{ X502_ERR_SVC_RESOLVE_TIMEOUT, "Превышен таймаут запроса параметров автообнаруженного сетевого устройства"},
{ X502_ERR_INSTANCE_NAME_ENCODING, "Ошибка в кодировке имени экземляра устройства"},
{ X502_ERR_INSTANCE_MISMATCH, "Экземпляры модулей не совпадают"},
{ X502_ERR_NOT_SUP_BY_FIRMWARE, "Возможность не поддерживается текущей версией прошивки устройства"},
{ X502_ERR_NOT_SUP_BY_DRIVER, "Возможность не поддерживается текущей версией драйвера устройства"},
{ X502_ERR_OUT_CYCLE_SETUP_TOUT, "Превышено время ожидания установления цикличиского сигнала на вывод"},
{ X502_ERR_INVALID_LTABLE_SIZE, "Задан неверный размер логической таблицы"},
{ X502_ERR_INVALID_LCH_NUMBER, "Задан неверный номер логического канала"},
{ X502_ERR_INVALID_LCH_RANGE, "Неверно задано значение диапазона АЦП"},
{ X502_ERR_INVALID_LCH_MODE, "Неверно задан режим измерения для логического канала"},
{ X502_ERR_INVALID_LCH_PHY_NUMBER, "Неверно задан номер физического канала при настройке логического"},
{ X502_ERR_INVALID_LCH_AVG_SIZE, "Неверно задан размер усреднения для логического канала"},
{ X502_ERR_INVALID_ADC_FREQ_DIV, "Неверно задан делитель частоты сбора данных АЦП"},
{ X502_ERR_INVALID_DIN_FREQ_DIV, "Неверно задан делитель частоты синхронного ввода цифровых линий"},
{ X502_ERR_INVALID_MODE, "Неверно задан режим работы платы"},
{ X502_ERR_INVALID_DAC_CHANNEL, "Неверный номер канала ЦАП"},
{ X502_ERR_INVALID_REF_FREQ, "Неверный код выбора опорной частоты синхронизации"},
{ X502_ERR_INVALID_INTERFRAME_DELAY,"Неверно задано значение межкадровой задержки"},
{ X502_ERR_INVALID_SYNC_MODE, "Неверно задан режим синхронизации"},
{ X502_ERR_INVALID_STREAM_CH, "Неверно задан номер потока данных"},
{ X502_ERR_INVALID_OUT_FREQ_DIV, "Неверно задан делитель частоты синхронного вывода"},
{ X502_ERR_REF_FREQ_NOT_LOCKED, "Ошибка захвата опорной частоты синхронизации"},
{ X502_ERR_IOCTL_FAILD, "Управляющий запрос к драйверу завершен с ошибкой"},
{ X502_ERR_IOCTL_TIMEOUT, "Истек таймаут ожидания завершения выполнения управляющего запроса к драйверу"},
{ X502_ERR_GET_INFO, "Ошибка получения информации о устройстве от драйвера"},
{ X502_ERR_DIG_IN_NOT_RDY, "За время ожидания не было считано новое слово с цифровых линий"},
{ X502_ERR_RECV_INSUFFICIENT_WORDS, "Принято недостаточно слов от модуля"},
{ X502_ERR_DAC_NOT_PRESENT, "Попытка выполнить операцию, требующую наличие ЦАП, при его отсутствии"},
{ X502_ERR_SEND_INSUFFICIENT_WORDS, "Передано недостаточно слов в модуль"},
{ X502_ERR_NO_CMD_RESPONSE, "Не пришло ответа на переданную команду"},
{ X502_ERR_PROC_INVALID_CH_NUM, "Неверный номер канала в обрабатываемом потоке синхронного ввода"},
{ X502_ERR_PROC_INVALID_CH_RANGE, "Неверный код диапазона в обрабатываемом потоке синхронного ввода"},
{ X502_ERR_FLASH_INVALID_ADDR, "Задан неверный адрес во Flash-памяти"},
{ X502_ERR_FLASH_INVALID_SIZE, "Задан неверный размер блока данных при работе с Flash-памятью"},
{ X502_ERR_FLASH_WRITE_TOUT, "Истек таймаут ожидания завершения записи во Flash-память"},
{ X502_ERR_FLASH_ERASE_TOUT, "Истек таймаут ожидания завершения стирания блока Flash-памяти"},
{ X502_ERR_FLASH_SECTOR_BOUNDARY, "Заданная область для стирания Flash-памяти нарушает границу блока в 4 Кбайт"},
{ X502_ERR_SOCKET_OPEN, "Не удалось открыть сокет для соединения"},
{ X502_ERR_CONNECTION_TOUT, "Превышено время подключения"},
{ X502_ERR_CONNECTION_CLOSED_BY_DEV,"Соединение закрыто устройством"},
{ X502_ERR_SOCKET_SET_BUF_SIZE, "Не удалось установить заданный размер буфера сокета"},
{ X502_ERR_NO_DATA_CONNECTION, "Соединение для передачи данных не установлено"},
{ X502_ERR_NO_STREAM_END_MSG, "Не удалось дождаться сообщения о завершении потока"},
{ X502_ERR_CONNECTION_RESET, "Соединение было сброшено другой стороной"},
{ X502_ERR_HOST_UNREACHABLE, "Не удалось найти хост с указанным адресом"},
{ X502_ERR_TCP_CONNECTION_ERROR, "Ошибка установления TCP-соединения"},
{ X502_ERR_LDR_FILE_OPEN, "Не удалось открыть файл прошивки BlackFin"},
{ X502_ERR_LDR_FILE_READ, "Ошибка чтения из фала прошивки BlackFin"},
{ X502_ERR_LDR_FILE_FORMAT, "Неверный формат файла прошивки BlackFin"},
{ X502_ERR_LDR_FILE_UNSUP_FEATURE, "Используются возможность LDR-файла, недоступные при записи прошивки BlackFin по HDMA"},
{ X502_ERR_LDR_FILE_UNSUP_STARTUP_ADDR, "Неверный стартовый адрес программы в прошивке BlackFin"},
{ X502_ERR_BF_REQ_TIMEOUT, "Истек таймаут выполнения запроса на чтения/запись памяти BlackFin"},
{ X502_ERR_BF_CMD_IN_PROGRESS, "Команда для BlackFin все еще находится в процессе обработки"},
{ X502_ERR_BF_CMD_TIMEOUT, "Истекло время выполнения управляющей команды процессором BlackFin"},
{ X502_ERR_BF_CMD_RETURN_INSUF_DATA,"Возвращено недостаточно данных в ответ на команду к BlackFin"},
{ X502_ERR_BF_LOAD_RDY_TOUT, "Истек таймаут ожидания готовности процессора BlackFin к записи прошивки"},
{ X502_ERR_BF_NOT_PRESENT, "Процессор BlackFin не присутствует на плате"},
{ X502_ERR_BF_INVALID_ADDR, "Неверный адрес памяти BlackFin при записи или чтении по HDMA"},
{ X502_ERR_BF_INVALID_CMD_DATA_SIZE,"Неверный размер данных, передаваемых с управляющей командой в BlackFin"},
{ L502_BF_ERR_UNSUP_CMD, "Ошибка BlackFin: неподдерживаемый код команды"},
{ L502_BF_ERR_CMD_OVERRUN, "Ошибка BlackFin: запрос на выполнение команды опережает завершение предыдущей"},
{ L502_BF_ERR_INVALID_CMD_PARAMS, "Ошибка BlackFin: неверное значение параметров команды"},
{ L502_BF_ERR_INSUF_CMD_DATA, "Ошибка BlackFin: недостаточное данных передано с командой"},
{ L502_BF_ERR_STREAM_RUNNING, "Ошибка BlackFin: команда не допустима при запущеном сборе"},
{ L502_BF_ERR_STREAM_STOPPED, "Ошибка BlackFin: команда допустима только при запущеном сборе"},
{ L502_BF_ERR_NO_TEST_IN_PROGR, "Ошибка BlackFin: не выполняется ни одного теста"},
{ L502_BF_ERR_TEST_VALUE, "Ошибка BlackFin: неверное значение при выполнении теста"},
{ E502_CM4_ERR_FPGA_NSTATUS_TOUT, "Ошибка Cortex-M4: При загрузке ПЛИС не удалось дождаться сигнала перехода в режим загрузки"},
{ E502_CM4_ERR_FPGA_CONF_DONE_TOUT, "Ошибка Cortex-M4: При загрузке ПЛИС не удалось дождаться сигнала завершения загрузки"},
{ E502_CM4_ERR_FPGA_FW_NOT_PRESENT, "Ошибка Cortex-M4: Не обнаружена прошивка ПЛИС во flash-памяти модуля"},
{ E502_CM4_ERR_FPGA_REG_NACK, "Ошибка Cortex-M4: Обращение к регистру ПЛИС вернуло ответ NACK"},
{ E502_CM4_ERR_FPGA_REG_ERROR, "Ошибка Cortex-M4: Обращение к регистру ПЛИС вернуло ответ ERROR"},
{ E502_CM4_ERR_FPGA_REG_WT_TOUT, "Ошибка Cortex-M4: Не удалось дожлаться ответ на обращение к регистру ПЛИС"},
{ E502_CM4_ERR_TEST_INVALID_NUM, "Ошибка Cortex-M4: Неподдерживаемый номер теста"},
{ E502_CM4_ERR_TEST_VALUE_MISMATH, "Ошибка Cortex-M4: Несовпадение ожидаемых значений при проходе теста"},
{ E502_CM4_ERR_TEST_NOT_RUNNING, "Ошибка Cortex-M4: Тест не запущен"},
{ E502_CM4_ERR_TEST_ALREADY_RUNNING,"Ошибка Cortex-M4: Tест уже запщен"},
{ E502_CM4_ERR_BF_LDR_FILE_SIZE, "Ошибка Cortex-M4: Не удалось найти конец файла прошивки BlackFin"},
{ E502_CM4_ERR_LDR_FILE_FORMAT, "Ошибка Cortex-M4: Неверный формат файла прошивки BlackFin"},
{ E502_CM4_ERR_LDR_FILE_UNSUP_FEATURE, "Ошибка Cortex-M4: Используются возможность LDR-файла, недоступные при записи прошивки BlackFin по HDMA"},
{ E502_CM4_ERR_LDR_FILE_UNSUP_STARTUP_ADDR, "Ошибка Cortex-M4: Неверный стартовый адрес программы в прошивке BlackFin"},
{ E502_CM4_ERR_BF_REQ_TIMEOUT, "Ошибка Cortex-M4: Истек таймаут выполнения запроса на чтения/запись памяти BlackFin"},
{ E502_CM4_ERR_BF_CMD_IN_PROGRESS, "Ошибка Cortex-M4: Команда для BlackFin все еще находится в процессе обработки"},
{ E502_CM4_ERR_BF_CMD_TIMEOUT, "Ошибка Cortex-M4: Истекло время выполнения управляющей команды процессором BlackFin"},
{ E502_CM4_ERR_BF_CMD_RETURN_INSUF_DATA, "Ошибка Cortex-M4: Возвращено недостаточно данных в ответ на команду к BlackFin"},
{ E502_CM4_ERR_BF_LOAD_RDY_TOUT, "Ошибка Cortex-M4: Истек таймаут ожидания готовности процессора BlackFin к записи прошивки"},
{ E502_CM4_ERR_BF_NOT_PRESENT, "Ошибка Cortex-M4: Попытка выполнить операцию для которой нужен сигнальный процессор при отсутствии сигнального процессора в модуле"},
{ E502_CM4_ERR_BF_INVALID_ADDR, "Ошибка Cortex-M4: Неверный адрес памяти BlackFin при записи или чтении по HDMA"},
{ E502_CM4_ERR_BF_INVALID_CMD_DATA_SIZE, "Ошибка Cortex-M4: Неверный размер данных, передаваемых с управляющей командой в BlackFin"},
{ E502_CM4_ERR_UNKNOWN_CMD, "Ошибка Cortex-M4: Неподдерживаемый код команды"},
{ E502_CM4_ERR_INVALID_CMD_PARAMS, "Ошибка Cortex-M4: Неверные параметры переданной команды"},
{ E502_CM4_ERR_FIRM_BUF_OVERFLOW, "Ошибка Cortex-M4: Переполнение буфера для приема прошивки"},
{ E502_CM4_ERR_CMD_SIGNATURE, "Ошибка Cortex-M4: Неверный признак начала команды"},
{ E502_CM4_ERR_INVALID_CMD_DATA_SIZE, "Ошибка Cortex-M4: Неверное количество данных в команде"},
{ E502_CM4_ERR_FLASH_PROT_CODE, "Ошибка Cortex-M4: Неверный код настройки защиты Flash-памяти"},
{ E502_CM4_ERR_FLASH_OP, "Ошибка Cortex-M4: Ошибка выполнения операции с Flash-памятью"},
{ E502_CM4_ERR_FLASH_DATA_COMPARE, "Ошибка Cortex-M4: Ошибка сравнения записанных данных во Flash-память"},
{ E502_CM4_ERR_INVALID_PASSWORD, "Ошибка Cortex-M4: Неверный пароль для изменения сетевых настроек"},
{ E502_CM4_ERR_FPGA_NOT_LOADED, "Ошибка Cortex-M4: ПЛИС не был загружен"},
{ E502_CM4_ERR_FLASH_SET_PROT_BITS, "Ошибка Cortex-M4: Не удалось изменить занчения битов защиты Flash-памяти"},
{ E502_CM4_ERR_FPGA_FW_INVALID_TEMP_RANGE, "Ошибка Cortex-M4: Загруженная прошивка ПЛИС предназначена для другого темп. исполнения"},
{ E502_CM4_ERR_M0_STREAM_START_REQ, "Ошибка Cortex-M4: Нет ответа на запрос запуска потока от ядра Cortex-M0"},
{ E502_CM4_ERR_M0_STREAM_STOP_REQ, "Ошибка Cortex-M4: Нет ответа на запрос останова потока от ядра Cortex-M0"},
{ E502_CM4_ERR_OUT_STREAM_RUNNING, "Ошибка Cortex-M4: Уже запущен вывод в потоковом режиме"},
{ E502_CM4_ERR_OUT_NO_CYCLE_BUF, "Ошибка Cortex-M4: Нет свободного буфера для циклического режима. Не произошла смена страниц"},
{ E502_CM4_ERR_OUT_CYCLE_BUF_SIZE, "Ошибка Cortex-M4: Задан слишком большой размер циклического буфера"},
{ E502_CM4_ERR_OUT_CYCLE_NOT_LOADED, "Ошибка Cortex-M4: Не был полностью загружен циклический буфер перед сменой"}
};
X502_EXPORT(const char*) X502_GetErrorString(int32_t err) {
size_t i;
const char *str = f_unknow_err;
for (i=0; (i < sizeof(f_err_tbl)/sizeof(f_err_tbl[0])) && (str==f_unknow_err); i++) {
if (f_err_tbl[i].err == err)
str = f_err_tbl[i].str;
}
return str;
}

310
lib/x502/x502api_private.h Normal file
View File

@ -0,0 +1,310 @@
#ifndef X502API_PRIVATE_H
#define X502API_PRIVATE_H
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#include <sys/time.h>
#endif
#include "x502api.h"
#include "osspec.h"
#include "l502_bf_cmd_defs.h"
#include "x502_fpga_regs.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct st_x502_devrec_inptr {
const void *iface;
void *iface_data;
};
#define E16_DEVICE_NAME "E16"
#define X502_SIGN 0xA55A0502
#define X502_CHECK_HND(hnd) ((hnd!=NULL) ? (hnd)->sign == X502_SIGN ? X502_ERR_OK \
: X502_ERR_INVALID_HANDLE : X502_ERR_INVALID_HANDLE)
#define X502_CHECK_HND_OPENED(hnd) ((hnd!=NULL) ? (hnd)->sign == X502_SIGN ? \
(((hnd)->flags & PRIV_FLAGS_OPENED) ? X502_ERR_OK : X502_ERR_DEVICE_NOT_OPENED) \
: X502_ERR_INVALID_HANDLE : X502_ERR_INVALID_HANDLE)
/* на сколько секунд данных будет рассчитан внутренний буфер */
#define X502_DMA_IN_BUF_FOR_SEC 4
/* максимальное кол-во прерываний в секунду */
#define X502_DMA_IN_MAX_IRQ_PER_SEC 20
#define X502_DMA_OUT_BUF_SIZE (3*3*1024*1024)
#define X502_DMA_OUT_IRQ_STEP (3*1024*1024/32)
#define X502_MUTEX_CFG_LOCK_TOUT 1000
#define X502_OUT_CYCLE_WAIT_TOUT 20000
#define X502_STREAM_CH_CNT 2
#ifdef _WIN32
#define SLEEP_MS(ms) Sleep(ms)
#else
#define SLEEP_MS(ms) usleep(ms*1000)
#endif
/** параметры канала потока данных */
typedef struct {
uint32_t buf_size; /** размер временного буфера */
uint32_t step; /** через сколько переданных отсчетов будет генерироваться прерывание */
} t_x502_stream_ch_params;
typedef int32_t (*t_x502_iface_free_devinfo_ptr)(t_x502_devrec_inptr *devinfo_ptr);
typedef int32_t (*t_x502_iface_open)(t_x502_hnd hnd, const t_x502_devrec *devinfo);
typedef int32_t (*t_x502_iface_close)(t_x502_hnd hnd);
typedef int32_t (*t_x502_iface_fpga_reg_read)(t_x502_hnd hnd, uint32_t addr, uint32_t *val);
typedef int32_t (*t_x502_iface_fpga_reg_write)(t_x502_hnd hnd, uint32_t addr, uint32_t val);
typedef int32_t (*t_x502_iface_stream_cfg)(t_x502_hnd hnd, uint32_t ch, t_x502_stream_ch_params *pars);
typedef int32_t (*t_x502_iface_stream_start)(t_x502_hnd hnd, uint32_t ch, uint32_t flags);
typedef int32_t (*t_x502_iface_stream_stop)(t_x502_hnd hnd, uint32_t ch, uint32_t flags);
typedef int32_t (*t_x502_iface_stream_free)(t_x502_hnd hnd, uint32_t ch, uint32_t flags);
typedef int32_t (*t_x502_iface_stream_running)(t_x502_hnd hnd, uint32_t ch, int32_t* running);
typedef int32_t (*t_x502_iface_stream_read)(t_x502_hnd hnd, uint32_t *buf, uint32_t size, uint32_t tout);
typedef int32_t (*t_x502_iface_stream_write)(t_x502_hnd hnd, const uint32_t *buf, uint32_t size, uint32_t tout);
typedef int32_t (*t_x502_iface_stream_get_rdy_cnt)(t_x502_hnd hnd, uint32_t ch, uint32_t *rdy_cnt);
typedef int32_t (*t_x502_iface_bf_mem_block_rd)(t_x502_hnd hnd, uint32_t addr, uint32_t *block, uint32_t size);
typedef int32_t (*t_x502_iface_bf_mem_block_wr)(t_x502_hnd hnd, uint32_t addr, const uint32_t *block, uint32_t size);
typedef int32_t (*t_x502_iface_bf_firm_load)(t_x502_hnd hnd, const char* filename);
typedef int32_t (*t_x502_iface_flash_rd)(t_x502_hnd hnd, uint32_t addr, uint8_t* data, uint32_t size);
typedef int32_t (*t_x502_iface_flash_wr)(t_x502_hnd hnd, uint32_t addr, const uint8_t* data, uint32_t size);
typedef int32_t (*t_x502_iface_flash_erase)(t_x502_hnd hnd, uint32_t addr, uint32_t size);
typedef int32_t (*t_x502_iface_flash_set_prot)(t_x502_hnd hnd, uint32_t flags,
const uint8_t* prot_data, uint32_t size);
typedef int32_t (*t_x502_iface_reload_devinfo)(t_x502_hnd hnd);
typedef int32_t (*t_x502_iface_cycle_load_start)(t_x502_hnd hnd, uint32_t size);
typedef int32_t (*t_x502_iface_cycle_setup)(t_x502_hnd hnd, uint32_t flags);
typedef int32_t (*t_x502_iface_cycle_stop)(t_x502_hnd hnd, uint32_t flags);
typedef int32_t (*t_x502_iface_cycle_check_setup)(t_x502_hnd hnd, uint32_t *done);
typedef int32_t (*t_x502_iface_gen_ioctl)(t_x502_hnd hnd, uint32_t cmd_code, uint32_t param,
const void* snd_data, uint32_t snd_size,
void* rcv_data, uint32_t recv_size,
uint32_t* recvd_size, uint32_t tout);
typedef int32_t (*t_x502_iface_check_feature)(t_x502_hnd hnd, uint32_t feature);
typedef int32_t (*t_x502_iface_fpga_mode_init)(t_x502_hnd hnd);
typedef enum {
X502_STREAM_FLAG_SINGLE = 0x01,
X502_STREAM_FLAG_NO_REQUEST = 0x02
} t_x502_streams_flags;
typedef struct {
uint16_t id_reg_addr;
uint16_t in_stream_buf_min;
uint16_t ioctl_max_data_size;
uint16_t bf_mem_block_size;
uint16_t flash_rd_size; /**< Максимальный размер чтения из flash-памяти за один запрос */
uint16_t flash_wr_size; /**< Максимальный размер записи во flash-память за один запрос */
t_x502_iface_free_devinfo_ptr free_devinfo_ptr;
t_x502_iface_open open;
t_x502_iface_close close;
t_x502_iface_fpga_reg_read fpga_reg_read;
t_x502_iface_fpga_reg_write fpga_reg_write;
t_x502_iface_stream_cfg stream_cfg;
t_x502_iface_stream_start stream_start;
t_x502_iface_stream_stop stream_stop;
t_x502_iface_stream_free stream_free;
t_x502_iface_stream_running stream_running;
t_x502_iface_stream_read stream_read;
t_x502_iface_stream_write stream_write;
t_x502_iface_stream_get_rdy_cnt stream_get_rdy_cnt;
t_x502_iface_bf_mem_block_rd bf_mem_block_rd;
t_x502_iface_bf_mem_block_wr bf_mem_block_wr;
t_x502_iface_bf_firm_load bf_firm_load;
t_x502_iface_flash_rd flash_rd;
t_x502_iface_flash_wr flash_wr;
t_x502_iface_flash_erase flash_erase;
t_x502_iface_flash_set_prot flash_set_prot;
t_x502_iface_reload_devinfo reload_dev_info;
t_x502_iface_cycle_load_start cycle_load_start;
t_x502_iface_cycle_setup cycle_setup;
t_x502_iface_cycle_stop cycle_stop;
t_x502_iface_cycle_check_setup cycle_check_setup;
t_x502_iface_fpga_mode_init fpga_mode_init;
t_x502_iface_gen_ioctl gen_ioctl;
t_x502_iface_check_feature check_feature;
} t_x502_dev_iface;
typedef enum {
STREAM_IN_WRD_ADC = 0,
STREAM_IN_WRD_DIN = 1,
STREAM_IN_WRD_MSG = 2,
STREAM_IN_WRD_USR = 3,
STREAM_IN_WRD_TSP = 4,
} t_stream_in_wrd_type;
typedef enum {
PRIV_FLAGS_OPENED = 0x0001,
PRIV_FLAGS_PRELOAD_DONE = 0x0002,
PRIV_FLAGS_CYCLE_MODE = 0x0004,
PRIV_FLAGS_STREAM_RUN = 0x0080
} t_x502_state_flags;
typedef enum {
X502_RELOAD_FLAGS_NO_DAC = 0x0001,
X502_RELOAD_FLAGS_NO_ADC = 0x0002
} t_x502_reload_flags;
/** структура, описывающая параметры логического канала */
typedef struct {
uint32_t ch; /** физический номер канала */
uint32_t mode; /** режим работы канала из #t_l502_ch_mode */
uint32_t range; /** диапазон измерения */
uint32_t avg; /** коэффициент усреднения */
} t_x502_lch;
typedef struct {
t_x502_lch lch[X502_LTABLE_MAX_CH_CNT];
uint32_t lch_cnt;
uint32_t adc_freq_div;
uint32_t adc_frame_delay;
uint32_t din_freq_div;
uint32_t sync_mode;
uint32_t sync_start_mode;
uint32_t ref_freq;
double ext_ref_freq;
uint32_t out_freq_div;
uint32_t adc_sync_ch;
uint32_t adc_sync_range;
uint32_t adc_sync_mode;
double adc_sync_val;
double dac_range;
uint32_t dac_code_max;
uint32_t adc_code_max;
const double *f_scales;
} t_x502_settings;
typedef struct st_x502 {
uint32_t sign; /* признак описателя L502/E502 */
t_x502_iface iface;
const t_x502_dev_iface *iface_hnd;
void *iface_data;
t_x502_state_flags flags; /* флаги состояния платы */
t_x502_streams streams; /* какие синхронные потоки разрешены */
t_x502_mode mode; /* режим работы (через ПЛИС или DSP) */
t_x502_info info;
t_x502_settings set; /* настройки платы */
t_x502_stream_ch_params stream_pars[X502_STREAM_CH_CNT];
uint32_t last_dout; /* последнее выданное значение на DIGOUT */
uint32_t proc_adc_ch; /* ожидаемый логический канал для следующей ProcessData() */
t_mutex mutex_cfg; /* мьютекс для доступа к полям параметров и состояния модуля */
t_mutex mutex_bf; /* мьютекс для доступа к памяти сигнального процессора */
uint32_t bf_ver; /* версия прошивки BlackFin, если есть */
uint32_t bf_features; /* дополниельные возможности, поддерживаемые прошивкой */
} t_x502;
typedef int32_t (APIENTRY *t_x502_get_devinfo_list_cb)(t_x502_devrec* list, uint32_t size,
uint32_t flags, uint32_t* devcnt);
bool x502_is_E16(t_x502_hnd hnd);
int x502_check_eeprom(t_x502_hnd hnd, uint32_t flags);
X502_EXPORT(int32_t) X502_DevRecordInit(t_x502_devrec *info);
X502_EXPORT(int32_t) X502_Open(t_x502_hnd hnd, const char* serial,
const char *devname, t_x502_get_devinfo_list_cb get_list);
X502_EXPORT(int32_t) X502_GetSerialList(char serials[][X502_SERIAL_SIZE], uint32_t size,
uint32_t flags, uint32_t *devcnt, const char *devname,
t_x502_get_devinfo_list_cb get_list);
X502_EXPORT(int32_t) X502_FpgaRegWrite(t_x502_hnd hnd, uint32_t reg, uint32_t val);
X502_EXPORT(int32_t) X502_FpgaRegRead(t_x502_hnd hnd, uint32_t reg, uint32_t *val);
X502_EXPORT(int32_t) X502_ReloadDevInfo(t_x502_hnd hnd, uint32_t flags);
int32_t bf_fpga_reg_rd(t_x502_hnd hnd, uint32_t addr, uint32_t* val);
int32_t bf_fpga_reg_wr(t_x502_hnd hnd, uint32_t addr, uint32_t val);
#define x502_bf_set_par(hnd, par, data, size) X502_BfExecCmd(hnd, L502_BF_CMD_CODE_SET_PARAM, \
par, data, size, NULL, 0, X502_BF_CMD_DEFAULT_TOUT, NULL)
#define x502_bf_get_par(hnd, par, data, size) X502_BfExecCmd(hnd, L502_BF_CMD_CODE_GET_PARAM, \
par, NULL, 0, data, size, X502_BF_CMD_DEFAULT_TOUT, NULL)
#define FILL_HARD_ID_FLAGS(devflags, hard_id) do { \
if (hard_id & 0x01) { \
devflags |= X502_DEVFLAGS_DAC_PRESENT; \
} else { \
devflags &= ~X502_DEVFLAGS_DAC_PRESENT; \
} \
if (hard_id & 0x02) { \
devflags |= X502_DEVFLAGS_GAL_PRESENT; \
} else { \
devflags &= ~X502_DEVFLAGS_GAL_PRESENT; \
} \
if (hard_id & 0x04) {\
devflags |= X502_DEVFLAGS_BF_PRESENT; \
} else { \
devflags &= ~X502_DEVFLAGS_BF_PRESENT; \
} \
} while(0)
#define STREAM_OUT_IRQ_STEP(hnd) (hnd->stream_pars[X502_STREAM_CH_OUT].step ? \
hnd->stream_pars[X502_STREAM_CH_OUT].step : \
X502_DMA_OUT_IRQ_STEP/hnd->set.out_freq_div)
#define STREAM_OUT_CFG(hnd, err) do { \
t_x502_stream_ch_params params; \
memset(&params, 0, sizeof(params)); \
params.buf_size = hnd->stream_pars[X502_STREAM_CH_OUT].buf_size ? \
hnd->stream_pars[X502_STREAM_CH_OUT].buf_size : \
X502_DMA_OUT_BUF_SIZE; \
params.step = STREAM_OUT_IRQ_STEP(hnd); \
err = hnd->iface_hnd->stream_cfg(hnd, X502_STREAM_CH_OUT, &params); \
} while(0)
#endif // X502API_PRIVATE_H

717
lib/x502/x502api_streams.c Normal file
View File

@ -0,0 +1,717 @@
#include "x502api_private.h"
#include "x502_fpga_regs.h"
#include "l502_bf_cmd_defs.h"
#include "ltimer.h"
#include <string.h>
#include <stdlib.h>
/* разрешение/запрещение потоков ввода вывода в соответствии с полем hnd->streams */
static int32_t f_set_streams(t_x502_hnd hnd, uint32_t streams) {
int32_t err = X502_ERR_OK;
if (hnd->mode == X502_MODE_FPGA) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOARITH_IN_STREAM_ENABLE,
(streams & X502_STREAM_ADC ? 0x01 : 0) |
(streams & X502_STREAM_DIN ? 0x02 : 0));
}
if (err == X502_ERR_OK) {
hnd->streams = streams;
}
return err;
}
/* Функция автоматического рассчета параметов DMA для входного потока
на основе частоты сбора данных */
static int32_t f_stream_in_cfg(t_x502 *hnd) {
int32_t err = X502_ERR_OK;
t_x502_stream_ch_params params;
double din_freq = 0;
uint32_t total_size = 0;
double ref_freq;
memset(&params, 0, sizeof(params));
X502_GetRefFreqValue(hnd, &ref_freq);
/* рассчитываем частоту сбора для потоков АЦП и DIN */
if (hnd->streams & X502_STREAM_ADC) {
double f_frame;
X502_GetAdcFreq(hnd, NULL, &f_frame);
din_freq = f_frame*hnd->set.lch_cnt;
}
if (hnd->streams & X502_STREAM_DIN) {
din_freq+=ref_freq/hnd->set.din_freq_div;
}
/* размер полного буфера определяем таким, чтобы его хватило на
L502_DMA_IN_BUF_FOR_SEC секунд постоянного сбора, но не меньше минимального
размера */
total_size = (uint32_t)(X502_DMA_IN_BUF_FOR_SEC*din_freq);
if (total_size < hnd->iface_hnd->in_stream_buf_min)
total_size = hnd->iface_hnd->in_stream_buf_min;
/* рассчитываем IRQ_STEP, чтобы он был L502_DMA_IN_MAX_IRQ_PER_SEC
в секунду */
params.step = hnd->stream_pars[X502_STREAM_CH_IN].step ?
hnd->stream_pars[X502_STREAM_CH_IN].step :
(din_freq>X502_DMA_IN_MAX_IRQ_PER_SEC) ?
(uint32_t)(din_freq/X502_DMA_IN_MAX_IRQ_PER_SEC) : 1;
/* для эффиктивности делаем размер буфера кратным irq_step */
total_size = ((total_size+params.step-1)/params.step)*params.step;
params.buf_size = hnd->stream_pars[X502_STREAM_CH_IN].buf_size ?
hnd->stream_pars[X502_STREAM_CH_IN].buf_size : total_size;
err = hnd->iface_hnd->stream_cfg(hnd, X502_STREAM_CH_IN, &params);
if ((err == X502_ERR_OK) && (hnd->mode == X502_MODE_DSP)) {
/* для BlackFin нужно так же установить еще шаг прерываний для
приема данных от SPORT'а */
uint32_t size;
err = x502_bf_get_par(hnd, L502_BF_PARAM_IN_BUF_SIZE, &size, 1);
if (err == X502_ERR_OK) {
uint32_t instep = params.step;
if (instep>size/4) {
instep=size/4;
}
if (instep > 0x8000)
instep = 0x8000;
err = x502_bf_set_par(hnd, L502_BF_PARAM_IN_STEP_SIZE, &instep, 1);
}
}
return err;
}
static int32_t f_out_stream_preload(t_x502 *hnd) {
int32_t err;
STREAM_OUT_CFG(hnd, err);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->stream_start(hnd, X502_STREAM_CH_OUT, 0);
if ((err == X502_ERR_OK) && (hnd->mode == X502_MODE_DSP)) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_PRELOAD, 0, NULL, 0,
NULL, 0, X502_BF_REQ_TOUT, NULL);
}
if (err == X502_ERR_OK) {
hnd->flags |= PRIV_FLAGS_PRELOAD_DONE;
}
return err;
}
X502_EXPORT(int32_t) X502_StreamsEnable(t_x502_hnd hnd, uint32_t streams) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_STREAM_EN, streams,
NULL, 0, NULL, 0, X502_BF_REQ_TOUT, NULL);
if (err == X502_ERR_OK)
hnd->streams |= streams;
} else {
if (hnd->flags & PRIV_FLAGS_STREAM_RUN) {
uint32_t old_streams = hnd->streams;
hnd->streams |= streams;
/* если не было разрешено потока на ввод до этого,
а при вызове стал разрешен => инициализируем его */
if ((err == X502_ERR_OK) && !(old_streams & X502_STREAM_ALL_IN) &&
(streams & X502_STREAM_ALL_IN)) {
err = f_stream_in_cfg(hnd);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->stream_start(hnd, X502_STREAM_CH_IN, 0);
} else if ((err == X502_ERR_OK) && ((old_streams & X502_STREAM_ALL_IN) !=
(streams & X502_STREAM_ALL_IN))) {
err =f_stream_in_cfg(hnd);
}
/* Запись в регистры плиса имеет смысл делать только перед запуском
или во время запуска синхронного сбора, т.к. пока сбор не запущен
- не вляют. но в старых версиях ПЛИС могли приводит к сдвигу по
времени первого отсчета АЦП.
Разрешение потока в ПЛИС следует делать уже после stream_start,
чтобы ПК был готов принимать данные */
err = f_set_streams(hnd, hnd->streams | streams);
} else {
hnd->streams |= streams;
}
}
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}
X502_EXPORT(int32_t) X502_StreamsDisable(t_x502_hnd hnd, uint32_t streams) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_STREAM_DIS, streams,
NULL, 0, NULL, 0, X502_BF_REQ_TOUT, NULL);
if (err == X502_ERR_OK)
hnd->streams &= ~streams;
} else {
if (hnd->flags & PRIV_FLAGS_STREAM_RUN) {
uint32_t old_streams = hnd->streams;
err = f_set_streams(hnd, hnd->streams & ~streams);
/* если все потоки на ввод были запрещены, то
останавливаем их */
if ((err == X502_ERR_OK) && (old_streams & X502_STREAM_ALL_IN) &&
!(hnd->streams & X502_STREAM_ALL_IN)) {
err = hnd->iface_hnd->stream_stop(hnd, X502_STREAM_CH_IN, 0);
}
if ((err == X502_ERR_OK) && (old_streams & X502_STREAM_ALL_OUT) &&
!(hnd->streams & X502_STREAM_ALL_OUT)) {
err = hnd->iface_hnd->stream_stop(hnd, X502_STREAM_CH_OUT, 0);
if (err == X502_ERR_OK) {
hnd->flags &= ~PRIV_FLAGS_PRELOAD_DONE;
}
}
} else {
hnd->streams &= ~streams;
}
}
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}
X502_EXPORT(int32_t) X502_GetEnabledStreams(t_x502_hnd hnd, uint32_t* streams) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (streams == NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK)
*streams = hnd->streams;
return err;
}
X502_EXPORT(int32_t) X502_StreamsStart(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_RUNNING;
if ((err == X502_ERR_OK) && (hnd->mode==X502_MODE_FPGA)) {
uint32_t reg;
err = hnd->iface_hnd->fpga_reg_read(hnd, X502_REGS_IOHARD_IO_MODE, &reg);
if ((err == X502_ERR_OK) && !(reg & X502_REGBIT_ADC_SLV_CLK_LOCK_Msk))
err = X502_ERR_REF_FREQ_NOT_LOCKED;
}
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
int in_started = 0;
f_set_streams(hnd, hnd->streams);
/** @todo корректные действия, если сбор в Bf не остановлен */
/* выполняем предзагрузку первого слова выходного потока и
коммутатора АЦП (при наличии DSP это делает DSP) */
if ((err == X502_ERR_OK) && (hnd->mode==X502_MODE_FPGA)) {
/* предзагрузку значения на вывод делаем только если реально данные уже были
* предзагружены в буфер платы */
if ((hnd->streams & X502_STREAM_ALL_OUT) &&
(hnd->flags & (PRIV_FLAGS_PRELOAD_DONE | PRIV_FLAGS_CYCLE_MODE))) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_OUTSWAP_BFCTL, 1);
}
/* Предзагрузку АЦП должны делать всегда, так как по этой функции
выполняется часть инициализации параметров синхронного сбора!
Так как конвейер автомата управления входной коммутации АЦП состоит
из 2-х стадий, для корректного синхронного старта необходимо в
ыполнить два раза предзагрузку. В противном случае,
время момента первого отсчета может не совпадать с моментом
запуска синхронизации
*/
if (err == X502_ERR_OK)
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_PRELOAD_ADC, 1);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_PRELOAD_ADC, 1);
SLEEP_MS(20);
}
/* запуск потока на ввод выполняем при запуске синхронного ввода-вывода */
if ((err == X502_ERR_OK) && (hnd->streams & X502_STREAM_ALL_IN)) {
err = f_stream_in_cfg(hnd);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->stream_start(hnd, X502_STREAM_CH_IN, 0);
if (err == X502_ERR_OK)
in_started = 1;
}
if (err == X502_ERR_OK) {
if (hnd->mode == X502_MODE_FPGA) {
/* взводим сигнал GO, указывающий что запущен синхронных ввод-вывод */
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_GO_SYNC_IO, 1);
} else if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_STREAM_START, 0,
NULL, 0, NULL, 0, X502_BF_CMD_DEFAULT_TOUT, NULL);
} else {
err = X502_ERR_INVALID_MODE;
}
}
if (err && in_started) {
hnd->iface_hnd->stream_free(hnd, X502_STREAM_CH_IN, 0);
}
if (err == X502_ERR_OK) {
hnd->flags |= PRIV_FLAGS_STREAM_RUN;
hnd->proc_adc_ch = 0;
}
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}
X502_EXPORT(int32_t) X502_StreamsStop(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
int32_t stop_err1, stop_err2;
if (hnd->mode==X502_MODE_FPGA) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_GO_SYNC_IO, 0);
} else if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_STREAM_STOP, 0,
NULL, 0, NULL, 0, X502_BF_CMD_DEFAULT_TOUT, NULL);
}
stop_err1 = hnd->iface_hnd->stream_free(hnd, X502_STREAM_CH_IN, 0);
stop_err2 = hnd->iface_hnd->stream_free(hnd, X502_STREAM_CH_OUT, 0);
if (err == X502_ERR_OK)
err = stop_err1;
if (err == X502_ERR_OK)
err = stop_err2;
hnd->flags &= ~(PRIV_FLAGS_STREAM_RUN | PRIV_FLAGS_PRELOAD_DONE | PRIV_FLAGS_CYCLE_MODE);
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}
X502_EXPORT(int32_t) X502_IsRunning(t_x502_hnd hnd) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
uint32_t bf_mode=0;
if ((err == X502_ERR_OK) && (hnd->mode==X502_MODE_DSP)) {
err = x502_bf_get_par(hnd, L502_BF_PARAM_STREAM_MODE, &bf_mode, 1);
}
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
if (hnd->mode==X502_MODE_DSP) {
if (bf_mode==L502_BF_MODE_IDLE) {
hnd->flags &= ~PRIV_FLAGS_STREAM_RUN;
} else {
hnd->flags |= PRIV_FLAGS_STREAM_RUN;
}
}
if (!(hnd->flags & PRIV_FLAGS_STREAM_RUN))
err = X502_ERR_STREAM_IS_NOT_RUNNING;
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}
X502_EXPORT(int32_t) X502_Recv(t_x502_hnd hnd, uint32_t* buf, uint32_t size, uint32_t tout) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (buf==NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->stream_read(hnd, buf, size, tout);
}
return err;
}
X502_EXPORT(int32_t) X502_Send(t_x502_hnd hnd, const uint32_t* buf, uint32_t size, uint32_t tout) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (buf==NULL))
err = X502_ERR_INVALID_POINTER;
/* если разрешен синхронный вывод, но не было
* вызова X502_PreloadStart() или не был установлен синхронных режим, то
* делаем запуск потока вывода при первой записи */
if ((err == X502_ERR_OK) && (hnd->streams & X502_STREAM_ALL_OUT)) {
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
if (!(hnd->flags & (PRIV_FLAGS_PRELOAD_DONE | PRIV_FLAGS_CYCLE_MODE))) {
err = f_out_stream_preload(hnd);
}
osspec_mutex_release(hnd->mutex_cfg);
}
}
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->stream_write(hnd, buf, size, tout);
}
return err;
}
X502_EXPORT(int32_t)X502_PreloadStart(t_x502_hnd hnd) {
int err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
err = f_out_stream_preload(hnd);
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}
X502_EXPORT(int32_t) X502_GetRecvReadyCount(t_x502_hnd hnd, uint32_t *rdy_cnt) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (rdy_cnt==NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK)
err = hnd->iface_hnd->stream_get_rdy_cnt(hnd, X502_STREAM_CH_IN, rdy_cnt);
return err;
}
X502_EXPORT(int32_t) X502_GetSendReadyCount(t_x502_hnd hnd, uint32_t *rdy_cnt) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (rdy_cnt==NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK)
err = hnd->iface_hnd->stream_get_rdy_cnt(hnd, X502_STREAM_CH_OUT, rdy_cnt);
return err;
}
static int32_t f_check_stream_ch_par_en(t_x502_hnd hnd, uint32_t stream_ch) {
int32_t err = 0;
if (stream_ch == X502_STREAM_CH_IN) {
if ((hnd->flags & PRIV_FLAGS_STREAM_RUN)
&& (hnd->streams & X502_STREAM_ALL_IN)) {
err = X502_ERR_STREAM_IS_RUNNING;
}
} else if (stream_ch == X502_STREAM_CH_OUT) {
if ((hnd->flags & (PRIV_FLAGS_PRELOAD_DONE | PRIV_FLAGS_STREAM_RUN))
&& (hnd->streams & X502_STREAM_ALL_OUT)) {
err = X502_ERR_STREAM_IS_RUNNING;
}
} else {
err = X502_ERR_INVALID_STREAM_CH;
}
return err;
}
X502_EXPORT(int32_t) X502_SetStreamBufSize(t_x502_hnd hnd, uint32_t ch, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = f_check_stream_ch_par_en(hnd, ch);
if (err == X502_ERR_OK)
hnd->stream_pars[ch].buf_size = size;
return err;
}
X502_EXPORT(int32_t) X502_SetStreamStep(t_x502_hnd hnd, uint32_t ch, uint32_t step) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = f_check_stream_ch_par_en(hnd, ch);
if (err == X502_ERR_OK)
hnd->stream_pars[ch].step = step;
return err;
}
X502_EXPORT(int32_t) X502_OutCycleLoadStart(t_x502_hnd hnd, uint32_t size) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
/** @todo проверить правильность момента вызова */
err = hnd->iface_hnd->cycle_load_start(hnd, size);
/* если еще не была выполнена предзагрузка сигнала, то посылаем DSP
команду, чтобы успел подгрузить данные до старта выдачи */
if ((err == X502_ERR_OK) && !(hnd->flags & (PRIV_FLAGS_CYCLE_MODE | PRIV_FLAGS_PRELOAD_DONE))) {
if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_PRELOAD, 0, NULL, 0,
NULL, 0, X502_BF_REQ_TOUT, NULL);
}
}
if (err == X502_ERR_OK)
hnd->flags |= PRIV_FLAGS_CYCLE_MODE;
osspec_mutex_release(hnd->mutex_cfg);
}
}
return err;
}
static int32_t f_cycle_setup_wait(t_x502_hnd hnd, uint32_t tout) {
int32_t err = X502_ERR_OK;
t_ltimer tmr;
uint32_t done = 0;
int first = 1;
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout));
do {
if (!first) {
SLEEP_MS(5);
} else {
first = 0;
}
err = X502_OutCycleCheckSetupDone(hnd, &done);
} while (!done && !ltimer_expired(&tmr) && (err == X502_ERR_OK));
if ((err == X502_ERR_NOT_SUP_BY_DRIVER) || (err == X502_ERR_NOT_SUP_BY_FIRMWARE)) {
done = 1;
err = X502_ERR_OK;
}
if ((err == X502_ERR_OK) && !done) {
err = X502_ERR_OUT_CYCLE_SETUP_TOUT;
}
return err;
}
X502_EXPORT(int32_t) X502_OutCycleSetup(t_x502_hnd hnd, uint32_t flags) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->cycle_setup(hnd, flags);
if ((err == X502_ERR_OK) && (flags & X502_OUT_CYCLE_FLAGS_WAIT_DONE))
err = f_cycle_setup_wait(hnd, X502_OUT_CYCLE_WAIT_TOUT);
return err;
}
X502_EXPORT(int32_t) X502_OutCycleStop(t_x502_hnd hnd, uint32_t flags) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = hnd->iface_hnd->cycle_stop(hnd, flags);
if (err == X502_ERR_OK) {
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
hnd->flags &= ~PRIV_FLAGS_CYCLE_MODE;
osspec_mutex_release(hnd->mutex_cfg);
}
}
if ((err == X502_ERR_OK) && (flags & X502_OUT_CYCLE_FLAGS_WAIT_DONE))
err = f_cycle_setup_wait(hnd, X502_OUT_CYCLE_WAIT_TOUT);
return err;
}
X502_EXPORT(int32_t) X502_OutCycleCheckSetupDone(t_x502_hnd hnd, uint32_t *done) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->cycle_check_setup(hnd, done);
}
return err;
}
X502_EXPORT(int32_t) X502_OutGetStatusFlags(t_x502_hnd hnd, uint32_t *status) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->check_feature(hnd, X502_FEATURE_OUT_STATUS_FLAGS);
}
if (err == X502_ERR_OK) {
if (hnd->mode == X502_MODE_DSP) {
if (hnd->bf_features & L502_BF_FEATURE_OUT_STATUS_FLAGS) {
uint32_t recvd;
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_GET_OUT_STATUS,
0, NULL, 0, status, 1, X502_BF_CMD_DEFAULT_TOUT,
&recvd);
if ((err == X502_ERR_OK) && (recvd < 1)) {
err = X502_ERR_BF_CMD_RETURN_INSUF_DATA;
}
} else {
err = X502_ERR_NOT_IMPLEMENTED;
}
} else {
err = X502_FpgaRegRead(hnd, X502_REGS_IOHARD_OUTSWAP_ERROR, status);
}
}
return err;
}
X502_EXPORT(int32_t) X502_AsyncGetAdcFrame(t_x502_hnd hnd, uint32_t flags,
uint32_t tout, double* data) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if ((err == X502_ERR_OK) && (data==NULL))
err = X502_ERR_INVALID_POINTER;
if (err == X502_ERR_OK)
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err == X502_ERR_OK) {
if (hnd->mode == X502_MODE_FPGA) {
/* если запущен хоть один поток на ввод синхронно, то ввод кадра
* не возможне */
if ((hnd->flags & PRIV_FLAGS_STREAM_RUN) && (hnd->streams & X502_STREAM_ALL_IN)) {
err = X502_ERR_STREAM_IS_RUNNING;
}
if (err == X502_ERR_OK) {
int need_stop = 0;
int old_streams = hnd->streams;
uint32_t *wrds = NULL;
int32_t rcv_size = hnd->set.lch_cnt;
/* разрешаем поток для АЦП */
err = f_set_streams(hnd, (hnd->streams & ~X502_STREAM_ALL_IN)
| X502_STREAM_ADC);
hnd->proc_adc_ch = 0;
if (err == X502_ERR_OK) {
/* инициализируем буфер для приема - достаточно всего на один кадр */
t_x502_stream_ch_params par = hnd->stream_pars[X502_STREAM_CH_IN];
hnd->stream_pars[X502_STREAM_CH_IN].buf_size = hnd->iface_hnd->in_stream_buf_min;
hnd->stream_pars[X502_STREAM_CH_IN].step = hnd->set.lch_cnt;
err = f_stream_in_cfg(hnd);
/* восстанавливаем параметры в структуре, что были заданы
до этой функции */
hnd->stream_pars[X502_STREAM_CH_IN] = par;
}
if (err == X502_ERR_OK) {
/* выделяем массив для необработанных отсчетов */
wrds = malloc(sizeof(wrds[0])*rcv_size);
if (wrds==NULL)
err = X502_ERR_MEMORY_ALLOC;
}
/* предзагрузка логической таблицы для АЦП */
if (err == X502_ERR_OK)
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_PRELOAD_ADC, 1);
/* запуск канала DMA на прием данных */
if (err == X502_ERR_OK) {
err = hnd->iface_hnd->stream_start(hnd, X502_STREAM_CH_IN,
X502_STREAM_FLAG_SINGLE);
}
/* если общий синхронный ввод не был запущен - разрешаем его */
if (err == X502_ERR_OK) {
if (!(hnd->flags & PRIV_FLAGS_STREAM_RUN)) {
err = hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_GO_SYNC_IO, 1);
if (err == X502_ERR_OK)
need_stop = 1;
}
}
if (err == X502_ERR_OK) {
/* принимаем отсчеты от одного кадра */
int32_t rcv = X502_Recv(hnd, wrds, rcv_size, tout);
if (rcv < 0) {
err = rcv;
} else if (rcv!=rcv_size) {
err = X502_ERR_RECV_INSUFFICIENT_WORDS;
} else {
err = X502_ProcessAdcData(hnd, wrds, data, (uint32_t*)&rcv_size, flags);
}
}
/* если в этой функции запустили синхронный сбор, то останвливаем его */
if (need_stop)
hnd->iface_hnd->fpga_reg_write(hnd, X502_REGS_IOHARD_GO_SYNC_IO, 0);
hnd->proc_adc_ch = 0;
hnd->iface_hnd->stream_free(hnd, X502_STREAM_CH_IN, 0);
/* восстанавливаем те потоки, которые были разрешены */
f_set_streams(hnd, old_streams);
free(wrds);
}
} else if (hnd->mode == X502_MODE_DSP) {
err = X502_BfExecCmd(hnd, L502_BF_CMD_CODE_ADC_GET_FRAME,
0, NULL, 0, (uint32_t*)data, 2*hnd->set.lch_cnt,
X502_BF_CMD_DEFAULT_TOUT, NULL);
} else {
err = X502_ERR_INVALID_MODE;
}
osspec_mutex_release(hnd->mutex_cfg);
}
return err;
}
X502_EXPORT(int32_t) X502_ManualStreamStart(t_x502_hnd hnd, uint32_t stream_ch, uint32_t flags) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = X502_StreamsEnable(hnd, stream_ch == X502_STREAM_CH_IN ? X502_STREAM_ALL_IN : X502_STREAM_ALL_OUT );
if (err == X502_ERR_OK) {
if (stream_ch == X502_STREAM_CH_IN) {
err = f_stream_in_cfg(hnd);
} else {
STREAM_OUT_CFG(hnd, err);
}
}
if (err == X502_ERR_OK)
err = hnd->iface_hnd->stream_start(hnd, stream_ch, flags);
if ((err == X502_ERR_OK) && (stream_ch == X502_STREAM_CH_OUT)) {
err = osspec_mutex_lock(hnd->mutex_cfg, X502_MUTEX_CFG_LOCK_TOUT);
if (err==X502_ERR_OK) {
hnd->flags |= PRIV_FLAGS_PRELOAD_DONE;
osspec_mutex_release(hnd->mutex_cfg);
}
}
return err;
}
X502_EXPORT(int32_t) X502_ManualStreamStop(t_x502_hnd hnd, uint32_t stream_ch) {
int32_t err = X502_CHECK_HND_OPENED(hnd);
if (err == X502_ERR_OK)
err = X502_StreamsDisable(hnd, stream_ch == X502_STREAM_CH_IN ? X502_STREAM_ALL_IN : X502_STREAM_ALL_OUT );
if (err == X502_ERR_OK)
err = hnd->iface_hnd->stream_free(hnd, stream_ch, 0);
return err;
}

137
lib/x502/x502tstp.c Normal file
View File

@ -0,0 +1,137 @@
#include <string.h>
#include "x502tstp.h"
typedef enum {
STREAM_IN_WRD_ADC = 0,
STREAM_IN_WRD_DIN = 1,
STREAM_IN_WRD_MSG = 2,
STREAM_IN_WRD_USR = 3,
STREAM_IN_WRD_TSP = 4,
} t_stream_in_wrd_type;
#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
static uint64_t get_secssec(uint32_t wrd1, uint32_t wrd2, uint32_t wrd3) {
uint64_t wrd1_sec = TSP_WRD1_GET_SSEC(wrd1);
uint64_t wrd2_sec = TSP_WRD2_GET_SECSSEC(wrd2);
uint64_t wrd3_sec = TSP_WRD3_GET_SEC(wrd3);
uint64_t ret;
ret = wrd1_sec | wrd2_sec | wrd3_sec;
return ret;
//return TSP_WRD3_GET_SEC(wrd3) | TSP_WRD2_GET_SECSSEC(wrd2) | TSP_WRD1_GET_SSEC(wrd1);
}
#if 0
static int32_t get_ssec(uint32_t wrd1, uint32_t wrd2, uint32_t wrd3) {
int32_t ret;
ret = (TSP_WRD2_GET_SSEC(wrd2) << TSP_WRD1_SSEC_LEN) | TSP_WRD1_GET_SSEC(wrd1);
if(ret < 0) {
fprintf(stderr, "unexpected get_ssec ret=%d\n", ret);
while(1);
}
return ret;
}
static uint32_t get_sec(uint32_t wrd2) {
return ((wrd2 & TSP_WRD2_SEC_MASK) >> TSP_WRD2_SSEC_LEN);
}
#endif
X502_EXPORT(bool) X502_tstp_get_lock(t_x502_tstp_state *tstp_state) {
if (TSP_WRD1_IS_LOCK(tstp_state->wrd[1])) {
return true;
} else {
return false;
}
}
X502_EXPORT(void) X502_tstp_process_wrd(t_x502_tstp_state *tstp_state, uint32_t wrd) {
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(wrd);
if (type == STREAM_IN_WRD_TSP) {
if (TSP_WRD_NUM(wrd) == 3) {
uint64_t cur_tspt_time;
tstp_state->wrd[3] = wrd;
cur_tspt_time = get_secssec(tstp_state->wrd[1], tstp_state->wrd[2], tstp_state->wrd[3]);
if (TSP_WRD1_IS_FMARK(tstp_state->wrd[1])) {
tstp_state->tstp_start_time = cur_tspt_time;
#ifdef DEBUG
if (tstp_state->tstp_mark_rcvd) {
fprintf(stderr, "fmark && tstp_mark_rcv unexpected!\n");
}
#endif
tstp_state->tstp_mark_rcvd = true;
}
tstp_state->adcwrds_after_tstp = 0;
tstp_state->dinwrds_after_tstp = 0;
tstp_state->wrds_after_tstp = 0;
if (cur_tspt_time < tstp_state->last_tstp_time) {
#ifdef DEBUG
fprintf(stderr, "cur = %" PRIu64 " last = %" PRIu64 "\n", cur_tspt_time, tstp_state->last_tstp_time);
fprintf(stderr, "cur_tstp < last_tstp unexpected!\n");
#endif
return;
}
//printf("tstp time = %d.%09d\n", TSTP_SECSSEC_TO_SEC(cur_tspt_time), TSTP_SSEC_TO_NSEC(cur_tspt_time));
tstp_state->last_tstp_time = cur_tspt_time;
} else {
if (TSP_WRD_NUM(wrd) == 0) {
tstp_state->wrd[0] = wrd;
} else
if (TSP_WRD_NUM(wrd) == 1) {
tstp_state->wrd[1] = wrd;
} else
if (TSP_WRD_NUM(wrd) == 2) {
tstp_state->wrd[2] = wrd;
}
tstp_state->wrds_after_tstp++;
}
} else {
if (type == STREAM_IN_WRD_DIN) {
tstp_state->dinwrds_after_tstp++;
} else
if (type == STREAM_IN_WRD_ADC) {
tstp_state->adcwrds_after_tstp++;
}
tstp_state->wrds_after_tstp++;
}
tstp_state->processed_wrds++;
tstp_state->cur_wrd = wrd;
}
X502_EXPORT(void) X502_tstp_init(t_x502_tstp_state *tstp_state, uint32_t adc_freq, uint32_t din_freq) {
memset(tstp_state, 0, sizeof(*tstp_state));
tstp_state->adc_freq = adc_freq;
tstp_state->din_freq = din_freq;
}
X502_EXPORT(void) X502_tstp_get_curwrd_time(t_x502_tstp_state *tstp_state, t_x502_tstptime *ret) {
t_x502_tstptime wrd_time;
t_stream_in_wrd_type type = STREAM_IN_WRD_TYPE(tstp_state->cur_wrd);
if (type == STREAM_IN_WRD_DIN) {
wrd_time = tstp_state->last_tstp_time + ((double)(tstp_state->dinwrds_after_tstp - 1) / tstp_state->din_freq) * (1U << 31);
} else
if (type == STREAM_IN_WRD_ADC) {
wrd_time = tstp_state->last_tstp_time + ((double)(tstp_state->adcwrds_after_tstp - 1)/ tstp_state->adc_freq) * (1U << 31);
} else {
// чтобы посчитать время слова отличного от АЦП и DIN нужно знать частоту их появления
wrd_time = tstp_state->last_tstp_time + ((double)(tstp_state->adcwrds_after_tstp - 1)/ tstp_state->adc_freq) * (1U << 31);
wrd_time += tstp_state->last_tstp_time + ((double)(tstp_state->dinwrds_after_tstp - 1) / tstp_state->din_freq) * (1U << 31);
}
if (ret) {
*ret = wrd_time;
}
}

140
lib/x502/x502tstp.h Normal file
View File

@ -0,0 +1,140 @@
#ifndef E502TSTP_H
#define E502TSTP_H
#include "x502api.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup tstpfunc_list Функции для работы с метками времени
@{ **/
/***************************************************************************//**
@addtogroup tstptype_list Константы и перечисления
@{
*****************************************************************************/
#define TSP_NSEC_PER_SEC (1000000000)
#define TSP_WRD1_SSEC_LEN (24)
#define TSP_WRD2_SSEC_LEN (7)
#define TSP_WRD2_SEC_LEN (19)
#define TSP_WRD3_SEC_LEN (13)
#define TSP_SSEC_WIDTH (31)
#define TSP_WRD_NUM(wrd) (((wrd) >> 26) & 3)
#define TSP_WRD0_ADC_CLK_NUM_MASK (0x3ffffff)
#define TSP_WRD1_LOCK_MASK (1 << 25)
#define TSP_WRD1_FMARK_MASK (1 << 24)
#define TSP_WRD1_SSEC_MASK ((1 << TSP_WRD1_SSEC_LEN) - 1)
#define TSP_WRD2_SEC_MASK (0x3ffff80)
#define TSP_WRD2_SSEC_MASK ((1 << TSP_WRD2_SSEC_LEN) - 1)
#define TSP_WRD2_SECSSEC_MASK ((1 << (TSP_WRD2_SEC_LEN + TSP_WRD2_SSEC_LEN)) - 1)
#define TSP_WRD3_SEC_MASK ((1 << TSP_WRD3_SEC_LEN) - 1)
#define TSP_WRD1_IS_FMARK(wrd) (!!((wrd) & TSP_WRD1_FMARK_MASK))
#define TSP_WRD1_IS_LOCK(wrd) (!!((wrd) & TSP_WRD1_LOCK_MASK))
#define TSP_WRD1_GET_SSEC(wrd) ((wrd) & TSP_WRD1_SSEC_MASK)
#define TSP_WRD2_GET_SECSSEC(wrd) ((uint64_t)((wrd) & TSP_WRD2_SECSSEC_MASK) << TSP_WRD1_SSEC_LEN)
#define TSP_WRD2_GET_SSEC(wrd) ((wrd) & TSP_WRD2_SSEC_MASK)
#define TSP_WRD3_GET_SEC(wrd) ((uint64_t)((wrd) & TSP_WRD3_SEC_MASK) << (TSP_WRD1_SSEC_LEN + TSP_WRD2_SSEC_LEN + TSP_WRD2_SEC_LEN))
#define SSEC_MAX (0x7fffffff)
#define TSTP_SSEC_TO_NSEC(time) (time > 0 ? ((uint32_t)((((double)((time) & SSEC_MAX)) / (1U << TSP_SSEC_WIDTH)) * TSP_NSEC_PER_SEC)) : ((uint32_t)((((double)((time*(-1)) & SSEC_MAX)) / (1U << TSP_SSEC_WIDTH)) * TSP_NSEC_PER_SEC)))
#define TSTP_SECSSEC_TO_SEC(time) (time > 0 ? (uint32_t)((time) >> TSP_SSEC_WIDTH) : (uint32_t)((time * -1) >> TSP_SSEC_WIDTH))
#define TSTP_SECSSEC_TO_SEC_DOUBLE(time) (((double)(time)) / (1U << TSP_SSEC_WIDTH))
#define TSTP_SEC_TO_SSEC(time) (((uint64_t)(time)) << TSP_SSEC_WIDTH)
/** Тип данных для хранения времени
* Время хранится в секундах прошедшее с начала этой эпохи (00:00:00 UTC, 1 Января 1970 года)
* Дробный формат хранения 32.31: 32 целых бит, 31 дробных бит,
* старшие 32 бита - секунды, младшие 31 бит сабсекунды = 1 / (1<<31) секунд
+ сабсекунды,
*/
typedef uint64_t t_x502_tstptime;
/** Структура для хранения контекста при обработке потока слов "на ввод" с включенными метками времени */
typedef struct {
/** значение слов последней метки времени */
uint32_t wrd[4];
/** частота АЦП */
uint32_t adc_freq;
/** частота DIN */
uint32_t din_freq;
/** время первой метки времени */
t_x502_tstptime tstp_start_time;
/** признак, что первая метка времени получена */
bool tstp_mark_rcvd;
/** значение текущего обрабатываемого слова */
uint32_t cur_wrd;
/** кол-во обработанных слов из потока */
uint32_t processed_wrds;
/** кол-во слов АЦП после последней метки времени */
uint32_t adcwrds_after_tstp;
/** кол-во слов DIN после последней метки времени */
uint32_t dinwrds_after_tstp;
/** общее кол-во слов после последней метки времени */
uint32_t wrds_after_tstp;
/** время последней метки времени */
t_x502_tstptime last_tstp_time;
} t_x502_tstp_state;
/** @} */
/***************************************************************************//**
@addtogroup func_tstp Функции для работы с метками времени
@{
*******************************************************************************/
/***************************************************************************//**
@brief Инициализация tstp_state, в нем хранится текущий контекст для операций с метками времени из потока "на ввод"
Данная функция инициализирует структуру в которой хранится контекст для работы с метками времени
Необходимо указывать на частоту АЦП и DIN т.к. время для слов между двумя метками
будет считаться в зависимости от частоты.
@param[in] tstp_state Указатель на существующую струтуру t_x502_tstp_state
@param[in] adc_freq Частота АЦП
@param[in] din_freq Частота DIN
*******************************************************************************/
X502_EXPORT(void) X502_tstp_init(t_x502_tstp_state *tstp_state, uint32_t adc_freq, uint32_t din_freq);
/** @brief Обработать очередное слово wrd из потока "на ввод"
*
* Функция должна быть вызвана только один раз и последовательно для каждого слова полученного из X502_Recv
*
* @param[in] tstp_state Указатель на струтуру t_x502_tstp_state предварительно инициализированную через tstp_init()
* @param[in] wrd Слово из потока "на ввод"
*/
X502_EXPORT(void) X502_tstp_process_wrd(t_x502_tstp_state *tstp_state, uint32_t wrd);
/** @brief Узнать время текущего обработанного слова
*
* Узнать время текущего слова которое до этого было обработано функцией tstp_process_wrd()
* Формат времени: 32бита - секунды, 31 бит сабсекунды = 1 / (1<<31) секунд
*
* @param[in] tstp_state Указатель на струтуру t_x502_tstp_state предварительно инициализированную через tstp_init()
* @param[in] ret Указатель на t_x502_tstptime по которому будет сохранено расчитанное значение времени для текущего слова
*/
X502_EXPORT(void) X502_tstp_get_curwrd_time(t_x502_tstp_state *tstp_state, t_x502_tstptime *ret);
/** @brief Возвращает признак того что часы синхронизированы
*
* Возвращает признак "захват PTP" для текущего обработанного слова
*
* @param[in] tstp_state Указатель на струтуру t_x502_tstp_state предварительно инициализированную через tstp_init()
*
* @return true: присутствует признак "захват PTP" для текущего обработанного слова, false: признак "захват PTP" отсутствует
*/
X502_EXPORT(bool) X502_tstp_get_lock(t_x502_tstp_state *tstp_state);
/** @} */
/** @} */
#ifdef __cplusplus
}
#endif
#endif //E502TSTP_H