Files
E502_ADC_BF_PC_companion/lib/x502/x502api.c

732 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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