[k32w] use a custom Persistent Data Manager (#5496)

This commit add support for a custom PDM (Persistent Data Manager)
which is also used inside Project CHIP.

Signed-off-by: Doru Gucea <[email protected]>
This commit is contained in:
doru91
2020-09-07 21:56:45 -07:00
committed by GitHub
parent f5508ad5dd
commit 2c5d22f0b7
56 changed files with 17887 additions and 537 deletions
+13 -13
View File
@@ -81,19 +81,19 @@ CONFIG_FILE = OPENTHREAD_PROJECT_CORE_CONFIG_FILE='\"openthread-core-jn5189
CONFIG_FILE_PATH = $(AbsTopSourceDir)/examples/platforms/k32w/jn5189/
SIGN_IMAGE_PATH = $(AbsTopSourceDir)/third_party/nxp/JN5189DK6/tools/imagetool/
COMMONCFLAGS := \
-fdata-sections \
-ffunction-sections \
-Os \
-g \
-DCPU_JN518X \
-DCPU_JN518X_REV=2 \
-DJENNIC_CHIP_FAMILY_JN518x \
-DJENNIC_CHIP_FAMILY_NAME=_JN518x \
-DSDK_DEBUGCONSOLE=0 \
-D$(CONFIG_FILE) \
-DUSE_RTOS=0 \
-I$(CONFIG_FILE_PATH) \
COMMONCFLAGS :=\
-fdata-sections \
-ffunction-sections \
-Os \
-g \
-DCPU_JN518X \
-DCPU_JN518X_REV=2 \
-DJENNIC_CHIP_FAMILY_JN518x \
-DJENNIC_CHIP_FAMILY_NAME=_JN518x \
-DSDK_DEBUGCONSOLE=0 \
-D$(CONFIG_FILE) \
-imacros "$(AbsTopSourceDir)/examples/platforms/k32w/jn5189/jn5189-sdk-config.h" \
-I$(CONFIG_FILE_PATH) \
$(NULL)
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/common-switches.mk
+13 -13
View File
@@ -83,19 +83,19 @@ CONFIG_FILE = OPENTHREAD_PROJECT_CORE_CONFIG_FILE='\"openthread-core-k32w06
CONFIG_FILE_PATH = $(AbsTopSourceDir)/examples/platforms/k32w/k32w061/
SIGN_IMAGE_PATH = $(AbsTopSourceDir)/third_party/nxp/K32W061DK6/tools/imagetool/
COMMONCFLAGS := \
-fdata-sections \
-ffunction-sections \
-Os \
-g \
-DCPU_K32W061HN \
-DCPU_JN518X \
-DCPU_JN518X_REV=2 \
-DJENNIC_CHIP_FAMILY_JN518x \
-DJENNIC_CHIP_FAMILY_NAME=_JN518x \
-DSDK_DEBUGCONSOLE=0 \
-D$(CONFIG_FILE) \
-DUSE_RTOS=0 \
COMMONCFLAGS := \
-fdata-sections \
-ffunction-sections \
-Os \
-g \
-DCPU_K32W061HN \
-DCPU_JN518X \
-DCPU_JN518X_REV=2 \
-DJENNIC_CHIP_FAMILY_JN518x \
-DJENNIC_CHIP_FAMILY_NAME=_JN518x \
-DSDK_DEBUGCONSOLE=0 \
-D$(CONFIG_FILE) \
-imacros "$(AbsTopSourceDir)/examples/platforms/k32w/k32w061/k32w061-sdk-config.h" \
-I$(CONFIG_FILE_PATH) \
$(NULL)
+15 -1
View File
@@ -66,13 +66,22 @@ LIB_FLAGS
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/XCVR/DK6/Build/Include \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/XCVR/DK6 \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/Common \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/ \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Interface/ \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Interface \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/SerialManager/Source \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/TimersManager/Source \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Include \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface \
-I$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal \
-Wno-unknown-pragmas \
-Wno-sign-compare \
-Wno-unused-function \
-Wno-unused-parameter \
-Wno-empty-body \
-Wno-missing-field-initializers \
-Wno-clobbered \
-fno-strict-aliasing \
$(NULL)
@@ -87,7 +96,6 @@ libopenthread_jn5189_plat_a_CPPFLAGS
PLATFORM_SOURCES = \
src/alarm.c \
src/diag.c \
src/flash.c \
src/logging.c \
src/misc.c \
src/radio.c \
@@ -123,6 +131,12 @@ libopenthread_jn5189_sdk_a_SOURCES
@top_builddir@/third_party/nxp/JN5189DK6/devices/JN5189/utilities/debug_console/fsl_debug_console.c \
@top_builddir@/third_party/nxp/JN5189DK6/devices/JN5189/utilities/str/fsl_str.c \
@top_builddir@/third_party/nxp/JN5189DK6/middleware/wireless/framework/Common/MicroInt_arm_sdk2.c \
@top_builddir@/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c \
@top_builddir@/third_party/nxp/JN5189DK6/middleware/wireless/framework/Reset/Reset.c \
@top_builddir@/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Source/MemManager.c \
@top_builddir@/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/pdm_port.c \
@top_builddir@/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.c \
@top_builddir@/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c \
$(NULL)
libopenthread_jn5189_plat_a_SOURCES = \
@@ -35,6 +35,7 @@ LDADD_COMMON
$(top_builddir)/examples/platforms/k32w/libopenthread-jn5189_sdk.a \
$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/ieee-802.15.4/lib/libMiniMac.a \
$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/XCVR/lib/libRadio.a \
$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Library/libPDM.a \
$(NULL)
LDFLAGS_COMMON += \
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JN5189_SDK_CONFIG_H
#define JN5189_SDK_CONFIG_H
#ifndef gUsePdm_d
#define gUsePdm_d 1
#endif
#ifndef gPdmMemPoolId_c
#define gPdmMemPoolId_c 0
#endif
#ifndef gPdmNbSegments
#define gPdmNbSegments 63 /* number of sectors contained in PDM storage */
#endif
#ifndef USE_RTOS
#define USE_RTOS 0
#endif
#ifndef PoolsDetails_c
#define PoolsDetails_c \
_block_size_ 512 _number_of_blocks_ 2 _pool_id_(0) _eol_ _block_size_ 768 _number_of_blocks_ 1 _pool_id_(0) _eol_
#endif
#endif // JN5189_SDK_CONFIG_H
+6 -6
View File
@@ -69,10 +69,10 @@ m_fsl_prodInfo_size = m_sector_size;
m_fsl_prodInfo_end = m_flash_size - 17 * m_sector_size - 1;
m_fsl_prodInfo_start = m_fsl_prodInfo_end - m_fsl_prodInfo_size + 1;
NV_STORAGE_MAX_SECTORS = 64;
NV_STORAGE_MAX_SECTORS = 63;
NV_STORAGE_SIZE = NV_STORAGE_MAX_SECTORS * m_sector_size;
NV_STORAGE_END_ADDRESS = m_fsl_prodInfo_start - 1;
NV_STORAGE_START_ADDRESS = NV_STORAGE_END_ADDRESS - NV_STORAGE_SIZE + 1;
NV_STORAGE_START_ADDRESS = m_flash_size - 17 * m_sector_size - 1;
NV_STORAGE_END_ADDRESS = NV_STORAGE_START_ADDRESS - NV_STORAGE_SIZE + 1;
INT_STORAGE_END = NV_STORAGE_START_ADDRESS - 1;
INT_STORAGE_START = 0x48000;
@@ -288,8 +288,8 @@ SECTIONS
_end_boot_resume_stack = .;
} > RAM0
__nv_storage_end_address = NV_STORAGE_END_ADDRESS;
__nv_storage_start_address = NV_STORAGE_START_ADDRESS;
__nv_storage_end_address = NV_STORAGE_START_ADDRESS;
__nv_storage_start_address = NV_STORAGE_END_ADDRESS;
PROVIDE(_vStackTop = __top_RAM0 - 32);
PROVIDE(__mac_buffer_base = (__mac_buffer_start & 0xfffe0000));
@@ -301,4 +301,4 @@ SECTIONS
__StackLimit = _vStackTop - STACK_SIZE;
ASSERT(__StackLimit >= _end_boot_resume_stack, "Possible stack corruption with data/bss/boot_stack")
}
}
@@ -115,7 +115,7 @@
* Define to 1 if you want to use JN589 Flash implementation.
*
*/
#define OPENTHREAD_SETTINGS_RAM 1
#define OPENTHREAD_SETTINGS_RAM 0
/**
* @def OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE
+15 -1
View File
@@ -67,14 +67,23 @@ LIB_FLAGS
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/XCVR/DK6/Build/Include \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/XCVR/DK6 \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/Common/ \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/ \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Interface/ \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Interface \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/SerialManager/Source \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/TimersManager/Source \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Include \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal \
-I$(top_srcdir)/third_party/nxp/K32W061DK6/boards/k32w061dk6/wireless_examples/openthread/enablement \
-Wno-unknown-pragmas \
-Wno-sign-compare \
-Wno-unused-function \
-Wno-unused-parameter \
-Wno-empty-body \
-Wno-missing-field-initializers \
-Wno-clobbered \
-fno-strict-aliasing \
$(NULL)
@@ -89,7 +98,6 @@ libopenthread_k32w061_plat_a_CPPFLAGS
PLATFORM_SOURCES = \
src/alarm.c \
src/diag.c \
src/flash.c \
src/logging.c \
src/misc.c \
src/radio.c \
@@ -125,6 +133,12 @@ libopenthread_k32w061_sdk_a_SOURCES
@top_builddir@/third_party/nxp/K32W061DK6/devices/K32W061/utilities/debug_console/fsl_debug_console.c \
@top_builddir@/third_party/nxp/K32W061DK6/devices/K32W061/utilities/str/fsl_str.c \
@top_builddir@/third_party/nxp/K32W061DK6/middleware/wireless/framework/Common/MicroInt_arm_sdk2.c \
@top_builddir@/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c \
@top_builddir@/third_party/nxp/K32W061DK6/middleware/wireless/framework/Reset/Reset.c \
@top_builddir@/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Source/MemManager.c \
@top_builddir@/third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/pdm_port.c \
@top_builddir@/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.c \
@top_builddir@/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c \
$(NULL)
libopenthread_k32w061_plat_a_SOURCES = \
@@ -36,6 +36,7 @@ LDADD_COMMON
$(top_builddir)/examples/platforms/k32w/libopenthread-k32w061_sdk.a \
$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/ieee-802.15.4/lib/libMiniMac.a \
$(top_srcdir)/third_party/nxp/K32W061DK6/middleware/wireless/framework/XCVR/lib/libRadio.a \
$(top_srcdir)/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Library/libPDM.a \
$(NULL)
LDFLAGS_COMMON += \
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef K32W061_SDK_CONFIG_H
#define K32W061_SDK_CONFIG_H
#ifndef gUsePdm_d
#define gUsePdm_d 1
#endif
#ifndef gPdmMemPoolId_c
#define gPdmMemPoolId_c 0
#endif
#ifndef gPdmNbSegments
#define gPdmNbSegments 63 /* number of sectors contained in PDM storage */
#endif
#ifndef USE_RTOS
#define USE_RTOS 0
#endif
#ifndef PoolsDetails_c
#define PoolsDetails_c \
_block_size_ 512 _number_of_blocks_ 2 _pool_id_(0) _eol_ _block_size_ 768 _number_of_blocks_ 1 _pool_id_(0) _eol_
#endif
#endif // K32W061_SDK_CONFIG_H
+5 -5
View File
@@ -69,10 +69,10 @@ m_fsl_prodInfo_size = m_sector_size;
m_fsl_prodInfo_end = m_flash_size - 17 * m_sector_size - 1;
m_fsl_prodInfo_start = m_fsl_prodInfo_end - m_fsl_prodInfo_size + 1;
NV_STORAGE_MAX_SECTORS = 64;
NV_STORAGE_MAX_SECTORS = 63;
NV_STORAGE_SIZE = NV_STORAGE_MAX_SECTORS * m_sector_size;
NV_STORAGE_END_ADDRESS = m_fsl_prodInfo_start - 1;
NV_STORAGE_START_ADDRESS = NV_STORAGE_END_ADDRESS - NV_STORAGE_SIZE + 1;
NV_STORAGE_START_ADDRESS = m_flash_size - 17 * m_sector_size - 1;
NV_STORAGE_END_ADDRESS = NV_STORAGE_START_ADDRESS - NV_STORAGE_SIZE + 1;
INT_STORAGE_END = NV_STORAGE_START_ADDRESS - 1;
INT_STORAGE_START = 0x48000;
@@ -288,8 +288,8 @@ SECTIONS
_end_boot_resume_stack = .;
} > RAM0
__nv_storage_end_address = NV_STORAGE_END_ADDRESS;
__nv_storage_start_address = NV_STORAGE_START_ADDRESS;
__nv_storage_end_address = NV_STORAGE_START_ADDRESS;
__nv_storage_start_address = NV_STORAGE_END_ADDRESS;
PROVIDE(_vStackTop = __top_RAM0 - 32);
PROVIDE(__mac_buffer_base = (__mac_buffer_start & 0xfffe0000));
@@ -115,7 +115,7 @@
* Define to 1 if you want to use K32W061 Flash implementation.
*
*/
#define OPENTHREAD_SETTINGS_RAM 1
#define OPENTHREAD_SETTINGS_RAM 0
/**
* @def OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE
+82 -495
View File
@@ -37,353 +37,67 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <openthread-core-config.h>
#include <openthread/instance.h>
#include <openthread/platform/settings.h>
#include <string.h>
#include "utils/code_utils.h"
#include "openthread/platform/flash.h"
#include "EmbeddedTypes.h"
#include "PDM.h"
#define OT_FLASH_BLOCK_ADD_BEGIN_FLAG (1 << 0)
#define OT_FLASH_BLOCK_ADD_COMPLETE_FLAG (1 << 1)
#define OT_FLASH_BLOCK_DELETE_FLAG (1 << 2)
#define OT_FLASH_BLOCK_INDEX_0_FLAG (1 << 3)
/* Compact flag is used to indicate that the next settings block follows at the next 16 bytes
* aligned address after the data portion of the current one. Otherwise the next block will be
* placed in the next flash page */
#define OT_FLASH_BLOCK_COMPACT_FLAG (1 << 4)
#define pdmBufferSize 512
#define NVM_START_ID 0x4F00
#define OT_SETTINGS_FLAG_SIZE 16
#define OT_SETTINGS_BLOCK_DATA_SIZE 256
/* WARNING - the defines below must be in sync with OT NVM datasets from Settings.hpp */
#define NVM_MAX_ID 7
/* K32W erases the flash to value 0x00 */
#define FLASH_ERASE_VALUE 0x00
#define FLASH_ALIGN_SIZE 16
#define FLASH_BLOCK_PAD1_SIZE 10
#define FLASH_BLOCK_PAD2_SIZE 15
static uint8_t sPdmBuffer[pdmBufferSize] __attribute__((aligned(4))) = {0};
#define OT_SETTINGS_IN_USE 0xbe5cc5ee
extern otError utilsFlashErasePage(uint32_t aAddress);
/* Added padding to make settings block structure align to minimum flash write size of 16 bytes.
* The delFlag field has an offset of 16 bytes from the beginning of the structure to allow a new
* write on the field. */
OT_TOOL_PACKED_BEGIN
struct settingsBlock
{
uint16_t key;
uint16_t flag;
uint16_t length;
uint8_t padding1[FLASH_BLOCK_PAD1_SIZE];
uint8_t delFlag;
uint8_t padding2[FLASH_BLOCK_PAD2_SIZE];
} OT_TOOL_PACKED_END;
/**
* @def SETTINGS_CONFIG_BASE_ADDRESS
*
* The base address of settings.
*
*/
#ifndef SETTINGS_CONFIG_BASE_ADDRESS
#define SETTINGS_CONFIG_BASE_ADDRESS 0
#endif // SETTINGS_CONFIG_BASE_ADDRESS
/**
* @def SETTINGS_CONFIG_PAGE_SIZE
*
* The page size of settings.
*
*/
#ifndef SETTINGS_CONFIG_PAGE_SIZE
#define SETTINGS_CONFIG_PAGE_SIZE 0x800
#endif // SETTINGS_CONFIG_PAGE_SIZE
/**
* @def SETTINGS_CONFIG_PAGE_NUM
*
* The page number of settings.
*
*/
#ifndef SETTINGS_CONFIG_PAGE_NUM
#define SETTINGS_CONFIG_PAGE_NUM 2
#endif // SETTINGS_CONFIG_PAGE_NUM
#if (SETTINGS_CONFIG_PAGE_NUM <= 1)
#error "Invalid value for `SETTINGS_CONFIG_PAGE_NUM` (should be >= 2)"
#endif
/**
* @def FLASH_ERASE_VALUE
*
* The value a byte in flash takes after an erase operation.
*
*/
#ifndef FLASH_ERASE_VALUE
#define FLASH_ERASE_VALUE 0xFF
#endif // FLASH_ERASE_VALUE
/* macros for setting/clearing bits in a flash byte depending on flash erase value */
#if (FLASH_ERASE_VALUE == 0xFF)
#define SET_FLASH_BLOCK_FLAG(aVar, aFlag) ((aVar) &= (~(aFlag)))
#define FLASH_BLOCK_FLAG_IS_SET(aVar, aFlag) (!((aVar) & (aFlag)))
#else
// FLASH_ERASE_VALUE = 0x00
#define SET_FLASH_BLOCK_FLAG(aVar, aFlag) ((aVar) |= (aFlag))
#define FLASH_BLOCK_FLAG_IS_SET(aVar, aFlag) ((aVar) & (aFlag))
#endif
static uint32_t sSettingsBaseAddress;
static uint32_t sSettingsUsedSize;
static uint32_t sSettingsPageNum;
/* linker file symbol for the number of flash sectors used for NVM */
extern uint32_t NV_STORAGE_MAX_SECTORS;
extern uint8_t pageBuffer[];
/**
* Calculates the aligned length of data for current settings block based on Compact flag
*
* @param[in] currentPos Offset from the beginning of settings base address where the current
* block is located
* @param[in] blockFlag Settings block flags value
* @param[in] length Length of current block data
* @return uint16_t Length of aligned data
*/
static uint16_t getAlignLength(uint16_t currentPos, uint8_t blockFlag, uint16_t length)
{
uint16_t alignLen;
/* in case the compact flag is set length is calculated based on real one aligned to
* FLASH_ALIGN_SIZE(16 in this case) */
if (FLASH_BLOCK_FLAG_IS_SET(blockFlag, OT_FLASH_BLOCK_COMPACT_FLAG))
{
alignLen = (length + 1) & 0xfffe;
}
else
{
/* if the block is not compacted the length will be calculated so that the next block starts
* in the next flash page */
uint16_t pageOffset = currentPos % SETTINGS_CONFIG_PAGE_SIZE;
alignLen = SETTINGS_CONFIG_PAGE_SIZE - pageOffset - sizeof(struct settingsBlock);
}
return alignLen;
}
static void setSettingsFlag(uint32_t aBase, uint32_t aFlag)
{
otPlatFlashWrite(0, 0, aBase, (uint8_t *)&aFlag, sizeof(aFlag));
}
static void eraseSettings(uint32_t aBase)
{
uint32_t address = aBase;
uint32_t settingsSize = SETTINGS_CONFIG_PAGE_SIZE * sSettingsPageNum / 2;
while (address < (aBase + settingsSize))
{
utilsFlashErasePage(address);
address += SETTINGS_CONFIG_PAGE_SIZE;
}
}
static void initSettings(uint32_t aBase, uint32_t aFlag)
{
eraseSettings(aBase);
setSettingsFlag(aBase, aFlag);
}
static uint32_t swapSettingsBlock(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
uint32_t oldBase = sSettingsBaseAddress;
uint32_t swapAddress = oldBase;
uint32_t usedSize = sSettingsUsedSize;
uint32_t settingsSize = SETTINGS_CONFIG_PAGE_SIZE * sSettingsPageNum / 2;
bool pageBufferUsed = true;
uint8_t tempFlag;
/* New settings base address */
sSettingsBaseAddress =
(swapAddress == SETTINGS_CONFIG_BASE_ADDRESS) ? (swapAddress + settingsSize) : SETTINGS_CONFIG_BASE_ADDRESS;
/* Erase new settings */
eraseSettings(sSettingsBaseAddress);
/* Erase the page buffer used to accumulate data that will be written to a flash page once it is
* full */
memset(pageBuffer, FLASH_ERASE_VALUE, SETTINGS_CONFIG_PAGE_SIZE);
*((uint32_t *)pageBuffer) = OT_SETTINGS_IN_USE;
sSettingsUsedSize = OT_SETTINGS_FLAG_SIZE;
swapAddress += OT_SETTINGS_FLAG_SIZE;
while (swapAddress < (oldBase + usedSize))
{
OT_TOOL_PACKED_BEGIN
struct addSettingsBlock
{
struct settingsBlock block;
uint8_t data[OT_SETTINGS_BLOCK_DATA_SIZE];
} OT_TOOL_PACKED_END addBlock;
bool valid = true;
otPlatFlashRead(aInstance, 0, swapAddress, (uint8_t *)(&addBlock.block), sizeof(struct settingsBlock));
swapAddress += sizeof(struct settingsBlock);
tempFlag = addBlock.block.flag;
if ((FLASH_BLOCK_FLAG_IS_SET(addBlock.block.flag, OT_FLASH_BLOCK_ADD_COMPLETE_FLAG)) &&
(0 == FLASH_BLOCK_FLAG_IS_SET(addBlock.block.delFlag, OT_FLASH_BLOCK_DELETE_FLAG)))
{
uint32_t address = swapAddress + getAlignLength(swapAddress - sizeof(struct settingsBlock),
addBlock.block.flag, addBlock.block.length);
while (address < (oldBase + usedSize))
{
struct settingsBlock block;
otPlatFlashRead(aInstance, 0, address, (uint8_t *)(&block), sizeof(block));
if ((FLASH_BLOCK_FLAG_IS_SET(block.flag, OT_FLASH_BLOCK_ADD_COMPLETE_FLAG)) &&
(0 == FLASH_BLOCK_FLAG_IS_SET(block.delFlag, OT_FLASH_BLOCK_DELETE_FLAG)) &&
(FLASH_BLOCK_FLAG_IS_SET(block.flag, OT_FLASH_BLOCK_INDEX_0_FLAG)) &&
(block.key == addBlock.block.key))
{
valid = false;
break;
}
address += (getAlignLength(address, block.flag, block.length) + sizeof(struct settingsBlock));
}
if (valid)
{
/* Calculate the size of data(block + settings data) that will be written to the
* page buffer */
uint32_t writeSize = sizeof(struct settingsBlock);
if (!FLASH_BLOCK_FLAG_IS_SET(addBlock.block.flag, OT_FLASH_BLOCK_COMPACT_FLAG))
{
/* Once a swap is initiated every settings block is compacted in the new flash
* region */
SET_FLASH_BLOCK_FLAG(addBlock.block.flag, OT_FLASH_BLOCK_COMPACT_FLAG);
}
/* current pos parameter doesn't count in this case */
writeSize += getAlignLength(0, OT_FLASH_BLOCK_COMPACT_FLAG, addBlock.block.length);
otPlatFlashRead(aInstance, 0, swapAddress, addBlock.data, addBlock.block.length);
/* contents fits in current page - we can copy it to page buffer until there is
* enough data to program a page */
if ((sSettingsUsedSize % SETTINGS_CONFIG_PAGE_SIZE) + writeSize <= SETTINGS_CONFIG_PAGE_SIZE)
{
pageBufferUsed = false;
memcpy(pageBuffer + (sSettingsUsedSize % SETTINGS_CONFIG_PAGE_SIZE), (uint8_t *)(&addBlock),
writeSize);
}
else
{
/* Page buffer is full and can be written to a flash page */
pageBufferUsed = true;
uint32_t remPageSize = SETTINGS_CONFIG_PAGE_SIZE - (sSettingsUsedSize % SETTINGS_CONFIG_PAGE_SIZE);
memcpy(pageBuffer + (sSettingsUsedSize % SETTINGS_CONFIG_PAGE_SIZE), (uint8_t *)(&addBlock),
remPageSize);
/* calculate page address that we are going to write */
uint32_t alignAddress = sSettingsBaseAddress + sSettingsUsedSize;
alignAddress = alignAddress - (alignAddress % SETTINGS_CONFIG_PAGE_SIZE);
otPlatFlashWrite(aInstance, 0, alignAddress, pageBuffer, SETTINGS_CONFIG_PAGE_SIZE);
/* After the page buffer is erased copy what dind't fit the previous page */
memset(pageBuffer, FLASH_ERASE_VALUE, SETTINGS_CONFIG_PAGE_SIZE);
memcpy(pageBuffer, (uint8_t *)(&addBlock) + remPageSize, writeSize - remPageSize);
}
sSettingsUsedSize += writeSize;
}
}
else if (addBlock.block.flag == FLASH_ERASE_VALUE)
{
break;
}
swapAddress += getAlignLength(swapAddress - sizeof(struct settingsBlock), tempFlag, addBlock.block.length);
}
if (false == pageBufferUsed)
{
/* If the page buffer has been used and it's not full write to flash at the end */
uint32_t alignAddr = sSettingsBaseAddress + sSettingsUsedSize;
alignAddr = alignAddr - (alignAddr % SETTINGS_CONFIG_PAGE_SIZE);
otPlatFlashWrite(aInstance, 0, alignAddr, pageBuffer, SETTINGS_CONFIG_PAGE_SIZE);
}
/* Clear the old settings zone */
eraseSettings(oldBase);
return settingsSize - sSettingsUsedSize;
}
static otError addSetting(otInstance * aInstance,
uint16_t aKey,
bool aIndex0,
const uint8_t *aValue,
uint16_t aValueLength);
static otError addSetting(otInstance * aInstance,
uint16_t aKey,
bool aIndex0,
const uint8_t *aValue,
uint16_t aValueLength)
{
otError error = OT_ERROR_NONE;
OT_TOOL_PACKED_BEGIN
struct addSettingsBlock
{
struct settingsBlock block;
uint8_t data[OT_SETTINGS_BLOCK_DATA_SIZE];
} OT_TOOL_PACKED_END addBlock;
uint32_t settingsSize = SETTINGS_CONFIG_PAGE_SIZE * sSettingsPageNum / 2;
/* Add all the settings flags once and optimize for one write to flash */
addBlock.block.flag = FLASH_ERASE_VALUE;
addBlock.block.delFlag = FLASH_ERASE_VALUE;
addBlock.block.key = aKey;
memset(addBlock.block.padding1, FLASH_ERASE_VALUE, FLASH_BLOCK_PAD1_SIZE);
memset(addBlock.block.padding2, FLASH_ERASE_VALUE, FLASH_BLOCK_PAD2_SIZE);
{
otError error = OT_ERROR_NONE;
PDM_teStatus pdmStatus;
uint16_t bytesRead;
otEXPECT_ACTION((pdmBufferSize > aValueLength + sizeof(uint16_t)), error = OT_ERROR_NO_BUFS);
if (aIndex0)
{
SET_FLASH_BLOCK_FLAG(addBlock.block.flag, OT_FLASH_BLOCK_INDEX_0_FLAG);
/* save the lenght of the first record element at the start of the record so we can know
if the record contains multiple entries of a size or just a single entry */
memcpy(sPdmBuffer, (uint8_t *)&aValueLength, sizeof(uint16_t));
memcpy(sPdmBuffer + sizeof(uint16_t), (uint8_t *)aValue, aValueLength);
pdmStatus = PDM_eSaveRecordData(aKey + NVM_START_ID, sPdmBuffer, aValueLength + sizeof(uint16_t));
otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NO_BUFS);
}
SET_FLASH_BLOCK_FLAG(addBlock.block.flag, OT_FLASH_BLOCK_ADD_BEGIN_FLAG);
addBlock.block.length = aValueLength;
if ((sSettingsUsedSize + getAlignLength(sSettingsUsedSize, addBlock.block.flag, addBlock.block.length) +
sizeof(struct settingsBlock)) >= settingsSize)
else
{
otEXPECT_ACTION(swapSettingsBlock(aInstance) >=
(getAlignLength(sSettingsUsedSize, addBlock.block.flag, addBlock.block.length) +
sizeof(struct settingsBlock)),
error = OT_ERROR_NO_BUFS);
pdmStatus = PDM_eReadDataFromRecord(aKey + NVM_START_ID, sPdmBuffer, pdmBufferSize, &bytesRead);
otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NOT_FOUND);
otEXPECT_ACTION((pdmBufferSize > aValueLength + bytesRead), error = OT_ERROR_NO_BUFS);
memcpy(sPdmBuffer + bytesRead, (uint8_t *)aValue, aValueLength);
pdmStatus = PDM_eSaveRecordData(aKey + NVM_START_ID, sPdmBuffer, aValueLength + bytesRead);
otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NO_BUFS);
}
memset(addBlock.data, FLASH_ERASE_VALUE, OT_SETTINGS_BLOCK_DATA_SIZE);
memcpy(addBlock.data, aValue, addBlock.block.length);
SET_FLASH_BLOCK_FLAG(addBlock.block.flag, OT_FLASH_BLOCK_ADD_COMPLETE_FLAG);
otPlatFlashWrite(aInstance, 0, sSettingsBaseAddress + sSettingsUsedSize, (uint8_t *)(&addBlock.block),
sizeof(struct settingsBlock) + addBlock.block.length);
/* The next settings block will be written to the next flash page to optimize the number of
* writes made to a page */
sSettingsUsedSize +=
(sizeof(struct settingsBlock) + getAlignLength(sSettingsUsedSize, addBlock.block.flag, addBlock.block.length));
exit:
return error;
}
@@ -392,52 +106,7 @@ exit:
void otPlatSettingsInit(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
uint8_t index;
struct settingsBlock block;
/* exported symbol from linker file */
sSettingsPageNum = (uint32_t)&NV_STORAGE_MAX_SECTORS;
uint32_t settingsSize = SETTINGS_CONFIG_PAGE_SIZE * sSettingsPageNum / 2;
sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS;
otPlatFlashInit(aInstance);
for (index = 0; index < 2; index++)
{
uint32_t blockFlag;
sSettingsBaseAddress += settingsSize * index;
otPlatFlashRead(aInstance, 0, sSettingsBaseAddress, (uint8_t *)(&blockFlag), sizeof(blockFlag));
if (blockFlag == OT_SETTINGS_IN_USE)
{
break;
}
}
if (index == 2)
{
initSettings(sSettingsBaseAddress, (uint32_t)OT_SETTINGS_IN_USE);
}
sSettingsUsedSize = OT_SETTINGS_FLAG_SIZE;
while (sSettingsUsedSize < settingsSize)
{
otPlatFlashRead(aInstance, 0, sSettingsBaseAddress + sSettingsUsedSize, (uint8_t *)(&block), sizeof(block));
if (FLASH_BLOCK_FLAG_IS_SET(block.flag, OT_FLASH_BLOCK_ADD_BEGIN_FLAG))
{
sSettingsUsedSize +=
(getAlignLength(sSettingsUsedSize, block.flag, block.length) + sizeof(struct settingsBlock));
}
else
{
break;
}
}
(void)PDM_Init();
}
void otPlatSettingsDeinit(otInstance *aInstance)
@@ -445,84 +114,38 @@ void otPlatSettingsDeinit(otInstance *aInstance)
OT_UNUSED_VARIABLE(aInstance);
}
otError otPlatSettingsBeginChange(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NONE;
}
otError otPlatSettingsCommitChange(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NONE;
}
otError otPlatSettingsAbandonChange(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NONE;
}
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
{
OT_UNUSED_VARIABLE(aInstance);
otError error = OT_ERROR_NOT_FOUND;
uint32_t address = sSettingsBaseAddress + OT_SETTINGS_FLAG_SIZE;
uint16_t valueLength = 0;
int index = 0;
otError error = OT_ERROR_NONE;
PDM_teStatus pdmStatus;
uint16_t bytesRead = 0;
uint16_t offset = 0;
while (address < (sSettingsBaseAddress + sSettingsUsedSize))
// only perform read if an input buffer was passed in
if (aValue != NULL && aValueLength != NULL)
{
struct settingsBlock block;
offset = aIndex * (*aValueLength);
pdmStatus = PDM_eReadPartialDataFromExistingRecord(aKey + NVM_START_ID, offset + sizeof(uint16_t), aValue,
*aValueLength, &bytesRead);
otPlatFlashRead(aInstance, 0, address, (uint8_t *)(&block), sizeof(block));
if (block.key == aKey)
otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NOT_FOUND);
*aValueLength = bytesRead;
}
else
{
if (false == PDM_bDoesDataExist(aKey + NVM_START_ID, &bytesRead))
{
if (FLASH_BLOCK_FLAG_IS_SET(block.flag, OT_FLASH_BLOCK_INDEX_0_FLAG))
{
index = 0;
}
if ((FLASH_BLOCK_FLAG_IS_SET(block.flag, OT_FLASH_BLOCK_ADD_COMPLETE_FLAG)) &&
(0 == FLASH_BLOCK_FLAG_IS_SET(block.delFlag, OT_FLASH_BLOCK_DELETE_FLAG)))
{
if (index == aIndex)
{
uint16_t readLength = block.length;
// only perform read if an input buffer was passed in
if (aValue != NULL && aValueLength != NULL)
{
// adjust read length if input buffer length is smaller
if (readLength > *aValueLength)
{
readLength = *aValueLength;
}
otPlatFlashRead(aInstance, 0, address + sizeof(struct settingsBlock), aValue, readLength);
}
valueLength = block.length;
error = OT_ERROR_NONE;
}
index++;
}
error = OT_ERROR_NOT_FOUND;
}
else if (aValueLength != NULL)
{
*aValueLength = bytesRead;
}
address += (getAlignLength(address, block.flag, block.length) + sizeof(struct settingsBlock));
}
if (aValueLength != NULL)
{
*aValueLength = valueLength;
}
exit:
return error;
}
@@ -544,80 +167,44 @@ otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
{
OT_UNUSED_VARIABLE(aInstance);
otError error = OT_ERROR_NOT_FOUND;
uint32_t address = sSettingsBaseAddress + OT_SETTINGS_FLAG_SIZE;
int index = 0;
otError error = OT_ERROR_NONE;
PDM_teStatus pdmStatus;
uint16_t bytesRead = 0;
uint16_t recordElmSize = 0;
while (address < (sSettingsBaseAddress + sSettingsUsedSize))
pdmStatus = PDM_eReadDataFromRecord(aKey + NVM_START_ID, sPdmBuffer, pdmBufferSize, &bytesRead);
otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NOT_FOUND);
recordElmSize = *((uint16_t *)sPdmBuffer);
/* Determine if record contains multiple entries or just one */
if ((-1 == aIndex) || (recordElmSize == bytesRead - sizeof(recordElmSize)))
{
struct settingsBlock block;
PDM_vDeleteDataRecord(aKey + NVM_START_ID);
}
else if (recordElmSize < bytesRead)
{
uint8_t *pMovePtrDst = sPdmBuffer + sizeof(recordElmSize) + (recordElmSize * aIndex);
uint8_t *pMovePtrSrc = pMovePtrDst + recordElmSize;
otPlatFlashRead(aInstance, 0, address, (uint8_t *)(&block), sizeof(block));
if (block.key == aKey)
if (pMovePtrSrc < sPdmBuffer + bytesRead)
{
if (FLASH_BLOCK_FLAG_IS_SET(block.flag, OT_FLASH_BLOCK_INDEX_0_FLAG))
{
index = 0;
}
if ((FLASH_BLOCK_FLAG_IS_SET(block.flag, OT_FLASH_BLOCK_ADD_COMPLETE_FLAG)) &&
(0 == FLASH_BLOCK_FLAG_IS_SET(block.delFlag, OT_FLASH_BLOCK_DELETE_FLAG)))
{
bool flashWrite = false;
if (aIndex == index || aIndex == -1)
{
error = OT_ERROR_NONE;
SET_FLASH_BLOCK_FLAG(block.delFlag, OT_FLASH_BLOCK_DELETE_FLAG);
flashWrite = true;
}
if (index == 1 && aIndex == 0)
{
SET_FLASH_BLOCK_FLAG(block.flag, OT_FLASH_BLOCK_INDEX_0_FLAG);
flashWrite = true;
}
if (flashWrite)
{
otPlatFlashWrite(aInstance, 0, address, (uint8_t *)(&block), sizeof(block));
}
index++;
}
memcpy(pMovePtrDst, pMovePtrSrc, recordElmSize);
}
address += (getAlignLength(address, block.flag, block.length) + sizeof(struct settingsBlock));
pdmStatus = PDM_eSaveRecordData(aKey + NVM_START_ID, sPdmBuffer, bytesRead - recordElmSize);
otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NOT_FOUND);
}
exit:
return error;
}
void otPlatSettingsWipe(otInstance *aInstance)
{
uint32_t address = SETTINGS_CONFIG_BASE_ADDRESS;
OT_UNUSED_VARIABLE(aInstance);
/* Clears all the flash pages during a factory reset */
for (uint32_t i = 0; i < sSettingsPageNum; i++)
for (uint32_t i = 0; i <= NVM_MAX_ID; i++)
{
/* This function protects against erasing an already erased page so we can just erase all
* pages to have and have all the settings storage clean */
utilsFlashErasePage(address);
address += SETTINGS_CONFIG_PAGE_SIZE;
PDM_vDeleteDataRecord(NVM_START_ID + i);
}
/* Each time a factory reset is invoked start the settings zone in the alternate region to
* maximize wear leveling */
if (SETTINGS_CONFIG_BASE_ADDRESS == sSettingsBaseAddress)
{
sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS + (SETTINGS_CONFIG_PAGE_SIZE * sSettingsPageNum / 2);
}
else
{
sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS;
}
setSettingsFlag(sSettingsBaseAddress, OT_SETTINGS_IN_USE);
otPlatSettingsInit(aInstance);
}
+40 -1
View File
@@ -39,7 +39,10 @@
#include <stdbool.h>
#include <stdint.h>
otInstance *sInstance;
#include "MemManager.h"
otInstance * sInstance;
OT_TOOL_WEAK uint32_t gInterruptDisableCount = 0;
void otSysInit(int argc, char *argv[])
{
@@ -57,6 +60,7 @@ void otSysInit(int argc, char *argv[])
BOARD_BootClockRUN();
BOARD_InitPins();
MEM_Init();
}
K32WAlarmInit();
@@ -86,3 +90,38 @@ WEAK void otSysEventSignalPending(void)
{
/* Intentionally left empty */
}
/*FUNCTION**********************************************************************
*
* Function Name : OSA_InterruptEnable
* Description : self explanatory.
*
*END**************************************************************************/
OT_TOOL_WEAK void OSA_InterruptEnable(void)
{
if (gInterruptDisableCount > 0)
{
gInterruptDisableCount--;
if (gInterruptDisableCount == 0)
{
__enable_irq();
}
/* call core API to enable the global interrupt*/
}
}
/*FUNCTION**********************************************************************
*
* Function Name : OSA_InterruptDisable
* Description : self explanatory.
*
*END**************************************************************************/
OT_TOOL_WEAK void OSA_InterruptDisable(void)
{
/* call core API to disable the global interrupt*/
__disable_irq();
/* update counter*/
gInterruptDisableCount++;
}
@@ -0,0 +1,822 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "Flash_Adapter.h"
#include "FunctionLib.h"
#include "fsl_os_abstraction.h"
#if gNvStorageIncluded_d
#include "NVM_Interface.h"
#endif
#include "Panic.h"
#include "fsl_debug_console.h"
/*****************************************************************************
*****************************************************************************
* Private macros
*****************************************************************************
*****************************************************************************/
#if (PGM_SIZE_BYTE == 4)
#define mProgBuffSizeInPgmWrUnits_c 16
#elif (PGM_SIZE_BYTE == 8)
#define mProgBuffSizeInPgmWrUnits_c 8
#else
#define mProgBuffSizeInPgmWrUnits_c 4
#endif
/* Generator for CRC calculations. */
#define POLGEN 0x1021
#ifdef CPU_JN518X
#include "rom_psector.h"
void ResetMCU(void);
#endif
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private prototypes
*************************************************************************************
********************************************************************************** */
static uint32_t NV_FlashProgramAdaptation(uint32_t dest, uint32_t size, uint8_t* pData);
#if !defined CPU_QN908X && ! defined CPU_JN518X
static uint8_t NV_VerifyCrcOverHWParameters(hardwareParameters_t* pHwParams);
static uint16_t NV_ComputeCrcOverHWParameters(hardwareParameters_t* pHwParams);
#endif
static void NV_Flash_WaitForCSEndAndDisableInterrupts(void);
#ifdef CPU_QN908X
static uint32_t SwFlashVerifyErase (uint32_t start, uint32_t lengthInBytes);
#endif
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
/* Hardware parameters */
hardwareParameters_t gHardwareParameters;
extern flash_config_t gFlashConfig;
#if !defined CPU_QN908X && !defined CPU_JN518X
static const uint8_t mProdDataIdentifier[10] = {"PROD_DATA:"};
#endif
#if (USE_RTOS)
static osaSemaphoreId_t mFlashAdapterSemaphoreId;
#endif
static volatile uint8_t mFA_CSFlag = 0;
static volatile uint8_t mFA_SemWaitCount = 0;
/*****************************************************************************
*****************************************************************************
* Private functions
*****************************************************************************
*****************************************************************************/
/*! *********************************************************************************
* \brief This function ensures that there are no critical sections on and disables interrupts.
*
* \param[in] none
* \return nothing
*
********************************************************************************** */
static void NV_Flash_WaitForCSEndAndDisableInterrupts(void)
{
#if (USE_RTOS)
#if (gNvStorageIncluded_d)
/*on freeRTOS NvIdle runs on a freeRTOS idle task hook which must never block. In this RTOS at least one task must be ready */
/*since NvIdle runs on the task which has the least priority in the system we can wait in a loop for the end of the critical section */
osaTaskId_t currentTaskId = OSA_TaskGetId();
if(currentTaskId == (osaTaskId_t)NvGetNvIdleTaskId())
{
while(1)
{
while (mFA_CSFlag);
OSA_InterruptDisable();
if(mFA_CSFlag == 0)
{
break;
}
OSA_InterruptEnable();
}
}
else
#endif
{
while(1)
{
OSA_InterruptDisable();
if(mFA_CSFlag == 0)
{
break;
}
mFA_SemWaitCount++;
OSA_InterruptEnable();
OSA_SemaphoreWait(mFlashAdapterSemaphoreId, osaWaitForever_c);
}
}
#else
OSA_InterruptDisable();
#endif
}
/*! *********************************************************************************
* \brief Write aligned data to FLASH
*
* \param[in] dest The address of the Flash location
* \param[in] size The number of bytes to be programed
* \param[in] pData Pointer to the data to be programmed to Flash
*
* \return error code
*
********************************************************************************** */
static uint32_t NV_FlashProgramAdaptation(uint32_t dest, uint32_t size, uint8_t* pData)
{
uint32_t progBuf[PGM_SIZE_BYTE/sizeof(uint32_t)];
uint32_t status = kStatus_FLASH_Success;
#if !defined (CPU_JN518X)
if( (size & (PGM_SIZE_BYTE - 0x01U)) != 0 )
{
return kStatus_FLASH_AlignmentError;
}
#if gFlashEraseDuringWrite
{
NV_FlashEraseSector(dest, size-1);
}
#endif
#else
if( (size & (PGM_SIZE_BYTE - 0x01U)) != 0 )
{
return kStatus_FLASH_AlignmentError;
}
if( (dest & MASK_LOG(PGM_SIZE_BYTE_LOG)) != 0 )
{
PRINTF("Unaligned flash address %08lx", dest);
return kStatus_FLASH_AlignmentError;
}
NV_FlashEraseSector(dest, size-1);
#endif
while(size)
{
FLib_MemCpy(progBuf, pData, PGM_SIZE_BYTE);
#if gNvDisableIntCmdSeq_c
NV_Flash_WaitForCSEndAndDisableInterrupts();
#endif
status = FLASH_PROGRAM_AREA(dest, progBuf, PGM_SIZE_BYTE);
#if gNvDisableIntCmdSeq_c
OSA_InterruptEnable();
#endif
if(status != kStatus_FLASH_Success)
{
break;
}
pData += PGM_SIZE_BYTE;
dest += PGM_SIZE_BYTE;
size -= PGM_SIZE_BYTE;
}
return status;
}
#if !defined CPU_QN908X && ! defined CPU_JN518X
/*! *********************************************************************************
* \brief Verifies if the CRC field matches computed CRC over stored values
*
* \param[in] pHwParams pointer to a structure containing HW parameters
*
* \return 1 on success, 0 otherwise
*
********************************************************************************** */
static uint8_t NV_VerifyCrcOverHWParameters(hardwareParameters_t* pHwParams)
{
uint8_t status = 0;
if(NV_ComputeCrcOverHWParameters(pHwParams) == pHwParams->hardwareParamsCrc)
{
status = 1;
}
else
{
status = 0;
}
return status;
}
/*! *********************************************************************************
* \brief Computes the CRC for the hardware parameters and stores it
*
* \param[in] pHwParams pointer to a structure containing HW parameters
*
* \return Computed CRC value.
*
********************************************************************************** */
static uint16_t NV_ComputeCrcOverHWParameters(hardwareParameters_t* pHwParams)
{
uint16_t computedCRC = 0;
uint8_t crcA;
uint8_t byte = 0;
if(NULL != pHwParams)
{
uint8_t *ptr = (uint8_t *)(&pHwParams->reserved);
uint16_t len = (uint8_t *)(&pHwParams->hardwareParamsCrc) -
(uint8_t *)(&pHwParams->reserved);
while(len)
{
byte = *ptr;
computedCRC ^= ((uint16_t)byte << 8);
for(crcA = 8; crcA; crcA--)
{
if(computedCRC & 0x8000) {
computedCRC <<= 1;
computedCRC ^= POLGEN;
}
else computedCRC <<= 1;
}
--len;
++ptr;
}
}
return computedCRC;
}
#endif
#ifdef CPU_QN908X
/*! *********************************************************************************
* \brief Flash verify erase software implementation
*
* \param[in] start - start address of the memory block to be verified
* \param[in] lengthInBytes - memory block length
*
* \return TRUE if the flash memory area is blank (erased), FALSE otherwise
*
********************************************************************************** */
uint32_t SwFlashVerifyErase (uint32_t start, uint32_t lengthInBytes)
{
uint8_t* pAddress = (uint8_t*)start;
flash_status_t status = kStatus_FLASH_Success;
do
{
if(*pAddress++ != 0xff)
{
status = kStatus_FLASH_EraseError;
break;
}
} while(--lengthInBytes);
return (uint32_t)status;
}
#endif
#ifdef CPU_JN518X
#define FLASH_WORD_SZ 16
/* This is kept as an example of code using the TRY .. CATCH for exceptions
* Using it raises some execution issues with a debugger
*/
uint32_t NV_ReadSweep(uint32_t start_addr, uint32_t end_addr)
{
uint32_t addr = start_addr;
TRY
{
while (addr < end_addr)
{
volatile uint32_t read_val;
read_val = *(uint32_t*)addr;
read_val = read_val;
addr += FLASH_WORD_SZ;
}
}
CATCH (BUS_EXCEPTION)
{
/* return page address if an error is detected */
return ROUND_FLOOR(addr, 9);
}
YRT;
return 0;
}
uint32_t NV_SafeReadFromFlash(uint8_t * ram_dst, uint8_t * flash_src, size_t size)
{
uint32_t au32Data[FLASH_WORD_SZ/sizeof(uint32_t)];
uint32_t st = kStatus_FLASH_Fail;
uint32_t nb_flash_words = (size + (FLASH_WORD_SZ-1)) / FLASH_WORD_SZ;
while (nb_flash_words-- > 0)
{
size_t sz;
sz = (size >= FLASH_WORD_SZ) ? FLASH_WORD_SZ : size;
st = FLASH_Read(FLASH, flash_src, 0, au32Data);
if (st != kStatus_FLASH_Success) break;
memcpy(ram_dst, (uint8_t*)&au32Data[0], sz);
ram_dst += sz;
flash_src += sz;
size -= sz;
}
return st;
}
void NV_FlashPerformAudit(void)
{
int status;
uint32_t addr = INT_STORAGE_START_OFFSET;
if (INT_STORAGE_END_OFFSET == INT_STORAGE_START_OFFSET) addr++;
uint32_t end = (uint32_t)0x9ddff;
uint32_t failed_addr;
uint8_t buf[FLASH_PAGE_SIZE];
while (addr <= ROUND_FLOOR(end, 9))
{
status = FLASH_BlankCheck(FLASH, (uint8_t*)addr, (uint8_t*)end);
if (kStatus_FLASH_Fail == status)
{
failed_addr = FLASH->DATAW[0]; /* is a flash word address */
failed_addr <<= 4;
addr = ROUND_FLOOR(failed_addr, 9);
status = NV_SafeReadFromFlash(buf, (uint8_t*)addr, FLASH_PAGE_SIZE);
if (kStatus_FLASH_Success != status)
{
status = FLASH_Erase(FLASH,
(uint8_t*)addr,
(uint8_t*)(addr+FLASH_PAGE_SIZE-1));
if (status != kStatus_FLASH_Success)
{
PRINTF("NV Audit Erase failed at addr=%08lx\r\n", addr);
break;
}
}
addr += FLASH_PAGE_SIZE;
}
else
{
addr = end;
}
}
}
#endif
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
#ifdef CPU_JN518X
int PsectorUpdateFlashAudit(uint32_t new_value)
{
int res = 1;
psector_page_data_t page_buf;
psector_page_data_t *page0 = (psector_page_data_t*)0x9e800;
memcpy(&page_buf, page0, FLASH_PAGE_SIZE);
((psector_page_data_t*)&page_buf)->page0_v3.flash_audit_done = new_value;
page_buf.hdr.version ++;
page_buf.hdr.checksum = psector_CalculateChecksum((psector_page_t *)&page_buf);
if (psector_WriteUpdatePage(PSECTOR_PAGE0_PART, (psector_page_t *)&page_buf) != WRITE_OK)
{
res = -1;
}
else
{
ResetMCU(); /* Commit now by forcing reset */
}
return res;
}
int psector_FlashAudit(void)
{
int res = -1;
do {
psector_page_data_t *page0 = (psector_page_data_t*)0x9e800;
uint32_t flash_audit_word = page0->page0_v3.flash_audit_done;
if ((flash_audit_word & 0xffff) == FLASH_AUDIT_DONE)
{
res = 0;
break;
}
else
{
/* Need to verify internal flash */
NV_FlashPerformAudit();
uint32_t flash_audit_code = (flash_audit_word & 0xffff0000u) | FLASH_AUDIT_DONE;
res = PsectorUpdateFlashAudit(flash_audit_code);
if (res < 0)
break;
}
} while (0);
return res;
}
#endif
/*! *********************************************************************************
* \brief Initialize the FLASH driver
*
********************************************************************************** */
void NV_Init(void)
{
static bool_t nvmInit = 0;
if(nvmInit == 0)
{
#ifdef CPU_QN908X
/* Configure Flash */
FLASH_GetDefaultConfig(&gFlashConfig);
gFlashConfig.blockBase = 0x0U;
#endif /* CPU_QN908X */
#ifdef gNVM_MULTICORE_SUPPORT_d
FLASH_SetProperty(&gFlashConfig, kFLASH_PropertyFlashMemoryIndex, 1);
#endif
/* Init Flash */
FLASH_INIT();
#if (defined(CPU_MKW36Z512VFP4) || defined(CPU_MKW36Z512VHT4))
/* KW36 has 256KB of FlexNVM mapped at adress 0x1000 0000 which also has an alias starting from address 0x0004 0000.
* Configured the Flash driver to treat the PFLASH bloxk and FlexNVM block as a continuous memory block. */
gFlashConfig.DFlashBlockBase = FSL_FEATURE_FLASH_PFLASH_BLOCK_SIZE * FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT;
#endif
#if (USE_RTOS)
if( (mFlashAdapterSemaphoreId = OSA_SemaphoreCreate(0)) == NULL )
{
panic( ID_PANIC(0,0), (uint32_t)NV_Init, 0, 0 );
}
#endif
#ifdef CPU_JN518X
if (!nvmInit)
{
if (psector_FlashAudit() == 0)
nvmInit = 1;
}
#else
nvmInit = 1;
#endif
}
}
/******************************************************************************
* Name: NvSetCriticalSection
* Description: enter critical section
* Parameters: -
* Return: -
******************************************************************************/
/*! *********************************************************************************
* \brief Start a critical section during which flash operations are not allowed
*
* \param[in] none
* \return nothing
*
********************************************************************************** */
void NV_Flash_SetCriticalSection
(
void
)
{
#if (USE_RTOS)
OSA_InterruptDisable();
++mFA_CSFlag;
OSA_InterruptEnable();
#endif
}
/*! *********************************************************************************
* \brief Start a critical section during which flash operations are not allowed
*
* \param[in] none
* \return nothing
*
********************************************************************************** */
void NV_Flash_ClearCriticalSection
(
void
)
{
#if (USE_RTOS)
OSA_InterruptDisable();
if(mFA_CSFlag)
{
mFA_CSFlag--;
}
OSA_InterruptEnable();
while(1)
{
OSA_InterruptDisable();
if(mFA_CSFlag)
{
break;
}
if(mFA_SemWaitCount == 0)
{
break;
}
mFA_SemWaitCount--;
OSA_InterruptEnable();
OSA_SemaphorePost(mFlashAdapterSemaphoreId);
}
OSA_InterruptEnable();
#endif
}
/*! *********************************************************************************
* \brief Verify erase data in Flash
*
* \param[in] start The address of the Flash location
* \param[in] lengthInBytes The number of bytes to be checked
* \param[in] margin
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashVerifyErase ( uint32_t start, uint32_t lengthInBytes)
{
uint32_t status;
#if gNvDisableIntCmdSeq_c
NV_Flash_WaitForCSEndAndDisableInterrupts();
#endif
status = FLASH_VERIFY_ERASE(start, lengthInBytes);
#if gNvDisableIntCmdSeq_c
OSA_InterruptEnable();
#endif
return status;
}
/*! *********************************************************************************
* \brief Write aligned data to FLASH
*
* \param[in] pSSDConfig Pointer to a flash config structure
* \param[in] dest The address of the Flash location
* \param[in] size The number of bytes to be programed
* \param[in] pData Pointer to the data to be programmed to Flash
* \param[in] pFlashCommandSequence Pointer to the Flash RAM function
*
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashProgram(uint32_t dest,
uint32_t size,
uint8_t* pData)
{
return NV_FlashProgramAdaptation(dest, size, pData);
}
/*! *********************************************************************************
* \brief Write data to FLASH
*
* \param[in] pSSDConfig Pointer to a flash config structure
* \param[in] dest The address of the Flash location
* \param[in] size The number of bytes to be programed
* \param[in] pData Pointer to the data to be programmed to Flash
* \param[in] pFlashCommandSequence Pointer to the Flash RAM function
*
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashProgramUnaligned(uint32_t dest,
uint32_t size,
uint8_t* pData)
{
uint8_t buffer[PGM_SIZE_BYTE];
uint32_t status;
do {
uint32_t align_addr = ROUND_FLOOR(dest, PGM_SIZE_BYTE_LOG);
uint16_t bytes = (dest - align_addr);
if( bytes )
{
uint16_t unalignedBytes = PGM_SIZE_BYTE - bytes;
if( unalignedBytes > size )
{
unalignedBytes = size;
}
if (FLib_CopyFromFlash(buffer, (void*)align_addr, PGM_SIZE_BYTE))
{
PRINTF("Raised error while reading from %08lx\r\n", align_addr);
}
FLib_MemCpy(&buffer[bytes], pData, unalignedBytes);
status = NV_FlashProgramAdaptation(align_addr, PGM_SIZE_BYTE, buffer);
if(status != kStatus_FLASH_Success) break;
dest += unalignedBytes;
/* if size is less than the distance to the end of program block
unalignedBytes has been shrunk , after size is decremented it will become 0 */
pData += unalignedBytes;
size -= unalignedBytes;
}
bytes = size & ~(PGM_SIZE_BYTE - 1U);
/* Now dest is on an aligned boundary */
/* bytes is an integer number of program blocks (pages) */
if( bytes )
{
status = NV_FlashProgramAdaptation(dest, bytes, pData);
if(status != kStatus_FLASH_Success) break;
dest += bytes;
pData += bytes;
size -= bytes;
}
/* dest is still aligned because we have increased it by a multiple of the program block (page) */
if( size )
{
if (
#ifdef CPU_JN518X
/* Avoid reading page if it is blank */
(FLASH_VERIFY_ERASE(dest, PGM_SIZE_BYTE) == kStatus_FLASH_Fail) &&
#endif
(FLib_CopyFromFlash(buffer, (void*)dest, PGM_SIZE_BYTE))
)
{
PRINTF("Raised error while reading from %08lx\r\n", (dest - bytes));
}
FLib_MemCpy(buffer, pData, size);
status = NV_FlashProgramAdaptation(dest, PGM_SIZE_BYTE, buffer);
if(status != kStatus_FLASH_Success) break;
}
status = kStatus_FLASH_Success;
} while (0);
return status;
}
/*! *********************************************************************************
* \brief Erase to 0xFF one ore more FLASH sectors.
*
* \param[in] pSSDConfig Pointer to a flash config structure
* \param[in] dest The start address of the first sector to be erased
* \param[in] size The amount of flash to be erased (multiple of sector size)
* \param[in] pFlashCommandSequence Pointer to the Flash RAM function
*
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashEraseSector(uint32_t dest, uint32_t size)
{
uint32_t status;
#ifdef CPU_QN908X
uint32_t status_flags;
#endif
#if gNvDisableIntCmdSeq_c
NV_Flash_WaitForCSEndAndDisableInterrupts();
#endif
#if defined(CPU_QN908X)
status_flags = FLASH_GetStatusFlags();
if(status_flags & FLASH_INT_STAT_AHBL_INT_MASK)
{
FLASH_ClearStatusFlags(FLASH_INTCLR_AHBL_INTCLR_MASK);
}
if(status_flags & FLASH_INT_STAT_AHBH_INT_MASK)
{
FLASH_ClearStatusFlags(FLASH_INTCLR_AHBH_INTCLR_MASK);
}
#endif
status = FLASH_ERASE_AREA(dest, size);
#if gNvDisableIntCmdSeq_c
OSA_InterruptEnable();
#endif
return status;
}
#if !defined CPU_QN908X && !defined CPU_JN518X
/*! *********************************************************************************
* \brief Load the HW parameters from Flash to RAM
*
* \param[in] pHwParams pointer to a structure where HW parameters will be stored
*
* \return error code
*
********************************************************************************** */
uint32_t NV_ReadHWParameters(hardwareParameters_t *pHwParams)
{
hardwareParameters_t* pLocalParams = (hardwareParameters_t*)FREESCALE_PROD_DATA_BASE_ADDR;
uint32_t status = 0;
do {
if(NULL == pHwParams)
{
/* Invalid parameter */
status = 2;
break;
}
#ifdef CPU_JN518X
#if 0
if (NV_SafeReadFromFlash((uint8_t*)pHwParams,
(uint8_t*)pLocalParams,
sizeof(hardwareParameters_t)) == kStatus_FLASH_Success)
{
if (FLib_MemCmp(pHwParams,
(void*)mProdDataIdentifier,
sizeof(mProdDataIdentifier)) &&
NV_VerifyCrcOverHWParameters(pHwParams))
{
status = 0;
break;
}
}
else
{
NV_FlashEraseSector((uint32_t)pLocalParams, FLASH_PAGE_SIZE-1);
FLib_MemSet(pHwParams, 0xFF, sizeof(hardwareParameters_t));
status = 1;
}
#endif
#else
if (FLib_MemCmp(FREESCALE_PROD_DATA_BASE_ADDR, (void*)mProdDataIdentifier, sizeof(mProdDataIdentifier)) &&
NV_VerifyCrcOverHWParameters(pLocalParams))
{
FLib_MemCpy(pHwParams, FREESCALE_PROD_DATA_BASE_ADDR, sizeof(hardwareParameters_t));
status = 0;
}
else
{
FLib_MemSet(pHwParams, 0xFF, sizeof(hardwareParameters_t));
status = 1;
break;
}
#endif
} while (0);
return status;
}
/*! *********************************************************************************
* \brief Store the HW parameters to Flash
*
* \param[in] pHwParams pointer to a structure containing HW parameters
*
* \return error code of the Flash erase/write functions
*
********************************************************************************** */
uint32_t NV_WriteHWParameters(hardwareParameters_t *pHwParams)
{
uint32_t status = 0;
NV_Init();
#ifndef CPU_JN518X
#ifdef CPU_JN518X
status = FLASH_BlankCheck(FLASH, (uint8_t *)FREESCALE_PROD_DATA_BASE_ADDR,
(uint8_t *)(FREESCALE_PROD_DATA_BASE_ADDR + sizeof(hardwareParameters_t)));
#endif
if(
#ifdef CPU_JN518X
(status == kStatus_FLASH_Success) ||
#endif
!FLib_MemCmp(pHwParams, (void*)FREESCALE_PROD_DATA_BASE_ADDR, sizeof(hardwareParameters_t)))
{
pHwParams->hardwareParamsCrc = NV_ComputeCrcOverHWParameters(pHwParams);
FLib_MemCpy(pHwParams->identificationWord, (void*)mProdDataIdentifier, sizeof(mProdDataIdentifier));
#if defined(FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE)
status = NV_FlashEraseSector((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR, FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE);
#elif defined(FSL_FEATURE_FLASH_PAGE_SIZE_BYTES)
status = NV_FlashEraseSector((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR, FSL_FEATURE_FLASH_PAGE_SIZE_BYTES);
#endif
if( kStatus_FLASH_Success == status )
{
status = NV_FlashProgramUnaligned((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR,
sizeof(hardwareParameters_t),
(uint8_t*)pHwParams);
}
}
#endif
return status;
}
#endif /* neither CPU_QN908X not CPU_JN518X */
@@ -0,0 +1,238 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017, 2019 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef __FLASH_ADAPTER_H__
#define __FLASH_ADAPTER_H__
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
#include "fsl_flash.h"
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
/*
* Name: gNvDisableIntCmdSeq_c
* Description: this macro is used to enable/disable interrupts when the
* FTFL controller executes a command sequence. This macro
* has to be set according to NVM configuration. Therefore,
* if the FLASH region used by the NVM is placed in the same
* program block as the ISR's executable code, the interrupts
* MUST be disabled (because no code pre-fetching can be performed
* while FTFL controller executes a command sequence, i.e.
* program/erase). If the interrupts are not disabled, the
* system will assert a hard fault when the flash controller
* executes a command sequnce and an IRQ is about to be handled.
* If the NVM region is placed in a different program block than
* the ISR's code, this macro shall be set to FALSE (recommended).
*/
#ifndef gNvDisableIntCmdSeq_c
#define gNvDisableIntCmdSeq_c (1)
#endif
/* size of array to copy__Launch_Command function to.*/
/* It should be at least equal to actual size of __Launch_Command func */
/* User can change this value based on RAM size availability and actual size of __Launch_Command function */
#define LAUNCH_CMD_SIZE 64
#define PGM_SIZE_BYTE FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE
#define P_BLOCK_NUM FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT
#define P_SECTOR_SIZE FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE
/* Data Flash block information */
#define FLEXNVM_BASE FSL_FEATURE_FLASH_FLEX_NVM_START_ADDRESS
#define FLEXNVM_SECTOR_SIZE FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SECTOR_SIZE
#define FLEXNVM_BLOCK_SIZE FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SIZE
#define FLEXNVM_BLOCK_NUM FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_COUNT
/* Other defines */
#define DEBUGENABLE 0x00
#define FTFx_REG_BASE 0x40020000
#define P_FLASH_BASE 0x00000000
/* Flex Ram block information */
#define EERAM_BASE FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS
#define EERAM_SIZE FSL_FEATURE_FLASH_FLEX_RAM_SIZE
#define READ_NORMAL_MARGIN 0x00
#define READ_USER_MARGIN 0x01
#define READ_FACTORY_MARGIN 0x02
#define NV_FlashRead(pSrc, pDest, size) FLib_MemCpy((void*)(pDest), (void*)(pSrc), size);
#if defined(CPU_QN908X)
#define kStatus_FLASH_AlignmentError MAKE_STATUS(kStatusGroup_FLASH, 6)
#elif defined(CPU_JN518X)
#define FLASH_AUDIT_DONE 0xc65c
int PsectorUpdateFlashAudit(uint32_t new_value);
#endif
#define PGM_SIZE_BYTE_LOG LOG(PGM_SIZE_BYTE)
#define FLASH_PAGE_SZ_LOG LOG(FLASH_PAGE_SIZE)
#define IS_MULTIPLE_OF_SECT_SIZE(len) (((len) & (FLASH_PAGE_SIZE-1)) == 0)
#define SIZE2SEGNB(sz, sz_log) ((sz)>>(sz_log))
#define ADDR2SEG(addr, sz_log) (((uint32_t)(addr))>>(sz_log))
#if defined(__CC_ARM)
extern uint32_t Image$$INT_STORAGE$$Base[];
extern uint32_t Image$$INT_STORAGE$$Length[];
extern uint32_t Image$$INT_STORAGE$$End[];
#define INT_STORAGE_START_OFFSET ((uint32_t)Image$$INT_STORAGE$$Base)
#define INT_STORAGE_TOTAL_SIZE ((uint32_t)Image$$INT_STORAGE$$Length)
#define INT_STORAGE_END_OFFSET ((uint32_t)Image$$INT_STORAGE$$End)
#else /* defined(__CC_ARM) */
extern uint32_t INT_STORAGE_START[];
extern uint32_t INT_STORAGE_SIZE[];
extern uint32_t INT_STORAGE_END[];
extern uint32_t INT_STORAGE_SECTOR_SIZE[];
#define INT_STORAGE_START_OFFSET ((uint32_t)INT_STORAGE_END)
#define INT_STORAGE_END_OFFSET ((uint32_t)INT_STORAGE_START)
#define INT_STORAGE_TOTAL_SIZE ((uint32_t)INT_STORAGE_SIZE)
/*
* Name: NV_STORAGE_END_ADDRESS
* Description: NV_STORAGE_END_ADDRESS from linker command file is used by this code
* as Raw Sector Start Address.
*/
extern uint32_t NV_STORAGE_END_ADDRESS[];
/*
* Name: NV_STORAGE_SECTOR_SIZE
* Description: external symbol from linker command file, it represents the size
* of a FLASH sector
*/
extern uint32_t NV_STORAGE_SECTOR_SIZE[];
/*
* Name: NV_STORAGE_MAX_SECTORS
* Description: external symbol from linker command file, it represents the sectors
* count used by the ENVM storage system; it has to be a multiple of 2
*/
extern uint32_t NV_STORAGE_MAX_SECTORS[];
/*
* Name: NV_STORAGE_START_ADDRESS
* Description: NV_STORAGE_START_ADDRESS from linker command file is used by this code
* as Raw Sector End Address. Start is End address
*/
extern uint32_t NV_STORAGE_START_ADDRESS[];
#endif /* defined(__CC_ARM) */
/* Flash address of the Product Data sector */
#if defined(__CC_ARM)
extern uint32_t Load$$LR$$LR_Prod_Data$$Base[];
#define FREESCALE_PROD_DATA_BASE_ADDR Load$$LR$$LR_Prod_Data$$Base
#else
extern uint32_t FREESCALE_PROD_DATA_BASE_ADDR[];
#endif /* defined(__CC_ARM) */
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
/*! GCC would warn about packing, so add pragma to repress warning */
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wattributes"
#endif
typedef PACKED_STRUCT hardwareParameters_tag
{
uint8_t identificationWord[10]; /* valid data present */
#ifdef CPU_JN518X
uint8_t flash_audit_done;
uint8_t reserved[3];
#else
uint8_t reserved[32]; /* for backward compatibillity */
uint8_t ieee_802_15_4_address[8]; /* IEEE 802.15.4 MAC address */
uint8_t bluetooth_address[6]; /* Bluetooth address */
uint32_t xtalTrim; /* KW4x only */
uint32_t edCalibrationOffset; /* KW01 ED offset */
uint32_t pllFStepOffset; /* KW01 fine tune pll */
#endif
uint32_t gInternalStorageAddr; /* The start address of the internal storage used for OTA update.
A value of 0xFFFFFFFF means that the External storage is used.
Warning: The offset to this field in respect to the start address of the structure
must not be changed.*/
/* For forward compatibility additional fields may be added here
Existing data in flash will not be compatible after modifying the hardwareParameters_t typedef*/
uint16_t hardwareParamsCrc; /* crc for data between start of reserved area and start of hardwareParamsCrc field (not included). */
}hardwareParameters_t;
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
extern flash_config_t gFlashConfig;
extern hardwareParameters_t gHardwareParameters;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
void NV_Init(void);
uint32_t NV_FlashProgram( uint32_t dest,
uint32_t size,
uint8_t* pData);
uint32_t NV_FlashProgramUnaligned(uint32_t dest,
uint32_t size,
uint8_t* pData);
uint32_t NV_FlashEraseSector(uint32_t dest,
uint32_t size);
#if defined(CPU_JN518X)
#define FLASH_ERASE_AREA(ADDR, SZ) FLASH_Erase(FLASH, (uint8_t *)(ADDR), (uint8_t *)((ADDR) + (SZ) - 1))
#define FLASH_PROGRAM_AREA(ADDR, SRC, SZ) FLASH_Program(FLASH, (uint32_t *)(ADDR), (uint32_t*)(SRC), (SZ))
#define FLASH_INIT() FLASH_Init(FLASH)
#define FLASH_VERIFY_ERASE(ADDR, SZ) FLASH_BlankCheck(FLASH, (uint8_t *)(ADDR), (uint8_t *)((ADDR) + (SZ) - 1))
#elif defined(CPU_QN908X)
#define FLASH_VERIFY_ERASE(ADDR, SZ) SwFlashVerifyErase((ADDR), (SZ), ,kFLASH_MarginValueNormal)
#define FLASH_ERASE_AREA(ADDR, SZ) FLASH_Erase(&gFlashConfig, (ADDR), (SZ))
#define FLASH_PROGRAM_AREA(ADDR, SRC, SZ) FLASH_Program(&gFlashConfig, (uint32_t *)(ADDR), (uint32_t*)(SRC), (SZ))
#define FLASH_INIT() FLASH_Init(&gFlashConfig)
#define FLASH_VERIFY_ERASE(ADDR, SZ) SwFlashVerifyErase ((ADDR), (SZ))
#else
#define FLASH_VERIFY_ERASE(ADDR, SZ) NV_FlashVerifyErase(ADDR, SZ)
#define FLASH_ERASE_AREA, SZ) FLASH_Erase(&gFlashConfig, (ADDR), (SZ), kFLASH_ApiEraseKey)
#define FLASH_PROGRAM_AREA(ADDR, SRC, SZ) FLASH_Program(&gFlashConfig, (uint32_t *)(ADDR), (uint32_t*)(SRC), (SZ))
#define FLASH_INIT() FLASH_Init(&gFlashConfig)
#define FLASH_VERIFY_ERASE(ADDR, SZ) FLASH_VerifyErase(&gFlashConfig, (ADDR), (SZ), kFLASH_MarginValueNormal)
#endif
uint32_t NV_ReadHWParameters(hardwareParameters_t *pHwParams);
uint32_t NV_WriteHWParameters(hardwareParameters_t *pHwParams);
void NV_Flash_SetCriticalSection(void);
void NV_Flash_ClearCriticalSection(void);
#endif /* __FLASH_ADAPTER_H__ */
@@ -0,0 +1,573 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This module contains various common functions like copy and compare routines.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#include "FunctionLib.h"
#if gUseToolchainMemFunc_d
#include <string.h>
#endif
#if gFLib_CheckBufferOverflow_d
#include "MemManager.h"
#endif
/*! *********************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private prototypes
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function copies bytes from one buffer to another.
* The buffers should not overlap.
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \post The source and destination buffers must not overlap.
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpy (void* pDst,
const void* pSrc,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pDst, cBytes);
#endif
#if gUseToolchainMemFunc_d
memcpy(pDst, pSrc, cBytes);
#else
while (cBytes)
{
*((uint8_t*)pDst) = *((uint8_t*)pSrc);
pDst = ((uint8_t*)pDst)+1;
pSrc = ((uint8_t*)pSrc)+1;
cBytes--;
}
#endif
}
/*! *********************************************************************************
* \brief This function copies the specified number of bytes from the
* source address to the destination address. No attempt is made
* to handle overlapping copies to prevent loss of data.
* The copying is optimized to avoid alignment problems, and attempts
* to copy 32bit numbers optimally.
*
* \param[in] from_ptr Pointer to the source buffer.
*
* \param[in, out] to_ptr Pointer to the destination buffer.
*
* \param[in] number_of_bytes Number of bytes to copy (32 bit value).
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpyAligned32bit (void* to_ptr,
const void* from_ptr,
register uint32_t number_of_bytes)
{
uint8_t* from8_ptr = (uint8_t*)from_ptr;
uint8_t* to8_ptr = (uint8_t*)to_ptr;
uint16_t* from16_ptr = (uint16_t*)from_ptr;
uint16_t* to16_ptr = (uint16_t*)to_ptr;
register uint32_t* from32_ptr = (uint32_t*)from_ptr;
register uint32_t* to32_ptr = (uint32_t*)to_ptr;
register uint32_t loops;
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(to_ptr, number_of_bytes);
#endif
if (number_of_bytes > 3)
{
/* Try to align source on word */
if ((uint32_t)from_ptr & 1)
{
from8_ptr = (uint8_t*)from_ptr;
to8_ptr = (uint8_t*)to_ptr;
*to8_ptr++ = *from8_ptr++;
from_ptr = from8_ptr;
to_ptr = to8_ptr;
--number_of_bytes;
}
/* Try to align source on longword */
if ((uint32_t)from_ptr & 2)
{
from16_ptr = (uint16_t*)from_ptr;
to16_ptr = (uint16_t*)to_ptr;
*to16_ptr++ = *from16_ptr++;
from_ptr = from16_ptr;
to_ptr = to16_ptr;
number_of_bytes -= 2;
}
from32_ptr = (uint32_t*)from_ptr;
to32_ptr = (uint32_t*)to_ptr;
for (loops = number_of_bytes >> 2; loops != 0; loops--)
{
*to32_ptr++ = *from32_ptr++;
}
from_ptr = from32_ptr;
to_ptr = to32_ptr;
}
/* Copy all remaining bytes */
if (number_of_bytes & 2)
{
from16_ptr = (uint16_t*)from_ptr;
to16_ptr = (uint16_t*)to_ptr;
*to16_ptr++ = *from16_ptr++;
from_ptr = from16_ptr;
to_ptr = to16_ptr;
}
if (number_of_bytes & 1)
{
*(uint8_t*)to_ptr = *(uint8_t*)from_ptr;
}
}
/*! *********************************************************************************
* \brief Copy bytes from one buffer to another. The buffers should not overlap.
* The function can copy in either direction. If 'dir' is TRUE, then the function
* works like FLib_MemCpy(). If FALSE, the function swaps the buffer pointers
* before copying.
*
* \param[in, out] pBuf1 Pointer to the destination/source buffer.
*
* \param[in, out] pBuf2 Pointer to the source/destination buffer.
*
* \param[in] dir Direction to copy: pBuf2->pBuf1 if TRUE, pBuf1->pBuf2 if FALSE
*
* \param[in] n Number of bytes to copy.
*
* \post The source and destination buffers must not overlap.
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpyDir (void* pBuf1,
void* pBuf2,
bool_t dir,
uint32_t n)
{
if (dir)
{
FLib_MemCpy (pBuf1, pBuf2, n);
}
else
{
FLib_MemCpy (pBuf2, pBuf1, n);
}
}
/*! *********************************************************************************
* \brief The byte at index i from the source buffer is copied to index ((n-1) - i)
* in the destination buffer (and vice versa).
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpyReverseOrder (void* pDst,
const void* pSrc,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pDst, cBytes);
#endif
if(cBytes)
{
pDst = (uint8_t*)pDst + (uint32_t)(cBytes-1);
while (cBytes)
{
*((uint8_t*)pDst) = *((uint8_t*)pSrc);
pDst = (uint8_t*)pDst-1;
pSrc = (uint8_t*)pSrc+1;
cBytes--;
}
}
}
/*! *********************************************************************************
* \brief This function compares two buffers.
*
* \param[in] pData1 First buffer to compare.
*
* \param[in] pData2 Second buffer to compare.
*
* \param[in] cBytes Number of bytes to compare.
*
* \return This function return TRUE if the buffers are equal and FALSE otherwise.
*
* \post
*
* \remarks
*
********************************************************************************** */
bool_t FLib_MemCmp (const void* pData1, /* IN: First memory block to compare */
const void* pData2, /* IN: Second memory block to compare */
uint32_t cBytes /* IN: Number of bytes to compare. */
)
{
bool_t status = TRUE;
#if gUseToolchainMemFunc_d
if( memcmp(pData1, pData2, cBytes) )
{
status = FALSE;
}
#else
while (cBytes)
{
if ( *((uint8_t *)pData1) != *((uint8_t *)pData2))
{
status = FALSE;
break;
}
pData2 = (uint8_t* )pData2+1;
pData1 = (uint8_t* )pData1+1;
cBytes--;
}
#endif
return status;
}
/*! *********************************************************************************
* \brief This function compares each octet of a given location to a value.
*
* \param [in] pAddr location to be compared
*
* \param [in] val reference value
*
* \param [in] len length of location to be compared
*
* \return This function return TRUE if all octests match and FALSE otherwise.
*
* \post
*
* \remarks
*
********************************************************************************** */
bool_t FLib_MemCmpToVal
(
const void* pAddr,
uint8_t val,
uint32_t len
)
{
while(len)
{
len--;
if(((uint8_t *)pAddr)[len] != val)
{
return FALSE;
}
}
return TRUE;
}
/*! *********************************************************************************
* \brief This function resets all bytes in a specified buffer to a set value.
*
* \param[in,out] pDst Address of the buffer to set.
*
* \param[in] value Set value.
*
* \param[in] cBytes Number of bytes to set in the buffer (maximum 255 bytes).
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemSet (void* pData,
uint8_t value,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pData, cBytes);
#endif
#if gUseToolchainMemFunc_d
memset(pData, value, cBytes);
#else
while (cBytes)
{
((uint8_t* )pData)[--cBytes] = value;
}
#endif
}
/*! *********************************************************************************
* \brief This function copies a buffer,
* possibly into the same overlapping memory as it is taken from
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemInPlaceCpy (void* pDst,
void* pSrc,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pDst, cBytes);
#endif
if (pDst != pSrc)
{
/* Do nothing if copying to same position */
if (pDst < pSrc)
{
/* If dst is before src in memory copy forward */
while (cBytes)
{
*((uint8_t*)pDst) = *((uint8_t*)pSrc);
pDst = ((uint8_t*)pDst)+1;
pSrc = ((uint8_t*)pSrc)+1;
cBytes--;
}
}
else
{
/* If dst is after src in memory copy backward */
while(cBytes)
{
cBytes--;
((uint8_t* )pDst)[cBytes] = ((uint8_t* )pSrc)[cBytes];
}
}
}
}
/*! *********************************************************************************
* \brief This function copies a 16bit value to an unaligned a memory block.
*
* \param[in, out] pDst Pointer to the destination memory block.
*
* \param[in] val16 The value to be copied.
*
********************************************************************************** */
void FLib_MemCopy16Unaligned (void* pDst,
uint16_t val16)
{
uint8_t* pData = (uint8_t*)pDst;
*pData++ = (uint8_t)(val16);
*pData = (uint8_t)(val16 >> 8);
return;
}
/*! *********************************************************************************
* \brief This function copies a 32bit value to an unaligned a memory block.
*
* \param[in, out] pDst Pointer to the destination memory block.
*
* \param[in] val32 The value to be copied.
*
********************************************************************************** */
void FLib_MemCopy32Unaligned (void* pDst,
uint32_t val32)
{
uint8_t* pData = (uint8_t*)pDst;
*pData++ = (uint8_t)(val32);
*pData++ = (uint8_t)(val32 >> 8);
*pData++ = (uint8_t)(val32 >> 16);
*pData++ = (uint8_t)(val32 >> 24);
return;
}
/*! *********************************************************************************
* \brief This function copies a 64bit value to an unaligned a memory block.
*
* \param[in, out] pDst Pointer to the destination memory block.
*
* \param[in] val64 The value to be copied.
*
********************************************************************************** */
void FLib_MemCopy64Unaligned (void* pDst,
uint64_t val64)
{
uint8_t* pData = (uint8_t*)pDst;
*pData++ = (uint8_t)(val64);
*pData++ = (uint8_t)(val64 >> 8);
*pData++ = (uint8_t)(val64 >> 16);
*pData++ = (uint8_t)(val64 >> 24);
*pData++ = (uint8_t)(val64 >> 32);
*pData++ = (uint8_t)(val64 >> 40);
*pData++ = (uint8_t)(val64 >> 48);
*pData = (uint8_t)(val64 >> 56);
return;
}
/*! *********************************************************************************
* \brief This function adds an offset to a pointer.
*
* \param[in,out] pPtr Pointer to the pointer to add the offset to
*
* \param[in] offset Offset to add to the specified pointer.
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_AddOffsetToPointer (void** pPtr,
uint32_t offset)
{
(*pPtr) = ((uint8_t* )*pPtr) + offset;
}
/*! *********************************************************************************
* \brief This function returns the length of a NULL terminated string.
*
* \param[in] str A NULL terminated string
*
* \return the size of string in bytes
*
********************************************************************************** */
uint32_t FLib_StrLen(const char *str)
{
#if gUseToolchainMemFunc_d
return strlen(str);
#else
register uint32_t len=0;
while(*str != '\0')
{
str++;
len++;
}
return len;
#endif
}
#ifdef CPU_JN518X
/*! *********************************************************************************
* \brief This function copies bytes from FLASH to ram.
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \remarks
*
********************************************************************************** */
bool_t FLib_CopyFromFlash(void* pDst,
const void* pSrc,
uint32_t cBytes)
{
bool_t raise_error = FALSE;
TRY
{
FLib_MemCpy(pDst, pSrc, cBytes);
}
CATCH (BUS_EXCEPTION)
{
raise_error = TRUE;
}
YRT;
return raise_error;
}
#else
bool_t FLib_CopyFromFlash(void* pDst,
const void* pSrc,
uint32_t cBytes)
{
FLib_MemCpy(pDst, pSrc, cBytes);
return false;
}
#endif
@@ -0,0 +1,320 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the Function Lib module header file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _FUNCTION_LIB_H_
#define _FUNCTION_LIB_H_
#include "EmbeddedTypes.h"
#include <setjmp.h>
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
#ifndef gUseToolchainMemFunc_d
#define gUseToolchainMemFunc_d 0
#endif
#ifndef gFLib_CheckBufferOverflow_d
#define gFLib_CheckBufferOverflow_d 0
#endif
#define FLib_MemSet16 FLib_MemSet
extern jmp_buf *exception_buf;
#define TRY do {jmp_buf exc_buf; \
jmp_buf *old_buf = exception_buf; \
exception_buf = &exc_buf; \
switch (setjmp(exc_buf)) { case 0:
#define CATCH(x) break; case x:
#define YRT } exception_buf = old_buf; } while(0)
typedef enum {
BUS_EXCEPTION = 1,
} EXCEPTION_ERROR_T;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
#ifdef __cplusplus
extern "C" {
#endif
/*! *********************************************************************************
* \brief Copy the content of one memory block to another. The amount of data to copy
* must be specified in number of bytes.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] pSrc Pointer to source memory block
* \param[in] cBytes Number of bytes to copy
*
********************************************************************************** */
void FLib_MemCpy (void* pDst,
const void* pSrc,
uint32_t cBytes
);
void FLib_MemCpyAligned32bit (void* to_ptr,
const void* from_ptr,
register uint32_t number_of_bytes);
void FLib_MemCpyDir (void* pBuf1,
void* pBuf2,
bool_t dir,
uint32_t n);
/*! *********************************************************************************
* \brief Copy bytes. The byte at index i from the source buffer is copied to index
* ((n-1) - i) in the destination buffer (and vice versa).
*
* \param[out] pDst Pointer to destination memory block
* \param[in] pSrc Pointer to source memory block
* \param[in] cBytes Number of bytes to copy
*
********************************************************************************** */
void FLib_MemCpyReverseOrder (void* pDst,
const void* pSrc,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Compare two memory blocks. The number of bytes to compare must be specified.
* If the blocks are equal byte by byte, the function returns TRUE,
* and FALSE otherwise.
*
* \param[in] pData1 First memory block to compare
* \param[in] pData2 Second memory block to compare
* \param[in] cBytes Number of bytes to compare
*
* \return TRUE if memory areas are equal. FALSE othwerwise.
*
********************************************************************************** */
bool_t FLib_MemCmp (const void* pData1,
const void* pData2,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Compare each byte of a memory block to a given value. The number of bytes to compare
must be specified.
* If all the bytes are equal to the given value, the function returns TRUE,
* and FALSE otherwise.
*
* \param[in] pAddr Location to be compared
* \param[in] val Reference value
* \param[in] length Number of bytes to compare
*
* \return TRUE if all bytes match and FALSE otherwise.
*
********************************************************************************** */
bool_t FLib_MemCmpToVal(const void* pAddr,
uint8_t val,
uint32_t len
);
/*! *********************************************************************************
* \brief Reset bytes in a memory block to a certain value. The value, and the number
* of bytes to be set, are supplied as arguments.
*
* \param[in] pData Pointer to memory block to reset
* \param[in] value Value that memory block will be set to
* \param[in] cBytes Number of bytes to set
*
********************************************************************************** */
void FLib_MemSet (void* pData,
uint8_t value,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Copy bytes, possibly into the same overlapping memory as it is taken from
*
* \param[out] pDst Pointer to destination memory block
* \param[in] pSrc Pointer to source memory block
* \param[in] cBytes Number of bytes to copy
*
********************************************************************************** */
void FLib_MemInPlaceCpy (void* pDst,
void* pSrc,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Copies a 16bit value to an unaligned a memory block.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] val16 The 16-bit value to be copied
*
********************************************************************************** */
void FLib_MemCopy16Unaligned (void* pDst,
uint16_t val16
);
/*! *********************************************************************************
* \brief Copies a 32bit value to an unaligned a memory block.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] val32 The 32-bit value to be copied
*
********************************************************************************** */
void FLib_MemCopy32Unaligned (void* pDst,
uint32_t val32
);
/*! *********************************************************************************
* \brief Copies a 64bit value to an unaligned a memory block.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] val64 The 64-bit value to be copied
*
********************************************************************************** */
void FLib_MemCopy64Unaligned (void* pDst,
uint64_t val64
);
bool_t FLib_CopyFromFlash(void* pDst,
const void* pSrc,
uint32_t cBytes);
/*! *********************************************************************************
* \brief Add an offset to a pointer.
*
* \param[out] pPtr Pointer to the pointer to be updated
* \param[in] offset The offset(in bytes) to be added
*
********************************************************************************** */
void FLib_AddOffsetToPointer (void** pPtr,
uint32_t offset);
#define FLib_AddOffsetToPtr(pPtr,offset) FLib_AddOffsetToPointer((void**)(pPtr),(offset))
/*! *********************************************************************************
* \brief This function returns the length of a NULL terminated string.
*
* \param[in] str A NULL terminated string
*
* \return the size of string in bytes
*
********************************************************************************** */
uint32_t FLib_StrLen(const char *str);
/*! *********************************************************************************
* \brief Compare two bytes.
*
* \param[in] pCmp1 pointer to the first 2-byte compare value
* \param[in] pCmp2 pointer to the second 2-byte compare value
*
* \return TRUE if the two bytes are equal, and FALSE otherwise.
*
********************************************************************************** */
#define FLib_Cmp2Bytes(pCmp1, pCmp2) ((((uint8_t *)(pCmp1))[0] == ((uint8_t *)(pCmp2))[0]) && \
(((uint8_t *)(pCmp1))[1] == ((uint8_t *)(pCmp2))[1]))
/*! *********************************************************************************
* \brief Returns the maximum value of arguments a and b.
*
* \return The maximum value of arguments a and b
*
* \remarks
* The primitive should must be implemented as a macro, as it should be possible to
* evaluate the result on compile time if the arguments are constants.
*
********************************************************************************** */
#define FLib_GetMax(a,b) (((a) > (b)) ? (a) : (b))
/*! *********************************************************************************
* \brief Returns the minimum value of arguments a and b.
*
* \return The minimum value of arguments a and b
*
* \remarks
* The primitive should must be implemented as a macro, as it should be possible to
* evaluate the result on compile time if the arguments are constants.
*
********************************************************************************** */
#define FLib_GetMin(a,b) (((a) < (b)) ? (a) : (b))
#ifdef __GNUC__
#define _CLZ(x) __builtin_clz(x)
#endif
#if defined (__IAR_SYSTEMS_ICC__)
#define _CLZ(x) __CLZ(x)
#endif
#define _BSR(x) (31 - _CLZ(x))
static inline uint32_t Flib_Log2(uint32_t x)
{
uint32_t msb = _BSR(x);
/* if not a power of 2, round to next so that x remains <= (1<<msb) */
if (x > (1<< msb)) msb++;
return msb;
}
#define LOG_1(n) (((n) >= 2) ? 1 : 0)
#define LOG_2(n) (((n) >= 1<<2) ? (2 + LOG_1((n)>>2)) : LOG_1(n))
#define LOG_4(n) (((n) >= 1<<4) ? (4 + LOG_2((n)>>4)) : LOG_2(n))
#define LOG_8(n) (((n) >= 1<<8) ? (8 + LOG_4((n)>>8)) : LOG_4(n))
#define LOG(n) (((n) >= 1<<16) ? (16 + LOG_8((n)>>16)) : LOG_8(n))
#define MASK_LOG(log) ((1<<(log))-1)
#define ROUND_FLOOR(x, log) (((x) >> (log)) << (log))
#define ROUND_CEIL(x, log) ((((x) + MASK_LOG(log) ) >> (log)) << (log))
#define IS_POW_OF_TWO(x) (((x) & ((x)-1)) == 0)
#ifdef __cplusplus
}
#endif
#endif /* _FUNCTION_LIB_H_ */
@@ -0,0 +1,561 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the source file for the linked lists part of the Utils package.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "GenericList.h"
#include "fsl_os_abstraction.h"
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief Initialises the list descriptor.
*
* \param[in] list - List handle to init.
* max - Maximum number of elements in list. 0 for unlimited.
*
* \return void.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
void ListInit(listHandle_t list, uint32_t max)
{
list->head = NULL;
list->tail = NULL;
list->max = max;
list->size = 0;
}
/*! *********************************************************************************
* \brief Gets the list that contains the given element.
*
* \param[in] element - Handle of the element.
*
* \return NULL if element is orphan.
* Handle of the list the element is inserted into.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listHandle_t ListGetList(listElementHandle_t element)
{
return element->list;
}
/*! *********************************************************************************
* \brief Links element to the tail of the list.
*
* \param[in] list - ID of list to insert into.
* element - element to add
*
* \return gListFull_c if list is full.
* gListOk_c if insertion was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListAddTail(listHandle_t list, listElementHandle_t element)
{
OSA_InterruptDisable();
if( (list->max != 0) && (list->max == list->size) )
{
OSA_InterruptEnable();
return gListFull_c;
}
if(list->size == 0)
{
list->head = element;
}
else
{
list->tail->next = element;
}
element->prev = list->tail;
element->next = NULL;
element->list = list;
list->tail = element;
list->size++;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Links element to the head of the list.
*
* \param[in] list - ID of list to insert into.
* element - element to add
*
* \return gListFull_c if list is full.
* gListOk_c if insertion was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListAddHead(listHandle_t list, listElementHandle_t element)
{
OSA_InterruptDisable();
if( (list->max != 0) && (list->max == list->size) )
{
OSA_InterruptEnable();
return gListFull_c;
}
if(list->size == 0)
{
list->tail = element;
}
else
{
list->head->prev = element;
}
element->next = list->head;
element->prev = NULL;
element->list = list;
list->head = element;
list->size++;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Unlinks element from the head of the list.
*
* \param[in] list - ID of list to remove from.
*
* \return NULL if list is empty.
* ID of removed element(pointer) if removal was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListRemoveHead(listHandle_t list)
{
listElementHandle_t element;
OSA_InterruptDisable();
if((NULL == list) || (list->size == 0))
{
OSA_InterruptEnable();
return NULL; /*List is empty*/
}
element = list->head;
list->size--;
if(list->size == 0)
{
list->tail = NULL;
}
else
{
element->next->prev = NULL;
}
list->head = element->next; /*Is NULL if element is head*/
element->list = NULL;
OSA_InterruptEnable();
return element;
}
/*! *********************************************************************************
* \brief Gets head element ID.
*
* \param[in] list - ID of list.
*
* \return NULL if list is empty.
* ID of head element if list is not empty.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListGetHead(listHandle_t list)
{
return list->head;
}
/*! *********************************************************************************
* \brief Gets next element ID.
*
* \param[in] element - ID of the element.
*
* \return NULL if element is tail.
* ID of next element if exists.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListGetNext(listElementHandle_t element)
{
return element->next;
}
/*! *********************************************************************************
* \brief Gets previous element ID.
*
* \param[in] element - ID of the element.
*
* \return NULL if element is head.
* ID of previous element if exists.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListGetPrev(listElementHandle_t element)
{
return element->prev;
}
/*! *********************************************************************************
* \brief Unlinks an element from its list.
*
* \param[in] element - ID of the element to remove.
*
* \return gOrphanElement_c if element is not part of any list.
* gListOk_c if removal was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListRemoveElement(listElementHandle_t element)
{
if(element->list == NULL)
{
return gOrphanElement_c; /*Element was previusly removed or never added*/
}
OSA_InterruptDisable();
if(element->prev == NULL) /*Element is head or solo*/
{
element->list->head = element->next; /*is null if solo*/
}
if(element->next == NULL) /*Element is tail or solo*/
{
element->list->tail = element->prev; /*is null if solo*/
}
if(element->prev != NULL) /*Element is not head*/
{
element->prev->next = element->next;
}
if(element->next != NULL) /*Element is not tail*/
{
element->next->prev = element->prev;
}
element->list->size--;
element->list = NULL;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Links an element in the previous position relative to a given member
* of a list.
*
* \param[in] element - ID of a member of a list.
* newElement - new element to insert before the given member.
*
* \return gOrphanElement_c if element is not part of any list.
* gListFull_c if list is full.
* gListOk_c if insertion was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListAddPrevElement(listElementHandle_t element, listElementHandle_t newElement)
{
if(element->list == NULL)
{
return gOrphanElement_c; /*Element was previusly removed or never added*/
}
OSA_InterruptDisable();
if( (element->list->max != 0) && (element->list->max == element->list->size) )
{
OSA_InterruptEnable();
return gListFull_c;
}
if(element->prev == NULL) /*Element is list head*/
{
element->list->head = newElement;
}
else
{
element->prev->next = newElement;
}
newElement->list = element->list;
element->list->size++;
newElement->next = element;
newElement->prev = element->prev;
element->prev = newElement;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Gets the current size of a list.
*
* \param[in] list - ID of the list.
*
* \return Current size of the list.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
uint32_t ListGetSize(listHandle_t list)
{
return list->size;
}
/*! *********************************************************************************
* \brief Gets the number of free places in the list.
*
* \param[in] list - ID of the list.
*
* \return Available size of the list.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
uint32_t ListGetAvailable(listHandle_t list)
{
return (list->max - list->size);
}
/*! *********************************************************************************
* \brief Creates, tests and deletes a list. Any error that occurs will trap the
* CPU in a while(1) loop.
*
* \param[in] void.
*
* \return gListOk_c.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
/* To be removed or rewritten to remove MemManager dependency. */
#if 0
listStatus_t ListTest()
{
listHandle_t list;
listElementHandle_t element, newElement;
uint32_t i,freeBlocks;
const uint32_t max = 10;
freeBlocks = MEM_GetAvailableFwkBlocks(0);
/*create list*/
list = ListCreate(max);
LIST_ASSERT(list != NULL);
/*add elements*/
for(i=0; i<max; i++)
{
element = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListAddHead(list, element) == gListOk_c);
LIST_ASSERT(list->head == element)
ListRemoveHead(list);
LIST_ASSERT(ListAddTail(list, element) == gListOk_c);
LIST_ASSERT(list->tail == element);
if(ListGetSize(list) == 1)
{
LIST_ASSERT(list->head == element);
}
else
{
LIST_ASSERT(list->head != element);
}
}
LIST_ASSERT(ListGetSize(list) == max);
/*add one more element*/
element = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListAddTail(list, element) == gListFull_c);
list->max = 0;
LIST_ASSERT(ListAddTail(list, element) == gListOk_c);
LIST_ASSERT(ListGetSize(list) == max+1);
/*remove the extra element*/
element = ListRemoveHead(list);
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListGetSize(list) == max);
LIST_ASSERT(MEM_BufferFree(element) == MEM_SUCCESS_c);
list->max = max;
/*parse elements*/
element = ListGetHead(list);
LIST_ASSERT(element != NULL);
for(i=0; i<(max-1); i++)
{
element = ListGetNext(element);
LIST_ASSERT(element != NULL);
}
LIST_ASSERT(element == list->tail);
LIST_ASSERT(ListGetNext(element) == NULL);
/*Reverse parse elements*/
for(i=0; i<(max-1); i++)
{
element = ListGetPrev(element);
LIST_ASSERT(element != NULL);
}
LIST_ASSERT(element == list->head);
LIST_ASSERT(ListGetPrev(element) == NULL);
/*Add prev*/
element = ListGetHead(list);
LIST_ASSERT(element != NULL);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListFull_c);
LIST_ASSERT(ListGetHead(list) == element);
list->max = 0;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListOk_c);
LIST_ASSERT(ListGetHead(list) == newElement);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
element = list->head->next->next;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListOk_c);
LIST_ASSERT(list->head->next->next == newElement);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
element = list->tail;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListOk_c);
LIST_ASSERT(list->tail->prev == newElement);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
element = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(element != NULL);
element->list = NULL;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gOrphanElement_c);
MEM_BufferFree(newElement);
MEM_BufferFree(element);
LIST_ASSERT(ListGetSize(list) == max+3);
/*Remove element*/
element = ListGetHead(list);
LIST_ASSERT(element == list->head);
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
LIST_ASSERT(list->head != element);
LIST_ASSERT(ListRemoveElement(element) == gOrphanElement_c);
MEM_BufferFree(element);
element = ListGetHead(list)->next->next;
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
MEM_BufferFree(element);
element = list->tail;
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
LIST_ASSERT(list->tail != element);
MEM_BufferFree(element);
LIST_ASSERT(ListGetSize(list) == max);
list->max = max;
for(i=0; i<(max-1); i++)
{
element = ListRemoveHead(list);
LIST_ASSERT(element != NULL);
MEM_BufferFree(element);
}
element = ListGetHead(list);
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
LIST_ASSERT(list->head == NULL);
LIST_ASSERT(list->tail == NULL);
LIST_ASSERT(element->list == NULL);
MEM_BufferFree(element);
/*List is empty here.*/
LIST_ASSERT(ListGetSize(list) == 0);
element = ListRemoveHead(list);
LIST_ASSERT(element == NULL);
element = ListGetHead(list);
LIST_ASSERT(element == NULL);
MEM_BufferFree(list);
/*Did we produce a memory leak?*/
LIST_ASSERT(freeBlocks == MEM_GetAvailableFwkBlocks(0));
return gListOk_c;
}
#else
listStatus_t ListTest(void)
{
return gListOk_c;
}
#endif
@@ -0,0 +1,90 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the header file for the linked lists part of the Utils package.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _GENERIC_LIST_H_
#define _GENERIC_LIST_H_
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
/*! *********************************************************************************
*************************************************************************************
* Public macro definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
typedef enum
{
gListOk_c = 0,
gListFull_c,
gListEmpty_c,
gOrphanElement_c
}listStatus_t;
typedef struct list_tag
{
struct listElement_tag *head;
struct listElement_tag *tail;
uint16_t size;
uint16_t max;
}list_t, *listHandle_t;
typedef struct listElement_tag
{
struct listElement_tag *next;
struct listElement_tag *prev;
struct list_tag *list;
}listElement_t, *listElementHandle_t;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
void ListInit(listHandle_t list, uint32_t max);
listHandle_t ListGetList(listElementHandle_t element);
listStatus_t ListAddHead(listHandle_t list, listElementHandle_t element);
listStatus_t ListAddTail(listHandle_t list, listElementHandle_t element);
listElementHandle_t ListRemoveHead(listHandle_t list);
listElementHandle_t ListGetHead(listHandle_t list);
listElementHandle_t ListGetNext(listElementHandle_t element);
listElementHandle_t ListGetPrev(listElementHandle_t element);
listStatus_t ListRemoveElement(listElementHandle_t element);
listStatus_t ListAddPrevElement(listElementHandle_t element, listElementHandle_t newElement);
uint32_t ListGetSize(listHandle_t list);
uint32_t ListGetAvailable(listHandle_t list);
listStatus_t ListTest(void);
/*! *********************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
********************************************************************************** */
#ifdef DEBUG_ASSERT
#define LIST_ASSERT(condition) if(!(condition))while(1);
#else
#define LIST_ASSERT(condition) (void)(condition);
#endif
#endif /*_GENERIC_LIST_H_*/
@@ -0,0 +1,223 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the header file for the Memory Manager interface.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _MEM_MANAGER_H_
#define _MEM_MANAGER_H_
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include <stddef.h>
#include "EmbeddedTypes.h"
#include "GenericList.h"
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
/*Defines pools by block size and number of blocks. Must be alligned to 4 bytes.*/
#ifndef PoolsDetails_c
#define PoolsDetails_c \
_block_size_ 64 _number_of_blocks_ 8 _pool_id_(0) _eol_ \
_block_size_ 128 _number_of_blocks_ 2 _pool_id_(0) _eol_ \
_block_size_ 256 _number_of_blocks_ 6 _pool_id_(0) _eol_
#endif
#if defined (__IAR_SYSTEMS_ICC__)
/* __get_LR() declaration not included to avoid issues with different versions of IAR compiler */
#elif defined(__GNUC__)
#define __get_LR() __builtin_return_address(0)
#elif defined(__CC_ARM)
#define __get_LR() __return_address()
#endif
/* If a buffer (that is not allocated forever using MEM_BufferAllocForever()) is not freed
in MEM_CheckMemBufferThreshold_c ms, the device will enter into panic */
#ifndef MEM_CheckMemBufferThreshold_c
#define MEM_CheckMemBufferThreshold_c 120000 /* ms */
#endif
/* How often the device should check if the above threshold expired */
#ifndef MEM_CheckMemBufferInterval_c
#define MEM_CheckMemBufferInterval_c 15000 /* ms */
#endif
/* Default memory allocator */
#ifndef MEM_BufferAlloc
#define MEM_BufferAlloc(numBytes) MEM_BufferAllocWithId(numBytes, 0, (void*)__get_LR())
#endif
/* Allocate a block from the memory pools forever.*/
#define MEM_BufferAllocForever(numBytes,poolId) MEM_BufferAllocWithId(numBytes, poolId, (void*)((uintptr_t)__get_LR() | 0x80000000 ))
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
/*Defines statuses used in MEM_BufferAlloc and MEM_BufferFree*/
typedef enum
{
MEM_SUCCESS_c = 0, /* No error occurred */
MEM_INIT_ERROR_c, /* Memory initialization error */
MEM_ALLOC_ERROR_c, /* Memory allocation error */
MEM_FREE_ERROR_c, /* Memory free error */
MEM_UNKNOWN_ERROR_c /* something bad has happened... */
}memStatus_t;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
/*Initialises the Memory Manager.*/
memStatus_t MEM_Init(void);
/*Returns the number of available blocks that fit the given size.*/
uint32_t MEM_GetAvailableBlocks(uint32_t size);
/*Frees the givem buffer.*/
memStatus_t MEM_BufferFree(void* buffer);
/*Returns the allocated buffer of the given size.*/
void* MEM_BufferAllocWithId(uint32_t numBytes , uint8_t poolId, void *pCaller);
/*Returns the size of a given buffer*/
uint16_t MEM_BufferGetSize(void* buffer);
/*Performs a write-read-verify test accross all pools*/
uint32_t MEM_WriteReadTest(void);
#if (defined MULTICORE_MEM_MANAGER) && ((defined MULTICORE_HOST) || (defined MULTICORE_BLACKBOX))
/*Free a buffer on the Master core*/
memStatus_t MEM_BufferFreeOnMaster(uint8_t * pBuff);
/*Free a buffer on the Slave core*/
memStatus_t MEM_BufferFreeOnSlave(uint8_t * pBuff);
#endif
/*! *********************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
********************************************************************************** */
#if defined(MEM_TRACKING) && defined(DEBUG_ASSERT)
#define MEM_ASSERT(condition) if(!(condition))while(1);
#else
#define MEM_ASSERT(condition) (void)(condition);
#endif
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
#ifdef MEM_STATISTICS
/*Statistics structure definition. Used by pools.*/
typedef struct poolStat_tag
{
uint16_t numBlocks;
uint16_t allocatedBlocks;
uint16_t allocatedBlocksPeak;
uint16_t allocationFailures;
uint16_t freeFailures;
#ifdef MEM_TRACKING
uint16_t poolFragmentWaste;
uint16_t poolFragmentWastePeak;
uint16_t poolFragmentMinWaste;
uint16_t poolFragmentMaxWaste;
#endif /*MEM_TRACKING*/
} poolStat_t;
#endif /*MEM_STATISTICS*/
#ifdef MEM_TRACKING
/*Definition for alloc indicators. Used in buffer tracking.*/
typedef enum
{
MEM_TRACKING_FREE_c = 0,
MEM_TRACKING_ALLOC_c,
}memTrackingStatus_t;
/*Tracking structure definition.*/
typedef PACKED_STRUCT BlockTracking_tag
{
void *blockAddr; /*Addr of Msg, not that this pointer is
4 byte bigger than the addr in the pool
has the header of the msg is 4 bytes */
uint16_t blockSize; /*Size of block in bytes.*/
uint16_t fragmentWaste; /*Size requested by allocator.*/
void *allocAddr; /*Return address of last Alloc made */
void *freeAddr; /*Return address of last Free made */
uint16_t allocCounter; /*No of time this msg has been allocated */
uint16_t freeCounter; /*No of time this msg has been freed */
memTrackingStatus_t allocStatus; /*1 if currently allocated, 0 if currently free */
uint32_t timeStamp;
void *pCaller;
}blockTracking_t;
#endif /*MEM_TRACKING*/
/*Header description for buffers.*/
typedef struct listHeader_tag
{
listElement_t link;
struct pools_tag *pParentPool;
}listHeader_t;
/*Buffer pools. Used by most functions*/
typedef struct pools_tag
{
list_t anchor; /* MUST be first element in pools_t struct */
uint16_t nextBlockSize;
uint16_t blockSize;
uint16_t poolId;
#ifdef MEM_STATISTICS
poolStat_t poolStatistics;
#endif /*MEM_STATISTICS*/
uint8_t numBlocks;
uint8_t allocatedBlocks;
}pools_t;
/*Buffer pool description. Used by MM_Init() for creating the buffer pools. */
typedef struct poolInfo_tag
{
uint16_t blockSize;
uint16_t poolSize;
uint16_t poolId;
uint8_t padding[2];
}poolInfo_t;
/*! *********************************************************************************
*************************************************************************************
* Private prototypes
*************************************************************************************
********************************************************************************** */
#ifdef MEM_TRACKING
uint8_t MEM_Track(listHeader_t *block, memTrackingStatus_t alloc, uint32_t address, uint16_t requestedSize, void *pCaller);
uint8_t MEM_BufferCheck(uint8_t *p, uint32_t size);
void MEM_CheckIfMemBuffersAreFreed(void);
/* The timestamp function used by MEM Manager for debug purpose.
The timestamp must be in milliseconds! */
#if defined(__IAR_SYSTEMS_ICC__)
extern __weak uint32_t MEM_GetTimeStamp(void);
#elif defined(__GNUC__)
extern __attribute__((weak)) uint32_t MEM_GetTimeStamp(void);
#endif
#endif /*MEM_TRACKING*/
#endif /* _MEM_MANAGER_H_ */
@@ -0,0 +1,815 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the source file for the Memory Manager.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
#include "fsl_os_abstraction.h"
#include "Panic.h"
#include "MemManager.h"
#include "FunctionLib.h"
/*! *********************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
********************************************************************************** */
#define _block_size_ {
#define _number_of_blocks_ ,
#define _pool_id_(a) , a ,
#define _eol_ },
poolInfo_t poolInfo[] =
{
PoolsDetails_c
{0, 0, 0} /*termination tag*/
};
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#define _block_size_ (sizeof(listHeader_t)+
#define _number_of_blocks_ ) *
#define _eol_ +
#define _pool_id_(a)
#define heapSize_c (PoolsDetails_c 0)
/* Heap */
uint32_t memHeap[heapSize_c/sizeof(uint32_t)];
const uint32_t heapSize = heapSize_c;
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#define _block_size_ 0 *
#define _number_of_blocks_ + 0 *
#define _eol_ + 1 +
#define _pool_id_(a)
#define poolCount (PoolsDetails_c 0)
/* Memory pool info and anchors. */
pools_t memPools[poolCount];
#ifdef MEM_STATISTICS
pools_t memPoolsSnapShot[poolCount];
#endif
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#ifdef MEM_TRACKING
#ifndef NUM_OF_TRACK_PTR
#define NUM_OF_TRACK_PTR 1
#endif
#define _block_size_ 0*
#define _number_of_blocks_ +
#define _eol_ +
#define _pool_id_(a)
#define mTotalNoOfMsgs_d (PoolsDetails_c 0)
static const uint16_t mTotalNoOfMsgs_c = mTotalNoOfMsgs_d;
blockTracking_t memTrack[mTotalNoOfMsgs_d];
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#endif /*MEM_TRACKING*/
/* Free messages counter. Not used by module. */
uint16_t gFreeMessagesCount;
#ifdef MEM_STATISTICS
uint16_t gFreeMessagesCountMin = 0xFFFF;
uint16_t gTotalFragmentWaste = 0;
uint16_t gMaxTotalFragmentWaste = 0;
#endif
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function initializes the message module private variables.
* Must be called at boot time, or if device is reset.
*
* \param[in] none
*
* \return MEM_SUCCESS_c if initialization is successful. (It's always successful).
*
********************************************************************************** */
memStatus_t MEM_Init(void)
{
poolInfo_t *pPoolInfo = poolInfo; /* IN: Memory layout information */
pools_t *pPools = memPools;/* OUT: Will be initialized with requested memory pools. */
uint8_t *pHeap = (uint8_t *)memHeap;/* IN: Memory heap.*/
uint16_t poolN;
#ifdef MEM_TRACKING
uint16_t memTrackIndex = 0;
#endif /*MEM_TRACKING*/
gFreeMessagesCount = 0;
for(;;)
{
poolN = pPoolInfo->poolSize;
ListInit((listHandle_t)&pPools->anchor, poolN);
#ifdef MEM_STATISTICS
pPools->poolStatistics.numBlocks = 0;
pPools->poolStatistics.allocatedBlocks = 0;
pPools->poolStatistics.allocatedBlocksPeak = 0;
pPools->poolStatistics.allocationFailures = 0;
pPools->poolStatistics.freeFailures = 0;
#ifdef MEM_TRACKING
pPools->poolStatistics.poolFragmentWaste = 0;
pPools->poolStatistics.poolFragmentWastePeak = 0;
pPools->poolStatistics.poolFragmentMinWaste = 0xFFFF;
pPools->poolStatistics.poolFragmentMaxWaste = 0;
#endif /*MEM_TRACKING*/
#endif /*MEM_STATISTICS*/
while(poolN)
{
/* Add block to list of free memory. */
ListAddTail((listHandle_t)&pPools->anchor, (listElementHandle_t)&((listHeader_t *)pHeap)->link);
((listHeader_t *)pHeap)->pParentPool = pPools;
#ifdef MEM_STATISTICS
pPools->poolStatistics.numBlocks++;
#endif /*MEM_STATISTICS*/
pPools->numBlocks++;
gFreeMessagesCount++;
#ifdef MEM_TRACKING
memTrack[memTrackIndex].blockAddr = (void *)(pHeap + sizeof(listHeader_t));
memTrack[memTrackIndex].blockSize = pPoolInfo->blockSize;
memTrack[memTrackIndex].fragmentWaste = 0;
memTrack[memTrackIndex].allocAddr = NULL;
memTrack[memTrackIndex].allocCounter = 0;
memTrack[memTrackIndex].allocStatus = MEM_TRACKING_FREE_c;
memTrack[memTrackIndex].freeAddr = NULL;
memTrack[memTrackIndex].freeCounter = 0;
memTrackIndex++;
#endif /*MEM_TRACKING*/
/* Add block size (without list header)*/
pHeap += pPoolInfo->blockSize + sizeof(listHeader_t);
poolN--;
}
pPools->blockSize = pPoolInfo->blockSize;
pPools->poolId = pPoolInfo->poolId;
pPools->nextBlockSize = (pPoolInfo+1)->blockSize;
if(pPools->nextBlockSize == 0)
{
break;
}
pPools++;
pPoolInfo++;
}
return MEM_SUCCESS_c;
}
/*! *********************************************************************************
* \brief This function returns the number of available blocks greater or
* equal to the given size.
*
* \param[in] size - Size of blocks to check for availability.
*
* \return Number of available blocks greater or equal to the given size.
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
uint32_t MEM_GetAvailableBlocks
(
uint32_t size
)
{
pools_t *pPools = memPools;
uint32_t pTotalCount = 0;
for(;;)
{
if(size <= pPools->blockSize)
{
pTotalCount += ListGetSize((listHandle_t)&pPools->anchor);
}
if(pPools->nextBlockSize == 0)
{
break;
}
pPools++;
}
return pTotalCount;
}
/*! *********************************************************************************
* \brief Allocate a block from the memory pools. The function uses the
* numBytes argument to look up a pool with adequate block sizes.
* \param[in] numBytes - Size of buffer to allocate.
*
* \return Pointer to the allocated buffer, NULL if failed.
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
/*! *********************************************************************************
* \brief Allocate a block from the memory pools. The function uses the
* numBytes argument to look up a pool with adequate block sizes.
* \param[in] numBytes - Size of buffer to allocate.
* \param[in] poolId - The ID of the pool where to search for a free buffer.
* \param[in] pCaller - pointer to the caller function (Debug purpose)
*
* \return Pointer to the allocated buffer, NULL if failed.
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
void* MEM_BufferAllocWithId
(
uint32_t numBytes,
uint8_t poolId,
void *pCaller
)
{
#ifdef MEM_TRACKING
/* Save the Link Register */
volatile uint32_t savedLR = (uint32_t) __get_LR();
#endif
#if defined(MEM_TRACKING) || defined(MEM_DEBUG_OUT_OF_MEMORY)
uint16_t requestedSize = numBytes;
#endif /*MEM_TRACKING*/
#ifdef MEM_STATISTICS
bool_t allocFailure = FALSE;
#endif
pools_t *pPools = memPools;
listHeader_t *pBlock;
OSA_InterruptDisable();
while(numBytes)
{
if( (numBytes <= pPools->blockSize) && (poolId == pPools->poolId) )
{
pBlock = (listHeader_t *)ListRemoveHead((listHandle_t)&pPools->anchor);
if(NULL != pBlock)
{
pBlock++;
gFreeMessagesCount--;
pPools->allocatedBlocks++;
#ifdef MEM_STATISTICS
if(gFreeMessagesCount < gFreeMessagesCountMin)
{
gFreeMessagesCountMin = gFreeMessagesCount;
}
pPools->poolStatistics.allocatedBlocks++;
if ( pPools->poolStatistics.allocatedBlocks > pPools->poolStatistics.allocatedBlocksPeak )
{
pPools->poolStatistics.allocatedBlocksPeak = pPools->poolStatistics.allocatedBlocks;
}
MEM_ASSERT(pPools->poolStatistics.allocatedBlocks <= pPools->poolStatistics.numBlocks);
#endif /*MEM_STATISTICS*/
#ifdef MEM_TRACKING
MEM_Track(pBlock, MEM_TRACKING_ALLOC_c, savedLR, requestedSize, pCaller);
#endif /*MEM_TRACKING*/
OSA_InterruptEnable();
return pBlock;
}
else
{
#ifdef MEM_STATISTICS
if(!allocFailure)
{
pPools->poolStatistics.allocationFailures++;
allocFailure = TRUE;
}
#endif /*MEM_STATISTICS*/
if(numBytes > pPools->nextBlockSize)
{
break;
}
/* No more blocks of that size, try next size. */
numBytes = pPools->nextBlockSize;
}
}
/* Try next pool*/
if(pPools->nextBlockSize)
{
pPools++;
}
else
{
numBytes = 0;
}
}
#ifdef MEM_DEBUG_OUT_OF_MEMORY
if (requestedSize)
{
panic( 0, (uint32_t)MEM_BufferAllocWithId, 0, 0);
}
#endif
OSA_InterruptEnable();
return NULL;
}
/*! *********************************************************************************
* \brief Deallocate a memory block by putting it in the corresponding pool
* of free blocks.
*
* \param[in] buffer - Pointer to buffer to deallocate.
*
* \return MEM_SUCCESS_c if deallocation was successful, MEM_FREE_ERROR_c if not.
*
* \pre Memory manager must be previously initialized.
*
* \remarks Never deallocate the same buffer twice.
*
********************************************************************************** */
#if (defined MULTICORE_MEM_MANAGER) && ((defined MULTICORE_HOST) || (defined MULTICORE_BLACKBOX))
#if defined MULTICORE_HOST
memStatus_t MEM_BufferFreeOnMaster
#elif defined MULTICORE_BLACKBOX
memStatus_t MEM_BufferFreeOnSlave
#endif /* MULTICORE_HOST */
(
uint8_t *pBuff
)
{
#ifdef MEM_TRACKING
/* Save the Link Register */
volatile uint32_t savedLR = (uint32_t) __get_LR();
#endif /*MEM_TRACKING*/
listHeader_t *pHeader;
if( pBuff == NULL )
{
return MEM_FREE_ERROR_c;
}
pHeader = (listHeader_t *)pBuff-1;
if( ((uint8_t*)pHeader < (uint8_t*)memHeap) || ((uint8_t*)pHeader > ((uint8_t*)memHeap + sizeof(memHeap))) )
{
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
}
else
{
return MEM_BufferFree(pBuff);
}
}
#endif /* (defined MULTICORE_MEM_MANAGER) && ((defined MULTICORE_HOST) || (defined MULTICORE_BLACKBOX)) */
memStatus_t MEM_BufferFree
(
void* buffer /* IN: Block of memory to free*/
)
{
#ifdef MEM_TRACKING
/* Save the Link Register */
volatile uint32_t savedLR = (uint32_t) __get_LR();
#endif /*MEM_TRACKING*/
listHeader_t *pHeader;
pools_t *pParentPool;
pools_t *pool;
if( buffer == NULL )
{
return MEM_FREE_ERROR_c;
}
pHeader = (listHeader_t *)buffer-1;
if( ((uint8_t*)pHeader < (uint8_t*)memHeap) || ((uint8_t*)pHeader > ((uint8_t*)memHeap + sizeof(memHeap))) )
{
#if (defined MULTICORE_MEM_MANAGER) && (defined MULTICORE_BLACKBOX)
return MEM_BufferFreeOnMaster(buffer);
#elif (defined MULTICORE_MEM_MANAGER) && (defined MULTICORE_HOST)
return MEM_BufferFreeOnSlave(buffer);
#else
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
#endif
}
OSA_InterruptDisable();
pParentPool = (pools_t *)pHeader->pParentPool;
pool = memPools;
for(;;)
{
if (pParentPool == pool)
{
break;
}
if(pool->nextBlockSize == 0)
{
/* The parent pool was not found! This means that the memory buffer is corrupt or
that the MEM_BufferFree() function was called with an invalid parameter */
#ifdef MEM_STATISTICS
pParentPool->poolStatistics.freeFailures++;
#endif /*MEM_STATISTICS*/
OSA_InterruptEnable();
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
}
pool++;
}
if( pHeader->link.list != NULL )
{
/* The memory buffer appears to be enqueued in a linked list.
This list may be the free memory buffers pool, or another list. */
#ifdef MEM_STATISTICS
pParentPool->poolStatistics.freeFailures++;
#endif /*MEM_STATISTICS*/
OSA_InterruptEnable();
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
}
gFreeMessagesCount++;
ListAddTail((listHandle_t)&pParentPool->anchor, (listElementHandle_t)&pHeader->link);
pParentPool->allocatedBlocks--;
#ifdef MEM_STATISTICS
MEM_ASSERT(pParentPool->poolStatistics.allocatedBlocks > 0);
pParentPool->poolStatistics.allocatedBlocks--;
#endif /*MEM_STATISTICS*/
#ifdef MEM_TRACKING
MEM_Track(buffer, MEM_TRACKING_FREE_c, savedLR, 0, NULL);
#endif /*MEM_TRACKING*/
OSA_InterruptEnable();
return MEM_SUCCESS_c;
}
/*! *********************************************************************************
* \brief Determines the size of a memory block
*
* \param[in] buffer - Pointer to buffer.
*
* \return size of memory block
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
uint16_t MEM_BufferGetSize
(
void* buffer /* IN: Block of memory to free*/
)
{
if( buffer )
{
return ((pools_t *)((listHeader_t *)buffer-1)->pParentPool)->blockSize;
}
return 0;
}
/*! *********************************************************************************
*************************************************************************************
* Private functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function updates the tracking array element corresponding to the given
* block.
*
* \param[in] block - Pointer to the block.
* \param[in] alloc - Indicates whether an allocation or free operation was performed
* \param[in] address - Address where MEM_BufferAlloc or MEM_BufferFree was called
* \param[in] requestedSize - Indicates the requested buffer size passed to MEM_BufferAlloc.
* Has no use if a free operation was performed.
*
* \return Returns TRUE if correct allocation or dealocation was performed, FALSE if a
* buffer was allocated or freed twice.
*
********************************************************************************** */
#ifdef MEM_TRACKING
uint8_t MEM_Track(listHeader_t *block, memTrackingStatus_t alloc, uint32_t address, uint16_t requestedSize, void *pCaller)
{
uint16_t i;
blockTracking_t *pTrack = NULL;
#ifdef MEM_STATISTICS
poolStat_t * poolStatistics = (poolStat_t *)&((pools_t *)( (listElementHandle_t)(block-1)->pParentPool ))->poolStatistics;
#endif
for( i=0; i<mTotalNoOfMsgs_c; i++ )
{
if( block == memTrack[i].blockAddr )
{
pTrack = &memTrack[i];
break;
}
}
if( !pTrack || pTrack->allocStatus == alloc)
{
#ifdef MEM_DEBUG
panic( 0, (uint32_t)MEM_Track, 0, 0);
#endif
return FALSE;
}
pTrack->allocStatus = alloc;
pTrack->pCaller = (void*)((uint32_t)pCaller & 0x7FFFFFFF);
if(alloc == MEM_TRACKING_ALLOC_c)
{
pTrack->fragmentWaste = pTrack->blockSize - requestedSize;
pTrack->allocCounter++;
pTrack->allocAddr = (void *)address;
if( (uint32_t)pCaller & 0x80000000 )
{
pTrack->timeStamp = 0xFFFFFFFF;
}
else
{
pTrack->timeStamp = MEM_GetTimeStamp();
}
#ifdef MEM_STATISTICS
gTotalFragmentWaste += pTrack->fragmentWaste;
if(gTotalFragmentWaste > gMaxTotalFragmentWaste)
{
gMaxTotalFragmentWaste = gTotalFragmentWaste;
FLib_MemCpy(&memPoolsSnapShot[0], &memPools[0], sizeof(memPools));
}
poolStatistics->poolFragmentWaste += pTrack->fragmentWaste;
if(poolStatistics->poolFragmentWaste > poolStatistics->poolFragmentWastePeak)
poolStatistics->poolFragmentWastePeak = poolStatistics->poolFragmentWaste;
if(pTrack->fragmentWaste < poolStatistics->poolFragmentMinWaste)
{
poolStatistics->poolFragmentMinWaste = pTrack->fragmentWaste;
}
if(pTrack->fragmentWaste > poolStatistics->poolFragmentMaxWaste)
{
poolStatistics->poolFragmentMaxWaste = pTrack->fragmentWaste;
}
if(poolStatistics->allocatedBlocks == poolStatistics->numBlocks)
{
//__asm("BKPT #0\n") ; /* cause the debugger to stop */
}
#endif /*MEM_STATISTICS*/
}
else
{
#ifdef MEM_STATISTICS
poolStatistics->poolFragmentWaste -= pTrack->fragmentWaste;
gTotalFragmentWaste -= pTrack->fragmentWaste;
#endif /*MEM_STATISTICS*/
pTrack->fragmentWaste = 0;
pTrack->freeCounter++;
pTrack->freeAddr = (void *)address;
pTrack->timeStamp = 0;
}
return TRUE;
}
/*! *********************************************************************************
* \brief This function checks for buffer overflow when copying multiple bytes
*
* \param[in] p - pointer to destination.
* \param[in] size - number of bytes to copy
*
* \return 1 if overflow detected, else 0
*
********************************************************************************** */
uint8_t MEM_BufferCheck(uint8_t *p, uint32_t size)
{
poolInfo_t *pPollInfo = poolInfo;
uint8_t* memAddr = (uint8_t *)memHeap;
uint32_t poolBytes, blockBytes, i;
if( (p < (uint8_t*)memHeap) || (p > ((uint8_t*)memHeap + sizeof(memHeap))) )
{
return 0;
}
while( pPollInfo->blockSize )
{
blockBytes = pPollInfo->blockSize + sizeof(listHeader_t);
poolBytes = blockBytes * pPollInfo->poolSize;
/* Find the correct message pool */
if( (p >= memAddr) && (p < memAddr + poolBytes) )
{
/* Check if the size to copy is greather then the size of the current block */
if( size > pPollInfo->blockSize )
{
#ifdef MEM_DEBUG
panic(0,0,0,0);
#endif
return 1;
}
/* Find the correct memory block */
for( i=0; i<pPollInfo->poolSize; i++ )
{
if( (p >= memAddr) && (p < memAddr + blockBytes) )
{
if( p + size > memAddr + blockBytes )
{
#ifdef MEM_DEBUG
panic(0,0,0,0);
#endif
return 1;
}
else
{
return 0;
}
}
memAddr += blockBytes;
}
}
/* check next pool */
memAddr += poolBytes;
pPollInfo++;
}
return 0;
}
#endif /*MEM_TRACKING*/
/*! *********************************************************************************
* \brief This function checks if the buffers are allocated for more than the
* specified duration
*
********************************************************************************** */
#ifdef MEM_TRACKING
void MEM_CheckIfMemBuffersAreFreed(void)
{
uint32_t t;
uint16_t i, j = 0;
uint8_t trackCount = 0;
pools_t *pParentPool;
volatile blockTracking_t *pTrack;
static volatile blockTracking_t *mpTrackTbl[NUM_OF_TRACK_PTR];
static uint32_t lastTimestamp = 0;
uint32_t currentTime = MEM_GetTimeStamp();
if( (currentTime - lastTimestamp) >= MEM_CheckMemBufferInterval_c )
{
lastTimestamp = currentTime;
j = 0;
for( i = 0; i < mTotalNoOfMsgs_c; i++ )
{
pTrack = &memTrack[i];
/* Validate the pParent first */
pParentPool = (((listHeader_t *)(pTrack->blockAddr))-1)->pParentPool;
if(pParentPool != &memPools[j])
{
if(j < NumberOfElements(memPools))
{
j++;
if(pParentPool != &memPools[j])
{
panic(0,0,0,0);
}
}
else
{
panic(0,0,0,0);
}
}
/* Check if it should be freed */
OSA_InterruptDisable();
if((pTrack->timeStamp != 0xffffffff ) &&
(pTrack->allocStatus == MEM_TRACKING_ALLOC_c) &&
(currentTime > pTrack->timeStamp))
{
t = currentTime - pTrack->timeStamp;
if( t > MEM_CheckMemBufferThreshold_c )
{
mpTrackTbl[trackCount++] = pTrack;
if(trackCount == NUM_OF_TRACK_PTR)
{
(void)mpTrackTbl; /* remove compiler warnings */
panic(0,0,0,0);
break;
}
}
}
OSA_InterruptEnable();
} /* end for */
}
}
#endif /*MEM_TRACKING*/
/*! *********************************************************************************
* \brief Get time-stamp for memory operation: alloc/free.
*
* \return dymmy time-stamp
*
********************************************************************************** */
#ifdef MEM_TRACKING
#if defined(__IAR_SYSTEMS_ICC__)
__weak uint32_t MEM_GetTimeStamp(void)
#elif defined(__GNUC__)
__attribute__((weak)) uint32_t MEM_GetTimeStamp(void)
#endif
{
return 0xFFFFFFFF;
}
#endif /* MEM_TRACKING */
/*! ************************************************************************************************
\brief MEM Manager calloc alternative implementation.
\param [in] len Number of blocks
\param [in] size Size of one block
\return void* Pointer to the allocated buffer or NULL in case of error
************************************************************************************************* */
void* MEM_CallocAlt
(
size_t len,
size_t val
)
{
void *pData = MEM_BufferAllocForever (len* val, 0);
if (pData)
{
FLib_MemSet (pData, 0, len* val);
}
return pData;
}
/*! ************************************************************************************************
\brief MEM Manager free alternative implementation.
\param [in] pData Pointer to the allocated buffer
\return void
************************************************************************************************* */
void MEM_FreeAlt
(
void* pData
)
{
MEM_BufferFree (pData);
}
@@ -0,0 +1,612 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _FSL_OS_ABSTRACTION_H_
#define _FSL_OS_ABSTRACTION_H_
#include "EmbeddedTypes.h"
#include "fsl_os_abstraction_config.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
/*! @brief Type for the Task Priority*/
typedef uint16_t osaTaskPriority_t;
/*! @brief Type for the timer definition*/
typedef enum {
osaTimer_Once = 0, /*!< one-shot timer*/
osaTimer_Periodic = 1 /*!< repeating timer*/
} osaTimer_t;
/*! @brief Type for a task handler, returned by the OSA_TaskCreate function. */
typedef void* osaTaskId_t;
/*! @brief Type for the parameter to be passed to the task at its creation */
typedef void* osaTaskParam_t;
/*! @brief Type for task pointer. Task prototype declaration */
typedef void (*osaTaskPtr_t) (osaTaskParam_t task_param);
/*! @brief Type for the semaphore handler, returned by the OSA_SemaphoreCreate function. */
typedef void* osaSemaphoreId_t;
/*! @brief Type for the mutex handler, returned by the OSA_MutexCreate function. */
typedef void* osaMutexId_t;
/*! @brief Type for the event handler, returned by the OSA_EventCreate function. */
typedef void* osaEventId_t;
/*! @brief Type for an event flags group, bit 32 is reserved. */
typedef uint32_t osaEventFlags_t;
/*! @brief Message definition. */
typedef void* osaMsg_t;
/*! @brief Type for the message queue handler, returned by the OSA_MsgQCreate function. */
typedef void* osaMsgQId_t;
/*! @brief Type for the Timer handler, returned by the OSA_TimerCreate function. */
typedef void *osaTimerId_t;
/*! @brief Type for the Timer callback function pointer. */
typedef void (*osaTimerFctPtr_t) (void const *argument);
/*! @brief Thread Definition structure contains startup information of a thread.*/
typedef struct osaThreadDef_tag {
osaTaskPtr_t pthread; /*!< start address of thread function*/
uint32_t tpriority; /*!< initial thread priority*/
uint32_t instances; /*!< maximum number of instances of that thread function*/
uint32_t stacksize; /*!< stack size requirements in bytes; 0 is default stack size*/
uint32_t *tstack;
void *tlink;
uint8_t *tname;
bool_t useFloat;
} osaThreadDef_t;
/*! @brief Thread Link Definition structure .*/
typedef struct osaThreadLink_tag{
uint8_t link[12];
osaTaskId_t osThreadId;
osaThreadDef_t *osThreadDefHandle;
uint32_t *osThreadStackHandle;
}osaThreadLink_t, *osaThreadLinkHandle_t;
/*! @Timer Definition structure contains timer parameters.*/
typedef struct osaTimerDef_tag {
osaTimerFctPtr_t pfCallback; /* < start address of a timer function */
void *argument;
} osaTimerDef_t;
/*! @brief Defines the return status of OSA's functions */
typedef enum osaStatus_tag
{
osaStatus_Success = 0U, /*!< Success */
osaStatus_Error = 1U, /*!< Failed */
osaStatus_Timeout = 2U, /*!< Timeout occurs while waiting */
osaStatus_Idle = 3U /*!< Used for bare metal only, the wait object is not ready
and timeout still not occur */
}osaStatus_t;
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
#if defined (FSL_RTOS_MQX)
#define USE_RTOS 1
#elif defined (FSL_RTOS_FREE_RTOS)
#define USE_RTOS 1
#elif defined (FSL_RTOS_UCOSII)
#define USE_RTOS 1
#elif defined (FSL_RTOS_UCOSIII)
#define USE_RTOS 1
#else
#define USE_RTOS 0
#endif
#define OSA_PRIORITY_IDLE (6)
#define OSA_PRIORITY_LOW (5)
#define OSA_PRIORITY_BELOW_NORMAL (4)
#define OSA_PRIORITY_NORMAL (3)
#define OSA_PRIORITY_ABOVE_NORMAL (2)
#define OSA_PRIORITY_HIGH (1)
#define OSA_PRIORITY_REAL_TIME (0)
#define OSA_TASK_PRIORITY_MAX (0)
#define OSA_TASK_PRIORITY_MIN (15)
#define SIZE_IN_UINT32_UNITS(size) (((size) + sizeof(uint32_t) - 1) / sizeof(uint32_t))
/*! @brief Constant to pass as timeout value in order to wait indefinitely. */
#define osaWaitForever_c ((uint32_t)(-1))
#define osaEventFlagsAll_c ((osaEventFlags_t)(0x00FFFFFF))
#define osThreadStackArray(name) osThread_##name##_stack
#define osThreadStackDef(name, stacksize, instances) \
uint32_t osThreadStackArray(name)[SIZE_IN_UINT32_UNITS(stacksize)*(instances)];
/* ==== Thread Management ==== */
/* Create a Thread Definition with function, priority, and stack requirements.
* \param name name of the thread function.
* \param priority initial priority of the thread function.
* \param instances number of possible thread instances.
* \param stackSz stack size (in bytes) requirements for the thread function.
* \param useFloat
*/
#if defined(FSL_RTOS_MQX)
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadLink_t osThreadLink_##name[instances] = {0}; \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
osThreadLink_##name, \
(uint8_t*) #name,\
(useFloat)}
#elif defined (FSL_RTOS_UCOSII)
#if gTaskMultipleInstancesManagement_c
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadLink_t osThreadLink_##name[instances] = {0}; \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
osThreadLink_##name, \
(uint8_t*) #name,\
(useFloat)}
#else
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
NULL, \
(uint8_t*) #name,\
(useFloat)}
#endif
#else
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
NULL, \
NULL, \
(uint8_t*) #name,\
(useFloat)}
#endif
/* Access a Thread defintion.
* \param name name of the thread definition object.
*/
#define OSA_TASK(name) \
&os_thread_def_##name
#define OSA_TASK_PROTO(name) \
extern osaThreadDef_t os_thread_def_##name
/* ==== Timer Management ====
* Define a Timer object.
* \param name name of the timer object.
* \param function name of the timer call back function.
*/
#define OSA_TIMER_DEF(name, function) \
osaTimerDef_t os_timer_def_##name = \
{ (function), NULL }
/* Access a Timer definition.
* \param name name of the timer object.
*/
#define OSA_TIMER(name) \
&os_timer_def_##name
/*****************************************************************************
******************************************************************************
* Public memory declarations
******************************************************************************
*****************************************************************************/
extern const uint8_t gUseRtos_c;
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*!
* @name Task management
* @{
*/
/*!
* @brief Creates a task.
*
* This function is used to create task based on the resources defined
* by the macro OSA_TASK_DEFINE.
*
* @param thread_def pointer to the osaThreadDef_t structure which defines the task.
* @param task_param Pointer to be passed to the task when it is created.
*
* @retval taskId The task is successfully created.
* @retval NULL The task can not be created..
*
* Example:
@code
osaTaskId_t taskId;
OSA_TASK_DEFINE( Job1, OSA_PRIORITY_HIGH, 1, 800, 0);;
taskId = OSA__TaskCreate(OSA__TASK(Job1), (osaTaskParam_t)NULL);
@endcode
*/
osaTaskId_t OSA_TaskCreate(osaThreadDef_t *thread_def, osaTaskParam_t task_param);
/*!
* @brief Gets the handler of active task.
*
* @return Handler to current active task.
*/
osaTaskId_t OSA_TaskGetId(void);
/*!
* @brief Puts the active task to the end of scheduler's queue.
*
* When a task calls this function, it gives up the CPU and puts itself to the
* end of a task ready list.
*
* @retval osaStatus_Success The function is called successfully.
* @retval osaStatus_Error Error occurs with this function.
*/
osaStatus_t OSA_TaskYield(void);
/*!
* @brief Gets the priority of a task.
*
* @param taskId The handler of the task whose priority is received.
*
* @return Task's priority.
*/
osaTaskPriority_t OSA_TaskGetPriority(osaTaskId_t taskId);
/*!
* @brief Sets the priority of a task.
*
* @param taskId The handler of the task whose priority is set.
* @param taskPriority The priority to set.
*
* @retval osaStatus_Success Task's priority is set successfully.
* @retval osaStatus_Error Task's priority can not be set.
*/
osaStatus_t OSA_TaskSetPriority(osaTaskId_t taskId, osaTaskPriority_t taskPriority);
/*!
* @brief Destroys a previously created task.
*
* @param taskId The handler of the task to destroy. Returned by the OSA_TaskCreate function.
*
* @retval osaStatus_Success The task was successfully destroyed.
* @retval osaStatus_Error Task destruction failed or invalid parameter.
*/
osaStatus_t OSA_TaskDestroy(osaTaskId_t taskId);
/*!
* @brief Creates a semaphore with a given value.
*
* This function creates a semaphore and sets the value to the parameter
* initValue.
*
* @param initValue Initial value the semaphore will be set to.
*
* @retval handler to the new semaphore if the semaphore is created successfully.
* @retval NULL if the semaphore can not be created.
*
*
*/
osaSemaphoreId_t OSA_SemaphoreCreate(uint32_t initValue);
/*!
* @brief Destroys a previously created semaphore.
*
* @param semId Pointer to the semaphore to destroy.
*
* @retval osaStatus_Success The semaphore is successfully destroyed.
* @retval osaStatus_Error The semaphore can not be destroyed.
*/
osaStatus_t OSA_SemaphoreDestroy(osaSemaphoreId_t semId);
/*!
* @brief Pending a semaphore with timeout.
*
* This function checks the semaphore's counting value. If it is positive,
* decreases it and returns osaStatus_Success. Otherwise, a timeout is used
* to wait.
*
* @param semId Pointer to the semaphore.
* @param millisec The maximum number of milliseconds to wait if semaphore is not
* positive. Pass osaWaitForever_c to wait indefinitely, pass 0
* will return osaStatus_Timeout immediately.
*
* @retval osaStatus_Success The semaphore is received.
* @retval osaStatus_Timeout The semaphore is not received within the specified 'timeout'.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec);
/*!
* @brief Signals for someone waiting on the semaphore to wake up.
*
* Wakes up one task that is waiting on the semaphore. If no task is waiting, increases
* the semaphore's counting value.
*
* @param semId Pointer to the semaphore to signal.
*
* @retval osaStatus_Success The semaphore is successfully signaled.
* @retval osaStatus_Error The object can not be signaled or invalid parameter.
*
*/
osaStatus_t OSA_SemaphorePost(osaSemaphoreId_t semId);
/*!
* @brief Create an unlocked mutex.
*
* This function creates a non-recursive mutex and sets it to unlocked status.
*
* @param none.
*
* @retval handler to the new mutex if the mutex is created successfully.
* @retval NULL if the mutex can not be created.
*/
osaMutexId_t OSA_MutexCreate(void);
/*!
* @brief Waits for a mutex and locks it.
*
* This function checks the mutex's status. If it is unlocked, locks it and returns the
* osaStatus_Success. Otherwise, waits for a timeout in milliseconds to lock.
*
* @param mutexId Pointer to the Mutex.
* @param millisec The maximum number of milliseconds to wait for the mutex.
* If the mutex is locked, Pass the value osaWaitForever_c will
* wait indefinitely, pass 0 will return osaStatus_Timeout
* immediately.
*
* @retval osaStatus_Success The mutex is locked successfully.
* @retval osaStatus_Timeout Timeout occurred.
* @retval osaStatus_Error Incorrect parameter was passed.
*
* @note This is non-recursive mutex, a task can not try to lock the mutex it has locked.
*/
osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec);
/*!
* @brief Unlocks a previously locked mutex.
*
* @param mutexId Pointer to the Mutex.
*
* @retval osaStatus_Success The mutex is successfully unlocked.
* @retval osaStatus_Error The mutex can not be unlocked or invalid parameter.
*/
osaStatus_t OSA_MutexUnlock(osaMutexId_t mutexId);
/*!
* @brief Destroys a previously created mutex.
*
* @param mutexId Pointer to the Mutex.
*
* @retval osaStatus_Success The mutex is successfully destroyed.
* @retval osaStatus_Error The mutex can not be destroyed.
*
*/
osaStatus_t OSA_MutexDestroy(osaMutexId_t mutexId);
/*!
* @brief Initializes an event object with all flags cleared.
*
* This function creates an event object and set its clear mode. If autoClear
* is TRUE, when a task gets the event flags, these flags will be
* cleared automatically. Otherwise these flags must
* be cleared manually.
*
* @param autoClear TRUE The event is auto-clear.
* FALSE The event manual-clear
* @retval handler to the new event if the event is created successfully.
* @retval NULL if the event can not be created.
*/
osaEventId_t OSA_EventCreate(bool_t autoClear);
/*!
* @brief Sets one or more event flags.
*
* Sets specified flags of an event object.
*
* @param eventId Pointer to the event.
* @param flagsToSet Flags to be set.
*
* @retval osaStatus_Success The flags were successfully set.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_EventSet(osaEventId_t eventId, osaEventFlags_t flagsToSet);
/*!
* @brief Clears one or more flags.
*
* Clears specified flags of an event object.
*
* @param eventId Pointer to the event.
* @param flagsToClear Flags to be clear.
*
* @retval osaStatus_Success The flags were successfully cleared.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_EventClear(osaEventId_t eventId, osaEventFlags_t flagsToClear);
/*!
* @brief Waits for specified event flags to be set.
*
* This function waits for a combination of flags to be set in an event object.
* Applications can wait for any/all bits to be set. Also this function could
* obtain the flags who wakeup the waiting task.
*
* @param eventId Pointer to the event.
* @param flagsToWait Flags that to wait.
* @param waitAll Wait all flags or any flag to be set.
* @param millisec The maximum number of milliseconds to wait for the event.
* If the wait condition is not met, pass osaWaitForever_c will
* wait indefinitely, pass 0 will return osaStatus_Timeout
* immediately.
* @param setFlags Flags that wakeup the waiting task are obtained by this parameter.
*
* @retval osaStatus_Success The wait condition met and function returns successfully.
* @retval osaStatus_Timeout Has not met wait condition within timeout.
* @retval osaStatus_Error An incorrect parameter was passed.
*
* @note Please pay attention to the flags bit width, FreeRTOS uses the most
* significant 8 bis as control bits, so do not wait these bits while using
* FreeRTOS.
*
*/
osaStatus_t OSA_EventWait(osaEventId_t eventId, osaEventFlags_t flagsToWait, bool_t waitAll, uint32_t millisec, osaEventFlags_t *pSetFlags);
/*!
* @brief Destroys a previously created event object.
*
* @param eventId Pointer to the event.
*
* @retval osaStatus_Success The event is successfully destroyed.
* @retval osaStatus_Error Event destruction failed.
*/
osaStatus_t OSA_EventDestroy(osaEventId_t eventId);
/*!
* @brief Initializes a message queue.
*
* This function allocates memory for and initializes a message queue. Message queue elements are hardcoded as void*.
*
* @param msgNo :number of messages the message queue should accommodate.
* This parameter should not exceed osNumberOfMessages defined in OSAbstractionConfig.h.
*
* @return: Handler to access the queue for put and get operations. If message queue
* creation failed, return NULL.
*/
osaMsgQId_t OSA_MsgQCreate(uint32_t msgNo);
/*!
* @brief Puts a message at the end of the queue.
*
* This function puts a message to the end of the message queue. If the queue
* is full, this function returns the osaStatus_Error;
*
* @param msgQId pointer to queue returned by the OSA_MsgQCreate function.
* @param pMessage Pointer to the message to be put into the queue.
*
* @retval osaStatus_Success Message successfully put into the queue.
* @retval osaStatus_Error The queue was full or an invalid parameter was passed.
*/
osaStatus_t OSA_MsgQPut(osaMsgQId_t msgQId, osaMsg_t pMessage);
/*!
* @brief Reads and remove a message at the head of the queue.
*
* This function gets a message from the head of the message queue. If the
* queue is empty, timeout is used to wait.
*
* @param msgQId Queue handler returned by the OSA_MsgQCreate function.
* @param pMessage Pointer to a memory to save the message.
* @param millisec The number of milliseconds to wait for a message. If the
* queue is empty, pass osaWaitForever_c will wait indefinitely,
* pass 0 will return osaStatus_Timeout immediately.
*
* @retval osaStatus_Success Message successfully obtained from the queue.
* @retval osaStatus_Timeout The queue remains empty after timeout.
* @retval osaStatus_Error Invalid parameter.
*/
osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, osaMsg_t pMessage, uint32_t millisec);
/*!
* @brief Destroys a previously created queue.
*
* @param msgQId queue handler returned by the OSA_MsgQCreate function.
*
* @retval osaStatus_Success The queue was successfully destroyed.
* @retval osaStatus_Error Message queue destruction failed.
*/
osaStatus_t OSA_MsgQDestroy(osaMsgQId_t msgQId);
/*!
* @brief Enable all interrupts.
*/
void OSA_InterruptEnable(void);
/*!
* @brief Disable all interrupts.
*/
void OSA_InterruptDisable(void);
/*!
* @brief Disable interrupts except high-priority ones
*
* @param pu8OldIntLevel Variable to hold previous setting
*/
void OSA_InterruptEnableRestricted(uint32_t *pu32OldIntLevel);
/*!
* @brief Restore interrupts that were previously restricted by a call
* to OSA_InterruptEnableRestricted
*
* @param pu8OldIntLevel Variable holding previous setting
*/
void OSA_InterruptEnableRestore(uint32_t *pu32OldIntLevel);
/*!
* @brief Enable all interrupts using PRIMASK.
*/
void OSA_EnableIRQGlobal(void);
/*!
* @brief Disable all interrupts using PRIMASK.
*/
void OSA_DisableIRQGlobal(void);
/*!
* @brief Delays execution for a number of milliseconds.
*
* @param millisec The time in milliseconds to wait.
*/
void OSA_TimeDelay(uint32_t millisec);
/*!
* @brief This function gets current time in milliseconds.
*
* @retval current time in milliseconds
*/
uint32_t OSA_TimeGetMsec(void);
/*!
* @brief This function resets the current time to 0.
*/
void OSA_TimeResetMsec(void);
/*!
* @brief Installs the interrupt handler.
*
* @param IRQNumber IRQ number of the interrupt.
* @param handler The interrupt handler to install.
*/
void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void));
/*!
* @brief Init the OSA time.
*
*/
void OSA_TimeInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,168 @@
/*! *********************************************************************************
* Copyright (c) 2013-2014, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#if !defined(__FSL_OS_ABSTRACTION_BM_H__)
#define __FSL_OS_ABSTRACTION_BM_H__
/*!
* @addtogroup os_abstraction_bm
* @{
*/
/*******************************************************************************
* Declarations
******************************************************************************/
/*! @brief Bare Metal does not use timer. */
#define FSL_OSA_BM_TIMER_NONE 0U
/*! @brief Bare Metal uses SYSTICK as timer. */
#define FSL_OSA_BM_TIMER_SYSTICK 1U
/*! @brief Configure what timer is used in Bare Metal. */
#ifndef FSL_OSA_BM_TIMER_CONFIG
#define FSL_OSA_BM_TIMER_CONFIG FSL_OSA_BM_TIMER_NONE
#endif
/*! @brief Type for an semaphore */
typedef struct Semaphore
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout on this object */
volatile uint8_t semCount; /*!< The count value of the object */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
} semaphore_t;
/*! @brief Type for a mutex */
typedef struct Mutex
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout on this mutex */
volatile bool_t isLocked; /*!< Is the object locked or not */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
} mutex_t;
/*! @brief Type for task parameter */
typedef void* task_param_t;
#define gIdleTaskPriority_c ((task_priority_t) 0)
#define gInvalidTaskPriority_c ((task_priority_t) -1)
/*! @brief Type for a task handler, returned by the OSA_TaskCreate function */
typedef void (* task_t)(task_param_t param);
/*! @brief Task control block for bare metal. */
typedef struct TaskControlBlock
{
osaTaskPtr_t p_func; /*!< Task's entry */
bool_t haveToRun; /*!< Task was signaled */
osaTaskPriority_t priority; /*!< Task's priority */
osaTaskParam_t param; /*!< Task's parameter */
struct TaskControlBlock *next; /*!< Pointer to next task control block */
struct TaskControlBlock *prev; /*!< Pointer to previous task control block */
} task_control_block_t;
/*! @brief Type for a task pointer */
typedef task_control_block_t* task_handler_t;
/*! @brief Type for a task stack */
typedef uint32_t task_stack_t;
/*! @brief Type for an event flags group, bit 32 is reserved */
typedef uint32_t event_flags_t;
/*! @brief Type for an event object */
typedef struct Event
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout on this event */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
volatile event_flags_t flags; /*!< The flags status */
bool_t autoClear; /*!< Auto clear or manual clear */
task_handler_t waitingTask; /*!< Handler to the waiting task */
} event_t;
/*! @brief Type for a message queue */
typedef struct MsgQueue
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout */
uint16_t number; /*!< The number of messages in the queue */
uint16_t max; /*!< The max number of queue messages */
uint16_t head; /*!< Index of the next message to be read */
uint16_t tail; /*!< Index of the next place to write to */
uint32_t queueMem[osNumberOfMessages]; /*!< Points to the queue memory */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
task_handler_t waitingTask; /*!< Handler to the waiting task */
}msg_queue_t;
/*! @brief Type for a message queue handler */
typedef msg_queue_t* msg_queue_handler_t;
/*! @brief Constant to pass as timeout value in order to wait indefinitely. */
#define OSA_WAIT_FOREVER 0xFFFFFFFFU
/*! @brief How many tasks can the bare metal support. */
#define TASK_MAX_NUM 7
/*! @brief OSA's time range in millisecond, OSA time wraps if exceeds this value. */
#define FSL_OSA_TIME_RANGE 0xFFFFFFFFU
/*! @brief The default interrupt handler installed in vector table. */
#define OSA_DEFAULT_INT_HANDLER ((osa_int_handler_t)(&DefaultISR))
/*! @brief The default interrupt handler installed in vector table. */
extern void DefaultISR(void);
/*!
* @name Thread management
* @{
*/
/*!
* @brief Defines a task.
*
* This macro defines resources for a task statically. Then, the OSA_TaskCreate
* creates the task based-on these resources.
*
* @param task The task function.
* @param stackSize The stack size this task needs in bytes.
*/
#define PRIORITY_OSA_TO_RTOS(osa_prio) (osa_prio)
#define PRIORITY_RTOS_TO_OSA(rtos_prio) (rtos_prio)
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus*/
/*!
* @brief Calls all task functions one time except for the current task.
*
* This function calls all other task functions one time. If current
* task is waiting for an event triggered by other tasks, this function
* could be used to trigger the event.
*
* @note There should be only one task calls this function, if more than
* one task call this function, stack overflow may occurs. Be careful
* to use this function.
*
*/
void OSA_PollAllOtherTasks(void);
#if defined(__cplusplus)
}
#endif /* __cplusplus*/
/*! @}*/
#endif /* __FSL_OS_ABSTRACTION_BM_H__ */
/*******************************************************************************
* EOF
******************************************************************************/
@@ -0,0 +1,53 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _FSL_OS_ABSTRACTION_CONFIG_H_
#define _FSL_OS_ABSTRACTION_CONFIG_H_
#ifndef osNumberOfSemaphores
#define osNumberOfSemaphores 5
#endif
#ifndef osNumberOfMutexes
#define osNumberOfMutexes 5
#endif
#ifndef osNumberOfMessageQs
#define osNumberOfMessageQs 0
#endif
#ifndef osNumberOfMessages
#define osNumberOfMessages 10
#endif
#ifndef osNumberOfEvents
#define osNumberOfEvents 5
#endif
#ifndef CPU_JN518X
#ifndef gMainThreadStackSize_c
#define gMainThreadStackSize_c 1024
#endif
#else
#if !defined gMainThreadStackSize_c || (gMainThreadStackSize_c < 1200)
#undef gMainThreadStackSize_c
#define gMainThreadStackSize_c 1200
#endif
#endif
#ifndef gMainThreadPriority_c
#define gMainThreadPriority_c 7
#endif
#ifndef gTaskMultipleInstancesManagement_c
#define gTaskMultipleInstancesManagement_c 0
#endif
#ifndef osCustomStartup
#define osCustomStartup 0
#endif
#endif /* _FSL_OS_ABSTRACTION_CONFIG_H_ */
@@ -0,0 +1,161 @@
/*! *********************************************************************************
* Copyright (c) 2013-2014, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#if !defined(__FSL_OS_ABSTRACTION_FREERTOS_H__)
#define __FSL_OS_ABSTRACTION_FREERTOS_H__
#if defined ( __IAR_SYSTEMS_ICC__ )
/**
* Workaround to disable MISRA C message suppress warnings for IAR compiler.
* http://supp.iar.com/Support/?note=24725
*/
#define MISRAC_DISABLE _Pragma ("diag_suppress= \
Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\
Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\
Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\
Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\
Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\
Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\
Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\
Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\
Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\
Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\
Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\
Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\
Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\
Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\
Pm155")
#define MISRAC_ENABLE _Pragma ("diag_default= \
Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\
Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\
Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\
Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\
Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\
Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\
Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\
Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\
Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\
Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\
Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\
Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\
Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\
Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\
Pm155")
#else
/* Empty MISRA C macros for other toolchains. */
#define MISRAC_DISABLE
#define MISRAC_ENABLE
#endif
MISRAC_DISABLE
#include "FreeRTOS.h"
#include "semphr.h"
#include "event_groups.h"
MISRAC_ENABLE
/*!
* @addtogroup os_abstraction_free_rtos
* @{
*/
/*******************************************************************************
* Declarations
******************************************************************************/
/*! @brief Type for a task handler, returned by the OSA_TaskCreate function. */
typedef TaskHandle_t task_handler_t;
/*! @brief Type for a task stack.*/
typedef portSTACK_TYPE task_stack_t;
/*! @brief Type for task parameter */
typedef void* task_param_t;
/*! @brief Type for a task function. */
typedef pdTASK_CODE task_t;
/*! @brief Type for a mutex. */
typedef xSemaphoreHandle mutex_t;
/*! @brief Type for a semaphore. */
typedef xSemaphoreHandle semaphore_t;
/*! @brief Type for an event flags object.*/
typedef EventBits_t event_flags_t;
/*! @brief Type for an event group object in FreeRTOS OS */
typedef struct EventFreertos {
bool_t autoClear; /*!< Auto clear or manual clear */
EventGroupHandle_t eventHandler; /*!< FreeRTOS OS event handler */
} event_freertos;
/*! @brief Type for an event group object */
typedef event_freertos event_t;
/*! @brief Type for a message queue declaration and creation. */
typedef xQueueHandle msg_queue_t;
/*! @brief Type for a message queue handler */
typedef xQueueHandle msg_queue_handler_t;
/*! @brief Constant to pass as timeout value in order to wait indefinitely. */
#define OSA_WAIT_FOREVER 0xFFFFFFFFU
/*! @brief OSA's time range in millisecond, OSA time wraps if exceeds this value. */
#define FSL_OSA_TIME_RANGE 0xFFFFFFFFU
/*! @brief The default interrupt handler installed in vector table. */
#define OSA_DEFAULT_INT_HANDLER ((osa_int_handler_t)(&DefaultISR))
/*! @brief The Max depth of Enter/Exist Critical could be nested in interrupt. */
#define OSA_MAX_ISR_CRITICAL_SECTION_DEPTH 0x8U
extern void DefaultISR(void);
/*!
* @name Thread management
* @{
*/
/*!
* @brief To provide unified task piority for upper layer, OSA layer makes conversion.
*/
#define PRIORITY_OSA_TO_RTOS(osa_prio) (configMAX_PRIORITIES - (osa_prio) -2)
#define PRIORITY_RTOS_TO_OSA(rtos_prio) (configMAX_PRIORITIES - (rtos_prio) -2)
/* @}*/
/*!
* @name Message queues
* @{
*/
/*!
* @brief This macro statically reserves the memory required for the queue.
*
* @param name Identifier for the memory region.
* @param number Number of elements in the queue.
* @param size Size of every elements in words.
*/
#define MSG_QUEUE_DECLARE(name, number, size) \
msg_queue_t *name = NULL
/* @}*/
/*! @}*/
#endif // __FSL_OS_ABSTRACTION_FREERTOS_H__
/*******************************************************************************
* EOF
******************************************************************************/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+485
View File
@@ -0,0 +1,485 @@
/*****************************************************************************
*
* MODULE: Persistent Data Manager
*
* DESCRIPTION: Provide management of data which needs to persist over
* cold or warm start
*
****************************************************************************
*
* This software is owned by NXP B.V. and/or its supplier and is protected
* under applicable copyright laws. All rights are reserved. We grant You,
* and any third parties, a license to use this software solely and
* exclusively on NXP products [NXP Microcontrollers such as JN5148, JN5142, JN5139].
* You, and any third parties must reproduce the copyright and warranty notice
* and any other legend of ownership on each copy or partial copy of the
* software.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright NXP B.V. 2012. All rights reserved
*
***************************************************************************/
#ifndef PDM_H_INCLUDED
#define PDM_H_INCLUDED
/****************************************************************************/
/*** Include Files ***/
/****************************************************************************/
#define PUBLIC
#if defined __cplusplus
extern "C" {
#endif
/*!
* @addtogroup PDM library
* @{
*/
/****************************************************************************/
/*** Macro Definitions ***/
/****************************************************************************/
#ifdef SE_HOST_COPROCESSOR
#define PDM_EXTERNAL_FLASH
#endif
#define PDM_NUM_BLOCKS 128
#ifdef PDM_EXTERNAL_FLASH
#define PDM_NAME_SIZE 16
#else
#define PDM_NAME_SIZE 7
#ifndef PDM_USER_SUPPLIED_ID
#define PDM_USER_SUPPLIED_ID /* Defaulting to having this enabled */
#endif
#endif
#define PDM_INVALID_ID ((uint16)(-1))
/* PDM ID range allocation reservations
* Each PDM_ID_BASE_xxx below is the base value for a block of 256 (0x100) IDs.
* Within a module the individual IDs used by that module will be an offset from
* this base.
*
* These ID ranges should not be re-used by other modules, even if the modules
* are not both present in the build.
*
* Values should not be changed. Reserve a new range instead of changing an
* existing range.
*/
#define PDM_ID_BASE_APP_ZB (0x0000) /* 0x0000?0x00ff: ZigBee Application Notes */
#define PDM_ID_BASE_ZPSAPL (0xf000) /* 0xf000?0xf0ff: ZigBee ZPS APL layer */
#define PDM_ID_BASE_ZPSNWK (0xf100) /* 0xf100?0xf1ff: ZigBee ZPS NWK layer */
#define PDM_ID_BASE_RADIO (0xff00) /* 0xff00?0xffff: Radio driver */
/* PDM ID individual allocation reservations
* Each PDM_ID_xxx below is an individual ID within one of the reserved ranges.
* Individual IDs need to be declared here only if they are shared between modules.
* Please include a descriptive comment to aid accurate identification.
*/
#define PDM_ID_RADIO_SETTINGS (PDM_ID_BASE_RADIO + 0x0000) /* Holds radio KMOD calibration data */
/* Defined because still using heap in PDM builds */
#define PDM_USE_HEAP
#if (defined PDM_USE_HEAP)
/* Empty declaration: buffer not needed */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments)
#else
/* Macro to create a static block of RAM to use instead of heap
NOTE: Must be declared at module scope, not within a function
NOTE: Value of 12 is based on size of tsPDM_FileSystemRecord */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments) \
PUBLIC uint8 au8PDM_HeapBuffer[(u8NumberOfSegments) * 12] __attribute__((aligned (4)))
#endif
/****************************************************************************/
/*** Type Definitions ***/
/****************************************************************************/
typedef enum
{
PDM_E_STATUS_OK,
PDM_E_STATUS_INVLD_PARAM,
// NVM based PDM codes
PDM_E_STATUS_PDM_FULL,
PDM_E_STATUS_NOT_SAVED,
PDM_E_STATUS_RECOVERED,
PDM_E_STATUS_PDM_RECOVERED_NOT_SAVED,
PDM_E_STATUS_USER_BUFFER_SIZE,
PDM_E_STATUS_BITMAP_SATURATED_NO_INCREMENT,
PDM_E_STATUS_BITMAP_SATURATED_OK,
PDM_E_STATUS_IMAGE_BITMAP_COMPLETE,
PDM_E_STATUS_IMAGE_BITMAP_INCOMPLETE,
PDM_E_STATUS_INTERNAL_ERROR
} PDM_teStatus;
typedef enum
{
PDM_RECOVERY_STATE_NONE = 0,
PDM_RECOVERY_STATE_NEW, // 1
PDM_RECOVERY_STATE_RECOVERED, // 2
PDM_RECOVERY_STATE_RECOVERED_NOT_READ, // 3
PDM_RECOVERY_STATE_SAVED, // 4
PDM_RECOVERY_STATE_NOT_SAVED, // 5
PDM_RECOVERY_STATE_APPENDED, // 6
// do not move
PDM_RECOVERY_STATE_NUMBER
} PDM_teRecoveryState;
typedef struct
{
/* this function gets called after a cold or warm start */
void (*prInitHwCb)(void);
/* this function gets called to erase the given sector */
void (*prEraseCb)(uint8_t u8Sector);
/* this function gets called to write data to an addresss
* within a given sector. address zero is the start of the
* given sector */
void (*prWriteCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
/* this function gets called to read data from an address
* within a given sector. address zero is the start of the
* given sector */
void (*prReadCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
} PDM_tsHwFncTable;
typedef enum
{
E_PDM_SYSTEM_EVENT_WEAR_COUNT_TRIGGER_VALUE_REACHED = 0,
E_PDM_SYSTEM_EVENT_WEAR_COUNT_MAXIMUM_REACHED,
E_PDM_SYSTEM_EVENT_SAVE_FAILED,
E_PDM_SYSTEM_EVENT_NOT_ENOUGH_SPACE,
E_PDM_SYSTEM_EVENT_LARGEST_RECORD_FULL_SAVE_NO_LONGER_POSSIBLE,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_CHECKSUM_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_SAVE_OK,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_READ_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_WRITE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_ERASE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_CHECK_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_DATA_WRITE_FAIL,
// nerdy event codes
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIRED,
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIR_FAILED,
E_PDM_SYSTEM_EVENT_SYSTEM_INTERNAL_BUFFER_WEAR_COUNT_SWAP,
E_PDM_SYSTEM_EVENT_SYSTEM_DUPLICATE_FILE_SEGMENT_DETECTED,
E_PDM_SYSTEM_EVENT_SYSTEM_ERROR,
// used in test harness
E_PDM_SYSTEM_EVENT_SEGMENT_PREWRITE,
E_PDM_SYSTEM_EVENT_SEGMENT_POSTWRITE,
E_PDM_SYSTEM_EVENT_SEQUENCE_DUPLICATE_DETECTED,
E_PDM_SYSTEM_EVENT_SEQUENCE_VERIFY_FAIL,
E_PDM_SYSTEM_EVENT_SMART_SAVE,
E_PDM_SYSTEM_EVENT_FULL_SAVE
} PDM_eSystemEventCode;
typedef struct
{
uint32_t u32eventNumber;
PDM_eSystemEventCode eSystemEventCode;
} PDM_tfpSystemEventCallback;
typedef void (*PDM_tpfvSystemEventCallback)(uint32_t u32eventNumber, PDM_eSystemEventCode eSystemEventCode);
/****************************************************************************/
/*** Exported Functions ***/
/****************************************************************************/
/*!
* @brief Initialise the PDM
*
* This function is to be called in order to initialise the PDM module
* call this EVERY cold start and EVERY warm start
*
* @param u16StartSegment: Start segment in flash
* @param u8NumberOfSegments: number of contiguous segments from u16StartSegment
* that belong to the PDM NVM space.
* @param fpvPDM_SystemEventCallback: function pointer passed by using layer
* to be notified of events/errors
*
* @retval PDM_E_STATUS_OK if success PDM_E_STATUS_INTERNAL_ERROR otherwise
*/
PUBLIC PDM_teStatus PDM_eInitialise(uint16_t u16StartSegment,
uint8_t u8NumberOfSegments,
PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Save a PDM record
*
* This function saves the specified application data from RAM to the specified record
* in NVM. The record is identified by means of a 16-bit user-defined value.
* When a data record is saved to the NVM for the first time, the data is written provided
* there are enough NVM segments available to hold the data. Upon subsequent save
* requests, if there has been a change between the RAM-based and NVM-based data
* buffers then the PDM will attempt to re-save only the segments that have changed
* (if no data has changed, no save will be performed). This is advantageous due to the
* restricted size of the NVM and the constraint that old data must be preserved while
* saving changed data to the NVM.
* Provided that you have registered a callback function with the PDM (see Section 6.3),
* the callback mechanism will signal when a save has failed. Upon failure, the callback
* function will be invoked and pass the event E_PDM_SYSTEM_EVENT_DESCRIPTOR_SAVE_FAILED
* to the application
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (specified record ID is invalid)
* @retval PDM_E_STATUS_NOT_SAVED (save to NVM failed)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordData(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save a PDM record next time in idle task
*
* Like PDM_eSaveRecordData, except that the record information is queued to
* saved in the idle task, when PDM_vIdleTask is called. Note that if the
* internal queue is full, the first record on the queue is saved immediately
* to make space for this record.
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordDataInIdleTask(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save queued PDM records
*
* Synchronously saves any queued record writes that have been generated by
* calls to PDM_eSaveRecordDataInIdleTask. To avoid this function taking too
* much time, the number of records that can be written can be limited by
* the u8WritesAllowed parameter. Use a value of 255 to effectively avoid
* this limit.
* @param u8WritesAllowed Maximum number of records that can be written
*
* @retval none
*/
PUBLIC void PDM_vIdleTask(uint8_t u8WritesAllowed);
/*!
* @brief Purge the pending event available in the queue
*
* @retval none
*/
PUBLIC void PDM_vQueuePurge(void);
/*!
* @brief Reads Partial Data from an Existing Record in the File System
*
* This function appends data to a record previously written.
* The record is identified by means of a 16-bit user-defined value.
*
* @param u16IdValue User-defined ID of the record to be read from
* @param u16TableOffset Data Offset
* @param pu8DataBuffer Data Buffer
* @param u16DataLength Length of input data, in bytes.
* @param pu16DataBytesRead Number Of Data Bytes Read u16IdValue
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (error in arguments)
* @retval PDM_E_STATUS_INTERNAL_ERROR
*/
PUBLIC PDM_teStatus PDM_eReadPartialDataFromExistingRecord(uint16_t u16IdValue,
uint16_t u16TableOffset,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function reads the specified record of application data from the NVM and stores
* the read data in the supplied data buffer in RAM. The record is specified using its
* unique 16-bit identifier.
* Before calling this function, it may be useful to call PDM_bDoesDataExist() in order
* to determine whether a record with the specified identifier exists in the EEPROM and,
* if it does, to obtain its size.
*
* @param u16IdValue User-defined ID of the record to be read
* @param pvDataBuffer Pointer to the data buffer in RAM where the read data is to
* be stored
* @param u16DataBufferLength Length of the data buffer, in bytes
* @param pu16DataBytesRead Pointer to a location to receive the number of data bytes
* read
*
* @retval PDM_E_STATUS_OK if success
* @retval PDM_E_STATUS_INVLD_PARAM otherwise i.e. specified record ID is invalid
*/
PUBLIC PDM_teStatus PDM_eReadDataFromRecord(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function deletes the specified record of application data in NVM.
* @see PDM_eDeleteAllData to alternatively delete all records in NVM
*
* @param u16IdValue User-defined ID of the record to be deleted
*
* @retval none
*/
PUBLIC void PDM_vDeleteDataRecord(uint16_t u16IdValue);
/*!
* @brief Delete a PDM record
*
* This function deletes all records in NVM, including both application data and stack
* context data, resulting in an empty PDM file system. The NVM segment Wear Count
* values are preserved (and incremented) throughout this function call.
* This function is to be used with extreme care in a Zigbee application context
*
* @param none
*
* @retval none
*/
PUBLIC void PDM_vDeleteAllDataRecords(void);
/*!
* @brief Seeks for a certain record by record identifier
*
* This function checks whether data associated with thd specified record ID
* exists in the NVM. If the data record exists, the function returns the data
* length, in bytes, in a location to which a pointer must be provided.
*
* @param u16IdValue User-defined ID of the record to be found
* @param pu16DataLength Pointer to location to receive length, in bytes,
* of data record (if any) associated with specified record ID
*
* @retval true if record was fond false otherwise
*/
PUBLIC bool_t PDM_bDoesDataExist(uint16_t u16IdValue, uint16_t *pu16DataLength);
/*!
* @brief Tells how many free segments are left in the PDM space
*
* This function returns the number of unused segments that remain in the NVM.
* Note that the returned parameter being a uint8_t the total expected number of
* segments cannot exceed 255
*
* @param none
*
* @retval Number of PDM NVM segments free
*/
PUBLIC uint8_t PDM_u8GetSegmentCapacity(void);
/*!
* @brief Tells how many free segments are occupied in the PDM space
*
* This function returns the number of used segments in the NVM
* @see PDM_u8GetSegmentCapacity
*
* @param none
*
* @retval Number of NVM segments used
*/
PUBLIC uint8_t PDM_u8GetSegmentOccupancy(void);
/*!
* @brief Register a User defined system callback function
*
* This function registers a callback function that will be called in error events
* @see PDM_pfGetSystemCallback
* @see PDM_eInitialise
*
* @param fpvPDM_SystemEventCallback function to replace the one that was set on PDM initialisation
*
* @retval none
*/
PUBLIC void PDM_vRegisterSystemCallback(PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Retrieve the previously defined system callback function
*
* This function retrieves the callback function that has been set by PDM_eInitialise
* or PDM_vRegisterSystemCallback
* @see PDM_vRegisterSystemCallback
* @see PDM_eInitialise
*
* @param none
*
* @retval fpvPDM_SystemEventCallback function used to notify error events
*/
PUBLIC PDM_tpfvSystemEventCallback PDM_pfGetSystemCallback(void);
PUBLIC void PDM_vSetWearCountTriggerLevel(uint32_t u32WearCountTriggerLevel);
PUBLIC PDM_teStatus PDM_eGetSegmentWearCount(uint8_t u8SegmentIndex, uint32_t *pu32WearCount);
PUBLIC PDM_teStatus PDM_eGetDeviceWearCountProfile(uint32_t au32WearCount[], uint8_t u8NumberOfSegments);
PUBLIC void PDM_vSetWearLevelDifference(uint32_t u32WearLevelDifference);
int PDM_Init(void);
#if defined UART_DEBUG
PUBLIC void vPDM_InitialiseDisplayDataInFileSystem(uint16_t *pau16PDMFileIDrecord, uint8_t u8NumberOfPDMSegments);
PUBLIC void vPDM_DisplayDataInFileSystem(void);
PUBLIC int iPDM_DisplayDataWithIdInFileSystem(uint16_t u16IdValue);
PUBLIC void vPDM_DisplayDataInNVM(void);
PUBLIC int iPDM_DisplayNVMsegmentData(uint8_t u8SegmentIndex);
PUBLIC char *psPDM_PrintEventID(PDM_eSystemEventCode eSystemEventCode);
PUBLIC int iPDM_ReadRawNVMsegmentDataToBuffer(uint8_t u8SegmentIndex,
uint8_t *pu8SegmentDataBuffer,
uint16_t *pu16SegmentDataSize);
#endif
/****************************************************************************/
/*** Exported Variables ***/
/****************************************************************************/
extern PUBLIC const uint32_t PDM_g_u32Version;
/*@}*/
#if defined __cplusplus
};
#endif
#endif /*PDM_H_INCLUDED*/
/****************************************************************************/
/*** END OF FILE ***/
/****************************************************************************/
Binary file not shown.
+488
View File
@@ -0,0 +1,488 @@
/*****************************************************************************
*
* MODULE: Persistent Data Manager
*
* DESCRIPTION: Provide management of data which needs to persist over
* cold or warm start
*
****************************************************************************
*
* This software is owned by NXP B.V. and/or its supplier and is protected
* under applicable copyright laws. All rights are reserved. We grant You,
* and any third parties, a license to use this software solely and
* exclusively on NXP products [NXP Microcontrollers such as JN5148, JN5142, JN5139].
* You, and any third parties must reproduce the copyright and warranty notice
* and any other legend of ownership on each copy or partial copy of the
* software.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright NXP B.V. 2012. All rights reserved
*
***************************************************************************/
#ifndef PDM_H_INCLUDED
#define PDM_H_INCLUDED
/****************************************************************************/
/*** Include Files ***/
/****************************************************************************/
#include "EmbeddedTypes.h"
#define PUBLIC
#if defined __cplusplus
extern "C" {
#endif
/*!
* @addtogroup PDM library
* @{
*/
/****************************************************************************/
/*** Macro Definitions ***/
/****************************************************************************/
#ifdef SE_HOST_COPROCESSOR
#define PDM_EXTERNAL_FLASH
#endif
#define PDM_NUM_BLOCKS 128
#ifdef PDM_EXTERNAL_FLASH
#define PDM_NAME_SIZE 16
#else
#define PDM_NAME_SIZE 7
#ifndef PDM_USER_SUPPLIED_ID
#define PDM_USER_SUPPLIED_ID /* Defaulting to having this enabled */
#endif
#endif
#define PDM_INVALID_ID ((uint16)(-1))
/* PDM ID range allocation reservations
* Each PDM_ID_BASE_xxx below is the base value for a block of 256 (0x100) IDs.
* Within a module the individual IDs used by that module will be an offset from
* this base.
*
* These ID ranges should not be re-used by other modules, even if the modules
* are not both present in the build.
*
* Values should not be changed. Reserve a new range instead of changing an
* existing range.
*/
#define PDM_ID_BASE_APP_ZB (0x0000) /* 0x0000?0x00ff: ZigBee Application Notes */
#define PDM_ID_BASE_ZPSAPL (0xf000) /* 0xf000?0xf0ff: ZigBee ZPS APL layer */
#define PDM_ID_BASE_ZPSNWK (0xf100) /* 0xf100?0xf1ff: ZigBee ZPS NWK layer */
#define PDM_ID_BASE_RADIO (0xff00) /* 0xff00?0xffff: Radio driver */
/* PDM ID individual allocation reservations
* Each PDM_ID_xxx below is an individual ID within one of the reserved ranges.
* Individual IDs need to be declared here only if they are shared between modules.
* Please include a descriptive comment to aid accurate identification.
*/
#define PDM_ID_RADIO_SETTINGS (PDM_ID_BASE_RADIO + 0x0000) /* Holds radio KMOD calibration data */
/* Defined because still using heap in PDM builds */
#define PDM_USE_HEAP
#if (defined PDM_USE_HEAP)
/* Empty declaration: buffer not needed */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments)
#else
/* Macro to create a static block of RAM to use instead of heap
NOTE: Must be declared at module scope, not within a function
NOTE: Value of 12 is based on size of tsPDM_FileSystemRecord */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments) \
PUBLIC uint8 au8PDM_HeapBuffer[(u8NumberOfSegments) * 12] __attribute__((aligned (4)))
#endif
/****************************************************************************/
/*** Type Definitions ***/
/****************************************************************************/
typedef enum
{
PDM_E_STATUS_OK,
PDM_E_STATUS_INVLD_PARAM,
// NVM based PDM codes
PDM_E_STATUS_PDM_FULL,
PDM_E_STATUS_NOT_SAVED,
PDM_E_STATUS_RECOVERED,
PDM_E_STATUS_PDM_RECOVERED_NOT_SAVED,
PDM_E_STATUS_USER_BUFFER_SIZE,
PDM_E_STATUS_BITMAP_SATURATED_NO_INCREMENT,
PDM_E_STATUS_BITMAP_SATURATED_OK,
PDM_E_STATUS_IMAGE_BITMAP_COMPLETE,
PDM_E_STATUS_IMAGE_BITMAP_INCOMPLETE,
PDM_E_STATUS_INTERNAL_ERROR
} PDM_teStatus;
typedef enum
{
PDM_RECOVERY_STATE_NONE = 0,
PDM_RECOVERY_STATE_NEW, // 1
PDM_RECOVERY_STATE_RECOVERED, // 2
PDM_RECOVERY_STATE_RECOVERED_NOT_READ, // 3
PDM_RECOVERY_STATE_SAVED, // 4
PDM_RECOVERY_STATE_NOT_SAVED, // 5
PDM_RECOVERY_STATE_APPENDED, // 6
// do not move
PDM_RECOVERY_STATE_NUMBER
} PDM_teRecoveryState;
typedef struct
{
/* this function gets called after a cold or warm start */
void (*prInitHwCb)(void);
/* this function gets called to erase the given sector */
void (*prEraseCb)(uint8_t u8Sector);
/* this function gets called to write data to an addresss
* within a given sector. address zero is the start of the
* given sector */
void (*prWriteCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
/* this function gets called to read data from an address
* within a given sector. address zero is the start of the
* given sector */
void (*prReadCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
} PDM_tsHwFncTable;
typedef enum
{
E_PDM_SYSTEM_EVENT_WEAR_COUNT_TRIGGER_VALUE_REACHED = 0,
E_PDM_SYSTEM_EVENT_WEAR_COUNT_MAXIMUM_REACHED,
E_PDM_SYSTEM_EVENT_SAVE_FAILED,
E_PDM_SYSTEM_EVENT_NOT_ENOUGH_SPACE,
E_PDM_SYSTEM_EVENT_LARGEST_RECORD_FULL_SAVE_NO_LONGER_POSSIBLE,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_CHECKSUM_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_SAVE_OK,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_READ_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_WRITE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_ERASE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_CHECK_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_DATA_WRITE_FAIL,
// nerdy event codes
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIRED,
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIR_FAILED,
E_PDM_SYSTEM_EVENT_SYSTEM_INTERNAL_BUFFER_WEAR_COUNT_SWAP,
E_PDM_SYSTEM_EVENT_SYSTEM_DUPLICATE_FILE_SEGMENT_DETECTED,
E_PDM_SYSTEM_EVENT_SYSTEM_ERROR,
// used in test harness
E_PDM_SYSTEM_EVENT_SEGMENT_PREWRITE,
E_PDM_SYSTEM_EVENT_SEGMENT_POSTWRITE,
E_PDM_SYSTEM_EVENT_SEQUENCE_DUPLICATE_DETECTED,
E_PDM_SYSTEM_EVENT_SEQUENCE_VERIFY_FAIL,
E_PDM_SYSTEM_EVENT_SMART_SAVE,
E_PDM_SYSTEM_EVENT_FULL_SAVE
} PDM_eSystemEventCode;
typedef struct
{
uint32_t u32eventNumber;
PDM_eSystemEventCode eSystemEventCode;
} PDM_tfpSystemEventCallback;
typedef void (*PDM_tpfvSystemEventCallback)(uint32_t u32eventNumber, PDM_eSystemEventCode eSystemEventCode);
/****************************************************************************/
/*** Exported Functions ***/
/****************************************************************************/
/*!
* @brief Initialise the PDM
*
* This function is to be called in order to initialise the PDM module
* call this EVERY cold start and EVERY warm start
*
* @param u16StartSegment: Start segment in flash
* @param u8NumberOfSegments: number of contiguous segments from u16StartSegment
* that belong to the PDM NVM space.
* @param fpvPDM_SystemEventCallback: function pointer passed by using layer
* to be notified of events/errors
*
* @retval PDM_E_STATUS_OK if success PDM_E_STATUS_INTERNAL_ERROR otherwise
*/
PUBLIC PDM_teStatus PDM_eInitialise(uint16_t u16StartSegment,
uint8_t u8NumberOfSegments,
PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Save a PDM record
*
* This function saves the specified application data from RAM to the specified record
* in NVM. The record is identified by means of a 16-bit user-defined value.
* When a data record is saved to the NVM for the first time, the data is written provided
* there are enough NVM segments available to hold the data. Upon subsequent save
* requests, if there has been a change between the RAM-based and NVM-based data
* buffers then the PDM will attempt to re-save only the segments that have changed
* (if no data has changed, no save will be performed). This is advantageous due to the
* restricted size of the NVM and the constraint that old data must be preserved while
* saving changed data to the NVM.
* Provided that you have registered a callback function with the PDM (see Section 6.3),
* the callback mechanism will signal when a save has failed. Upon failure, the callback
* function will be invoked and pass the event E_PDM_SYSTEM_EVENT_DESCRIPTOR_SAVE_FAILED
* to the application
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (specified record ID is invalid)
* @retval PDM_E_STATUS_NOT_SAVED (save to NVM failed)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordData(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save a PDM record next time in idle task
*
* Like PDM_eSaveRecordData, except that the record information is queued to
* saved in the idle task, when PDM_vIdleTask is called. Note that if the
* internal queue is full, the first record on the queue is saved immediately
* to make space for this record.
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordDataInIdleTask(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save queued PDM records
*
* Synchronously saves any queued record writes that have been generated by
* calls to PDM_eSaveRecordDataInIdleTask. To avoid this function taking too
* much time, the number of records that can be written can be limited by
* the u8WritesAllowed parameter. Use a value of 255 to effectively avoid
* this limit.
* @param u8WritesAllowed Maximum number of records that can be written
*
* @retval none
*/
PUBLIC void PDM_vIdleTask(uint8_t u8WritesAllowed);
/*!
* @brief Purge the pending event available in the queue
*
* @retval none
*/
PUBLIC void PDM_vQueuePurge(void);
/*!
* @brief Reads Partial Data from an Existing Record in the File System
*
* This function appends data to a record previously written.
* The record is identified by means of a 16-bit user-defined value.
*
* @param u16IdValue User-defined ID of the record to be read from
* @param u16TableOffset Data Offset
* @param pu8DataBuffer Data Buffer
* @param u16DataLength Length of input data, in bytes.
* @param pu16DataBytesRead Number Of Data Bytes Read u16IdValue
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (error in arguments)
* @retval PDM_E_STATUS_INTERNAL_ERROR
*/
PUBLIC PDM_teStatus PDM_eReadPartialDataFromExistingRecord(uint16_t u16IdValue,
uint16_t u16TableOffset,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function reads the specified record of application data from the NVM and stores
* the read data in the supplied data buffer in RAM. The record is specified using its
* unique 16-bit identifier.
* Before calling this function, it may be useful to call PDM_bDoesDataExist() in order
* to determine whether a record with the specified identifier exists in the EEPROM and,
* if it does, to obtain its size.
*
* @param u16IdValue User-defined ID of the record to be read
* @param pvDataBuffer Pointer to the data buffer in RAM where the read data is to
* be stored
* @param u16DataBufferLength Length of the data buffer, in bytes
* @param pu16DataBytesRead Pointer to a location to receive the number of data bytes
* read
*
* @retval PDM_E_STATUS_OK if success
* @retval PDM_E_STATUS_INVLD_PARAM otherwise i.e. specified record ID is invalid
*/
PUBLIC PDM_teStatus PDM_eReadDataFromRecord(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function deletes the specified record of application data in NVM.
* @see PDM_eDeleteAllData to alternatively delete all records in NVM
*
* @param u16IdValue User-defined ID of the record to be deleted
*
* @retval none
*/
PUBLIC void PDM_vDeleteDataRecord(uint16_t u16IdValue);
/*!
* @brief Delete a PDM record
*
* This function deletes all records in NVM, including both application data and stack
* context data, resulting in an empty PDM file system. The NVM segment Wear Count
* values are preserved (and incremented) throughout this function call.
* This function is to be used with extreme care in a Zigbee application context
*
* @param none
*
* @retval none
*/
PUBLIC void PDM_vDeleteAllDataRecords(void);
/*!
* @brief Seeks for a certain record by record identifier
*
* This function checks whether data associated with thd specified record ID
* exists in the NVM. If the data record exists, the function returns the data
* length, in bytes, in a location to which a pointer must be provided.
*
* @param u16IdValue User-defined ID of the record to be found
* @param pu16DataLength Pointer to location to receive length, in bytes,
* of data record (if any) associated with specified record ID
*
* @retval true if record was fond false otherwise
*/
PUBLIC bool_t PDM_bDoesDataExist(uint16_t u16IdValue, uint16_t *pu16DataLength);
/*!
* @brief Tells how many free segments are left in the PDM space
*
* This function returns the number of unused segments that remain in the NVM.
* Note that the returned parameter being a uint8_t the total expected number of
* segments cannot exceed 255
*
* @param none
*
* @retval Number of PDM NVM segments free
*/
PUBLIC uint8_t PDM_u8GetSegmentCapacity(void);
/*!
* @brief Tells how many free segments are occupied in the PDM space
*
* This function returns the number of used segments in the NVM
* @see PDM_u8GetSegmentCapacity
*
* @param none
*
* @retval Number of NVM segments used
*/
PUBLIC uint8_t PDM_u8GetSegmentOccupancy(void);
/*!
* @brief Register a User defined system callback function
*
* This function registers a callback function that will be called in error events
* @see PDM_pfGetSystemCallback
* @see PDM_eInitialise
*
* @param fpvPDM_SystemEventCallback function to replace the one that was set on PDM initialisation
*
* @retval none
*/
PUBLIC void PDM_vRegisterSystemCallback(PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Retrieve the previously defined system callback function
*
* This function retrieves the callback function that has been set by PDM_eInitialise
* or PDM_vRegisterSystemCallback
* @see PDM_vRegisterSystemCallback
* @see PDM_eInitialise
*
* @param none
*
* @retval fpvPDM_SystemEventCallback function used to notify error events
*/
PUBLIC PDM_tpfvSystemEventCallback PDM_pfGetSystemCallback(void);
PUBLIC void PDM_vSetWearCountTriggerLevel(uint32_t u32WearCountTriggerLevel);
PUBLIC PDM_teStatus PDM_eGetSegmentWearCount(uint8_t u8SegmentIndex, uint32_t *pu32WearCount);
PUBLIC PDM_teStatus PDM_eGetDeviceWearCountProfile(uint32_t au32WearCount[], uint8_t u8NumberOfSegments);
PUBLIC void PDM_vSetWearLevelDifference(uint32_t u32WearLevelDifference);
int PDM_Init(void);
#if defined UART_DEBUG
PUBLIC void vPDM_InitialiseDisplayDataInFileSystem(uint16_t *pau16PDMFileIDrecord, uint8_t u8NumberOfPDMSegments);
PUBLIC void vPDM_DisplayDataInFileSystem(void);
PUBLIC int iPDM_DisplayDataWithIdInFileSystem(uint16_t u16IdValue);
PUBLIC void vPDM_DisplayDataInNVM(void);
PUBLIC int iPDM_DisplayNVMsegmentData(uint8_t u8SegmentIndex);
PUBLIC char *psPDM_PrintEventID(PDM_eSystemEventCode eSystemEventCode);
PUBLIC int iPDM_ReadRawNVMsegmentDataToBuffer(uint8_t u8SegmentIndex,
uint8_t *pu8SegmentDataBuffer,
uint16_t *pu16SegmentDataSize);
#endif
/****************************************************************************/
/*** Exported Variables ***/
/****************************************************************************/
extern PUBLIC const uint32_t PDM_g_u32Version;
/*@}*/
#if defined __cplusplus
};
#endif
#endif /*PDM_H_INCLUDED*/
/****************************************************************************/
/*** END OF FILE ***/
/****************************************************************************/
+278
View File
@@ -0,0 +1,278 @@
/*****************************************************************************
*
* MODULE:
*
* COMPONENT:
*
* DESCRIPTION:
*
*****************************************************************************
*
* This software is owned by NXP B.V. and/or its supplier and is protected
* under applicable copyright laws. All rights are reserved. We grant You,
* and any third parties, a license to use this software solely and
* exclusively on NXP products [NXP Microcontrollers such as JN5168, JN5179].
* You, and any third parties must reproduce the copyright and warranty notice
* and any other legend of ownership on each copy or partial copy of the
* software.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright NXP B.V. 2016. All rights reserved
*
****************************************************************************/
/* Standard includes. */
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#if defined FSL_RTOS_FREE_RTOS && (FSL_RTOS_FREE_RTOS != 0)
#include "FreeRTOSConfig.h"
#include "projdefs.h"
#include "portable.h"
#else
#include "MemManager.h"
#endif
#include "FunctionLib.h"
#include "fsl_debug_console.h"
#include "Flash_Adapter.h"
#include "PDM.h"
typedef struct
{
uint8_t u8Level;
} tsMicroIntStorage;
#if defined(__GNUC__)
#define __WEAK_FUNC __attribute__((weak))
#elif defined(__ICCARM__)
#define __WEAK_FUNC __weak
#elif defined( __CC_ARM )
#define __WEAK_FUNC __weak
#endif
#if gUsePdm_d
/****************************************************************************/
/*** Macro Definitions ***/
/****************************************************************************/
/* In this module pvHeap_Alloc, vHeap_Free, vHeap_ResetHeap,
* vMicroIntEnableOnly, vMicroIntRestoreState
* are default weak implementations that can be overridden
* for USE_RTOS or DUAL_MODE_APP builds */
/****************************************************************************/
/*** Local Function Prototypes ***/
/****************************************************************************/
/****************************************************************************/
/*** Exported Variables ***/
/****************************************************************************/
/****************************************************************************/
/*** Local Variables ***/
/****************************************************************************/
/****************************************************************************/
/*** Imported Functions ***/
/****************************************************************************/
/****************************************************************************/
/*** Exported Functions ***/
/****************************************************************************/
/****************************************************************************/
/*** Type Definitions ***/
/****************************************************************************/
typedef enum
{
E_HEAP_ALLOC = 0,
E_HEAP_RESET,
E_FUNCTION_MAX
} eFunctionId;
/* Nested interrupt control */
#ifndef MICRO_SET_PRIMASK_LEVEL
#define MICRO_SET_PRIMASK_LEVEL(A) __set_PRIMASK(A)
#endif
// read back PRIMASK status into u32Store variable then disable the interrupts
#ifndef MICRO_DISABLE_AND_SAVE_INTERRUPTS
#define MICRO_DISABLE_AND_SAVE_INTERRUPTS(u32Store) \
u32Store = __get_PRIMASK(); __disable_irq();
#endif
#ifndef MICRO_GET_ACTIVE_INT_LEVEL
#define MICRO_GET_ACTIVE_INT_LEVEL __get_BASEPRI
#endif
#ifndef MICRO_SET_ACTIVE_INT_LEVEL_MAX
#define MICRO_SET_ACTIVE_INT_LEVEL_MAX(A) __set_BASEPRI_MAX(A)
#endif
#ifndef MICRO_SET_ACTIVE_INT_LEVEL
#define MICRO_SET_ACTIVE_INT_LEVEL(A) __set_BASEPRI(A)
#endif
/****************************************************************************
*
* NAME: pvHeap_Alloc
*
* DESCRIPTION:
* Allocates a block of memory from the heap.
*
* RETURNS:
* Pointer to block, or NULL if the heap didn't have enough space. If block
* was already assigned, returns original value and doesn't take anything
* from heap.
*
* NOTES:
* If buffer has already been allocated, it is not cleared.
* If it is a fresh allocation, it is cleared on request.
*
****************************************************************************/
__WEAK_FUNC void *pvHeap_Alloc(void *pvPointer, uint32_t u32BytesNeeded, bool_t bClear)
{
do {
if (pvPointer != NULL) break;
#if defined FSL_RTOS_FREE_RTOS && (FSL_RTOS_FREE_RTOS != 0)
pvPointer = pvPortMalloc(u32BytesNeeded);
#else
pvPointer = MEM_BufferAllocWithId(u32BytesNeeded, gPdmMemPoolId_c, (void*)__get_LR());
#endif
if (pvPointer == NULL) break;
if (bClear)
{
FLib_MemSet(pvPointer, 0, u32BytesNeeded);
}
} while (0);
return pvPointer;
}
/****************************************************************************
*
* NAME: vHeap_Free
*
* DESCRIPTION:
* Release a block of memory from the heap.
*
* RETURNS:
* none
* NOTES:
*
****************************************************************************/
__WEAK_FUNC void vHeap_Free(void *pvPointer)
{
#if defined FSL_RTOS_FREE_RTOS && (FSL_RTOS_FREE_RTOS != 0)
vPortFree(pvPointer);
#else
memStatus_t status;
status = MEM_BufferFree(pvPointer);
if (status != MEM_SUCCESS_c)
{
#ifdef DEBUG
PRINTF("MemMngt error freeing %08lx code=%d\r\n", (uint32_t)pvPointer, status);
#endif
}
#endif
}
__WEAK_FUNC void vHeap_ResetHeap(void)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
__WEAK_FUNC void vMicroIntEnableOnly(tsMicroIntStorage *int_storage, uint32_t u32EnableMask)
{
uint32_t primask_lvl;
MICRO_DISABLE_AND_SAVE_INTERRUPTS(primask_lvl);
int_storage->u8Level = (uint8_t)MICRO_GET_ACTIVE_INT_LEVEL();
MICRO_SET_ACTIVE_INT_LEVEL_MAX( 96 );
MICRO_SET_PRIMASK_LEVEL(primask_lvl);
}
__WEAK_FUNC void vMicroIntRestoreState(tsMicroIntStorage * int_storage)
{
MICRO_SET_ACTIVE_INT_LEVEL(int_storage->u8Level);
}
#endif
/****************************************************************************
*
* NAME: PDM_Init
*
* DESCRIPTION:
* Wrapper to call PDM Initialization with the right Flash configuration parameters
*
* Note: FLASH_Init must have been called beforehand in order to initialize gFlashConfig.
*
* RETURNS:
* 0: if no error, negative value otherwise
* NOTES:
*
****************************************************************************/
int PDM_Init(void)
{
int status = -1;
#if gUsePdm_d
static bool pdm_init_done = false;
do {
if (pdm_init_done)
{
status = 0;
break;
}
NV_Init(); /* used to setup the gFlashConfig.PFlashTotalSize value */
PDM_teStatus st = PDM_E_STATUS_INTERNAL_ERROR;
uint8_t *base = (uint8_t*)NV_STORAGE_END_ADDRESS;
size_t len = (size_t)((uint32_t)NV_STORAGE_START_ADDRESS + 1 - (uint32_t)NV_STORAGE_END_ADDRESS);
#ifdef DEBUG
uint8_t * flash_top = (uint8_t*)(gFlashConfig.PFlashTotalSize + gFlashConfig.PFlashBlockBase);
uint8_t * flash_base = (uint8_t*)gFlashConfig.PFlashBlockBase;
assert(base >= flash_base);
assert(base + len <= flash_top);
assert(len > FLASH_PAGE_SIZE*2);
#endif
#if !defined gPdmNbSegments || (gPdmNbSegments < NV_STORAGE_MAX_SECTORS)
#error "gPdmNbSegments should match NV_STORAGE_MAX_SECTORS"
#endif
uint32_t sect_sz_log = Flib_Log2(gFlashConfig.PFlashSectorSize);
st = PDM_eInitialise(ADDR2SEG(base, sect_sz_log),
SIZE2SEGNB(len, sect_sz_log), NULL);
if (st != PDM_E_STATUS_OK)
{
#ifdef DEBUG
PRINTF("PDM/NVM misconfiguration\r\n");
#endif
assert(st != PDM_E_STATUS_OK);
status = -st;
break;
}
pdm_init_done = true;
status = 0;
} while (0);
#endif
return status;
}
/*-----------------------------------------------------------*/
@@ -0,0 +1,68 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the header file for the Panic module.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef __PANIC_H__
#define __PANIC_H__
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
typedef uint32_t panicId_t;
typedef struct
{
panicId_t id;
uint32_t location;
uint32_t extra1;
uint32_t extra2;
uint32_t linkRegister;
uint32_t cpsr_contents; /* may not be used initially */
uint8_t stack_dump[4]; /* initially just contain the contents of the LR */
} panicData_t;
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
#ifndef gUsePanic_c
#define gUsePanic_c 0
#endif
#define ID_PANIC(grp,value) ((panicId_t)(((panicId_t)(grp) << 16)+((panicId_t)(value))))
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
void panic
(
panicId_t id,
uint32_t location,
uint32_t extra1,
uint32_t extra2
);
#endif /* __PANIC_H__ */
@@ -0,0 +1,86 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the source file for the Panic module.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "Panic.h"
#include "fsl_os_abstraction.h"
#if gLoggingActive_d
#include "dbg_logging.h"
#endif
/*! *********************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
********************************************************************************** */
#if gUsePanic_c
panicData_t panic_data;
#endif
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function will halt the system
*
* \param[in] id Description of the param2 in parameter
* \param[in] location address where the Panic occurred
* \param[in] extra1 parameter to be stored in Panic structure
* \param[in] extra2 parameter to be stored in Panic structure
*
********************************************************************************** */
void panic( panicId_t id, uint32_t location, uint32_t extra1, uint32_t extra2 )
{
#if gUsePanic_c
/* Save the Link Register */
volatile uint32_t savedLR = 0;
__asm("push {r2} ");
__asm("push {LR} ");
__asm("pop {r2} ");
#if defined(__GNUC__)
__asm("str r2, [SP, #24]");
#else
__asm("str r2, [SP, #4]");
#endif
__asm("pop {r2}");
panic_data.id = id;
panic_data.location = location;
panic_data.extra1 = extra1;
panic_data.extra2 = extra2;
panic_data.linkRegister = savedLR;
panic_data.cpsr_contents = 0;
OSA_InterruptDisable(); /* disable interrupts */
#if gLoggingActive_d
DbgLogDump(1);
#endif
/* infinite loop just to ensure this routine never returns */
for(;;)
{
__asm("NOP");
}
#endif
}
#if defined(__GNUC__)
void __attribute__((weak)) __assertion_failed(char* s) {}
#endif
+53
View File
@@ -0,0 +1,53 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* MCU reset related functions implementation
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/************************************************************************************
*************************************************************************************
* Include
*************************************************************************************
************************************************************************************/
#include "fsl_device_registers.h"
#ifdef CPU_JN518X
#include "fsl_reset.h"
#endif
/************************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
************************************************************************************/
/************************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
************************************************************************************/
void ResetMCU(void);
/************************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
************************************************************************************/
void ResetMCU(void)
{
#ifdef CPU_JN518X
RESET_SystemReset();
#else
NVIC_SystemReset();
#endif
while(1){}
}
/********************************** EOF ***************************************/
@@ -0,0 +1,822 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "Flash_Adapter.h"
#include "FunctionLib.h"
#include "fsl_os_abstraction.h"
#if gNvStorageIncluded_d
#include "NVM_Interface.h"
#endif
#include "Panic.h"
#include "fsl_debug_console.h"
/*****************************************************************************
*****************************************************************************
* Private macros
*****************************************************************************
*****************************************************************************/
#if (PGM_SIZE_BYTE == 4)
#define mProgBuffSizeInPgmWrUnits_c 16
#elif (PGM_SIZE_BYTE == 8)
#define mProgBuffSizeInPgmWrUnits_c 8
#else
#define mProgBuffSizeInPgmWrUnits_c 4
#endif
/* Generator for CRC calculations. */
#define POLGEN 0x1021
#ifdef CPU_JN518X
#include "rom_psector.h"
void ResetMCU(void);
#endif
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private prototypes
*************************************************************************************
********************************************************************************** */
static uint32_t NV_FlashProgramAdaptation(uint32_t dest, uint32_t size, uint8_t* pData);
#if !defined CPU_QN908X && ! defined CPU_JN518X
static uint8_t NV_VerifyCrcOverHWParameters(hardwareParameters_t* pHwParams);
static uint16_t NV_ComputeCrcOverHWParameters(hardwareParameters_t* pHwParams);
#endif
static void NV_Flash_WaitForCSEndAndDisableInterrupts(void);
#ifdef CPU_QN908X
static uint32_t SwFlashVerifyErase (uint32_t start, uint32_t lengthInBytes);
#endif
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
/* Hardware parameters */
hardwareParameters_t gHardwareParameters;
extern flash_config_t gFlashConfig;
#if !defined CPU_QN908X && !defined CPU_JN518X
static const uint8_t mProdDataIdentifier[10] = {"PROD_DATA:"};
#endif
#if (USE_RTOS)
static osaSemaphoreId_t mFlashAdapterSemaphoreId;
#endif
static volatile uint8_t mFA_CSFlag = 0;
static volatile uint8_t mFA_SemWaitCount = 0;
/*****************************************************************************
*****************************************************************************
* Private functions
*****************************************************************************
*****************************************************************************/
/*! *********************************************************************************
* \brief This function ensures that there are no critical sections on and disables interrupts.
*
* \param[in] none
* \return nothing
*
********************************************************************************** */
static void NV_Flash_WaitForCSEndAndDisableInterrupts(void)
{
#if (USE_RTOS)
#if (gNvStorageIncluded_d)
/*on freeRTOS NvIdle runs on a freeRTOS idle task hook which must never block. In this RTOS at least one task must be ready */
/*since NvIdle runs on the task which has the least priority in the system we can wait in a loop for the end of the critical section */
osaTaskId_t currentTaskId = OSA_TaskGetId();
if(currentTaskId == (osaTaskId_t)NvGetNvIdleTaskId())
{
while(1)
{
while (mFA_CSFlag);
OSA_InterruptDisable();
if(mFA_CSFlag == 0)
{
break;
}
OSA_InterruptEnable();
}
}
else
#endif
{
while(1)
{
OSA_InterruptDisable();
if(mFA_CSFlag == 0)
{
break;
}
mFA_SemWaitCount++;
OSA_InterruptEnable();
OSA_SemaphoreWait(mFlashAdapterSemaphoreId, osaWaitForever_c);
}
}
#else
OSA_InterruptDisable();
#endif
}
/*! *********************************************************************************
* \brief Write aligned data to FLASH
*
* \param[in] dest The address of the Flash location
* \param[in] size The number of bytes to be programed
* \param[in] pData Pointer to the data to be programmed to Flash
*
* \return error code
*
********************************************************************************** */
static uint32_t NV_FlashProgramAdaptation(uint32_t dest, uint32_t size, uint8_t* pData)
{
uint32_t progBuf[PGM_SIZE_BYTE/sizeof(uint32_t)];
uint32_t status = kStatus_FLASH_Success;
#if !defined (CPU_JN518X)
if( (size & (PGM_SIZE_BYTE - 0x01U)) != 0 )
{
return kStatus_FLASH_AlignmentError;
}
#if gFlashEraseDuringWrite
{
NV_FlashEraseSector(dest, size-1);
}
#endif
#else
if( (size & (PGM_SIZE_BYTE - 0x01U)) != 0 )
{
return kStatus_FLASH_AlignmentError;
}
if( (dest & MASK_LOG(PGM_SIZE_BYTE_LOG)) != 0 )
{
PRINTF("Unaligned flash address %08lx", dest);
return kStatus_FLASH_AlignmentError;
}
NV_FlashEraseSector(dest, size-1);
#endif
while(size)
{
FLib_MemCpy(progBuf, pData, PGM_SIZE_BYTE);
#if gNvDisableIntCmdSeq_c
NV_Flash_WaitForCSEndAndDisableInterrupts();
#endif
status = FLASH_PROGRAM_AREA(dest, progBuf, PGM_SIZE_BYTE);
#if gNvDisableIntCmdSeq_c
OSA_InterruptEnable();
#endif
if(status != kStatus_FLASH_Success)
{
break;
}
pData += PGM_SIZE_BYTE;
dest += PGM_SIZE_BYTE;
size -= PGM_SIZE_BYTE;
}
return status;
}
#if !defined CPU_QN908X && ! defined CPU_JN518X
/*! *********************************************************************************
* \brief Verifies if the CRC field matches computed CRC over stored values
*
* \param[in] pHwParams pointer to a structure containing HW parameters
*
* \return 1 on success, 0 otherwise
*
********************************************************************************** */
static uint8_t NV_VerifyCrcOverHWParameters(hardwareParameters_t* pHwParams)
{
uint8_t status = 0;
if(NV_ComputeCrcOverHWParameters(pHwParams) == pHwParams->hardwareParamsCrc)
{
status = 1;
}
else
{
status = 0;
}
return status;
}
/*! *********************************************************************************
* \brief Computes the CRC for the hardware parameters and stores it
*
* \param[in] pHwParams pointer to a structure containing HW parameters
*
* \return Computed CRC value.
*
********************************************************************************** */
static uint16_t NV_ComputeCrcOverHWParameters(hardwareParameters_t* pHwParams)
{
uint16_t computedCRC = 0;
uint8_t crcA;
uint8_t byte = 0;
if(NULL != pHwParams)
{
uint8_t *ptr = (uint8_t *)(&pHwParams->reserved);
uint16_t len = (uint8_t *)(&pHwParams->hardwareParamsCrc) -
(uint8_t *)(&pHwParams->reserved);
while(len)
{
byte = *ptr;
computedCRC ^= ((uint16_t)byte << 8);
for(crcA = 8; crcA; crcA--)
{
if(computedCRC & 0x8000) {
computedCRC <<= 1;
computedCRC ^= POLGEN;
}
else computedCRC <<= 1;
}
--len;
++ptr;
}
}
return computedCRC;
}
#endif
#ifdef CPU_QN908X
/*! *********************************************************************************
* \brief Flash verify erase software implementation
*
* \param[in] start - start address of the memory block to be verified
* \param[in] lengthInBytes - memory block length
*
* \return TRUE if the flash memory area is blank (erased), FALSE otherwise
*
********************************************************************************** */
uint32_t SwFlashVerifyErase (uint32_t start, uint32_t lengthInBytes)
{
uint8_t* pAddress = (uint8_t*)start;
flash_status_t status = kStatus_FLASH_Success;
do
{
if(*pAddress++ != 0xff)
{
status = kStatus_FLASH_EraseError;
break;
}
} while(--lengthInBytes);
return (uint32_t)status;
}
#endif
#ifdef CPU_JN518X
#define FLASH_WORD_SZ 16
/* This is kept as an example of code using the TRY .. CATCH for exceptions
* Using it raises some execution issues with a debugger
*/
uint32_t NV_ReadSweep(uint32_t start_addr, uint32_t end_addr)
{
uint32_t addr = start_addr;
TRY
{
while (addr < end_addr)
{
volatile uint32_t read_val;
read_val = *(uint32_t*)addr;
read_val = read_val;
addr += FLASH_WORD_SZ;
}
}
CATCH (BUS_EXCEPTION)
{
/* return page address if an error is detected */
return ROUND_FLOOR(addr, 9);
}
YRT;
return 0;
}
uint32_t NV_SafeReadFromFlash(uint8_t * ram_dst, uint8_t * flash_src, size_t size)
{
uint32_t au32Data[FLASH_WORD_SZ/sizeof(uint32_t)];
uint32_t st = kStatus_FLASH_Fail;
uint32_t nb_flash_words = (size + (FLASH_WORD_SZ-1)) / FLASH_WORD_SZ;
while (nb_flash_words-- > 0)
{
size_t sz;
sz = (size >= FLASH_WORD_SZ) ? FLASH_WORD_SZ : size;
st = FLASH_Read(FLASH, flash_src, 0, au32Data);
if (st != kStatus_FLASH_Success) break;
memcpy(ram_dst, (uint8_t*)&au32Data[0], sz);
ram_dst += sz;
flash_src += sz;
size -= sz;
}
return st;
}
void NV_FlashPerformAudit(void)
{
int status;
uint32_t addr = INT_STORAGE_START_OFFSET;
if (INT_STORAGE_END_OFFSET == INT_STORAGE_START_OFFSET) addr++;
uint32_t end = (uint32_t)0x9ddff;
uint32_t failed_addr;
uint8_t buf[FLASH_PAGE_SIZE];
while (addr <= ROUND_FLOOR(end, 9))
{
status = FLASH_BlankCheck(FLASH, (uint8_t*)addr, (uint8_t*)end);
if (kStatus_FLASH_Fail == status)
{
failed_addr = FLASH->DATAW[0]; /* is a flash word address */
failed_addr <<= 4;
addr = ROUND_FLOOR(failed_addr, 9);
status = NV_SafeReadFromFlash(buf, (uint8_t*)addr, FLASH_PAGE_SIZE);
if (kStatus_FLASH_Success != status)
{
status = FLASH_Erase(FLASH,
(uint8_t*)addr,
(uint8_t*)(addr+FLASH_PAGE_SIZE-1));
if (status != kStatus_FLASH_Success)
{
PRINTF("NV Audit Erase failed at addr=%08lx\r\n", addr);
break;
}
}
addr += FLASH_PAGE_SIZE;
}
else
{
addr = end;
}
}
}
#endif
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
#ifdef CPU_JN518X
int PsectorUpdateFlashAudit(uint32_t new_value)
{
int res = 1;
psector_page_data_t page_buf;
psector_page_data_t *page0 = (psector_page_data_t*)0x9e800;
memcpy(&page_buf, page0, FLASH_PAGE_SIZE);
((psector_page_data_t*)&page_buf)->page0_v3.flash_audit_done = new_value;
page_buf.hdr.version ++;
page_buf.hdr.checksum = psector_CalculateChecksum((psector_page_t *)&page_buf);
if (psector_WriteUpdatePage(PSECTOR_PAGE0_PART, (psector_page_t *)&page_buf) != WRITE_OK)
{
res = -1;
}
else
{
ResetMCU(); /* Commit now by forcing reset */
}
return res;
}
int psector_FlashAudit(void)
{
int res = -1;
do {
psector_page_data_t *page0 = (psector_page_data_t*)0x9e800;
uint32_t flash_audit_word = page0->page0_v3.flash_audit_done;
if ((flash_audit_word & 0xffff) == FLASH_AUDIT_DONE)
{
res = 0;
break;
}
else
{
/* Need to verify internal flash */
NV_FlashPerformAudit();
uint32_t flash_audit_code = (flash_audit_word & 0xffff0000u) | FLASH_AUDIT_DONE;
res = PsectorUpdateFlashAudit(flash_audit_code);
if (res < 0)
break;
}
} while (0);
return res;
}
#endif
/*! *********************************************************************************
* \brief Initialize the FLASH driver
*
********************************************************************************** */
void NV_Init(void)
{
static bool_t nvmInit = 0;
if(nvmInit == 0)
{
#ifdef CPU_QN908X
/* Configure Flash */
FLASH_GetDefaultConfig(&gFlashConfig);
gFlashConfig.blockBase = 0x0U;
#endif /* CPU_QN908X */
#ifdef gNVM_MULTICORE_SUPPORT_d
FLASH_SetProperty(&gFlashConfig, kFLASH_PropertyFlashMemoryIndex, 1);
#endif
/* Init Flash */
FLASH_INIT();
#if (defined(CPU_MKW36Z512VFP4) || defined(CPU_MKW36Z512VHT4))
/* KW36 has 256KB of FlexNVM mapped at adress 0x1000 0000 which also has an alias starting from address 0x0004 0000.
* Configured the Flash driver to treat the PFLASH bloxk and FlexNVM block as a continuous memory block. */
gFlashConfig.DFlashBlockBase = FSL_FEATURE_FLASH_PFLASH_BLOCK_SIZE * FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT;
#endif
#if (USE_RTOS)
if( (mFlashAdapterSemaphoreId = OSA_SemaphoreCreate(0)) == NULL )
{
panic( ID_PANIC(0,0), (uint32_t)NV_Init, 0, 0 );
}
#endif
#ifdef CPU_JN518X
if (!nvmInit)
{
if (psector_FlashAudit() == 0)
nvmInit = 1;
}
#else
nvmInit = 1;
#endif
}
}
/******************************************************************************
* Name: NvSetCriticalSection
* Description: enter critical section
* Parameters: -
* Return: -
******************************************************************************/
/*! *********************************************************************************
* \brief Start a critical section during which flash operations are not allowed
*
* \param[in] none
* \return nothing
*
********************************************************************************** */
void NV_Flash_SetCriticalSection
(
void
)
{
#if (USE_RTOS)
OSA_InterruptDisable();
++mFA_CSFlag;
OSA_InterruptEnable();
#endif
}
/*! *********************************************************************************
* \brief Start a critical section during which flash operations are not allowed
*
* \param[in] none
* \return nothing
*
********************************************************************************** */
void NV_Flash_ClearCriticalSection
(
void
)
{
#if (USE_RTOS)
OSA_InterruptDisable();
if(mFA_CSFlag)
{
mFA_CSFlag--;
}
OSA_InterruptEnable();
while(1)
{
OSA_InterruptDisable();
if(mFA_CSFlag)
{
break;
}
if(mFA_SemWaitCount == 0)
{
break;
}
mFA_SemWaitCount--;
OSA_InterruptEnable();
OSA_SemaphorePost(mFlashAdapterSemaphoreId);
}
OSA_InterruptEnable();
#endif
}
/*! *********************************************************************************
* \brief Verify erase data in Flash
*
* \param[in] start The address of the Flash location
* \param[in] lengthInBytes The number of bytes to be checked
* \param[in] margin
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashVerifyErase ( uint32_t start, uint32_t lengthInBytes)
{
uint32_t status;
#if gNvDisableIntCmdSeq_c
NV_Flash_WaitForCSEndAndDisableInterrupts();
#endif
status = FLASH_VERIFY_ERASE(start, lengthInBytes);
#if gNvDisableIntCmdSeq_c
OSA_InterruptEnable();
#endif
return status;
}
/*! *********************************************************************************
* \brief Write aligned data to FLASH
*
* \param[in] pSSDConfig Pointer to a flash config structure
* \param[in] dest The address of the Flash location
* \param[in] size The number of bytes to be programed
* \param[in] pData Pointer to the data to be programmed to Flash
* \param[in] pFlashCommandSequence Pointer to the Flash RAM function
*
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashProgram(uint32_t dest,
uint32_t size,
uint8_t* pData)
{
return NV_FlashProgramAdaptation(dest, size, pData);
}
/*! *********************************************************************************
* \brief Write data to FLASH
*
* \param[in] pSSDConfig Pointer to a flash config structure
* \param[in] dest The address of the Flash location
* \param[in] size The number of bytes to be programed
* \param[in] pData Pointer to the data to be programmed to Flash
* \param[in] pFlashCommandSequence Pointer to the Flash RAM function
*
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashProgramUnaligned(uint32_t dest,
uint32_t size,
uint8_t* pData)
{
uint8_t buffer[PGM_SIZE_BYTE];
uint32_t status;
do {
uint32_t align_addr = ROUND_FLOOR(dest, PGM_SIZE_BYTE_LOG);
uint16_t bytes = (dest - align_addr);
if( bytes )
{
uint16_t unalignedBytes = PGM_SIZE_BYTE - bytes;
if( unalignedBytes > size )
{
unalignedBytes = size;
}
if (FLib_CopyFromFlash(buffer, (void*)align_addr, PGM_SIZE_BYTE))
{
PRINTF("Raised error while reading from %08lx\r\n", align_addr);
}
FLib_MemCpy(&buffer[bytes], pData, unalignedBytes);
status = NV_FlashProgramAdaptation(align_addr, PGM_SIZE_BYTE, buffer);
if(status != kStatus_FLASH_Success) break;
dest += unalignedBytes;
/* if size is less than the distance to the end of program block
unalignedBytes has been shrunk , after size is decremented it will become 0 */
pData += unalignedBytes;
size -= unalignedBytes;
}
bytes = size & ~(PGM_SIZE_BYTE - 1U);
/* Now dest is on an aligned boundary */
/* bytes is an integer number of program blocks (pages) */
if( bytes )
{
status = NV_FlashProgramAdaptation(dest, bytes, pData);
if(status != kStatus_FLASH_Success) break;
dest += bytes;
pData += bytes;
size -= bytes;
}
/* dest is still aligned because we have increased it by a multiple of the program block (page) */
if( size )
{
if (
#ifdef CPU_JN518X
/* Avoid reading page if it is blank */
(FLASH_VERIFY_ERASE(dest, PGM_SIZE_BYTE) == kStatus_FLASH_Fail) &&
#endif
(FLib_CopyFromFlash(buffer, (void*)dest, PGM_SIZE_BYTE))
)
{
PRINTF("Raised error while reading from %08lx\r\n", (dest - bytes));
}
FLib_MemCpy(buffer, pData, size);
status = NV_FlashProgramAdaptation(dest, PGM_SIZE_BYTE, buffer);
if(status != kStatus_FLASH_Success) break;
}
status = kStatus_FLASH_Success;
} while (0);
return status;
}
/*! *********************************************************************************
* \brief Erase to 0xFF one ore more FLASH sectors.
*
* \param[in] pSSDConfig Pointer to a flash config structure
* \param[in] dest The start address of the first sector to be erased
* \param[in] size The amount of flash to be erased (multiple of sector size)
* \param[in] pFlashCommandSequence Pointer to the Flash RAM function
*
* \return error code
*
********************************************************************************** */
uint32_t NV_FlashEraseSector(uint32_t dest, uint32_t size)
{
uint32_t status;
#ifdef CPU_QN908X
uint32_t status_flags;
#endif
#if gNvDisableIntCmdSeq_c
NV_Flash_WaitForCSEndAndDisableInterrupts();
#endif
#if defined(CPU_QN908X)
status_flags = FLASH_GetStatusFlags();
if(status_flags & FLASH_INT_STAT_AHBL_INT_MASK)
{
FLASH_ClearStatusFlags(FLASH_INTCLR_AHBL_INTCLR_MASK);
}
if(status_flags & FLASH_INT_STAT_AHBH_INT_MASK)
{
FLASH_ClearStatusFlags(FLASH_INTCLR_AHBH_INTCLR_MASK);
}
#endif
status = FLASH_ERASE_AREA(dest, size);
#if gNvDisableIntCmdSeq_c
OSA_InterruptEnable();
#endif
return status;
}
#if !defined CPU_QN908X && !defined CPU_JN518X
/*! *********************************************************************************
* \brief Load the HW parameters from Flash to RAM
*
* \param[in] pHwParams pointer to a structure where HW parameters will be stored
*
* \return error code
*
********************************************************************************** */
uint32_t NV_ReadHWParameters(hardwareParameters_t *pHwParams)
{
hardwareParameters_t* pLocalParams = (hardwareParameters_t*)FREESCALE_PROD_DATA_BASE_ADDR;
uint32_t status = 0;
do {
if(NULL == pHwParams)
{
/* Invalid parameter */
status = 2;
break;
}
#ifdef CPU_JN518X
#if 0
if (NV_SafeReadFromFlash((uint8_t*)pHwParams,
(uint8_t*)pLocalParams,
sizeof(hardwareParameters_t)) == kStatus_FLASH_Success)
{
if (FLib_MemCmp(pHwParams,
(void*)mProdDataIdentifier,
sizeof(mProdDataIdentifier)) &&
NV_VerifyCrcOverHWParameters(pHwParams))
{
status = 0;
break;
}
}
else
{
NV_FlashEraseSector((uint32_t)pLocalParams, FLASH_PAGE_SIZE-1);
FLib_MemSet(pHwParams, 0xFF, sizeof(hardwareParameters_t));
status = 1;
}
#endif
#else
if (FLib_MemCmp(FREESCALE_PROD_DATA_BASE_ADDR, (void*)mProdDataIdentifier, sizeof(mProdDataIdentifier)) &&
NV_VerifyCrcOverHWParameters(pLocalParams))
{
FLib_MemCpy(pHwParams, FREESCALE_PROD_DATA_BASE_ADDR, sizeof(hardwareParameters_t));
status = 0;
}
else
{
FLib_MemSet(pHwParams, 0xFF, sizeof(hardwareParameters_t));
status = 1;
break;
}
#endif
} while (0);
return status;
}
/*! *********************************************************************************
* \brief Store the HW parameters to Flash
*
* \param[in] pHwParams pointer to a structure containing HW parameters
*
* \return error code of the Flash erase/write functions
*
********************************************************************************** */
uint32_t NV_WriteHWParameters(hardwareParameters_t *pHwParams)
{
uint32_t status = 0;
NV_Init();
#ifndef CPU_JN518X
#ifdef CPU_JN518X
status = FLASH_BlankCheck(FLASH, (uint8_t *)FREESCALE_PROD_DATA_BASE_ADDR,
(uint8_t *)(FREESCALE_PROD_DATA_BASE_ADDR + sizeof(hardwareParameters_t)));
#endif
if(
#ifdef CPU_JN518X
(status == kStatus_FLASH_Success) ||
#endif
!FLib_MemCmp(pHwParams, (void*)FREESCALE_PROD_DATA_BASE_ADDR, sizeof(hardwareParameters_t)))
{
pHwParams->hardwareParamsCrc = NV_ComputeCrcOverHWParameters(pHwParams);
FLib_MemCpy(pHwParams->identificationWord, (void*)mProdDataIdentifier, sizeof(mProdDataIdentifier));
#if defined(FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE)
status = NV_FlashEraseSector((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR, FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE);
#elif defined(FSL_FEATURE_FLASH_PAGE_SIZE_BYTES)
status = NV_FlashEraseSector((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR, FSL_FEATURE_FLASH_PAGE_SIZE_BYTES);
#endif
if( kStatus_FLASH_Success == status )
{
status = NV_FlashProgramUnaligned((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR,
sizeof(hardwareParameters_t),
(uint8_t*)pHwParams);
}
}
#endif
return status;
}
#endif /* neither CPU_QN908X not CPU_JN518X */
@@ -0,0 +1,238 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017, 2019 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef __FLASH_ADAPTER_H__
#define __FLASH_ADAPTER_H__
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
#include "fsl_flash.h"
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
/*
* Name: gNvDisableIntCmdSeq_c
* Description: this macro is used to enable/disable interrupts when the
* FTFL controller executes a command sequence. This macro
* has to be set according to NVM configuration. Therefore,
* if the FLASH region used by the NVM is placed in the same
* program block as the ISR's executable code, the interrupts
* MUST be disabled (because no code pre-fetching can be performed
* while FTFL controller executes a command sequence, i.e.
* program/erase). If the interrupts are not disabled, the
* system will assert a hard fault when the flash controller
* executes a command sequnce and an IRQ is about to be handled.
* If the NVM region is placed in a different program block than
* the ISR's code, this macro shall be set to FALSE (recommended).
*/
#ifndef gNvDisableIntCmdSeq_c
#define gNvDisableIntCmdSeq_c (1)
#endif
/* size of array to copy__Launch_Command function to.*/
/* It should be at least equal to actual size of __Launch_Command func */
/* User can change this value based on RAM size availability and actual size of __Launch_Command function */
#define LAUNCH_CMD_SIZE 64
#define PGM_SIZE_BYTE FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE
#define P_BLOCK_NUM FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT
#define P_SECTOR_SIZE FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE
/* Data Flash block information */
#define FLEXNVM_BASE FSL_FEATURE_FLASH_FLEX_NVM_START_ADDRESS
#define FLEXNVM_SECTOR_SIZE FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SECTOR_SIZE
#define FLEXNVM_BLOCK_SIZE FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SIZE
#define FLEXNVM_BLOCK_NUM FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_COUNT
/* Other defines */
#define DEBUGENABLE 0x00
#define FTFx_REG_BASE 0x40020000
#define P_FLASH_BASE 0x00000000
/* Flex Ram block information */
#define EERAM_BASE FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS
#define EERAM_SIZE FSL_FEATURE_FLASH_FLEX_RAM_SIZE
#define READ_NORMAL_MARGIN 0x00
#define READ_USER_MARGIN 0x01
#define READ_FACTORY_MARGIN 0x02
#define NV_FlashRead(pSrc, pDest, size) FLib_MemCpy((void*)(pDest), (void*)(pSrc), size);
#if defined(CPU_QN908X)
#define kStatus_FLASH_AlignmentError MAKE_STATUS(kStatusGroup_FLASH, 6)
#elif defined(CPU_JN518X)
#define FLASH_AUDIT_DONE 0xc65c
int PsectorUpdateFlashAudit(uint32_t new_value);
#endif
#define PGM_SIZE_BYTE_LOG LOG(PGM_SIZE_BYTE)
#define FLASH_PAGE_SZ_LOG LOG(FLASH_PAGE_SIZE)
#define IS_MULTIPLE_OF_SECT_SIZE(len) (((len) & (FLASH_PAGE_SIZE-1)) == 0)
#define SIZE2SEGNB(sz, sz_log) ((sz)>>(sz_log))
#define ADDR2SEG(addr, sz_log) (((uint32_t)(addr))>>(sz_log))
#if defined(__CC_ARM)
extern uint32_t Image$$INT_STORAGE$$Base[];
extern uint32_t Image$$INT_STORAGE$$Length[];
extern uint32_t Image$$INT_STORAGE$$End[];
#define INT_STORAGE_START_OFFSET ((uint32_t)Image$$INT_STORAGE$$Base)
#define INT_STORAGE_TOTAL_SIZE ((uint32_t)Image$$INT_STORAGE$$Length)
#define INT_STORAGE_END_OFFSET ((uint32_t)Image$$INT_STORAGE$$End)
#else /* defined(__CC_ARM) */
extern uint32_t INT_STORAGE_START[];
extern uint32_t INT_STORAGE_SIZE[];
extern uint32_t INT_STORAGE_END[];
extern uint32_t INT_STORAGE_SECTOR_SIZE[];
#define INT_STORAGE_START_OFFSET ((uint32_t)INT_STORAGE_END)
#define INT_STORAGE_END_OFFSET ((uint32_t)INT_STORAGE_START)
#define INT_STORAGE_TOTAL_SIZE ((uint32_t)INT_STORAGE_SIZE)
/*
* Name: NV_STORAGE_END_ADDRESS
* Description: NV_STORAGE_END_ADDRESS from linker command file is used by this code
* as Raw Sector Start Address.
*/
extern uint32_t NV_STORAGE_END_ADDRESS[];
/*
* Name: NV_STORAGE_SECTOR_SIZE
* Description: external symbol from linker command file, it represents the size
* of a FLASH sector
*/
extern uint32_t NV_STORAGE_SECTOR_SIZE[];
/*
* Name: NV_STORAGE_MAX_SECTORS
* Description: external symbol from linker command file, it represents the sectors
* count used by the ENVM storage system; it has to be a multiple of 2
*/
extern uint32_t NV_STORAGE_MAX_SECTORS[];
/*
* Name: NV_STORAGE_START_ADDRESS
* Description: NV_STORAGE_START_ADDRESS from linker command file is used by this code
* as Raw Sector End Address. Start is End address
*/
extern uint32_t NV_STORAGE_START_ADDRESS[];
#endif /* defined(__CC_ARM) */
/* Flash address of the Product Data sector */
#if defined(__CC_ARM)
extern uint32_t Load$$LR$$LR_Prod_Data$$Base[];
#define FREESCALE_PROD_DATA_BASE_ADDR Load$$LR$$LR_Prod_Data$$Base
#else
extern uint32_t FREESCALE_PROD_DATA_BASE_ADDR[];
#endif /* defined(__CC_ARM) */
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
/*! GCC would warn about packing, so add pragma to repress warning */
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wattributes"
#endif
typedef PACKED_STRUCT hardwareParameters_tag
{
uint8_t identificationWord[10]; /* valid data present */
#ifdef CPU_JN518X
uint8_t flash_audit_done;
uint8_t reserved[3];
#else
uint8_t reserved[32]; /* for backward compatibillity */
uint8_t ieee_802_15_4_address[8]; /* IEEE 802.15.4 MAC address */
uint8_t bluetooth_address[6]; /* Bluetooth address */
uint32_t xtalTrim; /* KW4x only */
uint32_t edCalibrationOffset; /* KW01 ED offset */
uint32_t pllFStepOffset; /* KW01 fine tune pll */
#endif
uint32_t gInternalStorageAddr; /* The start address of the internal storage used for OTA update.
A value of 0xFFFFFFFF means that the External storage is used.
Warning: The offset to this field in respect to the start address of the structure
must not be changed.*/
/* For forward compatibility additional fields may be added here
Existing data in flash will not be compatible after modifying the hardwareParameters_t typedef*/
uint16_t hardwareParamsCrc; /* crc for data between start of reserved area and start of hardwareParamsCrc field (not included). */
}hardwareParameters_t;
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
extern flash_config_t gFlashConfig;
extern hardwareParameters_t gHardwareParameters;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
void NV_Init(void);
uint32_t NV_FlashProgram( uint32_t dest,
uint32_t size,
uint8_t* pData);
uint32_t NV_FlashProgramUnaligned(uint32_t dest,
uint32_t size,
uint8_t* pData);
uint32_t NV_FlashEraseSector(uint32_t dest,
uint32_t size);
#if defined(CPU_JN518X)
#define FLASH_ERASE_AREA(ADDR, SZ) FLASH_Erase(FLASH, (uint8_t *)(ADDR), (uint8_t *)((ADDR) + (SZ) - 1))
#define FLASH_PROGRAM_AREA(ADDR, SRC, SZ) FLASH_Program(FLASH, (uint32_t *)(ADDR), (uint32_t*)(SRC), (SZ))
#define FLASH_INIT() FLASH_Init(FLASH)
#define FLASH_VERIFY_ERASE(ADDR, SZ) FLASH_BlankCheck(FLASH, (uint8_t *)(ADDR), (uint8_t *)((ADDR) + (SZ) - 1))
#elif defined(CPU_QN908X)
#define FLASH_VERIFY_ERASE(ADDR, SZ) SwFlashVerifyErase((ADDR), (SZ), ,kFLASH_MarginValueNormal)
#define FLASH_ERASE_AREA(ADDR, SZ) FLASH_Erase(&gFlashConfig, (ADDR), (SZ))
#define FLASH_PROGRAM_AREA(ADDR, SRC, SZ) FLASH_Program(&gFlashConfig, (uint32_t *)(ADDR), (uint32_t*)(SRC), (SZ))
#define FLASH_INIT() FLASH_Init(&gFlashConfig)
#define FLASH_VERIFY_ERASE(ADDR, SZ) SwFlashVerifyErase ((ADDR), (SZ))
#else
#define FLASH_VERIFY_ERASE(ADDR, SZ) NV_FlashVerifyErase(ADDR, SZ)
#define FLASH_ERASE_AREA, SZ) FLASH_Erase(&gFlashConfig, (ADDR), (SZ), kFLASH_ApiEraseKey)
#define FLASH_PROGRAM_AREA(ADDR, SRC, SZ) FLASH_Program(&gFlashConfig, (uint32_t *)(ADDR), (uint32_t*)(SRC), (SZ))
#define FLASH_INIT() FLASH_Init(&gFlashConfig)
#define FLASH_VERIFY_ERASE(ADDR, SZ) FLASH_VerifyErase(&gFlashConfig, (ADDR), (SZ), kFLASH_MarginValueNormal)
#endif
uint32_t NV_ReadHWParameters(hardwareParameters_t *pHwParams);
uint32_t NV_WriteHWParameters(hardwareParameters_t *pHwParams);
void NV_Flash_SetCriticalSection(void);
void NV_Flash_ClearCriticalSection(void);
#endif /* __FLASH_ADAPTER_H__ */
@@ -0,0 +1,573 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This module contains various common functions like copy and compare routines.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#include "FunctionLib.h"
#if gUseToolchainMemFunc_d
#include <string.h>
#endif
#if gFLib_CheckBufferOverflow_d
#include "MemManager.h"
#endif
/*! *********************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private prototypes
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function copies bytes from one buffer to another.
* The buffers should not overlap.
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \post The source and destination buffers must not overlap.
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpy (void* pDst,
const void* pSrc,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pDst, cBytes);
#endif
#if gUseToolchainMemFunc_d
memcpy(pDst, pSrc, cBytes);
#else
while (cBytes)
{
*((uint8_t*)pDst) = *((uint8_t*)pSrc);
pDst = ((uint8_t*)pDst)+1;
pSrc = ((uint8_t*)pSrc)+1;
cBytes--;
}
#endif
}
/*! *********************************************************************************
* \brief This function copies the specified number of bytes from the
* source address to the destination address. No attempt is made
* to handle overlapping copies to prevent loss of data.
* The copying is optimized to avoid alignment problems, and attempts
* to copy 32bit numbers optimally.
*
* \param[in] from_ptr Pointer to the source buffer.
*
* \param[in, out] to_ptr Pointer to the destination buffer.
*
* \param[in] number_of_bytes Number of bytes to copy (32 bit value).
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpyAligned32bit (void* to_ptr,
const void* from_ptr,
register uint32_t number_of_bytes)
{
uint8_t* from8_ptr = (uint8_t*)from_ptr;
uint8_t* to8_ptr = (uint8_t*)to_ptr;
uint16_t* from16_ptr = (uint16_t*)from_ptr;
uint16_t* to16_ptr = (uint16_t*)to_ptr;
register uint32_t* from32_ptr = (uint32_t*)from_ptr;
register uint32_t* to32_ptr = (uint32_t*)to_ptr;
register uint32_t loops;
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(to_ptr, number_of_bytes);
#endif
if (number_of_bytes > 3)
{
/* Try to align source on word */
if ((uint32_t)from_ptr & 1)
{
from8_ptr = (uint8_t*)from_ptr;
to8_ptr = (uint8_t*)to_ptr;
*to8_ptr++ = *from8_ptr++;
from_ptr = from8_ptr;
to_ptr = to8_ptr;
--number_of_bytes;
}
/* Try to align source on longword */
if ((uint32_t)from_ptr & 2)
{
from16_ptr = (uint16_t*)from_ptr;
to16_ptr = (uint16_t*)to_ptr;
*to16_ptr++ = *from16_ptr++;
from_ptr = from16_ptr;
to_ptr = to16_ptr;
number_of_bytes -= 2;
}
from32_ptr = (uint32_t*)from_ptr;
to32_ptr = (uint32_t*)to_ptr;
for (loops = number_of_bytes >> 2; loops != 0; loops--)
{
*to32_ptr++ = *from32_ptr++;
}
from_ptr = from32_ptr;
to_ptr = to32_ptr;
}
/* Copy all remaining bytes */
if (number_of_bytes & 2)
{
from16_ptr = (uint16_t*)from_ptr;
to16_ptr = (uint16_t*)to_ptr;
*to16_ptr++ = *from16_ptr++;
from_ptr = from16_ptr;
to_ptr = to16_ptr;
}
if (number_of_bytes & 1)
{
*(uint8_t*)to_ptr = *(uint8_t*)from_ptr;
}
}
/*! *********************************************************************************
* \brief Copy bytes from one buffer to another. The buffers should not overlap.
* The function can copy in either direction. If 'dir' is TRUE, then the function
* works like FLib_MemCpy(). If FALSE, the function swaps the buffer pointers
* before copying.
*
* \param[in, out] pBuf1 Pointer to the destination/source buffer.
*
* \param[in, out] pBuf2 Pointer to the source/destination buffer.
*
* \param[in] dir Direction to copy: pBuf2->pBuf1 if TRUE, pBuf1->pBuf2 if FALSE
*
* \param[in] n Number of bytes to copy.
*
* \post The source and destination buffers must not overlap.
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpyDir (void* pBuf1,
void* pBuf2,
bool_t dir,
uint32_t n)
{
if (dir)
{
FLib_MemCpy (pBuf1, pBuf2, n);
}
else
{
FLib_MemCpy (pBuf2, pBuf1, n);
}
}
/*! *********************************************************************************
* \brief The byte at index i from the source buffer is copied to index ((n-1) - i)
* in the destination buffer (and vice versa).
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemCpyReverseOrder (void* pDst,
const void* pSrc,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pDst, cBytes);
#endif
if(cBytes)
{
pDst = (uint8_t*)pDst + (uint32_t)(cBytes-1);
while (cBytes)
{
*((uint8_t*)pDst) = *((uint8_t*)pSrc);
pDst = (uint8_t*)pDst-1;
pSrc = (uint8_t*)pSrc+1;
cBytes--;
}
}
}
/*! *********************************************************************************
* \brief This function compares two buffers.
*
* \param[in] pData1 First buffer to compare.
*
* \param[in] pData2 Second buffer to compare.
*
* \param[in] cBytes Number of bytes to compare.
*
* \return This function return TRUE if the buffers are equal and FALSE otherwise.
*
* \post
*
* \remarks
*
********************************************************************************** */
bool_t FLib_MemCmp (const void* pData1, /* IN: First memory block to compare */
const void* pData2, /* IN: Second memory block to compare */
uint32_t cBytes /* IN: Number of bytes to compare. */
)
{
bool_t status = TRUE;
#if gUseToolchainMemFunc_d
if( memcmp(pData1, pData2, cBytes) )
{
status = FALSE;
}
#else
while (cBytes)
{
if ( *((uint8_t *)pData1) != *((uint8_t *)pData2))
{
status = FALSE;
break;
}
pData2 = (uint8_t* )pData2+1;
pData1 = (uint8_t* )pData1+1;
cBytes--;
}
#endif
return status;
}
/*! *********************************************************************************
* \brief This function compares each octet of a given location to a value.
*
* \param [in] pAddr location to be compared
*
* \param [in] val reference value
*
* \param [in] len length of location to be compared
*
* \return This function return TRUE if all octests match and FALSE otherwise.
*
* \post
*
* \remarks
*
********************************************************************************** */
bool_t FLib_MemCmpToVal
(
const void* pAddr,
uint8_t val,
uint32_t len
)
{
while(len)
{
len--;
if(((uint8_t *)pAddr)[len] != val)
{
return FALSE;
}
}
return TRUE;
}
/*! *********************************************************************************
* \brief This function resets all bytes in a specified buffer to a set value.
*
* \param[in,out] pDst Address of the buffer to set.
*
* \param[in] value Set value.
*
* \param[in] cBytes Number of bytes to set in the buffer (maximum 255 bytes).
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemSet (void* pData,
uint8_t value,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pData, cBytes);
#endif
#if gUseToolchainMemFunc_d
memset(pData, value, cBytes);
#else
while (cBytes)
{
((uint8_t* )pData)[--cBytes] = value;
}
#endif
}
/*! *********************************************************************************
* \brief This function copies a buffer,
* possibly into the same overlapping memory as it is taken from
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_MemInPlaceCpy (void* pDst,
void* pSrc,
uint32_t cBytes)
{
#if gFLib_CheckBufferOverflow_d && defined(MEM_TRACKING)
(void)MEM_BufferCheck(pDst, cBytes);
#endif
if (pDst != pSrc)
{
/* Do nothing if copying to same position */
if (pDst < pSrc)
{
/* If dst is before src in memory copy forward */
while (cBytes)
{
*((uint8_t*)pDst) = *((uint8_t*)pSrc);
pDst = ((uint8_t*)pDst)+1;
pSrc = ((uint8_t*)pSrc)+1;
cBytes--;
}
}
else
{
/* If dst is after src in memory copy backward */
while(cBytes)
{
cBytes--;
((uint8_t* )pDst)[cBytes] = ((uint8_t* )pSrc)[cBytes];
}
}
}
}
/*! *********************************************************************************
* \brief This function copies a 16bit value to an unaligned a memory block.
*
* \param[in, out] pDst Pointer to the destination memory block.
*
* \param[in] val16 The value to be copied.
*
********************************************************************************** */
void FLib_MemCopy16Unaligned (void* pDst,
uint16_t val16)
{
uint8_t* pData = (uint8_t*)pDst;
*pData++ = (uint8_t)(val16);
*pData = (uint8_t)(val16 >> 8);
return;
}
/*! *********************************************************************************
* \brief This function copies a 32bit value to an unaligned a memory block.
*
* \param[in, out] pDst Pointer to the destination memory block.
*
* \param[in] val32 The value to be copied.
*
********************************************************************************** */
void FLib_MemCopy32Unaligned (void* pDst,
uint32_t val32)
{
uint8_t* pData = (uint8_t*)pDst;
*pData++ = (uint8_t)(val32);
*pData++ = (uint8_t)(val32 >> 8);
*pData++ = (uint8_t)(val32 >> 16);
*pData++ = (uint8_t)(val32 >> 24);
return;
}
/*! *********************************************************************************
* \brief This function copies a 64bit value to an unaligned a memory block.
*
* \param[in, out] pDst Pointer to the destination memory block.
*
* \param[in] val64 The value to be copied.
*
********************************************************************************** */
void FLib_MemCopy64Unaligned (void* pDst,
uint64_t val64)
{
uint8_t* pData = (uint8_t*)pDst;
*pData++ = (uint8_t)(val64);
*pData++ = (uint8_t)(val64 >> 8);
*pData++ = (uint8_t)(val64 >> 16);
*pData++ = (uint8_t)(val64 >> 24);
*pData++ = (uint8_t)(val64 >> 32);
*pData++ = (uint8_t)(val64 >> 40);
*pData++ = (uint8_t)(val64 >> 48);
*pData = (uint8_t)(val64 >> 56);
return;
}
/*! *********************************************************************************
* \brief This function adds an offset to a pointer.
*
* \param[in,out] pPtr Pointer to the pointer to add the offset to
*
* \param[in] offset Offset to add to the specified pointer.
*
* \post
*
* \remarks
*
********************************************************************************** */
void FLib_AddOffsetToPointer (void** pPtr,
uint32_t offset)
{
(*pPtr) = ((uint8_t* )*pPtr) + offset;
}
/*! *********************************************************************************
* \brief This function returns the length of a NULL terminated string.
*
* \param[in] str A NULL terminated string
*
* \return the size of string in bytes
*
********************************************************************************** */
uint32_t FLib_StrLen(const char *str)
{
#if gUseToolchainMemFunc_d
return strlen(str);
#else
register uint32_t len=0;
while(*str != '\0')
{
str++;
len++;
}
return len;
#endif
}
#ifdef CPU_JN518X
/*! *********************************************************************************
* \brief This function copies bytes from FLASH to ram.
*
* \param[in, out] pDst Pointer to the destination buffer.
*
* \param[in] pSrc Pointer to the source buffer.
*
* \param[in] cBytes Number of bytes to copy.
*
* \remarks
*
********************************************************************************** */
bool_t FLib_CopyFromFlash(void* pDst,
const void* pSrc,
uint32_t cBytes)
{
bool_t raise_error = FALSE;
TRY
{
FLib_MemCpy(pDst, pSrc, cBytes);
}
CATCH (BUS_EXCEPTION)
{
raise_error = TRUE;
}
YRT;
return raise_error;
}
#else
bool_t FLib_CopyFromFlash(void* pDst,
const void* pSrc,
uint32_t cBytes)
{
FLib_MemCpy(pDst, pSrc, cBytes);
return false;
}
#endif
@@ -0,0 +1,320 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the Function Lib module header file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _FUNCTION_LIB_H_
#define _FUNCTION_LIB_H_
#include "EmbeddedTypes.h"
#include <setjmp.h>
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
#ifndef gUseToolchainMemFunc_d
#define gUseToolchainMemFunc_d 0
#endif
#ifndef gFLib_CheckBufferOverflow_d
#define gFLib_CheckBufferOverflow_d 0
#endif
#define FLib_MemSet16 FLib_MemSet
extern jmp_buf *exception_buf;
#define TRY do {jmp_buf exc_buf; \
jmp_buf *old_buf = exception_buf; \
exception_buf = &exc_buf; \
switch (setjmp(exc_buf)) { case 0:
#define CATCH(x) break; case x:
#define YRT } exception_buf = old_buf; } while(0)
typedef enum {
BUS_EXCEPTION = 1,
} EXCEPTION_ERROR_T;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
#ifdef __cplusplus
extern "C" {
#endif
/*! *********************************************************************************
* \brief Copy the content of one memory block to another. The amount of data to copy
* must be specified in number of bytes.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] pSrc Pointer to source memory block
* \param[in] cBytes Number of bytes to copy
*
********************************************************************************** */
void FLib_MemCpy (void* pDst,
const void* pSrc,
uint32_t cBytes
);
void FLib_MemCpyAligned32bit (void* to_ptr,
const void* from_ptr,
register uint32_t number_of_bytes);
void FLib_MemCpyDir (void* pBuf1,
void* pBuf2,
bool_t dir,
uint32_t n);
/*! *********************************************************************************
* \brief Copy bytes. The byte at index i from the source buffer is copied to index
* ((n-1) - i) in the destination buffer (and vice versa).
*
* \param[out] pDst Pointer to destination memory block
* \param[in] pSrc Pointer to source memory block
* \param[in] cBytes Number of bytes to copy
*
********************************************************************************** */
void FLib_MemCpyReverseOrder (void* pDst,
const void* pSrc,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Compare two memory blocks. The number of bytes to compare must be specified.
* If the blocks are equal byte by byte, the function returns TRUE,
* and FALSE otherwise.
*
* \param[in] pData1 First memory block to compare
* \param[in] pData2 Second memory block to compare
* \param[in] cBytes Number of bytes to compare
*
* \return TRUE if memory areas are equal. FALSE othwerwise.
*
********************************************************************************** */
bool_t FLib_MemCmp (const void* pData1,
const void* pData2,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Compare each byte of a memory block to a given value. The number of bytes to compare
must be specified.
* If all the bytes are equal to the given value, the function returns TRUE,
* and FALSE otherwise.
*
* \param[in] pAddr Location to be compared
* \param[in] val Reference value
* \param[in] length Number of bytes to compare
*
* \return TRUE if all bytes match and FALSE otherwise.
*
********************************************************************************** */
bool_t FLib_MemCmpToVal(const void* pAddr,
uint8_t val,
uint32_t len
);
/*! *********************************************************************************
* \brief Reset bytes in a memory block to a certain value. The value, and the number
* of bytes to be set, are supplied as arguments.
*
* \param[in] pData Pointer to memory block to reset
* \param[in] value Value that memory block will be set to
* \param[in] cBytes Number of bytes to set
*
********************************************************************************** */
void FLib_MemSet (void* pData,
uint8_t value,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Copy bytes, possibly into the same overlapping memory as it is taken from
*
* \param[out] pDst Pointer to destination memory block
* \param[in] pSrc Pointer to source memory block
* \param[in] cBytes Number of bytes to copy
*
********************************************************************************** */
void FLib_MemInPlaceCpy (void* pDst,
void* pSrc,
uint32_t cBytes
);
/*! *********************************************************************************
* \brief Copies a 16bit value to an unaligned a memory block.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] val16 The 16-bit value to be copied
*
********************************************************************************** */
void FLib_MemCopy16Unaligned (void* pDst,
uint16_t val16
);
/*! *********************************************************************************
* \brief Copies a 32bit value to an unaligned a memory block.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] val32 The 32-bit value to be copied
*
********************************************************************************** */
void FLib_MemCopy32Unaligned (void* pDst,
uint32_t val32
);
/*! *********************************************************************************
* \brief Copies a 64bit value to an unaligned a memory block.
*
* \param[out] pDst Pointer to destination memory block
* \param[in] val64 The 64-bit value to be copied
*
********************************************************************************** */
void FLib_MemCopy64Unaligned (void* pDst,
uint64_t val64
);
bool_t FLib_CopyFromFlash(void* pDst,
const void* pSrc,
uint32_t cBytes);
/*! *********************************************************************************
* \brief Add an offset to a pointer.
*
* \param[out] pPtr Pointer to the pointer to be updated
* \param[in] offset The offset(in bytes) to be added
*
********************************************************************************** */
void FLib_AddOffsetToPointer (void** pPtr,
uint32_t offset);
#define FLib_AddOffsetToPtr(pPtr,offset) FLib_AddOffsetToPointer((void**)(pPtr),(offset))
/*! *********************************************************************************
* \brief This function returns the length of a NULL terminated string.
*
* \param[in] str A NULL terminated string
*
* \return the size of string in bytes
*
********************************************************************************** */
uint32_t FLib_StrLen(const char *str);
/*! *********************************************************************************
* \brief Compare two bytes.
*
* \param[in] pCmp1 pointer to the first 2-byte compare value
* \param[in] pCmp2 pointer to the second 2-byte compare value
*
* \return TRUE if the two bytes are equal, and FALSE otherwise.
*
********************************************************************************** */
#define FLib_Cmp2Bytes(pCmp1, pCmp2) ((((uint8_t *)(pCmp1))[0] == ((uint8_t *)(pCmp2))[0]) && \
(((uint8_t *)(pCmp1))[1] == ((uint8_t *)(pCmp2))[1]))
/*! *********************************************************************************
* \brief Returns the maximum value of arguments a and b.
*
* \return The maximum value of arguments a and b
*
* \remarks
* The primitive should must be implemented as a macro, as it should be possible to
* evaluate the result on compile time if the arguments are constants.
*
********************************************************************************** */
#define FLib_GetMax(a,b) (((a) > (b)) ? (a) : (b))
/*! *********************************************************************************
* \brief Returns the minimum value of arguments a and b.
*
* \return The minimum value of arguments a and b
*
* \remarks
* The primitive should must be implemented as a macro, as it should be possible to
* evaluate the result on compile time if the arguments are constants.
*
********************************************************************************** */
#define FLib_GetMin(a,b) (((a) < (b)) ? (a) : (b))
#ifdef __GNUC__
#define _CLZ(x) __builtin_clz(x)
#endif
#if defined (__IAR_SYSTEMS_ICC__)
#define _CLZ(x) __CLZ(x)
#endif
#define _BSR(x) (31 - _CLZ(x))
static inline uint32_t Flib_Log2(uint32_t x)
{
uint32_t msb = _BSR(x);
/* if not a power of 2, round to next so that x remains <= (1<<msb) */
if (x > (1<< msb)) msb++;
return msb;
}
#define LOG_1(n) (((n) >= 2) ? 1 : 0)
#define LOG_2(n) (((n) >= 1<<2) ? (2 + LOG_1((n)>>2)) : LOG_1(n))
#define LOG_4(n) (((n) >= 1<<4) ? (4 + LOG_2((n)>>4)) : LOG_2(n))
#define LOG_8(n) (((n) >= 1<<8) ? (8 + LOG_4((n)>>8)) : LOG_4(n))
#define LOG(n) (((n) >= 1<<16) ? (16 + LOG_8((n)>>16)) : LOG_8(n))
#define MASK_LOG(log) ((1<<(log))-1)
#define ROUND_FLOOR(x, log) (((x) >> (log)) << (log))
#define ROUND_CEIL(x, log) ((((x) + MASK_LOG(log) ) >> (log)) << (log))
#define IS_POW_OF_TWO(x) (((x) & ((x)-1)) == 0)
#ifdef __cplusplus
}
#endif
#endif /* _FUNCTION_LIB_H_ */
@@ -0,0 +1,561 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the source file for the linked lists part of the Utils package.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "GenericList.h"
#include "fsl_os_abstraction.h"
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief Initialises the list descriptor.
*
* \param[in] list - List handle to init.
* max - Maximum number of elements in list. 0 for unlimited.
*
* \return void.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
void ListInit(listHandle_t list, uint32_t max)
{
list->head = NULL;
list->tail = NULL;
list->max = max;
list->size = 0;
}
/*! *********************************************************************************
* \brief Gets the list that contains the given element.
*
* \param[in] element - Handle of the element.
*
* \return NULL if element is orphan.
* Handle of the list the element is inserted into.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listHandle_t ListGetList(listElementHandle_t element)
{
return element->list;
}
/*! *********************************************************************************
* \brief Links element to the tail of the list.
*
* \param[in] list - ID of list to insert into.
* element - element to add
*
* \return gListFull_c if list is full.
* gListOk_c if insertion was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListAddTail(listHandle_t list, listElementHandle_t element)
{
OSA_InterruptDisable();
if( (list->max != 0) && (list->max == list->size) )
{
OSA_InterruptEnable();
return gListFull_c;
}
if(list->size == 0)
{
list->head = element;
}
else
{
list->tail->next = element;
}
element->prev = list->tail;
element->next = NULL;
element->list = list;
list->tail = element;
list->size++;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Links element to the head of the list.
*
* \param[in] list - ID of list to insert into.
* element - element to add
*
* \return gListFull_c if list is full.
* gListOk_c if insertion was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListAddHead(listHandle_t list, listElementHandle_t element)
{
OSA_InterruptDisable();
if( (list->max != 0) && (list->max == list->size) )
{
OSA_InterruptEnable();
return gListFull_c;
}
if(list->size == 0)
{
list->tail = element;
}
else
{
list->head->prev = element;
}
element->next = list->head;
element->prev = NULL;
element->list = list;
list->head = element;
list->size++;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Unlinks element from the head of the list.
*
* \param[in] list - ID of list to remove from.
*
* \return NULL if list is empty.
* ID of removed element(pointer) if removal was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListRemoveHead(listHandle_t list)
{
listElementHandle_t element;
OSA_InterruptDisable();
if((NULL == list) || (list->size == 0))
{
OSA_InterruptEnable();
return NULL; /*List is empty*/
}
element = list->head;
list->size--;
if(list->size == 0)
{
list->tail = NULL;
}
else
{
element->next->prev = NULL;
}
list->head = element->next; /*Is NULL if element is head*/
element->list = NULL;
OSA_InterruptEnable();
return element;
}
/*! *********************************************************************************
* \brief Gets head element ID.
*
* \param[in] list - ID of list.
*
* \return NULL if list is empty.
* ID of head element if list is not empty.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListGetHead(listHandle_t list)
{
return list->head;
}
/*! *********************************************************************************
* \brief Gets next element ID.
*
* \param[in] element - ID of the element.
*
* \return NULL if element is tail.
* ID of next element if exists.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListGetNext(listElementHandle_t element)
{
return element->next;
}
/*! *********************************************************************************
* \brief Gets previous element ID.
*
* \param[in] element - ID of the element.
*
* \return NULL if element is head.
* ID of previous element if exists.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listElementHandle_t ListGetPrev(listElementHandle_t element)
{
return element->prev;
}
/*! *********************************************************************************
* \brief Unlinks an element from its list.
*
* \param[in] element - ID of the element to remove.
*
* \return gOrphanElement_c if element is not part of any list.
* gListOk_c if removal was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListRemoveElement(listElementHandle_t element)
{
if(element->list == NULL)
{
return gOrphanElement_c; /*Element was previusly removed or never added*/
}
OSA_InterruptDisable();
if(element->prev == NULL) /*Element is head or solo*/
{
element->list->head = element->next; /*is null if solo*/
}
if(element->next == NULL) /*Element is tail or solo*/
{
element->list->tail = element->prev; /*is null if solo*/
}
if(element->prev != NULL) /*Element is not head*/
{
element->prev->next = element->next;
}
if(element->next != NULL) /*Element is not tail*/
{
element->next->prev = element->prev;
}
element->list->size--;
element->list = NULL;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Links an element in the previous position relative to a given member
* of a list.
*
* \param[in] element - ID of a member of a list.
* newElement - new element to insert before the given member.
*
* \return gOrphanElement_c if element is not part of any list.
* gListFull_c if list is full.
* gListOk_c if insertion was successful.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
listStatus_t ListAddPrevElement(listElementHandle_t element, listElementHandle_t newElement)
{
if(element->list == NULL)
{
return gOrphanElement_c; /*Element was previusly removed or never added*/
}
OSA_InterruptDisable();
if( (element->list->max != 0) && (element->list->max == element->list->size) )
{
OSA_InterruptEnable();
return gListFull_c;
}
if(element->prev == NULL) /*Element is list head*/
{
element->list->head = newElement;
}
else
{
element->prev->next = newElement;
}
newElement->list = element->list;
element->list->size++;
newElement->next = element;
newElement->prev = element->prev;
element->prev = newElement;
OSA_InterruptEnable();
return gListOk_c;
}
/*! *********************************************************************************
* \brief Gets the current size of a list.
*
* \param[in] list - ID of the list.
*
* \return Current size of the list.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
uint32_t ListGetSize(listHandle_t list)
{
return list->size;
}
/*! *********************************************************************************
* \brief Gets the number of free places in the list.
*
* \param[in] list - ID of the list.
*
* \return Available size of the list.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
uint32_t ListGetAvailable(listHandle_t list)
{
return (list->max - list->size);
}
/*! *********************************************************************************
* \brief Creates, tests and deletes a list. Any error that occurs will trap the
* CPU in a while(1) loop.
*
* \param[in] void.
*
* \return gListOk_c.
*
* \pre
*
* \post
*
* \remarks
*
********************************************************************************** */
/* To be removed or rewritten to remove MemManager dependency. */
#if 0
listStatus_t ListTest()
{
listHandle_t list;
listElementHandle_t element, newElement;
uint32_t i,freeBlocks;
const uint32_t max = 10;
freeBlocks = MEM_GetAvailableFwkBlocks(0);
/*create list*/
list = ListCreate(max);
LIST_ASSERT(list != NULL);
/*add elements*/
for(i=0; i<max; i++)
{
element = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListAddHead(list, element) == gListOk_c);
LIST_ASSERT(list->head == element)
ListRemoveHead(list);
LIST_ASSERT(ListAddTail(list, element) == gListOk_c);
LIST_ASSERT(list->tail == element);
if(ListGetSize(list) == 1)
{
LIST_ASSERT(list->head == element);
}
else
{
LIST_ASSERT(list->head != element);
}
}
LIST_ASSERT(ListGetSize(list) == max);
/*add one more element*/
element = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListAddTail(list, element) == gListFull_c);
list->max = 0;
LIST_ASSERT(ListAddTail(list, element) == gListOk_c);
LIST_ASSERT(ListGetSize(list) == max+1);
/*remove the extra element*/
element = ListRemoveHead(list);
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListGetSize(list) == max);
LIST_ASSERT(MEM_BufferFree(element) == MEM_SUCCESS_c);
list->max = max;
/*parse elements*/
element = ListGetHead(list);
LIST_ASSERT(element != NULL);
for(i=0; i<(max-1); i++)
{
element = ListGetNext(element);
LIST_ASSERT(element != NULL);
}
LIST_ASSERT(element == list->tail);
LIST_ASSERT(ListGetNext(element) == NULL);
/*Reverse parse elements*/
for(i=0; i<(max-1); i++)
{
element = ListGetPrev(element);
LIST_ASSERT(element != NULL);
}
LIST_ASSERT(element == list->head);
LIST_ASSERT(ListGetPrev(element) == NULL);
/*Add prev*/
element = ListGetHead(list);
LIST_ASSERT(element != NULL);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListFull_c);
LIST_ASSERT(ListGetHead(list) == element);
list->max = 0;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListOk_c);
LIST_ASSERT(ListGetHead(list) == newElement);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
element = list->head->next->next;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListOk_c);
LIST_ASSERT(list->head->next->next == newElement);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
element = list->tail;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gListOk_c);
LIST_ASSERT(list->tail->prev == newElement);
newElement = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(newElement != NULL);
element = (listElementHandle_t)MEM_BufferFwkAlloc(sizeof(listElement_t));
LIST_ASSERT(element != NULL);
element->list = NULL;
LIST_ASSERT(ListAddPrevElement(element, newElement) == gOrphanElement_c);
MEM_BufferFree(newElement);
MEM_BufferFree(element);
LIST_ASSERT(ListGetSize(list) == max+3);
/*Remove element*/
element = ListGetHead(list);
LIST_ASSERT(element == list->head);
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
LIST_ASSERT(list->head != element);
LIST_ASSERT(ListRemoveElement(element) == gOrphanElement_c);
MEM_BufferFree(element);
element = ListGetHead(list)->next->next;
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
MEM_BufferFree(element);
element = list->tail;
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
LIST_ASSERT(list->tail != element);
MEM_BufferFree(element);
LIST_ASSERT(ListGetSize(list) == max);
list->max = max;
for(i=0; i<(max-1); i++)
{
element = ListRemoveHead(list);
LIST_ASSERT(element != NULL);
MEM_BufferFree(element);
}
element = ListGetHead(list);
LIST_ASSERT(element != NULL);
LIST_ASSERT(ListRemoveElement(element) == gListOk_c);
LIST_ASSERT(list->head == NULL);
LIST_ASSERT(list->tail == NULL);
LIST_ASSERT(element->list == NULL);
MEM_BufferFree(element);
/*List is empty here.*/
LIST_ASSERT(ListGetSize(list) == 0);
element = ListRemoveHead(list);
LIST_ASSERT(element == NULL);
element = ListGetHead(list);
LIST_ASSERT(element == NULL);
MEM_BufferFree(list);
/*Did we produce a memory leak?*/
LIST_ASSERT(freeBlocks == MEM_GetAvailableFwkBlocks(0));
return gListOk_c;
}
#else
listStatus_t ListTest(void)
{
return gListOk_c;
}
#endif
@@ -0,0 +1,90 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the header file for the linked lists part of the Utils package.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _GENERIC_LIST_H_
#define _GENERIC_LIST_H_
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
/*! *********************************************************************************
*************************************************************************************
* Public macro definitions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
typedef enum
{
gListOk_c = 0,
gListFull_c,
gListEmpty_c,
gOrphanElement_c
}listStatus_t;
typedef struct list_tag
{
struct listElement_tag *head;
struct listElement_tag *tail;
uint16_t size;
uint16_t max;
}list_t, *listHandle_t;
typedef struct listElement_tag
{
struct listElement_tag *next;
struct listElement_tag *prev;
struct list_tag *list;
}listElement_t, *listElementHandle_t;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
void ListInit(listHandle_t list, uint32_t max);
listHandle_t ListGetList(listElementHandle_t element);
listStatus_t ListAddHead(listHandle_t list, listElementHandle_t element);
listStatus_t ListAddTail(listHandle_t list, listElementHandle_t element);
listElementHandle_t ListRemoveHead(listHandle_t list);
listElementHandle_t ListGetHead(listHandle_t list);
listElementHandle_t ListGetNext(listElementHandle_t element);
listElementHandle_t ListGetPrev(listElementHandle_t element);
listStatus_t ListRemoveElement(listElementHandle_t element);
listStatus_t ListAddPrevElement(listElementHandle_t element, listElementHandle_t newElement);
uint32_t ListGetSize(listHandle_t list);
uint32_t ListGetAvailable(listHandle_t list);
listStatus_t ListTest(void);
/*! *********************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
********************************************************************************** */
#ifdef DEBUG_ASSERT
#define LIST_ASSERT(condition) if(!(condition))while(1);
#else
#define LIST_ASSERT(condition) (void)(condition);
#endif
#endif /*_GENERIC_LIST_H_*/
@@ -0,0 +1,223 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the header file for the Memory Manager interface.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _MEM_MANAGER_H_
#define _MEM_MANAGER_H_
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include <stddef.h>
#include "EmbeddedTypes.h"
#include "GenericList.h"
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
/*Defines pools by block size and number of blocks. Must be alligned to 4 bytes.*/
#ifndef PoolsDetails_c
#define PoolsDetails_c \
_block_size_ 64 _number_of_blocks_ 8 _pool_id_(0) _eol_ \
_block_size_ 128 _number_of_blocks_ 2 _pool_id_(0) _eol_ \
_block_size_ 256 _number_of_blocks_ 6 _pool_id_(0) _eol_
#endif
#if defined (__IAR_SYSTEMS_ICC__)
/* __get_LR() declaration not included to avoid issues with different versions of IAR compiler */
#elif defined(__GNUC__)
#define __get_LR() __builtin_return_address(0)
#elif defined(__CC_ARM)
#define __get_LR() __return_address()
#endif
/* If a buffer (that is not allocated forever using MEM_BufferAllocForever()) is not freed
in MEM_CheckMemBufferThreshold_c ms, the device will enter into panic */
#ifndef MEM_CheckMemBufferThreshold_c
#define MEM_CheckMemBufferThreshold_c 120000 /* ms */
#endif
/* How often the device should check if the above threshold expired */
#ifndef MEM_CheckMemBufferInterval_c
#define MEM_CheckMemBufferInterval_c 15000 /* ms */
#endif
/* Default memory allocator */
#ifndef MEM_BufferAlloc
#define MEM_BufferAlloc(numBytes) MEM_BufferAllocWithId(numBytes, 0, (void*)__get_LR())
#endif
/* Allocate a block from the memory pools forever.*/
#define MEM_BufferAllocForever(numBytes,poolId) MEM_BufferAllocWithId(numBytes, poolId, (void*)((uintptr_t)__get_LR() | 0x80000000 ))
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
/*Defines statuses used in MEM_BufferAlloc and MEM_BufferFree*/
typedef enum
{
MEM_SUCCESS_c = 0, /* No error occurred */
MEM_INIT_ERROR_c, /* Memory initialization error */
MEM_ALLOC_ERROR_c, /* Memory allocation error */
MEM_FREE_ERROR_c, /* Memory free error */
MEM_UNKNOWN_ERROR_c /* something bad has happened... */
}memStatus_t;
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
/*Initialises the Memory Manager.*/
memStatus_t MEM_Init(void);
/*Returns the number of available blocks that fit the given size.*/
uint32_t MEM_GetAvailableBlocks(uint32_t size);
/*Frees the givem buffer.*/
memStatus_t MEM_BufferFree(void* buffer);
/*Returns the allocated buffer of the given size.*/
void* MEM_BufferAllocWithId(uint32_t numBytes , uint8_t poolId, void *pCaller);
/*Returns the size of a given buffer*/
uint16_t MEM_BufferGetSize(void* buffer);
/*Performs a write-read-verify test accross all pools*/
uint32_t MEM_WriteReadTest(void);
#if (defined MULTICORE_MEM_MANAGER) && ((defined MULTICORE_HOST) || (defined MULTICORE_BLACKBOX))
/*Free a buffer on the Master core*/
memStatus_t MEM_BufferFreeOnMaster(uint8_t * pBuff);
/*Free a buffer on the Slave core*/
memStatus_t MEM_BufferFreeOnSlave(uint8_t * pBuff);
#endif
/*! *********************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
********************************************************************************** */
#if defined(MEM_TRACKING) && defined(DEBUG_ASSERT)
#define MEM_ASSERT(condition) if(!(condition))while(1);
#else
#define MEM_ASSERT(condition) (void)(condition);
#endif
/*! *********************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
********************************************************************************** */
#ifdef MEM_STATISTICS
/*Statistics structure definition. Used by pools.*/
typedef struct poolStat_tag
{
uint16_t numBlocks;
uint16_t allocatedBlocks;
uint16_t allocatedBlocksPeak;
uint16_t allocationFailures;
uint16_t freeFailures;
#ifdef MEM_TRACKING
uint16_t poolFragmentWaste;
uint16_t poolFragmentWastePeak;
uint16_t poolFragmentMinWaste;
uint16_t poolFragmentMaxWaste;
#endif /*MEM_TRACKING*/
} poolStat_t;
#endif /*MEM_STATISTICS*/
#ifdef MEM_TRACKING
/*Definition for alloc indicators. Used in buffer tracking.*/
typedef enum
{
MEM_TRACKING_FREE_c = 0,
MEM_TRACKING_ALLOC_c,
}memTrackingStatus_t;
/*Tracking structure definition.*/
typedef PACKED_STRUCT BlockTracking_tag
{
void *blockAddr; /*Addr of Msg, not that this pointer is
4 byte bigger than the addr in the pool
has the header of the msg is 4 bytes */
uint16_t blockSize; /*Size of block in bytes.*/
uint16_t fragmentWaste; /*Size requested by allocator.*/
void *allocAddr; /*Return address of last Alloc made */
void *freeAddr; /*Return address of last Free made */
uint16_t allocCounter; /*No of time this msg has been allocated */
uint16_t freeCounter; /*No of time this msg has been freed */
memTrackingStatus_t allocStatus; /*1 if currently allocated, 0 if currently free */
uint32_t timeStamp;
void *pCaller;
}blockTracking_t;
#endif /*MEM_TRACKING*/
/*Header description for buffers.*/
typedef struct listHeader_tag
{
listElement_t link;
struct pools_tag *pParentPool;
}listHeader_t;
/*Buffer pools. Used by most functions*/
typedef struct pools_tag
{
list_t anchor; /* MUST be first element in pools_t struct */
uint16_t nextBlockSize;
uint16_t blockSize;
uint16_t poolId;
#ifdef MEM_STATISTICS
poolStat_t poolStatistics;
#endif /*MEM_STATISTICS*/
uint8_t numBlocks;
uint8_t allocatedBlocks;
}pools_t;
/*Buffer pool description. Used by MM_Init() for creating the buffer pools. */
typedef struct poolInfo_tag
{
uint16_t blockSize;
uint16_t poolSize;
uint16_t poolId;
uint8_t padding[2];
}poolInfo_t;
/*! *********************************************************************************
*************************************************************************************
* Private prototypes
*************************************************************************************
********************************************************************************** */
#ifdef MEM_TRACKING
uint8_t MEM_Track(listHeader_t *block, memTrackingStatus_t alloc, uint32_t address, uint16_t requestedSize, void *pCaller);
uint8_t MEM_BufferCheck(uint8_t *p, uint32_t size);
void MEM_CheckIfMemBuffersAreFreed(void);
/* The timestamp function used by MEM Manager for debug purpose.
The timestamp must be in milliseconds! */
#if defined(__IAR_SYSTEMS_ICC__)
extern __weak uint32_t MEM_GetTimeStamp(void);
#elif defined(__GNUC__)
extern __attribute__((weak)) uint32_t MEM_GetTimeStamp(void);
#endif
#endif /*MEM_TRACKING*/
#endif /* _MEM_MANAGER_H_ */
@@ -0,0 +1,815 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the source file for the Memory Manager.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
#include "fsl_os_abstraction.h"
#include "Panic.h"
#include "MemManager.h"
#include "FunctionLib.h"
/*! *********************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
********************************************************************************** */
#define _block_size_ {
#define _number_of_blocks_ ,
#define _pool_id_(a) , a ,
#define _eol_ },
poolInfo_t poolInfo[] =
{
PoolsDetails_c
{0, 0, 0} /*termination tag*/
};
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#define _block_size_ (sizeof(listHeader_t)+
#define _number_of_blocks_ ) *
#define _eol_ +
#define _pool_id_(a)
#define heapSize_c (PoolsDetails_c 0)
/* Heap */
uint32_t memHeap[heapSize_c/sizeof(uint32_t)];
const uint32_t heapSize = heapSize_c;
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#define _block_size_ 0 *
#define _number_of_blocks_ + 0 *
#define _eol_ + 1 +
#define _pool_id_(a)
#define poolCount (PoolsDetails_c 0)
/* Memory pool info and anchors. */
pools_t memPools[poolCount];
#ifdef MEM_STATISTICS
pools_t memPoolsSnapShot[poolCount];
#endif
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#ifdef MEM_TRACKING
#ifndef NUM_OF_TRACK_PTR
#define NUM_OF_TRACK_PTR 1
#endif
#define _block_size_ 0*
#define _number_of_blocks_ +
#define _eol_ +
#define _pool_id_(a)
#define mTotalNoOfMsgs_d (PoolsDetails_c 0)
static const uint16_t mTotalNoOfMsgs_c = mTotalNoOfMsgs_d;
blockTracking_t memTrack[mTotalNoOfMsgs_d];
#undef _block_size_
#undef _number_of_blocks_
#undef _eol_
#undef _pool_id_
#endif /*MEM_TRACKING*/
/* Free messages counter. Not used by module. */
uint16_t gFreeMessagesCount;
#ifdef MEM_STATISTICS
uint16_t gFreeMessagesCountMin = 0xFFFF;
uint16_t gTotalFragmentWaste = 0;
uint16_t gMaxTotalFragmentWaste = 0;
#endif
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function initializes the message module private variables.
* Must be called at boot time, or if device is reset.
*
* \param[in] none
*
* \return MEM_SUCCESS_c if initialization is successful. (It's always successful).
*
********************************************************************************** */
memStatus_t MEM_Init(void)
{
poolInfo_t *pPoolInfo = poolInfo; /* IN: Memory layout information */
pools_t *pPools = memPools;/* OUT: Will be initialized with requested memory pools. */
uint8_t *pHeap = (uint8_t *)memHeap;/* IN: Memory heap.*/
uint16_t poolN;
#ifdef MEM_TRACKING
uint16_t memTrackIndex = 0;
#endif /*MEM_TRACKING*/
gFreeMessagesCount = 0;
for(;;)
{
poolN = pPoolInfo->poolSize;
ListInit((listHandle_t)&pPools->anchor, poolN);
#ifdef MEM_STATISTICS
pPools->poolStatistics.numBlocks = 0;
pPools->poolStatistics.allocatedBlocks = 0;
pPools->poolStatistics.allocatedBlocksPeak = 0;
pPools->poolStatistics.allocationFailures = 0;
pPools->poolStatistics.freeFailures = 0;
#ifdef MEM_TRACKING
pPools->poolStatistics.poolFragmentWaste = 0;
pPools->poolStatistics.poolFragmentWastePeak = 0;
pPools->poolStatistics.poolFragmentMinWaste = 0xFFFF;
pPools->poolStatistics.poolFragmentMaxWaste = 0;
#endif /*MEM_TRACKING*/
#endif /*MEM_STATISTICS*/
while(poolN)
{
/* Add block to list of free memory. */
ListAddTail((listHandle_t)&pPools->anchor, (listElementHandle_t)&((listHeader_t *)pHeap)->link);
((listHeader_t *)pHeap)->pParentPool = pPools;
#ifdef MEM_STATISTICS
pPools->poolStatistics.numBlocks++;
#endif /*MEM_STATISTICS*/
pPools->numBlocks++;
gFreeMessagesCount++;
#ifdef MEM_TRACKING
memTrack[memTrackIndex].blockAddr = (void *)(pHeap + sizeof(listHeader_t));
memTrack[memTrackIndex].blockSize = pPoolInfo->blockSize;
memTrack[memTrackIndex].fragmentWaste = 0;
memTrack[memTrackIndex].allocAddr = NULL;
memTrack[memTrackIndex].allocCounter = 0;
memTrack[memTrackIndex].allocStatus = MEM_TRACKING_FREE_c;
memTrack[memTrackIndex].freeAddr = NULL;
memTrack[memTrackIndex].freeCounter = 0;
memTrackIndex++;
#endif /*MEM_TRACKING*/
/* Add block size (without list header)*/
pHeap += pPoolInfo->blockSize + sizeof(listHeader_t);
poolN--;
}
pPools->blockSize = pPoolInfo->blockSize;
pPools->poolId = pPoolInfo->poolId;
pPools->nextBlockSize = (pPoolInfo+1)->blockSize;
if(pPools->nextBlockSize == 0)
{
break;
}
pPools++;
pPoolInfo++;
}
return MEM_SUCCESS_c;
}
/*! *********************************************************************************
* \brief This function returns the number of available blocks greater or
* equal to the given size.
*
* \param[in] size - Size of blocks to check for availability.
*
* \return Number of available blocks greater or equal to the given size.
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
uint32_t MEM_GetAvailableBlocks
(
uint32_t size
)
{
pools_t *pPools = memPools;
uint32_t pTotalCount = 0;
for(;;)
{
if(size <= pPools->blockSize)
{
pTotalCount += ListGetSize((listHandle_t)&pPools->anchor);
}
if(pPools->nextBlockSize == 0)
{
break;
}
pPools++;
}
return pTotalCount;
}
/*! *********************************************************************************
* \brief Allocate a block from the memory pools. The function uses the
* numBytes argument to look up a pool with adequate block sizes.
* \param[in] numBytes - Size of buffer to allocate.
*
* \return Pointer to the allocated buffer, NULL if failed.
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
/*! *********************************************************************************
* \brief Allocate a block from the memory pools. The function uses the
* numBytes argument to look up a pool with adequate block sizes.
* \param[in] numBytes - Size of buffer to allocate.
* \param[in] poolId - The ID of the pool where to search for a free buffer.
* \param[in] pCaller - pointer to the caller function (Debug purpose)
*
* \return Pointer to the allocated buffer, NULL if failed.
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
void* MEM_BufferAllocWithId
(
uint32_t numBytes,
uint8_t poolId,
void *pCaller
)
{
#ifdef MEM_TRACKING
/* Save the Link Register */
volatile uint32_t savedLR = (uint32_t) __get_LR();
#endif
#if defined(MEM_TRACKING) || defined(MEM_DEBUG_OUT_OF_MEMORY)
uint16_t requestedSize = numBytes;
#endif /*MEM_TRACKING*/
#ifdef MEM_STATISTICS
bool_t allocFailure = FALSE;
#endif
pools_t *pPools = memPools;
listHeader_t *pBlock;
OSA_InterruptDisable();
while(numBytes)
{
if( (numBytes <= pPools->blockSize) && (poolId == pPools->poolId) )
{
pBlock = (listHeader_t *)ListRemoveHead((listHandle_t)&pPools->anchor);
if(NULL != pBlock)
{
pBlock++;
gFreeMessagesCount--;
pPools->allocatedBlocks++;
#ifdef MEM_STATISTICS
if(gFreeMessagesCount < gFreeMessagesCountMin)
{
gFreeMessagesCountMin = gFreeMessagesCount;
}
pPools->poolStatistics.allocatedBlocks++;
if ( pPools->poolStatistics.allocatedBlocks > pPools->poolStatistics.allocatedBlocksPeak )
{
pPools->poolStatistics.allocatedBlocksPeak = pPools->poolStatistics.allocatedBlocks;
}
MEM_ASSERT(pPools->poolStatistics.allocatedBlocks <= pPools->poolStatistics.numBlocks);
#endif /*MEM_STATISTICS*/
#ifdef MEM_TRACKING
MEM_Track(pBlock, MEM_TRACKING_ALLOC_c, savedLR, requestedSize, pCaller);
#endif /*MEM_TRACKING*/
OSA_InterruptEnable();
return pBlock;
}
else
{
#ifdef MEM_STATISTICS
if(!allocFailure)
{
pPools->poolStatistics.allocationFailures++;
allocFailure = TRUE;
}
#endif /*MEM_STATISTICS*/
if(numBytes > pPools->nextBlockSize)
{
break;
}
/* No more blocks of that size, try next size. */
numBytes = pPools->nextBlockSize;
}
}
/* Try next pool*/
if(pPools->nextBlockSize)
{
pPools++;
}
else
{
numBytes = 0;
}
}
#ifdef MEM_DEBUG_OUT_OF_MEMORY
if (requestedSize)
{
panic( 0, (uint32_t)MEM_BufferAllocWithId, 0, 0);
}
#endif
OSA_InterruptEnable();
return NULL;
}
/*! *********************************************************************************
* \brief Deallocate a memory block by putting it in the corresponding pool
* of free blocks.
*
* \param[in] buffer - Pointer to buffer to deallocate.
*
* \return MEM_SUCCESS_c if deallocation was successful, MEM_FREE_ERROR_c if not.
*
* \pre Memory manager must be previously initialized.
*
* \remarks Never deallocate the same buffer twice.
*
********************************************************************************** */
#if (defined MULTICORE_MEM_MANAGER) && ((defined MULTICORE_HOST) || (defined MULTICORE_BLACKBOX))
#if defined MULTICORE_HOST
memStatus_t MEM_BufferFreeOnMaster
#elif defined MULTICORE_BLACKBOX
memStatus_t MEM_BufferFreeOnSlave
#endif /* MULTICORE_HOST */
(
uint8_t *pBuff
)
{
#ifdef MEM_TRACKING
/* Save the Link Register */
volatile uint32_t savedLR = (uint32_t) __get_LR();
#endif /*MEM_TRACKING*/
listHeader_t *pHeader;
if( pBuff == NULL )
{
return MEM_FREE_ERROR_c;
}
pHeader = (listHeader_t *)pBuff-1;
if( ((uint8_t*)pHeader < (uint8_t*)memHeap) || ((uint8_t*)pHeader > ((uint8_t*)memHeap + sizeof(memHeap))) )
{
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
}
else
{
return MEM_BufferFree(pBuff);
}
}
#endif /* (defined MULTICORE_MEM_MANAGER) && ((defined MULTICORE_HOST) || (defined MULTICORE_BLACKBOX)) */
memStatus_t MEM_BufferFree
(
void* buffer /* IN: Block of memory to free*/
)
{
#ifdef MEM_TRACKING
/* Save the Link Register */
volatile uint32_t savedLR = (uint32_t) __get_LR();
#endif /*MEM_TRACKING*/
listHeader_t *pHeader;
pools_t *pParentPool;
pools_t *pool;
if( buffer == NULL )
{
return MEM_FREE_ERROR_c;
}
pHeader = (listHeader_t *)buffer-1;
if( ((uint8_t*)pHeader < (uint8_t*)memHeap) || ((uint8_t*)pHeader > ((uint8_t*)memHeap + sizeof(memHeap))) )
{
#if (defined MULTICORE_MEM_MANAGER) && (defined MULTICORE_BLACKBOX)
return MEM_BufferFreeOnMaster(buffer);
#elif (defined MULTICORE_MEM_MANAGER) && (defined MULTICORE_HOST)
return MEM_BufferFreeOnSlave(buffer);
#else
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
#endif
}
OSA_InterruptDisable();
pParentPool = (pools_t *)pHeader->pParentPool;
pool = memPools;
for(;;)
{
if (pParentPool == pool)
{
break;
}
if(pool->nextBlockSize == 0)
{
/* The parent pool was not found! This means that the memory buffer is corrupt or
that the MEM_BufferFree() function was called with an invalid parameter */
#ifdef MEM_STATISTICS
pParentPool->poolStatistics.freeFailures++;
#endif /*MEM_STATISTICS*/
OSA_InterruptEnable();
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
}
pool++;
}
if( pHeader->link.list != NULL )
{
/* The memory buffer appears to be enqueued in a linked list.
This list may be the free memory buffers pool, or another list. */
#ifdef MEM_STATISTICS
pParentPool->poolStatistics.freeFailures++;
#endif /*MEM_STATISTICS*/
OSA_InterruptEnable();
#ifdef MEM_DEBUG_INVALID_POINTERS
panic( 0, (uint32_t)MEM_BufferFree, 0, 0);
#endif
return MEM_FREE_ERROR_c;
}
gFreeMessagesCount++;
ListAddTail((listHandle_t)&pParentPool->anchor, (listElementHandle_t)&pHeader->link);
pParentPool->allocatedBlocks--;
#ifdef MEM_STATISTICS
MEM_ASSERT(pParentPool->poolStatistics.allocatedBlocks > 0);
pParentPool->poolStatistics.allocatedBlocks--;
#endif /*MEM_STATISTICS*/
#ifdef MEM_TRACKING
MEM_Track(buffer, MEM_TRACKING_FREE_c, savedLR, 0, NULL);
#endif /*MEM_TRACKING*/
OSA_InterruptEnable();
return MEM_SUCCESS_c;
}
/*! *********************************************************************************
* \brief Determines the size of a memory block
*
* \param[in] buffer - Pointer to buffer.
*
* \return size of memory block
*
* \pre Memory manager must be previously initialized.
*
********************************************************************************** */
uint16_t MEM_BufferGetSize
(
void* buffer /* IN: Block of memory to free*/
)
{
if( buffer )
{
return ((pools_t *)((listHeader_t *)buffer-1)->pParentPool)->blockSize;
}
return 0;
}
/*! *********************************************************************************
*************************************************************************************
* Private functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function updates the tracking array element corresponding to the given
* block.
*
* \param[in] block - Pointer to the block.
* \param[in] alloc - Indicates whether an allocation or free operation was performed
* \param[in] address - Address where MEM_BufferAlloc or MEM_BufferFree was called
* \param[in] requestedSize - Indicates the requested buffer size passed to MEM_BufferAlloc.
* Has no use if a free operation was performed.
*
* \return Returns TRUE if correct allocation or dealocation was performed, FALSE if a
* buffer was allocated or freed twice.
*
********************************************************************************** */
#ifdef MEM_TRACKING
uint8_t MEM_Track(listHeader_t *block, memTrackingStatus_t alloc, uint32_t address, uint16_t requestedSize, void *pCaller)
{
uint16_t i;
blockTracking_t *pTrack = NULL;
#ifdef MEM_STATISTICS
poolStat_t * poolStatistics = (poolStat_t *)&((pools_t *)( (listElementHandle_t)(block-1)->pParentPool ))->poolStatistics;
#endif
for( i=0; i<mTotalNoOfMsgs_c; i++ )
{
if( block == memTrack[i].blockAddr )
{
pTrack = &memTrack[i];
break;
}
}
if( !pTrack || pTrack->allocStatus == alloc)
{
#ifdef MEM_DEBUG
panic( 0, (uint32_t)MEM_Track, 0, 0);
#endif
return FALSE;
}
pTrack->allocStatus = alloc;
pTrack->pCaller = (void*)((uint32_t)pCaller & 0x7FFFFFFF);
if(alloc == MEM_TRACKING_ALLOC_c)
{
pTrack->fragmentWaste = pTrack->blockSize - requestedSize;
pTrack->allocCounter++;
pTrack->allocAddr = (void *)address;
if( (uint32_t)pCaller & 0x80000000 )
{
pTrack->timeStamp = 0xFFFFFFFF;
}
else
{
pTrack->timeStamp = MEM_GetTimeStamp();
}
#ifdef MEM_STATISTICS
gTotalFragmentWaste += pTrack->fragmentWaste;
if(gTotalFragmentWaste > gMaxTotalFragmentWaste)
{
gMaxTotalFragmentWaste = gTotalFragmentWaste;
FLib_MemCpy(&memPoolsSnapShot[0], &memPools[0], sizeof(memPools));
}
poolStatistics->poolFragmentWaste += pTrack->fragmentWaste;
if(poolStatistics->poolFragmentWaste > poolStatistics->poolFragmentWastePeak)
poolStatistics->poolFragmentWastePeak = poolStatistics->poolFragmentWaste;
if(pTrack->fragmentWaste < poolStatistics->poolFragmentMinWaste)
{
poolStatistics->poolFragmentMinWaste = pTrack->fragmentWaste;
}
if(pTrack->fragmentWaste > poolStatistics->poolFragmentMaxWaste)
{
poolStatistics->poolFragmentMaxWaste = pTrack->fragmentWaste;
}
if(poolStatistics->allocatedBlocks == poolStatistics->numBlocks)
{
//__asm("BKPT #0\n") ; /* cause the debugger to stop */
}
#endif /*MEM_STATISTICS*/
}
else
{
#ifdef MEM_STATISTICS
poolStatistics->poolFragmentWaste -= pTrack->fragmentWaste;
gTotalFragmentWaste -= pTrack->fragmentWaste;
#endif /*MEM_STATISTICS*/
pTrack->fragmentWaste = 0;
pTrack->freeCounter++;
pTrack->freeAddr = (void *)address;
pTrack->timeStamp = 0;
}
return TRUE;
}
/*! *********************************************************************************
* \brief This function checks for buffer overflow when copying multiple bytes
*
* \param[in] p - pointer to destination.
* \param[in] size - number of bytes to copy
*
* \return 1 if overflow detected, else 0
*
********************************************************************************** */
uint8_t MEM_BufferCheck(uint8_t *p, uint32_t size)
{
poolInfo_t *pPollInfo = poolInfo;
uint8_t* memAddr = (uint8_t *)memHeap;
uint32_t poolBytes, blockBytes, i;
if( (p < (uint8_t*)memHeap) || (p > ((uint8_t*)memHeap + sizeof(memHeap))) )
{
return 0;
}
while( pPollInfo->blockSize )
{
blockBytes = pPollInfo->blockSize + sizeof(listHeader_t);
poolBytes = blockBytes * pPollInfo->poolSize;
/* Find the correct message pool */
if( (p >= memAddr) && (p < memAddr + poolBytes) )
{
/* Check if the size to copy is greather then the size of the current block */
if( size > pPollInfo->blockSize )
{
#ifdef MEM_DEBUG
panic(0,0,0,0);
#endif
return 1;
}
/* Find the correct memory block */
for( i=0; i<pPollInfo->poolSize; i++ )
{
if( (p >= memAddr) && (p < memAddr + blockBytes) )
{
if( p + size > memAddr + blockBytes )
{
#ifdef MEM_DEBUG
panic(0,0,0,0);
#endif
return 1;
}
else
{
return 0;
}
}
memAddr += blockBytes;
}
}
/* check next pool */
memAddr += poolBytes;
pPollInfo++;
}
return 0;
}
#endif /*MEM_TRACKING*/
/*! *********************************************************************************
* \brief This function checks if the buffers are allocated for more than the
* specified duration
*
********************************************************************************** */
#ifdef MEM_TRACKING
void MEM_CheckIfMemBuffersAreFreed(void)
{
uint32_t t;
uint16_t i, j = 0;
uint8_t trackCount = 0;
pools_t *pParentPool;
volatile blockTracking_t *pTrack;
static volatile blockTracking_t *mpTrackTbl[NUM_OF_TRACK_PTR];
static uint32_t lastTimestamp = 0;
uint32_t currentTime = MEM_GetTimeStamp();
if( (currentTime - lastTimestamp) >= MEM_CheckMemBufferInterval_c )
{
lastTimestamp = currentTime;
j = 0;
for( i = 0; i < mTotalNoOfMsgs_c; i++ )
{
pTrack = &memTrack[i];
/* Validate the pParent first */
pParentPool = (((listHeader_t *)(pTrack->blockAddr))-1)->pParentPool;
if(pParentPool != &memPools[j])
{
if(j < NumberOfElements(memPools))
{
j++;
if(pParentPool != &memPools[j])
{
panic(0,0,0,0);
}
}
else
{
panic(0,0,0,0);
}
}
/* Check if it should be freed */
OSA_InterruptDisable();
if((pTrack->timeStamp != 0xffffffff ) &&
(pTrack->allocStatus == MEM_TRACKING_ALLOC_c) &&
(currentTime > pTrack->timeStamp))
{
t = currentTime - pTrack->timeStamp;
if( t > MEM_CheckMemBufferThreshold_c )
{
mpTrackTbl[trackCount++] = pTrack;
if(trackCount == NUM_OF_TRACK_PTR)
{
(void)mpTrackTbl; /* remove compiler warnings */
panic(0,0,0,0);
break;
}
}
}
OSA_InterruptEnable();
} /* end for */
}
}
#endif /*MEM_TRACKING*/
/*! *********************************************************************************
* \brief Get time-stamp for memory operation: alloc/free.
*
* \return dymmy time-stamp
*
********************************************************************************** */
#ifdef MEM_TRACKING
#if defined(__IAR_SYSTEMS_ICC__)
__weak uint32_t MEM_GetTimeStamp(void)
#elif defined(__GNUC__)
__attribute__((weak)) uint32_t MEM_GetTimeStamp(void)
#endif
{
return 0xFFFFFFFF;
}
#endif /* MEM_TRACKING */
/*! ************************************************************************************************
\brief MEM Manager calloc alternative implementation.
\param [in] len Number of blocks
\param [in] size Size of one block
\return void* Pointer to the allocated buffer or NULL in case of error
************************************************************************************************* */
void* MEM_CallocAlt
(
size_t len,
size_t val
)
{
void *pData = MEM_BufferAllocForever (len* val, 0);
if (pData)
{
FLib_MemSet (pData, 0, len* val);
}
return pData;
}
/*! ************************************************************************************************
\brief MEM Manager free alternative implementation.
\param [in] pData Pointer to the allocated buffer
\return void
************************************************************************************************* */
void MEM_FreeAlt
(
void* pData
)
{
MEM_BufferFree (pData);
}
@@ -0,0 +1,612 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _FSL_OS_ABSTRACTION_H_
#define _FSL_OS_ABSTRACTION_H_
#include "EmbeddedTypes.h"
#include "fsl_os_abstraction_config.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
/*! @brief Type for the Task Priority*/
typedef uint16_t osaTaskPriority_t;
/*! @brief Type for the timer definition*/
typedef enum {
osaTimer_Once = 0, /*!< one-shot timer*/
osaTimer_Periodic = 1 /*!< repeating timer*/
} osaTimer_t;
/*! @brief Type for a task handler, returned by the OSA_TaskCreate function. */
typedef void* osaTaskId_t;
/*! @brief Type for the parameter to be passed to the task at its creation */
typedef void* osaTaskParam_t;
/*! @brief Type for task pointer. Task prototype declaration */
typedef void (*osaTaskPtr_t) (osaTaskParam_t task_param);
/*! @brief Type for the semaphore handler, returned by the OSA_SemaphoreCreate function. */
typedef void* osaSemaphoreId_t;
/*! @brief Type for the mutex handler, returned by the OSA_MutexCreate function. */
typedef void* osaMutexId_t;
/*! @brief Type for the event handler, returned by the OSA_EventCreate function. */
typedef void* osaEventId_t;
/*! @brief Type for an event flags group, bit 32 is reserved. */
typedef uint32_t osaEventFlags_t;
/*! @brief Message definition. */
typedef void* osaMsg_t;
/*! @brief Type for the message queue handler, returned by the OSA_MsgQCreate function. */
typedef void* osaMsgQId_t;
/*! @brief Type for the Timer handler, returned by the OSA_TimerCreate function. */
typedef void *osaTimerId_t;
/*! @brief Type for the Timer callback function pointer. */
typedef void (*osaTimerFctPtr_t) (void const *argument);
/*! @brief Thread Definition structure contains startup information of a thread.*/
typedef struct osaThreadDef_tag {
osaTaskPtr_t pthread; /*!< start address of thread function*/
uint32_t tpriority; /*!< initial thread priority*/
uint32_t instances; /*!< maximum number of instances of that thread function*/
uint32_t stacksize; /*!< stack size requirements in bytes; 0 is default stack size*/
uint32_t *tstack;
void *tlink;
uint8_t *tname;
bool_t useFloat;
} osaThreadDef_t;
/*! @brief Thread Link Definition structure .*/
typedef struct osaThreadLink_tag{
uint8_t link[12];
osaTaskId_t osThreadId;
osaThreadDef_t *osThreadDefHandle;
uint32_t *osThreadStackHandle;
}osaThreadLink_t, *osaThreadLinkHandle_t;
/*! @Timer Definition structure contains timer parameters.*/
typedef struct osaTimerDef_tag {
osaTimerFctPtr_t pfCallback; /* < start address of a timer function */
void *argument;
} osaTimerDef_t;
/*! @brief Defines the return status of OSA's functions */
typedef enum osaStatus_tag
{
osaStatus_Success = 0U, /*!< Success */
osaStatus_Error = 1U, /*!< Failed */
osaStatus_Timeout = 2U, /*!< Timeout occurs while waiting */
osaStatus_Idle = 3U /*!< Used for bare metal only, the wait object is not ready
and timeout still not occur */
}osaStatus_t;
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
#if defined (FSL_RTOS_MQX)
#define USE_RTOS 1
#elif defined (FSL_RTOS_FREE_RTOS)
#define USE_RTOS 1
#elif defined (FSL_RTOS_UCOSII)
#define USE_RTOS 1
#elif defined (FSL_RTOS_UCOSIII)
#define USE_RTOS 1
#else
#define USE_RTOS 0
#endif
#define OSA_PRIORITY_IDLE (6)
#define OSA_PRIORITY_LOW (5)
#define OSA_PRIORITY_BELOW_NORMAL (4)
#define OSA_PRIORITY_NORMAL (3)
#define OSA_PRIORITY_ABOVE_NORMAL (2)
#define OSA_PRIORITY_HIGH (1)
#define OSA_PRIORITY_REAL_TIME (0)
#define OSA_TASK_PRIORITY_MAX (0)
#define OSA_TASK_PRIORITY_MIN (15)
#define SIZE_IN_UINT32_UNITS(size) (((size) + sizeof(uint32_t) - 1) / sizeof(uint32_t))
/*! @brief Constant to pass as timeout value in order to wait indefinitely. */
#define osaWaitForever_c ((uint32_t)(-1))
#define osaEventFlagsAll_c ((osaEventFlags_t)(0x00FFFFFF))
#define osThreadStackArray(name) osThread_##name##_stack
#define osThreadStackDef(name, stacksize, instances) \
uint32_t osThreadStackArray(name)[SIZE_IN_UINT32_UNITS(stacksize)*(instances)];
/* ==== Thread Management ==== */
/* Create a Thread Definition with function, priority, and stack requirements.
* \param name name of the thread function.
* \param priority initial priority of the thread function.
* \param instances number of possible thread instances.
* \param stackSz stack size (in bytes) requirements for the thread function.
* \param useFloat
*/
#if defined(FSL_RTOS_MQX)
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadLink_t osThreadLink_##name[instances] = {0}; \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
osThreadLink_##name, \
(uint8_t*) #name,\
(useFloat)}
#elif defined (FSL_RTOS_UCOSII)
#if gTaskMultipleInstancesManagement_c
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadLink_t osThreadLink_##name[instances] = {0}; \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
osThreadLink_##name, \
(uint8_t*) #name,\
(useFloat)}
#else
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
NULL, \
(uint8_t*) #name,\
(useFloat)}
#endif
#else
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
NULL, \
NULL, \
(uint8_t*) #name,\
(useFloat)}
#endif
/* Access a Thread defintion.
* \param name name of the thread definition object.
*/
#define OSA_TASK(name) \
&os_thread_def_##name
#define OSA_TASK_PROTO(name) \
extern osaThreadDef_t os_thread_def_##name
/* ==== Timer Management ====
* Define a Timer object.
* \param name name of the timer object.
* \param function name of the timer call back function.
*/
#define OSA_TIMER_DEF(name, function) \
osaTimerDef_t os_timer_def_##name = \
{ (function), NULL }
/* Access a Timer definition.
* \param name name of the timer object.
*/
#define OSA_TIMER(name) \
&os_timer_def_##name
/*****************************************************************************
******************************************************************************
* Public memory declarations
******************************************************************************
*****************************************************************************/
extern const uint8_t gUseRtos_c;
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*!
* @name Task management
* @{
*/
/*!
* @brief Creates a task.
*
* This function is used to create task based on the resources defined
* by the macro OSA_TASK_DEFINE.
*
* @param thread_def pointer to the osaThreadDef_t structure which defines the task.
* @param task_param Pointer to be passed to the task when it is created.
*
* @retval taskId The task is successfully created.
* @retval NULL The task can not be created..
*
* Example:
@code
osaTaskId_t taskId;
OSA_TASK_DEFINE( Job1, OSA_PRIORITY_HIGH, 1, 800, 0);;
taskId = OSA__TaskCreate(OSA__TASK(Job1), (osaTaskParam_t)NULL);
@endcode
*/
osaTaskId_t OSA_TaskCreate(osaThreadDef_t *thread_def, osaTaskParam_t task_param);
/*!
* @brief Gets the handler of active task.
*
* @return Handler to current active task.
*/
osaTaskId_t OSA_TaskGetId(void);
/*!
* @brief Puts the active task to the end of scheduler's queue.
*
* When a task calls this function, it gives up the CPU and puts itself to the
* end of a task ready list.
*
* @retval osaStatus_Success The function is called successfully.
* @retval osaStatus_Error Error occurs with this function.
*/
osaStatus_t OSA_TaskYield(void);
/*!
* @brief Gets the priority of a task.
*
* @param taskId The handler of the task whose priority is received.
*
* @return Task's priority.
*/
osaTaskPriority_t OSA_TaskGetPriority(osaTaskId_t taskId);
/*!
* @brief Sets the priority of a task.
*
* @param taskId The handler of the task whose priority is set.
* @param taskPriority The priority to set.
*
* @retval osaStatus_Success Task's priority is set successfully.
* @retval osaStatus_Error Task's priority can not be set.
*/
osaStatus_t OSA_TaskSetPriority(osaTaskId_t taskId, osaTaskPriority_t taskPriority);
/*!
* @brief Destroys a previously created task.
*
* @param taskId The handler of the task to destroy. Returned by the OSA_TaskCreate function.
*
* @retval osaStatus_Success The task was successfully destroyed.
* @retval osaStatus_Error Task destruction failed or invalid parameter.
*/
osaStatus_t OSA_TaskDestroy(osaTaskId_t taskId);
/*!
* @brief Creates a semaphore with a given value.
*
* This function creates a semaphore and sets the value to the parameter
* initValue.
*
* @param initValue Initial value the semaphore will be set to.
*
* @retval handler to the new semaphore if the semaphore is created successfully.
* @retval NULL if the semaphore can not be created.
*
*
*/
osaSemaphoreId_t OSA_SemaphoreCreate(uint32_t initValue);
/*!
* @brief Destroys a previously created semaphore.
*
* @param semId Pointer to the semaphore to destroy.
*
* @retval osaStatus_Success The semaphore is successfully destroyed.
* @retval osaStatus_Error The semaphore can not be destroyed.
*/
osaStatus_t OSA_SemaphoreDestroy(osaSemaphoreId_t semId);
/*!
* @brief Pending a semaphore with timeout.
*
* This function checks the semaphore's counting value. If it is positive,
* decreases it and returns osaStatus_Success. Otherwise, a timeout is used
* to wait.
*
* @param semId Pointer to the semaphore.
* @param millisec The maximum number of milliseconds to wait if semaphore is not
* positive. Pass osaWaitForever_c to wait indefinitely, pass 0
* will return osaStatus_Timeout immediately.
*
* @retval osaStatus_Success The semaphore is received.
* @retval osaStatus_Timeout The semaphore is not received within the specified 'timeout'.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec);
/*!
* @brief Signals for someone waiting on the semaphore to wake up.
*
* Wakes up one task that is waiting on the semaphore. If no task is waiting, increases
* the semaphore's counting value.
*
* @param semId Pointer to the semaphore to signal.
*
* @retval osaStatus_Success The semaphore is successfully signaled.
* @retval osaStatus_Error The object can not be signaled or invalid parameter.
*
*/
osaStatus_t OSA_SemaphorePost(osaSemaphoreId_t semId);
/*!
* @brief Create an unlocked mutex.
*
* This function creates a non-recursive mutex and sets it to unlocked status.
*
* @param none.
*
* @retval handler to the new mutex if the mutex is created successfully.
* @retval NULL if the mutex can not be created.
*/
osaMutexId_t OSA_MutexCreate(void);
/*!
* @brief Waits for a mutex and locks it.
*
* This function checks the mutex's status. If it is unlocked, locks it and returns the
* osaStatus_Success. Otherwise, waits for a timeout in milliseconds to lock.
*
* @param mutexId Pointer to the Mutex.
* @param millisec The maximum number of milliseconds to wait for the mutex.
* If the mutex is locked, Pass the value osaWaitForever_c will
* wait indefinitely, pass 0 will return osaStatus_Timeout
* immediately.
*
* @retval osaStatus_Success The mutex is locked successfully.
* @retval osaStatus_Timeout Timeout occurred.
* @retval osaStatus_Error Incorrect parameter was passed.
*
* @note This is non-recursive mutex, a task can not try to lock the mutex it has locked.
*/
osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec);
/*!
* @brief Unlocks a previously locked mutex.
*
* @param mutexId Pointer to the Mutex.
*
* @retval osaStatus_Success The mutex is successfully unlocked.
* @retval osaStatus_Error The mutex can not be unlocked or invalid parameter.
*/
osaStatus_t OSA_MutexUnlock(osaMutexId_t mutexId);
/*!
* @brief Destroys a previously created mutex.
*
* @param mutexId Pointer to the Mutex.
*
* @retval osaStatus_Success The mutex is successfully destroyed.
* @retval osaStatus_Error The mutex can not be destroyed.
*
*/
osaStatus_t OSA_MutexDestroy(osaMutexId_t mutexId);
/*!
* @brief Initializes an event object with all flags cleared.
*
* This function creates an event object and set its clear mode. If autoClear
* is TRUE, when a task gets the event flags, these flags will be
* cleared automatically. Otherwise these flags must
* be cleared manually.
*
* @param autoClear TRUE The event is auto-clear.
* FALSE The event manual-clear
* @retval handler to the new event if the event is created successfully.
* @retval NULL if the event can not be created.
*/
osaEventId_t OSA_EventCreate(bool_t autoClear);
/*!
* @brief Sets one or more event flags.
*
* Sets specified flags of an event object.
*
* @param eventId Pointer to the event.
* @param flagsToSet Flags to be set.
*
* @retval osaStatus_Success The flags were successfully set.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_EventSet(osaEventId_t eventId, osaEventFlags_t flagsToSet);
/*!
* @brief Clears one or more flags.
*
* Clears specified flags of an event object.
*
* @param eventId Pointer to the event.
* @param flagsToClear Flags to be clear.
*
* @retval osaStatus_Success The flags were successfully cleared.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_EventClear(osaEventId_t eventId, osaEventFlags_t flagsToClear);
/*!
* @brief Waits for specified event flags to be set.
*
* This function waits for a combination of flags to be set in an event object.
* Applications can wait for any/all bits to be set. Also this function could
* obtain the flags who wakeup the waiting task.
*
* @param eventId Pointer to the event.
* @param flagsToWait Flags that to wait.
* @param waitAll Wait all flags or any flag to be set.
* @param millisec The maximum number of milliseconds to wait for the event.
* If the wait condition is not met, pass osaWaitForever_c will
* wait indefinitely, pass 0 will return osaStatus_Timeout
* immediately.
* @param setFlags Flags that wakeup the waiting task are obtained by this parameter.
*
* @retval osaStatus_Success The wait condition met and function returns successfully.
* @retval osaStatus_Timeout Has not met wait condition within timeout.
* @retval osaStatus_Error An incorrect parameter was passed.
*
* @note Please pay attention to the flags bit width, FreeRTOS uses the most
* significant 8 bis as control bits, so do not wait these bits while using
* FreeRTOS.
*
*/
osaStatus_t OSA_EventWait(osaEventId_t eventId, osaEventFlags_t flagsToWait, bool_t waitAll, uint32_t millisec, osaEventFlags_t *pSetFlags);
/*!
* @brief Destroys a previously created event object.
*
* @param eventId Pointer to the event.
*
* @retval osaStatus_Success The event is successfully destroyed.
* @retval osaStatus_Error Event destruction failed.
*/
osaStatus_t OSA_EventDestroy(osaEventId_t eventId);
/*!
* @brief Initializes a message queue.
*
* This function allocates memory for and initializes a message queue. Message queue elements are hardcoded as void*.
*
* @param msgNo :number of messages the message queue should accommodate.
* This parameter should not exceed osNumberOfMessages defined in OSAbstractionConfig.h.
*
* @return: Handler to access the queue for put and get operations. If message queue
* creation failed, return NULL.
*/
osaMsgQId_t OSA_MsgQCreate(uint32_t msgNo);
/*!
* @brief Puts a message at the end of the queue.
*
* This function puts a message to the end of the message queue. If the queue
* is full, this function returns the osaStatus_Error;
*
* @param msgQId pointer to queue returned by the OSA_MsgQCreate function.
* @param pMessage Pointer to the message to be put into the queue.
*
* @retval osaStatus_Success Message successfully put into the queue.
* @retval osaStatus_Error The queue was full or an invalid parameter was passed.
*/
osaStatus_t OSA_MsgQPut(osaMsgQId_t msgQId, osaMsg_t pMessage);
/*!
* @brief Reads and remove a message at the head of the queue.
*
* This function gets a message from the head of the message queue. If the
* queue is empty, timeout is used to wait.
*
* @param msgQId Queue handler returned by the OSA_MsgQCreate function.
* @param pMessage Pointer to a memory to save the message.
* @param millisec The number of milliseconds to wait for a message. If the
* queue is empty, pass osaWaitForever_c will wait indefinitely,
* pass 0 will return osaStatus_Timeout immediately.
*
* @retval osaStatus_Success Message successfully obtained from the queue.
* @retval osaStatus_Timeout The queue remains empty after timeout.
* @retval osaStatus_Error Invalid parameter.
*/
osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, osaMsg_t pMessage, uint32_t millisec);
/*!
* @brief Destroys a previously created queue.
*
* @param msgQId queue handler returned by the OSA_MsgQCreate function.
*
* @retval osaStatus_Success The queue was successfully destroyed.
* @retval osaStatus_Error Message queue destruction failed.
*/
osaStatus_t OSA_MsgQDestroy(osaMsgQId_t msgQId);
/*!
* @brief Enable all interrupts.
*/
void OSA_InterruptEnable(void);
/*!
* @brief Disable all interrupts.
*/
void OSA_InterruptDisable(void);
/*!
* @brief Disable interrupts except high-priority ones
*
* @param pu8OldIntLevel Variable to hold previous setting
*/
void OSA_InterruptEnableRestricted(uint32_t *pu32OldIntLevel);
/*!
* @brief Restore interrupts that were previously restricted by a call
* to OSA_InterruptEnableRestricted
*
* @param pu8OldIntLevel Variable holding previous setting
*/
void OSA_InterruptEnableRestore(uint32_t *pu32OldIntLevel);
/*!
* @brief Enable all interrupts using PRIMASK.
*/
void OSA_EnableIRQGlobal(void);
/*!
* @brief Disable all interrupts using PRIMASK.
*/
void OSA_DisableIRQGlobal(void);
/*!
* @brief Delays execution for a number of milliseconds.
*
* @param millisec The time in milliseconds to wait.
*/
void OSA_TimeDelay(uint32_t millisec);
/*!
* @brief This function gets current time in milliseconds.
*
* @retval current time in milliseconds
*/
uint32_t OSA_TimeGetMsec(void);
/*!
* @brief This function resets the current time to 0.
*/
void OSA_TimeResetMsec(void);
/*!
* @brief Installs the interrupt handler.
*
* @param IRQNumber IRQ number of the interrupt.
* @param handler The interrupt handler to install.
*/
void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void));
/*!
* @brief Init the OSA time.
*
*/
void OSA_TimeInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,168 @@
/*! *********************************************************************************
* Copyright (c) 2013-2014, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#if !defined(__FSL_OS_ABSTRACTION_BM_H__)
#define __FSL_OS_ABSTRACTION_BM_H__
/*!
* @addtogroup os_abstraction_bm
* @{
*/
/*******************************************************************************
* Declarations
******************************************************************************/
/*! @brief Bare Metal does not use timer. */
#define FSL_OSA_BM_TIMER_NONE 0U
/*! @brief Bare Metal uses SYSTICK as timer. */
#define FSL_OSA_BM_TIMER_SYSTICK 1U
/*! @brief Configure what timer is used in Bare Metal. */
#ifndef FSL_OSA_BM_TIMER_CONFIG
#define FSL_OSA_BM_TIMER_CONFIG FSL_OSA_BM_TIMER_NONE
#endif
/*! @brief Type for an semaphore */
typedef struct Semaphore
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout on this object */
volatile uint8_t semCount; /*!< The count value of the object */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
} semaphore_t;
/*! @brief Type for a mutex */
typedef struct Mutex
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout on this mutex */
volatile bool_t isLocked; /*!< Is the object locked or not */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
} mutex_t;
/*! @brief Type for task parameter */
typedef void* task_param_t;
#define gIdleTaskPriority_c ((task_priority_t) 0)
#define gInvalidTaskPriority_c ((task_priority_t) -1)
/*! @brief Type for a task handler, returned by the OSA_TaskCreate function */
typedef void (* task_t)(task_param_t param);
/*! @brief Task control block for bare metal. */
typedef struct TaskControlBlock
{
osaTaskPtr_t p_func; /*!< Task's entry */
bool_t haveToRun; /*!< Task was signaled */
osaTaskPriority_t priority; /*!< Task's priority */
osaTaskParam_t param; /*!< Task's parameter */
struct TaskControlBlock *next; /*!< Pointer to next task control block */
struct TaskControlBlock *prev; /*!< Pointer to previous task control block */
} task_control_block_t;
/*! @brief Type for a task pointer */
typedef task_control_block_t* task_handler_t;
/*! @brief Type for a task stack */
typedef uint32_t task_stack_t;
/*! @brief Type for an event flags group, bit 32 is reserved */
typedef uint32_t event_flags_t;
/*! @brief Type for an event object */
typedef struct Event
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout on this event */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
volatile event_flags_t flags; /*!< The flags status */
bool_t autoClear; /*!< Auto clear or manual clear */
task_handler_t waitingTask; /*!< Handler to the waiting task */
} event_t;
/*! @brief Type for a message queue */
typedef struct MsgQueue
{
volatile bool_t isWaiting; /*!< Is any task waiting for a timeout */
uint16_t number; /*!< The number of messages in the queue */
uint16_t max; /*!< The max number of queue messages */
uint16_t head; /*!< Index of the next message to be read */
uint16_t tail; /*!< Index of the next place to write to */
uint32_t queueMem[osNumberOfMessages]; /*!< Points to the queue memory */
uint32_t time_start; /*!< The time to start timeout */
uint32_t timeout; /*!< Timeout to wait in milliseconds */
task_handler_t waitingTask; /*!< Handler to the waiting task */
}msg_queue_t;
/*! @brief Type for a message queue handler */
typedef msg_queue_t* msg_queue_handler_t;
/*! @brief Constant to pass as timeout value in order to wait indefinitely. */
#define OSA_WAIT_FOREVER 0xFFFFFFFFU
/*! @brief How many tasks can the bare metal support. */
#define TASK_MAX_NUM 7
/*! @brief OSA's time range in millisecond, OSA time wraps if exceeds this value. */
#define FSL_OSA_TIME_RANGE 0xFFFFFFFFU
/*! @brief The default interrupt handler installed in vector table. */
#define OSA_DEFAULT_INT_HANDLER ((osa_int_handler_t)(&DefaultISR))
/*! @brief The default interrupt handler installed in vector table. */
extern void DefaultISR(void);
/*!
* @name Thread management
* @{
*/
/*!
* @brief Defines a task.
*
* This macro defines resources for a task statically. Then, the OSA_TaskCreate
* creates the task based-on these resources.
*
* @param task The task function.
* @param stackSize The stack size this task needs in bytes.
*/
#define PRIORITY_OSA_TO_RTOS(osa_prio) (osa_prio)
#define PRIORITY_RTOS_TO_OSA(rtos_prio) (rtos_prio)
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus*/
/*!
* @brief Calls all task functions one time except for the current task.
*
* This function calls all other task functions one time. If current
* task is waiting for an event triggered by other tasks, this function
* could be used to trigger the event.
*
* @note There should be only one task calls this function, if more than
* one task call this function, stack overflow may occurs. Be careful
* to use this function.
*
*/
void OSA_PollAllOtherTasks(void);
#if defined(__cplusplus)
}
#endif /* __cplusplus*/
/*! @}*/
#endif /* __FSL_OS_ABSTRACTION_BM_H__ */
/*******************************************************************************
* EOF
******************************************************************************/
@@ -0,0 +1,53 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef _FSL_OS_ABSTRACTION_CONFIG_H_
#define _FSL_OS_ABSTRACTION_CONFIG_H_
#ifndef osNumberOfSemaphores
#define osNumberOfSemaphores 5
#endif
#ifndef osNumberOfMutexes
#define osNumberOfMutexes 5
#endif
#ifndef osNumberOfMessageQs
#define osNumberOfMessageQs 0
#endif
#ifndef osNumberOfMessages
#define osNumberOfMessages 10
#endif
#ifndef osNumberOfEvents
#define osNumberOfEvents 5
#endif
#ifndef CPU_JN518X
#ifndef gMainThreadStackSize_c
#define gMainThreadStackSize_c 1024
#endif
#else
#if !defined gMainThreadStackSize_c || (gMainThreadStackSize_c < 1200)
#undef gMainThreadStackSize_c
#define gMainThreadStackSize_c 1200
#endif
#endif
#ifndef gMainThreadPriority_c
#define gMainThreadPriority_c 7
#endif
#ifndef gTaskMultipleInstancesManagement_c
#define gTaskMultipleInstancesManagement_c 0
#endif
#ifndef osCustomStartup
#define osCustomStartup 0
#endif
#endif /* _FSL_OS_ABSTRACTION_CONFIG_H_ */
@@ -0,0 +1,161 @@
/*! *********************************************************************************
* Copyright (c) 2013-2014, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#if !defined(__FSL_OS_ABSTRACTION_FREERTOS_H__)
#define __FSL_OS_ABSTRACTION_FREERTOS_H__
#if defined ( __IAR_SYSTEMS_ICC__ )
/**
* Workaround to disable MISRA C message suppress warnings for IAR compiler.
* http://supp.iar.com/Support/?note=24725
*/
#define MISRAC_DISABLE _Pragma ("diag_suppress= \
Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\
Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\
Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\
Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\
Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\
Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\
Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\
Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\
Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\
Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\
Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\
Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\
Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\
Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\
Pm155")
#define MISRAC_ENABLE _Pragma ("diag_default= \
Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\
Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\
Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\
Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\
Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\
Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\
Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\
Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\
Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\
Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\
Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\
Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\
Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\
Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\
Pm155")
#else
/* Empty MISRA C macros for other toolchains. */
#define MISRAC_DISABLE
#define MISRAC_ENABLE
#endif
MISRAC_DISABLE
#include "FreeRTOS.h"
#include "semphr.h"
#include "event_groups.h"
MISRAC_ENABLE
/*!
* @addtogroup os_abstraction_free_rtos
* @{
*/
/*******************************************************************************
* Declarations
******************************************************************************/
/*! @brief Type for a task handler, returned by the OSA_TaskCreate function. */
typedef TaskHandle_t task_handler_t;
/*! @brief Type for a task stack.*/
typedef portSTACK_TYPE task_stack_t;
/*! @brief Type for task parameter */
typedef void* task_param_t;
/*! @brief Type for a task function. */
typedef pdTASK_CODE task_t;
/*! @brief Type for a mutex. */
typedef xSemaphoreHandle mutex_t;
/*! @brief Type for a semaphore. */
typedef xSemaphoreHandle semaphore_t;
/*! @brief Type for an event flags object.*/
typedef EventBits_t event_flags_t;
/*! @brief Type for an event group object in FreeRTOS OS */
typedef struct EventFreertos {
bool_t autoClear; /*!< Auto clear or manual clear */
EventGroupHandle_t eventHandler; /*!< FreeRTOS OS event handler */
} event_freertos;
/*! @brief Type for an event group object */
typedef event_freertos event_t;
/*! @brief Type for a message queue declaration and creation. */
typedef xQueueHandle msg_queue_t;
/*! @brief Type for a message queue handler */
typedef xQueueHandle msg_queue_handler_t;
/*! @brief Constant to pass as timeout value in order to wait indefinitely. */
#define OSA_WAIT_FOREVER 0xFFFFFFFFU
/*! @brief OSA's time range in millisecond, OSA time wraps if exceeds this value. */
#define FSL_OSA_TIME_RANGE 0xFFFFFFFFU
/*! @brief The default interrupt handler installed in vector table. */
#define OSA_DEFAULT_INT_HANDLER ((osa_int_handler_t)(&DefaultISR))
/*! @brief The Max depth of Enter/Exist Critical could be nested in interrupt. */
#define OSA_MAX_ISR_CRITICAL_SECTION_DEPTH 0x8U
extern void DefaultISR(void);
/*!
* @name Thread management
* @{
*/
/*!
* @brief To provide unified task piority for upper layer, OSA layer makes conversion.
*/
#define PRIORITY_OSA_TO_RTOS(osa_prio) (configMAX_PRIORITIES - (osa_prio) -2)
#define PRIORITY_RTOS_TO_OSA(rtos_prio) (configMAX_PRIORITIES - (rtos_prio) -2)
/* @}*/
/*!
* @name Message queues
* @{
*/
/*!
* @brief This macro statically reserves the memory required for the queue.
*
* @param name Identifier for the memory region.
* @param number Number of elements in the queue.
* @param size Size of every elements in words.
*/
#define MSG_QUEUE_DECLARE(name, number, size) \
msg_queue_t *name = NULL
/* @}*/
/*! @}*/
#endif // __FSL_OS_ABSTRACTION_FREERTOS_H__
/*******************************************************************************
* EOF
******************************************************************************/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,485 @@
/*****************************************************************************
*
* MODULE: Persistent Data Manager
*
* DESCRIPTION: Provide management of data which needs to persist over
* cold or warm start
*
****************************************************************************
*
* This software is owned by NXP B.V. and/or its supplier and is protected
* under applicable copyright laws. All rights are reserved. We grant You,
* and any third parties, a license to use this software solely and
* exclusively on NXP products [NXP Microcontrollers such as JN5148, JN5142, JN5139].
* You, and any third parties must reproduce the copyright and warranty notice
* and any other legend of ownership on each copy or partial copy of the
* software.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright NXP B.V. 2012. All rights reserved
*
***************************************************************************/
#ifndef PDM_H_INCLUDED
#define PDM_H_INCLUDED
/****************************************************************************/
/*** Include Files ***/
/****************************************************************************/
#define PUBLIC
#if defined __cplusplus
extern "C" {
#endif
/*!
* @addtogroup PDM library
* @{
*/
/****************************************************************************/
/*** Macro Definitions ***/
/****************************************************************************/
#ifdef SE_HOST_COPROCESSOR
#define PDM_EXTERNAL_FLASH
#endif
#define PDM_NUM_BLOCKS 128
#ifdef PDM_EXTERNAL_FLASH
#define PDM_NAME_SIZE 16
#else
#define PDM_NAME_SIZE 7
#ifndef PDM_USER_SUPPLIED_ID
#define PDM_USER_SUPPLIED_ID /* Defaulting to having this enabled */
#endif
#endif
#define PDM_INVALID_ID ((uint16)(-1))
/* PDM ID range allocation reservations
* Each PDM_ID_BASE_xxx below is the base value for a block of 256 (0x100) IDs.
* Within a module the individual IDs used by that module will be an offset from
* this base.
*
* These ID ranges should not be re-used by other modules, even if the modules
* are not both present in the build.
*
* Values should not be changed. Reserve a new range instead of changing an
* existing range.
*/
#define PDM_ID_BASE_APP_ZB (0x0000) /* 0x0000?0x00ff: ZigBee Application Notes */
#define PDM_ID_BASE_ZPSAPL (0xf000) /* 0xf000?0xf0ff: ZigBee ZPS APL layer */
#define PDM_ID_BASE_ZPSNWK (0xf100) /* 0xf100?0xf1ff: ZigBee ZPS NWK layer */
#define PDM_ID_BASE_RADIO (0xff00) /* 0xff00?0xffff: Radio driver */
/* PDM ID individual allocation reservations
* Each PDM_ID_xxx below is an individual ID within one of the reserved ranges.
* Individual IDs need to be declared here only if they are shared between modules.
* Please include a descriptive comment to aid accurate identification.
*/
#define PDM_ID_RADIO_SETTINGS (PDM_ID_BASE_RADIO + 0x0000) /* Holds radio KMOD calibration data */
/* Defined because still using heap in PDM builds */
#define PDM_USE_HEAP
#if (defined PDM_USE_HEAP)
/* Empty declaration: buffer not needed */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments)
#else
/* Macro to create a static block of RAM to use instead of heap
NOTE: Must be declared at module scope, not within a function
NOTE: Value of 12 is based on size of tsPDM_FileSystemRecord */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments) \
PUBLIC uint8 au8PDM_HeapBuffer[(u8NumberOfSegments) * 12] __attribute__((aligned (4)))
#endif
/****************************************************************************/
/*** Type Definitions ***/
/****************************************************************************/
typedef enum
{
PDM_E_STATUS_OK,
PDM_E_STATUS_INVLD_PARAM,
// NVM based PDM codes
PDM_E_STATUS_PDM_FULL,
PDM_E_STATUS_NOT_SAVED,
PDM_E_STATUS_RECOVERED,
PDM_E_STATUS_PDM_RECOVERED_NOT_SAVED,
PDM_E_STATUS_USER_BUFFER_SIZE,
PDM_E_STATUS_BITMAP_SATURATED_NO_INCREMENT,
PDM_E_STATUS_BITMAP_SATURATED_OK,
PDM_E_STATUS_IMAGE_BITMAP_COMPLETE,
PDM_E_STATUS_IMAGE_BITMAP_INCOMPLETE,
PDM_E_STATUS_INTERNAL_ERROR
} PDM_teStatus;
typedef enum
{
PDM_RECOVERY_STATE_NONE = 0,
PDM_RECOVERY_STATE_NEW, // 1
PDM_RECOVERY_STATE_RECOVERED, // 2
PDM_RECOVERY_STATE_RECOVERED_NOT_READ, // 3
PDM_RECOVERY_STATE_SAVED, // 4
PDM_RECOVERY_STATE_NOT_SAVED, // 5
PDM_RECOVERY_STATE_APPENDED, // 6
// do not move
PDM_RECOVERY_STATE_NUMBER
} PDM_teRecoveryState;
typedef struct
{
/* this function gets called after a cold or warm start */
void (*prInitHwCb)(void);
/* this function gets called to erase the given sector */
void (*prEraseCb)(uint8_t u8Sector);
/* this function gets called to write data to an addresss
* within a given sector. address zero is the start of the
* given sector */
void (*prWriteCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
/* this function gets called to read data from an address
* within a given sector. address zero is the start of the
* given sector */
void (*prReadCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
} PDM_tsHwFncTable;
typedef enum
{
E_PDM_SYSTEM_EVENT_WEAR_COUNT_TRIGGER_VALUE_REACHED = 0,
E_PDM_SYSTEM_EVENT_WEAR_COUNT_MAXIMUM_REACHED,
E_PDM_SYSTEM_EVENT_SAVE_FAILED,
E_PDM_SYSTEM_EVENT_NOT_ENOUGH_SPACE,
E_PDM_SYSTEM_EVENT_LARGEST_RECORD_FULL_SAVE_NO_LONGER_POSSIBLE,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_CHECKSUM_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_SAVE_OK,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_READ_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_WRITE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_ERASE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_CHECK_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_DATA_WRITE_FAIL,
// nerdy event codes
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIRED,
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIR_FAILED,
E_PDM_SYSTEM_EVENT_SYSTEM_INTERNAL_BUFFER_WEAR_COUNT_SWAP,
E_PDM_SYSTEM_EVENT_SYSTEM_DUPLICATE_FILE_SEGMENT_DETECTED,
E_PDM_SYSTEM_EVENT_SYSTEM_ERROR,
// used in test harness
E_PDM_SYSTEM_EVENT_SEGMENT_PREWRITE,
E_PDM_SYSTEM_EVENT_SEGMENT_POSTWRITE,
E_PDM_SYSTEM_EVENT_SEQUENCE_DUPLICATE_DETECTED,
E_PDM_SYSTEM_EVENT_SEQUENCE_VERIFY_FAIL,
E_PDM_SYSTEM_EVENT_SMART_SAVE,
E_PDM_SYSTEM_EVENT_FULL_SAVE
} PDM_eSystemEventCode;
typedef struct
{
uint32_t u32eventNumber;
PDM_eSystemEventCode eSystemEventCode;
} PDM_tfpSystemEventCallback;
typedef void (*PDM_tpfvSystemEventCallback)(uint32_t u32eventNumber, PDM_eSystemEventCode eSystemEventCode);
/****************************************************************************/
/*** Exported Functions ***/
/****************************************************************************/
/*!
* @brief Initialise the PDM
*
* This function is to be called in order to initialise the PDM module
* call this EVERY cold start and EVERY warm start
*
* @param u16StartSegment: Start segment in flash
* @param u8NumberOfSegments: number of contiguous segments from u16StartSegment
* that belong to the PDM NVM space.
* @param fpvPDM_SystemEventCallback: function pointer passed by using layer
* to be notified of events/errors
*
* @retval PDM_E_STATUS_OK if success PDM_E_STATUS_INTERNAL_ERROR otherwise
*/
PUBLIC PDM_teStatus PDM_eInitialise(uint16_t u16StartSegment,
uint8_t u8NumberOfSegments,
PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Save a PDM record
*
* This function saves the specified application data from RAM to the specified record
* in NVM. The record is identified by means of a 16-bit user-defined value.
* When a data record is saved to the NVM for the first time, the data is written provided
* there are enough NVM segments available to hold the data. Upon subsequent save
* requests, if there has been a change between the RAM-based and NVM-based data
* buffers then the PDM will attempt to re-save only the segments that have changed
* (if no data has changed, no save will be performed). This is advantageous due to the
* restricted size of the NVM and the constraint that old data must be preserved while
* saving changed data to the NVM.
* Provided that you have registered a callback function with the PDM (see Section 6.3),
* the callback mechanism will signal when a save has failed. Upon failure, the callback
* function will be invoked and pass the event E_PDM_SYSTEM_EVENT_DESCRIPTOR_SAVE_FAILED
* to the application
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (specified record ID is invalid)
* @retval PDM_E_STATUS_NOT_SAVED (save to NVM failed)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordData(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save a PDM record next time in idle task
*
* Like PDM_eSaveRecordData, except that the record information is queued to
* saved in the idle task, when PDM_vIdleTask is called. Note that if the
* internal queue is full, the first record on the queue is saved immediately
* to make space for this record.
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordDataInIdleTask(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save queued PDM records
*
* Synchronously saves any queued record writes that have been generated by
* calls to PDM_eSaveRecordDataInIdleTask. To avoid this function taking too
* much time, the number of records that can be written can be limited by
* the u8WritesAllowed parameter. Use a value of 255 to effectively avoid
* this limit.
* @param u8WritesAllowed Maximum number of records that can be written
*
* @retval none
*/
PUBLIC void PDM_vIdleTask(uint8_t u8WritesAllowed);
/*!
* @brief Purge the pending event available in the queue
*
* @retval none
*/
PUBLIC void PDM_vQueuePurge(void);
/*!
* @brief Reads Partial Data from an Existing Record in the File System
*
* This function appends data to a record previously written.
* The record is identified by means of a 16-bit user-defined value.
*
* @param u16IdValue User-defined ID of the record to be read from
* @param u16TableOffset Data Offset
* @param pu8DataBuffer Data Buffer
* @param u16DataLength Length of input data, in bytes.
* @param pu16DataBytesRead Number Of Data Bytes Read u16IdValue
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (error in arguments)
* @retval PDM_E_STATUS_INTERNAL_ERROR
*/
PUBLIC PDM_teStatus PDM_eReadPartialDataFromExistingRecord(uint16_t u16IdValue,
uint16_t u16TableOffset,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function reads the specified record of application data from the NVM and stores
* the read data in the supplied data buffer in RAM. The record is specified using its
* unique 16-bit identifier.
* Before calling this function, it may be useful to call PDM_bDoesDataExist() in order
* to determine whether a record with the specified identifier exists in the EEPROM and,
* if it does, to obtain its size.
*
* @param u16IdValue User-defined ID of the record to be read
* @param pvDataBuffer Pointer to the data buffer in RAM where the read data is to
* be stored
* @param u16DataBufferLength Length of the data buffer, in bytes
* @param pu16DataBytesRead Pointer to a location to receive the number of data bytes
* read
*
* @retval PDM_E_STATUS_OK if success
* @retval PDM_E_STATUS_INVLD_PARAM otherwise i.e. specified record ID is invalid
*/
PUBLIC PDM_teStatus PDM_eReadDataFromRecord(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function deletes the specified record of application data in NVM.
* @see PDM_eDeleteAllData to alternatively delete all records in NVM
*
* @param u16IdValue User-defined ID of the record to be deleted
*
* @retval none
*/
PUBLIC void PDM_vDeleteDataRecord(uint16_t u16IdValue);
/*!
* @brief Delete a PDM record
*
* This function deletes all records in NVM, including both application data and stack
* context data, resulting in an empty PDM file system. The NVM segment Wear Count
* values are preserved (and incremented) throughout this function call.
* This function is to be used with extreme care in a Zigbee application context
*
* @param none
*
* @retval none
*/
PUBLIC void PDM_vDeleteAllDataRecords(void);
/*!
* @brief Seeks for a certain record by record identifier
*
* This function checks whether data associated with thd specified record ID
* exists in the NVM. If the data record exists, the function returns the data
* length, in bytes, in a location to which a pointer must be provided.
*
* @param u16IdValue User-defined ID of the record to be found
* @param pu16DataLength Pointer to location to receive length, in bytes,
* of data record (if any) associated with specified record ID
*
* @retval true if record was fond false otherwise
*/
PUBLIC bool_t PDM_bDoesDataExist(uint16_t u16IdValue, uint16_t *pu16DataLength);
/*!
* @brief Tells how many free segments are left in the PDM space
*
* This function returns the number of unused segments that remain in the NVM.
* Note that the returned parameter being a uint8_t the total expected number of
* segments cannot exceed 255
*
* @param none
*
* @retval Number of PDM NVM segments free
*/
PUBLIC uint8_t PDM_u8GetSegmentCapacity(void);
/*!
* @brief Tells how many free segments are occupied in the PDM space
*
* This function returns the number of used segments in the NVM
* @see PDM_u8GetSegmentCapacity
*
* @param none
*
* @retval Number of NVM segments used
*/
PUBLIC uint8_t PDM_u8GetSegmentOccupancy(void);
/*!
* @brief Register a User defined system callback function
*
* This function registers a callback function that will be called in error events
* @see PDM_pfGetSystemCallback
* @see PDM_eInitialise
*
* @param fpvPDM_SystemEventCallback function to replace the one that was set on PDM initialisation
*
* @retval none
*/
PUBLIC void PDM_vRegisterSystemCallback(PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Retrieve the previously defined system callback function
*
* This function retrieves the callback function that has been set by PDM_eInitialise
* or PDM_vRegisterSystemCallback
* @see PDM_vRegisterSystemCallback
* @see PDM_eInitialise
*
* @param none
*
* @retval fpvPDM_SystemEventCallback function used to notify error events
*/
PUBLIC PDM_tpfvSystemEventCallback PDM_pfGetSystemCallback(void);
PUBLIC void PDM_vSetWearCountTriggerLevel(uint32_t u32WearCountTriggerLevel);
PUBLIC PDM_teStatus PDM_eGetSegmentWearCount(uint8_t u8SegmentIndex, uint32_t *pu32WearCount);
PUBLIC PDM_teStatus PDM_eGetDeviceWearCountProfile(uint32_t au32WearCount[], uint8_t u8NumberOfSegments);
PUBLIC void PDM_vSetWearLevelDifference(uint32_t u32WearLevelDifference);
int PDM_Init(void);
#if defined UART_DEBUG
PUBLIC void vPDM_InitialiseDisplayDataInFileSystem(uint16_t *pau16PDMFileIDrecord, uint8_t u8NumberOfPDMSegments);
PUBLIC void vPDM_DisplayDataInFileSystem(void);
PUBLIC int iPDM_DisplayDataWithIdInFileSystem(uint16_t u16IdValue);
PUBLIC void vPDM_DisplayDataInNVM(void);
PUBLIC int iPDM_DisplayNVMsegmentData(uint8_t u8SegmentIndex);
PUBLIC char *psPDM_PrintEventID(PDM_eSystemEventCode eSystemEventCode);
PUBLIC int iPDM_ReadRawNVMsegmentDataToBuffer(uint8_t u8SegmentIndex,
uint8_t *pu8SegmentDataBuffer,
uint16_t *pu16SegmentDataSize);
#endif
/****************************************************************************/
/*** Exported Variables ***/
/****************************************************************************/
extern PUBLIC const uint32_t PDM_g_u32Version;
/*@}*/
#if defined __cplusplus
};
#endif
#endif /*PDM_H_INCLUDED*/
/****************************************************************************/
/*** END OF FILE ***/
/****************************************************************************/
Binary file not shown.
+488
View File
@@ -0,0 +1,488 @@
/*****************************************************************************
*
* MODULE: Persistent Data Manager
*
* DESCRIPTION: Provide management of data which needs to persist over
* cold or warm start
*
****************************************************************************
*
* This software is owned by NXP B.V. and/or its supplier and is protected
* under applicable copyright laws. All rights are reserved. We grant You,
* and any third parties, a license to use this software solely and
* exclusively on NXP products [NXP Microcontrollers such as JN5148, JN5142, JN5139].
* You, and any third parties must reproduce the copyright and warranty notice
* and any other legend of ownership on each copy or partial copy of the
* software.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright NXP B.V. 2012. All rights reserved
*
***************************************************************************/
#ifndef PDM_H_INCLUDED
#define PDM_H_INCLUDED
/****************************************************************************/
/*** Include Files ***/
/****************************************************************************/
#include "EmbeddedTypes.h"
#define PUBLIC
#if defined __cplusplus
extern "C" {
#endif
/*!
* @addtogroup PDM library
* @{
*/
/****************************************************************************/
/*** Macro Definitions ***/
/****************************************************************************/
#ifdef SE_HOST_COPROCESSOR
#define PDM_EXTERNAL_FLASH
#endif
#define PDM_NUM_BLOCKS 128
#ifdef PDM_EXTERNAL_FLASH
#define PDM_NAME_SIZE 16
#else
#define PDM_NAME_SIZE 7
#ifndef PDM_USER_SUPPLIED_ID
#define PDM_USER_SUPPLIED_ID /* Defaulting to having this enabled */
#endif
#endif
#define PDM_INVALID_ID ((uint16)(-1))
/* PDM ID range allocation reservations
* Each PDM_ID_BASE_xxx below is the base value for a block of 256 (0x100) IDs.
* Within a module the individual IDs used by that module will be an offset from
* this base.
*
* These ID ranges should not be re-used by other modules, even if the modules
* are not both present in the build.
*
* Values should not be changed. Reserve a new range instead of changing an
* existing range.
*/
#define PDM_ID_BASE_APP_ZB (0x0000) /* 0x0000?0x00ff: ZigBee Application Notes */
#define PDM_ID_BASE_ZPSAPL (0xf000) /* 0xf000?0xf0ff: ZigBee ZPS APL layer */
#define PDM_ID_BASE_ZPSNWK (0xf100) /* 0xf100?0xf1ff: ZigBee ZPS NWK layer */
#define PDM_ID_BASE_RADIO (0xff00) /* 0xff00?0xffff: Radio driver */
/* PDM ID individual allocation reservations
* Each PDM_ID_xxx below is an individual ID within one of the reserved ranges.
* Individual IDs need to be declared here only if they are shared between modules.
* Please include a descriptive comment to aid accurate identification.
*/
#define PDM_ID_RADIO_SETTINGS (PDM_ID_BASE_RADIO + 0x0000) /* Holds radio KMOD calibration data */
/* Defined because still using heap in PDM builds */
#define PDM_USE_HEAP
#if (defined PDM_USE_HEAP)
/* Empty declaration: buffer not needed */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments)
#else
/* Macro to create a static block of RAM to use instead of heap
NOTE: Must be declared at module scope, not within a function
NOTE: Value of 12 is based on size of tsPDM_FileSystemRecord */
#define PDM_DECLARE_BUFFER(u16StartSegment, u8NumberOfSegments) \
PUBLIC uint8 au8PDM_HeapBuffer[(u8NumberOfSegments) * 12] __attribute__((aligned (4)))
#endif
/****************************************************************************/
/*** Type Definitions ***/
/****************************************************************************/
typedef enum
{
PDM_E_STATUS_OK,
PDM_E_STATUS_INVLD_PARAM,
// NVM based PDM codes
PDM_E_STATUS_PDM_FULL,
PDM_E_STATUS_NOT_SAVED,
PDM_E_STATUS_RECOVERED,
PDM_E_STATUS_PDM_RECOVERED_NOT_SAVED,
PDM_E_STATUS_USER_BUFFER_SIZE,
PDM_E_STATUS_BITMAP_SATURATED_NO_INCREMENT,
PDM_E_STATUS_BITMAP_SATURATED_OK,
PDM_E_STATUS_IMAGE_BITMAP_COMPLETE,
PDM_E_STATUS_IMAGE_BITMAP_INCOMPLETE,
PDM_E_STATUS_INTERNAL_ERROR
} PDM_teStatus;
typedef enum
{
PDM_RECOVERY_STATE_NONE = 0,
PDM_RECOVERY_STATE_NEW, // 1
PDM_RECOVERY_STATE_RECOVERED, // 2
PDM_RECOVERY_STATE_RECOVERED_NOT_READ, // 3
PDM_RECOVERY_STATE_SAVED, // 4
PDM_RECOVERY_STATE_NOT_SAVED, // 5
PDM_RECOVERY_STATE_APPENDED, // 6
// do not move
PDM_RECOVERY_STATE_NUMBER
} PDM_teRecoveryState;
typedef struct
{
/* this function gets called after a cold or warm start */
void (*prInitHwCb)(void);
/* this function gets called to erase the given sector */
void (*prEraseCb)(uint8_t u8Sector);
/* this function gets called to write data to an addresss
* within a given sector. address zero is the start of the
* given sector */
void (*prWriteCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
/* this function gets called to read data from an address
* within a given sector. address zero is the start of the
* given sector */
void (*prReadCb)(uint8_t u8Sector,
#ifdef SE_HOST_COPROCESSOR
uint32_t u32Addr,
uint32_t u32Len,
#else
uint16_t u16Addr,
uint16_t u16Len,
#endif
uint8_t *pu8Data);
} PDM_tsHwFncTable;
typedef enum
{
E_PDM_SYSTEM_EVENT_WEAR_COUNT_TRIGGER_VALUE_REACHED = 0,
E_PDM_SYSTEM_EVENT_WEAR_COUNT_MAXIMUM_REACHED,
E_PDM_SYSTEM_EVENT_SAVE_FAILED,
E_PDM_SYSTEM_EVENT_NOT_ENOUGH_SPACE,
E_PDM_SYSTEM_EVENT_LARGEST_RECORD_FULL_SAVE_NO_LONGER_POSSIBLE,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_CHECKSUM_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_SAVE_OK,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_READ_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_WRITE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_DATA_ERASE_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_CHECK_FAIL,
E_PDM_SYSTEM_EVENT_SEGMENT_BLANK_DATA_WRITE_FAIL,
// nerdy event codes
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIRED,
E_PDM_SYSTEM_EVENT_NVM_SEGMENT_HEADER_REPAIR_FAILED,
E_PDM_SYSTEM_EVENT_SYSTEM_INTERNAL_BUFFER_WEAR_COUNT_SWAP,
E_PDM_SYSTEM_EVENT_SYSTEM_DUPLICATE_FILE_SEGMENT_DETECTED,
E_PDM_SYSTEM_EVENT_SYSTEM_ERROR,
// used in test harness
E_PDM_SYSTEM_EVENT_SEGMENT_PREWRITE,
E_PDM_SYSTEM_EVENT_SEGMENT_POSTWRITE,
E_PDM_SYSTEM_EVENT_SEQUENCE_DUPLICATE_DETECTED,
E_PDM_SYSTEM_EVENT_SEQUENCE_VERIFY_FAIL,
E_PDM_SYSTEM_EVENT_SMART_SAVE,
E_PDM_SYSTEM_EVENT_FULL_SAVE
} PDM_eSystemEventCode;
typedef struct
{
uint32_t u32eventNumber;
PDM_eSystemEventCode eSystemEventCode;
} PDM_tfpSystemEventCallback;
typedef void (*PDM_tpfvSystemEventCallback)(uint32_t u32eventNumber, PDM_eSystemEventCode eSystemEventCode);
/****************************************************************************/
/*** Exported Functions ***/
/****************************************************************************/
/*!
* @brief Initialise the PDM
*
* This function is to be called in order to initialise the PDM module
* call this EVERY cold start and EVERY warm start
*
* @param u16StartSegment: Start segment in flash
* @param u8NumberOfSegments: number of contiguous segments from u16StartSegment
* that belong to the PDM NVM space.
* @param fpvPDM_SystemEventCallback: function pointer passed by using layer
* to be notified of events/errors
*
* @retval PDM_E_STATUS_OK if success PDM_E_STATUS_INTERNAL_ERROR otherwise
*/
PUBLIC PDM_teStatus PDM_eInitialise(uint16_t u16StartSegment,
uint8_t u8NumberOfSegments,
PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Save a PDM record
*
* This function saves the specified application data from RAM to the specified record
* in NVM. The record is identified by means of a 16-bit user-defined value.
* When a data record is saved to the NVM for the first time, the data is written provided
* there are enough NVM segments available to hold the data. Upon subsequent save
* requests, if there has been a change between the RAM-based and NVM-based data
* buffers then the PDM will attempt to re-save only the segments that have changed
* (if no data has changed, no save will be performed). This is advantageous due to the
* restricted size of the NVM and the constraint that old data must be preserved while
* saving changed data to the NVM.
* Provided that you have registered a callback function with the PDM (see Section 6.3),
* the callback mechanism will signal when a save has failed. Upon failure, the callback
* function will be invoked and pass the event E_PDM_SYSTEM_EVENT_DESCRIPTOR_SAVE_FAILED
* to the application
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (specified record ID is invalid)
* @retval PDM_E_STATUS_NOT_SAVED (save to NVM failed)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordData(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save a PDM record next time in idle task
*
* Like PDM_eSaveRecordData, except that the record information is queued to
* saved in the idle task, when PDM_vIdleTask is called. Note that if the
* internal queue is full, the first record on the queue is saved immediately
* to make space for this record.
* @param u16IdValue User-defined ID of the record to be saved
* @param pvDataBuffer Pointer to data buffer to be saved in the record in NVM
* @param u16Datalength Length of data to be saved, in bytes
*
* @retval PDM_E_STATUS_OK (success)
*/
PUBLIC PDM_teStatus PDM_eSaveRecordDataInIdleTask(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16Datalength);
/*!
* @brief Save queued PDM records
*
* Synchronously saves any queued record writes that have been generated by
* calls to PDM_eSaveRecordDataInIdleTask. To avoid this function taking too
* much time, the number of records that can be written can be limited by
* the u8WritesAllowed parameter. Use a value of 255 to effectively avoid
* this limit.
* @param u8WritesAllowed Maximum number of records that can be written
*
* @retval none
*/
PUBLIC void PDM_vIdleTask(uint8_t u8WritesAllowed);
/*!
* @brief Purge the pending event available in the queue
*
* @retval none
*/
PUBLIC void PDM_vQueuePurge(void);
/*!
* @brief Reads Partial Data from an Existing Record in the File System
*
* This function appends data to a record previously written.
* The record is identified by means of a 16-bit user-defined value.
*
* @param u16IdValue User-defined ID of the record to be read from
* @param u16TableOffset Data Offset
* @param pu8DataBuffer Data Buffer
* @param u16DataLength Length of input data, in bytes.
* @param pu16DataBytesRead Number Of Data Bytes Read u16IdValue
*
* @retval PDM_E_STATUS_OK (success)
* @retval PDM_E_STATUS_INVLD_PARAM (error in arguments)
* @retval PDM_E_STATUS_INTERNAL_ERROR
*/
PUBLIC PDM_teStatus PDM_eReadPartialDataFromExistingRecord(uint16_t u16IdValue,
uint16_t u16TableOffset,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function reads the specified record of application data from the NVM and stores
* the read data in the supplied data buffer in RAM. The record is specified using its
* unique 16-bit identifier.
* Before calling this function, it may be useful to call PDM_bDoesDataExist() in order
* to determine whether a record with the specified identifier exists in the EEPROM and,
* if it does, to obtain its size.
*
* @param u16IdValue User-defined ID of the record to be read
* @param pvDataBuffer Pointer to the data buffer in RAM where the read data is to
* be stored
* @param u16DataBufferLength Length of the data buffer, in bytes
* @param pu16DataBytesRead Pointer to a location to receive the number of data bytes
* read
*
* @retval PDM_E_STATUS_OK if success
* @retval PDM_E_STATUS_INVLD_PARAM otherwise i.e. specified record ID is invalid
*/
PUBLIC PDM_teStatus PDM_eReadDataFromRecord(uint16_t u16IdValue,
void *pvDataBuffer,
uint16_t u16DataBufferLength,
uint16_t *pu16DataBytesRead);
/*!
* @brief Delete a PDM record
*
* This function deletes the specified record of application data in NVM.
* @see PDM_eDeleteAllData to alternatively delete all records in NVM
*
* @param u16IdValue User-defined ID of the record to be deleted
*
* @retval none
*/
PUBLIC void PDM_vDeleteDataRecord(uint16_t u16IdValue);
/*!
* @brief Delete a PDM record
*
* This function deletes all records in NVM, including both application data and stack
* context data, resulting in an empty PDM file system. The NVM segment Wear Count
* values are preserved (and incremented) throughout this function call.
* This function is to be used with extreme care in a Zigbee application context
*
* @param none
*
* @retval none
*/
PUBLIC void PDM_vDeleteAllDataRecords(void);
/*!
* @brief Seeks for a certain record by record identifier
*
* This function checks whether data associated with thd specified record ID
* exists in the NVM. If the data record exists, the function returns the data
* length, in bytes, in a location to which a pointer must be provided.
*
* @param u16IdValue User-defined ID of the record to be found
* @param pu16DataLength Pointer to location to receive length, in bytes,
* of data record (if any) associated with specified record ID
*
* @retval true if record was fond false otherwise
*/
PUBLIC bool_t PDM_bDoesDataExist(uint16_t u16IdValue, uint16_t *pu16DataLength);
/*!
* @brief Tells how many free segments are left in the PDM space
*
* This function returns the number of unused segments that remain in the NVM.
* Note that the returned parameter being a uint8_t the total expected number of
* segments cannot exceed 255
*
* @param none
*
* @retval Number of PDM NVM segments free
*/
PUBLIC uint8_t PDM_u8GetSegmentCapacity(void);
/*!
* @brief Tells how many free segments are occupied in the PDM space
*
* This function returns the number of used segments in the NVM
* @see PDM_u8GetSegmentCapacity
*
* @param none
*
* @retval Number of NVM segments used
*/
PUBLIC uint8_t PDM_u8GetSegmentOccupancy(void);
/*!
* @brief Register a User defined system callback function
*
* This function registers a callback function that will be called in error events
* @see PDM_pfGetSystemCallback
* @see PDM_eInitialise
*
* @param fpvPDM_SystemEventCallback function to replace the one that was set on PDM initialisation
*
* @retval none
*/
PUBLIC void PDM_vRegisterSystemCallback(PDM_tpfvSystemEventCallback fpvPDM_SystemEventCallback);
/*!
* @brief Retrieve the previously defined system callback function
*
* This function retrieves the callback function that has been set by PDM_eInitialise
* or PDM_vRegisterSystemCallback
* @see PDM_vRegisterSystemCallback
* @see PDM_eInitialise
*
* @param none
*
* @retval fpvPDM_SystemEventCallback function used to notify error events
*/
PUBLIC PDM_tpfvSystemEventCallback PDM_pfGetSystemCallback(void);
PUBLIC void PDM_vSetWearCountTriggerLevel(uint32_t u32WearCountTriggerLevel);
PUBLIC PDM_teStatus PDM_eGetSegmentWearCount(uint8_t u8SegmentIndex, uint32_t *pu32WearCount);
PUBLIC PDM_teStatus PDM_eGetDeviceWearCountProfile(uint32_t au32WearCount[], uint8_t u8NumberOfSegments);
PUBLIC void PDM_vSetWearLevelDifference(uint32_t u32WearLevelDifference);
int PDM_Init(void);
#if defined UART_DEBUG
PUBLIC void vPDM_InitialiseDisplayDataInFileSystem(uint16_t *pau16PDMFileIDrecord, uint8_t u8NumberOfPDMSegments);
PUBLIC void vPDM_DisplayDataInFileSystem(void);
PUBLIC int iPDM_DisplayDataWithIdInFileSystem(uint16_t u16IdValue);
PUBLIC void vPDM_DisplayDataInNVM(void);
PUBLIC int iPDM_DisplayNVMsegmentData(uint8_t u8SegmentIndex);
PUBLIC char *psPDM_PrintEventID(PDM_eSystemEventCode eSystemEventCode);
PUBLIC int iPDM_ReadRawNVMsegmentDataToBuffer(uint8_t u8SegmentIndex,
uint8_t *pu8SegmentDataBuffer,
uint16_t *pu16SegmentDataSize);
#endif
/****************************************************************************/
/*** Exported Variables ***/
/****************************************************************************/
extern PUBLIC const uint32_t PDM_g_u32Version;
/*@}*/
#if defined __cplusplus
};
#endif
#endif /*PDM_H_INCLUDED*/
/****************************************************************************/
/*** END OF FILE ***/
/****************************************************************************/
+278
View File
@@ -0,0 +1,278 @@
/*****************************************************************************
*
* MODULE:
*
* COMPONENT:
*
* DESCRIPTION:
*
*****************************************************************************
*
* This software is owned by NXP B.V. and/or its supplier and is protected
* under applicable copyright laws. All rights are reserved. We grant You,
* and any third parties, a license to use this software solely and
* exclusively on NXP products [NXP Microcontrollers such as JN5168, JN5179].
* You, and any third parties must reproduce the copyright and warranty notice
* and any other legend of ownership on each copy or partial copy of the
* software.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright NXP B.V. 2016. All rights reserved
*
****************************************************************************/
/* Standard includes. */
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#if defined FSL_RTOS_FREE_RTOS && (FSL_RTOS_FREE_RTOS != 0)
#include "FreeRTOSConfig.h"
#include "projdefs.h"
#include "portable.h"
#else
#include "MemManager.h"
#endif
#include "FunctionLib.h"
#include "fsl_debug_console.h"
#include "Flash_Adapter.h"
#include "PDM.h"
typedef struct
{
uint8_t u8Level;
} tsMicroIntStorage;
#if defined(__GNUC__)
#define __WEAK_FUNC __attribute__((weak))
#elif defined(__ICCARM__)
#define __WEAK_FUNC __weak
#elif defined( __CC_ARM )
#define __WEAK_FUNC __weak
#endif
#if gUsePdm_d
/****************************************************************************/
/*** Macro Definitions ***/
/****************************************************************************/
/* In this module pvHeap_Alloc, vHeap_Free, vHeap_ResetHeap,
* vMicroIntEnableOnly, vMicroIntRestoreState
* are default weak implementations that can be overridden
* for USE_RTOS or DUAL_MODE_APP builds */
/****************************************************************************/
/*** Local Function Prototypes ***/
/****************************************************************************/
/****************************************************************************/
/*** Exported Variables ***/
/****************************************************************************/
/****************************************************************************/
/*** Local Variables ***/
/****************************************************************************/
/****************************************************************************/
/*** Imported Functions ***/
/****************************************************************************/
/****************************************************************************/
/*** Exported Functions ***/
/****************************************************************************/
/****************************************************************************/
/*** Type Definitions ***/
/****************************************************************************/
typedef enum
{
E_HEAP_ALLOC = 0,
E_HEAP_RESET,
E_FUNCTION_MAX
} eFunctionId;
/* Nested interrupt control */
#ifndef MICRO_SET_PRIMASK_LEVEL
#define MICRO_SET_PRIMASK_LEVEL(A) __set_PRIMASK(A)
#endif
// read back PRIMASK status into u32Store variable then disable the interrupts
#ifndef MICRO_DISABLE_AND_SAVE_INTERRUPTS
#define MICRO_DISABLE_AND_SAVE_INTERRUPTS(u32Store) \
u32Store = __get_PRIMASK(); __disable_irq();
#endif
#ifndef MICRO_GET_ACTIVE_INT_LEVEL
#define MICRO_GET_ACTIVE_INT_LEVEL __get_BASEPRI
#endif
#ifndef MICRO_SET_ACTIVE_INT_LEVEL_MAX
#define MICRO_SET_ACTIVE_INT_LEVEL_MAX(A) __set_BASEPRI_MAX(A)
#endif
#ifndef MICRO_SET_ACTIVE_INT_LEVEL
#define MICRO_SET_ACTIVE_INT_LEVEL(A) __set_BASEPRI(A)
#endif
/****************************************************************************
*
* NAME: pvHeap_Alloc
*
* DESCRIPTION:
* Allocates a block of memory from the heap.
*
* RETURNS:
* Pointer to block, or NULL if the heap didn't have enough space. If block
* was already assigned, returns original value and doesn't take anything
* from heap.
*
* NOTES:
* If buffer has already been allocated, it is not cleared.
* If it is a fresh allocation, it is cleared on request.
*
****************************************************************************/
__WEAK_FUNC void *pvHeap_Alloc(void *pvPointer, uint32_t u32BytesNeeded, bool_t bClear)
{
do {
if (pvPointer != NULL) break;
#if defined FSL_RTOS_FREE_RTOS && (FSL_RTOS_FREE_RTOS != 0)
pvPointer = pvPortMalloc(u32BytesNeeded);
#else
pvPointer = MEM_BufferAllocWithId(u32BytesNeeded, gPdmMemPoolId_c, (void*)__get_LR());
#endif
if (pvPointer == NULL) break;
if (bClear)
{
FLib_MemSet(pvPointer, 0, u32BytesNeeded);
}
} while (0);
return pvPointer;
}
/****************************************************************************
*
* NAME: vHeap_Free
*
* DESCRIPTION:
* Release a block of memory from the heap.
*
* RETURNS:
* none
* NOTES:
*
****************************************************************************/
__WEAK_FUNC void vHeap_Free(void *pvPointer)
{
#if defined FSL_RTOS_FREE_RTOS && (FSL_RTOS_FREE_RTOS != 0)
vPortFree(pvPointer);
#else
memStatus_t status;
status = MEM_BufferFree(pvPointer);
if (status != MEM_SUCCESS_c)
{
#ifdef DEBUG
PRINTF("MemMngt error freeing %08lx code=%d\r\n", (uint32_t)pvPointer, status);
#endif
}
#endif
}
__WEAK_FUNC void vHeap_ResetHeap(void)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
__WEAK_FUNC void vMicroIntEnableOnly(tsMicroIntStorage *int_storage, uint32_t u32EnableMask)
{
uint32_t primask_lvl;
MICRO_DISABLE_AND_SAVE_INTERRUPTS(primask_lvl);
int_storage->u8Level = (uint8_t)MICRO_GET_ACTIVE_INT_LEVEL();
MICRO_SET_ACTIVE_INT_LEVEL_MAX( 96 );
MICRO_SET_PRIMASK_LEVEL(primask_lvl);
}
__WEAK_FUNC void vMicroIntRestoreState(tsMicroIntStorage * int_storage)
{
MICRO_SET_ACTIVE_INT_LEVEL(int_storage->u8Level);
}
#endif
/****************************************************************************
*
* NAME: PDM_Init
*
* DESCRIPTION:
* Wrapper to call PDM Initialization with the right Flash configuration parameters
*
* Note: FLASH_Init must have been called beforehand in order to initialize gFlashConfig.
*
* RETURNS:
* 0: if no error, negative value otherwise
* NOTES:
*
****************************************************************************/
int PDM_Init(void)
{
int status = -1;
#if gUsePdm_d
static bool pdm_init_done = false;
do {
if (pdm_init_done)
{
status = 0;
break;
}
NV_Init(); /* used to setup the gFlashConfig.PFlashTotalSize value */
PDM_teStatus st = PDM_E_STATUS_INTERNAL_ERROR;
uint8_t *base = (uint8_t*)NV_STORAGE_END_ADDRESS;
size_t len = (size_t)((uint32_t)NV_STORAGE_START_ADDRESS + 1 - (uint32_t)NV_STORAGE_END_ADDRESS);
#ifdef DEBUG
uint8_t * flash_top = (uint8_t*)(gFlashConfig.PFlashTotalSize + gFlashConfig.PFlashBlockBase);
uint8_t * flash_base = (uint8_t*)gFlashConfig.PFlashBlockBase;
assert(base >= flash_base);
assert(base + len <= flash_top);
assert(len > FLASH_PAGE_SIZE*2);
#endif
#if !defined gPdmNbSegments || (gPdmNbSegments < NV_STORAGE_MAX_SECTORS)
#error "gPdmNbSegments should match NV_STORAGE_MAX_SECTORS"
#endif
uint32_t sect_sz_log = Flib_Log2(gFlashConfig.PFlashSectorSize);
st = PDM_eInitialise(ADDR2SEG(base, sect_sz_log),
SIZE2SEGNB(len, sect_sz_log), NULL);
if (st != PDM_E_STATUS_OK)
{
#ifdef DEBUG
PRINTF("PDM/NVM misconfiguration\r\n");
#endif
assert(st != PDM_E_STATUS_OK);
status = -st;
break;
}
pdm_init_done = true;
status = 0;
} while (0);
#endif
return status;
}
/*-----------------------------------------------------------*/
@@ -0,0 +1,68 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the header file for the Panic module.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
#ifndef __PANIC_H__
#define __PANIC_H__
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "EmbeddedTypes.h"
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
typedef uint32_t panicId_t;
typedef struct
{
panicId_t id;
uint32_t location;
uint32_t extra1;
uint32_t extra2;
uint32_t linkRegister;
uint32_t cpsr_contents; /* may not be used initially */
uint8_t stack_dump[4]; /* initially just contain the contents of the LR */
} panicData_t;
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
#ifndef gUsePanic_c
#define gUsePanic_c 0
#endif
#define ID_PANIC(grp,value) ((panicId_t)(((panicId_t)(grp) << 16)+((panicId_t)(value))))
/*! *********************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
********************************************************************************** */
void panic
(
panicId_t id,
uint32_t location,
uint32_t extra1,
uint32_t extra2
);
#endif /* __PANIC_H__ */
@@ -0,0 +1,86 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This is the source file for the Panic module.
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/*! *********************************************************************************
*************************************************************************************
* Include
*************************************************************************************
********************************************************************************** */
#include "Panic.h"
#include "fsl_os_abstraction.h"
#if gLoggingActive_d
#include "dbg_logging.h"
#endif
/*! *********************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
********************************************************************************** */
#if gUsePanic_c
panicData_t panic_data;
#endif
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*! *********************************************************************************
* \brief This function will halt the system
*
* \param[in] id Description of the param2 in parameter
* \param[in] location address where the Panic occurred
* \param[in] extra1 parameter to be stored in Panic structure
* \param[in] extra2 parameter to be stored in Panic structure
*
********************************************************************************** */
void panic( panicId_t id, uint32_t location, uint32_t extra1, uint32_t extra2 )
{
#if gUsePanic_c
/* Save the Link Register */
volatile uint32_t savedLR = 0;
__asm("push {r2} ");
__asm("push {LR} ");
__asm("pop {r2} ");
#if defined(__GNUC__)
__asm("str r2, [SP, #24]");
#else
__asm("str r2, [SP, #4]");
#endif
__asm("pop {r2}");
panic_data.id = id;
panic_data.location = location;
panic_data.extra1 = extra1;
panic_data.extra2 = extra2;
panic_data.linkRegister = savedLR;
panic_data.cpsr_contents = 0;
OSA_InterruptDisable(); /* disable interrupts */
#if gLoggingActive_d
DbgLogDump(1);
#endif
/* infinite loop just to ensure this routine never returns */
for(;;)
{
__asm("NOP");
}
#endif
}
#if defined(__GNUC__)
void __attribute__((weak)) __assertion_failed(char* s) {}
#endif
+53
View File
@@ -0,0 +1,53 @@
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* MCU reset related functions implementation
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */
/************************************************************************************
*************************************************************************************
* Include
*************************************************************************************
************************************************************************************/
#include "fsl_device_registers.h"
#ifdef CPU_JN518X
#include "fsl_reset.h"
#endif
/************************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
************************************************************************************/
/************************************************************************************
*************************************************************************************
* Public prototypes
*************************************************************************************
************************************************************************************/
void ResetMCU(void);
/************************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
************************************************************************************/
void ResetMCU(void)
{
#ifdef CPU_JN518X
RESET_SystemReset();
#else
NVIC_SystemReset();
#endif
while(1){}
}
/********************************** EOF ***************************************/