summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 6de8ee4)
raw | patch | inline | side by side (parent: 6de8ee4)
author | sujith <sujith.s@ti.com> | |
Fri, 16 Feb 2018 14:07:29 +0000 (19:37 +0530) | ||
committer | sujith <sujith.s@ti.com> | |
Thu, 1 Mar 2018 08:40:34 +0000 (14:10 +0530) |
Changes done
Uses LINE EVENT Notification and WR DMA END events
to issue CB to applications
Line Length : There is a restriction on minimum no of lines that could
be sepecified for notification. The IP team is yet to confirm on the
actual limit
Testing : Bare Metal application demonstrates the use of this feature
Signed-off-by: sujith <sujith.s@ti.com>
Uses LINE EVENT Notification and WR DMA END events
to issue CB to applications
Line Length : There is a restriction on minimum no of lines that could
be sepecified for notification. The IP team is yet to confirm on the
actual limit
Testing : Bare Metal application demonstrates the use of this feature
Signed-off-by: sujith <sujith.s@ti.com>
12 files changed:
examples/iss/isscapt_baremetal_app/inc/app_framebufmgnt.h | patch | blob | history | |
examples/iss/isscapt_baremetal_app/src/app_framebufmgnt.c | patch | blob | history | |
examples/iss/isscapt_baremetal_app/src/app_iss.c | patch | blob | history | |
examples/iss/isscapt_baremetal_app/src/app_tdaxx.c | patch | blob | history | |
include/fvid2/fvid2_dataTypes.h | patch | blob | history | |
include/iss/vps_cfgcal.h | patch | blob | history | |
src/vpslib/calcore/vpscore_capture.h | [changed mode: 0644->0755] | patch | blob | history |
src/vpslib/common/vpscore.h | [changed mode: 0644->0755] | patch | blob | history |
src/vpslib/hal/src/vpshal_isscal.c | patch | blob | history | |
src/vpslib/hal/vpshal_isscal.h | patch | blob | history | |
src/vpslib/isscore/src/vpscore_captureapi.c | patch | blob | history | |
src/vpslib/isscore/vpscore_capture.h | [changed mode: 0644->0755] | patch | blob | history |
diff --git a/examples/iss/isscapt_baremetal_app/inc/app_framebufmgnt.h b/examples/iss/isscapt_baremetal_app/inc/app_framebufmgnt.h
index 015a1c5b61fa27d1c4701cb2a9b90b6973605def..a7a0638b05dd68f01180ba1e33e3982fba2da9fa 100755 (executable)
{
#endif
+#define CAL_APP_NUM_FRAMES (0x40U)
+/**< Number of frames to capture */
+#define CAL_APP_NUM_SUB_FRAMES (0x1U)
+/**< Number of sub frames per frame, right now only 1 */
+#define CAL_APP_TOTAL_NUM_SUB_FRAMES \
+ (CAL_APP_NUM_FRAMES * CAL_APP_NUM_SUB_FRAMES)
+
+/**< Designator for Sub Frame callback, used in sequence checks */
+#define CAL_APP_SUB_F_CB (const VpsCore_Frame *) (0xFFFF)
+/**< Designator for EOF callback, used in sequence checks */
+#define CAL_APP_EOF_CB (const VpsCore_Frame *) (0xAAAA)
+/**< Designator for callback which returns frame, used in sequence checks */
+#define CAL_APP_CAPT_F_CB (const VpsCore_Frame *) (0x5555)
+/**< Number of callback expected (Eof, Sof & X line) */
+#define CAL_APP_NUM_CB (CAL_APP_NUM_FRAMES * 3U)
void CalAppUtils_BoardInit(void);
void CalAppUtils_FrameBufInit(void);
void CalAppUtils_FrameBufDeInit(void);
diff --git a/examples/iss/isscapt_baremetal_app/src/app_framebufmgnt.c b/examples/iss/isscapt_baremetal_app/src/app_framebufmgnt.c
index bb3ca0260e06eb67885ef68c109303cb6d622be8..e181ad214475493f68abcf06cc6e0c676b926483 100755 (executable)
/*\r
* \brief Maximum number of buffers to be allocated\r
*/\r
-#define MAX_NUM_BUFS (4U)\r
+#define MAX_NUM_BUFS (CAL_APP_NUM_FRAMES)\r
\r
/*\r
* \brief Maximum Buffer Size, assuming input size is always greater\r
diff --git a/examples/iss/isscapt_baremetal_app/src/app_iss.c b/examples/iss/isscapt_baremetal_app/src/app_iss.c
index e1076c8e406dbd2779fe54e6239bd6359a845e5f..80411729032d485f8da0364aedc1cf09efd1cec4 100755 (executable)
#include <ti/csl/csl_types.h>
#include <ti/csl/soc.h>
#include <ti/drv/vps/include/common/bsp_types.h>
+#include <ti/drv/vps/include/osal/bsp_osal.h>
+
#include <ti/drv/vps/src/vpslib/common/vpscore.h>
#include <ti/drv/vps/include/common/bsp_utils.h>
#include <ti/drv/vps/src/vpslib/common/iem_evtmgr.h>
#include <ti/drv/vps/src/vpslib/common/vps_common.h>
#include <ti/drv/vps/src/vpslib/common/cal_evtmgr.h>
#include <ti/drv/vps/src/vpslib/calcore/vpscore_capture.h>
+
+#include <ti/drv/stw_lld/uartconsole/uartStdio.h>
+
#include <app_framebufmgnt.h>
/* ========================================================================== */
#define CAL_APP_NUM_LANES (4)
/**< Number of active lanes, excluding clock */
#define CAL_APP_CSI2_PHY_MHZ (400U)
-/**< DDR Clock */
+/**< DDR Clock, CSI2 Clock */
#define CAL_APP_IN_WIDTH (640U)
#define CAL_APP_IN_HEIGHT (480U)
#define CAL_APP_IN_PITCH (CAL_APP_IN_WIDTH * 3U)
+/**< For RAW 12, this should be width * 2U */
#define CAL_APP_IN_BPP (FVID2_BPP_BITS24)
+/**< For RAW 12, this should be FVID2_BPP_BITS12 */
#define CAL_APP_CSI2_DATA_FMT (VPS_ISS_CAL_CSI2_RGB888)
-/**< In comming data format on CSI2 i/f */
+/**< In coming data format on CSI2 i/f.
+ For RAW 12 this should be VPS_ISS_CAL_CSI2_RAW12 */
#define CAL_APP_INSTANCE_ID (0U)
/**< CAL A */
-#define CAL_APP_NUM_FRAMES (0x4U)
-/**< Number of frames to capture */
+#define CAL_APP_NOTIFY_LINE_NUM (16U)
+/**< Enable notification on detection of above line number */
/* ========================================================================== */
/* Structure Declarations */
/**< CAL ID */
volatile UInt32 frmDone;
/**< Variable to wait for the frame completion interrupt */
- const volatile VpsCore_Frame *frameCaptured;
- /**< Captured frame that would be checked */
const VpsCore_Ops *coreOps;
/**< Core Operations of CAL core */
VpsCore_Handle *calCoreHndl;
const VpsCore_Frame *pFramesCaptured[CAL_APP_NUM_FRAMES+1U];
/**< Addresses of frames captured */
volatile UInt32 index;
- /**< Index used to remmember last frame captured */
+ /**< Index used to remember last frame captured */
+ UInt32 capFrameStatus[CAL_APP_NUM_FRAMES+1U];
+ /**< Status of the captured frames */
+
+ UInt32 subFrmIndex;
+ /**< Index used to remember last frame captured */
+ Fvid2_SubFrameInfo subFrameInfo[CAL_APP_TOTAL_NUM_SUB_FRAMES+1U];
+ /**< Sub frame info returned */
+ UInt32 subFrameStatus[CAL_APP_TOTAL_NUM_SUB_FRAMES+1U];
+ /**< status of frame returned at sub-frame/eof callback */
+ const VpsCore_Frame *pSubFramesCaptured[CAL_APP_NUM_FRAMES+1U];
+ /**< Addresses of frames, returned by sub-frame CB */
+
+ UInt32 eofFrmIndex;
+ /**< Index used to remember last frame captured */
+ const VpsCore_Frame *pEofFramesCaptured[CAL_APP_NUM_FRAMES+1U];
+ /**< Addresses of frames, returned by end of frame CB */
+ UInt32 eofFrameStatus[CAL_APP_NUM_FRAMES+1U];
+ /**< status of frame returned at sub-frame/eof callback */
+
+ const VpsCore_Frame *pFramesCapturedSeq[CAL_APP_NUM_CB+2U][2U];
+ /**< Frames pointers, stored in order of notification in CB */
+ UInt32 frmSeqIndex;
+ /**< Index for above */
+
+ UInt32 errUnkownCbEof[CAL_APP_NUM_FRAMES+1U];
+ /**< Debug counter, to check if any classified callbacks are issued */
+ UInt32 errUnkownCbIdx;
+ /**< Index for above */
+
+ UInt32 dataChk[CAL_APP_NUM_FRAMES+1U];
+ /**< Data check, check to ensure data is present */
+ UInt32 dataChkIndex;
+ /**< Index for above */
+
+ UInt32 timeTickVal[CAL_APP_NUM_FRAMES+1U];
+ /**< Time stamp for frames returned */
+ UInt32 subFrameTimeTickVal[CAL_APP_NUM_FRAMES+1U];
+ /**< Time stamp for sub-frame callback */
+ UInt32 eofFrameTimeTickVal[CAL_APP_NUM_FRAMES+1U];
+ /**< Time stamp for end-frame callback */
+
} vpsAppObject_t;
/* ========================================================================== */
Int32 AppCalOpen(vpsAppObject_t *appObj);
Int32 AppCalClose(vpsAppObject_t *appObj);
Int32 AppCalApplyCfg(vpsAppObject_t *appObj);
+Int32 AppCalRegErrCb(vpsAppObject_t *appObj);
+Int32 AppCalRegEofFrmSubFrmCb(vpsAppObject_t *appObj);
+Int32 AppCalSubFrame_FrameCapturedCb (void *drvData,
+ const VpsCore_Frame *frame,
+ Fvid2_SubFrameInfo *subFrmInfo);
Int32 AppCalFrameCapturedCb(void *drvData, const VpsCore_Frame *frame);
VpsCore_Frame *AppCalReqFrameCb(void *drvData, UInt32 streamId, UInt32 chId);
+Int32 AppCalCheckReceivedFrames(vpsAppObject_t *appObj);
/* ========================================================================== */
/* Global Variables */
/* Function Definitions */
/* ========================================================================== */
+void AppCalPrintErrorCode(Fvid2_FrameStatus status)
+{
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR, "");
+ switch (status)
+ {
+ case FVID2_FRAME_STATUS_ECC_CORRECTED:
+ UARTprintf("1 Bit ECC error detected and corrected \n");
+ break;
+ case FVID2_FRAME_STATUS_CRC_ERROR:
+ UARTprintf("CRC error detected \n");
+ break;
+ case FVID2_FRAME_STATUS_ECC_ERROR:
+ UARTprintf("ECC error detected \n");
+ break;
+ default:
+ UARTprintf("UN Known error detected \n");
+ break;
+ }
+}
+
Int32 AppCalDeInit(vpsAppObject_t *appObj)
{
return VpsLib_deInit(NULL);
(void *) &appObj->coreOpenRtnParams);
appObj->frmDone = 0x0;
appObj->index = 0;
+ appObj->subFrmIndex = 0U;
+ appObj->eofFrmIndex = 0U;
+ appObj->frmSeqIndex = 0U;
+ appObj->errUnkownCbIdx = 0U;
+ appObj->dataChkIndex = 0U;
}
return FVID2_SOK;
}
Int32 AppCalApplyCfg(vpsAppObject_t *appObj)
{
+ Int32 status = FVID2_SOK;
+ UInt32 i;
+ vpsissCalCfg_t cfg;
+
+ cfg.numStream = 1U;
+ for (i = 0U; i < cfg.numStream; i++)
+ {
+ cfg.streamId[i] = i;
+ cfg.inFmt[i].width = CAL_APP_IN_WIDTH;
+ cfg.inFmt[i].height = CAL_APP_IN_HEIGHT;
+
+ cfg.inFmt[i].pitch[0] = CAL_APP_IN_PITCH;
+ cfg.inFmt[i].bpp = CAL_APP_IN_BPP;
+ cfg.csi2DataFormat[i] = CAL_APP_CSI2_DATA_FMT;
+ cfg.inFmt[i].dataFormat = 0x0U;
+
+ cfg.csi2VirtualChanNo[i] = 0x0U;
+ cfg.streamType[i] = VPS_ISS_CAL_TAG_PIX_DATA;
+ cfg.isPixProcCfgValid[i] = FALSE;
+ cfg.isBysOutCfgValid[i] = FALSE;
+ cfg.bysInEnable[i] = FALSE;
+ cfg.isVportCfgValid[i] = FALSE;
+ cfg.writeToMem[i] = TRUE;
+
+ if (VPS_ISS_CAL_CSI2_RAW12 == CAL_APP_CSI2_DATA_FMT)
+ {
+ cfg.isPixProcCfgValid[i] = TRUE;
+ cfg.pixProcCfg[i].decCodec = VPS_ISS_CAL_DPCM_DEC_BYPASS;
+ cfg.pixProcCfg[i].enableDpcmInitContext = FALSE;
+ cfg.pixProcCfg[i].encCodec = VPS_ISS_CAL_DPCM_ENC_BYPASS;
+ cfg.pixProcCfg[i].pack = VPS_ISS_CAL_PIX_PACK_B16;
+ }
+ /* For VPS_ISS_CAL_CSI2_RGB888, there is no native support and hence
+ treating it as 8 bit stream */
+ }
+ status = appObj->coreOps->control(appObj->calCoreHndl,
+ VCORE_ISS_CAPT_CAL_SET_PARAMS,
+ &cfg, NULL);
+ return status;
+}
+
+Int32 AppCalRegErrCb(vpsAppObject_t *appObj)
+{
+ vpsissCalErrorCfg_t errSrcCfg;
Int32 status = FVID2_SOK;
- UInt32 i;
- isshalCalCfg_t cfg;
- cfg.numCPortId = appObj->coreOpenRtnParams.numStreamsAlloc;
+ errSrcCfg.cmplxIoId = 0U; /* Only 1, in TDA3x */
+ errSrcCfg.numErrorsToMonitor = 0U;
+
+ /* Un Correctable ECC errors */
+ errSrcCfg.errSrc[errSrcCfg.numErrorsToMonitor] =
+ VPS_CAL_CSI2_PPI_CMPLXIO_ECC_NO_CORRECTION;
+ errSrcCfg.numErrorsToMonitor++;
+
+ /* CRC errors */
+ errSrcCfg.errSrc[errSrcCfg.numErrorsToMonitor] =
+ VPS_CAL_CSI2_PPI_VC_CRC_MISMATCH_VC1;
+ errSrcCfg.numErrorsToMonitor++;
+
+ /* Like to be notified of 1 bit ECC errors, which were corrected */
+ errSrcCfg.errSrc[errSrcCfg.numErrorsToMonitor] =
+ VPS_CAL_CSI2_PPI_VC_ECC_CORRECTION_VC1;
+ errSrcCfg.numErrorsToMonitor++;
+
+ /* No callback provided, we will rely on frame status to determine if there
+ were any errors.
+ If require application could provide a callback here, which would called
+ when error are detected */
+ errSrcCfg.appCb = NULL;
+
+ errSrcCfg.pAppCbArgs = NULL;
+ errSrcCfg.pAdditionalArgs = NULL;
+
+ status = appObj->coreOps->control(appObj->calCoreHndl,
+ VCORE_ISS_CAPT_CAL_SET_ERR_PRMS,
+ &errSrcCfg, NULL);
- for(i = 0; i < appObj->coreOpenRtnParams.numStreamsAlloc; i++)
+ return (status);
+}
+
+Int32 AppCalRegEofFrmSubFrmCb(vpsAppObject_t *appObj)
+{
+ Int32 status;
+ UInt32 idx;
+ vcoreissCaptSubFrameCfg_t subFrmCfg;
+
+ subFrmCfg.numStream = 0U;
+ for (idx = 0U; idx < CAL_APP_NUM_SUB_FRAMES; idx++)
{
- cfg.cportId[i] = appObj->coreOpenRtnParams.cportIdAlloc[i];
- cfg.streamFmt[i].width = CAL_APP_IN_WIDTH;
- cfg.streamFmt[i].height = CAL_APP_IN_HEIGHT;
- cfg.streamFmt[i].pitch[0] = CAL_APP_IN_PITCH;
- cfg.streamFmt[i].bpp = CAL_APP_IN_BPP;
- cfg.isCsi2BasedCapture[i] = TRUE;
- cfg.csiDataType[i] = CAL_APP_CSI2_DATA_FMT;
-
- cfg.streamFmt[i].dataFormat = 0;
- cfg.virtualChanNum[i] = 0x0;
- cfg.stream[i] = VPS_ISS_CAL_TAG_PIX_DATA;
-
- cfg.isPixProcCfgValid[i] = FALSE;
- cfg.isBysOutCfgValid[i] = FALSE;
- cfg.isBysInCfgValid[i] = FALSE;
- cfg.bysInEnable[i] = FALSE;
- cfg.isVportCfgValid[i] = FALSE;
- cfg.writeToMem[i] = TRUE;
-
- cfg.isPixProcCfgValid[i] = FALSE;
- /* No Native support to extract and pack 24 bits/pixel, hence bypassing
- treating it as 8b stream */
- cfg.streamFmt[i].pitch[0] = CAL_APP_IN_PITCH;
- cfg.streamFmt[i].bpp = CAL_APP_IN_BPP;
+ subFrmCfg.numStream++;
+ subFrmCfg.streamId[idx] = 0x0U;
+ subFrmCfg.notifyAfterFirstXLines[idx] = CAL_APP_NOTIFY_LINE_NUM;
+ subFrmCfg.notifyAfterEndOfFrame[idx] = TRUE;
}
- if(appObj->coreOps->setParams != NULL)
+
+ subFrmCfg.appCb = (VpsCore_SubFrameCbFxn) &AppCalSubFrame_FrameCapturedCb;
+ subFrmCfg.pAppCbArgs = appObj;
+ subFrmCfg.pAdditionalArgs = NULL;
+ status = appObj->coreOps->control(appObj->calCoreHndl,
+ VCORE_ISS_CAPT_CAL_SET_SUB_FRM_PRMS,
+ &subFrmCfg, NULL);
+
+ return (status);
+}
+
+/* Callback, will be called for Nth line and end of frame */
+Int32 AppCalSubFrame_FrameCapturedCb (void *drvData,
+ const VpsCore_Frame *frame,
+ Fvid2_SubFrameInfo *subFrmInfo)
+{
+ vpsAppObject_t *pAppObj;
+ Fvid2_SubFrameInfo *pSubFrmInfo;
+
+ pAppObj = (vpsAppObject_t *) drvData;
+
+ /* Nth line / Sub frame callback */
+ if ((CAL_APP_NUM_SUB_FRAMES > subFrmInfo->subFrameNum) &&
+ (CAL_APP_TOTAL_NUM_SUB_FRAMES > pAppObj->subFrmIndex))
+ {
+ pSubFrmInfo = &pAppObj->subFrameInfo[pAppObj->subFrmIndex];
+
+ /* Sub frame Info */
+ pSubFrmInfo->subFrameNum = subFrmInfo->subFrameNum;
+ pSubFrmInfo->numOutLines = subFrmInfo->numOutLines;
+ pSubFrmInfo->numInLines = 0U;
+
+ /* Book keeping for error, sequence checks */
+ pAppObj->subFrameStatus[pAppObj->subFrmIndex] = frame->status;
+ pAppObj->pSubFramesCaptured[pAppObj->subFrmIndex] = frame;
+ pAppObj->subFrameTimeTickVal[pAppObj->subFrmIndex] =
+ BspOsal_getClockTicks();
+ pAppObj->subFrmIndex++;
+
+ if (pAppObj->frmSeqIndex < CAL_APP_NUM_CB)
+ {
+ pAppObj->pFramesCapturedSeq[pAppObj->frmSeqIndex][0U] = frame;
+ pAppObj->pFramesCapturedSeq[pAppObj->frmSeqIndex]
+ [1U] = CAL_APP_SUB_F_CB;
+ pAppObj->frmSeqIndex++;
+ }
+ if (CAL_APP_NUM_FRAMES > pAppObj->dataChkIndex)
+ {
+ pAppObj->dataChk[pAppObj->dataChkIndex] =
+ *((UInt32 *)((UInt32) frame->addr[0U][0U] +
+ ((CAL_APP_IN_PITCH) * CAL_APP_NOTIFY_LINE_NUM)));
+ pAppObj->dataChkIndex++;
+ }
+
+ } else
+
+ /* End of frame */
+ if ((CAL_APP_NUM_SUB_FRAMES == subFrmInfo->subFrameNum) &&
+ (CAL_APP_NUM_FRAMES > pAppObj->eofFrmIndex))
{
- status = appObj->coreOps->setParams(appObj->calCoreHndl, &cfg, NULL);
+ /* frame : Pointer to just captured frame */
+
+ /* Book keeping for error, sequence checks */
+ if (pAppObj->frmSeqIndex < CAL_APP_NUM_CB)
+ {
+ pAppObj->pFramesCapturedSeq[pAppObj->frmSeqIndex][0U] = frame;
+ pAppObj->pFramesCapturedSeq[pAppObj->frmSeqIndex]
+ [1U] = CAL_APP_EOF_CB;
+ pAppObj->frmSeqIndex++;
+ }
+ pAppObj->eofFrameStatus[pAppObj->eofFrmIndex] = frame->status;
+ pAppObj->pEofFramesCaptured[pAppObj->eofFrmIndex] = frame;
+ pAppObj->eofFrameTimeTickVal[pAppObj->eofFrmIndex] =
+ BspOsal_getClockTicks();
+ pAppObj->eofFrmIndex++;
+ }
+ else if (CAL_APP_NUM_SUB_FRAMES < subFrmInfo->subFrameNum)
+ {
+ pAppObj->errUnkownCbEof[pAppObj->errUnkownCbIdx] =
+ subFrmInfo->subFrameNum;
+ pAppObj->errUnkownCbIdx++;
+ }
+ else
+ {
+ /* Beyond the storage allocated to store status, this can occur stop
+ */
}
- return status;
+ return 0x0;
}
Int32 AppCalFrameCapturedCb(void *drvData, const VpsCore_Frame *frame)
pAppObj = (vpsAppObject_t *) drvData;
if(gAppObj.index < CAL_APP_NUM_FRAMES)
{
+ if (pAppObj->frmSeqIndex < CAL_APP_NUM_CB)
+ {
+ pAppObj->pFramesCapturedSeq[pAppObj->frmSeqIndex][0U] = frame;
+ pAppObj->pFramesCapturedSeq[pAppObj->frmSeqIndex]
+ [1U] = CAL_APP_CAPT_F_CB;
+ pAppObj->frmSeqIndex++;
+ }
+
+ gAppObj.timeTickVal[gAppObj.index] = BspOsal_getClockTicks();
+ gAppObj.capFrameStatus[gAppObj.index] = frame->status;
gAppObj.pFramesCaptured[gAppObj.index++] = frame;
}
pAppObj->frmDone++;
- pAppObj->frameCaptured = frame;
return 0x0;
}
{
VpsCore_Frame *pCoreFrame = NULL;
pCoreFrame = CalAppUtils_GetFrameBuf();
+
+ /* Ensure to clear location used to check */
+ *((UInt32 *)((UInt32) pCoreFrame->addr[0U][0U] +
+ ((CAL_APP_IN_PITCH) * CAL_APP_NOTIFY_LINE_NUM))) = 0xFEEDFEED;
+
return pCoreFrame;
}
{
Int32 status, totalBytes;
- /* Initiliaze dependencies, UART, I2C, PM */
+ /* Initialize dependencies, UART, I2C, PM */
CalAppUtils_BoardInit();
/* Initialize platform, ISS control, power up CAL / ISP */
status = AppCalInit(&gAppObj);
if(FVID2_SOK != status)
{
- Bsp_printf(CAL_APP_UTIL CAL_APP_ERR "Core Init Failed\n");
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR "Core Init Failed\n");
}
else
{
status = AppCalOpen(&gAppObj);
if(FVID2_SOK != status)
{
- Bsp_printf(CAL_APP_UTIL CAL_APP_ERR "Core Open Failed\n");
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR "Core Open Failed\n");
}
else
{
status = AppCalApplyCfg(&gAppObj);
if(FVID2_SOK != status)
{
- Bsp_printf(CAL_APP_UTIL CAL_APP_ERR
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
"ISS CAL App: Core could not apply config\n");
}
- else
+
+ if(FVID2_SOK == status)
+ {
+ AppCalRegErrCb(&gAppObj);
+ if(FVID2_SOK != status)
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "ISS CAL App: Core could not register error CB's \n");
+ }
+ }
+
+ if(FVID2_SOK == status)
+ {
+ AppCalRegEofFrmSubFrmCb(&gAppObj);
+ if(FVID2_SOK != status)
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "ISS CAL App: Core could not register EOF/SUB Frm CB's \n");
+ }
+ }
+
+ if(FVID2_SOK == status)
{
- Bsp_printf(CAL_APP_UTIL CAL_APP_INFO
+ UARTprintf(CAL_APP_UTIL CAL_APP_INFO
"Configured CAL to receive!!!\n");
- Bsp_printf(CAL_APP_UTIL CAL_APP_INFO "Configuring Sensor!!!\n");
+ UARTprintf(CAL_APP_UTIL CAL_APP_INFO "Configuring Sensor!!!\n");
+ /* With external sensor, remove this API, initialize the
+ sensor here */
CalAppUtils_appInitUb954_Ub953();
- Bsp_printf(CAL_APP_UTIL CAL_APP_INFO
+ UARTprintf(CAL_APP_UTIL CAL_APP_INFO
"Sensor configured & Streaming!!!\n");
- Bsp_printf(CAL_APP_UTIL CAL_APP_INFO "Starting Capture Now!!!\n");
+ UARTprintf(CAL_APP_UTIL CAL_APP_INFO "Starting Capture Now!!!\n");
status = gAppObj.coreOps->start(gAppObj.calCoreHndl);
while(gAppObj.frmDone < CAL_APP_NUM_FRAMES)
{
temp = lastFrameNo;
lastFrameNo = gAppObj.frmDone;
- Bsp_printf(CAL_APP_UTIL CAL_APP_INFO
- "Recevied Frame %x of %x\n", temp, CAL_APP_NUM_FRAMES);
+ UARTprintf(CAL_APP_UTIL CAL_APP_INFO
+ "Received Frame %x of %x\n", temp, CAL_APP_NUM_FRAMES);
}
}
status = gAppObj.coreOps->stop(gAppObj.calCoreHndl);
- Bsp_printf(CAL_APP_UTIL CAL_APP_INFO
+ UARTprintf(CAL_APP_UTIL CAL_APP_INFO
"Frame reception is completed \n");
totalBytes = (CAL_APP_IN_PITCH * CAL_APP_IN_HEIGHT) / 4U;
CalAppUtils_appDeInitUb954_Ub953();
+ AppCalCheckReceivedFrames(&gAppObj);
+
while(gAppObj.index)
{
gAppObj.index--;
- Bsp_printf("saveRaw(0, 0x%x, "
+ if (FVID2_FRAME_STATUS_COMPLETED ==
+ gAppObj.capFrameStatus[gAppObj.index])
+ {
+ UARTprintf("saveRaw(0, 0x%x, "
"\"D:\\\\RGB888_%dx%d.yuv\","
"%d, 32, false)\n",
gAppObj.pFramesCaptured[gAppObj.index]->addr[0U][0U],
CAL_APP_IN_WIDTH, CAL_APP_IN_HEIGHT,
totalBytes);
+ }
+ else
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "Detected following error (s) \n");
+ AppCalPrintErrorCode( (Fvid2_FrameStatus)
+ gAppObj.capFrameStatus[gAppObj.index]);
+ UARTprintf("saveRaw(0, 0x%x, "
+ "\"D:\\\\RGB888_%dx%d.yuv\","
+ "%d, 32, false)\n",
+ gAppObj.pFramesCaptured[gAppObj.index]->addr[0U][0U],
+ CAL_APP_IN_WIDTH, CAL_APP_IN_HEIGHT,
+ totalBytes);
+ }
}
- Bsp_printf (CAL_APP_UTIL CAL_APP_INFO "Put a break point here"
+ UARTprintf (CAL_APP_UTIL CAL_APP_INFO "Put a break point here"
", In case you want to save frames using above "
"commands \n");
AppCalClose(&gAppObj);
AppCalDeInit(&gAppObj);
- Bsp_printf (CAL_APP_UTIL CAL_APP_INFO "ISS CAL App: Passed\n");
+ UARTprintf (CAL_APP_UTIL CAL_APP_INFO "ISS CAL App: Passed\n");
}
}
}
return 0;
}
+
+Int32 AppCalCheckReceivedFrames(vpsAppObject_t *appObj)
+{
+ UInt32 idx;
+ /* Checks performed
+ Check 1 : Ensure correct frames are returned.
+ i.e. Received frame address should same for sub-frame,
+ start of frame and end of frame
+ Check 2 : Captured line numbers are marked correctly
+ Check 3 : Ensure frames are received in correct order.
+ i.e. First should be Sub Frame CB, End of Frame and
+ captured frame
+ Check 4 : Data Available in DDR, when sub-frame callback is received.
+ Check 5 : Time stamp : Check if in order
+ */
+ /* Check 1 : Ensure correct frames are returned. */
+ for (idx = 0U; idx < CAL_APP_NUM_FRAMES; idx++)
+ {
+ if (appObj->pEofFramesCaptured[idx] != appObj->pFramesCaptured[idx])
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "Frames returned in EoF and Frame captured CB don't match \n");
+ }
+ if (appObj->pSubFramesCaptured[idx] != appObj->pFramesCaptured[idx])
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "Frames returned in SubFrame CB and Frame captured CB "
+ "don't match \n");
+ }
+ }
+ if (idx != CAL_APP_NUM_FRAMES)
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "Eof and frame captured CB don't add up \n");
+ }
+ else
+ {
+ UARTprintf (CAL_APP_UTIL CAL_APP_INFO "Received 0x%x Sub Frame CB \n",
+ appObj->subFrmIndex);
+ UARTprintf (CAL_APP_UTIL CAL_APP_INFO "Received 0x%x EOF CB \n",
+ appObj->eofFrmIndex);
+ UARTprintf (CAL_APP_UTIL CAL_APP_INFO "Received 0x%x Frame Done CB \n",
+ appObj->index);
+ if (0U != appObj->errUnkownCbIdx)
+ {
+ UARTprintf (CAL_APP_UTIL CAL_APP_INFO "Received 0x%x Error CB \n",
+ appObj->errUnkownCbIdx);
+ }
+ }
+
+ /* Check 2 : Captured line numbers are marked correctly */
+ for (idx = 0U; idx < appObj->errUnkownCbIdx; idx++)
+ {
+ UARTprintf (CAL_APP_UTIL CAL_APP_INFO
+ "Received 0x%x Error CB Sub Frame no\n",
+ appObj->errUnkownCbEof[idx]);
+ }
+
+ /* Check 3 : Ensure frames are received in correct order. */
+ for (idx = 0U; idx < CAL_APP_NUM_CB; idx +=3U)
+ {
+ if ((appObj->pFramesCapturedSeq[idx+0U][0U] !=
+ appObj->pFramesCapturedSeq[idx+1U][0U]) ||
+ (appObj->pFramesCapturedSeq[idx+0U][0U] !=
+ appObj->pFramesCapturedSeq[idx+2U][0U]))
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "Frames returned in Sub Frame, End Of Frame and Capture"
+ " completed don't match !!!\n");
+ }
+ if ((appObj->pFramesCapturedSeq[idx+0U][1U] != CAL_APP_SUB_F_CB) ||
+ (appObj->pFramesCapturedSeq[idx+1U][1U] != CAL_APP_EOF_CB) ||
+ (appObj->pFramesCapturedSeq[idx+2U][1U] != CAL_APP_CAPT_F_CB))
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "Sequence of CB isn't correct !!! \n"
+ "Expected sequence is SubFrame, End of Frame and"
+ " Capture completed \n");
+ }
+ }
+
+ /* Check 4 : Data Available in DDR, when sub-frame callback is received */
+ for (idx = 0U; idx < CAL_APP_NUM_FRAMES; idx++)
+ {
+ if (appObj->dataChk[idx] != 0xAAAAAAAA)
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "Data is in-consistent in SubFrame CB !!!\n");
+ }
+ }
+ /* Check 5 : Time stamp : Check if in order */
+ for (idx = 0U; idx < CAL_APP_NUM_FRAMES; idx++)
+ {
+ if (appObj->subFrameTimeTickVal[idx] >=
+ appObj->eofFrameTimeTickVal[idx])
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "End of sub-frame was notified after EOF !!!\n");
+ }
+ else if (appObj->eofFrameTimeTickVal[idx] >=
+ appObj->timeTickVal[idx])
+ {
+ UARTprintf(CAL_APP_UTIL CAL_APP_ERR
+ "End of frame was notified after frame was returned !!!\n");
+ }
+ else
+ {
+ /* Everything in order */
+ }
+ }
+ return 0x0;
+}
diff --git a/examples/iss/isscapt_baremetal_app/src/app_tdaxx.c b/examples/iss/isscapt_baremetal_app/src/app_tdaxx.c
index 5bafa78bb0f3bad185506f2b7646b8eb8c76322b..b9e847eea833156e7557d31cc06d9152333faa8c 100755 (executable)
#include <ti/csl/tistdtypes.h>
#include <ti/csl/csl_types.h>
#include <ti/csl/soc.h>
+#include <ti/csl/arch/csl_arch.h>
#include <ti/csl/example/utils/i2c/inc/i2c.h>
#include <ti/drv/vps/include/common/bsp_types.h>
#include <ti/drv/vps/include/common/trace.h>
{0x12, 0x13, 0x100},
{0x32, 0x01, 0x100},
{0x33, 0x03, 0x100},
- {0xB0, 0x00, 0x100}, /* Indirect access to pattern genrator */
+ {0xB0, 0x00, 0x100}, /* Indirect access to pattern generator */
{0xB1, 0x01, 0x100}, /* Select Reg PGEN_CTL */
{0xB2, 0x01, 0x100}, /* Write 1 to it */
{0x20, 0x00, 0x100}
void CalAppUtils_IntrInit(void)
{
+ Intc_Init();
+
/* XBAR ISS_IRQ_INT0 to IPU1_33 */
IRQXBARConnect(SOC_IRQ_DMARQ_CROSSBAR_REGISTERS_BASE,
CPU_IPU1, XBAR_INST_IPU1_IRQ_33, ISS_IRQ_INT0);
index 8ce2b05e17314f4870c18c3173698275fa6a9bed..65ec63fb8b40f537194e4975274118b8d55fddcc 100755 (executable)
/**
* \brief Enum for state of the FVID2 frame. Typically used for
- * marking FVID2_frame as either SUBMITTED, Completed/Done, Errorneous
+ * marking FVID2_frame as either SUBMITTED, Completed/Done, Erroneous
* at the time of flush/abort when driver returns back all the frames
*/
typedef enum
index 76f5d96c59899f327071a2de9abcc0d355a4d93d..84793aaece3db9a580a0f11a158f797f64d05aa6 100755 (executable)
--- a/include/iss/vps_cfgcal.h
+++ b/include/iss/vps_cfgcal.h
**/
#define VPS_ISS_CAL_MAX_ERROR_INTERRUPTS (20U)
+/** \brief Defines the total number of VC, for which a callback can be issued
+ * on reception of X lines.
+**/
+#define VPS_ISS_CAL_MAX_X_LINE_MONITOR_CNT (1U)
+
/* ========================================================================== */
/* Function Types */
/* ========================================================================== */
*/
#define VCORE_ISS_CAPT_CAL_SET_ERR_PRMS (VCORE_ISS_CAPT_BASE_IOCTL + 3U)
+/** \brief Enable CB on reception of Nth line and end of frame
+ * vcoreissCaptSubFrameCfg_t defined in starterware_\include\vps\iss\vps_cfgcal.h
+ */
+#define VCORE_ISS_CAPT_CAL_SET_SUB_FRM_PRMS (VCORE_ISS_CAPT_BASE_IOCTL + 4U)
+
/* ========================================================================== */
/* Structure Declarations */
/* ========================================================================== */
/**< Not used as of now */
} vcoreissCaptOpenRetParams_t;
+/**
+ * struct vcoreissCaptSubFrameCfg
+ * \brief CAL could be configured to notify application on end of frame or on
+ * reception of first X lines.
+ *
+ * Limitation on first x lines callback : Currently this can be enabled for
+ * one stream and stream should be of type VPS_ISS_CAL_TAG_PIX_DATA
+ *
+ */
+typedef struct vcoreissCaptSubFrameCfg
+{
+ uint32_t numStream;
+ /**< Number of streams, which requires to be monitored for end of frame,
+ and or first X lines */
+ uint32_t streamId[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Specify the stream ID, which requires to be monitored */
+ uint32_t notifyAfterFirstXLines[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Will call the application provided callback, after reception of
+ number of lines specified here.
+ Restriction :
+ This can be supported for only VPS_ISS_CAL_MAX_X_LINE_MONITOR_CNT
+ virtual channel */
+ uint32_t notifyAfterEndOfFrame[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Will call the application provided callback, after reception of
+ End Of Frame short packet */
+ VpsCore_SubFrameCbFxn appCb;
+ /**< Application callback */
+ Ptr pAppCbArgs;
+ /**< Argument that would be passed when appCb is called. */
+ Ptr pAdditionalArgs;
+ /**< Not used for now - should be set to NULL */
+} vcoreissCaptSubFrameCfg_t;
+
/* ========================================================================== */
/* Function Declarations */
/* ========================================================================== */
const VpsCore_Frame *frm);
typedef Int32 (*VpsCore_FrameDoneNotifyCb)(void *drvData);
+
+/**
+ * \brief Extern callback function to be implemented by driver to notify
+ * completion of reception of sub-frame
+ */
+typedef Int32 (*VpsCore_SubFrameCbFxn)(void *drvData,
+ const VpsCore_Frame *frm,
+ Fvid2_SubFrameInfo *subFrmInfo);
+
/**
* enum VpsCore_Frame
* \brief Frame structure containing information about video buffer exchanged
index 7ab84a3571b8607d60eac52ce8e88e34f9d754dc..f7bf718fb6c4c4b078f8b327a38fcfabe8a69039 100755 (executable)
static int32_t calSetWrDmaMode(const isshalCalInstObj_t *pInstObj,
const isshalCalDmaVcCfg_t *pDmaCfg);
+/**
+ * \brief Sets the DMA configurations such as burst size, mode, etc...
+ *
+ * \param pInstObj Pointer to instance object.
+ * \param pDmaCfg Pointer to DMA config
+ *
+ * \return FVID2_SOK
+ *
+ **/
static int32_t CalCfgInstWrDma(
uint32_t baseAddr, const isshalCalInstCfg_t *pCfg);
+/**
+ * \brief Configure the interrupt generation on reception of specified line
+ * of video data.
+ *
+ * \param pInstObj Pointer to instance object.
+ * \param plnEvtCfg Pointer to line event configuration
+ *
+ * \return FVID2_SOK
+ *
+ **/
+static int32_t CalSetLineEventCfg(const isshalCalInstObj_t *pInstObj,
+ const isshalCalLineEventCfg_t *plnEvtCfg);
+
/* ========================================================================== */
/* Global Variables */
/* ========================================================================== */
}
break;
+ case VPS_HAL_ISS_IOCTL_CAL_LINE_EVENT_CFG:
+ if(NULL != cmdArgs)
+ {
+ rtnVal = CalSetLineEventCfg(hndl->pInstObj,
+ (isshalCalLineEventCfg_t *) cmdArgs);
+ }
+ else
+ {
+ rtnVal = FVID2_EBADARGS;
+ }
+ break;
+
default:
rtnVal = FVID2_EUNSUPPORTED_CMD;
break;
}
/**************************Function Separator**********************************/
+
+static int32_t CalSetLineEventCfg(const isshalCalInstObj_t *pInstObj,
+ const isshalCalLineEventCfg_t *plnEvtCfg)
+{
+ volatile uint32_t reg;
+ uint32_t baseAddr, cportId, i;
+
+ baseAddr = pInstObj->baseAddr;
+ for(i = 0; i < plnEvtCfg->numCPortId; i++)
+ {
+ cportId = plnEvtCfg->cportId[i];
+ reg = HW_RD_REG32(baseAddr + CAL_LINE_NUMBER_EVT);
+
+ reg &= ~CAL_LINE_NUMBER_EVT_CPORT_MASK;
+ reg &= ~CAL_LINE_NUMBER_EVT_MASK;
+
+ reg |= CAL_LINE_NUMBER_EVT_CPORT_MASK &
+ (plnEvtCfg->cportId[i] << CAL_LINE_NUMBER_EVT_CPORT_SHIFT);
+
+ reg |= CAL_LINE_NUMBER_EVT_MASK &
+ (plnEvtCfg->lineNumber[cportId] << CAL_LINE_NUMBER_EVT_SHIFT);
+
+ HW_WR_REG32(baseAddr + CAL_LINE_NUMBER_EVT, reg);
+ }
+ return (FVID2_SOK);
+}
+
+/**************************Function Separator**********************************/
index e2de24fe8895c4029bad906a9893efb25dcd3346..dddd1201c655e3874b45723c9e1a34a0f0c9e147 100755 (executable)
* VPS_HAL_ISS_IOCTL_CAL_RESET
* \brief This control is to be used to perform soft reset of CAL
*
- * \warning Ensure not active operations are in progress.
+ * \warning Ensure no active operations are in progress.
*
* \param handle A non NULL handle returned by function VpsHal_isscalOpen
* \param cmd VPS_HAL_ISS_IOCTL_CAL_RESET
* VPS_HAL_ISS_IOCTL_CAL_SET_INSTANCECFG
* \brief Updated the current instance config
*
- * \warning Ensure not active operations are in progress.
+ * \warning Ensure no active operations are in progress.
*
* \param handle A non NULL handle returned by function VpsHal_isscalOpen
* \param cmd VPS_HAL_ISS_IOCTL_CAL_SET_INSTANCECFG
* VPS_HAL_ISS_IOCTL_CAL_SET_VPORT_CFG
* \brief Set the Vport Configuration
*
- * \warning Ensure not active operations are in progress.
+ * \warning Ensure no active operations are in progress.
*
* \param handle A non NULL handle returned by function VpsHal_isscalOpen
* \param cmd VPS_HAL_ISS_IOCTL_CAL_SET_VPORT_CFG
#define VPS_HAL_ISS_IOCTL_CAL_RD_FMT_UPDATE \
(VPS_HAL_ISS_IOCTL_CAL_SET_BYSOUT_CFG + 1U)
+/**
+ * VPS_HAL_ISS_IOCTL_CAL_LINE_EVENT_CFG
+ * \brief Configure the line number at which an event/interrupt should be
+ * raised.
+ *
+ * \warning Ensure no active operations are in progress.
+ *
+ * \param handle A non NULL handle returned by function VpsHal_isscalOpen
+ * \param cmd VPS_HAL_ISS_IOCTL_CAL_LINE_EVENT_CFG
+ * \param cmdArgs A pointer to structure of type #isshalCalLineEventCfg_t.
+ * \param arg None
+ *
+ * \return Returns FVID2_SOK always
+ */
+#define VPS_HAL_ISS_IOCTL_CAL_LINE_EVENT_CFG \
+ (VPS_HAL_ISS_IOCTL_CAL_RD_FMT_UPDATE + 1U)
/* ========================================================================== */
/* Structure Declarations */
* applied. */
} isshalCalDmaVcCfg_t;
+/**
+ * struct isshalCalLineEventCfg
+ * \brief Line number event notification configuration.
+ *
+ */
+typedef struct isshalCalLineEventCfg
+{
+ uint32_t numCPortId;
+ /**< Defines the total captures streams, for which line notification should
+ * be configured. Should be 0x01 */
+ uint32_t cportId[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Associated CPORT IDs. All other members of this struct uses the
+ * contents of cportId[] as index. */
+ uint32_t lineNumber[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Specify the line number, at which notification should be generated.
+ * Valid range is between 1 & (2^14) - 1 */
+} isshalCalLineEventCfg_t;
+
/**
* struct isshalCalCfg
* \brief CAL config, Primarily used by core to convey CAL config to HAL.
* VpsHal_calPhyEnClockAndReset
* \brief This function is specific to PHY/Platform, initializes the PHY.
*
- * \param baseAddr Adress of the CAL peripheral
+ * \param baseAddr Address of the CAL peripheral
* \param cam0RxCoreBaseAddr Address of the PHY connected to PPI 0
* \param cam1RxCoreBaseAddr Address of the PHY connected to PPI 1
* \param pCfg A Valid CAL instance config
diff --git a/src/vpslib/isscore/src/vpscore_captureapi.c b/src/vpslib/isscore/src/vpscore_captureapi.c
index 564d81739d5186c09da68b0b0f8d494fe1d19f76..f38922a8c350de401522103a7b011fca404a4c84 100755 (executable)
1 when when DMA writes first byte of a given frame
other when DMA writes last byte of a given frame
- In cases where applications requires to be notified as soon as a
- frame is available, set this flag to TRUE.
+ By default we rely on start-of-frame interrupt to notify successful
+ capture of previous frame.
- When disabled, after a given frame is captured, applications would
- not be notified until the start of next frame. Essentially the
- blanking interval.
+ In cases where applications requires to be notified as soon a frame
+ is captured, the end-of-frame notification can be enabled with
+ VCORE_ISS_CAPT_CAL_SET_SUB_FRM_PRMS
This is a per instance flag, either CAL operates with dual
interrupt or single interrupt */
/**< Flag to specify if an instance is initialized */
vpsissCaptInstId_t instId;
/**< Platform data */
- uint32_t useDmaEndIntr;
- /**< TRUE: Enables DMA Frame End Interrupt
- * FALSE: No DMA Frame End Interrupt,
- * all processing is done in DMA Frame Start interrupt */
BspOsal_SemHandle instLock;
/**< Instance mutual exclusion */
uint32_t streamIdToVcMap[VPS_ISS_CAL_MAX_STREAMS];
/**< Maps stream ID to virtual channel. Value 0x4 is used to indicate
data is sourced from BYS_IN */
+ isshalCalLineEventCfg_t lineEventCfg;
+ /**< Place holder for line event configurations */
} vpscoreissCaptInstObj_t;
/** \brief Capture CAL handle object */
While starting / priming, capture would require to know the
ISP Streams ID for a given capture stream ID.
This variable, set up by application relates the same. */
+
+ void *emSubFrmCmpltHndl;
+ /**< Event manager handle for Sub Frame reception completion */
+ uint32_t subFrmstreamId;
+ /**< Stream ID, for which X line callback is enabled */
+ Fvid2_SubFrameInfo currSubFrame[VPS_ISS_CAL_MAX_STREAMS][2U];
+ /**< Place holder for sub-frame Info */
+ uint32_t isSubFrameCfgValid;
+ /**< Flag indicating valid / in valid sub-frame config. FALSE is invalid
+ and TRUE is valid */
+ vcoreissCaptSubFrameCfg_t subFrameCfg;
+ /**< Configuration for sub-frame and end of frame */
} vpscoreissCaptCalHndlObj_t;
/* ========================================================================== */
UInt32 numEvents,
Ptr arg);
+/** \brief Configured line has been received, called by event manager
+ * This ISR would be called only when X line event is configured.
+ *
+ * \param event Arrays of events which occurred
+ * \param numEvents number of valid entries in event
+ * \param arg Not used
+ *
+ */
+static void vcoreCaptXlineCmpltCb(const UInt32 *event,
+ UInt32 numEvents,
+ Ptr arg);
+
/** \brief Frame Done Processing - provide frame info and execute callback
* function
*/
static int32_t vcoreCaptFrameDoneProc(vpscoreissCaptCalHndlObj_t *pHndlObj,
uint32_t streamId);
-
+/** \brief Sub Frame completed - Will check for errors and issue callback's.
+ * Is expected to be called on write DMA completion also (end-of-frame)
+ *
+ */
+static int32_t vcoreCaptSubFrameDoneProc(vpscoreissCaptCalHndlObj_t *pHndlObj,
+ uint32_t streamId,
+ uint32_t isEof);
/** \brief Function to deallocate CAL sub modules
*
* \param calId CAL Id
*
* \return FVID2_SOK on success, appropriate error code otherwise.
*/
-static int32_t vcoreCaptDeAllocCalRes(
- Irm_Modules_t calId,
- vpsissCaptureBlocks_t resDeAlloc[
- VPS_ISS_CAL_MAX_STREAMS],
- UInt32 cnt);
+static int32_t vcoreCaptDeAllocCalRes(Irm_Modules_t calId,
+ vpsissCaptureBlocks_t resDeAlloc[VPS_ISS_CAL_MAX_STREAMS],
+ UInt32 cnt);
/** \brief Function to allocate CAL handle and sub modules required. Also
* determines if a given stream is to be processed by CAL / Others
*pHndlObj,
const vpsissCalErrorCfg_t *pErrCfg);
+/** \brief Configure sub-frame parameters and End of frame notification.
+ *
+ * \param pInstObj Pointer to handle object
+ *
+ * \return FVID2_SOK on success, appropriate error code otherwise.
+ */
+static int32_t vcoreCaptCfgSubEof(
+ vpscoreissCaptCalHndlObj_t *pHndlObj,
+ const vcoreissCaptSubFrameCfg_t *pSubFrmCfg);
+
+/** \brief Registers end of frame and x line interrupt handler
+ *
+ * \param pInstObj Pointer to handle object
+ *
+ * \return FVID2_SOK on success, appropriate error code otherwise.
+ */
+static int32_t vcoreCaptRegisterSubEofIsr(
+ vpscoreissCaptCalHndlObj_t *pHndlObj,
+ const vcoreissCaptSubFrameCfg_t *pSubFrmCfg);
#ifdef __cplusplus
}
#endif
static vpscoreissCaptInstObj_t gCaptInstObjs[VPS_ISS_CAPT_INST_MAX_ID] =
{
{(uint32_t) FALSE, /* We really require to set this to FALSE. */
- VPS_ISS_CAPT_INST_MAX_ID,
- (uint32_t) TRUE},
+ VPS_ISS_CAPT_INST_MAX_ID},
{(uint32_t) FALSE, /* We really require to set this to FALSE. */
- VPS_ISS_CAPT_INST_MAX_ID,
- (uint32_t) TRUE},
+ VPS_ISS_CAPT_INST_MAX_ID},
{(uint32_t) FALSE, /* We really require to set this to FALSE. */
- VPS_ISS_CAPT_INST_MAX_ID,
- (uint32_t) TRUE},
+ VPS_ISS_CAPT_INST_MAX_ID},
};
/* ========================================================================== */
{
BspUtils_memset((Ptr)&gCaptInstObjs[initParams->instId], 0x0,
sizeof(vpscoreissCaptInstObj_t));
- /* Configure to use dual interrupt or single interrupt */
- gCaptInstObjs[initParams->instId].useDmaEndIntr =
- CAL_USE_DUAL_INTERRUPT;
gCaptInstObjs[initParams->instId].instId = initParams->instId;
}
}
pHndlObj->next[i] = 1U;
pHndlObj->currBufs[i][0x0] = NULL;
pHndlObj->currBufs[i][0x1] = NULL;
+
+ Fvid2SubFrameInfo_init(&pHndlObj->currSubFrame[i][0x0]);
+ Fvid2SubFrameInfo_init(&pHndlObj->currSubFrame[i][0x1]);
+
rtnPrms->cportIdAlloc[i] = pHndlObj->allocatedRes[i].cport;
if((VCORE_CAL_STREAM_MODE_CAL_WRITE ==
pHndlObj->streamMode[i]) ||
(Ptr) &pHndlObj->streamOtfMap, (UInt8) 0xFF,
(UInt32) sizeof(vpsissCalOtfStreamMapCfg_t));
pHndlObj->streamOtfMap.numStream = 0U;
+
+ pHndlObj->isSubFrameCfgValid = FALSE;
}
else
{
GT_assert(VpsIssCalCoreTrace, (FVID2_SOK == rtnVal));
}
- if(TRUE == pInstObj->useDmaEndIntr)
+ if(NULL != pHndlObj->emDmaCmpltHndl[strmId])
{
rtnVal = Vps_iemUnRegister(
pHndlObj->emDmaCmpltHndl[strmId]);
GT_assert(VpsIssCalCoreTrace, (FVID2_SOK == rtnVal));
}
+
+ if (NULL != pHndlObj->emSubFrmCmpltHndl)
+ {
+ rtnVal = Vps_iemUnRegister(pHndlObj->emSubFrmCmpltHndl);
+ GT_assert(VpsIssCalCoreTrace, (FVID2_SOK == rtnVal));
+ }
}
}
}
if((FVID2_SOK == rtnVal) && (TRUE == pInstObj->isStarted))
{
cookie = BspOsal_disableInterrupt();
+ if (NULL != pHndlObj->emSubFrmCmpltHndl)
+ {
+ rtnVal = Vps_iemDisable(pHndlObj->emSubFrmCmpltHndl);
+ }
for(i = 0; i < pHndlObj->numStreams; i++)
{
if(NULL != pHndlObj->emDmaStartHndl[i])
rtnVal = Vps_iemDisable(pHndlObj->emDmaStartHndl[i]);
}
- if(TRUE == pInstObj->useDmaEndIntr)
+ if(NULL != pHndlObj->emDmaCmpltHndl[i])
{
rtnVal = Vps_iemDisable(pHndlObj->emDmaCmpltHndl[i]);
}
retVal = FVID2_EBADARGS;
}
break;
+ case VCORE_ISS_CAPT_CAL_SET_SUB_FRM_PRMS:
+ if(NULL != appArgs)
+ {
+ retVal = vcoreCaptCfgSubEof(pHndlObj,
+ (const vcoreissCaptSubFrameCfg_t *) appArgs);
+ }
+ else
+ {
+ retVal = FVID2_EBADARGS;
+ }
+ break;
default:
retVal = vcoreIspControl(
pHndlObj->ispPrms,
rtnVal = FVID2_EBADARGS;
}
- if((FALSE == pInstObj->useDmaEndIntr) && (FVID2_SOK == rtnVal))
+ if (FVID2_SOK == rtnVal)
{
if((FALSE == pHndlObj->firstDmaStartIntr[streamId]) &&
(NULL != pHndlObj->openPrms.frmDoneCb) &&
cookie = BspOsal_disableInterrupt();
pHndlObj->currBufs[streamId][pHndlObj->next[streamId]] =
newFrame;
+ /* Reset the sub-frame count */
+ pHndlObj->currSubFrame[streamId][pHndlObj->next[streamId]] \
+ .subFrameNum = 0xFFFFFFFFU;
+
BspOsal_restoreInterrupt(cookie);
}
else
}
}
+static void vcoreCaptXlineCmpltCb(const UInt32 *event,
+ UInt32 numEvents,
+ Ptr arg)
+{
+ UInt32 i, eventNo, streamId;
+ vpscoreissCaptCalHndlObj_t *pHndlObj;
+ int32_t rtnVal;
+
+ rtnVal = FVID2_SOK;
+ pHndlObj = (vpscoreissCaptCalHndlObj_t *) arg;
+
+ for(i = 0U; i < numEvents; i++)
+ {
+ eventNo = event[i];
+ if (IEM_CAL_EVENT_LINE_NUMBER == eventNo)
+ {
+ if((TRUE == pHndlObj->isSubFrameCfgValid) && (FVID2_SOK == rtnVal))
+ {
+ streamId = pHndlObj->subFrmstreamId;
+
+ rtnVal = vcoreCaptSubFrameDoneProc(pHndlObj, streamId, FALSE);
+ }
+ }
+ else
+ {
+ rtnVal = FVID2_EBADARGS;
+ }
+ }
+
+ return;
+}
+
static void vcoreCaptDmaCmpltCb(const UInt32 *event,
UInt32 numEvents,
Ptr arg)
}
}
- if(FVID2_SOK == rtnVal)
- {
- if(FALSE == pInstObj->useDmaEndIntr)
- {
- /* Should not Come in this case */
- GT_assert(VpsIssCalCoreTrace, FALSE);
- }
- }
-
if(FVID2_SOK == rtnVal)
{
for(i = 0U; i < numEvents; i++)
if(VCORE_CAL_STREAM_MODE_CAL_WRITE !=
pHndlObj->streamMode[streamId])
{
- /* If CAL is not writing, we do not expect enf of frame
+ /* If CAL is not writing, we do not expect end of frame
interrupt at all */
GT_assert(VpsIssCalCoreTrace, FALSE);
}
rtnVal = FVID2_EBADARGS;
}
- if((NULL != pHndlObj->openPrms.frmDoneCb) &&
- (FVID2_SOK == rtnVal))
+ if((NULL != pHndlObj->emDmaCmpltHndl[streamId]) &&
+ (FVID2_SOK == rtnVal))
{
- rtnVal = vcoreCaptFrameDoneProc(pHndlObj, streamId);
+ rtnVal = vcoreCaptSubFrameDoneProc(pHndlObj, streamId, TRUE);
}
}
}
}
+static int32_t vcoreCaptSubFrameDoneProc(vpscoreissCaptCalHndlObj_t *pHndlObj,
+ uint32_t streamId,
+ uint32_t isEof)
+{
+ uint32_t cookie, tmpVal, frmStatus, vc, curr;
+ volatile VpsCore_Frame *tmpBuf;
+ volatile Fvid2_SubFrameInfo *tmpSubFrmStatus;
+ vpscoreissCaptInstObj_t *pInstObj = NULL;
+
+ cookie = BspOsal_disableInterrupt();
+ curr = pHndlObj->curr[streamId];
+ /* Pending as, frame is not yet ready to be de-queued */
+ frmStatus = FVID2_FRAME_STATUS_PENDING;
+ tmpBuf = pHndlObj->currBufs[streamId][curr];
+ tmpSubFrmStatus =
+ &pHndlObj->currSubFrame[streamId][curr];
+
+ /* Get errors status if any */
+ pInstObj = pHndlObj->pInstObj;
+ vc = pInstObj->streamIdToVcMap[streamId];
+ if(CAL_MAX_VIRTUAL_CHAN >= vc)
+ {
+ /* Note that error status (stored locally in s/w : handleObject is not)
+ cleared. This would be cleared while returning back the frame.
+
+ The rational is, if there was one/more error in the first-n-lines,
+ this error could be applicable for complete frame. Typically,
+ applications want to know reception at end of frame also */
+ tmpVal = pInstObj->fifoOverFlow[vc] | pInstObj->eccCouldNotCorrect[vc]
+ | pInstObj->crcMisMatch[vc] | pInstObj->eccCorrected[vc];
+ if((uint32_t) FALSE != tmpVal)
+ {
+ if((uint32_t) TRUE == pInstObj->fifoOverFlow[vc])
+ {
+ frmStatus = FVID2_FRAME_STATUS_OVERFLOW;
+ }
+ else if((uint32_t) TRUE == pInstObj->eccCouldNotCorrect[vc])
+ {
+ frmStatus = FVID2_FRAME_STATUS_ECC_ERROR;
+ }
+ else if((uint32_t) TRUE == pInstObj->crcMisMatch[vc])
+ {
+ frmStatus = FVID2_FRAME_STATUS_CRC_ERROR;
+ }
+ else if((uint32_t) TRUE == pInstObj->eccCorrected[vc])
+ {
+ frmStatus = FVID2_FRAME_STATUS_ECC_CORRECTED;
+ }
+ else
+ {
+ frmStatus = FVID2_FRAME_STATUS_OVERFLOW;
+ }
+ }
+ tmpSubFrmStatus->subFrameNum = 0U;
+ tmpBuf->status = frmStatus;
+ tmpSubFrmStatus->numOutLines =
+ (tmpSubFrmStatus->subFrameNum + 1U) *
+ pHndlObj->subFrameCfg.notifyAfterFirstXLines[streamId];
+ if (TRUE == isEof)
+ {
+ tmpSubFrmStatus->subFrameNum = 1U;
+ tmpSubFrmStatus->numOutLines =
+ pHndlObj->calDmaVcCfg.csi2VcCfg[streamId].lines;
+ }
+
+ /* Let Applications know */
+ pHndlObj->subFrameCfg.appCb(pHndlObj->subFrameCfg.pAppCbArgs,
+ (VpsCore_Frame *) tmpBuf,
+ (Fvid2_SubFrameInfo *) tmpSubFrmStatus);
+ if (TRUE == isEof)
+ {
+ tmpSubFrmStatus->subFrameNum = 0xFFFFFFFFU;
+ }
+ BspOsal_restoreInterrupt(cookie);
+ }
+ return BSP_SOK;
+}
+
static int32_t vcoreCaptFrameDoneProc(vpscoreissCaptCalHndlObj_t *pHndlObj,
uint32_t streamId)
{
pInstObj = pHndlObj->pInstObj;
vc = pInstObj->streamIdToVcMap[streamId];
/* Update error status if any */
- if(CAL_BYS_IN_POSITION >= vc)
+ if(CAL_MAX_VIRTUAL_CHAN >= vc)
{
tmpVal = pInstObj->fifoOverFlow[vc] | pInstObj->eccCouldNotCorrect[vc]
| pInstObj->crcMisMatch[vc] | pInstObj->eccCorrected[vc];
(FVID2_BPP_BITS13 == pCalCfg->streamFmt[i].bpp) ||
(FVID2_BPP_BITS14 == pCalCfg->streamFmt[i].bpp) ||
(FVID2_BPP_BITS15 == pCalCfg->streamFmt[i].bpp) ||
- (FVID2_BPP_BITS16 == pCalCfg->streamFmt[i].bpp)
- )
+ (FVID2_BPP_BITS16 == pCalCfg->streamFmt[i].bpp))
{
pDmaVcCfg->wrDmaCfg[i].format.width =
(2U * pCalCfg->streamFmt[i].width) / 8U;
{
rtnVal = FVID2_EFAIL;
}
-
- if(TRUE == pInstObj->useDmaEndIntr)
- {
- pHndlObj->emDmaCmpltHndl[i] = Vps_iemregister(
- pInstObj->initPrms.irqNum,
- eventGroup,
- &pHndlObj->dmaCmpltEvent[i],
- 1U,
- IEM_PRIORITY4,
- vcoreCaptDmaCmpltCb,
- (Ptr) pHndlObj);
- if(NULL == pHndlObj->emDmaCmpltHndl[i])
- {
- rtnVal = FVID2_EFAIL;
- }
- }
}
}
{
retVal = Vps_iemEnable(pHndlObj->emDmaStartHndl[i]);
}
- if((TRUE == pInstObj->useDmaEndIntr) && (FVID2_SOK == retVal))
+ if((NULL != pHndlObj->emDmaCmpltHndl[i]) &&
+ (FVID2_SOK == retVal))
{
retVal = Vps_iemEnable(pHndlObj->emDmaCmpltHndl[i]);
}
+ if((TRUE == pHndlObj->isSubFrameCfgValid) &&
+ (FVID2_SOK == retVal))
+ {
+ retVal = Vps_iemEnable(pHndlObj->emSubFrmCmpltHndl);
+ }
BspOsal_restoreInterrupt(cookie);
}
}
return;
}
+static int32_t vcoreCaptCfgSubEof(
+ vpscoreissCaptCalHndlObj_t *pHndlObj,
+ const vcoreissCaptSubFrameCfg_t *pSubFrmCfg)
+{
+ UInt32 streamId, idx, xLineIntCnt, cportId;
+ int32_t retVal = FVID2_EBADARGS;
+ vpscoreissCaptInstObj_t *pInstObj = pHndlObj->pInstObj;
+
+ /* Steps
+ 1. Error Checks
+ 2. Set the CAL for Line event notification
+ 3. Register Line event and end-of-frame interrupts handlers
+ */
+ /* Step 1. Error Checks */
+ /*
+ 1. Ensure valid stream id
+ 2. Ensure x line interrupt is being enabled for only 1 vc/stream
+ */
+ if ((NULL != pSubFrmCfg->appCb) &&
+ (VPS_ISS_CAL_MAX_STREAMS > pSubFrmCfg->numStream))
+ {
+ retVal = FVID2_SOK;
+ xLineIntCnt = 0U;
+ for (idx = 0U;
+ ((idx < pSubFrmCfg->numStream) && (FVID2_SOK == retVal)); idx++)
+ {
+ streamId = pSubFrmCfg->streamId[idx];
+ if (VPS_ISS_CAL_MAX_STREAMS <= streamId)
+ {
+ retVal = FVID2_EBADARGS;
+ }
+ else if (VCORE_CAL_STREAM_MODE_CAL_WRITE !=
+ pHndlObj->streamMode[streamId])
+ {
+ retVal = FVID2_EBADARGS;
+ }
+ else
+ {
+ if (0U != pSubFrmCfg->notifyAfterFirstXLines[idx])
+ {
+ xLineIntCnt++;
+ if (pInstObj->calCfg.streamFmt[streamId].height <
+ pSubFrmCfg->notifyAfterFirstXLines[idx])
+ {
+ retVal = FVID2_EBADARGS;
+ }
+
+ if (VPS_ISS_CAL_MAX_X_LINE_MONITOR_CNT < xLineIntCnt)
+ {
+ retVal = FVID2_EBADARGS;
+ }
+ }
+ }
+ }
+ }
+ /* Step 2. Set the CAL for Line event notification */
+ if (FVID2_SOK == retVal)
+ {
+ pInstObj->lineEventCfg.numCPortId = 0U;
+ for (idx = 0U;
+ ((idx < pSubFrmCfg->numStream) && (FVID2_SOK == retVal)); idx++)
+ {
+ xLineIntCnt = pSubFrmCfg->notifyAfterFirstXLines[idx];
+ if (0U != xLineIntCnt)
+ {
+ streamId = pSubFrmCfg->streamId[idx];
+ cportId = pHndlObj->allocatedRes[streamId].cport;
+
+ pInstObj->lineEventCfg.cportId[idx] = cportId;
+ pInstObj->lineEventCfg.lineNumber[cportId] = xLineIntCnt;
+ pInstObj->lineEventCfg.numCPortId++;
+ }
+ }
+
+ retVal = VpsHal_isscalControl(
+ pInstObj->calHalHandle,
+ VPS_HAL_ISS_IOCTL_CAL_LINE_EVENT_CFG,
+ (Ptr) &pInstObj->lineEventCfg, NULL);
+ }
+ /* Step 3. Register Line event and end-of-frame interrupts handlers */
+ if (FVID2_SOK == retVal)
+ {
+ retVal = vcoreCaptRegisterSubEofIsr(pHndlObj, pSubFrmCfg);
+ if (FVID2_SOK == retVal)
+ {
+ BspUtils_memcpy((Ptr) (&pHndlObj->subFrameCfg),
+ (const void *) (pSubFrmCfg),
+ sizeof(vcoreissCaptSubFrameCfg_t));
+ }
+ }
+
+ return (retVal);
+}
+
+static int32_t vcoreCaptRegisterSubEofIsr(
+ vpscoreissCaptCalHndlObj_t *pHndlObj,
+ const vcoreissCaptSubFrameCfg_t *pSubFrmCfg)
+{
+ UInt32 streamId, idx;
+ int32_t retVal = FVID2_SOK;
+ vpscoreissCaptInstObj_t *pInstObj = NULL;
+ issemCalEvents_t lineNumEvent = IEM_CAL_EVENT_LINE_NUMBER;
+ /* Register ISR's and don't yet enable them (enable at start) */
+ pInstObj = pHndlObj->pInstObj;
+
+ for (idx = 0U;
+ ((idx < pSubFrmCfg->numStream) && (FVID2_SOK == retVal)); idx++)
+ {
+ streamId = pSubFrmCfg->streamId[idx];
+
+ if (TRUE == pSubFrmCfg->notifyAfterEndOfFrame[idx])
+ {
+ pHndlObj->emDmaCmpltHndl[streamId] = Vps_iemregister(
+ pInstObj->initPrms.irqNum,
+ IEM_EG_CAL_A,
+ &pHndlObj->dmaCmpltEvent[streamId],
+ 1U,
+ IEM_PRIORITY4,
+ vcoreCaptDmaCmpltCb,
+ (Ptr) pHndlObj);
+ if(NULL == pHndlObj->emDmaCmpltHndl[streamId])
+ {
+ retVal = FVID2_EFAIL;
+ }
+ }
+
+ /* Need not check if multiple streams are enabled for X line
+ callback, as the caller has already checked this */
+ if (0U != pSubFrmCfg->notifyAfterFirstXLines[idx])
+ {
+ pHndlObj->emSubFrmCmpltHndl = Vps_iemregister(
+ pInstObj->initPrms.irqNum,
+ IEM_EG_CAL_A,
+ &lineNumEvent,
+ 1U,
+ IEM_PRIORITY2,
+ vcoreCaptXlineCmpltCb,
+ (Ptr) pHndlObj);
+ if(NULL == pHndlObj->emSubFrmCmpltHndl)
+ {
+ retVal = FVID2_EFAIL;
+ }
+ else
+ {
+ pHndlObj->isSubFrameCfgValid = TRUE;
+ }
+ }
+
+ }
+ if (FVID2_SOK == retVal)
+ {
+ pHndlObj->subFrameCfg.appCb = pSubFrmCfg->appCb;
+ pHndlObj->subFrameCfg.pAppCbArgs = pSubFrmCfg->pAppCbArgs;
+ }
+
+ return retVal;
+}
+
static int32_t vcoreCaptRegisterErrorIsr(const vpscoreissCaptCalHndlObj_t
*pHndlObj,
const vpsissCalErrorCfg_t *pErrCfg)
*/
#define VCORE_ISS_CAPT_CAL_SET_ERR_PRMS (VCORE_ISS_CAPT_BASE_IOCTL + 3U)
+/** \brief Enable CB on reception of Nth line and end of frame
+ * vcoreissCaptSubFrameCfg_t defined in starterware_\include\vps\iss\vps_cfgcal.h
+ */
+#define VCORE_ISS_CAPT_CAL_SET_SUB_FRM_PRMS (VCORE_ISS_CAPT_BASE_IOCTL + 4U)
+
/* ========================================================================== */
/* Structure Declarations */
/* ========================================================================== */
UInt32 subModules[VPS_ISS_CAL_MAX_STREAMS];
/**< Identify the modules required for each stream.
* e.g. modulesReq[0] =
- * IRM_CAL_SUB_PPI_ID | IRM_CAL_SUB_WR_DMA_ID resources are defined
- * in vpsissCaptureSubModuleId_t
+ * VPS_ISS_CAPT_CAL_SUB_PPI_ID | VPS_ISS_CAPT_CAL_SUB_PIX_EXTRACT_ID
+ * resources are defined in vpsissCaptureSubModuleId_t
* Only 2 modules required, 1 to decode CSI2 and write received data */
uint32_t isCmplxIoCfgValid[CSL_CAL_CMPLXIO_CNT];
/**< Specify if the complex IO configurations should be applied or the
/**< Not used as of now */
} vcoreissCaptOpenRetParams_t;
+/**
+ * struct vcoreissCaptSubFrameCfg
+ * \brief CAL could be configured to notify application on end of frame or on
+ * reception of first X lines.
+ *
+ * Limitation on first x lines callback : Currently this can be enabled for
+ * one stream and stream should be of type VPS_ISS_CAL_TAG_PIX_DATA
+ *
+ */
+typedef struct vcoreissCaptSubFrameCfg
+{
+ uint32_t numStream;
+ /**< Number of streams, which requires to be monitored for end of frame,
+ and or first X lines */
+ uint32_t streamId[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Specify the stream ID, which requires to be monitored */
+ uint32_t notifyAfterFirstXLines[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Will call the application provided callback, after reception of
+ number of lines specified here.
+ Restriction :
+ This can be supported for only VPS_ISS_CAL_MAX_X_LINE_MONITOR_CNT
+ virtual channel */
+ uint32_t notifyAfterEndOfFrame[VPS_ISS_CAL_MAX_STREAMS];
+ /**< Will call the application provided callback, after reception of
+ End Of Frame short packet */
+ VpsCore_SubFrameCbFxn appCb;
+ /**< Application callback */
+ Ptr pAppCbArgs;
+ /**< Argument that would be passed when appCb is called. */
+ Ptr pAdditionalArgs;
+ /**< Not used for now - should be set to NULL */
+} vcoreissCaptSubFrameCfg_t;
+
/* ========================================================================== */
/* Function Declarations */
/* ========================================================================== */