Files
E502_ADC_BF_PC_companion/lib/x502/x502api_streams.c

718 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_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;
}