718 lines
28 KiB
C
718 lines
28 KiB
C
#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(¶ms, 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, ¶ms);
|
||
|
||
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, ®);
|
||
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;
|
||
}
|