419 lines
18 KiB
C
419 lines
18 KiB
C
|
|
/***********************************************************************************************************************
|
||
|
|
* FILE DESCRIPTION
|
||
|
|
* ------------------------------------------------------------------------------------------------------------------*/
|
||
|
|
/** \file
|
||
|
|
* \brief RAM driver functions
|
||
|
|
*
|
||
|
|
* --------------------------------------------------------------------------------------------------------------------
|
||
|
|
* COPYRIGHT
|
||
|
|
* --------------------------------------------------------------------------------------------------------------------
|
||
|
|
* \par Copyright
|
||
|
|
* \verbatim
|
||
|
|
* Copyright (c) 2022 by Vector Informatik GmbH. All rights reserved.
|
||
|
|
*
|
||
|
|
* This software is copyright protected and proprietary to Vector Informatik GmbH.
|
||
|
|
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
|
||
|
|
* All other rights remain with Vector Informatik GmbH.
|
||
|
|
* \endverbatim
|
||
|
|
*/
|
||
|
|
/**********************************************************************************************************************/
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* REVISION HISTORY
|
||
|
|
* --------------------------------------------------------------------------------------------------------------------
|
||
|
|
* Version Date Author Change Id Description
|
||
|
|
* --------------------------------------------------------------------------------------------------------------------
|
||
|
|
* 01.00.00 2013-10-23 visjhg - Initial release
|
||
|
|
* 01.01.00 2015-11-27 visase ESCAN00086297 Allow to override the RAM buffer base address via configuration
|
||
|
|
* 01.02.00 2016-06-17 visci ESCAN00090364 Added support for flashCode use case
|
||
|
|
* 01.02.01 2018-03-22 visdkl ESCAN00098872 No changes
|
||
|
|
* 01.02.02 2021-03-08 vishor ESCAN00108134 Added/adapted MemMap sections
|
||
|
|
* 01.03.00 2022-03-17 visstn FBL-4366 Perform MISRA 2012 migration
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
#define FBL_RAMIO_SOURCE
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* INCLUDES
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
#include "fbl_ramio_inc.h"
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* VERSION
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
#if ( FBLWRAPPERFLASH_XRAMHIS_VERSION != 0x0103u ) || \
|
||
|
|
( FBLWRAPPERFLASH_XRAMHIS_RELEASE_VERSION != 0x00u )
|
||
|
|
# error "Error in FBL_RAMIO.C: Source and header file are inconsistent!"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* CONFIGURATION CHECKS
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
/* Check if buffer size is correctly defined */
|
||
|
|
#if defined( RAM_DRV_BUFFER_SIZE ) && ( RAM_DRV_BUFFER_SIZE > 0u )
|
||
|
|
#else
|
||
|
|
# error "Error in FBL_RAMIO.C: Missing or wrong configuration of RAM_DRV_BUFFER_SIZE."
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* Check if segment size and buffer size match each other */
|
||
|
|
#if defined( RAM_DRV_SEGMENT_SIZE )
|
||
|
|
# if ( RAM_DRV_SEGMENT_SIZE > 1u )
|
||
|
|
# if ( 0u != (RAM_DRV_BUFFER_SIZE & (RAM_DRV_SEGMENT_SIZE - 1u)) )
|
||
|
|
# error "Error in FBL_RAMIO.C: Inconsistent configuration of RAM_DRV_SEGMENT_SIZE and RAM_DRV_BUFFER_SIZE."
|
||
|
|
# endif
|
||
|
|
# endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* Check if segment size has reasonable / supported value */
|
||
|
|
#if defined( RAM_DRV_SEGMENT_SIZE )
|
||
|
|
# if ( RAM_DRV_SEGMENT_SIZE == 1u ) || ( RAM_DRV_SEGMENT_SIZE == 2u ) || ( RAM_DRV_SEGMENT_SIZE == 4u )
|
||
|
|
# else
|
||
|
|
# error "Error in FBL_RAMIO.C: Wrong configuration of RAM_DRV_SEGMENT_SIZE."
|
||
|
|
# endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined( RAM_DRV_SEGMENT_SIZE ) && \
|
||
|
|
defined( RAM_DRV_BASE_ADDRESS_OVERRIDE )
|
||
|
|
/* Check alignment of base address */
|
||
|
|
# if ( 0u != (RAM_DRV_BASE_ADDRESS_OVERRIDE & (RAM_DRV_SEGMENT_SIZE - 1u)) )
|
||
|
|
# error "Error in FBL_RAMIO.C: Inconsistent configuration of RAM_DRV_SEGMENT_SIZE and RAM_DRV_BASE_ADDRESS_OVERRIDE."
|
||
|
|
# endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined( RAM_DRV_POLLING_INTERVAL )
|
||
|
|
# if ( 0u == RAM_DRV_POLLING_INTERVAL ) || \
|
||
|
|
( 0u != (RAM_DRV_POLLING_INTERVAL & (RAM_DRV_POLLING_INTERVAL - 1u)) )
|
||
|
|
# error "Error in FBL_RAMIO.C: Wrong configuration of RAM_DRV_POLLING_INTERVAL (shall be 2^n)."
|
||
|
|
# endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* DEFINES
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
#if defined( RAM_DRV_EXT_BUFFER )
|
||
|
|
# define RAM_DRV_BUFFER RAM_DRV_EXT_BUFFER
|
||
|
|
#else
|
||
|
|
# define RAM_DRV_BUFFER g_RamData
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined( RAM_DRV_BASE_ADDRESS_OVERRIDE )
|
||
|
|
/** Allow to override the base address via fbl_ramio_cfg.h, e.g. if RAM_DRV_BUFFER shall be located at an arbitrary address */
|
||
|
|
# define RAM_DRV_BASE_ADDRESS RAM_DRV_BASE_ADDRESS_OVERRIDE
|
||
|
|
#else
|
||
|
|
/** Base address of accessible RAM area */
|
||
|
|
# define RAM_DRV_BASE_ADDRESS ((IO_PositionType)RAM_DRV_BUFFER)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* GLOBAL DATA
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
#if defined( RAM_DRV_EXT_BUFFER )
|
||
|
|
#else
|
||
|
|
# define FBLRAMIO_START_SEC_VAR
|
||
|
|
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
|
||
|
|
|
||
|
|
/** Global data buffer that can be accessed via RamDriver interface */
|
||
|
|
V_MEMRAM0 static V_MEMRAM1 IO_U8 V_MEMRAM2 g_RamData[RAM_DRV_BUFFER_SIZE];
|
||
|
|
|
||
|
|
# define FBLRAMIO_STOP_SEC_VAR
|
||
|
|
# include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
|
||
|
|
#endif /* RAM_DRV_EXT_BUFFER */
|
||
|
|
|
||
|
|
#define FBLRAMIO_START_SEC_CODE
|
||
|
|
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* LOCAL FUNCTION PROTOTYPES
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
static IO_ErrorType V_API_NEAR RamDriver_GetOffset( IO_SizeType length, IO_PositionType address,
|
||
|
|
V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * pOffset );
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* LOCAL FUNCTIONS
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* RamDriver_GetOffset
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/*! \brief Get the local buffer offset
|
||
|
|
* \param[in] length The number of bytes to be modified
|
||
|
|
* \param[in] address The start address
|
||
|
|
* \param[out] offset The returned offset
|
||
|
|
* \return IO_E_OK if succeeded, IO_E_NOT_OK otherwise
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
static IO_ErrorType V_API_NEAR RamDriver_GetOffset( IO_SizeType length, IO_PositionType address,
|
||
|
|
V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * pOffset )
|
||
|
|
{
|
||
|
|
IO_ErrorType result;
|
||
|
|
IO_SizeType offset;
|
||
|
|
|
||
|
|
result = IO_E_NOT_OK;
|
||
|
|
|
||
|
|
/* Avoid compiler warning (comparison against 0 always true) */
|
||
|
|
#if defined( RAM_DRV_BASE_ADDRESS_OVERRIDE )
|
||
|
|
# if ( 0u != RAM_DRV_BASE_ADDRESS )
|
||
|
|
if (address >= RAM_DRV_BASE_ADDRESS) /* PRQA S 0306 */ /* MD_FblRamio_0306 */
|
||
|
|
# endif
|
||
|
|
#endif
|
||
|
|
{
|
||
|
|
offset = address - RAM_DRV_BASE_ADDRESS; /* PRQA S 0306 */ /* MD_FblRamio_0306 */
|
||
|
|
|
||
|
|
if ( (length <= RAM_DRV_BUFFER_SIZE)
|
||
|
|
&& (offset <= (RAM_DRV_BUFFER_SIZE - length)) )
|
||
|
|
{
|
||
|
|
*pOffset = offset;
|
||
|
|
result = IO_E_OK;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* GLOBAL FUNCTIONS
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* RamDriver_InitSync
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/*! \brief Initialize the RAM algorithm
|
||
|
|
* \param[in] address Unused parameter for HIS interface compliance
|
||
|
|
* \return The return code shows the success of the initialization
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */
|
||
|
|
IO_ErrorType V_API_NEAR RamDriver_InitSync( void * address )
|
||
|
|
{
|
||
|
|
IO_ErrorType result;
|
||
|
|
#if defined( RAM_DRV_ENABLE_MEM_INIT )
|
||
|
|
IO_U32 i;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined( V_ENABLE_USE_DUMMY_STATEMENT )
|
||
|
|
(void)address;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
result = IO_E_OK;
|
||
|
|
|
||
|
|
#if defined( RAM_DRV_BASE_ADDRESS_OVERRIDE )
|
||
|
|
/* Alignment check executed by preprocessor (see configuration checks section) */
|
||
|
|
#else
|
||
|
|
/* PRQA S 2992, 2996, 0306 1 */ /* MD_FblRamio_2992_2996, MD_FblRamio_2992_2996, MD_FblRamio_0306 */
|
||
|
|
if (0u != (RAM_DRV_BASE_ADDRESS & (RAM_DRV_SEGMENT_SIZE - 1u)))
|
||
|
|
{
|
||
|
|
/* RAM buffer is not aligned with configured segment size */
|
||
|
|
result = IO_E_NOT_OK;
|
||
|
|
}
|
||
|
|
#endif /* RAM_DRV_BASE_ADDRESS_OVERRIDE */
|
||
|
|
|
||
|
|
#if defined( RAM_DRV_ENABLE_MEM_INIT )
|
||
|
|
if (IO_E_OK == result) /* PRQA S 2991, 2995 */ /* MD_FblRamio_2991_2995 */
|
||
|
|
{
|
||
|
|
for (i = 0u; i < (RAM_DRV_BUFFER_SIZE / RAM_DRV_SEGMENT_SIZE); i++)
|
||
|
|
{
|
||
|
|
# if ( RAM_DRV_SEGMENT_SIZE == 1u )
|
||
|
|
((IO_U8 *)RAM_DRV_BUFFER)[i] = 0u;
|
||
|
|
# elif ( RAM_DRV_SEGMENT_SIZE == 2u )
|
||
|
|
((IO_U16 *)RAM_DRV_BUFFER)[i] = 0u; /* PRQA S 0310, 3305 */ /* MD_FblRamio_0310_3305 */
|
||
|
|
# elif ( RAM_DRV_SEGMENT_SIZE == 4u )
|
||
|
|
((IO_U32 *)RAM_DRV_BUFFER)[i] = 0u; /* PRQA S 0310, 3305 */ /* MD_FblRamio_0310_3305 */
|
||
|
|
# endif
|
||
|
|
|
||
|
|
# if defined( RAM_DRV_POLLING_INTERVAL )
|
||
|
|
/* PRQA S 2985, 2991, 2995 1 */ /* MD_FblRamio_2985, MD_FblRamio_2991_2995, MD_FblRamio_2991_2995 */
|
||
|
|
if (0u == (i & (RAM_DRV_POLLING_INTERVAL - 1u)))
|
||
|
|
{
|
||
|
|
RAM_DRV_POLLING_FUNCTION();
|
||
|
|
}
|
||
|
|
# endif /* RAM_DRV_POLLING_INTERVAL */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif /* RAM_DRV_ENABLE_MEM_INIT */
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* RamDriver_DeinitSync
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/*! \brief Deinitialize the RAM algorithm
|
||
|
|
* \param[in] address Unused parameter for HIS interface compliance
|
||
|
|
* \return The return code shows the success of the deinitialization
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
IO_ErrorType V_API_NEAR RamDriver_DeinitSync( void * address )
|
||
|
|
{
|
||
|
|
IO_ErrorType result;
|
||
|
|
|
||
|
|
/* Clean-up memory */
|
||
|
|
result = RamDriver_InitSync(address);
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* RamDriver_RWriteSync
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/*! \brief Program RAM memory
|
||
|
|
* \param[in] writeBuffer Write data buffer
|
||
|
|
* \param[in] writeLength Number of bytes to be written
|
||
|
|
* \param[in] writeAddress The write address
|
||
|
|
* \return Status of RAM programming
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */
|
||
|
|
IO_ErrorType V_API_NEAR RamDriver_RWriteSync( IO_MemPtrType writeBuffer, IO_SizeType writeLength, IO_PositionType writeAddress )
|
||
|
|
{
|
||
|
|
IO_ErrorType result;
|
||
|
|
IO_SizeType offset;
|
||
|
|
IO_SizeType i;
|
||
|
|
|
||
|
|
result = RamDriver_GetOffset(writeLength, writeAddress, &offset);
|
||
|
|
|
||
|
|
if (IO_E_OK == result)
|
||
|
|
{
|
||
|
|
for (i = 0u; i < writeLength; i++)
|
||
|
|
{
|
||
|
|
#if defined( RAM_DRV_POLLING_INTERVAL )
|
||
|
|
/* PRQA S 2985, 2991, 2995 1 */ /* MD_FblRamio_2985, MD_FblRamio_2991_2995, MD_FblRamio_2991_2995 */
|
||
|
|
if (0u == (i & (RAM_DRV_POLLING_INTERVAL - 1u)))
|
||
|
|
{
|
||
|
|
RAM_DRV_POLLING_FUNCTION();
|
||
|
|
}
|
||
|
|
#endif /* RAM_DRV_POLLING_INTERVAL */
|
||
|
|
|
||
|
|
RAM_DRV_BUFFER[offset] = writeBuffer[i];
|
||
|
|
offset++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* RamDriver_REraseSync
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/*! \brief Erase RAM memory
|
||
|
|
* \pre RAM driver has to be initialized
|
||
|
|
* \param[in] eraseLength Number of bytes to be erased
|
||
|
|
* \param[in] eraseAddress The erase address
|
||
|
|
* \return Status of RAM erase
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
IO_ErrorType V_API_NEAR RamDriver_REraseSync( IO_SizeType eraseLength, IO_PositionType eraseAddress )
|
||
|
|
{
|
||
|
|
#if defined( RAM_DRV_DELETED )
|
||
|
|
IO_ErrorType result;
|
||
|
|
IO_SizeType offset;
|
||
|
|
IO_SizeType i;
|
||
|
|
|
||
|
|
result = RamDriver_GetOffset(eraseLength, eraseAddress, &offset);
|
||
|
|
|
||
|
|
if (IO_E_OK == result)
|
||
|
|
{
|
||
|
|
for (i = 0u; i < eraseLength; i++)
|
||
|
|
{
|
||
|
|
# if defined( RAM_DRV_POLLING_INTERVAL )
|
||
|
|
/* PRQA S 2985, 2991, 2995 1 */ /* MD_FblRamio_2985, MD_FblRamio_2991_2995, MD_FblRamio_2991_2995 */
|
||
|
|
if (0u == (i & (RAM_DRV_POLLING_INTERVAL - 1u)))
|
||
|
|
{
|
||
|
|
RAM_DRV_POLLING_FUNCTION();
|
||
|
|
}
|
||
|
|
# endif /* RAM_DRV_POLLING_INTERVAL */
|
||
|
|
|
||
|
|
RAM_DRV_BUFFER[offset] = RAM_DRV_DELETED;
|
||
|
|
offset++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
#else /* ! RAM_DRV_DELETED */
|
||
|
|
# if defined( V_ENABLE_USE_DUMMY_STATEMENT )
|
||
|
|
(void)eraseLength;
|
||
|
|
(void)eraseAddress;
|
||
|
|
# endif /* V_ENABLE_USE_DUMMY_STATEMENT */
|
||
|
|
|
||
|
|
return IO_E_OK;
|
||
|
|
#endif /* ! RAM_DRV_DELETED */
|
||
|
|
}
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* RamDriver_RReadSync
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
/*! \brief Read RAM memory
|
||
|
|
* \pre RAM driver has to be initialized
|
||
|
|
* \param[out] readBuffer Read data buffer
|
||
|
|
* \param[in] readLength Number of bytes to be read
|
||
|
|
* \param[in] readAddress The read address
|
||
|
|
* \return Status of RAM read
|
||
|
|
**********************************************************************************************************************/
|
||
|
|
IO_ErrorType V_API_NEAR RamDriver_RReadSync( IO_MemPtrType readBuffer, IO_SizeType readLength, IO_PositionType readAddress )
|
||
|
|
{
|
||
|
|
IO_ErrorType result;
|
||
|
|
IO_SizeType offset;
|
||
|
|
IO_SizeType i;
|
||
|
|
|
||
|
|
result = RamDriver_GetOffset(readLength, readAddress, &offset);
|
||
|
|
|
||
|
|
if (IO_E_OK == result)
|
||
|
|
{
|
||
|
|
for (i = 0u; i < readLength; i++)
|
||
|
|
{
|
||
|
|
#if defined( RAM_DRV_POLLING_INTERVAL )
|
||
|
|
/* PRQA S 2985, 2991, 2995 1 */ /* MD_FblRamio_2985, MD_FblRamio_2991_2995, MD_FblRamio_2991_2995 */
|
||
|
|
if (0u == (i & (RAM_DRV_POLLING_INTERVAL - 1u)))
|
||
|
|
{
|
||
|
|
RAM_DRV_POLLING_FUNCTION();
|
||
|
|
}
|
||
|
|
#endif /* RAM_DRV_POLLING_INTERVAL */
|
||
|
|
|
||
|
|
readBuffer[i] = RAM_DRV_BUFFER[offset];
|
||
|
|
offset++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
#define FBLRAMIO_STOP_SEC_CODE
|
||
|
|
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
|
||
|
|
|
||
|
|
/* Module specific MISRA deviations:
|
||
|
|
|
||
|
|
MD_FblRamio_0306:
|
||
|
|
Reason: Address conversion between integer values and pointers is required to allow for hardware independent
|
||
|
|
configuration and address range checks.
|
||
|
|
Risk: The size of integer required to hold the result of a pointer cast is implementation defined.
|
||
|
|
Prevention: The size of the respective integer data type which holds the address value is adapted on a hardware
|
||
|
|
specific basis.
|
||
|
|
|
||
|
|
MD_FblRamio_0310_3305:
|
||
|
|
Reason: Pointer is casted as different memory access sizes are utilized due to performance reasons.
|
||
|
|
Risk: Wrong pointer access is performed.
|
||
|
|
Prevention: Code inspection and test of the different variants in the component test.
|
||
|
|
|
||
|
|
MD_FblRamio_2985:
|
||
|
|
Reason: Depending on configuration, RAM_DRV_POLLING_INTERVAL might be zero and thus
|
||
|
|
i & (RAM_DRV_POLLING_INTERVAL - 1u) might be redundant.
|
||
|
|
Risk: No identifiable risk.
|
||
|
|
Prevention: No prevention required.
|
||
|
|
|
||
|
|
MD_FblRamio_2991_2995:
|
||
|
|
Reason: Depending on configuration, the controlling expression might always be true. This code structure maintains
|
||
|
|
readbillity.
|
||
|
|
Risk: No identifiable risk.
|
||
|
|
Prevention: No prevention required.
|
||
|
|
|
||
|
|
MD_FblRamio_2992_2996:
|
||
|
|
Reason: Depending on configuration, the controlling expression might always be false. This code structure
|
||
|
|
maintains readbillity.
|
||
|
|
Risk: No identifiable risk.
|
||
|
|
Prevention: No prevention required.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
/***********************************************************************************************************************
|
||
|
|
* END OF FILE: FBL_RAMIO.C
|
||
|
|
**********************************************************************************************************************/
|