From 2c5d22f0b7f4ec078aed4f4e31900a585d64f728 Mon Sep 17 00:00:00 2001 From: doru91 Date: Tue, 8 Sep 2020 07:56:45 +0300 Subject: [PATCH] [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 --- examples/Makefile-jn5189 | 26 +- examples/Makefile-k32w061 | 26 +- examples/platforms/k32w/jn5189/Makefile.am | 16 +- .../k32w/jn5189/Makefile.platform.am | 1 + .../platforms/k32w/jn5189/jn5189-sdk-config.h | 53 + examples/platforms/k32w/jn5189/jn5189.ld | 12 +- .../jn5189/openthread-core-jn5189-config.h | 2 +- examples/platforms/k32w/k32w061/Makefile.am | 16 +- .../k32w/k32w061/Makefile.platform.am | 1 + .../k32w/k32w061/k32w061-sdk-config.h | 53 + examples/platforms/k32w/k32w061/k32w061.ld | 10 +- .../k32w061/openthread-core-k32w061-config.h | 2 +- examples/platforms/k32w/src/settings_k32w.c | 575 +------ examples/platforms/k32w/src/system.c | 41 +- .../framework/Flash/Internal/Flash_Adapter.c | 822 +++++++++ .../framework/Flash/Internal/Flash_Adapter.h | 238 +++ .../framework/FunctionLib/FunctionLib.c | 573 +++++++ .../framework/FunctionLib/FunctionLib.h | 320 ++++ .../wireless/framework/Lists/GenericList.c | 561 ++++++ .../wireless/framework/Lists/GenericList.h | 90 + .../MemManager/Interface/MemManager.h | 223 +++ .../framework/MemManager/Source/MemManager.c | 815 +++++++++ .../Interface/fsl_os_abstraction.h | 612 +++++++ .../Interface/fsl_os_abstraction_bm.h | 168 ++ .../Interface/fsl_os_abstraction_config.h | 53 + .../Interface/fsl_os_abstraction_free_rtos.h | 161 ++ .../Source/fsl_os_abstraction_bm.c | 1527 +++++++++++++++++ .../Source/fsl_os_abstraction_free_rtos.c | 1173 +++++++++++++ .../wireless/framework/PDM/Include/PDM.h | 485 ++++++ .../wireless/framework/PDM/Library/libPDM.a | Bin 0 -> 92286 bytes .../middleware/wireless/framework/PDM/PDM.h | 488 ++++++ .../wireless/framework/PDM/pdm_port.c | 278 +++ .../framework/Panic/Interface/Panic.h | 68 + .../wireless/framework/Panic/Source/Panic.c | 86 + .../wireless/framework/Reset/Reset.c | 53 + .../framework/Flash/Internal/Flash_Adapter.c | 822 +++++++++ .../framework/Flash/Internal/Flash_Adapter.h | 238 +++ .../framework/FunctionLib/FunctionLib.c | 573 +++++++ .../framework/FunctionLib/FunctionLib.h | 320 ++++ .../wireless/framework/Lists/GenericList.c | 561 ++++++ .../wireless/framework/Lists/GenericList.h | 90 + .../MemManager/Interface/MemManager.h | 223 +++ .../framework/MemManager/Source/MemManager.c | 815 +++++++++ .../Interface/fsl_os_abstraction.h | 612 +++++++ .../Interface/fsl_os_abstraction_bm.h | 168 ++ .../Interface/fsl_os_abstraction_config.h | 53 + .../Interface/fsl_os_abstraction_free_rtos.h | 161 ++ .../Source/fsl_os_abstraction_bm.c | 1527 +++++++++++++++++ .../Source/fsl_os_abstraction_free_rtos.c | 1173 +++++++++++++ .../wireless/framework/PDM/Include/PDM.h | 485 ++++++ .../wireless/framework/PDM/Library/libPDM.a | Bin 0 -> 92286 bytes .../middleware/wireless/framework/PDM/PDM.h | 488 ++++++ .../wireless/framework/PDM/pdm_port.c | 278 +++ .../framework/Panic/Interface/Panic.h | 68 + .../wireless/framework/Panic/Source/Panic.c | 86 + .../wireless/framework/Reset/Reset.c | 53 + 56 files changed, 17886 insertions(+), 536 deletions(-) create mode 100644 examples/platforms/k32w/jn5189/jn5189-sdk-config.h create mode 100644 examples/platforms/k32w/k32w061/k32w061-sdk-config.h mode change 100755 => 100644 examples/platforms/k32w/src/settings_k32w.c mode change 100755 => 100644 examples/platforms/k32w/src/system.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Interface/MemManager.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Source/MemManager.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Include/PDM.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Library/libPDM.a create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/PDM.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/pdm_port.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Interface/Panic.h create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Source/Panic.c create mode 100755 third_party/nxp/JN5189DK6/middleware/wireless/framework/Reset/Reset.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Interface/MemManager.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Source/MemManager.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Include/PDM.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Library/libPDM.a create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/PDM.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/pdm_port.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Interface/Panic.h create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Source/Panic.c create mode 100755 third_party/nxp/K32W061DK6/middleware/wireless/framework/Reset/Reset.c diff --git a/examples/Makefile-jn5189 b/examples/Makefile-jn5189 index 6cc5b67faf5..834db22800d 100755 --- a/examples/Makefile-jn5189 +++ b/examples/Makefile-jn5189 @@ -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 diff --git a/examples/Makefile-k32w061 b/examples/Makefile-k32w061 index 3c39573c303..ee8a2f83a09 100755 --- a/examples/Makefile-k32w061 +++ b/examples/Makefile-k32w061 @@ -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) diff --git a/examples/platforms/k32w/jn5189/Makefile.am b/examples/platforms/k32w/jn5189/Makefile.am index d076268c39d..b7ef9c89ee1 100755 --- a/examples/platforms/k32w/jn5189/Makefile.am +++ b/examples/platforms/k32w/jn5189/Makefile.am @@ -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 = \ diff --git a/examples/platforms/k32w/jn5189/Makefile.platform.am b/examples/platforms/k32w/jn5189/Makefile.platform.am index 0e279c904c4..494fbd6d7ab 100755 --- a/examples/platforms/k32w/jn5189/Makefile.platform.am +++ b/examples/platforms/k32w/jn5189/Makefile.platform.am @@ -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 += \ diff --git a/examples/platforms/k32w/jn5189/jn5189-sdk-config.h b/examples/platforms/k32w/jn5189/jn5189-sdk-config.h new file mode 100644 index 00000000000..32280e961d9 --- /dev/null +++ b/examples/platforms/k32w/jn5189/jn5189-sdk-config.h @@ -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 diff --git a/examples/platforms/k32w/jn5189/jn5189.ld b/examples/platforms/k32w/jn5189/jn5189.ld index 44608e89e7d..1d0099f0935 100755 --- a/examples/platforms/k32w/jn5189/jn5189.ld +++ b/examples/platforms/k32w/jn5189/jn5189.ld @@ -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") -} \ No newline at end of file +} diff --git a/examples/platforms/k32w/jn5189/openthread-core-jn5189-config.h b/examples/platforms/k32w/jn5189/openthread-core-jn5189-config.h index b9df9802b7e..51f7d27e604 100755 --- a/examples/platforms/k32w/jn5189/openthread-core-jn5189-config.h +++ b/examples/platforms/k32w/jn5189/openthread-core-jn5189-config.h @@ -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 diff --git a/examples/platforms/k32w/k32w061/Makefile.am b/examples/platforms/k32w/k32w061/Makefile.am index 123ddd1118d..fd88e64e5a3 100755 --- a/examples/platforms/k32w/k32w061/Makefile.am +++ b/examples/platforms/k32w/k32w061/Makefile.am @@ -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 = \ diff --git a/examples/platforms/k32w/k32w061/Makefile.platform.am b/examples/platforms/k32w/k32w061/Makefile.platform.am index b79dbd17223..c36658872c7 100755 --- a/examples/platforms/k32w/k32w061/Makefile.platform.am +++ b/examples/platforms/k32w/k32w061/Makefile.platform.am @@ -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 += \ diff --git a/examples/platforms/k32w/k32w061/k32w061-sdk-config.h b/examples/platforms/k32w/k32w061/k32w061-sdk-config.h new file mode 100644 index 00000000000..753860e82ae --- /dev/null +++ b/examples/platforms/k32w/k32w061/k32w061-sdk-config.h @@ -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 diff --git a/examples/platforms/k32w/k32w061/k32w061.ld b/examples/platforms/k32w/k32w061/k32w061.ld index fbebd6423fb..ebaa60daf4d 100755 --- a/examples/platforms/k32w/k32w061/k32w061.ld +++ b/examples/platforms/k32w/k32w061/k32w061.ld @@ -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)); diff --git a/examples/platforms/k32w/k32w061/openthread-core-k32w061-config.h b/examples/platforms/k32w/k32w061/openthread-core-k32w061-config.h index bd2efaba5c7..c6e877b4687 100755 --- a/examples/platforms/k32w/k32w061/openthread-core-k32w061-config.h +++ b/examples/platforms/k32w/k32w061/openthread-core-k32w061-config.h @@ -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 diff --git a/examples/platforms/k32w/src/settings_k32w.c b/examples/platforms/k32w/src/settings_k32w.c old mode 100755 new mode 100644 index f92dff9d10c..cbbd62fe326 --- a/examples/platforms/k32w/src/settings_k32w.c +++ b/examples/platforms/k32w/src/settings_k32w.c @@ -37,352 +37,66 @@ #include #include #include -#include #include #include #include +#include #include "utils/code_utils.h" -#include "openthread/platform/flash.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 OT_SETTINGS_FLAG_SIZE 16 -#define OT_SETTINGS_BLOCK_DATA_SIZE 256 - -/* 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 - -#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 +#include "EmbeddedTypes.h" +#include "PDM.h" -static uint32_t sSettingsBaseAddress; -static uint32_t sSettingsUsedSize; -static uint32_t sSettingsPageNum; +#define pdmBufferSize 512 +#define NVM_START_ID 0x4F00 -/* linker file symbol for the number of flash sectors used for NVM */ -extern uint32_t NV_STORAGE_MAX_SECTORS; -extern uint8_t pageBuffer[]; +/* WARNING - the defines below must be in sync with OT NVM datasets from Settings.hpp */ +#define NVM_MAX_ID 7 -/** - * 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); +static uint8_t sPdmBuffer[pdmBufferSize] __attribute__((aligned(4))) = {0}; - 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); - 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) - { - otEXPECT_ACTION(swapSettingsBlock(aInstance) >= - (getAlignLength(sSettingsUsedSize, addBlock.block.flag, addBlock.block.length) + - sizeof(struct settingsBlock)), - error = OT_ERROR_NO_BUFS); + pdmStatus = PDM_eSaveRecordData(aKey + NVM_START_ID, sPdmBuffer, aValueLength + sizeof(uint16_t)); + otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NO_BUFS); } + else + { + 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); - memset(addBlock.data, FLASH_ERASE_VALUE, OT_SETTINGS_BLOCK_DATA_SIZE); - memcpy(addBlock.data, aValue, addBlock.block.length); + memcpy(sPdmBuffer + bytesRead, (uint8_t *)aValue, aValueLength); - 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)); + pdmStatus = PDM_eSaveRecordData(aKey + NVM_START_ID, sPdmBuffer, aValueLength + bytesRead); + otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NO_BUFS); + } exit: return error; @@ -392,52 +106,7 @@ static otError addSetting(otInstance * aInstance, 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; - - otPlatFlashRead(aInstance, 0, address, (uint8_t *)(&block), sizeof(block)); - - if (block.key == aKey) - { - 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++; - } - } + offset = aIndex * (*aValueLength); + pdmStatus = PDM_eReadPartialDataFromExistingRecord(aKey + NVM_START_ID, offset + sizeof(uint16_t), aValue, + *aValueLength, &bytesRead); - address += (getAlignLength(address, block.flag, block.length) + sizeof(struct settingsBlock)); + otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NOT_FOUND); + *aValueLength = bytesRead; } - - if (aValueLength != NULL) + else { - *aValueLength = valueLength; + if (false == PDM_bDoesDataExist(aKey + NVM_START_ID, &bytesRead)) + { + error = OT_ERROR_NOT_FOUND; + } + else if (aValueLength != NULL) + { + *aValueLength = bytesRead; + } } +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)) - { - struct settingsBlock block; + pdmStatus = PDM_eReadDataFromRecord(aKey + NVM_START_ID, sPdmBuffer, pdmBufferSize, &bytesRead); + otEXPECT_ACTION((PDM_E_STATUS_OK == pdmStatus), error = OT_ERROR_NOT_FOUND); - otPlatFlashRead(aInstance, 0, address, (uint8_t *)(&block), sizeof(block)); + recordElmSize = *((uint16_t *)sPdmBuffer); - if (block.key == aKey) + /* Determine if record contains multiple entries or just one */ + if ((-1 == aIndex) || (recordElmSize == bytesRead - sizeof(recordElmSize))) + { + PDM_vDeleteDataRecord(aKey + NVM_START_ID); + } + else if (recordElmSize < bytesRead) + { + uint8_t *pMovePtrDst = sPdmBuffer + sizeof(recordElmSize) + (recordElmSize * aIndex); + uint8_t *pMovePtrSrc = pMovePtrDst + recordElmSize; + + 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; - - /* Clears all the flash pages during a factory reset */ - for (uint32_t i = 0; i < sSettingsPageNum; 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; - } + OT_UNUSED_VARIABLE(aInstance); - /* 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) + for (uint32_t i = 0; i <= NVM_MAX_ID; i++) { - sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS + (SETTINGS_CONFIG_PAGE_SIZE * sSettingsPageNum / 2); + PDM_vDeleteDataRecord(NVM_START_ID + i); } - else - { - sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS; - } - setSettingsFlag(sSettingsBaseAddress, OT_SETTINGS_IN_USE); - - otPlatSettingsInit(aInstance); } diff --git a/examples/platforms/k32w/src/system.c b/examples/platforms/k32w/src/system.c old mode 100755 new mode 100644 index fd7339c4397..abf83de6216 --- a/examples/platforms/k32w/src/system.c +++ b/examples/platforms/k32w/src/system.c @@ -39,7 +39,10 @@ #include #include -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++; +} diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c new file mode 100755 index 00000000000..2f55db224d8 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c @@ -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 */ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h new file mode 100755 index 00000000000..9c89723ce93 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h @@ -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__ */ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c new file mode 100755 index 00000000000..5e6b88ad6f9 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c @@ -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 +#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 diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h new file mode 100755 index 00000000000..047b2fd77f1 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h @@ -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 + +/*! ********************************************************************************* +************************************************************************************* +* 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< (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_ */ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.c new file mode 100755 index 00000000000..21ea993b0bc --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.c @@ -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; ihead == 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 + diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.h new file mode 100755 index 00000000000..a094ce9bd92 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Lists/GenericList.h @@ -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_*/ \ No newline at end of file diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Interface/MemManager.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Interface/MemManager.h new file mode 100755 index 00000000000..f9e6fb5b81e --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Interface/MemManager.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 + +#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_ */ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Source/MemManager.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Source/MemManager.c new file mode 100755 index 00000000000..903d473dc87 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/MemManager/Source/MemManager.c @@ -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; iallocStatus == 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; ipoolSize; 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); +} diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h new file mode 100755 index 00000000000..0f8b2c21aae --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h @@ -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 diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h new file mode 100755 index 00000000000..1578be2e47f --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h @@ -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 + ******************************************************************************/ + diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h new file mode 100755 index 00000000000..d74baaf99d0 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h @@ -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_ */ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.h new file mode 100755 index 00000000000..c1ba2924383 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.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 + ******************************************************************************/ + diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c new file mode 100755 index 00000000000..bb5fc93e379 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c @@ -0,0 +1,1527 @@ +/*! ********************************************************************************* +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* Copyright 2016-2017 NXP +* All rights reserved. +* +* \file +* +* This is the source file for the OS Abstraction layer for MQXLite. +* +* SPDX-License-Identifier: BSD-3-Clause +********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ + +#include "EmbeddedTypes.h" +#include "fsl_os_abstraction.h" +#include "fsl_os_abstraction_bm.h" +#include "fsl_common.h" +#include +#include "GenericList.h" + +/*! ********************************************************************************* +************************************************************************************* +* Private macros +************************************************************************************* +********************************************************************************** */ + +/* Weak function. */ +#if defined(__GNUC__) +#define __WEAK_FUNC __attribute__((weak)) +#elif defined(__ICCARM__) +#define __WEAK_FUNC __weak +#elif defined( __CC_ARM ) +#define __WEAK_FUNC __weak +#endif + +#ifdef DEBUG_ASSERT +#define OS_ASSERT(condition) if(!(condition))while(1); +#else +#define OS_ASSERT(condition) (void)(condition); +#endif + +#if (osNumberOfSemaphores || osNumberOfMutexes || osNumberOfEvents || osNumberOfMessageQs) +#define osObjectAlloc_c 1 +#else +#define osObjectAlloc_c 0 +#endif + +/************************************************************************************ +************************************************************************************* +* Private type definitions +************************************************************************************* +************************************************************************************/ + +typedef struct osMutexStruct_tag + { + uint32_t inUse; + mutex_t mutex; + }osMutexStruct_t; + +typedef struct osEventStruct_tag + { + uint32_t inUse; + event_t event; + }osEventStruct_t; + +typedef struct osSemaphoreStruct_tag + { + uint32_t inUse; + semaphore_t semaphore; + }osSemaphoreStruct_t; + +typedef struct osMsgQStruct_tag + { + uint32_t inUse; + msg_queue_t queue; + }osMsgQStruct_t; + +typedef struct osObjStruct_tag + { + uint32_t inUse; + uint32_t osObj; + }osObjStruct_t; + +typedef struct osObjectInfo_tag +{ + void* pHeap; + uint32_t objectStructSize; + uint32_t objNo; +}osObjectInfo_t; + + +/*! ********************************************************************************* +************************************************************************************* +* Private prototypes +************************************************************************************* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo); +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +#endif + +extern void main_task(void *argument); +void task_init(void); +__WEAK_FUNC void OSA_TimeInit(void); +__WEAK_FUNC uint32_t OSA_TimeDiff(uint32_t time_start, uint32_t time_end); +osaStatus_t OSA_Init(void); +void OSA_Start(void); +static void OSA_InsertTaskBefore(task_handler_t newTCB, task_handler_t currentTCB); + +/*! ********************************************************************************* +************************************************************************************* +* Public memory declarations +************************************************************************************* +********************************************************************************** */ +#define main_taskStack NULL + +const uint8_t gUseRtos_c = USE_RTOS; /* USE_RTOS = 0 for BareMetal and 1 for OS */ + +/*! ********************************************************************************* +************************************************************************************* +* Private memory declarations +************************************************************************************* +********************************************************************************** */ + +list_t threadList; + +#if osNumberOfSemaphores +osSemaphoreStruct_t osSemaphoreHeap[osNumberOfSemaphores]; +const osObjectInfo_t osSemaphoreInfo = {osSemaphoreHeap, sizeof(osSemaphoreStruct_t),osNumberOfSemaphores}; +#endif + +#if osNumberOfMutexes +osMutexStruct_t osMutexHeap[osNumberOfMutexes]; +const osObjectInfo_t osMutexInfo = {osMutexHeap, sizeof(osMutexStruct_t),osNumberOfMutexes}; +#endif + +#if osNumberOfEvents +osEventStruct_t osEventHeap[osNumberOfEvents]; +const osObjectInfo_t osEventInfo = {osEventHeap, sizeof(osEventStruct_t),osNumberOfEvents}; +#endif + +#if osNumberOfMessageQs +osMsgQStruct_t osMsgQHeap[osNumberOfMessageQs]; +const osObjectInfo_t osMsgQInfo = {osMsgQHeap, sizeof(osMsgQStruct_t),osNumberOfMessageQs}; +#endif + +#if (TASK_MAX_NUM > 0) + +/* Global variales for task. */ +static task_handler_t g_curTask; /* Current task. */ +/* + * All task control blocks in g_taskControlBlockPool will be linked as a + * list, and the list is managed by the pointer g_freeTaskControlBlock. + */ +static task_control_block_t g_taskControlBlockPool[TASK_MAX_NUM]; + +/* + * Pointer to the free task control blocks. To create a task, we should get + * task control block from this pointer. When task is destroyed, the control + * block will be returned and managed by this pointer. + */ +static task_control_block_t *g_freeTaskControlBlock; + +/* Head node of task list, all tasks will be linked to this head node. */ +static task_control_block_t *p_taskListHead = NULL; +#endif +uint32_t gInterruptDisableCount = 0; +uint32_t gTickCounter = 0; + +/*! ********************************************************************************* +************************************************************************************* +* Public functions +************************************************************************************* +********************************************************************************** */ +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EnableIRQGlobal + * Description : Disable system interrupt. + * + *END**************************************************************************/ +void OSA_EnableIRQGlobal(void) +{ + if (gInterruptDisableCount > 0) + { + gInterruptDisableCount--; + + if (gInterruptDisableCount == 0) + { + __enable_irq(); + } + /* call core API to enable the global interrupt*/ + } +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_DisableIRQGlobal + * Description : Disable system interrupt + * This function will disable the global interrupt by calling the core API + * + *END**************************************************************************/ +void OSA_DisableIRQGlobal(void) +{ + /* call core API to disable the global interrupt*/ + __disable_irq(); + + /* update counter*/ + gInterruptDisableCount++; +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetId + * Description : This function is used to get current active task's handler. + * + *END**************************************************************************/ + +osaTaskId_t OSA_TaskGetId(void) +{ + return (osaTaskId_t)g_curTask; +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EXT_TaskYield + * Description : When a task calls this function, it will give up CPU and put + * itself to the tail of ready list. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskYield(void) +{ + return osaStatus_Success; +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetPriority + * Description : This function returns task's priority by task handler. + * + *END**************************************************************************/ + +osaTaskPriority_t OSA_TaskGetPriority(osaTaskId_t taskId) +{ + task_handler_t handler = (task_handler_t)taskId; + return handler->priority; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskSetPriority + * Description : This function sets task's priority by task handler. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskSetPriority(osaTaskId_t taskId, osaTaskPriority_t taskPriority) +{ + task_handler_t handler = (task_handler_t)taskId; + task_handler_t p; + + /* Remove task control block from task list. */ + handler->prev->next = handler->next; + handler->next->prev = handler->prev; + if( handler == p_taskListHead ) + { + p_taskListHead = handler->next; + } + + handler->priority = taskPriority; + /* Insert task control block into the task list. */ + if( handler->priority <= p_taskListHead->priority ) + { + /* New task has the highest priority */ + OSA_InsertTaskBefore(handler, p_taskListHead); + p_taskListHead = handler; + } + else if( handler->priority >= p_taskListHead->prev->priority ) + { + /* New task has the lowest priority */ + OSA_InsertTaskBefore(handler, p_taskListHead); + } + else + { + p = p_taskListHead->next; + + while (p != p_taskListHead) + { + if (handler->priority <= p->priority) + { + OSA_InsertTaskBefore(handler, p); + break; + } + p = p->next; + } + } + + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : task_init + * Description : This function is used to initialize bare metal's task system, + * it will prepare task control block pool and initialize corresponding + * structures. This function should be called before creating any tasks. + * + *END**************************************************************************/ +void task_init(void) +{ + int32_t i = TASK_MAX_NUM-1; + + g_taskControlBlockPool[i].next = NULL; + + while (i--) + { + /* Link all task control blocks to a list. */ + g_taskControlBlockPool[i].next = &g_taskControlBlockPool[i+1]; + } + + g_freeTaskControlBlock = g_taskControlBlockPool; +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskCreate + * Description : This function is used to create a task and make it ready. + * Param[in] : threadDef - Definition of the thread. + * task_param - Parameter to pass to the new thread. + * Return Thread handle of the new thread, or NULL if failed. + * + *END**************************************************************************/ +osaTaskId_t OSA_TaskCreate(osaThreadDef_t *thread_def,osaTaskParam_t task_param) +{ + osaTaskId_t taskId = NULL; + task_control_block_t *p_newTaskControlBlock; + task_control_block_t *p_currentTaskControlBlock; + + if (g_freeTaskControlBlock) + { + /* Get new task control block from pool. */ + p_newTaskControlBlock = g_freeTaskControlBlock; + g_freeTaskControlBlock = g_freeTaskControlBlock->next; + /* Set task entry and parameter.*/ + p_newTaskControlBlock->p_func = thread_def->pthread; + p_newTaskControlBlock->haveToRun = true; + p_newTaskControlBlock->priority = PRIORITY_OSA_TO_RTOS(thread_def->tpriority); + p_newTaskControlBlock->param = task_param; + p_newTaskControlBlock->next = NULL; + p_newTaskControlBlock->prev = NULL; + + if (p_taskListHead == NULL) + { + p_taskListHead = p_newTaskControlBlock; + p_taskListHead->next = p_taskListHead; + p_taskListHead->prev = p_taskListHead; + } + else if (p_newTaskControlBlock->priority <= p_taskListHead->priority) + { + OSA_InsertTaskBefore(p_newTaskControlBlock, p_taskListHead); + p_taskListHead = p_newTaskControlBlock; + } + else if (p_newTaskControlBlock->priority >= p_taskListHead->prev->priority) + { + OSA_InsertTaskBefore(p_newTaskControlBlock, p_taskListHead); + } + else + { + p_currentTaskControlBlock = p_taskListHead->next; + + while (p_currentTaskControlBlock != p_taskListHead) + { + if (p_newTaskControlBlock->priority <= p_currentTaskControlBlock->priority) + { + OSA_InsertTaskBefore(p_newTaskControlBlock, p_currentTaskControlBlock); + break; + } + p_currentTaskControlBlock = p_currentTaskControlBlock->next; + } + + } + /* Task handler is pointer of task control block. */ + taskId = (osaTaskId_t)p_newTaskControlBlock; + } + + return taskId; +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskDestroy + * Description : This function destroy a task. + * Param[in] :taskId - Thread handle. + * Return osaStatus_Success if the task is destroied, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskDestroy(osaTaskId_t taskId) +{ + task_handler_t handler; + if(taskId == NULL) + { + return osaStatus_Error; + } + handler = (task_handler_t)taskId; + + /* Remove task control block from task list. */ + handler->prev->next = handler->next; + handler->next->prev = handler->prev; + + /* + * If current task is destroyed, then g_curTask will point to the previous + * task, so that the subsequent tasks could be called. Check the function + * OSA_Start for more details. + */ + if (handler == g_curTask) + { + g_curTask = handler->prev; + } + + /* Put task control block back to pool. */ + handler->prev = NULL; + handler->next = g_freeTaskControlBlock; + g_freeTaskControlBlock = handler; + + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeInit + * Description : This function initializes the timer used in BM OSA, the + * functions such as OSA_TimeDelay, OSA_TimeGetMsec, and the timeout are all + * based on this timer. + * + *END**************************************************************************/ +__WEAK_FUNC void OSA_TimeInit(void) +{ +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk); + SysTick->LOAD = SystemCoreClock/1000 - 1; + SysTick->VAL = 0; + SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_CLKSOURCE_Msk; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeDiff + * Description : This function gets the difference between two time stamp, + * time overflow is considered. + * + *END**************************************************************************/ +__WEAK_FUNC uint32_t OSA_TimeDiff(uint32_t time_start, uint32_t time_end) +{ + if (time_end >= time_start) + { + return time_end - time_start; + } + else + { + return FSL_OSA_TIME_RANGE - time_start + time_end + 1; + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA__TimeDelay + * Description : This function is used to suspend the active thread for the given number of milliseconds. + * + *END**************************************************************************/ +void OSA_TimeDelay(uint32_t millisec) +{ + uint32_t currTime, timeStart; + + timeStart = OSA_TimeGetMsec(); + + do { + currTime = OSA_TimeGetMsec(); /* Get current time stamp */ + } while (millisec >= OSA_TimeDiff(timeStart, currTime)); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeGetMsec + * Description : This function gets current time in milliseconds. + * + *END**************************************************************************/ +__WEAK_FUNC uint32_t OSA_TimeGetMsec(void) +{ +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + return gTickCounter; +#else + return 0; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeResetMsec + * Description : This function resets the current time to 0. + * + *END**************************************************************************/ +__WEAK_FUNC void OSA_TimeResetMsec(void) +{ + gTickCounter = 0; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreCreate + * Description : This function is used to create a semaphore. + * Return : Semaphore handle of the new semaphore, or NULL if failed. + * + *END**************************************************************************/ + +osaSemaphoreId_t OSA_SemaphoreCreate(uint32_t initValue) +{ +#if osNumberOfSemaphores + osaSemaphoreId_t semId; + osSemaphoreStruct_t* pSemStruct; + OSA_InterruptDisable(); + semId = pSemStruct = osObjectAlloc(&osSemaphoreInfo); + OSA_InterruptEnable(); + if(semId == NULL) + { + return NULL; + } + + pSemStruct->semaphore.semCount = initValue; + pSemStruct->semaphore.isWaiting = false; + pSemStruct->semaphore.time_start = 0u; + pSemStruct->semaphore.timeout = 0u; + + return semId; +#else + initValue=initValue; + return NULL; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreDestroy + * Description : This function is used to destroy a semaphore. + * Return : osaStatus_Success if the semaphore is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreDestroy(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + if(osObjectIsAllocated(&osSemaphoreInfo, semId) == FALSE) + { + return osaStatus_Error; + } + OSA_InterruptDisable(); + osObjectFree(&osSemaphoreInfo, semId); + OSA_InterruptEnable(); + return osaStatus_Success; +#else + semId=semId; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreWait + * Description : This function checks the semaphore's counting value, if it is + * positive, decreases it and returns osaStatus_Success, otherwise, timeout + * will be used for wait. The parameter timeout indicates how long should wait + * in milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will + * return osaStatus_Timeout immediately if semaphore is not positive. + * This function returns osaStatus_Success if the semaphore is received, returns + * osaStatus_Timeout if the semaphore is not received within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec) +{ +#if osNumberOfSemaphores + osSemaphoreStruct_t* pSemStruct; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + if(osObjectIsAllocated(&osSemaphoreInfo, semId) == FALSE) + { + return osaStatus_Error; + } + pSemStruct = (osSemaphoreStruct_t*)semId; + /* Check the sem count first. Deal with timeout only if not already set */ + + if (pSemStruct->semaphore.semCount) + { + OSA_DisableIRQGlobal(); + pSemStruct->semaphore.semCount --; + pSemStruct->semaphore.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and semaphore is not available, return kStatus_OSA_Timeout. */ + return osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pSemStruct->semaphore.isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pSemStruct->semaphore.timeout < OSA_TimeDiff(pSemStruct->semaphore.time_start, currentTime)) + { + OSA_DisableIRQGlobal(); + pSemStruct->semaphore.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Timeout; + } + } + else if (millisec != osaWaitForever_c) /* If don't wait forever, start the timer */ + { + /* Start the timeout counter */ + OSA_DisableIRQGlobal(); + pSemStruct->semaphore.isWaiting = true; + OSA_EnableIRQGlobal(); + pSemStruct->semaphore.time_start = OSA_TimeGetMsec(); + pSemStruct->semaphore.timeout = millisec; + } +#endif + } + + return osaStatus_Idle; +#else + semId=semId; + millisec=millisec; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphorePost + * Description : This function is used to wake up one task that wating on the + * semaphore. If no task is waiting, increase the semaphore. The function returns + * osaStatus_Success if the semaphre is post successfully, otherwise returns + * osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphorePost(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + osSemaphoreStruct_t* pSemStruct; + if(osObjectIsAllocated(&osSemaphoreInfo, semId) == FALSE) + { + return osaStatus_Error; + } + pSemStruct = (osSemaphoreStruct_t*)semId; + /* The max value is 0xFF */ + if (0xFF == pSemStruct->semaphore.semCount) + { + return osaStatus_Error; + } + OSA_DisableIRQGlobal(); + ++pSemStruct->semaphore.semCount; + OSA_EnableIRQGlobal(); + + return osaStatus_Success; +#else + semId=semId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexCreate + * Description : This function is used to create a mutex. + * Return : Mutex handle of the new mutex, or NULL if failed. + * + *END**************************************************************************/ +osaMutexId_t OSA_MutexCreate(void) +{ +#if osNumberOfMutexes + osaMutexId_t mutexId; + osMutexStruct_t* pMutexStruct; + OSA_InterruptDisable(); + mutexId = pMutexStruct = osObjectAlloc(&osMutexInfo); + OSA_InterruptEnable(); + if(mutexId == NULL) + { + return NULL; + } + pMutexStruct->mutex.isLocked = false; + pMutexStruct->mutex.isWaiting = false; + pMutexStruct->mutex.time_start = 0u; + pMutexStruct->mutex.timeout = 0u; + return mutexId; +#else + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexLock + * Description : This function checks the mutex's status, if it is unlocked, + * lock it and returns osaStatus_Success, otherwise, wait for the mutex. + * MQX does not support timeout to wait for a mutex. + * This function returns osaStatus_Success if the mutex is obtained, returns + * osaStatus_Error if any errors occur during waiting. If the mutex has been + * locked, pass 0 as timeout will return osaStatus_Timeout immediately. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec) +{ +#if osNumberOfMutexes + osMutexStruct_t* pMutexStruct; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + if(osObjectIsAllocated(&osMutexInfo, mutexId) == FALSE) + { + return osaStatus_Error; + } + pMutexStruct = (osMutexStruct_t*)mutexId; + + /* Always check first. Deal with timeout only if not available. */ + if (pMutexStruct->mutex.isLocked == false) + { + /* Get the lock and return success */ + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isLocked = true; + pMutexStruct->mutex.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and mutex is not available, return kStatus_OSA_Timeout. */ + return osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pMutexStruct->mutex.isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pMutexStruct->mutex.timeout < OSA_TimeDiff(pMutexStruct->mutex.time_start, currentTime)) + { + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Timeout; + } + } + else if (millisec != osaWaitForever_c) /* If dont't wait forever, start timer. */ + { + /* Start the timeout counter */ + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isWaiting = true; + OSA_EnableIRQGlobal(); + pMutexStruct->mutex.time_start = OSA_TimeGetMsec(); + pMutexStruct->mutex.timeout = millisec; + } +#endif + } + + return osaStatus_Idle; +#else + mutexId=mutexId; + millisec=millisec; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexUnlock + * Description : This function is used to unlock a mutex. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexUnlock(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + osMutexStruct_t* pMutexStruct; + if(osObjectIsAllocated(&osMutexInfo, mutexId) == FALSE) + { + return osaStatus_Error; + } + pMutexStruct = (osMutexStruct_t*)mutexId; + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isLocked = false; + OSA_EnableIRQGlobal(); + return osaStatus_Success; +#else + mutexId=mutexId; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexDestroy + * Description : This function is used to destroy a mutex. + * Return : osaStatus_Success if the lock object is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexDestroy(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + if(osObjectIsAllocated(&osMutexInfo, mutexId) == FALSE) + { + return osaStatus_Error; + } + OSA_InterruptDisable(); + osObjectFree(&osMutexInfo, mutexId); + OSA_InterruptEnable(); + + return osaStatus_Success; +#else + mutexId=mutexId; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventCreate + * Description : This function is used to create a event object. + * Return : Event handle of the new event, or NULL if failed. + * + *END**************************************************************************/ +osaEventId_t OSA_EventCreate(bool_t autoClear) +{ +#if osNumberOfEvents + osaEventId_t eventId; + osEventStruct_t* pEventStruct; + OSA_InterruptDisable(); + eventId = pEventStruct = osObjectAlloc(&osEventInfo); + OSA_InterruptEnable(); + if(eventId == NULL) + { + return NULL; + } + pEventStruct->event.isWaiting = false; + pEventStruct->event.flags = 0; + pEventStruct->event.autoClear = autoClear; + pEventStruct->event.time_start = 0u; + pEventStruct->event.timeout = 0u; + pEventStruct->event.waitingTask = NULL; + return eventId; +#else + (void)autoClear; + return NULL; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventSet + * Description : Set one or more event flags of an event object. + * Return : osaStatus_Success if set successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventSet(osaEventId_t eventId, osaEventFlags_t flagsToSet) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + /* Set flags ensuring atomic operation */ + OSA_DisableIRQGlobal(); + pEventStruct->event.flags |= flagsToSet; + if (pEventStruct->event.waitingTask != NULL) + { + pEventStruct->event.waitingTask->haveToRun = true; + } + OSA_EnableIRQGlobal(); + + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToSet; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventClear + * Description : Clear one or more event flags of an event object. + * Return :osaStatus_Success if clear successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventClear(osaEventId_t eventId, osaEventFlags_t flagsToClear) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + /* Clear flags ensuring atomic operation */ + OSA_DisableIRQGlobal(); + pEventStruct->event.flags &= ~flagsToClear; + if (pEventStruct->event.flags != 0x00) + { + if (pEventStruct->event.waitingTask != NULL) + { + pEventStruct->event.waitingTask->haveToRun = true; + } + } + OSA_EnableIRQGlobal(); + + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToClear; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventWait + * Description : This function checks the event's status, if it meets the wait + * condition, return osaStatus_Success, otherwise, timeout will be used for + * wait. The parameter timeout indicates how long should wait in milliseconds. + * Pass osaWaitForever_c to wait indefinitely, pass 0 will return the value + * osaStatus_Timeout immediately if wait condition is not met. The event flags + * will be cleared if the event is auto clear mode. Flags that wakeup waiting + * task could be obtained from the parameter setFlags. + * This function returns osaStatus_Success if wait condition is met, returns + * osaStatus_Timeout if wait condition is not met within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_EventWait(osaEventId_t eventId, osaEventFlags_t flagsToWait, bool_t waitAll, uint32_t millisec, osaEventFlags_t *pSetFlags) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + osaStatus_t retVal = osaStatus_Idle; + if(pSetFlags == NULL) + { + return osaStatus_Error; + } + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + + OSA_DisableIRQGlobal(); +#if (TASK_MAX_NUM > 0) + pEventStruct->event.waitingTask = OSA_TaskGetId(); +#endif + + *pSetFlags = pEventStruct->event.flags & flagsToWait; + + /* Check the event flag first, if does not meet wait condition, deal with timeout. */ + if ((((!waitAll) && (*pSetFlags))) || (*pSetFlags == flagsToWait)) + { + pEventStruct->event.isWaiting = false; + if(TRUE == pEventStruct->event.autoClear) + { + pEventStruct->event.flags &= ~flagsToWait; + pEventStruct->event.waitingTask->haveToRun = false; /* Cherry-picked from [MCKFW-1872] */ + } + retVal = osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and wait condition is not met, return kStatus_OSA_Timeout. */ + retVal = osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pEventStruct->event.isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pEventStruct->event.timeout < OSA_TimeDiff(pEventStruct->event.time_start, currentTime)) + { + pEventStruct->event.isWaiting = false; + retVal = osaStatus_Timeout; + } + } + else if(millisec != osaWaitForever_c) /* If no timeout, don't start the timer */ + { + /* Start the timeout counter */ + pEventStruct->event.isWaiting = true; + pEventStruct->event.time_start = OSA_TimeGetMsec(); + pEventStruct->event.timeout = millisec; + } +#endif + else + { + pEventStruct->event.waitingTask->haveToRun = false; + } + } + + OSA_EnableIRQGlobal(); + + return retVal; +#else + (void)eventId; + (void)flagsToWait; + (void)waitAll; + (void)millisec; + (void)pSetFlags; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventDestroy + * Description : This function is used to destroy a event object. Return + * osaStatus_Success if the event object is destroyed successfully, otherwise + * return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_EventDestroy(osaEventId_t eventId) +{ +#if osNumberOfEvents + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + + OSA_InterruptDisable(); + osObjectFree(&osEventInfo, eventId); + OSA_InterruptEnable(); + return osaStatus_Success; +#else + (void)eventId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQCreate + * Description : This function is used to create a message queue. + * Return : the handle to the message queue if create successfully, otherwise + * return NULL. + * + *END**************************************************************************/ +osaMsgQId_t OSA_MsgQCreate(uint32_t msgNo) +{ +#if osNumberOfMessageQs + osaMsgQId_t msgQId = NULL; + osMsgQStruct_t* pMsgQStruct; + + if(msgNo <= osNumberOfMessages) + { + OSA_InterruptDisable(); + msgQId = pMsgQStruct = osObjectAlloc(&osMsgQInfo); + OSA_InterruptEnable(); + + if(msgQId) + { + pMsgQStruct->queue.max = msgNo; + pMsgQStruct->queue.number = 0; + pMsgQStruct->queue.head = 0; + pMsgQStruct->queue.tail = 0; + } + } + + return msgQId; +#else + msgNo=msgNo; + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQPut + * Description : This function is used to put a message to a message queue. +* Return : osaStatus_Success if the message is put successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQPut(osaMsgQId_t msgQId, void* pMessage) +{ +#if osNumberOfMessageQs + msg_queue_t* pQueue; + osaStatus_t status = osaStatus_Success; + + if(osObjectIsAllocated(&osMsgQInfo, msgQId) == FALSE) + { + status = osaStatus_Error; + } + else + { + pQueue = &((osMsgQStruct_t*)msgQId)->queue; + + OSA_DisableIRQGlobal(); + if( pQueue->number >= pQueue->max ) + { + status = osaStatus_Error; + } + else + { + pQueue->queueMem[pQueue->tail] = *((uint32_t*)pMessage); + pQueue->number++; + pQueue->tail++; + + if( pQueue->tail >= pQueue->max ) + { + pQueue->tail = 0; + } + + if( pQueue->waitingTask ) + { + pQueue->waitingTask->haveToRun = 1; + } + } + OSA_EnableIRQGlobal(); + } + + return status; +#else + msgQId=msgQId; + pMessage=pMessage; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQGet + * Description : This function checks the queue's status, if it is not empty, + * get message from it and return osaStatus_Success, otherwise, timeout will + * be used for wait. The parameter timeout indicates how long should wait in + * milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will return + * osaStatus_Timeout immediately if queue is empty. + * This function returns osaStatus_Success if message is got successfully, + * returns osaStatus_Timeout if message queue is empty within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, void *pMessage, uint32_t millisec) +{ +#if osNumberOfMessageQs + osaStatus_t status = osaStatus_Idle; + msg_queue_t* pQueue; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + + if(osObjectIsAllocated(&osMsgQInfo, msgQId) == FALSE) + { + status = osaStatus_Error; + } + else + { + pQueue = &((osMsgQStruct_t*)msgQId)->queue; + pQueue->waitingTask = OSA_TaskGetId(); + + OSA_DisableIRQGlobal(); + if( pQueue->number ) + { + *((uint32_t*)pMessage) = pQueue->queueMem[pQueue->head]; + pQueue->number--; + pQueue->head++; + pQueue->isWaiting = 0; + + if( pQueue->head >= pQueue->max ) + { + pQueue->head = 0; + } + status = osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and wait condition is not met, return kStatus_OSA_Timeout. */ + status = osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pQueue->isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pQueue->timeout < OSA_TimeDiff(pQueue->time_start, currentTime)) + { + pQueue->isWaiting = 0; + status = osaStatus_Timeout; + } + } + else if(millisec != osaWaitForever_c) /* If no timeout, don't start the timer */ + { + /* Start the timeout counter */ + pQueue->isWaiting = 1; + pQueue->time_start = OSA_TimeGetMsec(); + pQueue->timeout = millisec; + } +#endif + else + { + pQueue->waitingTask->haveToRun = 0; + } + } + OSA_EnableIRQGlobal(); + } + + return status; +#else + msgQId=msgQId; + pMessage=pMessage; + millisec=millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EXT_MsgQDestroy + * Description : This function is used to destroy the message queue. + * Return : osaStatus_Success if the message queue is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQDestroy(osaMsgQId_t msgQId) +{ +#if osNumberOfMessageQs + osaStatus_t status = osaStatus_Success; + msg_queue_t* pQueue; + + if(osObjectIsAllocated(&osMsgQInfo, msgQId) == FALSE) + { + status = osaStatus_Error; + } + else + { + pQueue = &((osMsgQStruct_t*)msgQId)->queue; + + if( pQueue->waitingTask ) + { + pQueue->waitingTask->haveToRun = 1; + pQueue->waitingTask = NULL; + } + + OSA_InterruptDisable(); + osObjectFree(&osMsgQInfo, msgQId); + OSA_InterruptEnable(); + } + + return status; +#else + msgQId=msgQId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptEnable(void) +{ + OSA_EnableIRQGlobal(); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptDisable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptDisable(void) +{ + OSA_DisableIRQGlobal(); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestricted + * Description : Disable interrupts except high-priority ones + * + *END**************************************************************************/ + void OSA_InterruptEnableRestricted(uint32_t *pu32OldIntLevel) +{ + /* Disable interrupts for duration of this function */ + OSA_DisableIRQGlobal(); + + /* Store old priority level */ + *pu32OldIntLevel = __get_BASEPRI(); + + /* Update priority level, but only if it is a more restrictive value */ + __set_BASEPRI_MAX(((3U << (8U - __NVIC_PRIO_BITS)) & 0xffU)); + + /* Restore interrupts */ + OSA_EnableIRQGlobal(); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestore + * Description : Restore interrupts that were previously restricted by a call + * to OSA_InterruptEnableRestricted + * + *END**************************************************************************/ + void OSA_InterruptEnableRestore(uint32_t *pu32OldIntLevel) +{ + // write value direct into register ARM to ARM, no translations required + __set_BASEPRI(*pu32OldIntLevel); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InstallIntHandler + * Description : This function is used to install interrupt handler. + * + *END**************************************************************************/ +void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void)) +{ +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_suppress = Pm138") +#endif +#ifdef ENABLE_RAM_VECTOR_TABLE + InstallIRQHandler((IRQn_Type)IRQNumber, (uint32_t)handler); +#endif +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_remark = PM138") +#endif +} + +/*! ********************************************************************************* +************************************************************************************* +* Private functions +************************************************************************************* +********************************************************************************** */ +#if (osCustomStartup == 0) +OSA_TASK_DEFINE(main_task, gMainThreadPriority_c, 1, gMainThreadStackSize_c, 0); + +int main (void) +{ + extern void hardware_init(void); + + OSA_Init(); + /* Initialize MCU clock */ + hardware_init(); + OSA_TimeInit(); + OSA_TaskCreate(OSA_TASK(main_task),NULL); + OSA_Start(); + + return 0; +} +#endif + +/*! ********************************************************************************* +* \brief Allocates a osObjectStruct_t block in the osObjectHeap array. +* \param[in] pointer to the object info struct. +* Object can be semaphore, mutex, osTimer, message Queue, event +* \return Pointer to the allocated osObjectStruct_t, NULL if failed. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++) + { + if(((osObjStruct_t*)pObj)->inUse == 0) + { + ((osObjStruct_t*)pObj)->inUse = 1; + return (void*)pObj; + } + + pObj += pOsObjectInfo->objectStructSize; + } + return NULL; +} +#endif +/*! ********************************************************************************* +* \brief Verifies the object is valid and allocated in the osObjectHeap array. +* \param[in] the pointer to the object info struct. +* \param[in] the pointer to the object struct. +* Object can be semaphore, mutex, osTimer, message Queue, event +* \return TRUE if the object is valid and allocated, FALSE otherwise +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++) + { + if(pObj == pObjectStruct) + { + if(((osObjStruct_t*)pObj)->inUse) + { + return TRUE; + } + break; + } + pObj += pOsObjectInfo->objectStructSize; + } + return FALSE; +} +#endif + +/*! ********************************************************************************* +* \brief Frees an osObjectStruct_t block from the osObjectHeap array. +* \param[in] pointer to the object info struct. +* \param[in] Pointer to the allocated osObjectStruct_t to free. +* Object can be semaphore, mutex, osTimer, message Queue, event +* \return none. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0; i < pOsObjectInfo->objNo; i++ ) + { + if(pObj == pObjectStruct) + { + ((osObjStruct_t*)pObj)->inUse = 0; + break; + } + + pObj += pOsObjectInfo->objectStructSize; + } +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_Init + * Description : This function is used to setup the basic services, it should + * be called first in function main. Return kStatus_OSA_Success if services + * are initialized successfully, otherwise return kStatus_OSA_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_Init(void) +{ +#if (TASK_MAX_NUM > 0) + task_init(); +#endif + + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_Start + * Description : This function is used to start RTOS scheduler. + * + *END**************************************************************************/ +void OSA_Start(void) +{ +#if (TASK_MAX_NUM > 0) + g_curTask = p_taskListHead; + + for(;;) + { + if(g_curTask->haveToRun) + { + if(g_curTask->p_func) + { + g_curTask->p_func(g_curTask->param); + } + /* restart from the first task */ + g_curTask = p_taskListHead; + } + else + { + g_curTask = g_curTask->next; + } + } +#else + for(;;) + { + } +#endif +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InsertTaskBefore + * Description : Helper function to insert Task TCB into the task list. + * + *END**************************************************************************/ +static void OSA_InsertTaskBefore(task_handler_t newTCB, task_handler_t currentTCB) +{ + newTCB->next = currentTCB; + newTCB->prev = currentTCB->prev; + currentTCB->prev->next = newTCB; + currentTCB->prev = newTCB; +} + + +/*FUNCTION********************************************************************** + * + * Function Name : SysTick_Handler + * Description : This ISR of the SYSTICK timer. + * + *END**************************************************************************/ +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) +void SysTick_Handler(void) +{ + gTickCounter++; +} +#endif diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c new file mode 100755 index 00000000000..906c61e9e27 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c @@ -0,0 +1,1173 @@ +/*! ********************************************************************************* +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* Copyright 2016-2017, 2019 NXP +* All rights reserved. +* +* \file +* +* This is the source file for the OS Abstraction layer for freertos. +* +* SPDX-License-Identifier: BSD-3-Clause +********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ +#include "EmbeddedTypes.h" +#include "fsl_os_abstraction.h" +#include "fsl_os_abstraction_free_rtos.h" +#include +#include "GenericList.h" +#include "fsl_common.h" +#include "Panic.h" +/*! ********************************************************************************* +************************************************************************************* +* Private macros +************************************************************************************* +********************************************************************************** */ +#define millisecToTicks(millisec) ((millisec * configTICK_RATE_HZ + 999)/1000) + +#ifdef DEBUG_ASSERT +#define OS_ASSERT(condition) if(!(condition))while(1); +#else +#define OS_ASSERT(condition) (void)(condition); +#endif + +#if (osNumberOfEvents) +#define osObjectAlloc_c 1 +#else +#define osObjectAlloc_c 0 +#endif + +/*! @brief Converts milliseconds to ticks*/ +#define MSEC_TO_TICK(msec) (((uint32_t)(msec)+500uL/(uint32_t)configTICK_RATE_HZ) \ + *(uint32_t)configTICK_RATE_HZ/1000uL) +#define TICKS_TO_MSEC(tick) ((uint64_t)(tick)*1000uL/(uint32_t)configTICK_RATE_HZ) +/************************************************************************************ +************************************************************************************* +* Private type definitions +************************************************************************************* +************************************************************************************/ + +typedef struct osEventStruct_tag +{ + uint32_t inUse; + event_t event; +}osEventStruct_t; + +typedef struct osObjStruct_tag +{ + uint32_t inUse; + uint32_t osObj; +}osObjStruct_t; + +typedef struct osObjectInfo_tag +{ + void* pHeap; + uint32_t objectStructSize; + uint32_t objNo; +} osObjectInfo_t; + + +/*! ********************************************************************************* +************************************************************************************* +* Private prototypes +************************************************************************************* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo); +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +#endif +extern void main_task(void const *argument); +extern void hardware_init(void); +void startup_task(void* argument); + + +/*! ********************************************************************************* +************************************************************************************* +* Public memory declarations +************************************************************************************* +********************************************************************************** */ +const uint8_t gUseRtos_c = USE_RTOS; // USE_RTOS = 0 for BareMetal and 1 for OS +static uint32_t g_base_priority_array[OSA_MAX_ISR_CRITICAL_SECTION_DEPTH]; +static int32_t g_base_priority_top = 0; + +/*! ********************************************************************************* +************************************************************************************* +* Private memory declarations +************************************************************************************* +********************************************************************************** */ + +#if osNumberOfEvents +osEventStruct_t osEventHeap[osNumberOfEvents]; +const osObjectInfo_t osEventInfo = {osEventHeap, sizeof(osEventStruct_t),osNumberOfEvents}; +#endif + + +/*! ********************************************************************************* +************************************************************************************* +* Public functions +************************************************************************************* +********************************************************************************** */ + +/*FUNCTION********************************************************************** + * + * Function Name : startup_task + * Description : Wrapper over main_task.. + * + *END**************************************************************************/ +void startup_task(void* argument) +{ + main_task(argument); + while(1); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetId + * Description : This function is used to get current active task's handler. + * + *END**************************************************************************/ +osaTaskId_t OSA_TaskGetId(void) +{ + return xTaskGetCurrentTaskHandle(); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskYield + * Description : When a task calls this function, it will give up CPU and put + * itself to the tail of ready list. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskYield(void) +{ + taskYIELD(); + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetPriority + * Description : This function returns task's priority by task handler. + * + *END**************************************************************************/ +osaTaskPriority_t OSA_TaskGetPriority(osaTaskId_t taskId) +{ + return (osaTaskPriority_t)(PRIORITY_RTOS_TO_OSA(uxTaskPriorityGet((task_handler_t)taskId))); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskSetPriority + * Description : This function sets task's priority by task handler. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskSetPriority(osaTaskId_t taskId, osaTaskPriority_t taskPriority) +{ + vTaskPrioritySet((task_handler_t)taskId, PRIORITY_OSA_TO_RTOS(taskPriority)); + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** +* +* Function Name : OSA_TaskCreate +* Description : This function is used to create a task and make it ready. +* Param[in] : threadDef - Definition of the thread. +* task_param - Parameter to pass to the new thread. +* Return Thread handle of the new thread, or NULL if failed. +* +*END**************************************************************************/ +osaTaskId_t OSA_TaskCreate(osaThreadDef_t *thread_def,osaTaskParam_t task_param) +{ + osaTaskId_t taskId = NULL; + task_handler_t task_handler; + + if (xTaskCreate( + (task_t)thread_def->pthread, /* pointer to the task */ + (char const*)thread_def->tname, /* task name for kernel awareness debugging */ + thread_def->stacksize/sizeof(portSTACK_TYPE), /* task stack size */ + (task_param_t)task_param, /* optional task startup argument */ + PRIORITY_OSA_TO_RTOS(thread_def->tpriority), /* initial priority */ + &task_handler /* optional task handle to create */ + ) == pdPASS) + { + taskId = (osaTaskId_t)task_handler; + } + return taskId; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskDestroy + * Description : This function destroy a task. + * Param[in] :taskId - Thread handle. + * Return osaStatus_Success if the task is destroied, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskDestroy(osaTaskId_t taskId) +{ + osaStatus_t status; + uint16_t oldPriority; + /*Change priority to avoid context switches*/ + oldPriority = OSA_TaskGetPriority(OSA_TaskGetId()); + (void)OSA_TaskSetPriority(OSA_TaskGetId(), OSA_PRIORITY_REAL_TIME); +#if INCLUDE_vTaskDelete /* vTaskDelete() enabled */ + vTaskDelete((task_handler_t)taskId); + status = osaStatus_Success; +#else + status = osaStatus_Error; /* vTaskDelete() not available */ +#endif + (void)OSA_TaskSetPriority(OSA_TaskGetId(), oldPriority); + + return status; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeDelay + * Description : This function is used to suspend the active thread for the given number of milliseconds. + * + *END**************************************************************************/ +void OSA_TimeDelay(uint32_t millisec) +{ + vTaskDelay(millisecToTicks(millisec)); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeGetMsec + * Description : This function gets current time in milliseconds. + * + *END**************************************************************************/ +uint32_t OSA_TimeGetMsec(void) +{ + portTickType ticks; + + if (__get_IPSR()) + { + ticks = xTaskGetTickCountFromISR(); + } + else + { + ticks = xTaskGetTickCount(); + } + + return TICKS_TO_MSEC(ticks); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreCreate + * Description : This function is used to create a semaphore. + * Return : Semaphore handle of the new semaphore, or NULL if failed. + * + *END**************************************************************************/ +osaSemaphoreId_t OSA_SemaphoreCreate(uint32_t initValue) +{ +#if osNumberOfSemaphores + semaphore_t sem; + sem = xSemaphoreCreateCounting(0xFF, initValue); + return (osaSemaphoreId_t)sem; +#else + (void)initValue; + return NULL; +#endif + +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreDestroy + * Description : This function is used to destroy a semaphore. + * Return : osaStatus_Success if the semaphore is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreDestroy(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + semaphore_t sem = (semaphore_t)semId; + if(sem == NULL) + { + return osaStatus_Error; + } + vSemaphoreDelete(sem); + return osaStatus_Success; +#else + (void)semId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreWait + * Description : This function checks the semaphore's counting value, if it is + * positive, decreases it and returns osaStatus_Success, otherwise, timeout + * will be used for wait. The parameter timeout indicates how long should wait + * in milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will + * return osaStatus_Timeout immediately if semaphore is not positive. + * This function returns osaStatus_Success if the semaphore is received, returns + * osaStatus_Timeout if the semaphore is not received within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec) +{ +#if osNumberOfSemaphores + uint32_t timeoutTicks; + if(semId == NULL) + { + return osaStatus_Error; + } + semaphore_t sem = (semaphore_t)semId; + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + + if (xSemaphoreTake(sem, timeoutTicks)==pdFALSE) + { + return osaStatus_Timeout; /* timeout */ + } + else + { + return osaStatus_Success; /* semaphore taken */ + } +#else + (void)semId; + (void)millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphorePost + * Description : This function is used to wake up one task that wating on the + * semaphore. If no task is waiting, increase the semaphore. The function returns + * osaStatus_Success if the semaphre is post successfully, otherwise returns + * osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphorePost(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + osaStatus_t status = osaStatus_Error; + if(semId) + { + semaphore_t sem = (semaphore_t)semId; + + if (__get_IPSR()) + { + portBASE_TYPE taskToWake = pdFALSE; + + if (pdTRUE==xSemaphoreGiveFromISR(sem, &taskToWake)) + { + if (pdTRUE == taskToWake) + { + portYIELD_FROM_ISR(taskToWake); + } + status = osaStatus_Success; + } + else + { + status = osaStatus_Error; + } + } + else + { + if (pdTRUE == xSemaphoreGive(sem)) + { + status = osaStatus_Success; /* sync object given */ + } + else + { + status = osaStatus_Error; + } + } + } + return status; +#else + (void)semId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexCreate + * Description : This function is used to create a mutex. + * Return : Mutex handle of the new mutex, or NULL if failed. + * + *END**************************************************************************/ +osaMutexId_t OSA_MutexCreate(void) +{ +#if osNumberOfMutexes + mutex_t mutex; + mutex = xSemaphoreCreateMutex(); + return (osaMutexId_t)mutex; +#else + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexLock + * Description : This function checks the mutex's status, if it is unlocked, + * lock it and returns osaStatus_Success, otherwise, wait for the mutex. + * This function returns osaStatus_Success if the mutex is obtained, returns + * osaStatus_Error if any errors occur during waiting. If the mutex has been + * locked, pass 0 as timeout will return osaStatus_Timeout immediately. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec) +{ +#if osNumberOfMutexes + uint32_t timeoutTicks; + mutex_t mutex = (mutex_t)mutexId; + if(mutexId == NULL) + { + return osaStatus_Error; + } + /* If pMutex has been locked by current task, return error. */ + if (xSemaphoreGetMutexHolder(mutex) == xTaskGetCurrentTaskHandle()) + { + return osaStatus_Error; + } + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + + if (xSemaphoreTake(mutex, timeoutTicks)==pdFALSE) + { + return osaStatus_Timeout; /* timeout */ + } + else + { + return osaStatus_Success; /* semaphore taken */ + } +#else + (void)mutexId; + (void)millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexUnlock + * Description : This function is used to unlock a mutex. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexUnlock(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + mutex_t mutex = (mutex_t)mutexId; + if(mutexId == NULL) + { + return osaStatus_Error; + } + /* If pMutex is not locked by current task, return error. */ + if (xSemaphoreGetMutexHolder(mutex) != xTaskGetCurrentTaskHandle()) + { + return osaStatus_Error; + } + + if (xSemaphoreGive(mutex)==pdPASS) + { + return osaStatus_Success; + } + else + { + return osaStatus_Error; + } +#else + (void)mutexId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexDestroy + * Description : This function is used to destroy a mutex. + * Return : osaStatus_Success if the lock object is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexDestroy(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + mutex_t mutex = (mutex_t)mutexId; + if(mutexId == NULL) + { + return osaStatus_Error; + } + vSemaphoreDelete(mutex); + return osaStatus_Success; +#else + (void)mutexId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventCreate + * Description : This function is used to create a event object. + * Return : Event handle of the new event, or NULL if failed. + * + *END**************************************************************************/ +osaEventId_t OSA_EventCreate(bool_t autoClear) +{ +#if osNumberOfEvents + osaEventId_t eventId; + osEventStruct_t* pEventStruct; + OSA_InterruptDisable(); + eventId = pEventStruct = osObjectAlloc(&osEventInfo); + OSA_InterruptEnable(); + if(eventId == NULL) + { + return NULL; + } + + pEventStruct->event.eventHandler = xEventGroupCreate(); + if (pEventStruct->event.eventHandler) + { + pEventStruct->event.autoClear = autoClear; + } + else + { + OSA_InterruptDisable(); + osObjectFree(&osEventInfo, eventId); + OSA_InterruptEnable(); + eventId = NULL; + } + return eventId; +#else + (void)autoClear; + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventSet + * Description : Set one or more event flags of an event object. + * Return : osaStatus_Success if set successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventSet(osaEventId_t eventId, osaEventFlags_t flagsToSet) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + portBASE_TYPE taskToWake = pdFALSE; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + if (__get_IPSR()) + { + if (pdPASS != xEventGroupSetBitsFromISR(pEventStruct->event.eventHandler, (event_flags_t)flagsToSet, &taskToWake)) + { + panic(0,(uint32_t)OSA_EventSet,0,0); + return osaStatus_Error; + } + if (pdTRUE == taskToWake) + { + portYIELD_FROM_ISR(taskToWake); + } + } + else + { + xEventGroupSetBits(pEventStruct->event.eventHandler, (event_flags_t)flagsToSet); + } + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToSet; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventClear + * Description : Clear one or more event flags of an event object. + * Return :osaStatus_Success if clear successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventClear(osaEventId_t eventId, osaEventFlags_t flagsToClear) +{ +#if osNumberOfEvents + + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + + if (__get_IPSR()) + { + xEventGroupClearBitsFromISR(pEventStruct->event.eventHandler, (event_flags_t)flagsToClear); + } + else + { + xEventGroupClearBits(pEventStruct->event.eventHandler, (event_flags_t)flagsToClear); + } + + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToClear; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventWait + * Description : This function checks the event's status, if it meets the wait + * condition, return osaStatus_Success, otherwise, timeout will be used for + * wait. The parameter timeout indicates how long should wait in milliseconds. + * Pass osaWaitForever_c to wait indefinitely, pass 0 will return the value + * osaStatus_Timeout immediately if wait condition is not met. The event flags + * will be cleared if the event is auto clear mode. Flags that wakeup waiting + * task could be obtained from the parameter setFlags. + * This function returns osaStatus_Success if wait condition is met, returns + * osaStatus_Timeout if wait condition is not met within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_EventWait(osaEventId_t eventId, osaEventFlags_t flagsToWait, bool_t waitAll, uint32_t millisec, osaEventFlags_t *pSetFlags) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + BaseType_t clearMode; + uint32_t timeoutTicks; + event_flags_t flagsSave; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + + /* Clean FreeRTOS cotrol flags */ + flagsToWait = flagsToWait & 0x00FFFFFF; + + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = millisec/portTICK_PERIOD_MS; + } + + clearMode = (pEventStruct->event.autoClear) ? pdTRUE: pdFALSE; + + flagsSave = xEventGroupWaitBits(pEventStruct->event.eventHandler,(event_flags_t)flagsToWait,clearMode,(BaseType_t)waitAll,timeoutTicks); + + flagsSave &= (event_flags_t)flagsToWait; + if(pSetFlags) + { + *pSetFlags = (osaEventFlags_t)flagsSave; + } + + if (flagsSave) + { + return osaStatus_Success; + } + else + { + return osaStatus_Timeout; + } +#else + (void)eventId; + (void)flagsToWait; + (void)waitAll; + (void)millisec; + (void)pSetFlags; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventDestroy + * Description : This function is used to destroy a event object. Return + * osaStatus_Success if the event object is destroyed successfully, otherwise + * return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_EventDestroy(osaEventId_t eventId) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + vEventGroupDelete(pEventStruct->event.eventHandler); + OSA_InterruptDisable(); + osObjectFree(&osEventInfo, eventId); + OSA_InterruptEnable(); + return osaStatus_Success; +#else + (void)eventId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQCreate + * Description : This function is used to create a message queue. + * Return : the handle to the message queue if create successfully, otherwise + * return NULL. + * + *END**************************************************************************/ +osaMsgQId_t OSA_MsgQCreate( uint32_t msgNo ) +{ +#if osNumberOfMessageQs + msg_queue_handler_t msg_queue_handler; + + /* Create the message queue where each element is a pointer to the message item. */ + msg_queue_handler = xQueueCreate(msgNo,sizeof(osaMsg_t)); + return (osaMsgQId_t)msg_queue_handler; +#else + (void)msgNo; + return NULL; +#endif +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQPut + * Description : This function is used to put a message to a message queue. +* Return : osaStatus_Success if the message is put successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQPut(osaMsgQId_t msgQId, void* pMessage) +{ +#if osNumberOfMessageQs + msg_queue_handler_t handler; + osaStatus_t osaStatus; + if(msgQId == NULL) + { + return osaStatus_Error; + } + handler = (msg_queue_handler_t)msgQId; + { + if (__get_IPSR()) + { + portBASE_TYPE taskToWake = pdFALSE; + + if (pdTRUE == xQueueSendToBackFromISR(handler, pMessage, &taskToWake)) + { + if (pdTRUE == taskToWake) + { + portYIELD_FROM_ISR(taskToWake); + } + osaStatus = osaStatus_Success; + } + else + { + osaStatus = osaStatus_Error; + } + + } + else + { + osaStatus = (xQueueSendToBack(handler, pMessage, 0)== pdPASS)?(osaStatus_Success):(osaStatus_Error); + } + } + return osaStatus; +#else + (void)msgQId; + (void)pMessage; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQGet + * Description : This function checks the queue's status, if it is not empty, + * get message from it and return osaStatus_Success, otherwise, timeout will + * be used for wait. The parameter timeout indicates how long should wait in + * milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will return + * osaStatus_Timeout immediately if queue is empty. + * This function returns osaStatus_Success if message is got successfully, + * returns osaStatus_Timeout if message queue is empty within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, void *pMessage, uint32_t millisec) +{ +#if osNumberOfMessageQs + osaStatus_t osaStatus; + msg_queue_handler_t handler; + uint32_t timeoutTicks; + if( msgQId == NULL ) + { + return osaStatus_Error; + } + handler = (msg_queue_handler_t)msgQId; + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + if (xQueueReceive(handler, pMessage, timeoutTicks)!=pdPASS) + { + osaStatus = osaStatus_Timeout; /* not able to send it to the queue? */ + } + else + { + osaStatus = osaStatus_Success; + } + return osaStatus; +#else + (void)msgQId; + (void)pMessage; + (void)millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQDestroy + * Description : This function is used to destroy the message queue. + * Return : osaStatus_Success if the message queue is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQDestroy(osaMsgQId_t msgQId) +{ +#if osNumberOfMessageQs + msg_queue_handler_t handler; + if(msgQId == NULL ) + { + return osaStatus_Error; + } + handler = (msg_queue_handler_t)msgQId; + vQueueDelete(handler); + return osaStatus_Success; +#else + (void)msgQId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptEnable(void) +{ + if (__get_IPSR()) + { + if(g_base_priority_top) + { + g_base_priority_top--; + portCLEAR_INTERRUPT_MASK_FROM_ISR(g_base_priority_array[g_base_priority_top]); + } + + } + else + { + portEXIT_CRITICAL(); + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptDisable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptDisable(void) +{ + if (__get_IPSR()) + { + if(g_base_priority_top < OSA_MAX_ISR_CRITICAL_SECTION_DEPTH) + { + g_base_priority_array[g_base_priority_top] = portSET_INTERRUPT_MASK_FROM_ISR(); + g_base_priority_top++; + } + + } + else + { + portENTER_CRITICAL(); + } + +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestricted + * Description : Disable interrupts except high-priority ones + * + *END**************************************************************************/ +void OSA_InterruptEnableRestricted(uint32_t *pu8OldIntLevel) +{ + /* Disable interrupts for duration of this function */ + OSA_DisableIRQGlobal(); + + /* Store old priority level */ + *pu8OldIntLevel = __get_BASEPRI(); + + /* Update priority level, but only if it is a more restrictive value */ + __set_BASEPRI_MAX((3U << (8U - __NVIC_PRIO_BITS)) & 0xffU); + + /* Restore interrupts */ + OSA_EnableIRQGlobal(); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestore + * Description : Restore interrupts that were previously restricted by a call + * to OSA_InterruptEnableRestricted + * + *END**************************************************************************/ +void OSA_InterruptEnableRestore(uint32_t *pu8OldIntLevel) +{ + // write value direct into register ARM to ARM, no translations required + __set_BASEPRI(*pu8OldIntLevel); +} + + +uint32_t gInterruptDisableCount = 0; +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EnableIRQGlobal + * Description : enable interrupts using PRIMASK register. + * + *END**************************************************************************/ +void OSA_EnableIRQGlobal(void) +{ + if (gInterruptDisableCount > 0) + { + gInterruptDisableCount--; + + if (gInterruptDisableCount == 0) + { + __enable_irq(); + } + /* call core API to enable the global interrupt*/ + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_DisableIRQGlobal + * Description : disable interrupts using PRIMASK register. + * + *END**************************************************************************/ +void OSA_DisableIRQGlobal(void) +{ + /* call core API to disable the global interrupt*/ + __disable_irq(); + + /* update counter*/ + gInterruptDisableCount++; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InstallIntHandler + * Description : This function is used to install interrupt handler. + * + *END**************************************************************************/ +void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void)) +{ + +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_suppress = Pm138") +#endif + InstallIRQHandler((IRQn_Type)IRQNumber, (uint32_t)handler); +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_remark = PM138") +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeInit + * Description : Empty + * + *END**************************************************************************/ +void OSA_TimeInit(void) +{ + +} + +/*! ********************************************************************************* +************************************************************************************* +* Private functions +************************************************************************************* +********************************************************************************** */ +OSA_TASK_DEFINE(startup_task, gMainThreadPriority_c, 1, gMainThreadStackSize_c, 0) ; +int main (void) +{ + /* Initialize MCU clock */ + hardware_init(); + OSA_TaskCreate(OSA_TASK(startup_task), NULL); + vTaskStartScheduler(); + + return 0; +} + +/*! ********************************************************************************* +* \brief Allocates a osObjectStruct_t block in the osObjectHeap array. +* \param[in] pointer to the object info struct. +* Object can be semaphore, mutex, message Queue, event +* \return Pointer to the allocated osObjectStruct_t, NULL if failed. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++, pObj += pOsObjectInfo->objectStructSize) + { + if(((osObjStruct_t*)pObj)->inUse == 0) + { + ((osObjStruct_t*)pObj)->inUse = 1; + return (void*)pObj; + } + } + return NULL; +} +#endif + +/*! ********************************************************************************* +* \brief Verifies the object is valid and allocated in the osObjectHeap array. +* \param[in] the pointer to the object info struct. +* \param[in] the pointer to the object struct. +* Object can be semaphore, mutex, message Queue, event +* \return TRUE if the object is valid and allocated, FALSE otherwise +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++ , pObj += pOsObjectInfo->objectStructSize) + { + if(pObj == pObjectStruct) + { + if(((osObjStruct_t*)pObj)->inUse) + { + return TRUE; + } + break; + } + } + return FALSE; +} +#endif + +/*! ********************************************************************************* +* \brief Frees an osObjectStruct_t block from the osObjectHeap array. +* \param[in] pointer to the object info struct. +* \param[in] Pointer to the allocated osObjectStruct_t to free. +* Object can be semaphore, mutex, message Queue, event +* \return none. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0; i < pOsObjectInfo->objNo; i++, pObj += pOsObjectInfo->objectStructSize ) + { + if(pObj == pObjectStruct) + { + ((osObjStruct_t*)pObj)->inUse = 0; + break; + } + } +} +#endif + +/*! ********************************************************************************* +* \brief FreeRTOS application malloc failed hook +* +* +* \remarks Function is called by FreeRTOS if there is not enough space in the +* heap for task stack allocation or for OS object allocation +* +********************************************************************************** */ +#if (configUSE_MALLOC_FAILED_HOOK==1) +void vApplicationMallocFailedHook (void) +{ + panic(0,(uint32_t)vApplicationMallocFailedHook,0,0); +} +#endif + diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Include/PDM.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Include/PDM.h new file mode 100755 index 00000000000..a1650ab86b7 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Include/PDM.h @@ -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 ***/ +/****************************************************************************/ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Library/libPDM.a b/third_party/nxp/JN5189DK6/middleware/wireless/framework/PDM/Library/libPDM.a new file mode 100755 index 0000000000000000000000000000000000000000..9c40aac91a52f5114fe13f7df55b0bf35b1f314f GIT binary patch literal 92286 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 =&_DvGwM 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 +#include +#include + +#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; +} +/*-----------------------------------------------------------*/ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Interface/Panic.h b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Interface/Panic.h new file mode 100755 index 00000000000..aa65ec716eb --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Interface/Panic.h @@ -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__ */ diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Source/Panic.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Source/Panic.c new file mode 100755 index 00000000000..8315b0c1a11 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Panic/Source/Panic.c @@ -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 diff --git a/third_party/nxp/JN5189DK6/middleware/wireless/framework/Reset/Reset.c b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Reset/Reset.c new file mode 100755 index 00000000000..9fa25ce27f6 --- /dev/null +++ b/third_party/nxp/JN5189DK6/middleware/wireless/framework/Reset/Reset.c @@ -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 ***************************************/ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c new file mode 100755 index 00000000000..2f55db224d8 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.c @@ -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 */ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h new file mode 100755 index 00000000000..9c89723ce93 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Flash/Internal/Flash_Adapter.h @@ -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__ */ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c new file mode 100755 index 00000000000..5e6b88ad6f9 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.c @@ -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 +#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 diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h new file mode 100755 index 00000000000..047b2fd77f1 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/FunctionLib/FunctionLib.h @@ -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 + +/*! ********************************************************************************* +************************************************************************************* +* 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< (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_ */ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.c new file mode 100755 index 00000000000..21ea993b0bc --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.c @@ -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; ihead == 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 + diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.h new file mode 100755 index 00000000000..a094ce9bd92 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Lists/GenericList.h @@ -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_*/ \ No newline at end of file diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Interface/MemManager.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Interface/MemManager.h new file mode 100755 index 00000000000..f9e6fb5b81e --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Interface/MemManager.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 + +#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_ */ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Source/MemManager.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Source/MemManager.c new file mode 100755 index 00000000000..903d473dc87 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/MemManager/Source/MemManager.c @@ -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; iallocStatus == 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; ipoolSize; 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); +} diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h new file mode 100755 index 00000000000..0f8b2c21aae --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction.h @@ -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 diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h new file mode 100755 index 00000000000..1578be2e47f --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_bm.h @@ -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 + ******************************************************************************/ + diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h new file mode 100755 index 00000000000..d74baaf99d0 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_config.h @@ -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_ */ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.h new file mode 100755 index 00000000000..c1ba2924383 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Interface/fsl_os_abstraction_free_rtos.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 + ******************************************************************************/ + diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c new file mode 100755 index 00000000000..bb5fc93e379 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_bm.c @@ -0,0 +1,1527 @@ +/*! ********************************************************************************* +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* Copyright 2016-2017 NXP +* All rights reserved. +* +* \file +* +* This is the source file for the OS Abstraction layer for MQXLite. +* +* SPDX-License-Identifier: BSD-3-Clause +********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ + +#include "EmbeddedTypes.h" +#include "fsl_os_abstraction.h" +#include "fsl_os_abstraction_bm.h" +#include "fsl_common.h" +#include +#include "GenericList.h" + +/*! ********************************************************************************* +************************************************************************************* +* Private macros +************************************************************************************* +********************************************************************************** */ + +/* Weak function. */ +#if defined(__GNUC__) +#define __WEAK_FUNC __attribute__((weak)) +#elif defined(__ICCARM__) +#define __WEAK_FUNC __weak +#elif defined( __CC_ARM ) +#define __WEAK_FUNC __weak +#endif + +#ifdef DEBUG_ASSERT +#define OS_ASSERT(condition) if(!(condition))while(1); +#else +#define OS_ASSERT(condition) (void)(condition); +#endif + +#if (osNumberOfSemaphores || osNumberOfMutexes || osNumberOfEvents || osNumberOfMessageQs) +#define osObjectAlloc_c 1 +#else +#define osObjectAlloc_c 0 +#endif + +/************************************************************************************ +************************************************************************************* +* Private type definitions +************************************************************************************* +************************************************************************************/ + +typedef struct osMutexStruct_tag + { + uint32_t inUse; + mutex_t mutex; + }osMutexStruct_t; + +typedef struct osEventStruct_tag + { + uint32_t inUse; + event_t event; + }osEventStruct_t; + +typedef struct osSemaphoreStruct_tag + { + uint32_t inUse; + semaphore_t semaphore; + }osSemaphoreStruct_t; + +typedef struct osMsgQStruct_tag + { + uint32_t inUse; + msg_queue_t queue; + }osMsgQStruct_t; + +typedef struct osObjStruct_tag + { + uint32_t inUse; + uint32_t osObj; + }osObjStruct_t; + +typedef struct osObjectInfo_tag +{ + void* pHeap; + uint32_t objectStructSize; + uint32_t objNo; +}osObjectInfo_t; + + +/*! ********************************************************************************* +************************************************************************************* +* Private prototypes +************************************************************************************* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo); +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +#endif + +extern void main_task(void *argument); +void task_init(void); +__WEAK_FUNC void OSA_TimeInit(void); +__WEAK_FUNC uint32_t OSA_TimeDiff(uint32_t time_start, uint32_t time_end); +osaStatus_t OSA_Init(void); +void OSA_Start(void); +static void OSA_InsertTaskBefore(task_handler_t newTCB, task_handler_t currentTCB); + +/*! ********************************************************************************* +************************************************************************************* +* Public memory declarations +************************************************************************************* +********************************************************************************** */ +#define main_taskStack NULL + +const uint8_t gUseRtos_c = USE_RTOS; /* USE_RTOS = 0 for BareMetal and 1 for OS */ + +/*! ********************************************************************************* +************************************************************************************* +* Private memory declarations +************************************************************************************* +********************************************************************************** */ + +list_t threadList; + +#if osNumberOfSemaphores +osSemaphoreStruct_t osSemaphoreHeap[osNumberOfSemaphores]; +const osObjectInfo_t osSemaphoreInfo = {osSemaphoreHeap, sizeof(osSemaphoreStruct_t),osNumberOfSemaphores}; +#endif + +#if osNumberOfMutexes +osMutexStruct_t osMutexHeap[osNumberOfMutexes]; +const osObjectInfo_t osMutexInfo = {osMutexHeap, sizeof(osMutexStruct_t),osNumberOfMutexes}; +#endif + +#if osNumberOfEvents +osEventStruct_t osEventHeap[osNumberOfEvents]; +const osObjectInfo_t osEventInfo = {osEventHeap, sizeof(osEventStruct_t),osNumberOfEvents}; +#endif + +#if osNumberOfMessageQs +osMsgQStruct_t osMsgQHeap[osNumberOfMessageQs]; +const osObjectInfo_t osMsgQInfo = {osMsgQHeap, sizeof(osMsgQStruct_t),osNumberOfMessageQs}; +#endif + +#if (TASK_MAX_NUM > 0) + +/* Global variales for task. */ +static task_handler_t g_curTask; /* Current task. */ +/* + * All task control blocks in g_taskControlBlockPool will be linked as a + * list, and the list is managed by the pointer g_freeTaskControlBlock. + */ +static task_control_block_t g_taskControlBlockPool[TASK_MAX_NUM]; + +/* + * Pointer to the free task control blocks. To create a task, we should get + * task control block from this pointer. When task is destroyed, the control + * block will be returned and managed by this pointer. + */ +static task_control_block_t *g_freeTaskControlBlock; + +/* Head node of task list, all tasks will be linked to this head node. */ +static task_control_block_t *p_taskListHead = NULL; +#endif +uint32_t gInterruptDisableCount = 0; +uint32_t gTickCounter = 0; + +/*! ********************************************************************************* +************************************************************************************* +* Public functions +************************************************************************************* +********************************************************************************** */ +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EnableIRQGlobal + * Description : Disable system interrupt. + * + *END**************************************************************************/ +void OSA_EnableIRQGlobal(void) +{ + if (gInterruptDisableCount > 0) + { + gInterruptDisableCount--; + + if (gInterruptDisableCount == 0) + { + __enable_irq(); + } + /* call core API to enable the global interrupt*/ + } +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_DisableIRQGlobal + * Description : Disable system interrupt + * This function will disable the global interrupt by calling the core API + * + *END**************************************************************************/ +void OSA_DisableIRQGlobal(void) +{ + /* call core API to disable the global interrupt*/ + __disable_irq(); + + /* update counter*/ + gInterruptDisableCount++; +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetId + * Description : This function is used to get current active task's handler. + * + *END**************************************************************************/ + +osaTaskId_t OSA_TaskGetId(void) +{ + return (osaTaskId_t)g_curTask; +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EXT_TaskYield + * Description : When a task calls this function, it will give up CPU and put + * itself to the tail of ready list. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskYield(void) +{ + return osaStatus_Success; +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetPriority + * Description : This function returns task's priority by task handler. + * + *END**************************************************************************/ + +osaTaskPriority_t OSA_TaskGetPriority(osaTaskId_t taskId) +{ + task_handler_t handler = (task_handler_t)taskId; + return handler->priority; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskSetPriority + * Description : This function sets task's priority by task handler. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskSetPriority(osaTaskId_t taskId, osaTaskPriority_t taskPriority) +{ + task_handler_t handler = (task_handler_t)taskId; + task_handler_t p; + + /* Remove task control block from task list. */ + handler->prev->next = handler->next; + handler->next->prev = handler->prev; + if( handler == p_taskListHead ) + { + p_taskListHead = handler->next; + } + + handler->priority = taskPriority; + /* Insert task control block into the task list. */ + if( handler->priority <= p_taskListHead->priority ) + { + /* New task has the highest priority */ + OSA_InsertTaskBefore(handler, p_taskListHead); + p_taskListHead = handler; + } + else if( handler->priority >= p_taskListHead->prev->priority ) + { + /* New task has the lowest priority */ + OSA_InsertTaskBefore(handler, p_taskListHead); + } + else + { + p = p_taskListHead->next; + + while (p != p_taskListHead) + { + if (handler->priority <= p->priority) + { + OSA_InsertTaskBefore(handler, p); + break; + } + p = p->next; + } + } + + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : task_init + * Description : This function is used to initialize bare metal's task system, + * it will prepare task control block pool and initialize corresponding + * structures. This function should be called before creating any tasks. + * + *END**************************************************************************/ +void task_init(void) +{ + int32_t i = TASK_MAX_NUM-1; + + g_taskControlBlockPool[i].next = NULL; + + while (i--) + { + /* Link all task control blocks to a list. */ + g_taskControlBlockPool[i].next = &g_taskControlBlockPool[i+1]; + } + + g_freeTaskControlBlock = g_taskControlBlockPool; +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskCreate + * Description : This function is used to create a task and make it ready. + * Param[in] : threadDef - Definition of the thread. + * task_param - Parameter to pass to the new thread. + * Return Thread handle of the new thread, or NULL if failed. + * + *END**************************************************************************/ +osaTaskId_t OSA_TaskCreate(osaThreadDef_t *thread_def,osaTaskParam_t task_param) +{ + osaTaskId_t taskId = NULL; + task_control_block_t *p_newTaskControlBlock; + task_control_block_t *p_currentTaskControlBlock; + + if (g_freeTaskControlBlock) + { + /* Get new task control block from pool. */ + p_newTaskControlBlock = g_freeTaskControlBlock; + g_freeTaskControlBlock = g_freeTaskControlBlock->next; + /* Set task entry and parameter.*/ + p_newTaskControlBlock->p_func = thread_def->pthread; + p_newTaskControlBlock->haveToRun = true; + p_newTaskControlBlock->priority = PRIORITY_OSA_TO_RTOS(thread_def->tpriority); + p_newTaskControlBlock->param = task_param; + p_newTaskControlBlock->next = NULL; + p_newTaskControlBlock->prev = NULL; + + if (p_taskListHead == NULL) + { + p_taskListHead = p_newTaskControlBlock; + p_taskListHead->next = p_taskListHead; + p_taskListHead->prev = p_taskListHead; + } + else if (p_newTaskControlBlock->priority <= p_taskListHead->priority) + { + OSA_InsertTaskBefore(p_newTaskControlBlock, p_taskListHead); + p_taskListHead = p_newTaskControlBlock; + } + else if (p_newTaskControlBlock->priority >= p_taskListHead->prev->priority) + { + OSA_InsertTaskBefore(p_newTaskControlBlock, p_taskListHead); + } + else + { + p_currentTaskControlBlock = p_taskListHead->next; + + while (p_currentTaskControlBlock != p_taskListHead) + { + if (p_newTaskControlBlock->priority <= p_currentTaskControlBlock->priority) + { + OSA_InsertTaskBefore(p_newTaskControlBlock, p_currentTaskControlBlock); + break; + } + p_currentTaskControlBlock = p_currentTaskControlBlock->next; + } + + } + /* Task handler is pointer of task control block. */ + taskId = (osaTaskId_t)p_newTaskControlBlock; + } + + return taskId; +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskDestroy + * Description : This function destroy a task. + * Param[in] :taskId - Thread handle. + * Return osaStatus_Success if the task is destroied, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskDestroy(osaTaskId_t taskId) +{ + task_handler_t handler; + if(taskId == NULL) + { + return osaStatus_Error; + } + handler = (task_handler_t)taskId; + + /* Remove task control block from task list. */ + handler->prev->next = handler->next; + handler->next->prev = handler->prev; + + /* + * If current task is destroyed, then g_curTask will point to the previous + * task, so that the subsequent tasks could be called. Check the function + * OSA_Start for more details. + */ + if (handler == g_curTask) + { + g_curTask = handler->prev; + } + + /* Put task control block back to pool. */ + handler->prev = NULL; + handler->next = g_freeTaskControlBlock; + g_freeTaskControlBlock = handler; + + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeInit + * Description : This function initializes the timer used in BM OSA, the + * functions such as OSA_TimeDelay, OSA_TimeGetMsec, and the timeout are all + * based on this timer. + * + *END**************************************************************************/ +__WEAK_FUNC void OSA_TimeInit(void) +{ +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk); + SysTick->LOAD = SystemCoreClock/1000 - 1; + SysTick->VAL = 0; + SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_CLKSOURCE_Msk; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeDiff + * Description : This function gets the difference between two time stamp, + * time overflow is considered. + * + *END**************************************************************************/ +__WEAK_FUNC uint32_t OSA_TimeDiff(uint32_t time_start, uint32_t time_end) +{ + if (time_end >= time_start) + { + return time_end - time_start; + } + else + { + return FSL_OSA_TIME_RANGE - time_start + time_end + 1; + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA__TimeDelay + * Description : This function is used to suspend the active thread for the given number of milliseconds. + * + *END**************************************************************************/ +void OSA_TimeDelay(uint32_t millisec) +{ + uint32_t currTime, timeStart; + + timeStart = OSA_TimeGetMsec(); + + do { + currTime = OSA_TimeGetMsec(); /* Get current time stamp */ + } while (millisec >= OSA_TimeDiff(timeStart, currTime)); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeGetMsec + * Description : This function gets current time in milliseconds. + * + *END**************************************************************************/ +__WEAK_FUNC uint32_t OSA_TimeGetMsec(void) +{ +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + return gTickCounter; +#else + return 0; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeResetMsec + * Description : This function resets the current time to 0. + * + *END**************************************************************************/ +__WEAK_FUNC void OSA_TimeResetMsec(void) +{ + gTickCounter = 0; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreCreate + * Description : This function is used to create a semaphore. + * Return : Semaphore handle of the new semaphore, or NULL if failed. + * + *END**************************************************************************/ + +osaSemaphoreId_t OSA_SemaphoreCreate(uint32_t initValue) +{ +#if osNumberOfSemaphores + osaSemaphoreId_t semId; + osSemaphoreStruct_t* pSemStruct; + OSA_InterruptDisable(); + semId = pSemStruct = osObjectAlloc(&osSemaphoreInfo); + OSA_InterruptEnable(); + if(semId == NULL) + { + return NULL; + } + + pSemStruct->semaphore.semCount = initValue; + pSemStruct->semaphore.isWaiting = false; + pSemStruct->semaphore.time_start = 0u; + pSemStruct->semaphore.timeout = 0u; + + return semId; +#else + initValue=initValue; + return NULL; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreDestroy + * Description : This function is used to destroy a semaphore. + * Return : osaStatus_Success if the semaphore is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreDestroy(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + if(osObjectIsAllocated(&osSemaphoreInfo, semId) == FALSE) + { + return osaStatus_Error; + } + OSA_InterruptDisable(); + osObjectFree(&osSemaphoreInfo, semId); + OSA_InterruptEnable(); + return osaStatus_Success; +#else + semId=semId; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreWait + * Description : This function checks the semaphore's counting value, if it is + * positive, decreases it and returns osaStatus_Success, otherwise, timeout + * will be used for wait. The parameter timeout indicates how long should wait + * in milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will + * return osaStatus_Timeout immediately if semaphore is not positive. + * This function returns osaStatus_Success if the semaphore is received, returns + * osaStatus_Timeout if the semaphore is not received within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec) +{ +#if osNumberOfSemaphores + osSemaphoreStruct_t* pSemStruct; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + if(osObjectIsAllocated(&osSemaphoreInfo, semId) == FALSE) + { + return osaStatus_Error; + } + pSemStruct = (osSemaphoreStruct_t*)semId; + /* Check the sem count first. Deal with timeout only if not already set */ + + if (pSemStruct->semaphore.semCount) + { + OSA_DisableIRQGlobal(); + pSemStruct->semaphore.semCount --; + pSemStruct->semaphore.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and semaphore is not available, return kStatus_OSA_Timeout. */ + return osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pSemStruct->semaphore.isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pSemStruct->semaphore.timeout < OSA_TimeDiff(pSemStruct->semaphore.time_start, currentTime)) + { + OSA_DisableIRQGlobal(); + pSemStruct->semaphore.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Timeout; + } + } + else if (millisec != osaWaitForever_c) /* If don't wait forever, start the timer */ + { + /* Start the timeout counter */ + OSA_DisableIRQGlobal(); + pSemStruct->semaphore.isWaiting = true; + OSA_EnableIRQGlobal(); + pSemStruct->semaphore.time_start = OSA_TimeGetMsec(); + pSemStruct->semaphore.timeout = millisec; + } +#endif + } + + return osaStatus_Idle; +#else + semId=semId; + millisec=millisec; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphorePost + * Description : This function is used to wake up one task that wating on the + * semaphore. If no task is waiting, increase the semaphore. The function returns + * osaStatus_Success if the semaphre is post successfully, otherwise returns + * osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphorePost(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + osSemaphoreStruct_t* pSemStruct; + if(osObjectIsAllocated(&osSemaphoreInfo, semId) == FALSE) + { + return osaStatus_Error; + } + pSemStruct = (osSemaphoreStruct_t*)semId; + /* The max value is 0xFF */ + if (0xFF == pSemStruct->semaphore.semCount) + { + return osaStatus_Error; + } + OSA_DisableIRQGlobal(); + ++pSemStruct->semaphore.semCount; + OSA_EnableIRQGlobal(); + + return osaStatus_Success; +#else + semId=semId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexCreate + * Description : This function is used to create a mutex. + * Return : Mutex handle of the new mutex, or NULL if failed. + * + *END**************************************************************************/ +osaMutexId_t OSA_MutexCreate(void) +{ +#if osNumberOfMutexes + osaMutexId_t mutexId; + osMutexStruct_t* pMutexStruct; + OSA_InterruptDisable(); + mutexId = pMutexStruct = osObjectAlloc(&osMutexInfo); + OSA_InterruptEnable(); + if(mutexId == NULL) + { + return NULL; + } + pMutexStruct->mutex.isLocked = false; + pMutexStruct->mutex.isWaiting = false; + pMutexStruct->mutex.time_start = 0u; + pMutexStruct->mutex.timeout = 0u; + return mutexId; +#else + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexLock + * Description : This function checks the mutex's status, if it is unlocked, + * lock it and returns osaStatus_Success, otherwise, wait for the mutex. + * MQX does not support timeout to wait for a mutex. + * This function returns osaStatus_Success if the mutex is obtained, returns + * osaStatus_Error if any errors occur during waiting. If the mutex has been + * locked, pass 0 as timeout will return osaStatus_Timeout immediately. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec) +{ +#if osNumberOfMutexes + osMutexStruct_t* pMutexStruct; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + if(osObjectIsAllocated(&osMutexInfo, mutexId) == FALSE) + { + return osaStatus_Error; + } + pMutexStruct = (osMutexStruct_t*)mutexId; + + /* Always check first. Deal with timeout only if not available. */ + if (pMutexStruct->mutex.isLocked == false) + { + /* Get the lock and return success */ + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isLocked = true; + pMutexStruct->mutex.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and mutex is not available, return kStatus_OSA_Timeout. */ + return osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pMutexStruct->mutex.isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pMutexStruct->mutex.timeout < OSA_TimeDiff(pMutexStruct->mutex.time_start, currentTime)) + { + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isWaiting = false; + OSA_EnableIRQGlobal(); + return osaStatus_Timeout; + } + } + else if (millisec != osaWaitForever_c) /* If dont't wait forever, start timer. */ + { + /* Start the timeout counter */ + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isWaiting = true; + OSA_EnableIRQGlobal(); + pMutexStruct->mutex.time_start = OSA_TimeGetMsec(); + pMutexStruct->mutex.timeout = millisec; + } +#endif + } + + return osaStatus_Idle; +#else + mutexId=mutexId; + millisec=millisec; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexUnlock + * Description : This function is used to unlock a mutex. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexUnlock(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + osMutexStruct_t* pMutexStruct; + if(osObjectIsAllocated(&osMutexInfo, mutexId) == FALSE) + { + return osaStatus_Error; + } + pMutexStruct = (osMutexStruct_t*)mutexId; + OSA_DisableIRQGlobal(); + pMutexStruct->mutex.isLocked = false; + OSA_EnableIRQGlobal(); + return osaStatus_Success; +#else + mutexId=mutexId; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexDestroy + * Description : This function is used to destroy a mutex. + * Return : osaStatus_Success if the lock object is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexDestroy(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + if(osObjectIsAllocated(&osMutexInfo, mutexId) == FALSE) + { + return osaStatus_Error; + } + OSA_InterruptDisable(); + osObjectFree(&osMutexInfo, mutexId); + OSA_InterruptEnable(); + + return osaStatus_Success; +#else + mutexId=mutexId; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventCreate + * Description : This function is used to create a event object. + * Return : Event handle of the new event, or NULL if failed. + * + *END**************************************************************************/ +osaEventId_t OSA_EventCreate(bool_t autoClear) +{ +#if osNumberOfEvents + osaEventId_t eventId; + osEventStruct_t* pEventStruct; + OSA_InterruptDisable(); + eventId = pEventStruct = osObjectAlloc(&osEventInfo); + OSA_InterruptEnable(); + if(eventId == NULL) + { + return NULL; + } + pEventStruct->event.isWaiting = false; + pEventStruct->event.flags = 0; + pEventStruct->event.autoClear = autoClear; + pEventStruct->event.time_start = 0u; + pEventStruct->event.timeout = 0u; + pEventStruct->event.waitingTask = NULL; + return eventId; +#else + (void)autoClear; + return NULL; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventSet + * Description : Set one or more event flags of an event object. + * Return : osaStatus_Success if set successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventSet(osaEventId_t eventId, osaEventFlags_t flagsToSet) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + /* Set flags ensuring atomic operation */ + OSA_DisableIRQGlobal(); + pEventStruct->event.flags |= flagsToSet; + if (pEventStruct->event.waitingTask != NULL) + { + pEventStruct->event.waitingTask->haveToRun = true; + } + OSA_EnableIRQGlobal(); + + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToSet; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventClear + * Description : Clear one or more event flags of an event object. + * Return :osaStatus_Success if clear successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventClear(osaEventId_t eventId, osaEventFlags_t flagsToClear) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + /* Clear flags ensuring atomic operation */ + OSA_DisableIRQGlobal(); + pEventStruct->event.flags &= ~flagsToClear; + if (pEventStruct->event.flags != 0x00) + { + if (pEventStruct->event.waitingTask != NULL) + { + pEventStruct->event.waitingTask->haveToRun = true; + } + } + OSA_EnableIRQGlobal(); + + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToClear; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventWait + * Description : This function checks the event's status, if it meets the wait + * condition, return osaStatus_Success, otherwise, timeout will be used for + * wait. The parameter timeout indicates how long should wait in milliseconds. + * Pass osaWaitForever_c to wait indefinitely, pass 0 will return the value + * osaStatus_Timeout immediately if wait condition is not met. The event flags + * will be cleared if the event is auto clear mode. Flags that wakeup waiting + * task could be obtained from the parameter setFlags. + * This function returns osaStatus_Success if wait condition is met, returns + * osaStatus_Timeout if wait condition is not met within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_EventWait(osaEventId_t eventId, osaEventFlags_t flagsToWait, bool_t waitAll, uint32_t millisec, osaEventFlags_t *pSetFlags) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + osaStatus_t retVal = osaStatus_Idle; + if(pSetFlags == NULL) + { + return osaStatus_Error; + } + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + + OSA_DisableIRQGlobal(); +#if (TASK_MAX_NUM > 0) + pEventStruct->event.waitingTask = OSA_TaskGetId(); +#endif + + *pSetFlags = pEventStruct->event.flags & flagsToWait; + + /* Check the event flag first, if does not meet wait condition, deal with timeout. */ + if ((((!waitAll) && (*pSetFlags))) || (*pSetFlags == flagsToWait)) + { + pEventStruct->event.isWaiting = false; + if(TRUE == pEventStruct->event.autoClear) + { + pEventStruct->event.flags &= ~flagsToWait; + pEventStruct->event.waitingTask->haveToRun = false; /* Cherry-picked from [MCKFW-1872] */ + } + retVal = osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and wait condition is not met, return kStatus_OSA_Timeout. */ + retVal = osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pEventStruct->event.isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pEventStruct->event.timeout < OSA_TimeDiff(pEventStruct->event.time_start, currentTime)) + { + pEventStruct->event.isWaiting = false; + retVal = osaStatus_Timeout; + } + } + else if(millisec != osaWaitForever_c) /* If no timeout, don't start the timer */ + { + /* Start the timeout counter */ + pEventStruct->event.isWaiting = true; + pEventStruct->event.time_start = OSA_TimeGetMsec(); + pEventStruct->event.timeout = millisec; + } +#endif + else + { + pEventStruct->event.waitingTask->haveToRun = false; + } + } + + OSA_EnableIRQGlobal(); + + return retVal; +#else + (void)eventId; + (void)flagsToWait; + (void)waitAll; + (void)millisec; + (void)pSetFlags; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventDestroy + * Description : This function is used to destroy a event object. Return + * osaStatus_Success if the event object is destroyed successfully, otherwise + * return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_EventDestroy(osaEventId_t eventId) +{ +#if osNumberOfEvents + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + + OSA_InterruptDisable(); + osObjectFree(&osEventInfo, eventId); + OSA_InterruptEnable(); + return osaStatus_Success; +#else + (void)eventId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQCreate + * Description : This function is used to create a message queue. + * Return : the handle to the message queue if create successfully, otherwise + * return NULL. + * + *END**************************************************************************/ +osaMsgQId_t OSA_MsgQCreate(uint32_t msgNo) +{ +#if osNumberOfMessageQs + osaMsgQId_t msgQId = NULL; + osMsgQStruct_t* pMsgQStruct; + + if(msgNo <= osNumberOfMessages) + { + OSA_InterruptDisable(); + msgQId = pMsgQStruct = osObjectAlloc(&osMsgQInfo); + OSA_InterruptEnable(); + + if(msgQId) + { + pMsgQStruct->queue.max = msgNo; + pMsgQStruct->queue.number = 0; + pMsgQStruct->queue.head = 0; + pMsgQStruct->queue.tail = 0; + } + } + + return msgQId; +#else + msgNo=msgNo; + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQPut + * Description : This function is used to put a message to a message queue. +* Return : osaStatus_Success if the message is put successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQPut(osaMsgQId_t msgQId, void* pMessage) +{ +#if osNumberOfMessageQs + msg_queue_t* pQueue; + osaStatus_t status = osaStatus_Success; + + if(osObjectIsAllocated(&osMsgQInfo, msgQId) == FALSE) + { + status = osaStatus_Error; + } + else + { + pQueue = &((osMsgQStruct_t*)msgQId)->queue; + + OSA_DisableIRQGlobal(); + if( pQueue->number >= pQueue->max ) + { + status = osaStatus_Error; + } + else + { + pQueue->queueMem[pQueue->tail] = *((uint32_t*)pMessage); + pQueue->number++; + pQueue->tail++; + + if( pQueue->tail >= pQueue->max ) + { + pQueue->tail = 0; + } + + if( pQueue->waitingTask ) + { + pQueue->waitingTask->haveToRun = 1; + } + } + OSA_EnableIRQGlobal(); + } + + return status; +#else + msgQId=msgQId; + pMessage=pMessage; + return osaStatus_Error; +#endif +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQGet + * Description : This function checks the queue's status, if it is not empty, + * get message from it and return osaStatus_Success, otherwise, timeout will + * be used for wait. The parameter timeout indicates how long should wait in + * milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will return + * osaStatus_Timeout immediately if queue is empty. + * This function returns osaStatus_Success if message is got successfully, + * returns osaStatus_Timeout if message queue is empty within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, void *pMessage, uint32_t millisec) +{ +#if osNumberOfMessageQs + osaStatus_t status = osaStatus_Idle; + msg_queue_t* pQueue; +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + uint32_t currentTime; +#endif + + if(osObjectIsAllocated(&osMsgQInfo, msgQId) == FALSE) + { + status = osaStatus_Error; + } + else + { + pQueue = &((osMsgQStruct_t*)msgQId)->queue; + pQueue->waitingTask = OSA_TaskGetId(); + + OSA_DisableIRQGlobal(); + if( pQueue->number ) + { + *((uint32_t*)pMessage) = pQueue->queueMem[pQueue->head]; + pQueue->number--; + pQueue->head++; + pQueue->isWaiting = 0; + + if( pQueue->head >= pQueue->max ) + { + pQueue->head = 0; + } + status = osaStatus_Success; + } + else + { + if (0 == millisec) + { + /* If timeout is 0 and wait condition is not met, return kStatus_OSA_Timeout. */ + status = osaStatus_Timeout; + } +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) + else if (pQueue->isWaiting) + { + /* Check for timeout */ + currentTime = OSA_TimeGetMsec(); + if (pQueue->timeout < OSA_TimeDiff(pQueue->time_start, currentTime)) + { + pQueue->isWaiting = 0; + status = osaStatus_Timeout; + } + } + else if(millisec != osaWaitForever_c) /* If no timeout, don't start the timer */ + { + /* Start the timeout counter */ + pQueue->isWaiting = 1; + pQueue->time_start = OSA_TimeGetMsec(); + pQueue->timeout = millisec; + } +#endif + else + { + pQueue->waitingTask->haveToRun = 0; + } + } + OSA_EnableIRQGlobal(); + } + + return status; +#else + msgQId=msgQId; + pMessage=pMessage; + millisec=millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EXT_MsgQDestroy + * Description : This function is used to destroy the message queue. + * Return : osaStatus_Success if the message queue is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQDestroy(osaMsgQId_t msgQId) +{ +#if osNumberOfMessageQs + osaStatus_t status = osaStatus_Success; + msg_queue_t* pQueue; + + if(osObjectIsAllocated(&osMsgQInfo, msgQId) == FALSE) + { + status = osaStatus_Error; + } + else + { + pQueue = &((osMsgQStruct_t*)msgQId)->queue; + + if( pQueue->waitingTask ) + { + pQueue->waitingTask->haveToRun = 1; + pQueue->waitingTask = NULL; + } + + OSA_InterruptDisable(); + osObjectFree(&osMsgQInfo, msgQId); + OSA_InterruptEnable(); + } + + return status; +#else + msgQId=msgQId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptEnable(void) +{ + OSA_EnableIRQGlobal(); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptDisable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptDisable(void) +{ + OSA_DisableIRQGlobal(); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestricted + * Description : Disable interrupts except high-priority ones + * + *END**************************************************************************/ + void OSA_InterruptEnableRestricted(uint32_t *pu32OldIntLevel) +{ + /* Disable interrupts for duration of this function */ + OSA_DisableIRQGlobal(); + + /* Store old priority level */ + *pu32OldIntLevel = __get_BASEPRI(); + + /* Update priority level, but only if it is a more restrictive value */ + __set_BASEPRI_MAX(((3U << (8U - __NVIC_PRIO_BITS)) & 0xffU)); + + /* Restore interrupts */ + OSA_EnableIRQGlobal(); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestore + * Description : Restore interrupts that were previously restricted by a call + * to OSA_InterruptEnableRestricted + * + *END**************************************************************************/ + void OSA_InterruptEnableRestore(uint32_t *pu32OldIntLevel) +{ + // write value direct into register ARM to ARM, no translations required + __set_BASEPRI(*pu32OldIntLevel); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InstallIntHandler + * Description : This function is used to install interrupt handler. + * + *END**************************************************************************/ +void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void)) +{ +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_suppress = Pm138") +#endif +#ifdef ENABLE_RAM_VECTOR_TABLE + InstallIRQHandler((IRQn_Type)IRQNumber, (uint32_t)handler); +#endif +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_remark = PM138") +#endif +} + +/*! ********************************************************************************* +************************************************************************************* +* Private functions +************************************************************************************* +********************************************************************************** */ +#if (osCustomStartup == 0) +OSA_TASK_DEFINE(main_task, gMainThreadPriority_c, 1, gMainThreadStackSize_c, 0); + +int main (void) +{ + extern void hardware_init(void); + + OSA_Init(); + /* Initialize MCU clock */ + hardware_init(); + OSA_TimeInit(); + OSA_TaskCreate(OSA_TASK(main_task),NULL); + OSA_Start(); + + return 0; +} +#endif + +/*! ********************************************************************************* +* \brief Allocates a osObjectStruct_t block in the osObjectHeap array. +* \param[in] pointer to the object info struct. +* Object can be semaphore, mutex, osTimer, message Queue, event +* \return Pointer to the allocated osObjectStruct_t, NULL if failed. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++) + { + if(((osObjStruct_t*)pObj)->inUse == 0) + { + ((osObjStruct_t*)pObj)->inUse = 1; + return (void*)pObj; + } + + pObj += pOsObjectInfo->objectStructSize; + } + return NULL; +} +#endif +/*! ********************************************************************************* +* \brief Verifies the object is valid and allocated in the osObjectHeap array. +* \param[in] the pointer to the object info struct. +* \param[in] the pointer to the object struct. +* Object can be semaphore, mutex, osTimer, message Queue, event +* \return TRUE if the object is valid and allocated, FALSE otherwise +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++) + { + if(pObj == pObjectStruct) + { + if(((osObjStruct_t*)pObj)->inUse) + { + return TRUE; + } + break; + } + pObj += pOsObjectInfo->objectStructSize; + } + return FALSE; +} +#endif + +/*! ********************************************************************************* +* \brief Frees an osObjectStruct_t block from the osObjectHeap array. +* \param[in] pointer to the object info struct. +* \param[in] Pointer to the allocated osObjectStruct_t to free. +* Object can be semaphore, mutex, osTimer, message Queue, event +* \return none. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0; i < pOsObjectInfo->objNo; i++ ) + { + if(pObj == pObjectStruct) + { + ((osObjStruct_t*)pObj)->inUse = 0; + break; + } + + pObj += pOsObjectInfo->objectStructSize; + } +} +#endif + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_Init + * Description : This function is used to setup the basic services, it should + * be called first in function main. Return kStatus_OSA_Success if services + * are initialized successfully, otherwise return kStatus_OSA_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_Init(void) +{ +#if (TASK_MAX_NUM > 0) + task_init(); +#endif + + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_Start + * Description : This function is used to start RTOS scheduler. + * + *END**************************************************************************/ +void OSA_Start(void) +{ +#if (TASK_MAX_NUM > 0) + g_curTask = p_taskListHead; + + for(;;) + { + if(g_curTask->haveToRun) + { + if(g_curTask->p_func) + { + g_curTask->p_func(g_curTask->param); + } + /* restart from the first task */ + g_curTask = p_taskListHead; + } + else + { + g_curTask = g_curTask->next; + } + } +#else + for(;;) + { + } +#endif +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InsertTaskBefore + * Description : Helper function to insert Task TCB into the task list. + * + *END**************************************************************************/ +static void OSA_InsertTaskBefore(task_handler_t newTCB, task_handler_t currentTCB) +{ + newTCB->next = currentTCB; + newTCB->prev = currentTCB->prev; + currentTCB->prev->next = newTCB; + currentTCB->prev = newTCB; +} + + +/*FUNCTION********************************************************************** + * + * Function Name : SysTick_Handler + * Description : This ISR of the SYSTICK timer. + * + *END**************************************************************************/ +#if (FSL_OSA_BM_TIMER_CONFIG != FSL_OSA_BM_TIMER_NONE) +void SysTick_Handler(void) +{ + gTickCounter++; +} +#endif diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c new file mode 100755 index 00000000000..906c61e9e27 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/OSAbstraction/Source/fsl_os_abstraction_free_rtos.c @@ -0,0 +1,1173 @@ +/*! ********************************************************************************* +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* Copyright 2016-2017, 2019 NXP +* All rights reserved. +* +* \file +* +* This is the source file for the OS Abstraction layer for freertos. +* +* SPDX-License-Identifier: BSD-3-Clause +********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ +#include "EmbeddedTypes.h" +#include "fsl_os_abstraction.h" +#include "fsl_os_abstraction_free_rtos.h" +#include +#include "GenericList.h" +#include "fsl_common.h" +#include "Panic.h" +/*! ********************************************************************************* +************************************************************************************* +* Private macros +************************************************************************************* +********************************************************************************** */ +#define millisecToTicks(millisec) ((millisec * configTICK_RATE_HZ + 999)/1000) + +#ifdef DEBUG_ASSERT +#define OS_ASSERT(condition) if(!(condition))while(1); +#else +#define OS_ASSERT(condition) (void)(condition); +#endif + +#if (osNumberOfEvents) +#define osObjectAlloc_c 1 +#else +#define osObjectAlloc_c 0 +#endif + +/*! @brief Converts milliseconds to ticks*/ +#define MSEC_TO_TICK(msec) (((uint32_t)(msec)+500uL/(uint32_t)configTICK_RATE_HZ) \ + *(uint32_t)configTICK_RATE_HZ/1000uL) +#define TICKS_TO_MSEC(tick) ((uint64_t)(tick)*1000uL/(uint32_t)configTICK_RATE_HZ) +/************************************************************************************ +************************************************************************************* +* Private type definitions +************************************************************************************* +************************************************************************************/ + +typedef struct osEventStruct_tag +{ + uint32_t inUse; + event_t event; +}osEventStruct_t; + +typedef struct osObjStruct_tag +{ + uint32_t inUse; + uint32_t osObj; +}osObjStruct_t; + +typedef struct osObjectInfo_tag +{ + void* pHeap; + uint32_t objectStructSize; + uint32_t objNo; +} osObjectInfo_t; + + +/*! ********************************************************************************* +************************************************************************************* +* Private prototypes +************************************************************************************* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo); +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct); +#endif +extern void main_task(void const *argument); +extern void hardware_init(void); +void startup_task(void* argument); + + +/*! ********************************************************************************* +************************************************************************************* +* Public memory declarations +************************************************************************************* +********************************************************************************** */ +const uint8_t gUseRtos_c = USE_RTOS; // USE_RTOS = 0 for BareMetal and 1 for OS +static uint32_t g_base_priority_array[OSA_MAX_ISR_CRITICAL_SECTION_DEPTH]; +static int32_t g_base_priority_top = 0; + +/*! ********************************************************************************* +************************************************************************************* +* Private memory declarations +************************************************************************************* +********************************************************************************** */ + +#if osNumberOfEvents +osEventStruct_t osEventHeap[osNumberOfEvents]; +const osObjectInfo_t osEventInfo = {osEventHeap, sizeof(osEventStruct_t),osNumberOfEvents}; +#endif + + +/*! ********************************************************************************* +************************************************************************************* +* Public functions +************************************************************************************* +********************************************************************************** */ + +/*FUNCTION********************************************************************** + * + * Function Name : startup_task + * Description : Wrapper over main_task.. + * + *END**************************************************************************/ +void startup_task(void* argument) +{ + main_task(argument); + while(1); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetId + * Description : This function is used to get current active task's handler. + * + *END**************************************************************************/ +osaTaskId_t OSA_TaskGetId(void) +{ + return xTaskGetCurrentTaskHandle(); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskYield + * Description : When a task calls this function, it will give up CPU and put + * itself to the tail of ready list. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskYield(void) +{ + taskYIELD(); + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskGetPriority + * Description : This function returns task's priority by task handler. + * + *END**************************************************************************/ +osaTaskPriority_t OSA_TaskGetPriority(osaTaskId_t taskId) +{ + return (osaTaskPriority_t)(PRIORITY_RTOS_TO_OSA(uxTaskPriorityGet((task_handler_t)taskId))); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskSetPriority + * Description : This function sets task's priority by task handler. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskSetPriority(osaTaskId_t taskId, osaTaskPriority_t taskPriority) +{ + vTaskPrioritySet((task_handler_t)taskId, PRIORITY_OSA_TO_RTOS(taskPriority)); + return osaStatus_Success; +} + +/*FUNCTION********************************************************************** +* +* Function Name : OSA_TaskCreate +* Description : This function is used to create a task and make it ready. +* Param[in] : threadDef - Definition of the thread. +* task_param - Parameter to pass to the new thread. +* Return Thread handle of the new thread, or NULL if failed. +* +*END**************************************************************************/ +osaTaskId_t OSA_TaskCreate(osaThreadDef_t *thread_def,osaTaskParam_t task_param) +{ + osaTaskId_t taskId = NULL; + task_handler_t task_handler; + + if (xTaskCreate( + (task_t)thread_def->pthread, /* pointer to the task */ + (char const*)thread_def->tname, /* task name for kernel awareness debugging */ + thread_def->stacksize/sizeof(portSTACK_TYPE), /* task stack size */ + (task_param_t)task_param, /* optional task startup argument */ + PRIORITY_OSA_TO_RTOS(thread_def->tpriority), /* initial priority */ + &task_handler /* optional task handle to create */ + ) == pdPASS) + { + taskId = (osaTaskId_t)task_handler; + } + return taskId; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TaskDestroy + * Description : This function destroy a task. + * Param[in] :taskId - Thread handle. + * Return osaStatus_Success if the task is destroied, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_TaskDestroy(osaTaskId_t taskId) +{ + osaStatus_t status; + uint16_t oldPriority; + /*Change priority to avoid context switches*/ + oldPriority = OSA_TaskGetPriority(OSA_TaskGetId()); + (void)OSA_TaskSetPriority(OSA_TaskGetId(), OSA_PRIORITY_REAL_TIME); +#if INCLUDE_vTaskDelete /* vTaskDelete() enabled */ + vTaskDelete((task_handler_t)taskId); + status = osaStatus_Success; +#else + status = osaStatus_Error; /* vTaskDelete() not available */ +#endif + (void)OSA_TaskSetPriority(OSA_TaskGetId(), oldPriority); + + return status; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeDelay + * Description : This function is used to suspend the active thread for the given number of milliseconds. + * + *END**************************************************************************/ +void OSA_TimeDelay(uint32_t millisec) +{ + vTaskDelay(millisecToTicks(millisec)); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeGetMsec + * Description : This function gets current time in milliseconds. + * + *END**************************************************************************/ +uint32_t OSA_TimeGetMsec(void) +{ + portTickType ticks; + + if (__get_IPSR()) + { + ticks = xTaskGetTickCountFromISR(); + } + else + { + ticks = xTaskGetTickCount(); + } + + return TICKS_TO_MSEC(ticks); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreCreate + * Description : This function is used to create a semaphore. + * Return : Semaphore handle of the new semaphore, or NULL if failed. + * + *END**************************************************************************/ +osaSemaphoreId_t OSA_SemaphoreCreate(uint32_t initValue) +{ +#if osNumberOfSemaphores + semaphore_t sem; + sem = xSemaphoreCreateCounting(0xFF, initValue); + return (osaSemaphoreId_t)sem; +#else + (void)initValue; + return NULL; +#endif + +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreDestroy + * Description : This function is used to destroy a semaphore. + * Return : osaStatus_Success if the semaphore is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreDestroy(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + semaphore_t sem = (semaphore_t)semId; + if(sem == NULL) + { + return osaStatus_Error; + } + vSemaphoreDelete(sem); + return osaStatus_Success; +#else + (void)semId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphoreWait + * Description : This function checks the semaphore's counting value, if it is + * positive, decreases it and returns osaStatus_Success, otherwise, timeout + * will be used for wait. The parameter timeout indicates how long should wait + * in milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will + * return osaStatus_Timeout immediately if semaphore is not positive. + * This function returns osaStatus_Success if the semaphore is received, returns + * osaStatus_Timeout if the semaphore is not received within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec) +{ +#if osNumberOfSemaphores + uint32_t timeoutTicks; + if(semId == NULL) + { + return osaStatus_Error; + } + semaphore_t sem = (semaphore_t)semId; + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + + if (xSemaphoreTake(sem, timeoutTicks)==pdFALSE) + { + return osaStatus_Timeout; /* timeout */ + } + else + { + return osaStatus_Success; /* semaphore taken */ + } +#else + (void)semId; + (void)millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_SemaphorePost + * Description : This function is used to wake up one task that wating on the + * semaphore. If no task is waiting, increase the semaphore. The function returns + * osaStatus_Success if the semaphre is post successfully, otherwise returns + * osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_SemaphorePost(osaSemaphoreId_t semId) +{ +#if osNumberOfSemaphores + osaStatus_t status = osaStatus_Error; + if(semId) + { + semaphore_t sem = (semaphore_t)semId; + + if (__get_IPSR()) + { + portBASE_TYPE taskToWake = pdFALSE; + + if (pdTRUE==xSemaphoreGiveFromISR(sem, &taskToWake)) + { + if (pdTRUE == taskToWake) + { + portYIELD_FROM_ISR(taskToWake); + } + status = osaStatus_Success; + } + else + { + status = osaStatus_Error; + } + } + else + { + if (pdTRUE == xSemaphoreGive(sem)) + { + status = osaStatus_Success; /* sync object given */ + } + else + { + status = osaStatus_Error; + } + } + } + return status; +#else + (void)semId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexCreate + * Description : This function is used to create a mutex. + * Return : Mutex handle of the new mutex, or NULL if failed. + * + *END**************************************************************************/ +osaMutexId_t OSA_MutexCreate(void) +{ +#if osNumberOfMutexes + mutex_t mutex; + mutex = xSemaphoreCreateMutex(); + return (osaMutexId_t)mutex; +#else + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexLock + * Description : This function checks the mutex's status, if it is unlocked, + * lock it and returns osaStatus_Success, otherwise, wait for the mutex. + * This function returns osaStatus_Success if the mutex is obtained, returns + * osaStatus_Error if any errors occur during waiting. If the mutex has been + * locked, pass 0 as timeout will return osaStatus_Timeout immediately. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec) +{ +#if osNumberOfMutexes + uint32_t timeoutTicks; + mutex_t mutex = (mutex_t)mutexId; + if(mutexId == NULL) + { + return osaStatus_Error; + } + /* If pMutex has been locked by current task, return error. */ + if (xSemaphoreGetMutexHolder(mutex) == xTaskGetCurrentTaskHandle()) + { + return osaStatus_Error; + } + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + + if (xSemaphoreTake(mutex, timeoutTicks)==pdFALSE) + { + return osaStatus_Timeout; /* timeout */ + } + else + { + return osaStatus_Success; /* semaphore taken */ + } +#else + (void)mutexId; + (void)millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexUnlock + * Description : This function is used to unlock a mutex. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexUnlock(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + mutex_t mutex = (mutex_t)mutexId; + if(mutexId == NULL) + { + return osaStatus_Error; + } + /* If pMutex is not locked by current task, return error. */ + if (xSemaphoreGetMutexHolder(mutex) != xTaskGetCurrentTaskHandle()) + { + return osaStatus_Error; + } + + if (xSemaphoreGive(mutex)==pdPASS) + { + return osaStatus_Success; + } + else + { + return osaStatus_Error; + } +#else + (void)mutexId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MutexDestroy + * Description : This function is used to destroy a mutex. + * Return : osaStatus_Success if the lock object is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MutexDestroy(osaMutexId_t mutexId) +{ +#if osNumberOfMutexes + mutex_t mutex = (mutex_t)mutexId; + if(mutexId == NULL) + { + return osaStatus_Error; + } + vSemaphoreDelete(mutex); + return osaStatus_Success; +#else + (void)mutexId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventCreate + * Description : This function is used to create a event object. + * Return : Event handle of the new event, or NULL if failed. + * + *END**************************************************************************/ +osaEventId_t OSA_EventCreate(bool_t autoClear) +{ +#if osNumberOfEvents + osaEventId_t eventId; + osEventStruct_t* pEventStruct; + OSA_InterruptDisable(); + eventId = pEventStruct = osObjectAlloc(&osEventInfo); + OSA_InterruptEnable(); + if(eventId == NULL) + { + return NULL; + } + + pEventStruct->event.eventHandler = xEventGroupCreate(); + if (pEventStruct->event.eventHandler) + { + pEventStruct->event.autoClear = autoClear; + } + else + { + OSA_InterruptDisable(); + osObjectFree(&osEventInfo, eventId); + OSA_InterruptEnable(); + eventId = NULL; + } + return eventId; +#else + (void)autoClear; + return NULL; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventSet + * Description : Set one or more event flags of an event object. + * Return : osaStatus_Success if set successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventSet(osaEventId_t eventId, osaEventFlags_t flagsToSet) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + portBASE_TYPE taskToWake = pdFALSE; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + if (__get_IPSR()) + { + if (pdPASS != xEventGroupSetBitsFromISR(pEventStruct->event.eventHandler, (event_flags_t)flagsToSet, &taskToWake)) + { + panic(0,(uint32_t)OSA_EventSet,0,0); + return osaStatus_Error; + } + if (pdTRUE == taskToWake) + { + portYIELD_FROM_ISR(taskToWake); + } + } + else + { + xEventGroupSetBits(pEventStruct->event.eventHandler, (event_flags_t)flagsToSet); + } + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToSet; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventClear + * Description : Clear one or more event flags of an event object. + * Return :osaStatus_Success if clear successfully, osaStatus_Error if failed. + * + *END**************************************************************************/ +osaStatus_t OSA_EventClear(osaEventId_t eventId, osaEventFlags_t flagsToClear) +{ +#if osNumberOfEvents + + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + + if (__get_IPSR()) + { + xEventGroupClearBitsFromISR(pEventStruct->event.eventHandler, (event_flags_t)flagsToClear); + } + else + { + xEventGroupClearBits(pEventStruct->event.eventHandler, (event_flags_t)flagsToClear); + } + + return osaStatus_Success; +#else + (void)eventId; + (void)flagsToClear; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventWait + * Description : This function checks the event's status, if it meets the wait + * condition, return osaStatus_Success, otherwise, timeout will be used for + * wait. The parameter timeout indicates how long should wait in milliseconds. + * Pass osaWaitForever_c to wait indefinitely, pass 0 will return the value + * osaStatus_Timeout immediately if wait condition is not met. The event flags + * will be cleared if the event is auto clear mode. Flags that wakeup waiting + * task could be obtained from the parameter setFlags. + * This function returns osaStatus_Success if wait condition is met, returns + * osaStatus_Timeout if wait condition is not met within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_EventWait(osaEventId_t eventId, osaEventFlags_t flagsToWait, bool_t waitAll, uint32_t millisec, osaEventFlags_t *pSetFlags) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + BaseType_t clearMode; + uint32_t timeoutTicks; + event_flags_t flagsSave; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + + /* Clean FreeRTOS cotrol flags */ + flagsToWait = flagsToWait & 0x00FFFFFF; + + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = millisec/portTICK_PERIOD_MS; + } + + clearMode = (pEventStruct->event.autoClear) ? pdTRUE: pdFALSE; + + flagsSave = xEventGroupWaitBits(pEventStruct->event.eventHandler,(event_flags_t)flagsToWait,clearMode,(BaseType_t)waitAll,timeoutTicks); + + flagsSave &= (event_flags_t)flagsToWait; + if(pSetFlags) + { + *pSetFlags = (osaEventFlags_t)flagsSave; + } + + if (flagsSave) + { + return osaStatus_Success; + } + else + { + return osaStatus_Timeout; + } +#else + (void)eventId; + (void)flagsToWait; + (void)waitAll; + (void)millisec; + (void)pSetFlags; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EventDestroy + * Description : This function is used to destroy a event object. Return + * osaStatus_Success if the event object is destroyed successfully, otherwise + * return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_EventDestroy(osaEventId_t eventId) +{ +#if osNumberOfEvents + osEventStruct_t* pEventStruct; + if(osObjectIsAllocated(&osEventInfo, eventId) == FALSE) + { + return osaStatus_Error; + } + pEventStruct = (osEventStruct_t*)eventId; + if(pEventStruct->event.eventHandler == NULL) + { + return osaStatus_Error; + } + vEventGroupDelete(pEventStruct->event.eventHandler); + OSA_InterruptDisable(); + osObjectFree(&osEventInfo, eventId); + OSA_InterruptEnable(); + return osaStatus_Success; +#else + (void)eventId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQCreate + * Description : This function is used to create a message queue. + * Return : the handle to the message queue if create successfully, otherwise + * return NULL. + * + *END**************************************************************************/ +osaMsgQId_t OSA_MsgQCreate( uint32_t msgNo ) +{ +#if osNumberOfMessageQs + msg_queue_handler_t msg_queue_handler; + + /* Create the message queue where each element is a pointer to the message item. */ + msg_queue_handler = xQueueCreate(msgNo,sizeof(osaMsg_t)); + return (osaMsgQId_t)msg_queue_handler; +#else + (void)msgNo; + return NULL; +#endif +} + + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQPut + * Description : This function is used to put a message to a message queue. +* Return : osaStatus_Success if the message is put successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQPut(osaMsgQId_t msgQId, void* pMessage) +{ +#if osNumberOfMessageQs + msg_queue_handler_t handler; + osaStatus_t osaStatus; + if(msgQId == NULL) + { + return osaStatus_Error; + } + handler = (msg_queue_handler_t)msgQId; + { + if (__get_IPSR()) + { + portBASE_TYPE taskToWake = pdFALSE; + + if (pdTRUE == xQueueSendToBackFromISR(handler, pMessage, &taskToWake)) + { + if (pdTRUE == taskToWake) + { + portYIELD_FROM_ISR(taskToWake); + } + osaStatus = osaStatus_Success; + } + else + { + osaStatus = osaStatus_Error; + } + + } + else + { + osaStatus = (xQueueSendToBack(handler, pMessage, 0)== pdPASS)?(osaStatus_Success):(osaStatus_Error); + } + } + return osaStatus; +#else + (void)msgQId; + (void)pMessage; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQGet + * Description : This function checks the queue's status, if it is not empty, + * get message from it and return osaStatus_Success, otherwise, timeout will + * be used for wait. The parameter timeout indicates how long should wait in + * milliseconds. Pass osaWaitForever_c to wait indefinitely, pass 0 will return + * osaStatus_Timeout immediately if queue is empty. + * This function returns osaStatus_Success if message is got successfully, + * returns osaStatus_Timeout if message queue is empty within the specified + * 'timeout', returns osaStatus_Error if any errors occur during waiting. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, void *pMessage, uint32_t millisec) +{ +#if osNumberOfMessageQs + osaStatus_t osaStatus; + msg_queue_handler_t handler; + uint32_t timeoutTicks; + if( msgQId == NULL ) + { + return osaStatus_Error; + } + handler = (msg_queue_handler_t)msgQId; + if (millisec == osaWaitForever_c) + { + timeoutTicks = portMAX_DELAY; + } + else + { + timeoutTicks = MSEC_TO_TICK(millisec); + } + if (xQueueReceive(handler, pMessage, timeoutTicks)!=pdPASS) + { + osaStatus = osaStatus_Timeout; /* not able to send it to the queue? */ + } + else + { + osaStatus = osaStatus_Success; + } + return osaStatus; +#else + (void)msgQId; + (void)pMessage; + (void)millisec; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MsgQDestroy + * Description : This function is used to destroy the message queue. + * Return : osaStatus_Success if the message queue is destroyed successfully, otherwise return osaStatus_Error. + * + *END**************************************************************************/ +osaStatus_t OSA_MsgQDestroy(osaMsgQId_t msgQId) +{ +#if osNumberOfMessageQs + msg_queue_handler_t handler; + if(msgQId == NULL ) + { + return osaStatus_Error; + } + handler = (msg_queue_handler_t)msgQId; + vQueueDelete(handler); + return osaStatus_Success; +#else + (void)msgQId; + return osaStatus_Error; +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptEnable(void) +{ + if (__get_IPSR()) + { + if(g_base_priority_top) + { + g_base_priority_top--; + portCLEAR_INTERRUPT_MASK_FROM_ISR(g_base_priority_array[g_base_priority_top]); + } + + } + else + { + portEXIT_CRITICAL(); + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptDisable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptDisable(void) +{ + if (__get_IPSR()) + { + if(g_base_priority_top < OSA_MAX_ISR_CRITICAL_SECTION_DEPTH) + { + g_base_priority_array[g_base_priority_top] = portSET_INTERRUPT_MASK_FROM_ISR(); + g_base_priority_top++; + } + + } + else + { + portENTER_CRITICAL(); + } + +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestricted + * Description : Disable interrupts except high-priority ones + * + *END**************************************************************************/ +void OSA_InterruptEnableRestricted(uint32_t *pu8OldIntLevel) +{ + /* Disable interrupts for duration of this function */ + OSA_DisableIRQGlobal(); + + /* Store old priority level */ + *pu8OldIntLevel = __get_BASEPRI(); + + /* Update priority level, but only if it is a more restrictive value */ + __set_BASEPRI_MAX((3U << (8U - __NVIC_PRIO_BITS)) & 0xffU); + + /* Restore interrupts */ + OSA_EnableIRQGlobal(); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnableRestore + * Description : Restore interrupts that were previously restricted by a call + * to OSA_InterruptEnableRestricted + * + *END**************************************************************************/ +void OSA_InterruptEnableRestore(uint32_t *pu8OldIntLevel) +{ + // write value direct into register ARM to ARM, no translations required + __set_BASEPRI(*pu8OldIntLevel); +} + + +uint32_t gInterruptDisableCount = 0; +/*FUNCTION********************************************************************** + * + * Function Name : OSA_EnableIRQGlobal + * Description : enable interrupts using PRIMASK register. + * + *END**************************************************************************/ +void OSA_EnableIRQGlobal(void) +{ + if (gInterruptDisableCount > 0) + { + gInterruptDisableCount--; + + if (gInterruptDisableCount == 0) + { + __enable_irq(); + } + /* call core API to enable the global interrupt*/ + } +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_DisableIRQGlobal + * Description : disable interrupts using PRIMASK register. + * + *END**************************************************************************/ +void OSA_DisableIRQGlobal(void) +{ + /* call core API to disable the global interrupt*/ + __disable_irq(); + + /* update counter*/ + gInterruptDisableCount++; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InstallIntHandler + * Description : This function is used to install interrupt handler. + * + *END**************************************************************************/ +void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void)) +{ + +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_suppress = Pm138") +#endif + InstallIRQHandler((IRQn_Type)IRQNumber, (uint32_t)handler); +#if defined ( __IAR_SYSTEMS_ICC__ ) + _Pragma ("diag_remark = PM138") +#endif +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeInit + * Description : Empty + * + *END**************************************************************************/ +void OSA_TimeInit(void) +{ + +} + +/*! ********************************************************************************* +************************************************************************************* +* Private functions +************************************************************************************* +********************************************************************************** */ +OSA_TASK_DEFINE(startup_task, gMainThreadPriority_c, 1, gMainThreadStackSize_c, 0) ; +int main (void) +{ + /* Initialize MCU clock */ + hardware_init(); + OSA_TaskCreate(OSA_TASK(startup_task), NULL); + vTaskStartScheduler(); + + return 0; +} + +/*! ********************************************************************************* +* \brief Allocates a osObjectStruct_t block in the osObjectHeap array. +* \param[in] pointer to the object info struct. +* Object can be semaphore, mutex, message Queue, event +* \return Pointer to the allocated osObjectStruct_t, NULL if failed. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void* osObjectAlloc(const osObjectInfo_t* pOsObjectInfo) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++, pObj += pOsObjectInfo->objectStructSize) + { + if(((osObjStruct_t*)pObj)->inUse == 0) + { + ((osObjStruct_t*)pObj)->inUse = 1; + return (void*)pObj; + } + } + return NULL; +} +#endif + +/*! ********************************************************************************* +* \brief Verifies the object is valid and allocated in the osObjectHeap array. +* \param[in] the pointer to the object info struct. +* \param[in] the pointer to the object struct. +* Object can be semaphore, mutex, message Queue, event +* \return TRUE if the object is valid and allocated, FALSE otherwise +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static bool_t osObjectIsAllocated(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0 ; i < pOsObjectInfo->objNo ; i++ , pObj += pOsObjectInfo->objectStructSize) + { + if(pObj == pObjectStruct) + { + if(((osObjStruct_t*)pObj)->inUse) + { + return TRUE; + } + break; + } + } + return FALSE; +} +#endif + +/*! ********************************************************************************* +* \brief Frees an osObjectStruct_t block from the osObjectHeap array. +* \param[in] pointer to the object info struct. +* \param[in] Pointer to the allocated osObjectStruct_t to free. +* Object can be semaphore, mutex, message Queue, event +* \return none. +* +* \pre +* +* \post +* +* \remarks Function is unprotected from interrupts. +* +********************************************************************************** */ +#if osObjectAlloc_c +static void osObjectFree(const osObjectInfo_t* pOsObjectInfo, void* pObjectStruct) +{ + uint32_t i; + uint8_t* pObj = (uint8_t*)pOsObjectInfo->pHeap; + for( i=0; i < pOsObjectInfo->objNo; i++, pObj += pOsObjectInfo->objectStructSize ) + { + if(pObj == pObjectStruct) + { + ((osObjStruct_t*)pObj)->inUse = 0; + break; + } + } +} +#endif + +/*! ********************************************************************************* +* \brief FreeRTOS application malloc failed hook +* +* +* \remarks Function is called by FreeRTOS if there is not enough space in the +* heap for task stack allocation or for OS object allocation +* +********************************************************************************** */ +#if (configUSE_MALLOC_FAILED_HOOK==1) +void vApplicationMallocFailedHook (void) +{ + panic(0,(uint32_t)vApplicationMallocFailedHook,0,0); +} +#endif + diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Include/PDM.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Include/PDM.h new file mode 100755 index 00000000000..a1650ab86b7 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Include/PDM.h @@ -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 ***/ +/****************************************************************************/ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Library/libPDM.a b/third_party/nxp/K32W061DK6/middleware/wireless/framework/PDM/Library/libPDM.a new file mode 100755 index 0000000000000000000000000000000000000000..9c40aac91a52f5114fe13f7df55b0bf35b1f314f GIT binary patch literal 92286 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 =&_DvGwM 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 +#include +#include + +#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; +} +/*-----------------------------------------------------------*/ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Interface/Panic.h b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Interface/Panic.h new file mode 100755 index 00000000000..aa65ec716eb --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Interface/Panic.h @@ -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__ */ diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Source/Panic.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Source/Panic.c new file mode 100755 index 00000000000..8315b0c1a11 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Panic/Source/Panic.c @@ -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 diff --git a/third_party/nxp/K32W061DK6/middleware/wireless/framework/Reset/Reset.c b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Reset/Reset.c new file mode 100755 index 00000000000..9fa25ce27f6 --- /dev/null +++ b/third_party/nxp/K32W061DK6/middleware/wireless/framework/Reset/Reset.c @@ -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 ***************************************/