DEVEL: First open source release

This commit is contained in:
Oliver Bruendler
2019-08-02 10:03:58 +02:00
commit d455112276
167 changed files with 27513 additions and 0 deletions

809
driver/psi_ms_daq.c Normal file
View File

@ -0,0 +1,809 @@
/*############################################################################
# Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
# All rights reserved.
# Authors: Oliver Bruendler
############################################################################*/
#include "psi_ms_daq.h"
#include <stdlib.h>
//*******************************************************************************
// Types
//*******************************************************************************
typedef struct {
uint8_t nr;
bool isConfigured;
uint8_t widthBytes;
uint8_t windows;
int8_t lastProcWin;
uint32_t irqCalledWin;
PsiMsDaqn_WinIrq_f* irqFctWin;
PsiMsDaqn_StrIrq_f* irqFctStr;
void* irqArg;
PsiMsDaq_IpHandle ipHandle;
uint32_t bufStart;
uint32_t winSize;
uint32_t postTrig;
}PsiMsDaq_StrInst_t;
typedef struct {
uint32_t baseAddr;
uint8_t maxStreams;
uint8_t maxWindows;
uint32_t strAddrOffs;
PsiMsDaq_StrInst_t* streams;
PsiMsDaq_DataCopy_f* memcpyFct;
PsiMsDaq_RegWrite_f* regWrFct;
PsiMsDaq_RegRead_f* regRdFct;
} PsiMsDaq_Inst_t;
//*******************************************************************************
// Macros
//*******************************************************************************
#define SAFE_CALL(fctCall) { \
PsiMsDaq_RetCode_t r = fctCall; \
if (PsiMsDaq_RetCode_Success != r) {return r;}}
//*******************************************************************************
// Private Functions
//*******************************************************************************
void PsiMsDaq_DataCopy_Standard(void* dst, void* src, size_t n)
{
memcpy(dst, src, n);
}
void PsiMsDaq_RegWrite_Standard(const uint32_t addr, const uint32_t value)
{
volatile uint32_t* addr_p = (volatile uint32_t *)(size_t)addr;
*addr_p = value;
}
uint32_t PsiMsDaq_RegRead_Standard(const uint32_t addr)
{
volatile uint32_t* addr_p = (volatile uint32_t *)(size_t)addr;
return *addr_p;
}
PsiMsDaq_RetCode_t CheckStrDisabled( PsiMsDaq_IpHandle ipHandle,
const uint8_t streamNr)
{
uint32_t strEna;
SAFE_CALL(PsiMsDaq_RegRead(ipHandle, PSI_MS_DAQ_REG_STRENA, &strEna));
if (strEna & (1 << streamNr)) {
return PsiMsDaq_RetCode_StrNotDisabled;
}
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t CheckStrNr( PsiMsDaq_IpHandle ipHandle,
const uint8_t streamNr)
{
PsiMsDaq_Inst_t* inst_p = (PsiMsDaq_Inst_t*) ipHandle;
if (streamNr >= inst_p->maxStreams) {
return PsiMsDaq_RetCode_IllegalStrNr;
}
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t CheckWinNr( PsiMsDaq_StrHandle strHandle,
const uint8_t winNr)
{
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHandle;
if (winNr >= inst_p->windows) {
return PsiMsDaq_RetCode_IllegalWinNr;
}
return PsiMsDaq_RetCode_Success;
}
uint32_t Log2(const uint32_t x)
{
uint32_t v = x;
uint32_t r = 0;
while (v > 1) {
v = v/2;
r = r+1;
}
return r;
}
uint32_t Log2Ceil(const uint32_t x)
{
if (0 == x) {
return 0;
}
return Log2(x);
}
uint32_t Pow(const uint32_t x, const uint32_t y)
{
uint32_t r = x;
for (uint32_t i = 1; i < y; i ++) {
r *= x;
}
return r;
}
//*******************************************************************************
// IP Wide Functions
//*******************************************************************************
PsiMsDaq_IpHandle PsiMsDaq_Init( const uint32_t baseAddr,
const uint8_t maxStreams,
const uint8_t maxWindows,
const PsiMsDaq_AccessFct_t* const accessFct_p)
{
//Initialization and allocation
PsiMsDaq_Inst_t* inst_p = (PsiMsDaq_Inst_t*) malloc(sizeof(PsiMsDaq_Inst_t));
inst_p->baseAddr = baseAddr;
inst_p->streams = (PsiMsDaq_StrInst_t*) malloc(sizeof(PsiMsDaq_StrInst_t)*maxStreams);
inst_p->maxWindows = maxWindows;
inst_p->maxStreams = maxStreams;
inst_p->strAddrOffs = Pow(2, Log2Ceil(maxWindows))*0x10;
//Standard access functions
if (NULL == accessFct_p) {
inst_p->memcpyFct = PsiMsDaq_DataCopy_Standard;
inst_p->regWrFct = PsiMsDaq_RegWrite_Standard;
inst_p->regRdFct = PsiMsDaq_RegRead_Standard;
}
else {
inst_p->memcpyFct = accessFct_p->dataCopy;
inst_p->regWrFct = accessFct_p->regWrite;
inst_p->regRdFct = accessFct_p->regRead;
}
//Disable complete IP (all streams, IRQs, etc.)
PsiMsDaq_RegWrite(inst_p, PSI_MS_DAQ_REG_GCFG, 0);
PsiMsDaq_RegWrite(inst_p, PSI_MS_DAQ_REG_STRENA, 0);
PsiMsDaq_RegWrite(inst_p, PSI_MS_DAQ_REG_IRQENA, 0);
PsiMsDaq_RegWrite(inst_p, PSI_MS_DAQ_REG_IRQVEC, 0xFFFFFFFF);
//Reset values for all streams
for (int str = 0; str < maxStreams; str++) {
//Clear stream maximum level
PsiMsDaq_RegWrite(inst_p, PSI_MS_DAQ_REG_MAXLVL(str), 0);
//Mark windows as free
for (int win = 0; win < maxWindows; win++) {
PsiMsDaq_RegWrite(inst_p, PSI_MS_DAQ_WIN_WINCNT(str, win, inst_p->strAddrOffs), 0);
}
//Initialize data structure
inst_p->streams[str].nr = str;
inst_p->streams[str].isConfigured = false;
inst_p->streams[str].irqFctWin = NULL;
inst_p->streams[str].irqFctStr = NULL;
inst_p->streams[str].irqArg = NULL;
inst_p->streams[str].ipHandle = (PsiMsDaq_IpHandle) inst_p;
inst_p->streams[str].lastProcWin = -1;
inst_p->streams[str].irqCalledWin = 0;
}
//Set general Enables (never touched later)
PsiMsDaq_RegWrite(inst_p, PSI_MS_DAQ_REG_GCFG, PSI_MS_DAQ_REG_GCFG_BIT_ENA | PSI_MS_DAQ_REG_GCFG_BIT_IRQENA);
return (PsiMsDaq_IpHandle) inst_p;
}
PsiMsDaq_RetCode_t PsiMsDaq_GetStrHandle( PsiMsDaq_IpHandle ipHandle,
const uint8_t streamNr,
PsiMsDaq_StrHandle* const strHndl_p)
{
//Pointer Cast
PsiMsDaq_Inst_t* inst_p = (PsiMsDaq_Inst_t*) ipHandle;
//Checks
SAFE_CALL(CheckStrNr(ipHandle, streamNr));
//Implementation
*strHndl_p = (PsiMsDaq_StrHandle) &inst_p->streams[streamNr];
//Done
return PsiMsDaq_RetCode_Success;
}
void PsiMsDaq_HandleIrq(PsiMsDaq_IpHandle ipHandle)
{
//Pointer Cast
PsiMsDaq_Inst_t* inst_p = (PsiMsDaq_Inst_t*) ipHandle;
//Check which stream caused the IRQ and acknowledge it
uint32_t strWithIrq;
PsiMsDaq_RegRead(ipHandle, PSI_MS_DAQ_REG_IRQVEC, &strWithIrq);
PsiMsDaq_RegWrite(ipHandle, PSI_MS_DAQ_REG_IRQVEC, strWithIrq);
//Call handler for all streams with new windows pending
for (int str = 0; str < inst_p->maxStreams; str++) {
//Get stream handle
PsiMsDaq_StrInst_t* str_p = &inst_p->streams[str];
PsiMsDaq_StrHandle strHandle = (PsiMsDaq_StrHandle) str_p;
//Continue if stream has no IRQ pending
if (0 == (strWithIrq & (1 << str))){
continue;
}
//IRQ Handling Type: Stream
if (NULL != str_p->irqFctStr) {
str_p->irqFctStr(strHandle, str_p->irqArg);
}
//IRQ Handling Type: Window
if (NULL != str_p->irqFctWin) {
uint8_t lastWin;
PsiMsDaq_Str_GetLastWrittenWin(strHandle, &lastWin);
//Call user callbacks for new windows
int8_t win = str_p->lastProcWin;
do {
//Check if new data arrived and clear stream IRQ
PsiMsDaq_RegWrite(ipHandle, PSI_MS_DAQ_REG_IRQVEC, (1 << str));
PsiMsDaq_Str_GetLastWrittenWin(strHandle, &lastWin);
//Choose next window
win = (win + 1) % str_p->windows;
//Stopp if this window was not yet marked as free by the user
if (str_p->irqCalledWin & (1 << win)) {
break;
}
str_p->irqCalledWin |= (1 << win);
//Call user IRQ
PsiMsDaq_WinInfo_t winInfo;
winInfo.ipHandle = ipHandle;
winInfo.strHandle = strHandle;
winInfo.winNr = win;
if (str_p->irqFctWin != NULL) {
str_p->irqFctWin(winInfo, str_p->irqArg);
}
//Update State
str_p->lastProcWin = win;
} while (win != lastWin);
}
}
}
//*******************************************************************************
// Stream Related Functions
//*******************************************************************************
PsiMsDaq_RetCode_t PsiMsDaq_Str_Configure( PsiMsDaq_StrHandle strHndl,
PsiMsDaq_StrConfig_t* const config_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
PsiMsDaq_IpHandle ipHandle = inst_p->ipHandle;
PsiMsDaq_Inst_t* ipInst_p = (PsiMsDaq_Inst_t*) ipHandle;
const uint8_t strNr = inst_p->nr;
//Checks
if (0 != (config_p->streamWidthBits % 8)){
return PsiMsDaq_RetCode_IllegalStrWidth;
}
if (config_p->winCnt > ipInst_p->maxWindows) {
return PsiMsDaq_RetCode_IllegalWinCnt;
}
if (0 != (config_p->winSize % (config_p->streamWidthBits/8))) {
return PsiMsDaq_RetCode_WinSizeMustBeMultipleOfSamples;
}
SAFE_CALL(CheckStrDisabled(ipHandle, strNr));
//Set register values
SAFE_CALL(PsiMsDaq_RegWrite(ipHandle,
PSI_MS_DAQ_REG_POSTTRIG(strNr),
config_p->postTrigSamples));
SAFE_CALL(PsiMsDaq_RegSetField( ipHandle,
PSI_MS_DAQ_REG_MODE(strNr),
PSI_MS_DAQ_REG_MODE_LSB_RECM,
PSI_MS_DAQ_REG_MODE_MSB_RECM,
config_p->recMode));
SAFE_CALL(PsiMsDaq_RegSetBit( ipHandle,
PSI_MS_DAQ_CTX_SCFG(strNr),
PSI_MS_DAQ_CTX_SCFG_BIT_RINGBUF,
config_p->winAsRingbuf));
SAFE_CALL(PsiMsDaq_RegSetBit( ipHandle,
PSI_MS_DAQ_CTX_SCFG(strNr),
PSI_MS_DAQ_CTX_SCFG_BIT_OVERWRITE,
config_p->winOverwrite));
SAFE_CALL(PsiMsDaq_RegWrite(ipHandle,
PSI_MS_DAQ_CTX_BUFSTART(strNr),
config_p->bufStartAddr));
SAFE_CALL(PsiMsDaq_RegWrite(ipHandle,
PSI_MS_DAQ_CTX_WINSIZE(strNr),
config_p->winSize));
SAFE_CALL(PsiMsDaq_RegSetField( ipHandle,
PSI_MS_DAQ_CTX_SCFG(strNr),
PSI_MS_DAQ_CTX_SCFG_LSB_WINCNT,
PSI_MS_DAQ_CTX_SCFG_MSB_WINCNT,
config_p->winCnt-1));
//Set data structure values
inst_p->widthBytes = config_p->streamWidthBits/8;
inst_p->isConfigured = true;
inst_p->windows = config_p->winCnt;
inst_p->bufStart = config_p->bufStartAddr;
inst_p->postTrig = config_p->postTrigSamples;
inst_p->winSize = config_p->winSize;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetEnable( PsiMsDaq_StrHandle strHndl,
const bool enable)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
PsiMsDaq_IpHandle ipHandle = inst_p->ipHandle;
const uint8_t strNr = inst_p->nr;
//Implementation
const uint32_t msk = (1 << strNr);
SAFE_CALL(PsiMsDaq_RegSetBit(ipHandle, PSI_MS_DAQ_REG_STRENA, msk, enable));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetIrqCallbackWin( PsiMsDaq_StrHandle strHndl,
PsiMsDaqn_WinIrq_f* irqCb,
void* arg_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Checks
if (NULL != inst_p->irqFctStr) {
return PsiMsDaq_RetCode_IrqSchemesWinAndStrAreExclusive;
}
//Implementation
inst_p->irqFctWin = irqCb;
inst_p->irqArg = arg_p;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetIrqCallbackStr( PsiMsDaq_StrHandle strHndl,
PsiMsDaqn_StrIrq_f* irqCb,
void* arg_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Checks
if (NULL != inst_p->irqFctWin) {
return PsiMsDaq_RetCode_IrqSchemesWinAndStrAreExclusive;
}
//Implementation
inst_p->irqFctStr = irqCb;
inst_p->irqArg = arg_p;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetIrqEnable( PsiMsDaq_StrHandle strHndl,
const bool irqEna)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
PsiMsDaq_IpHandle ipHandle = inst_p->ipHandle;
const uint8_t strNr = inst_p->nr;
//Implementation
const uint32_t msk = (1 << strNr);
SAFE_CALL(PsiMsDaq_RegSetBit(ipHandle, PSI_MS_DAQ_REG_IRQENA, msk, irqEna));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_Arm(PsiMsDaq_StrHandle strHndl)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
PsiMsDaq_IpHandle ipHandle = inst_p->ipHandle;
const uint8_t strNr = inst_p->nr;
//Implementation
SAFE_CALL(PsiMsDaq_RegSetBit(ipHandle, PSI_MS_DAQ_REG_MODE(strNr), PSI_MS_DAQ_REG_MODE_BIT_ARM, true));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetMaxLvl( PsiMsDaq_StrHandle strHndl,
uint32_t* const maxLvl_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
PsiMsDaq_IpHandle ipHandle = inst_p->ipHandle;
const uint8_t strNr = inst_p->nr;
//Implementation
SAFE_CALL(PsiMsDaq_RegRead(ipHandle, PSI_MS_DAQ_REG_MAXLVL(strNr), maxLvl_p));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetFreeWindows( PsiMsDaq_StrHandle strHndl,
uint8_t* const freeWindows_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
PsiMsDaq_IpHandle ipHandle = inst_p->ipHandle;
PsiMsDaq_Inst_t* ip_p = (PsiMsDaq_Inst_t*) ipHandle;
const uint8_t strNr = inst_p->nr;
//Implementation (looping is not very efficient but safe and simple)
uint8_t freeWin = 0;
for (int win = inst_p->windows-1; win > 0; win--) {
uint32_t cnt;
SAFE_CALL(PsiMsDaq_RegGetField( ipHandle,
PSI_MS_DAQ_WIN_WINCNT(strNr, win, ip_p->strAddrOffs),
PSI_MS_DAQ_WIN_WINCNT_LSB_CNT,
PSI_MS_DAQ_WIN_WINCNT_MSB_CNT,
&cnt))
if (0 == cnt) {
freeWin++;
}
}
*freeWindows_p = freeWin;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetUsedWindows( PsiMsDaq_StrHandle strHndl,
uint8_t* const usedWindows_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
uint8_t freeWin;
SAFE_CALL(PsiMsDaq_Str_GetFreeWindows(strHndl, &freeWin));
*usedWindows_p = inst_p->windows-freeWin;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetTotalWindows( PsiMsDaq_StrHandle strHndl,
uint8_t* const windows_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
*windows_p = inst_p->windows;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetIpHandle( PsiMsDaq_StrHandle strHndl,
PsiMsDaq_IpHandle* ipHandle_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
*ipHandle_p = inst_p->ipHandle;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetStrNr( PsiMsDaq_StrHandle strHndl,
uint8_t* strNr_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
*strNr_p = inst_p->nr;
//Done
return PsiMsDaq_RetCode_Success;
}
//*******************************************************************************
// Window Related Functions
//*******************************************************************************
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetNoOfBytes( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const noOfBytes_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* str_p = (PsiMsDaq_StrInst_t*) winInfo.strHandle;
//Implementation
uint32_t samples;
SAFE_CALL(PsiMsDaq_StrWin_GetNoOfSamples(winInfo, &samples));
*noOfBytes_p = samples*str_p->widthBytes;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetNoOfSamples( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const noOfSamples_p)
{
//Pointer Case
PsiMsDaq_Inst_t* ip_p = (PsiMsDaq_Inst_t*)winInfo.ipHandle;
PsiMsDaq_StrInst_t* str_p = (PsiMsDaq_StrInst_t*)winInfo.strHandle;
//Setup
uint8_t strNr;
SAFE_CALL(PsiMsDaq_Str_GetStrNr(winInfo.strHandle, &strNr));
//Checks
SAFE_CALL(CheckStrNr(winInfo.ipHandle, strNr))
SAFE_CALL(CheckWinNr(winInfo.strHandle, winInfo.winNr))
//Implementation
uint32_t noOfBytes;
SAFE_CALL(PsiMsDaq_RegGetField( winInfo.ipHandle,
PSI_MS_DAQ_WIN_WINCNT(strNr, winInfo.winNr, ip_p->strAddrOffs),
PSI_MS_DAQ_WIN_WINCNT_LSB_CNT,
PSI_MS_DAQ_WIN_WINCNT_MSB_CNT,
&noOfBytes));
*noOfSamples_p = noOfBytes / str_p->widthBytes;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetPreTrigSamples( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const preTrigSamples_p)
{
//Setup
PsiMsDaq_StrInst_t* str_p = (PsiMsDaq_StrInst_t*) winInfo.strHandle;
PsiMsDaq_Inst_t* ip_p = (PsiMsDaq_Inst_t*)winInfo.ipHandle;
//Checks
bool containsTrig;
SAFE_CALL(PsiMsDaq_RegGetBit( winInfo.ipHandle,
PSI_MS_DAQ_WIN_WINCNT(str_p->nr, winInfo.winNr, ip_p->strAddrOffs),
PSI_MS_DAQ_WIN_WINCNT_BIT_ISTRIG,
&containsTrig))
if (!containsTrig) {
return PsiMsDaq_RetCode_NoTrigInWin;
}
//Implementation
uint32_t samples;
SAFE_CALL(PsiMsDaq_StrWin_GetNoOfSamples(winInfo, &samples));
*preTrigSamples_p = samples-str_p->postTrig;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetTimestamp( PsiMsDaq_WinInfo_t winInfo,
uint64_t* const timestamp_p)
{
//Setup
uint8_t strNr;
SAFE_CALL(PsiMsDaq_Str_GetStrNr(winInfo.strHandle, &strNr));
PsiMsDaq_Inst_t* ip_p = (PsiMsDaq_Inst_t*)winInfo.ipHandle;
//Checks
bool containsTrig;
SAFE_CALL(PsiMsDaq_RegGetBit( winInfo.ipHandle,
PSI_MS_DAQ_WIN_WINCNT(strNr, winInfo.winNr, ip_p->strAddrOffs),
PSI_MS_DAQ_WIN_WINCNT_BIT_ISTRIG,
&containsTrig))
if (!containsTrig) {
return PsiMsDaq_RetCode_NoTrigInWin;
}
//Implementation
uint32_t tsLo;
uint32_t tsHi;
SAFE_CALL(PsiMsDaq_RegRead(winInfo.ipHandle, PSI_MS_DAQ_WIN_TSLO(strNr, winInfo.winNr, ip_p->strAddrOffs), &tsLo));
SAFE_CALL(PsiMsDaq_RegRead(winInfo.ipHandle, PSI_MS_DAQ_WIN_TSHI(strNr, winInfo.winNr, ip_p->strAddrOffs), &tsHi));
*timestamp_p = (((uint64_t)tsHi) << 32) + tsLo;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetDataUnwrapped( PsiMsDaq_WinInfo_t winInfo,
const uint32_t preTrigSamples,
const uint32_t postTrigSamples, //including trigger
void* const buffer_p,
const size_t bufferSize)
{
//Pointer Cast
PsiMsDaq_StrInst_t* str_p = (PsiMsDaq_StrInst_t*) winInfo.strHandle;
PsiMsDaq_Inst_t* ip_p = (PsiMsDaq_Inst_t*) winInfo.ipHandle;
//Setup
const uint32_t samples = preTrigSamples+postTrigSamples;
const uint32_t bytes = samples*str_p->widthBytes;
uint32_t preTrig;
SAFE_CALL(PsiMsDaq_StrWin_GetPreTrigSamples(winInfo, &preTrig));
//Checks
if (bufferSize < bytes) {
return PsiMsDaq_RetCode_BufferTooSmall;
}
if (postTrigSamples > str_p->postTrig) {
return PsiMsDaq_RetCode_MorePostTrigThanConfigured;
}
if (preTrigSamples > preTrig) {
return PsiMsDaq_RetCode_MorePreTrigThanAvailable;
}
//Calculate window addresses
const uint32_t winStart = str_p->bufStart + str_p->winSize*winInfo.winNr;
const uint32_t winLast = winStart + str_p->winSize - 1;
//Calculate address of last byte and trigger byte (with regard to wrapping)
uint32_t lastSplAddr;
SAFE_CALL(PsiMsDaq_StrWin_GetLastSplAddr(winInfo, &lastSplAddr));
uint32_t trigByteAddr = lastSplAddr - (str_p->postTrig+1)*str_p->widthBytes; //+1 because trigger is not included in postTrigger
if (trigByteAddr < winStart) {
trigByteAddr += str_p->winSize;
}
uint32_t lastByteAddr = trigByteAddr + postTrigSamples*str_p->widthBytes + str_p->widthBytes-1;
if (lastByteAddr > winLast) {
lastByteAddr -= str_p->winSize;
}
//If all bytes are written without wrap, copy directly
const uint32_t firstByteLinear = lastByteAddr - bytes + 1;
if (firstByteLinear >= winStart) {
ip_p->memcpyFct(buffer_p, (void*)(size_t)firstByteLinear, bytes);
}
//Do unwrapping else
else {
const uint32_t secondChunkSize = lastByteAddr - winStart + 1;
const uint32_t firstChunkSize = bytes-secondChunkSize;
const uint32_t firstChunkStartAddr = winLast-firstChunkSize+1;
ip_p->memcpyFct(buffer_p, (void*)(size_t)firstChunkStartAddr, firstChunkSize);
ip_p->memcpyFct(buffer_p+firstChunkSize, (void*)(size_t)winStart, secondChunkSize);
}
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_MarkAsFree( PsiMsDaq_WinInfo_t winInfo)
{
//Setup
uint8_t strNr;
SAFE_CALL(PsiMsDaq_Str_GetStrNr(winInfo.strHandle, &strNr));
PsiMsDaq_Inst_t* ip_p = (PsiMsDaq_Inst_t*) winInfo.ipHandle;
PsiMsDaq_StrInst_t* str_p = (PsiMsDaq_StrInst_t*) winInfo.strHandle;
//Implementation
str_p->irqCalledWin &= ~(1 << winInfo.winNr);
SAFE_CALL(PsiMsDaq_RegWrite(winInfo.ipHandle, PSI_MS_DAQ_WIN_WINCNT(strNr, winInfo.winNr, ip_p->strAddrOffs), 0));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetLastSplAddr( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const lastSplAddr_p)
{
//Setup
uint8_t strNr;
SAFE_CALL(PsiMsDaq_Str_GetStrNr(winInfo.strHandle, &strNr));
PsiMsDaq_Inst_t* ip_p = (PsiMsDaq_Inst_t*) winInfo.ipHandle;
//Implementation
SAFE_CALL(PsiMsDaq_RegRead(winInfo.ipHandle, PSI_MS_DAQ_WIN_LAST(strNr, winInfo.winNr, ip_p->strAddrOffs), lastSplAddr_p));
//Done
return PsiMsDaq_RetCode_Success;
}
//*******************************************************************************
// Advanced Functions (only required for close control)
//*******************************************************************************
PsiMsDaq_RetCode_t PsiMsDaq_Str_IsRecording( PsiMsDaq_StrHandle strHndl,
bool* const isRecording_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
SAFE_CALL(PsiMsDaq_RegGetBit( inst_p->ipHandle,
PSI_MS_DAQ_REG_MODE(inst_p->nr),
PSI_MS_DAQ_REG_MODE_BIT_REC,
isRecording_p));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_CurrentWin( PsiMsDaq_StrHandle strHndl,
uint8_t* const currentWin_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
uint32_t field;
SAFE_CALL(PsiMsDaq_RegGetField( inst_p->ipHandle,
PSI_MS_DAQ_CTX_SCFG(inst_p->nr),
PSI_MS_DAQ_CTX_SCFG_LSB_WINCUR,
PSI_MS_DAQ_CTX_SCFG_MSB_WINCUR,
&field))
*currentWin_p = field;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_CurrentPtr( PsiMsDaq_StrHandle strHndl,
uint32_t* const currentPtr_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
SAFE_CALL(PsiMsDaq_RegRead(inst_p->ipHandle, PSI_MS_DAQ_CTX_PTR(inst_p->nr), currentPtr_p));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetLastWrittenWin( PsiMsDaq_StrHandle strHndl,
uint8_t* const lastWrittenWin_p)
{
//Pointer Cast
PsiMsDaq_StrInst_t* inst_p = (PsiMsDaq_StrInst_t*) strHndl;
//Implementation
uint32_t reg;
SAFE_CALL(PsiMsDaq_RegRead(inst_p->ipHandle, PSI_MS_DAQ_REG_LASTWIN(inst_p->nr), &reg));
*lastWrittenWin_p = reg;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_RegWrite( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint32_t value)
{
//Cast pointer
PsiMsDaq_Inst_t* inst_p = (PsiMsDaq_Inst_t*)ipHandle;
//Execute access
inst_p->regWrFct(inst_p->baseAddr+addr, value);
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_RegRead( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
uint32_t* const value_p)
{
//Cast pointer
PsiMsDaq_Inst_t* inst_p = (PsiMsDaq_Inst_t*)ipHandle;
//Execute access
*value_p = inst_p->regRdFct(inst_p->baseAddr+addr);
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_RegSetField( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint8_t lsb,
const uint8_t msb,
const uint32_t value)
{
//Execute access
uint32_t reg;
uint32_t msk = (1 << (msb+1))-1;
uint32_t mskSft = msk << lsb;
uint32_t valSft = ((value & msk) << lsb);
SAFE_CALL(PsiMsDaq_RegRead(ipHandle, addr, &reg));
reg &= ~mskSft;
reg |= valSft;
SAFE_CALL(PsiMsDaq_RegWrite(ipHandle, addr, reg));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_RegGetField( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint8_t lsb,
const uint8_t msb,
uint32_t* const value_p)
{
//Execute access
uint32_t reg;
uint32_t msk = (1 << (msb+1))-1;
SAFE_CALL(PsiMsDaq_RegRead(ipHandle, addr, &reg));
*value_p = (reg >> lsb) & msk;
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_RegSetBit( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint32_t mask,
const bool value)
{
//Execute access
uint32_t reg;
SAFE_CALL(PsiMsDaq_RegRead(ipHandle, addr, &reg));
reg &= ~mask;
if (value) {
reg |= mask;
}
SAFE_CALL(PsiMsDaq_RegWrite(ipHandle, addr, reg));
//Done
return PsiMsDaq_RetCode_Success;
}
PsiMsDaq_RetCode_t PsiMsDaq_RegGetBit( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint32_t mask,
bool* const value_p)
{
//Execute access
uint32_t reg;
SAFE_CALL(PsiMsDaq_RegRead(ipHandle, addr, &reg));
*value_p = (0 != (reg & mask));
//Done
return PsiMsDaq_RetCode_Success;
}

704
driver/psi_ms_daq.h Normal file
View File

@ -0,0 +1,704 @@
/*############################################################################
# Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
# All rights reserved.
# Authors: Oliver Bruendler
############################################################################*/
#pragma once
//*******************************************************************************
// Documentation
//*******************************************************************************
/**
* @mainpage
*
* @section ip_functionality IP Core Functionality
*
* The functionality of the IP-Core is not covered in detail here, however for using
* the driver it may beneficial to understand what the IP-Core does. To get this
* information, refer to the <a href="../../psi_multi_stream_daq.pdf"><b>IP-Core documentation</b></a>
*
* @section thread_safety Thread Safety
*
* The driver is not thread-safe in general. If API functions are used in more
* than one thread (e.g. in main and IRQs), these API functions must be protected (e.g. by disabling IRQs
* while the function is executing).
*
* In the simplest case, the IP core is configured before IRQs are enabled and afterwards data is only read
* from IRQs. In this case, no protection is required.
*
* Why is the IRQ disabling not implemented in the driver itself? Well, what IRQs must be disabled depends
* on what IRQs the driver API is used from. There may also other protection schemes be used (e.g. mutexes of a RTOS).
* As a result there is not single true protection mechanism that can be implemented within the driver.
*
* @section irq_handling IRQ Handling
*
* The driver supports two ways of handling IRQs. One of them (<i>Window based IRQ</i>) is a bit more elaborate and easy to use
* but it only covers the case, that each recorded window is processed by software. This is true
* in general but the IP-core also allows special configurations where data can be overwritten
* even if it was not processed. Since the handling of IRQs becomes more specific in this case,
* a special IRQ handling scheme called <i>Stream based IRQ </i> is implemented. In this case the
* user is responsible for implementing all actions to be taken in IRQs.
*
* In all IRQ handling schemes, the user is responsible for calling the function PsiMsDaq_HandleIrq() whenever the IP core
* asserts its interrupt (level sensitive, high active).
*
* Only one IRQ handlig scheme can be used per stream (not both at the same time for the same stream).
*
* @subsection window_irq Window based IRQ
*
* In this handling scheme, the driver ensures that the user callback gets called exactly once for every window that is recorded.
* Spurious interrupts (IRQs getting detected after the data was already processed) are suppressed by the driver. All information
* about the window which was completed is automatically passed to the user callback.
*
* This handling scheme only works if each window is really processed by the user and protected against being overwritten until
* the user acknowledged the processing. Implementationwise this means that window overwriting must be disable (config.overwrite = false)
* and that the user must acknowledge the processing of each window before new data can be recorded into it (by calling PsiMsDaq_StrWin_MarkAsFree()).
*
* Benefits of this scheme is simplicity, drawback is that the driver assumes that the user processes each window which may not
* be the case in special cases.
*
* @subsection stream_irq Stream based IRQ
*
* In this handling scheme, the driver does only detect which stream fired an IRQ and calls the user callback function.
* The callback function is called regardless of how many new windows were recorded. The user can do whatever processing
* of the IRQ he wants. This allows fine grained control over the IP core in special cases but it also means that the user
* is fully on his own. Therefore this option should only be used if there are good reasons for not using Window based IRQ.
*
* @section example_code Example Code
*
* This section contains a little code example to show how the driver is used.
*
* @code{.c}
* // *** Static Variables ***
* static PsiMsDaq_IpHandle daqHandle;
* static PsiMsDaq_StrHandle daqStrHandle;
*
* // *** System ISR ***
* //ISR that is called by the OS/baremetal drivers if an IRQ is asserted
* void PsiMsDaqIrqHandler(void* arg)
* {
* //We assume the handle to the psi_ms_daq driver is passed as callback argument
* PsiMsDaq_IpHandle ipHandle = (PsiMsDaq_IpHandle) arg;
* //Call IP-handling function
* PsiMsDaq_HandleIrq(ipHandle);
* }
*
* // *** IP User ISR ***
* void UserDaqIsr(PsiMsDaq_WinInfo_t winInfo, void* arg)
* {
* //Invalidate cache, example code is for xilinx devices
* Xil_DCacheInvalidateRange(<recodingLocation>, <recordingSize>);
* //Get recorded data
* PsiMsDaq_StrWin_GetDataUnwrapped(winInfo, <preTriggerSize>, <postTriggerSize>, <targetBuffer>, sizeof(<targetBuffer>));
* //Acknowledge processing of the data
* PsiMsDaq_StrWin_MarkAsFree(winInfo);
* }
*
* // *** Main function containing intialization ***
* int main()
* {
* //Initialize IP
* daqHandle = PsiMsDaq_Init(<baseAddress>, <streams>, <maxWindows>, NULL);
* PsiMsDaq_GetStrHandle(daqHandle, 0, &daqStrHandle);
*
* //Configure Stream
* PsiMsDaq_StrConfig_t cfg = {
* .postTrigSamples = <postTriggerSamplesToRecord>,
* .recMode = <mode>,
* .winAsRingbuf = true,
* .winOverwrite = false,
* .winCnt = <numberOfWindowsForThisStream>,
* .bufStartAddr = <recodingLocation>,
* .winSize = <sizePerWindow>, //in bytes
* .streamWidthBits = <widthInBits>
* };
* PsiMsDaq_Str_Configure(daqHandle, &cfg);
* //Register ballback
* PsiMsDaq_Str_SetIrqCallbackWin(daqHandle, UserDaqIsr, NULL);
* //Enable IRQ
* PsiMsDaq_Str_SetIrqEnable(daqHandle, true);
* //Enable recorder for stream
* PsiMsDaq_Str_SetEnable(daqHandle, true);
*
* //Wait in endless loop for IRQs comming in
* while(1){};
* }
* @endcode
*/
//*******************************************************************************
// Includes
//*******************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
//*******************************************************************************
// Constants
//*******************************************************************************
/// @cond
//ACQCONF Registers - General
#define PSI_MS_DAQ_REG_GCFG 0x000
#define PSI_MS_DAQ_REG_GCFG_BIT_ENA (1 << 0)
#define PSI_MS_DAQ_REG_GCFG_BIT_IRQENA (1 << 8)
#define PSI_MS_DAQ_REG_GSTAT 0x004
#define PSI_MS_DAQ_REG_IRQVEC 0x010
#define PSI_MS_DAQ_REG_IRQENA 0x014
#define PSI_MS_DAQ_REG_STRENA 0x020
//ACQCONF Registers - Per Stream
#define PSI_MS_DAQ_REG_MAXLVL(n) (0x200+0x10*(n))
#define PSI_MS_DAQ_REG_POSTTRIG(n) (0x204+0x10*(n))
#define PSI_MS_DAQ_REG_MODE(n) (0x208+0x10*(n))
#define PSI_MS_DAQ_REG_MODE_LSB_RECM 0
#define PSI_MS_DAQ_REG_MODE_MSB_RECM 1
#define PSI_MS_DAQ_REG_MODE_BIT_ARM (1 << 8)
#define PSI_MS_DAQ_REG_MODE_BIT_REC (1 << 16)
#define PSI_MS_DAQ_REG_LASTWIN(n) (0x20C+0x10*(n))
//CTXMEM for Stream n
#define PSI_MS_DAQ_CTX_SCFG(n) (0x1000+0x20*(n))
#define PSI_MS_DAQ_CTX_SCFG_BIT_RINGBUF (1 << 0)
#define PSI_MS_DAQ_CTX_SCFG_BIT_OVERWRITE (1 << 8)
#define PSI_MS_DAQ_CTX_SCFG_LSB_WINCNT 16
#define PSI_MS_DAQ_CTX_SCFG_MSB_WINCNT 20
#define PSI_MS_DAQ_CTX_SCFG_LSB_WINCUR 24
#define PSI_MS_DAQ_CTX_SCFG_MSB_WINCUR 28
#define PSI_MS_DAQ_CTX_BUFSTART(n) (0x1004+0x20*(n))
#define PSI_MS_DAQ_CTX_WINSIZE(n) (0x1008+0x20*(n))
#define PSI_MS_DAQ_CTX_PTR(n) (0x100C+0x20*(n))
#define PSI_MS_DAQ_CTX_WINEND(n) (0x1010+0x20*(n))
//WNDW Window w for Stream n
#define PSI_MS_DAQ_WIN_WINCNT(n, w, so) (0x4000+(so)*(n)+0x10*(w))
#define PSI_MS_DAQ_WIN_WINCNT_LSB_CNT 0
#define PSI_MS_DAQ_WIN_WINCNT_MSB_CNT 30
#define PSI_MS_DAQ_WIN_WINCNT_BIT_ISTRIG (1 << 31)
#define PSI_MS_DAQ_WIN_LAST(n, w, so) (0x4004+(so)*(n)+0x10*(w))
#define PSI_MS_DAQ_WIN_TSLO(n, w, so) (0x4008+(so)*(n)+0x10*(w))
#define PSI_MS_DAQ_WIN_TSHI(n, w, so) (0x400C+(so)*(n)+0x10*(w))
/// @endcond
//*******************************************************************************
// Types
//*******************************************************************************
//*** Handles ***
typedef void* PsiMsDaq_IpHandle; ///< Handle to an instance of the driver for a complete IP
typedef void* PsiMsDaq_StrHandle; ///< Handle to a specific stream of the driver
//*** Functions for access to data of the IP core ***
/**
* @brief Copy used to copy data recorded to other memory locations in PsiMsDaq_StrWin_GetDataUnwrapped()
*
* @param src Source memory address (exactly the way the IP sees the address space)
* @param dst Desitnation memory address (as the CPU sees it)
* @param n Number of bytes to copy
*/
typedef void PsiMsDaq_DataCopy_f(void* dst, void* src, size_t n);
/**
* @brief Write an IP-register
*
* @param addr Address to write (byte address)
* @param value Value to write
*/
typedef void PsiMsDaq_RegWrite_f(const uint32_t addr, const uint32_t value);
/**
* @brief Read an IP-register
*
* @param addr Address to read from (byte address)
* @return Read value
*/
typedef uint32_t PsiMsDaq_RegRead_f(const uint32_t addr);
/**
* @brief Window definition struct, used for more compact passing of common parameters
* @note This is not a handle and this struct is allocated on the stack, so it is only valid
* until the function returns!
*/
typedef struct {
uint8_t winNr; ///< Window number
PsiMsDaq_IpHandle ipHandle; ///< Handle of the IP the window belongs to
PsiMsDaq_StrHandle strHandle; ///< Handle of the stream the window belongs to
}PsiMsDaq_WinInfo_t;
/**
* @brief Interrupt callback function for the window based IRQ scheme.
* In this IRQ scheme, one callback function is called for each window that arrives.
* This IRQ scheme is only usable if window-overwrite is disable (config.onverwrite = false).
* After the window data is processed, it must be freed by calling PsiMsDaq_StrWin_MarkAsFree().
*
* @param winInfo Window information struct (allocated on stack!)
* @param arg User argument list
*/
typedef void PsiMsDaqn_WinIrq_f(PsiMsDaq_WinInfo_t winInfo, void* arg);
/**
* @brief Interrupt callback function for the stream based IRQ scheme.
* In this IRQ scheme, one callback function is called whenever the IP fires an IRQ.
* This IRQ scheme is always usable but usually only required if window-overwrite is used (since the
* more elaborate window based IRQ scheme is not usable in this case).
*
* @param strHandle Handle of the stream that fired the IRQ
* @param arg User argument list
*/
typedef void PsiMsDaqn_StrIrq_f(PsiMsDaq_StrHandle strHandle, void* arg);
/**
* @brief Recorder mode (see documentation)
*/
typedef enum {
PsiMsDaqn_RecMode_Continuous = 0, ///< Continuous recording
PsiMsDaqn_RecMode_TriggerMask = 1, ///< Continuously record pre-trigger data but only detect triggers after PsiMsDaq_Str_Arm() was called
PsiMsDaqn_RecMode_SingleShot = 2, ///< Only record pre-trigger after PsiMsDaq_Str_Arm() was called and stop recording after one trigger
PsiMsDaqn_RecMode_Manual = 3, ///< Manaully control the recording by setting and clearing the arm bit
} PsiMsDaq_RecMode_t;
/**
* @brief Stream configuration struct
*/
typedef struct {
uint32_t postTrigSamples; ///< Number of post trigger samples (incl. Trigger sample)
PsiMsDaq_RecMode_t recMode; ///< Recording mode
bool winAsRingbuf; ///< Use individual windows as ring-buffers (true=ringbuffer mode, false=linear mode)
bool winOverwrite; ///< If true, windows are overwritten even if they contain data. Usually set false here.
uint8_t winCnt; ///< Number of windows to use
uint32_t bufStartAddr; ///< Start address of the buffer for this stream
uint32_t winSize; ///< Size of the windows
uint16_t streamWidthBits; ///< Width od the stream in bits (must be a multiple of 8)
} PsiMsDaq_StrConfig_t;
/**
* @brief Memory access functions struct
*/
typedef struct {
PsiMsDaq_DataCopy_f* dataCopy; ///< Data copy function to use
PsiMsDaq_RegWrite_f* regWrite; ///< Register write function to use
PsiMsDaq_RegRead_f* regRead; ///< Register read function to use
} PsiMsDaq_AccessFct_t;
/**
* @brief Return codes
*/
typedef enum {
PsiMsDaq_RetCode_Success = 0, ///< No error, everything OK
PsiMsDaq_RetCode_IllegalStrNr = -1, ///< Illegal stream number passed
PsiMsDaq_RetCode_IllegalStrWidth = -2, ///< Illegal steram width selected
PsiMsDaq_RetCode_StrNotDisabled = -3, ///< This function is only allowed if the stream is disbled but it was enabled
PsiMsDaq_RetCode_IllegalWinCnt = -4, ///< Illegal window count passed
PsiMsDaq_RetCode_IllegalWinNr = -5, ///< Illegal window number passed
PsiMsDaq_RetCode_NoTrigInWin = -6, ///< This window does not contain a trigger as required for this function call
PsiMsDaq_RetCode_BufferTooSmall = -7, ///< The buffer passed is too small to contain all data
PsiMsDaq_RetCode_MorePostTrigThanConfigured = -8, ///< More post trigger data requested than configured to be recorded
PsiMsDaq_RetCode_MorePreTrigThanAvailable = -9, ///< More pre-trigger data requested than available
PsiMsDaq_RetCode_WinSizeMustBeMultipleOfSamples = -10, ///< Window size must be a multiple of the sample size
PsiMsDaq_RetCode_IrqSchemesWinAndStrAreExclusive = -11 ///< Only one IRQ scheme (...Str or ...Win) can be used
} PsiMsDaq_RetCode_t;
//*******************************************************************************
// IP Wide Functions
//*******************************************************************************
/**
* @brief Initialize the psi_ms_daq IP-Core
*
* @param baseAddr Base address of the IP core to access
* @param maxStreams Maximum number of streams supported by this IP (must match setting in Vivado IPI)
* @param maxWindows Maximum number of windows per stream supported by this IP (must match setting in Vivado IPI)
* @param accessFct_p Memory access functions to use (pass NULL to use the default functions)
* @return Driver Handle
*/
PsiMsDaq_IpHandle PsiMsDaq_Init( const uint32_t baseAddr,
const uint8_t maxStreams,
const uint8_t maxWindows,
const PsiMsDaq_AccessFct_t* const accessFct_p);
/**
* @brief Get a handle to a specific stream number
*
* @param ipHandle Driver handle for the whole IP
* @param streamNr Stream number to get handle for
* @param strHndl_p Pointer to write the stream handle to
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_GetStrHandle( PsiMsDaq_IpHandle ipHandle,
const uint8_t streamNr,
PsiMsDaq_StrHandle* const strHndl_p);
void PsiMsDaq_HandleIrq(PsiMsDaq_IpHandle inst_p);
//*******************************************************************************
// Stream Related Functions
//*******************************************************************************
/**
* @brief Configure stream.
*
* @param strHndl Driver handle for the stream
* @param config_p Struct containing all settings
* @return Return Code
*
* @note This function is only allwed if the corresponding stream is disabled
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_Configure( PsiMsDaq_StrHandle strHndl,
PsiMsDaq_StrConfig_t* const config_p);
/**
* @brief Enable/Disable a stream
*
* @param strHndl Driver handle for the stream
* @param enable true for enable, false for disable
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetEnable( PsiMsDaq_StrHandle strHndl,
const bool enable);
/**
* @brief Set window based interrupt callback function for a stream to be called whenever a new
* windows is recorded.
*
* @param strHndl Driver handle for the stream
* @param irqCb Callback function. Pass NULL to unregister the callback.
* @param arg_p Arguments passed to the user callback function
* @return Return Code
*
* @note Only one IRQ scheme (...Win or ...Str) can be used. Usually ...Win is
* used if window overwriting is disabled (config.overwrite = false) and ...Str
* otherwise.
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetIrqCallbackWin( PsiMsDaq_StrHandle strHndl,
PsiMsDaqn_WinIrq_f* irqCb,
void* arg_p);
/**
* @brief Set stream based interrupt callback function for a stream to be called whenever a new
* windows is recorded. Usually PsiMsDaq_Str_SetIrqCallbackWin() is used instead of this
* function. So without special reasons, use PsiMsDaq_Str_SetIrqCallbackWin().
*
* @param strHndl Driver handle for the stream
* @param irqCb Callback function. Pass NULL to unregister the callback.
* @param arg_p Arguments passed to the user callback function
* @return Return Code
*
* @note Only one IRQ scheme (...Win or ...Str) can be used. Usually ...Win is
* used if window overwriting is disabled (config.overwrite = false) and ...Str
* otherwise.
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetIrqCallbackStr( PsiMsDaq_StrHandle strHndl,
PsiMsDaqn_StrIrq_f* irqCb,
void* arg_p);
/**
* @brief Enable/Disable IRQ for a stream
*
* @param strHndl Driver handle for the stream
* @param irqEna true for enable, false for disable
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_SetIrqEnable( PsiMsDaq_StrHandle strHndl,
const bool irqEna);
/**
* @brief Arm the recorder for a given stream
*
* @param strHndl Driver handle for the stream
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_Arm(PsiMsDaq_StrHandle strHndl);
/**
* @brief Get maximum input buffer fill level
*
* @param strHndl Driver handle for the stream
* @param maxLvl_p Pointer to write the level into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetMaxLvl( PsiMsDaq_StrHandle strHndl,
uint32_t* const maxLvl_p);
/**
* @brief Get the number of free windows.
*
* This function is implemented by looping over all windows and checking if they
* contain any unacknowledged data. This is quite slow but the only safe approach.
* So do not use this function excessively.
*
* @param strHndl Driver handle for the stream
* @param freeWindows_p Pointer to write the number of free windows into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetFreeWindows( PsiMsDaq_StrHandle strHndl,
uint8_t* const freeWindows_p);
/**
* @brief Get the number of used (non-free) windows.
*
* This function is implemented by looping over all windows and checking if they
* contain any unacknowledged data. This is quite slow but the only safe approach.
* So do not use this function excessively.
*
* @param strHndl Driver handle for the stream
* @param usedWindows_p Pointer to write the number of used windows into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetUsedWindows( PsiMsDaq_StrHandle strHndl,
uint8_t* const usedWindows_p);
/**
* @brief Get the number of windows configured to be used for a given stream
*
* @param strHndl Driver handle for the stream
* @param windows_p Pointer to write the number of windows into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetTotalWindows( PsiMsDaq_StrHandle strHndl,
uint8_t* const windows_p);
/**
* @brief Get the IP Handle of the IP a stream belongs to
*
* @param strHndl Driver handle for the stream
* @param ipHandle_p Pointer to write the IP handle into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetIpHandle( PsiMsDaq_StrHandle strHndl,
PsiMsDaq_IpHandle* ipHandle_p);
/**
* @brief Get the stream number from a stream handle
*
* @param strHndl Driver handle for the stream
* @param strNr_p Pointer to write the stream number into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetStrNr( PsiMsDaq_StrHandle strHndl,
uint8_t* strNr_p);
//*******************************************************************************
// Window Related Functions
//*******************************************************************************
/**
* @brief Get number of valid and unacknowledged bytes in a window
*
* @param winInfo Window information
* @param noOfBytes_p Pointer to write number of bytes into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetNoOfBytes( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const noOfBytes_p);
/**
* @brief Get number of valid and unacknowledged samples in a window
*
* @param winInfo Window information
* @param noOfSamples_p Pointer to write number of samples into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetNoOfSamples( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const noOfSamples_p);
/**
* @brief Get the number of pre-trigger samples in a window (post trigger samples are known by config)
*
* @param winInfo Window information
* @param preTrigSamples_p Pointer to write number of pre-trigger samples into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetPreTrigSamples( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const preTrigSamples_p);
/**
* @brief Get the timestamp of a window
*
* @param winInfo Window information
* @param timestamp_p Pointer to write the timestamp to
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetTimestamp( PsiMsDaq_WinInfo_t winInfo,
uint64_t* const timestamp_p);
/**
* @brief Get unwrapped copy of the data in a window.
*
* @param winInfo Window information
* @param preTrigSamples Number of pre trigger samples to read
* @param postTrigSamples Number of post trigger samples to read (including the trigger sample)
* @param buffer_p Buffer to copy the data into
* @param bufferSize Size of buffer_p
* @return Return Code
*
* @note This function does not acknowledge the reading of the data. To do so, use PsiMsDaq_StrWin_MarkAsFree()
*/
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetDataUnwrapped( PsiMsDaq_WinInfo_t winInfo,
const uint32_t preTrigSamples,
const uint32_t postTrigSamples, //including trigger
void* const buffer_p,
const size_t bufferSize);
/**
* @brief Mark a window as free so it can receive new data. This function must be called after the window data is read
*
* @param winInfo Window information
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_MarkAsFree( PsiMsDaq_WinInfo_t winInfo);
/**
* @brief Get the address of the last sample (not byte) written into a window
*
* @param winInfo Window information
* @param lastSplAddr_p Pointer to write the address of the last sample into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_StrWin_GetLastSplAddr( PsiMsDaq_WinInfo_t winInfo,
uint32_t* const lastSplAddr_p);
//*******************************************************************************
// Advanced Functions (only required for close control)
//*******************************************************************************
/**
* @brief Check if the recorder of a given stream is currently recording data
*
* @param strHndl Driver handle for the stream
* @param isRecording_p Pointer to write the result into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_IsRecording( PsiMsDaq_StrHandle strHndl,
bool* const isRecording_p);
/**
* @brief Get the currently used recorder window
*
* @param strHndl Driver handle for the stream
* @param currentWin_p Pointer to write the result into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_CurrentWin( PsiMsDaq_StrHandle strHndl,
uint8_t* const currentWin_p);
/**
* @brief Get the current write pointer of the recording logic
*
* @param strHndl Driver handle for the stream
* @param currentPtr_p Pointer to write the result into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_CurrentPtr( PsiMsDaq_StrHandle strHndl,
uint32_t* const currentPtr_p);
/**
* @brief Get the number of the last window that was written to memory completely
*
* @param strHndl Driver handle for the stream
* @param lastWrittenWin_p Pointer to write the result into
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_Str_GetLastWrittenWin( PsiMsDaq_StrHandle strHndl,
uint8_t* const lastWrittenWin_p);
/**
* @brief Write to a register
*
* @param ipHandle Driver handle for the whole IP
* @param addr Register address
* @param value Value to write
* @return Return Code
*
* @note This function should only be used for debugging purposes!
* Otherwise the driver might not work.
*/
PsiMsDaq_RetCode_t PsiMsDaq_RegWrite( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint32_t value);
/**
* @brief Read a register
*
* @param ipHandle Driver handle for the whole IP
* @param addr Register address
* @param value_p Read value
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_RegRead( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
uint32_t* const value_p);
/**
* @brief Set a field in a register (RMW)
*
* @param ipHandle Driver handle for the whole IP
* @param addr Register address
* @param lsb Least significant bit number of the field
* @param msb Most significant bit number of the field
* @param value Value to write
* @return Return Code
*
* @note This function should only be used for debugging purposes!
* Otherwise the driver might not work.
*/
PsiMsDaq_RetCode_t PsiMsDaq_RegSetField( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint8_t lsb,
const uint8_t msb,
const uint32_t value);
/**
* @brief Read a field from a register
*
* @param ipHandle Driver handle for the whole IP
* @param addr Register address
* @param lsb Least significant bit number of the field
* @param msb Most significant bit number of the field
* @param value_p Read value
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_RegGetField( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint8_t lsb,
const uint8_t msb,
uint32_t* const value_p);
/**
* @brief Set a bit in a register (RMW)
*
* @param ipHandle Driver handle for the whole IP
* @param addr Register address
* @param mask Bitmask
* @param value Value to write
* @return Return Code
*
* @note This function should only be used for debugging purposes!
* Otherwise the driver might not work.
*/
PsiMsDaq_RetCode_t PsiMsDaq_RegSetBit( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint32_t mask,
const bool value);
/**
* @brief Read a bit from a register
*
* @param ipHandle Driver handle for the whole IP
* @param addr Register address
* @param mask Bitmask
* @param value_p Read value
* @return Return Code
*/
PsiMsDaq_RetCode_t PsiMsDaq_RegGetBit( PsiMsDaq_IpHandle ipHandle,
const uint32_t addr,
const uint32_t mask,
bool* const value_p);