初始版本
This commit is contained in:
449
components/libraries/atomic/nrf_atomic.c
Normal file
449
components/libraries/atomic/nrf_atomic.c
Normal file
@@ -0,0 +1,449 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_atomic.h"
|
||||
|
||||
#ifndef NRF_ATOMIC_USE_BUILD_IN
|
||||
#if (defined(__GNUC__) && defined(WIN32))
|
||||
#define NRF_ATOMIC_USE_BUILD_IN 1
|
||||
#else
|
||||
#define NRF_ATOMIC_USE_BUILD_IN 0
|
||||
#endif
|
||||
#endif // NRF_ATOMIC_USE_BUILD_IN
|
||||
|
||||
#if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U))
|
||||
#define STREX_LDREX_PRESENT
|
||||
#else
|
||||
#include "app_util_platform.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if (NRF_ATOMIC_USE_BUILD_IN == 0) && defined(STREX_LDREX_PRESENT)
|
||||
#include "nrf_atomic_internal.h"
|
||||
#endif
|
||||
|
||||
uint32_t nrf_atomic_u32_fetch_store(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_exchange_n(p_data, value, __ATOMIC_SEQ_CST);
|
||||
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
NRF_ATOMIC_OP(mov, old_val, new_val, p_data, value);
|
||||
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return old_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
uint32_t old_val = *p_data;
|
||||
*p_data = value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return old_val;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_store(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
__atomic_store_n(p_data, value, __ATOMIC_SEQ_CST);
|
||||
return value;
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(mov, old_val, new_val, p_data, value);
|
||||
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return new_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
*p_data = value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return value;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_fetch_or(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_fetch_or(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(orr, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return old_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
uint32_t old_val = *p_data;
|
||||
*p_data |= value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return old_val;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_or(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_or_fetch(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(orr, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return new_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
*p_data |= value;
|
||||
uint32_t new_value = *p_data;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return new_value;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_fetch_and(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_fetch_and(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(and, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return old_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
uint32_t old_val = *p_data;
|
||||
*p_data &= value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return old_val;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_and(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_and_fetch(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(and, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return new_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
*p_data &= value;
|
||||
uint32_t new_value = *p_data;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return new_value;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_fetch_xor(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_fetch_xor(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(eor, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return old_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
uint32_t old_val = *p_data;
|
||||
*p_data ^= value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return old_val;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_xor(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_xor_fetch(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(eor, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return new_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
*p_data ^= value;
|
||||
uint32_t new_value = *p_data;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return new_value;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_fetch_add(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_fetch_add(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(add, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return old_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
uint32_t old_val = *p_data;
|
||||
*p_data += value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return old_val;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_add(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_add_fetch(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(add, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return new_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
*p_data += value;
|
||||
uint32_t new_value = *p_data;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return new_value;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_fetch_sub(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_fetch_sub(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(sub, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return old_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
uint32_t old_val = *p_data;
|
||||
*p_data -= value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return old_val;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_sub(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_sub_fetch(p_data, value, __ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(sub, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return new_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
*p_data -= value;
|
||||
uint32_t new_value = *p_data;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return new_value;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
bool nrf_atomic_u32_cmp_exch(nrf_atomic_u32_t * p_data,
|
||||
uint32_t * p_expected,
|
||||
uint32_t desired)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
return __atomic_compare_exchange(p_data,
|
||||
p_expected,
|
||||
&desired,
|
||||
1,
|
||||
__ATOMIC_SEQ_CST,
|
||||
__ATOMIC_SEQ_CST);
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
return nrf_atomic_internal_cmp_exch(p_data, p_expected, desired);
|
||||
#else
|
||||
bool ret;
|
||||
CRITICAL_REGION_ENTER();
|
||||
if (*p_data == *p_expected)
|
||||
{
|
||||
*p_data = desired;
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p_expected = *p_data;
|
||||
ret = false;
|
||||
}
|
||||
CRITICAL_REGION_EXIT();
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_fetch_sub_hs(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
uint32_t expected = *p_data;
|
||||
uint32_t new_val;
|
||||
bool success;
|
||||
|
||||
do
|
||||
{
|
||||
if (expected >= value)
|
||||
{
|
||||
new_val = expected - value;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_val = expected;
|
||||
}
|
||||
success = __atomic_compare_exchange(p_data,
|
||||
&expected,
|
||||
&new_val,
|
||||
1,
|
||||
__ATOMIC_SEQ_CST,
|
||||
__ATOMIC_SEQ_CST);
|
||||
} while(!success);
|
||||
return expected;
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return old_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
uint32_t old_val = *p_data;
|
||||
*p_data -= value;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return old_val;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_u32_sub_hs(nrf_atomic_u32_t * p_data, uint32_t value)
|
||||
{
|
||||
#if NRF_ATOMIC_USE_BUILD_IN
|
||||
uint32_t expected = *p_data;
|
||||
uint32_t new_val;
|
||||
bool success;
|
||||
|
||||
do
|
||||
{
|
||||
if (expected >= value)
|
||||
{
|
||||
new_val = expected - value;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_val = expected;
|
||||
}
|
||||
success = __atomic_compare_exchange(p_data,
|
||||
&expected,
|
||||
&new_val,
|
||||
1,
|
||||
__ATOMIC_SEQ_CST,
|
||||
__ATOMIC_SEQ_CST);
|
||||
} while(!success);
|
||||
return new_val;
|
||||
#elif defined(STREX_LDREX_PRESENT)
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
|
||||
NRF_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
|
||||
UNUSED_PARAMETER(old_val);
|
||||
UNUSED_PARAMETER(new_val);
|
||||
return new_val;
|
||||
#else
|
||||
CRITICAL_REGION_ENTER();
|
||||
*p_data -= value;
|
||||
uint32_t new_value = *p_data;
|
||||
CRITICAL_REGION_EXIT();
|
||||
return new_value;
|
||||
#endif //NRF_ATOMIC_USE_BUILD_IN
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_flag_set_fetch(nrf_atomic_flag_t * p_data)
|
||||
{
|
||||
return nrf_atomic_u32_fetch_or(p_data, 1);
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_flag_set(nrf_atomic_flag_t * p_data)
|
||||
{
|
||||
return nrf_atomic_u32_or(p_data, 1);
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_flag_clear_fetch(nrf_atomic_flag_t * p_data)
|
||||
{
|
||||
return nrf_atomic_u32_fetch_and(p_data, 0);
|
||||
}
|
||||
|
||||
uint32_t nrf_atomic_flag_clear(nrf_atomic_flag_t * p_data)
|
||||
{
|
||||
return nrf_atomic_u32_and(p_data, 0);
|
||||
}
|
||||
|
||||
274
components/libraries/atomic/nrf_atomic.h
Normal file
274
components/libraries/atomic/nrf_atomic.h
Normal file
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_atomic Atomic operations API
|
||||
* @ingroup app_common
|
||||
* @{
|
||||
*
|
||||
* @brief @tagAPI52 This module implements C11 stdatomic.h simplified API.
|
||||
At this point only Cortex-M3/M4 cores are supported (LDREX/STREX instructions).
|
||||
* Atomic types are limited to @ref nrf_atomic_u32_t and @ref nrf_atomic_flag_t.
|
||||
*/
|
||||
|
||||
#ifndef NRF_ATOMIC_H__
|
||||
#define NRF_ATOMIC_H__
|
||||
|
||||
#include "sdk_common.h"
|
||||
|
||||
/**
|
||||
* @brief Atomic 32 bit unsigned type
|
||||
* */
|
||||
typedef volatile uint32_t nrf_atomic_u32_t;
|
||||
|
||||
/**
|
||||
* @brief Atomic 1 bit flag type (technically 32 bit)
|
||||
* */
|
||||
typedef volatile uint32_t nrf_atomic_flag_t;
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Stores value to an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value to store
|
||||
*
|
||||
* @return Old value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_fetch_store(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Stores value to an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value to store
|
||||
*
|
||||
* @return New value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_store(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Logical OR operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand OR operation
|
||||
*
|
||||
* @return Old value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_fetch_or(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Logical OR operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand OR operation
|
||||
*
|
||||
* @return New value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_or(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Logical AND operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand AND operation
|
||||
*
|
||||
* @return Old value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_fetch_and(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Logical AND operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand AND operation
|
||||
*
|
||||
* @return New value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_and(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Logical XOR operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand XOR operation
|
||||
*
|
||||
* @return Old value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_fetch_xor(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Logical XOR operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand XOR operation
|
||||
*
|
||||
* @return New value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_xor(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Arithmetic ADD operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand ADD operation
|
||||
*
|
||||
* @return Old value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_fetch_add(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Arithmetic ADD operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand ADD operation
|
||||
*
|
||||
* @return New value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_add(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Arithmetic SUB operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand SUB operation
|
||||
*
|
||||
* @return Old value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_fetch_sub(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Arithmetic SUB operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand SUB operation
|
||||
*
|
||||
* @return New value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_sub(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief If value at pointer is equal to expected value, changes value at pointer to desired
|
||||
*
|
||||
* Atomically compares the value pointed to by p_data with the value pointed to by p_expected,
|
||||
* and if those are equal, replaces the former with desired. Otherwise, loads the actual value
|
||||
* pointed to by p_data into *p_expected.
|
||||
*
|
||||
* @param p_data Atomic memory pointer to test and modify.
|
||||
* @param p_expected Pointer to test value.
|
||||
* @param desired Value to be stored to atomic memory.
|
||||
*
|
||||
* @retval true *p_data was equal to *p_expected
|
||||
* @retval false *p_data was not equal to *p_expected
|
||||
*/
|
||||
bool nrf_atomic_u32_cmp_exch(nrf_atomic_u32_t * p_data,
|
||||
uint32_t * p_expected,
|
||||
uint32_t desired);
|
||||
|
||||
/**
|
||||
* @brief Arithmetic SUB operation on an atomic object performed if object >= value.
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand SUB operation
|
||||
*
|
||||
* @return Old value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_fetch_sub_hs(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Arithmetic SUB operation on an atomic object performed if object >= value.
|
||||
*
|
||||
* @param[in] p_data Atomic memory pointer
|
||||
* @param[in] value Value of second operand SUB operation
|
||||
*
|
||||
* @return New value stored into atomic object
|
||||
* */
|
||||
uint32_t nrf_atomic_u32_sub_hs(nrf_atomic_u32_t * p_data, uint32_t value);
|
||||
|
||||
/**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Logic one bit flag set operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic flag memory pointer
|
||||
*
|
||||
* @return Old flag value
|
||||
* */
|
||||
uint32_t nrf_atomic_flag_set_fetch(nrf_atomic_flag_t * p_data);
|
||||
|
||||
/**
|
||||
* @brief Logic one bit flag set operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic flag memory pointer
|
||||
*
|
||||
* @return New flag value
|
||||
* */
|
||||
uint32_t nrf_atomic_flag_set(nrf_atomic_flag_t * p_data);
|
||||
|
||||
/**
|
||||
* @brief Logic one bit flag clear operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic flag memory pointer
|
||||
*
|
||||
* @return Old flag value
|
||||
* */
|
||||
uint32_t nrf_atomic_flag_clear_fetch(nrf_atomic_flag_t * p_data);
|
||||
|
||||
/**
|
||||
* @brief Logic one bit flag clear operation on an atomic object
|
||||
*
|
||||
* @param[in] p_data Atomic flag memory pointer
|
||||
*
|
||||
* @return New flag value
|
||||
* */
|
||||
uint32_t nrf_atomic_flag_clear(nrf_atomic_flag_t * p_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_ATOMIC_H__ */
|
||||
|
||||
/** @} */
|
||||
343
components/libraries/atomic/nrf_atomic_internal.h
Normal file
343
components/libraries/atomic/nrf_atomic_internal.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_ATOMIC_INTERNAL_H__
|
||||
#define NRF_ATOMIC_INTERNAL_H__
|
||||
|
||||
#include "sdk_common.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @defgroup nrf_atomic_internal Atomic operations internals
|
||||
* @ingroup nrf_atomic
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/* Only Cortex M cores > 3 support LDREX/STREX instructions*/
|
||||
#if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U)) == 0
|
||||
#error "Unsupported core version"
|
||||
#endif
|
||||
|
||||
#if defined ( __CC_ARM )
|
||||
static __asm uint32_t nrf_atomic_internal_mov(nrf_atomic_u32_t * p_ptr,
|
||||
uint32_t value,
|
||||
uint32_t * p_new)
|
||||
{
|
||||
/* The base standard provides for passing arguments in core registers (r0-r3) and on the stack.
|
||||
* Registers r4 and r5 have to be saved on stack. Note that only even number of register push are
|
||||
* allowed. This is a requirement of the Procedure Call Standard for the ARM Architecture [AAPCS].
|
||||
* */
|
||||
push {r4, r5}
|
||||
mov r4, r0
|
||||
|
||||
loop_mov
|
||||
ldrex r0, [r4]
|
||||
mov r5, r1
|
||||
strex r3, r5, [r4]
|
||||
cmp r3, #0
|
||||
bne loop_mov
|
||||
|
||||
str r5, [r2]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
static __asm uint32_t nrf_atomic_internal_orr(nrf_atomic_u32_t * p_ptr,
|
||||
uint32_t value,
|
||||
uint32_t * p_new)
|
||||
{
|
||||
push {r4, r5}
|
||||
mov r4, r0
|
||||
|
||||
loop_orr
|
||||
ldrex r0, [r4]
|
||||
orr r5, r0, r1
|
||||
strex r3, r5, [r4]
|
||||
cmp r3, #0
|
||||
bne loop_orr
|
||||
|
||||
str r5, [r2]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
static __asm uint32_t nrf_atomic_internal_and(nrf_atomic_u32_t * p_ptr,
|
||||
uint32_t value,
|
||||
uint32_t * p_new)
|
||||
{
|
||||
push {r4, r5}
|
||||
mov r4, r0
|
||||
|
||||
loop_and
|
||||
ldrex r0, [r4]
|
||||
and r5, r0, r1
|
||||
strex r3, r5, [r4]
|
||||
cmp r3, #0
|
||||
bne loop_and
|
||||
|
||||
str r5, [r2]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
static __asm uint32_t nrf_atomic_internal_eor(nrf_atomic_u32_t * p_ptr,
|
||||
uint32_t value,
|
||||
uint32_t * p_new)
|
||||
{
|
||||
push {r4, r5}
|
||||
mov r4, r0
|
||||
|
||||
loop_eor
|
||||
ldrex r0, [r4]
|
||||
eor r5, r0, r1
|
||||
strex r3, r5, [r4]
|
||||
cmp r3, #0
|
||||
bne loop_eor
|
||||
|
||||
str r5, [r2]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
static __asm uint32_t nrf_atomic_internal_add(nrf_atomic_u32_t * p_ptr,
|
||||
uint32_t value,
|
||||
uint32_t * p_new)
|
||||
{
|
||||
push {r4, r5}
|
||||
mov r4, r0
|
||||
|
||||
loop_add
|
||||
ldrex r0, [r4]
|
||||
add r5, r0, r1
|
||||
strex r3, r5, [r4]
|
||||
cmp r3, #0
|
||||
bne loop_add
|
||||
|
||||
str r5, [r2]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
static __asm uint32_t nrf_atomic_internal_sub(nrf_atomic_u32_t * p_ptr,
|
||||
uint32_t value,
|
||||
uint32_t * p_new)
|
||||
{
|
||||
push {r4, r5}
|
||||
mov r4, r0
|
||||
|
||||
loop_sub
|
||||
ldrex r0, [r4]
|
||||
sub r5, r0, r1
|
||||
strex r3, r5, [r4]
|
||||
cmp r3, #0
|
||||
bne loop_sub
|
||||
|
||||
str r5, [r2]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
static __asm bool nrf_atomic_internal_cmp_exch(nrf_atomic_u32_t * p_data,
|
||||
uint32_t * p_expected,
|
||||
uint32_t value)
|
||||
{
|
||||
#define RET_REG r0
|
||||
#define P_EXPC r1
|
||||
#define VALUE r2
|
||||
#define STR_RES r3
|
||||
#define P_DATA r4
|
||||
#define EXPC_VAL r5
|
||||
#define ACT_VAL r6
|
||||
|
||||
push {r4-r6}
|
||||
mov P_DATA, r0
|
||||
mov RET_REG, #0
|
||||
|
||||
loop_cmp_exch
|
||||
ldrex ACT_VAL, [P_DATA]
|
||||
ldr EXPC_VAL, [P_EXPC]
|
||||
cmp ACT_VAL, EXPC_VAL
|
||||
ittee eq
|
||||
strexeq STR_RES, VALUE, [P_DATA]
|
||||
moveq RET_REG, #1
|
||||
strexne STR_RES, ACT_VAL, [P_DATA]
|
||||
strne ACT_VAL, [P_EXPC]
|
||||
cmp STR_RES, #0
|
||||
itt ne
|
||||
movne RET_REG, #0
|
||||
bne loop_cmp_exch
|
||||
|
||||
pop {r4-r6}
|
||||
bx lr
|
||||
|
||||
#undef RET_REG
|
||||
#undef P_EXPC
|
||||
#undef VALUE
|
||||
#undef STR_RES
|
||||
#undef P_DATA
|
||||
#undef EXPC_VAL
|
||||
#undef ACT_VAL
|
||||
}
|
||||
|
||||
static __asm uint32_t nrf_atomic_internal_sub_hs(nrf_atomic_u32_t * p_ptr,
|
||||
uint32_t value,
|
||||
uint32_t * p_new)
|
||||
{
|
||||
push {r4, r5}
|
||||
mov r4, r0
|
||||
|
||||
loop_sub_ge
|
||||
ldrex r0, [r4]
|
||||
cmp r0, r1
|
||||
ite hs
|
||||
subhs r5, r0, r1
|
||||
movlo r5, r0
|
||||
strex r3, r5, [r4]
|
||||
cmp r3, #0
|
||||
bne loop_sub_ge
|
||||
|
||||
str r5, [r2]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
#define NRF_ATOMIC_OP(asm_op, old_val, new_val, ptr, value) \
|
||||
old_val = nrf_atomic_internal_##asm_op(ptr, value, &new_val)
|
||||
|
||||
#elif defined ( __ICCARM__ ) || defined ( __GNUC__ )
|
||||
|
||||
/**
|
||||
* @brief Atomic operation generic macro
|
||||
* @param[in] asm_op operation: mov, orr, and, eor, add, sub
|
||||
* @param[out] old_val atomic object output (uint32_t), value before operation
|
||||
* @param[out] new_val atomic object output (uint32_t), value after operation
|
||||
* @param[in] value atomic operation operand
|
||||
* */
|
||||
#define NRF_ATOMIC_OP(asm_op, old_val, new_val, ptr, value) \
|
||||
{ \
|
||||
uint32_t str_res; \
|
||||
__ASM volatile( \
|
||||
"1: ldrex %["#old_val"], [%["#ptr"]]\n" \
|
||||
NRF_ATOMIC_OP_##asm_op(new_val, old_val, value) \
|
||||
" strex %[str_res], %["#new_val"], [%["#ptr"]]\n" \
|
||||
" teq %[str_res], #0\n" \
|
||||
" bne.n 1b" \
|
||||
: \
|
||||
[old_val]"=&r" (old_val), \
|
||||
[new_val]"=&r" (new_val), \
|
||||
[str_res]"=&r" (str_res) \
|
||||
: \
|
||||
[ptr]"r" (ptr), \
|
||||
[value]"r" (value) \
|
||||
: "cc"); \
|
||||
UNUSED_PARAMETER(str_res); \
|
||||
}
|
||||
|
||||
#define NRF_ATOMIC_OP_mov(new_val, old_val, value) "mov %["#new_val"], %["#value"]\n"
|
||||
#define NRF_ATOMIC_OP_orr(new_val, old_val, value) "orr %["#new_val"], %["#old_val"], %["#value"]\n"
|
||||
#define NRF_ATOMIC_OP_and(new_val, old_val, value) "and %["#new_val"], %["#old_val"], %["#value"]\n"
|
||||
#define NRF_ATOMIC_OP_eor(new_val, old_val, value) "eor %["#new_val"], %["#old_val"], %["#value"]\n"
|
||||
#define NRF_ATOMIC_OP_add(new_val, old_val, value) "add %["#new_val"], %["#old_val"], %["#value"]\n"
|
||||
#define NRF_ATOMIC_OP_sub(new_val, old_val, value) "sub %["#new_val"], %["#old_val"], %["#value"]\n"
|
||||
#define NRF_ATOMIC_OP_sub_hs(new_val, old_val, value) \
|
||||
"cmp %["#old_val"], %["#value"]\n " \
|
||||
"ite hs\n" \
|
||||
"subhs %["#new_val"], %["#old_val"], %["#value"]\n" \
|
||||
"movlo %["#new_val"], %["#old_val"]\n"
|
||||
|
||||
static inline bool nrf_atomic_internal_cmp_exch(nrf_atomic_u32_t * p_data,
|
||||
uint32_t * p_expected,
|
||||
uint32_t value)
|
||||
{
|
||||
bool res = false;
|
||||
uint32_t str_res = 0;
|
||||
uint32_t act_val = 0;
|
||||
uint32_t exp_val = 0;
|
||||
UNUSED_VARIABLE(str_res);
|
||||
UNUSED_VARIABLE(act_val);
|
||||
UNUSED_VARIABLE(exp_val);
|
||||
__ASM volatile(
|
||||
"1: ldrex %[act_val], [%[ptr]]\n"
|
||||
" ldr %[exp_val], [%[expc]]\n"
|
||||
" cmp %[act_val], %[exp_val]\n"
|
||||
" ittee eq\n"
|
||||
" strexeq %[str_res], %[value], [%[ptr]]\n"
|
||||
" moveq %[res], #1\n"
|
||||
" strexne %[str_res], %[act_val], [%[ptr]]\n"
|
||||
" strne %[act_val], [%[expc]]\n"
|
||||
" cmp %[str_res], #0\n"
|
||||
" itt ne\n"
|
||||
" movne %[res], #0\n"
|
||||
" bne.n 1b"
|
||||
:
|
||||
[res] "=&r" (res),
|
||||
[exp_val] "=&r" (exp_val),
|
||||
[act_val] "=&r" (act_val),
|
||||
[str_res] "=&r" (str_res)
|
||||
:
|
||||
"0" (res),
|
||||
"1" (exp_val),
|
||||
"2" (act_val),
|
||||
[expc] "r" (p_expected),
|
||||
[ptr] "r" (p_data),
|
||||
[value] "r" (value)
|
||||
: "cc");
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Unsupported compiler"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_ATOMIC_INTERNAL_H__ */
|
||||
|
||||
/** @} */
|
||||
153
components/libraries/atomic/nrf_atomic_sanity_check.h
Normal file
153
components/libraries/atomic/nrf_atomic_sanity_check.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_ATOMIC_SANITY_CHECK_H__
|
||||
#define NRF_ATOMIC_SANITY_CHECK_H__
|
||||
|
||||
#include "nrf_atomic.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Quick sanity check of nrf_atomic API
|
||||
* */
|
||||
static inline void nrf_atomic_sanity_check(void)
|
||||
{
|
||||
#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER)
|
||||
nrf_atomic_u32_t val;
|
||||
nrf_atomic_u32_t flag;
|
||||
|
||||
/*Fetch version tests*/
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_store_fetch(&val, 10) == 0);
|
||||
ASSERT(nrf_atomic_u32_store_fetch(&val, 0) == 10);
|
||||
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_or_fetch(&val, 1 << 16) == 0);
|
||||
ASSERT(nrf_atomic_u32_or_fetch(&val, 1 << 5) == ((1 << 16)));
|
||||
ASSERT(nrf_atomic_u32_or_fetch(&val, 1 << 5) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_or_fetch(&val, 0) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_or_fetch(&val, 0xFFFFFFFF) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_or_fetch(&val, 0xFFFFFFFF) == (0xFFFFFFFF));
|
||||
|
||||
val = 0xFFFFFFFF;
|
||||
ASSERT(nrf_atomic_u32_and_fetch(&val, ~(1 << 16)) == 0xFFFFFFFF);
|
||||
ASSERT(nrf_atomic_u32_and_fetch(&val, ~(1 << 5)) == (0xFFFFFFFF & ~((1 << 16))));
|
||||
ASSERT(nrf_atomic_u32_and_fetch(&val, 0) == (0xFFFFFFFF & ~(((1 << 16) | (1 << 5)))));
|
||||
ASSERT(nrf_atomic_u32_and_fetch(&val, 0xFFFFFFFF) == (0));
|
||||
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_xor_fetch(&val, (1 << 16)) == 0);
|
||||
ASSERT(nrf_atomic_u32_xor_fetch(&val, (1 << 5)) == ((1 << 16)));
|
||||
ASSERT(nrf_atomic_u32_xor_fetch(&val, 0) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_xor_fetch(&val, (1 << 16) | (1 << 5)) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_xor_fetch(&val, 0) == (0));
|
||||
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_add_fetch(&val, 100) == 0);
|
||||
ASSERT(nrf_atomic_u32_add_fetch(&val, 100) == 100);
|
||||
ASSERT(nrf_atomic_u32_add_fetch(&val, 1 << 24) == 200);
|
||||
ASSERT(nrf_atomic_u32_add_fetch(&val, 0) == (200 + (1 << 24)));
|
||||
ASSERT(nrf_atomic_u32_add_fetch(&val, 0xFFFFFFFF) == (200 + (1 << 24)));
|
||||
ASSERT(nrf_atomic_u32_add_fetch(&val, 0) == (200 - 1 + (1 << 24)));
|
||||
|
||||
val = 1000;
|
||||
ASSERT(nrf_atomic_u32_sub_fetch(&val, 100) == 1000);
|
||||
ASSERT(nrf_atomic_u32_sub_fetch(&val, 100) == 900);
|
||||
ASSERT(nrf_atomic_u32_sub_fetch(&val, 0) == 800);
|
||||
ASSERT(nrf_atomic_u32_sub_fetch(&val, 0xFFFFFFFF) == 800);
|
||||
ASSERT(nrf_atomic_u32_sub_fetch(&val, 0) == 801);
|
||||
|
||||
flag = 0;
|
||||
ASSERT(nrf_atomic_flag_set_fetch(&flag) == 0);
|
||||
ASSERT(nrf_atomic_flag_set_fetch(&flag) == 1);
|
||||
ASSERT(nrf_atomic_flag_clear_fetch(&flag) == 1);
|
||||
ASSERT(nrf_atomic_flag_clear_fetch(&flag) == 0);
|
||||
|
||||
/*No fetch version tests*/
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_store(&val, 10) == 10);
|
||||
ASSERT(nrf_atomic_u32_store(&val, 0) == 0);
|
||||
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_or(&val, 1 << 16) == 1 << 16);
|
||||
ASSERT(nrf_atomic_u32_or(&val, 1 << 5) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_or(&val, 1 << 5) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_or(&val, 0) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_or(&val, 0xFFFFFFFF) == 0xFFFFFFFF);
|
||||
|
||||
val = 0xFFFFFFFF;
|
||||
ASSERT(nrf_atomic_u32_and(&val, ~(1 << 16)) == (0xFFFFFFFF & ~((1 << 16))));
|
||||
ASSERT(nrf_atomic_u32_and(&val, ~(1 << 5)) == (0xFFFFFFFF & ~(((1 << 16) | (1 << 5)))));
|
||||
ASSERT(nrf_atomic_u32_and(&val, 0) == 0);
|
||||
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_xor(&val, (1 << 16)) == ((1 << 16)));
|
||||
ASSERT(nrf_atomic_u32_xor(&val, (1 << 5)) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_xor(&val, 0) == ((1 << 16) | (1 << 5)));
|
||||
ASSERT(nrf_atomic_u32_xor(&val, (1 << 16) | (1 << 5)) == 0);
|
||||
|
||||
val = 0;
|
||||
ASSERT(nrf_atomic_u32_add(&val, 100) == 100);
|
||||
ASSERT(nrf_atomic_u32_add(&val, 100) == 200);
|
||||
ASSERT(nrf_atomic_u32_add(&val, 1 << 24) == (200 + (1 << 24)));
|
||||
ASSERT(nrf_atomic_u32_add(&val, 0) == (200 + (1 << 24)));
|
||||
ASSERT(nrf_atomic_u32_add(&val, 0xFFFFFFFF) == (200 - 1 + (1 << 24)));
|
||||
|
||||
val = 1000;
|
||||
ASSERT(nrf_atomic_u32_sub(&val, 100) == 900);
|
||||
ASSERT(nrf_atomic_u32_sub(&val, 100) == 800);
|
||||
ASSERT(nrf_atomic_u32_sub(&val, 0) == 800);
|
||||
ASSERT(nrf_atomic_u32_sub(&val, 0xFFFFFFFF) == 801);
|
||||
|
||||
flag = 0;
|
||||
ASSERT(nrf_atomic_flag_set(&flag) == 1);
|
||||
ASSERT(nrf_atomic_flag_set(&flag) == 1);
|
||||
ASSERT(nrf_atomic_flag_clear(&flag) == 0);
|
||||
ASSERT(nrf_atomic_flag_clear(&flag) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_ATOMIC_SANITY_CHECK_H__ */
|
||||
189
components/libraries/atomic_fifo/nrf_atfifo.c
Normal file
189
components/libraries/atomic_fifo/nrf_atfifo.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* Copyright (c) 2011 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "app_util.h"
|
||||
#include "nrf_atfifo.h"
|
||||
#include "nrf_atfifo_internal.h"
|
||||
|
||||
#if NRF_ATFIFO_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_ATFIFO_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INIT_FILTER_LEVEL NRF_ATFIFO_CONFIG_LOG_INIT_FILTER_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_ATFIFO_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_ATFIFO_CONFIG_DEBUG_COLOR
|
||||
#else
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif // NRF_ATFIFO_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
|
||||
/* Unions testing */
|
||||
STATIC_ASSERT(sizeof(nrf_atfifo_postag_t) == sizeof(uint32_t));
|
||||
|
||||
|
||||
ret_code_t nrf_atfifo_init(nrf_atfifo_t * const p_fifo, void * p_buf, uint16_t buf_size, uint16_t item_size)
|
||||
{
|
||||
if (NULL == p_buf)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_fifo->p_log, "Initialization failed. p_buf == NULL");
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
if (0 != (buf_size % item_size))
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_fifo->p_log, "Initialization failed. Buf_size not multiple of item_size");
|
||||
return NRF_ERROR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
p_fifo->p_buf = p_buf;
|
||||
p_fifo->tail.tag = 0;
|
||||
p_fifo->head.tag = 0;
|
||||
p_fifo->buf_size = buf_size;
|
||||
p_fifo->item_size = item_size;
|
||||
|
||||
NRF_LOG_INST_INFO(p_fifo->p_log, "Initialized.");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_atfifo_clear(nrf_atfifo_t * const p_fifo)
|
||||
{
|
||||
bool released = nrf_atfifo_space_clear(p_fifo);
|
||||
NRF_LOG_INST_INFO(p_fifo->p_log, "Cleared result:%s", released ? "success" : "busy");
|
||||
return released ? NRF_SUCCESS : NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_atfifo_alloc_put(nrf_atfifo_t * const p_fifo, void const * p_var, size_t size, bool * const p_visible)
|
||||
{
|
||||
nrf_atfifo_item_put_t context;
|
||||
bool visible;
|
||||
void * p_data = nrf_atfifo_item_alloc(p_fifo, &context);
|
||||
if (NULL == p_data)
|
||||
{
|
||||
NRF_LOG_INST_WARNING(p_fifo->p_log, "Copying in element (0x%08X) failed - no space.", p_var);
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
memcpy(p_data, p_var, size);
|
||||
|
||||
visible = nrf_atfifo_item_put(p_fifo, &context);
|
||||
if (NULL != p_visible)
|
||||
{
|
||||
*p_visible = visible;
|
||||
}
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Element (0x%08X) copied in.", p_var);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void * nrf_atfifo_item_alloc(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_put_t * p_context)
|
||||
{
|
||||
if (nrf_atfifo_wspace_req(p_fifo, &(p_context->last_tail)))
|
||||
{
|
||||
void * p_item = ((uint8_t*)(p_fifo->p_buf)) + p_context->last_tail.pos.wr;
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Allocated element (0x%08X).", p_item);
|
||||
return p_item;
|
||||
}
|
||||
NRF_LOG_INST_WARNING(p_fifo->p_log, "Allocation failed - no space.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool nrf_atfifo_item_put(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_put_t * p_context)
|
||||
{
|
||||
if ((p_context->last_tail.pos.wr) == (p_context->last_tail.pos.rd))
|
||||
{
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Put (uninterrupted)");
|
||||
nrf_atfifo_wspace_close(p_fifo);
|
||||
return true;
|
||||
}
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Put (interrupted!)");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_atfifo_get_free(nrf_atfifo_t * const p_fifo, void * const p_var, size_t size, bool * p_released)
|
||||
{
|
||||
nrf_atfifo_item_get_t context;
|
||||
bool released;
|
||||
void const * p_s = nrf_atfifo_item_get(p_fifo, &context);
|
||||
if (NULL == p_s)
|
||||
{
|
||||
NRF_LOG_INST_WARNING(p_fifo->p_log, "Copying out failed - no item in the FIFO.");
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
memcpy(p_var, p_s, size);
|
||||
|
||||
released = nrf_atfifo_item_free(p_fifo, &context);
|
||||
if (NULL != p_released)
|
||||
{
|
||||
*p_released = released;
|
||||
}
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Element (0x%08X) copied out.", p_var);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void * nrf_atfifo_item_get(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_get_t * p_context)
|
||||
{
|
||||
if (nrf_atfifo_rspace_req(p_fifo, &(p_context->last_head)))
|
||||
{
|
||||
void * p_item = ((uint8_t*)(p_fifo->p_buf)) + p_context->last_head.pos.rd;
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Get element: 0x%08X", p_item);
|
||||
return p_item;
|
||||
}
|
||||
NRF_LOG_INST_WARNING(p_fifo->p_log, "Get failed - no item in the FIFO.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool nrf_atfifo_item_free(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_get_t * p_context)
|
||||
{
|
||||
if ((p_context->last_head.pos.wr) == (p_context->last_head.pos.rd))
|
||||
{
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Free (uninterrupted)");
|
||||
nrf_atfifo_rspace_close(p_fifo);
|
||||
return true;
|
||||
}
|
||||
NRF_LOG_INST_DEBUG(p_fifo->p_log, "Free (interrupted)");
|
||||
return false;
|
||||
}
|
||||
424
components/libraries/atomic_fifo/nrf_atfifo.h
Normal file
424
components/libraries/atomic_fifo/nrf_atfifo.h
Normal file
@@ -0,0 +1,424 @@
|
||||
/**
|
||||
* Copyright (c) 2011 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_ATFIFO_H__
|
||||
#define NRF_ATFIFO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdk_config.h"
|
||||
#include "nordic_common.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf_log_instance.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup nrf_atfifo Atomic FIFO
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief @tagAPI52 FIFO implementation that allows for making atomic transactions without
|
||||
* locking interrupts.
|
||||
*
|
||||
* @details There are two types of functions to prepare the FIFO writing:
|
||||
* - Single function for simple access:
|
||||
* @code
|
||||
* if (NRF_SUCCESS != nrf_atfifo_simple_put(my_fifo, &data, NULL))
|
||||
* {
|
||||
* // Error handling
|
||||
* }
|
||||
* @endcode
|
||||
* - Function pair to limit data copying:
|
||||
* @code
|
||||
* struct point3d
|
||||
* {
|
||||
* int x, y, z;
|
||||
* }point3d_t;
|
||||
* nrf_atfifo_context_t context;
|
||||
* point3d_t * point;
|
||||
*
|
||||
* if (NULL != (point = nrf_atfifo_item_alloc(my_fifo, &context)))
|
||||
* {
|
||||
* point->x = a;
|
||||
* point->y = b;
|
||||
* point->z = c;
|
||||
* if (nrf_atfifo_item_put(my_fifo, &context))
|
||||
* {
|
||||
* // Send information to the rest of the system
|
||||
* // that there is new data in the FIFO available for reading.
|
||||
* }
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // Error handling
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
* @note
|
||||
* This atomic FIFO implementation requires that the operation that is
|
||||
* opened last is finished (committed/flushed) first.
|
||||
* This is typical for operations performed from the interrupt runtime
|
||||
* when the other operation is performed from the main thread.
|
||||
*
|
||||
* This implementation does not support typical multithreading operating system
|
||||
* access where operations can be started and finished in totally unrelated order.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Read and write position structure.
|
||||
*
|
||||
* A structure that holds the read and write position used by the FIFO head and tail.
|
||||
*/
|
||||
typedef struct nrf_atfifo_postag_pos_s
|
||||
{
|
||||
uint16_t wr; //!< First free space to write the data
|
||||
uint16_t rd; //!< A place after the last data to read
|
||||
}nrf_atfifo_postag_pos_t;
|
||||
|
||||
/**
|
||||
* @brief End data index tag.
|
||||
*
|
||||
* A tag used to mark the end of data.
|
||||
* To properly realize atomic data committing, the whole variable has to be
|
||||
* accessed atomically.
|
||||
*/
|
||||
typedef union nrf_atfifo_postag_u
|
||||
{
|
||||
uint32_t tag; //!< Whole tag, used for atomic, 32-bit access
|
||||
nrf_atfifo_postag_pos_t pos; //!< Structure that holds reading and writing position separately
|
||||
}nrf_atfifo_postag_t;
|
||||
|
||||
/**
|
||||
* @brief The FIFO instance.
|
||||
*
|
||||
* The instance of atomic FIFO.
|
||||
* Used with all FIFO functions.
|
||||
*/
|
||||
typedef struct nrf_atfifo_s
|
||||
{
|
||||
void * p_buf; //!< Pointer to the data buffer
|
||||
nrf_atfifo_postag_t tail; //!< Read and write tail position tag
|
||||
nrf_atfifo_postag_t head; //!< Read and write head position tag
|
||||
uint16_t buf_size; //!< FIFO size in number of bytes (has to be divisible by @c item_size)
|
||||
uint16_t item_size; //!< Size of a single FIFO item
|
||||
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
|
||||
}nrf_atfifo_t;
|
||||
|
||||
/**
|
||||
* @brief FIFO write operation item context.
|
||||
*
|
||||
* Context structure used to mark an allocated space in FIFO that is ready for put.
|
||||
* All the data required to properly put allocated and written data.
|
||||
*/
|
||||
typedef struct nrf_atfifo_item_put_s
|
||||
{
|
||||
nrf_atfifo_postag_t last_tail; //!< Tail tag value that was here when opening the FIFO to write
|
||||
}nrf_atfifo_item_put_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief FIFO read operation item context.
|
||||
*
|
||||
* Context structure used to mark an opened get operation to properly free an item after reading.
|
||||
*/
|
||||
typedef struct nrf_atfifo_rcontext_s
|
||||
{
|
||||
nrf_atfifo_postag_t last_head; //!< Head tag value that was here when opening the FIFO to read
|
||||
}nrf_atfifo_item_get_t;
|
||||
|
||||
|
||||
/** @brief Name of the module used for logger messaging.
|
||||
*/
|
||||
#define NRF_ATFIFO_LOG_NAME atfifo
|
||||
|
||||
/**
|
||||
* @defgroup nrf_atfifo_instmacros FIFO instance macros
|
||||
*
|
||||
* A group of macros helpful for FIFO instance creation and initialization.
|
||||
* They may be used to create and initialize instances for most use cases.
|
||||
*
|
||||
* FIFO may also be created and initialized directly using
|
||||
* @ref nrf_atfifo_init function.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Macro for generating the name for a data buffer.
|
||||
*
|
||||
* The name of the data buffer that would be created by
|
||||
* @ref NRF_ATFIFO_DEF macro.
|
||||
*
|
||||
* @param[in] fifo_id Identifier of the FIFO object.
|
||||
*
|
||||
* @return Name of the buffer variable.
|
||||
*
|
||||
* @note This is auxiliary internal macro and in normal usage
|
||||
* it should not be called.
|
||||
*/
|
||||
#define NRF_ATFIFO_BUF_NAME(fifo_id) CONCAT_2(fifo_id, _data)
|
||||
|
||||
/**
|
||||
* @brief Macro for generating the name for a FIFO instance.
|
||||
*
|
||||
* The name of the instance variable that will be created by the
|
||||
* @ref NRF_ATFIFO_DEF macro.
|
||||
*
|
||||
* @param[in] fifo_id Identifier of the FIFO object.
|
||||
*
|
||||
* @return Name of the instance variable.
|
||||
*
|
||||
* @note This is auxiliary internal macro and in normal usage
|
||||
* it should not be called.
|
||||
*/
|
||||
#define NRF_ATFIFO_INST_NAME(fifo_id) CONCAT_2(fifo_id, _inst)
|
||||
|
||||
/**
|
||||
* @brief Macro for creating an instance.
|
||||
*
|
||||
* Creates the FIFO object variable itself.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
* NRF_ATFIFO_DEF(my_fifo, uint16_t, 12);
|
||||
* NRF_ATFIFO_INIT(my_fifo);
|
||||
*
|
||||
* uint16_t some_val = 45;
|
||||
* nrf_atfifo_item_put(my_fifo, &some_val, sizeof(some_val), NULL);
|
||||
* nrf_atfifo_item_get(my_fifo, &some_val, sizeof(some_val), NULL);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] fifo_id Identifier of a FIFO object.
|
||||
* This identifier will be a pointer to the instance.
|
||||
* It makes it possible to use this directly for the functions
|
||||
* that operate on the FIFO.
|
||||
* Because it is a static const object, it should be optimized by the compiler.
|
||||
* @param[in] storage_type Type of data that will be stored in the FIFO.
|
||||
* @param[in] item_cnt Capacity of the created FIFO in maximum number of items that may be stored.
|
||||
* The phisical size of the buffer will be 1 element bigger.
|
||||
*/
|
||||
#define NRF_ATFIFO_DEF(fifo_id, storage_type, item_cnt) \
|
||||
static storage_type NRF_ATFIFO_BUF_NAME(fifo_id)[(item_cnt)+1]; \
|
||||
NRF_LOG_INSTANCE_REGISTER(NRF_ATFIFO_LOG_NAME, fifo_id, \
|
||||
NRF_ATFIFO_CONFIG_INFO_COLOR, \
|
||||
NRF_ATFIFO_CONFIG_DEBUG_COLOR, \
|
||||
NRF_ATFIFO_CONFIG_LOG_INIT_FILTER_LEVEL, \
|
||||
NRF_ATFIFO_CONFIG_LOG_ENABLED ? \
|
||||
NRF_ATFIFO_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
|
||||
static nrf_atfifo_t NRF_ATFIFO_INST_NAME(fifo_id) = { \
|
||||
.p_buf = NULL, \
|
||||
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_ATFIFO_LOG_NAME, fifo_id) \
|
||||
}; \
|
||||
static nrf_atfifo_t * const fifo_id = &NRF_ATFIFO_INST_NAME(fifo_id)
|
||||
|
||||
/**
|
||||
* @brief Macro for initializing the FIFO that was previously declared by the macro.
|
||||
*
|
||||
* Use this macro to simplify FIFO initialization.
|
||||
*
|
||||
* @note
|
||||
* This macro can be only used on a FIFO object defined by @ref NRF_ATFIFO_DEF macro.
|
||||
*
|
||||
* @param[in] fifo_id Identifier of the FIFO object.
|
||||
*
|
||||
* @return Value from the @ref nrf_atfifo_init function.
|
||||
*/
|
||||
#define NRF_ATFIFO_INIT(fifo_id) \
|
||||
nrf_atfifo_init( \
|
||||
fifo_id, \
|
||||
NRF_ATFIFO_BUF_NAME(fifo_id), \
|
||||
sizeof(NRF_ATFIFO_BUF_NAME(fifo_id)), \
|
||||
sizeof(NRF_ATFIFO_BUF_NAME(fifo_id)[0]) \
|
||||
)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Function for initializing the FIFO.
|
||||
*
|
||||
* Preparing the FIFO instance to work.
|
||||
*
|
||||
* @param[out] p_fifo FIFO object to initialize.
|
||||
* @param[in,out] p_buf FIFO buffer for storing data.
|
||||
* @param[in] buf_size Total buffer size (has to be divisible by @c item_size).
|
||||
* @param[in] item_size Size of a single item held inside the FIFO.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful.
|
||||
* @retval NRF_ERROR_NULL If a NULL pointer is provided as the buffer.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH If size of the buffer provided is not divisible by @c item_size.
|
||||
*
|
||||
* @note
|
||||
* Buffer size must be able to hold one element more than the designed FIFO capacity.
|
||||
* This one, empty element is used for overflow checking.
|
||||
*/
|
||||
ret_code_t nrf_atfifo_init(nrf_atfifo_t * const p_fifo, void * p_buf, uint16_t buf_size, uint16_t item_size);
|
||||
|
||||
/**
|
||||
* @brief Function for clearing the FIFO.
|
||||
*
|
||||
* Function for clearing the FIFO.
|
||||
*
|
||||
* If this function is called during an opened and uncommitted write operation,
|
||||
* the FIFO is cleared up to the currently ongoing commit.
|
||||
* There is no possibility to cancel an ongoing commit.
|
||||
*
|
||||
* If this function is called during an opened and unflushed read operation,
|
||||
* the read position in the head is set, but copying it into the write head position
|
||||
* is left to read closing operation.
|
||||
*
|
||||
* This way, there is no more data to read, but the memory is released
|
||||
* in the moment when it is safe.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
*
|
||||
* @retval NRF_SUCCESS FIFO totally cleared.
|
||||
* @retval NRF_ERROR_BUSY Function called in the middle of writing or reading operation.
|
||||
* If it is called in the middle of writing operation,
|
||||
* FIFO was cleared up to the already started and uncommitted write.
|
||||
* If it is called in the middle of reading operation,
|
||||
* write head was only moved. It will be copied into read tail when the reading operation
|
||||
* is flushed.
|
||||
*/
|
||||
ret_code_t nrf_atfifo_clear(nrf_atfifo_t * const p_fifo);
|
||||
|
||||
/**
|
||||
* @brief Function for atomically putting data into the FIFO.
|
||||
*
|
||||
* It uses memcpy function inside and in most situations, it is more suitable to
|
||||
* use @ref nrf_atfifo_item_alloc, write the data, and @ref nrf_atfifo_item_put to store a new value
|
||||
* in a FIFO.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[in] p_var Variable to copy.
|
||||
* @param[in] size Size of the variable to copy.
|
||||
* Can be smaller or equal to the FIFO item size.
|
||||
* @param[out] p_visible See value returned by @ref nrf_atfifo_item_put.
|
||||
* It may be NULL if the caller does not require the current operation status.
|
||||
*
|
||||
* @retval NRF_SUCCESS If an element has been successfully added to the FIFO.
|
||||
* @retval NRF_ERROR_NO_MEM If the FIFO is full.
|
||||
*
|
||||
* @note
|
||||
* To avoid data copying, you can use the @ref nrf_atfifo_item_alloc and @ref nrf_atfifo_item_put
|
||||
* functions pair.
|
||||
*/
|
||||
ret_code_t nrf_atfifo_alloc_put(nrf_atfifo_t * const p_fifo, void const * const p_var, size_t size, bool * const p_visible);
|
||||
|
||||
/**
|
||||
* @brief Function for opening the FIFO for writing.
|
||||
*
|
||||
* Function called to start the FIFO write operation and access the given FIFO buffer directly.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] p_context Operation context, required by @ref nrf_atfifo_item_put.
|
||||
*
|
||||
* @return Pointer to the space where variable data can be stored.
|
||||
* NULL if there is no space in the buffer.
|
||||
*/
|
||||
void * nrf_atfifo_item_alloc(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_put_t * p_context);
|
||||
|
||||
/**
|
||||
* @brief Function for closing the writing operation.
|
||||
*
|
||||
* Puts a previously allocated context into FIFO.
|
||||
* This function must be called to commit an opened write operation.
|
||||
* It sets all the buffers and marks the data, so that it is visible to read.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[in] p_context Operation context, filled by the @ref nrf_atfifo_item_alloc function.
|
||||
*
|
||||
* @retval true Data is currently ready and will be visible to read.
|
||||
* @retval false The internal commit was marked, but the writing operation interrupted another writing operation.
|
||||
* The data will be available to read when the interrupted operation is committed.
|
||||
*/
|
||||
bool nrf_atfifo_item_put(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_put_t * p_context);
|
||||
|
||||
/**
|
||||
* @brief Function for getting a single value from the FIFO.
|
||||
*
|
||||
* This function gets the value from the top of the FIFO.
|
||||
* The value is removed from the FIFO memory.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] p_var Pointer to the variable to store the data.
|
||||
* @param[in] size Size of the data to be loaded.
|
||||
* @param[out] p_released See the values returned by @ref nrf_atfifo_item_free.
|
||||
*
|
||||
* @retval NRF_SUCCESS Element was successfully copied from the FIFO memory.
|
||||
* @retval NRF_ERROR_NOT_FOUND No data in the FIFO.
|
||||
*/
|
||||
ret_code_t nrf_atfifo_get_free(nrf_atfifo_t * const p_fifo, void * const p_var, size_t size, bool * p_released);
|
||||
|
||||
/**
|
||||
* @brief Function for opening the FIFO for reading.
|
||||
*
|
||||
* Function called to start the FIFO read operation and access the given FIFO buffer directly.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] p_context The operation context, required by @ref nrf_atfifo_item_free
|
||||
*
|
||||
* @return Pointer to data buffer or NULL if there is no data in the FIFO.
|
||||
*/
|
||||
void * nrf_atfifo_item_get(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_get_t * p_context);
|
||||
|
||||
/**
|
||||
* @brief Function for closing the reading operation.
|
||||
*
|
||||
* Function used to finish the reading operation.
|
||||
* If this reading operation does not interrupt another reading operation, the head write buffer is moved.
|
||||
* If this reading operation is placed in the middle of another reading, only the new read pointer is written.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[in] p_context Context of the reading operation to be closed.
|
||||
*
|
||||
* @retval true This operation is not generated in the middle of another read operation and the write head will be updated to the read head (space is released).
|
||||
* @retval false This operation was performed in the middle of another read operation and the write buffer head was not moved (no space is released).
|
||||
*/
|
||||
bool nrf_atfifo_item_free(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_get_t * p_context);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_ATFIFO_H__ */
|
||||
577
components/libraries/atomic_fifo/nrf_atfifo_internal.h
Normal file
577
components/libraries/atomic_fifo/nrf_atfifo_internal.h
Normal file
@@ -0,0 +1,577 @@
|
||||
/**
|
||||
* Copyright (c) 2011 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Atomic FIFO internal file
|
||||
*
|
||||
* This file should be included only by nrf_atfifo internally.
|
||||
* Needs nrf_atfifo.h included first.
|
||||
*/
|
||||
#ifndef NRF_ATFIFO_H__
|
||||
#error This is internal file. Do not include this file in your program.
|
||||
#endif
|
||||
|
||||
#ifndef NRF_ATFIFO_INTERNAL_H__
|
||||
#define NRF_ATFIFO_INTERNAL_H__
|
||||
#include <stddef.h>
|
||||
#include "nrf.h"
|
||||
#include "app_util.h"
|
||||
#include "nordic_common.h"
|
||||
|
||||
#if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U)) == 0
|
||||
#error Unsupported core version
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure that rd and wr pos in a tag are aligned like expected
|
||||
* Changing this would require changes inside assembly code!
|
||||
*/
|
||||
STATIC_ASSERT(offsetof(nrf_atfifo_postag_pos_t, wr) == 0);
|
||||
STATIC_ASSERT(offsetof(nrf_atfifo_postag_pos_t, rd) == 2);
|
||||
|
||||
/**
|
||||
* @brief Atomically reserve space for a new write.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] old_tail Tail position tag before new space is reserved.
|
||||
*
|
||||
* @retval true Space available.
|
||||
* @retval false Memory full.
|
||||
*
|
||||
* @sa nrf_atfifo_wspace_close
|
||||
*/
|
||||
static bool nrf_atfifo_wspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail);
|
||||
|
||||
/**
|
||||
* @brief Atomically mark all written data available.
|
||||
*
|
||||
* This function marks all data available for reading.
|
||||
* This marking is done by copying tail.pos.wr into tail.pos.rd.
|
||||
*
|
||||
* It must be called only when closing the first write.
|
||||
* It cannot be called if any write access was interrupted.
|
||||
* See the code below:
|
||||
* @code
|
||||
* if (old_tail.pos.wr == old_tail.pos.rd)
|
||||
* {
|
||||
* nrf_atfifo_wspace_close(my_fifo);
|
||||
* return true;
|
||||
* }
|
||||
* return false;
|
||||
* @endcode
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
*
|
||||
* @sa nrf_atfifo_wspace_req
|
||||
*/
|
||||
static void nrf_atfifo_wspace_close(nrf_atfifo_t * const p_fifo);
|
||||
|
||||
/**
|
||||
* @brief Atomically get a part of a buffer to read data.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] old_head Head position tag before the data buffer is read.
|
||||
*
|
||||
* @retval true Data available for reading.
|
||||
* @retval false No data in the buffer.
|
||||
*
|
||||
* @sa nrf_atfifo_rspace_close
|
||||
*/
|
||||
static bool nrf_atfifo_rspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head);
|
||||
|
||||
/**
|
||||
* @brief Atomically release all read data.
|
||||
*
|
||||
* This function marks all data that was read as free space,
|
||||
* which is available for writing.
|
||||
* This marking is done by copying head.pos.rd into head.pos.wr.
|
||||
*
|
||||
* It must be called only when closing the first read.
|
||||
* It cannot be called when the current read access interrupted any other read access.
|
||||
* See code below:
|
||||
* @code
|
||||
* if (old_head.pos.wr == old_head.pos.rd)
|
||||
* {
|
||||
* nrf_atfifo_rspace_close(my_fifo);
|
||||
* return true;
|
||||
* }
|
||||
* return false;
|
||||
* @endcode
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
*
|
||||
* @sa nrf_atfifo_rspace_req
|
||||
*/
|
||||
static void nrf_atfifo_rspace_close(nrf_atfifo_t * const p_fifo);
|
||||
|
||||
/**
|
||||
* @brief Safely clear the FIFO, internal function.
|
||||
*
|
||||
* This function realizes the functionality required by @ref nrf_atfifo_clear.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
*
|
||||
* @retval true All the data was released.
|
||||
* @retval false All the data available for releasing was released, but there is some pending transfer.
|
||||
*/
|
||||
static bool nrf_atfifo_space_clear(nrf_atfifo_t * const p_fifo);
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Implementation starts here
|
||||
*/
|
||||
|
||||
#if defined ( __CC_ARM )
|
||||
|
||||
|
||||
__ASM bool nrf_atfifo_wspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - p_old_tail
|
||||
* R2 - internal variable old_tail (saved by caller)
|
||||
* R3 - internal variable new_tail (saved by caller)
|
||||
* R4 - internal temporary register (saved by this function)
|
||||
* R5 - not used stored to keep the stack aligned to 8 bytes
|
||||
* Returned value:
|
||||
* R0 (bool - 32 bits)
|
||||
*/
|
||||
push {r4, r5}
|
||||
nrf_atfifo_wspace_req_repeat
|
||||
/* Load tail tag and set memory monitor !!! R2 - old tail !!! */
|
||||
ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
|
||||
/* Extract write position !!! R3 !!! */
|
||||
uxth r3, r2
|
||||
/* Increment address with overload support !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, item_size))]
|
||||
add r3, r4
|
||||
ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, buf_size))]
|
||||
cmp r3, r4
|
||||
it hs
|
||||
subhs r3, r3, r4
|
||||
|
||||
/* Check if FIFO would overload after making this increment !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, head) + offsetof(nrf_atfifo_postag_pos_t, wr))]
|
||||
cmp r3, r4
|
||||
ittt eq
|
||||
clrexeq
|
||||
moveq r0, #__cpp(false)
|
||||
beq nrf_atfifo_wspace_req_exit
|
||||
|
||||
/* Pack everything back !!! R3 - new tail !!! */
|
||||
/* Copy lower byte from new_tail, and higher byte is a value from the top of old_tail */
|
||||
pkhbt r3, r3, r2
|
||||
|
||||
/* Store new value clearing memory monitor !!! R4 used temporary !!! */
|
||||
strex r4, r3, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
|
||||
cmp r4, #0
|
||||
bne nrf_atfifo_wspace_req_repeat
|
||||
|
||||
/* Return true */
|
||||
mov r0, #__cpp(true)
|
||||
nrf_atfifo_wspace_req_exit
|
||||
/* Save old tail */
|
||||
str r2, [r1]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM void nrf_atfifo_wspace_close(nrf_atfifo_t * const p_fifo)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - internal temporary register
|
||||
* R2 - new_tail
|
||||
*/
|
||||
nrf_atfifo_wspace_close_repeat
|
||||
ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
|
||||
/* Copy from lower byte to higher */
|
||||
pkhbt r2, r2, r2, lsl #16
|
||||
|
||||
strex r1, r2, [r0, #__cpp(offsetof(nrf_atfifo_t, tail))]
|
||||
cmp r1, #0
|
||||
bne nrf_atfifo_wspace_close_repeat
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM bool nrf_atfifo_rspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - p_old_head
|
||||
* R2 - internal variable old_head (saved by caller)
|
||||
* R3 - internal variable new_head (saved by caller)
|
||||
* R4 - internal temporary register (saved by this function)
|
||||
* R5 - not used stored to keep the stack aligned to 8 bytes
|
||||
* Returned value:
|
||||
* R0 (bool - 32 bits)
|
||||
*/
|
||||
push {r4, r5}
|
||||
nrf_atfifo_rspace_req_repeat
|
||||
/* Load tail tag and set memory monitor !!! R2 - old tail !!! */
|
||||
ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
|
||||
/* Extract read position !!! R3 !!! */
|
||||
uxth r3, r2, ror #16
|
||||
|
||||
/* Check if we have any data !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd))]
|
||||
cmp r3, r4
|
||||
ittt eq
|
||||
clrexeq
|
||||
moveq r0, #__cpp(false)
|
||||
beq nrf_atfifo_rspace_req_exit
|
||||
|
||||
/* Increment address with overload support !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, item_size))]
|
||||
add r3, r4
|
||||
ldrh r4, [r0, #__cpp(offsetof(nrf_atfifo_t, buf_size))]
|
||||
cmp r3, r4
|
||||
it hs
|
||||
subhs r3, r3, r4
|
||||
|
||||
/* Pack everything back !!! R3 - new tail !!! */
|
||||
/* Copy lower byte from old_head, and higher byte is a value from write_pos */
|
||||
pkhbt r3, r2, r3, lsl #16
|
||||
|
||||
/* Store new value clearing memory monitor !!! R4 used temporary !!! */
|
||||
strex r4, r3, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
|
||||
cmp r4, #0
|
||||
bne nrf_atfifo_rspace_req_repeat
|
||||
|
||||
/* Return true */
|
||||
mov r0, #__cpp(true)
|
||||
nrf_atfifo_rspace_req_exit
|
||||
/* Save old head */
|
||||
str r2, [r1]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM void nrf_atfifo_rspace_close(nrf_atfifo_t * const p_fifo)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - internal temporary register
|
||||
* R2 - new_tail
|
||||
*/
|
||||
nrf_atfifo_rspace_close_repeat
|
||||
ldrex r2, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
|
||||
/* Copy from higher byte to lower */
|
||||
pkhtb r2, r2, r2, asr #16
|
||||
|
||||
strex r1, r2, [r0, #__cpp(offsetof(nrf_atfifo_t, head))]
|
||||
cmp r1, #0
|
||||
bne nrf_atfifo_rspace_close_repeat
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM bool nrf_atfifo_space_clear(nrf_atfifo_t * const p_fifo)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo as input, bool output after
|
||||
* R1 - tail, rd pointer, new_head
|
||||
* R2 - head_old, destroyed when creating new_head
|
||||
* R3 - p_fifo - copy
|
||||
*/
|
||||
mov r3, r0
|
||||
nrf_atfifo_space_clear_repeat
|
||||
/* Load old head in !!! R2 register !!! and read pointer of tail in !!! R1 register !!! */
|
||||
ldrex r2, [r3, #__cpp(offsetof(nrf_atfifo_t, head))]
|
||||
ldrh r1, [r3, #__cpp(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd))]
|
||||
cmp r2, r2, ror #16
|
||||
/* Return false as default */
|
||||
mov r0, #__cpp(false)
|
||||
/* Create new head in !!! R1 register !!! Data in !!! R2 register broken !!! */
|
||||
itett ne
|
||||
uxthne r2, r2
|
||||
orreq r1, r1, r1, lsl #16
|
||||
orrne r1, r2, r1, lsl #16
|
||||
|
||||
/* Skip header test */
|
||||
bne nrf_atfifo_space_clear_head_test_skip
|
||||
|
||||
/* Load whole tail and test it !!! R2 used !!! */
|
||||
ldr r2, [r3, #__cpp(offsetof(nrf_atfifo_t, tail))]
|
||||
cmp r2, r2, ror #16
|
||||
/* Return true if equal */
|
||||
it eq
|
||||
moveq r0, #__cpp(true)
|
||||
|
||||
nrf_atfifo_space_clear_head_test_skip
|
||||
/* Store and test if success !!! R2 used temporary !!! */
|
||||
strex r2, r1, [r3, #__cpp(offsetof(nrf_atfifo_t, head))]
|
||||
cmp r2, #0
|
||||
bne nrf_atfifo_space_clear_repeat
|
||||
bx lr
|
||||
}
|
||||
|
||||
#elif defined ( __ICCARM__ ) || defined ( __GNUC__ )
|
||||
|
||||
bool nrf_atfifo_wspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail)
|
||||
{
|
||||
volatile bool ret;
|
||||
volatile uint32_t old_tail;
|
||||
uint32_t new_tail;
|
||||
uint32_t temp;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[old_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" uxth %[new_tail], %[old_tail] \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_item_size]] \n"
|
||||
" add %[new_tail], %[temp] \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_buf_size]] \n"
|
||||
" cmp %[new_tail], %[temp] \n"
|
||||
" it hs \n"
|
||||
" subhs %[new_tail], %[new_tail], %[temp] \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_head_wr]] \n"
|
||||
" cmp %[new_tail], %[temp] \n"
|
||||
" ittt eq \n"
|
||||
" clrexeq \n"
|
||||
" moveq %[ret], %[false_val] \n"
|
||||
" beq.n 2f \n"
|
||||
" \n"
|
||||
" pkhbt %[new_tail], %[new_tail], %[old_tail] \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
" \n"
|
||||
" mov %[ret], %[true_val] \n"
|
||||
"2: \n"
|
||||
: /* Output operands */
|
||||
[ret] "=r"(ret),
|
||||
[temp] "=&r"(temp),
|
||||
[old_tail]"=&r"(old_tail),
|
||||
[new_tail]"=&r"(new_tail)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_tail] "J"(offsetof(nrf_atfifo_t, tail)),
|
||||
[offset_head_wr] "J"(offsetof(nrf_atfifo_t, head) + offsetof(nrf_atfifo_postag_pos_t, wr)),
|
||||
[offset_item_size]"J"(offsetof(nrf_atfifo_t, item_size)),
|
||||
[offset_buf_size] "J"(offsetof(nrf_atfifo_t, buf_size)),
|
||||
[true_val] "I"(true),
|
||||
[false_val] "I"(false)
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
p_old_tail->tag = old_tail;
|
||||
UNUSED_VARIABLE(new_tail);
|
||||
UNUSED_VARIABLE(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void nrf_atfifo_wspace_close(nrf_atfifo_t * const p_fifo)
|
||||
{
|
||||
uint32_t temp;
|
||||
uint32_t new_tail;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[new_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" pkhbt %[new_tail],%[new_tail], %[new_tail], lsl #16 \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
: /* Output operands */
|
||||
[temp] "=&r"(temp),
|
||||
[new_tail] "=&r"(new_tail)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_tail] "J"(offsetof(nrf_atfifo_t, tail))
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
UNUSED_VARIABLE(temp);
|
||||
UNUSED_VARIABLE(new_tail);
|
||||
}
|
||||
|
||||
|
||||
bool nrf_atfifo_rspace_req(nrf_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head)
|
||||
{
|
||||
volatile bool ret;
|
||||
volatile uint32_t old_head;
|
||||
uint32_t new_head;
|
||||
uint32_t temp;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[old_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" uxth %[new_head], %[old_head], ror #16 \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_tail_rd]] \n"
|
||||
" cmp %[new_head], %[temp] \n"
|
||||
" ittt eq \n"
|
||||
" clrexeq \n"
|
||||
" moveq %[ret], %[false_val] \n"
|
||||
" beq.n 2f \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_item_size]] \n"
|
||||
" add %[new_head], %[temp] \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_buf_size]] \n"
|
||||
" cmp %[new_head], %[temp] \n"
|
||||
" it hs \n"
|
||||
" subhs %[new_head], %[new_head], %[temp] \n"
|
||||
" \n"
|
||||
" pkhbt %[new_head], %[old_head], %[new_head], lsl #16 \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
" \n"
|
||||
" mov %[ret], %[true_val] \n"
|
||||
"2: \n"
|
||||
: /* Output operands */
|
||||
[ret] "=r"(ret),
|
||||
[temp] "=&r"(temp),
|
||||
[old_head]"=&r"(old_head),
|
||||
[new_head]"=&r"(new_head)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_head] "J"(offsetof(nrf_atfifo_t, head)),
|
||||
[offset_tail_rd] "J"(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd)),
|
||||
[offset_item_size]"J"(offsetof(nrf_atfifo_t, item_size)),
|
||||
[offset_buf_size] "J"(offsetof(nrf_atfifo_t, buf_size)),
|
||||
[true_val] "I"(true),
|
||||
[false_val] "I"(false)
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
p_old_head->tag = old_head;
|
||||
UNUSED_VARIABLE(new_head);
|
||||
UNUSED_VARIABLE(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void nrf_atfifo_rspace_close(nrf_atfifo_t * const p_fifo)
|
||||
{
|
||||
uint32_t temp;
|
||||
uint32_t new_head;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" pkhtb %[new_head],%[new_head], %[new_head], asr #16 \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
: /* Output operands */
|
||||
[temp] "=&r"(temp),
|
||||
[new_head] "=&r"(new_head)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_head] "J"(offsetof(nrf_atfifo_t, head))
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
UNUSED_VARIABLE(temp);
|
||||
UNUSED_VARIABLE(new_head);
|
||||
}
|
||||
|
||||
|
||||
bool nrf_atfifo_space_clear(nrf_atfifo_t * const p_fifo)
|
||||
{
|
||||
volatile bool ret;
|
||||
uint32_t old_head; /* This variable is left broken after assembly code finishes */
|
||||
uint32_t new_head;
|
||||
|
||||
__ASM volatile(
|
||||
"1: \n"
|
||||
" ldrex %[old_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" ldrh %[new_head], [%[p_fifo], %[offset_tail_rd]] \n"
|
||||
" cmp %[old_head], %[old_head], ror #16 \n"
|
||||
" \n"
|
||||
" mov %[ret], %[false_val] \n"
|
||||
" \n"
|
||||
" itett ne \n"
|
||||
" uxthne %[old_head], %[old_head] \n"
|
||||
" orreq %[new_head], %[new_head], %[new_head], lsl #16 \n"
|
||||
" orrne %[new_head], %[old_head], %[new_head], lsl #16 \n"
|
||||
" \n"
|
||||
" bne.n 2f \n"
|
||||
" \n"
|
||||
" ldr %[old_head], [%[p_fifo], %[offset_tail]] \n"
|
||||
" cmp %[old_head], %[old_head], ror #16 \n"
|
||||
" it eq \n"
|
||||
" moveq %[ret], %[true_val] \n"
|
||||
" \n"
|
||||
"2: \n"
|
||||
" strex %[old_head], %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" cmp %[old_head], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
: /* Output operands */
|
||||
[ret] "=&r"(ret),
|
||||
[old_head] "=&r"(old_head),
|
||||
[new_head] "=&r"(new_head)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_head] "J"(offsetof(nrf_atfifo_t, head)),
|
||||
[offset_tail] "J"(offsetof(nrf_atfifo_t, tail)),
|
||||
[offset_tail_rd] "J"(offsetof(nrf_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd)),
|
||||
[true_val] "I"(true),
|
||||
[false_val] "I"(false)
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
UNUSED_VARIABLE(old_head);
|
||||
UNUSED_VARIABLE(new_head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
#error Unsupported compiler
|
||||
#endif
|
||||
|
||||
#endif /* NRF_ATFIFO_INTERNAL_H__ */
|
||||
160
components/libraries/atomic_flags/nrf_atflags.c
Normal file
160
components/libraries/atomic_flags/nrf_atflags.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nrf.h"
|
||||
#include "nrf_atomic.h"
|
||||
#include "nrf_atflags.h"
|
||||
#include "sdk_common.h"
|
||||
|
||||
|
||||
|
||||
/**@brief Macro for getting the index inside the flag array where a flag can be found.
|
||||
*
|
||||
* @param flag_index Index of the flag.
|
||||
*
|
||||
* @return Index of the @ref nrf_atflags_t the flag can be found in.
|
||||
*/
|
||||
#define FLAG_BASE(flag_index) ((flag_index) / NRF_ATFLAGS_FLAGS_PER_ELEMENT)
|
||||
|
||||
/**@brief Macro for getting the mask representing the flag within the flag array member.
|
||||
*
|
||||
* @param flag_index ID of the flag.
|
||||
*
|
||||
* @return Mask representing the flag within a single @ref nrf_atflags_t.
|
||||
*/
|
||||
#define FLAG_MASK(flag_index) (1UL << ((flag_index) % NRF_ATFLAGS_FLAGS_PER_ELEMENT))
|
||||
|
||||
|
||||
void nrf_atflags_set(nrf_atflags_t * p_flags, uint32_t flag_index)
|
||||
{
|
||||
uint32_t new_value = nrf_atomic_u32_or(&p_flags[FLAG_BASE(flag_index)], FLAG_MASK(flag_index));
|
||||
UNUSED_RETURN_VALUE(new_value);
|
||||
}
|
||||
|
||||
|
||||
bool nrf_atflags_fetch_set(nrf_atflags_t * p_flags, uint32_t flag_index)
|
||||
{
|
||||
return (nrf_atomic_u32_fetch_or(&p_flags[FLAG_BASE(flag_index)], FLAG_MASK(flag_index))
|
||||
& FLAG_MASK(flag_index)) != 0;
|
||||
}
|
||||
|
||||
|
||||
void nrf_atflags_clear(nrf_atflags_t * p_flags, uint32_t flag_index)
|
||||
{
|
||||
uint32_t new_value = nrf_atomic_u32_and(&p_flags[FLAG_BASE(flag_index)], ~FLAG_MASK(flag_index));
|
||||
UNUSED_RETURN_VALUE(new_value);
|
||||
}
|
||||
|
||||
|
||||
bool nrf_atflags_fetch_clear(nrf_atflags_t * p_flags, uint32_t flag_index)
|
||||
{
|
||||
return (nrf_atomic_u32_fetch_and(&p_flags[FLAG_BASE(flag_index)], ~FLAG_MASK(flag_index))
|
||||
& FLAG_MASK(flag_index)) != 0;
|
||||
}
|
||||
|
||||
|
||||
bool nrf_atflags_get(nrf_atflags_t const * p_flags, uint32_t flag_index)
|
||||
{
|
||||
return (p_flags[FLAG_BASE(flag_index)] & FLAG_MASK(flag_index)) != 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_atflags_init(nrf_atflags_t * p_flags, uint32_t flags_array_len, uint32_t flag_count)
|
||||
{
|
||||
uint32_t required_flags_array_len = NRF_ATFLAGS_ARRAY_LEN(flag_count);
|
||||
|
||||
if (required_flags_array_len <= flags_array_len)
|
||||
{
|
||||
for (uint32_t i = 0; i < required_flags_array_len; i++)
|
||||
{
|
||||
p_flags[i] = 0;
|
||||
}
|
||||
return required_flags_array_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t nrf_atflags_find_and_set_flag(nrf_atflags_t * p_flags, uint32_t flag_count)
|
||||
{
|
||||
for (uint32_t i = 0; i < NRF_ATFLAGS_ARRAY_LEN(flag_count); i++)
|
||||
{
|
||||
// Using __RBIT to make the order of flags more traditional.
|
||||
uint32_t first_zero = __CLZ(__RBIT(~p_flags[i]));
|
||||
while (first_zero < 32)
|
||||
{
|
||||
uint32_t first_zero_global = first_zero + (i * 32);
|
||||
if (first_zero_global >= flag_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!nrf_atflags_fetch_set(p_flags, first_zero_global))
|
||||
{
|
||||
return first_zero_global;
|
||||
}
|
||||
first_zero = __CLZ(__RBIT(~p_flags[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return flag_count;
|
||||
}
|
||||
|
||||
uint32_t nrf_atflags_find_and_clear_flag(nrf_atflags_t * p_flags, uint32_t flag_count)
|
||||
{
|
||||
for (uint32_t i = 0; i < NRF_ATFLAGS_ARRAY_LEN(flag_count); i++)
|
||||
{
|
||||
// Using __RBIT to make the order of flags more traditional.
|
||||
uint32_t first_one = __CLZ(__RBIT(p_flags[i]));
|
||||
while (first_one < 32)
|
||||
{
|
||||
uint32_t first_one_global = first_one + (i * 32);
|
||||
if (first_one_global >= flag_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (nrf_atflags_fetch_clear(p_flags, first_one_global))
|
||||
{
|
||||
return first_one_global;
|
||||
}
|
||||
first_one = __CLZ(__RBIT(p_flags[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return flag_count;
|
||||
}
|
||||
184
components/libraries/atomic_flags/nrf_atflags.h
Normal file
184
components/libraries/atomic_flags/nrf_atflags.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_atflags Atomic flags (bitmaps)
|
||||
* @ingroup app_common
|
||||
* @{
|
||||
*
|
||||
* @brief @tagAPI52 This module implements atomic flags as bitmaps.
|
||||
*
|
||||
* Operations on the individual flags are atomic, meaning that you are always sure that the flag is
|
||||
* set to the desired value, and you always know what value was there before. You also know that no
|
||||
* other flags were affected by the operation.
|
||||
*
|
||||
* Operations on the entire flag collection are NOT atomic. This essentially means that you can't
|
||||
* know the order in which operations on different flags happened, and you can't know the state of
|
||||
* the entire flag collection at any instant. These limitations can be overcome by protecting
|
||||
* operations with a mutex.
|
||||
*/
|
||||
|
||||
#ifndef NRF_ATFLAGS_H__
|
||||
#define NRF_ATFLAGS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief Array of atomic flags.
|
||||
* */
|
||||
typedef volatile uint32_t nrf_atflags_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Number of flags per @ref nrf_atflags_t.
|
||||
* */
|
||||
#define NRF_ATFLAGS_FLAGS_PER_ELEMENT (sizeof(nrf_atflags_t) * 8)
|
||||
|
||||
/**@brief Macro for the length of an array of @ref nrf_atflags_t needed to keep \p flag_count flags.
|
||||
*
|
||||
* @param flag_count Number of flags to keep in a flag array.
|
||||
*
|
||||
* @return Length of the array needed to house flag_count flags.
|
||||
*/
|
||||
#define NRF_ATFLAGS_ARRAY_LEN(flag_count) ((flag_count - 1) / NRF_ATFLAGS_FLAGS_PER_ELEMENT) + 1
|
||||
|
||||
/**@brief Macro for declaring a flag array with the right size and initial value.
|
||||
*
|
||||
* @note When using this macro, no call to @ref nrf_atflags_init is necessary for this array.
|
||||
*
|
||||
* @param _name Name to be given to the array.
|
||||
* @param flag_count Number of flags to be kept in the flag array.
|
||||
*
|
||||
* @return Flag array definition.
|
||||
*/
|
||||
#define NRF_ATFLAGS_DEF(_name, flag_count) \
|
||||
nrf_atflags_t _name[NRF_ATFLAGS_ARRAY_LEN((flag_count))] = {0}
|
||||
|
||||
/**@brief Macro for defining a flag array inside a struct.
|
||||
*
|
||||
* @note When using this macro, make sure to set the array to 0 or use @ref nrf_atflags_init
|
||||
*
|
||||
* @param _name Name to be given to the array.
|
||||
* @param flag_count Number of flags to be kept in the flag array.
|
||||
*
|
||||
* @return The flag array definition.
|
||||
*/
|
||||
#define NRF_ATFLAGS_DEF_MEMBER(_name, flag_count) \
|
||||
nrf_atflags_t _name[NRF_ATFLAGS_ARRAY_LEN((flag_count))]
|
||||
|
||||
/**@brief Function for safely initializing a flag array to 0.
|
||||
*
|
||||
* @param p_flags Flag array to initialize.
|
||||
* @param flags_array_len Length of \p p_flags.
|
||||
* @param flag_count Number of flags to be kept in the flag array.
|
||||
*
|
||||
* @retval 0 if the given length is not sufficient to house \p flag_count flags in the array.
|
||||
* @return If successful: The actual length required.
|
||||
*/
|
||||
uint32_t nrf_atflags_init(nrf_atflags_t * p_flags, uint32_t flags_array_len, uint32_t flag_count);
|
||||
|
||||
/**@brief Function for atomically setting a flag to 1.
|
||||
*
|
||||
* @param[in] p_flags Atomic flag array.
|
||||
* @param[in] flag_index Index of the flag in the array.
|
||||
*/
|
||||
void nrf_atflags_set(nrf_atflags_t * p_flags, uint32_t flag_index);
|
||||
|
||||
/**@brief Function for atomically setting a flag to 1, returning the previous value of the flag.
|
||||
*
|
||||
* @param[in] p_flags Atomic flag array.
|
||||
* @param[in] flag_index Index of the flag in the array.
|
||||
*
|
||||
* @return Old flag value.
|
||||
*/
|
||||
bool nrf_atflags_fetch_set(nrf_atflags_t * p_flags, uint32_t flag_index);
|
||||
|
||||
/**@brief Function for atomically setting a flag to 0.
|
||||
*
|
||||
* @param[in] p_flags Atomic flag array.
|
||||
* @param[in] flag_index Index of the flag in the array.
|
||||
*/
|
||||
void nrf_atflags_clear(nrf_atflags_t * p_flags, uint32_t flag_index);
|
||||
|
||||
/**@brief Function for atomically setting a flag to 0, returning the previous value of the flag.
|
||||
*
|
||||
* @param[in] p_flags Atomic flag array.
|
||||
* @param[in] flag_index Index of the flag in the array.
|
||||
*
|
||||
* @return Old flag value.
|
||||
*/
|
||||
bool nrf_atflags_fetch_clear(nrf_atflags_t * p_flags, uint32_t flag_index);
|
||||
|
||||
/**@brief Function for getting the value of a flag in a flag array.
|
||||
*
|
||||
* @param[in] p_flags Atomic flag array.
|
||||
* @param[in] flag_index Index of the flag in the array.
|
||||
*
|
||||
* @return Flag value.
|
||||
*/
|
||||
bool nrf_atflags_get(nrf_atflags_t const * p_flags, uint32_t flag_index);
|
||||
|
||||
/**@brief Function for finding a flag with value 0, and atomically setting it to one.
|
||||
*
|
||||
* @param[in] p_flags Atomic flag array.
|
||||
* @param[in] flag_count Number of flags in the array.
|
||||
*
|
||||
* @return Index of the cleared flag that has been set.
|
||||
*/
|
||||
uint32_t nrf_atflags_find_and_set_flag(nrf_atflags_t * p_flags, uint32_t flag_count);
|
||||
|
||||
/**@brief Function for finding a flag with value 1, and atomically clearing it to 0.
|
||||
*
|
||||
* @param[in] p_flags Atomic flag array.
|
||||
* @param[in] flag_count The number of flags in the array.
|
||||
*
|
||||
* @return The index of the set flag that has been cleared.
|
||||
*/
|
||||
uint32_t nrf_atflags_find_and_clear_flag(nrf_atflags_t * p_flags, uint32_t flag_count);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_ATFLAGS_H__ */
|
||||
|
||||
/** @} */
|
||||
399
components/libraries/balloc/nrf_balloc.c
Normal file
399
components/libraries/balloc/nrf_balloc.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_BALLOC)
|
||||
|
||||
#include "nrf_section.h"
|
||||
#include "nrf_balloc.h"
|
||||
#include "app_util_platform.h"
|
||||
|
||||
|
||||
#if NRF_BALLOC_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_BALLOC_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INITIAL_LEVEL NRF_BALLOC_CONFIG_INITIAL_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_BALLOC_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_BALLOC_CONFIG_DEBUG_COLOR
|
||||
#else
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif // NRF_BALLOC_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
|
||||
#define HEAD_GUARD_FILL 0xBAADF00D /**< Magic number used to mark head guard.*/
|
||||
#define TAIL_GUARD_FILL 0xBAADCAFE /**< Magic number used to mark tail guard.*/
|
||||
#define FREE_MEM_FILL 0xBAADBAAD /**< Magic number used to mark free memory.*/
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
#define POOL_ID(_p_pool) _p_pool->p_name
|
||||
#define POOL_MARKER "%s"
|
||||
#else
|
||||
#define POOL_ID(_p_pool) _p_pool
|
||||
#define POOL_MARKER "0x%08X"
|
||||
#endif
|
||||
|
||||
NRF_SECTION_DEF(nrf_balloc, nrf_balloc_t);
|
||||
|
||||
#if NRF_BALLOC_CLI_CMDS && NRF_CLI_ENABLED
|
||||
#include "nrf_cli.h"
|
||||
|
||||
static void nrf_balloc_status(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
UNUSED_PARAMETER(argv);
|
||||
|
||||
if (nrf_cli_help_requested(p_cli))
|
||||
{
|
||||
nrf_cli_help_print(p_cli, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "Bad argument count");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t num_of_instances = NRF_SECTION_ITEM_COUNT(nrf_balloc, nrf_balloc_t);
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < num_of_instances; i++)
|
||||
{
|
||||
const nrf_balloc_t * p_instance = NRF_SECTION_ITEM_GET(nrf_balloc, nrf_balloc_t, i);
|
||||
|
||||
uint32_t element_size = NRF_BALLOC_ELEMENT_SIZE(p_instance);
|
||||
uint32_t dbg_addon = p_instance->block_size - element_size;
|
||||
uint32_t pool_size = p_instance->p_stack_limit - p_instance->p_stack_base;
|
||||
uint32_t max_util = nrf_balloc_max_utilization_get(p_instance);
|
||||
uint32_t util = nrf_balloc_utilization_get(p_instance);
|
||||
const char * p_name = p_instance->p_name;
|
||||
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL,
|
||||
"%s\r\n\t- Element size:\t%d + %d bytes of debug information\r\n"
|
||||
"\t- Usage:\t%u%% (%u out of %u elements)\r\n"
|
||||
"\t- Maximum:\t%u%% (%u out of %u elements)\r\n\r\n",
|
||||
p_name, element_size, dbg_addon,
|
||||
100ul * util/pool_size, util,pool_size,
|
||||
100ul * max_util/pool_size, max_util,pool_size);
|
||||
|
||||
}
|
||||
}
|
||||
// Register "balloc" command and its subcommands in CLI.
|
||||
NRF_CLI_CREATE_STATIC_SUBCMD_SET(nrf_balloc_commands)
|
||||
{
|
||||
NRF_CLI_CMD(status, NULL, "Print status of balloc instances.", nrf_balloc_status),
|
||||
NRF_CLI_SUBCMD_SET_END
|
||||
};
|
||||
|
||||
NRF_CLI_CMD_REGISTER(balloc, &nrf_balloc_commands, "Commands for BALLOC management", nrf_balloc_status);
|
||||
#endif //NRF_BALLOC_CLI_CMDS
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
/**@brief Validate block memory, prepare block guards, and calculate pointer to the element.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool.
|
||||
* @param[in] p_head Pointer to the beginning of the block.
|
||||
*
|
||||
* @return Pointer to the element.
|
||||
*/
|
||||
__STATIC_INLINE void * nrf_balloc_block_unwrap(nrf_balloc_t const * p_pool, void * p_head)
|
||||
{
|
||||
ASSERT((p_pool != NULL) && ((p_pool->block_size % sizeof(uint32_t)) == 0));
|
||||
ASSERT((p_head != NULL) && (((uint32_t)(p_head) % sizeof(uint32_t)) == 0));
|
||||
|
||||
uint32_t head_words = NRF_BALLOC_DEBUG_HEAD_GUARD_WORDS_GET(p_pool->debug_flags);
|
||||
uint32_t tail_words = NRF_BALLOC_DEBUG_TAIL_GUARD_WORDS_GET(p_pool->debug_flags);
|
||||
|
||||
uint32_t * p_tail = (uint32_t *)((size_t)(p_head) + p_pool->block_size);
|
||||
uint32_t * p_element = (uint32_t *)p_head + head_words;
|
||||
|
||||
if (NRF_BALLOC_DEBUG_DATA_TRASHING_CHECK_GET(p_pool->debug_flags))
|
||||
{
|
||||
for (uint32_t * ptr = p_head; ptr < p_tail; ptr++)
|
||||
{
|
||||
if (*ptr != FREE_MEM_FILL)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_pool->p_log,
|
||||
"Detected free memory corruption at 0x%08X (0x%08X != 0x%08X)",
|
||||
ptr, *ptr, FREE_MEM_FILL);
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t * ptr = p_head; ptr < p_element; ptr++)
|
||||
{
|
||||
*ptr = HEAD_GUARD_FILL;
|
||||
}
|
||||
|
||||
for (uint32_t * ptr = ( p_tail - tail_words); ptr < p_tail; ptr++)
|
||||
{
|
||||
*ptr = TAIL_GUARD_FILL;
|
||||
}
|
||||
|
||||
return p_element;
|
||||
}
|
||||
|
||||
/**@brief Calculate pointer to the block, validate block guards, and mark block memory as free.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool.
|
||||
* @param[in] p_element Pointer to the element.
|
||||
*
|
||||
* @return Pointer to the beginning of the block.
|
||||
*/
|
||||
__STATIC_INLINE void * nrf_balloc_element_wrap(nrf_balloc_t const * p_pool, void * p_element)
|
||||
{
|
||||
ASSERT((p_pool != NULL) && ((p_pool->block_size % sizeof(uint32_t)) == 0));
|
||||
ASSERT((p_element != NULL) && (((uint32_t)(p_element) % sizeof(uint32_t)) == 0));
|
||||
|
||||
uint32_t head_words = NRF_BALLOC_DEBUG_HEAD_GUARD_WORDS_GET(p_pool->debug_flags);
|
||||
uint32_t tail_words = NRF_BALLOC_DEBUG_TAIL_GUARD_WORDS_GET(p_pool->debug_flags);
|
||||
|
||||
uint32_t * p_head = (uint32_t *)p_element - head_words;
|
||||
uint32_t * p_tail = (uint32_t *)((size_t)(p_head) + p_pool->block_size);
|
||||
|
||||
for (uint32_t * ptr = p_head; ptr < (uint32_t *)p_element; ptr++)
|
||||
{
|
||||
if (*ptr != HEAD_GUARD_FILL)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_pool->p_log,
|
||||
"Detected Head Guard corruption at 0x%08X (0x%08X != 0x%08X)",
|
||||
ptr, *ptr, HEAD_GUARD_FILL);
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t * ptr = ( p_tail - tail_words); ptr < p_tail; ptr++)
|
||||
{
|
||||
if (*ptr != TAIL_GUARD_FILL)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_pool->p_log,
|
||||
"Detected Tail Guard corruption at 0x%08X (0x%08X != 0x%08X)",
|
||||
ptr, *ptr, TAIL_GUARD_FILL);
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (NRF_BALLOC_DEBUG_DATA_TRASHING_CHECK_GET(p_pool->debug_flags))
|
||||
{
|
||||
for (uint32_t * ptr = p_head; ptr < p_tail; ptr++)
|
||||
{
|
||||
*ptr = FREE_MEM_FILL;
|
||||
}
|
||||
}
|
||||
|
||||
return p_head;
|
||||
}
|
||||
|
||||
#endif // NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
|
||||
/**@brief Convert block index to a pointer.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool.
|
||||
* @param[in] idx Index of the block.
|
||||
*
|
||||
* @return Pointer to the beginning of the block.
|
||||
*/
|
||||
static void * nrf_balloc_idx2block(nrf_balloc_t const * p_pool, uint8_t idx)
|
||||
{
|
||||
ASSERT(p_pool != NULL);
|
||||
return (uint8_t *)(p_pool->p_memory_begin) + ((size_t)(idx) * p_pool->block_size);
|
||||
}
|
||||
|
||||
/**@brief Convert block pointer to index.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool.
|
||||
* @param[in] p_block Pointer to the beginning of the block.
|
||||
*
|
||||
* @return Index of the block.
|
||||
*/
|
||||
static uint8_t nrf_balloc_block2idx(nrf_balloc_t const * p_pool, void const * p_block)
|
||||
{
|
||||
ASSERT(p_pool != NULL);
|
||||
return ((size_t)(p_block) - (size_t)(p_pool->p_memory_begin)) / p_pool->block_size;
|
||||
}
|
||||
|
||||
ret_code_t nrf_balloc_init(nrf_balloc_t const * p_pool)
|
||||
{
|
||||
uint8_t pool_size;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_pool);
|
||||
|
||||
ASSERT(p_pool->p_cb);
|
||||
ASSERT(p_pool->p_stack_base);
|
||||
ASSERT(p_pool->p_stack_limit);
|
||||
ASSERT(p_pool->p_memory_begin);
|
||||
ASSERT(p_pool->block_size);
|
||||
|
||||
pool_size = p_pool->p_stack_limit - p_pool->p_stack_base;
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
void *p_memory_end = (uint8_t *)(p_pool->p_memory_begin) + (pool_size * p_pool->block_size);
|
||||
if (NRF_BALLOC_DEBUG_DATA_TRASHING_CHECK_GET(p_pool->debug_flags))
|
||||
{
|
||||
for (uint32_t * ptr = p_pool->p_memory_begin; ptr < (uint32_t *)(p_memory_end); ptr++)
|
||||
{
|
||||
*ptr = FREE_MEM_FILL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NRF_LOG_INST_INFO(p_pool->p_log, "Initialized (size: %u x %u = %u bytes)",
|
||||
pool_size,
|
||||
p_pool->block_size,
|
||||
pool_size * p_pool->block_size);
|
||||
|
||||
p_pool->p_cb->p_stack_pointer = p_pool->p_stack_base;
|
||||
while (pool_size--)
|
||||
{
|
||||
*(p_pool->p_cb->p_stack_pointer)++ = pool_size;
|
||||
}
|
||||
|
||||
p_pool->p_cb->max_utilization = 0;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
void * nrf_balloc_alloc(nrf_balloc_t const * p_pool)
|
||||
{
|
||||
ASSERT(p_pool != NULL);
|
||||
|
||||
void * p_block = NULL;
|
||||
|
||||
CRITICAL_REGION_ENTER();
|
||||
|
||||
if (p_pool->p_cb->p_stack_pointer > p_pool->p_stack_base)
|
||||
{
|
||||
// Allocate block.
|
||||
p_block = nrf_balloc_idx2block(p_pool, *--(p_pool->p_cb->p_stack_pointer));
|
||||
|
||||
// Update utilization statistics.
|
||||
uint8_t utilization = p_pool->p_stack_limit - p_pool->p_cb->p_stack_pointer;
|
||||
if (p_pool->p_cb->max_utilization < utilization)
|
||||
{
|
||||
p_pool->p_cb->max_utilization = utilization;
|
||||
}
|
||||
}
|
||||
|
||||
CRITICAL_REGION_EXIT();
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
if (p_block != NULL)
|
||||
{
|
||||
p_block = nrf_balloc_block_unwrap(p_pool, p_block);
|
||||
}
|
||||
#endif
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_pool->p_log, "Allocating element: 0x%08X", p_block);
|
||||
|
||||
return p_block;
|
||||
}
|
||||
|
||||
void nrf_balloc_free(nrf_balloc_t const * p_pool, void * p_element)
|
||||
{
|
||||
ASSERT(p_pool != NULL);
|
||||
ASSERT(p_element != NULL)
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_pool->p_log, "Freeing element: 0x%08X", p_element);
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
void * p_block = nrf_balloc_element_wrap(p_pool, p_element);
|
||||
|
||||
// These checks could be done outside critical region as they use only pool configuration data.
|
||||
if (NRF_BALLOC_DEBUG_BASIC_CHECKS_GET(p_pool->debug_flags))
|
||||
{
|
||||
uint8_t pool_size = p_pool->p_stack_limit - p_pool->p_stack_base;
|
||||
void *p_memory_end = (uint8_t *)(p_pool->p_memory_begin) + (pool_size * p_pool->block_size);
|
||||
|
||||
// Check if the element belongs to this pool.
|
||||
if ((p_block < p_pool->p_memory_begin) || (p_block >= p_memory_end))
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_pool->p_log,
|
||||
"Attempted to free element (0x%08X) that does not belong to the pool.",
|
||||
p_element);
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
|
||||
// Check if the pointer is valid.
|
||||
if ((((size_t)(p_block) - (size_t)(p_pool->p_memory_begin)) % p_pool->block_size) != 0)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_pool->p_log,
|
||||
"Attempted to free corrupted element address (0x%08X).", p_element);
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void * p_block = p_element;
|
||||
#endif // NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
|
||||
CRITICAL_REGION_ENTER();
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
// These checks have to be done in critical region as they use p_pool->p_stack_pointer.
|
||||
if (NRF_BALLOC_DEBUG_BASIC_CHECKS_GET(p_pool->debug_flags))
|
||||
{
|
||||
// Check for allocated/free ballance.
|
||||
if (p_pool->p_cb->p_stack_pointer >= p_pool->p_stack_limit)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_pool->p_log,
|
||||
"Attempted to free an element (0x%08X) while the pool is full.",
|
||||
p_element);
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (NRF_BALLOC_DEBUG_DOUBLE_FREE_CHECK_GET(p_pool->debug_flags))
|
||||
{
|
||||
// Check for double free.
|
||||
for (uint8_t * p_idx = p_pool->p_stack_base; p_idx < p_pool->p_cb->p_stack_pointer; p_idx++)
|
||||
{
|
||||
if (nrf_balloc_idx2block(p_pool, *p_idx) == p_block)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_pool->p_log, "Attempted to double-free an element (0x%08X).",
|
||||
p_element);
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
|
||||
// Free the element.
|
||||
*(p_pool->p_cb->p_stack_pointer)++ = nrf_balloc_block2idx(p_pool, p_block);
|
||||
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(NRF_BALLOC)
|
||||
351
components/libraries/balloc/nrf_balloc.h
Normal file
351
components/libraries/balloc/nrf_balloc.h
Normal file
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @defgroup nrf_balloc Block memory allocator
|
||||
* @{
|
||||
* @ingroup app_common
|
||||
* @brief This module handles block memory allocator features.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NRF_BALLOC_H__
|
||||
#define NRF_BALLOC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdk_errors.h"
|
||||
#include "sdk_config.h"
|
||||
#include "app_util_platform.h"
|
||||
#include "app_util.h"
|
||||
#include "nrf_log_instance.h"
|
||||
#include "nrf_section.h"
|
||||
|
||||
/** @brief Name of the module used for logger messaging.
|
||||
*/
|
||||
#define NRF_BALLOC_LOG_NAME balloc
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED || NRF_BALLOC_CLI_CMDS
|
||||
#define NRF_BALLOC_HAS_NAME 1
|
||||
#else
|
||||
#define NRF_BALLOC_HAS_NAME 0
|
||||
#endif
|
||||
|
||||
/**@defgroup NRF_BALLOC_DEBUG Macros for preparing debug flags for block allocator module.
|
||||
* @{ */
|
||||
#define NRF_BALLOC_DEBUG_HEAD_GUARD_WORDS_SET(words) (((words) & 0xFF) << 0)
|
||||
#define NRF_BALLOC_DEBUG_HEAD_GUARD_WORDS_GET(flags) (((flags) >> 0) & 0xFF)
|
||||
#define NRF_BALLOC_DEBUG_TAIL_GUARD_WORDS_SET(words) (((words) & 0xFF) << 8)
|
||||
#define NRF_BALLOC_DEBUG_TAIL_GUARD_WORDS_GET(flags) (((flags) >> 8) & 0xFF)
|
||||
|
||||
#define NRF_BALLOC_DEBUG_BASIC_CHECKS_SET(enable) (!!(enable) << 16)
|
||||
#define NRF_BALLOC_DEBUG_BASIC_CHECKS_GET(flags) (flags & (1 << 16))
|
||||
#define NRF_BALLOC_DEBUG_DOUBLE_FREE_CHECK_SET(enable) (!!(enable) << 17)
|
||||
#define NRF_BALLOC_DEBUG_DOUBLE_FREE_CHECK_GET(flags) (flags & (1 << 17))
|
||||
#define NRF_BALLOC_DEBUG_DATA_TRASHING_CHECK_SET(enable) (!!(enable) << 18)
|
||||
#define NRF_BALLOC_DEBUG_DATA_TRASHING_CHECK_GET(flags) (flags & (1 << 18))
|
||||
/**@} */
|
||||
|
||||
/**@brief Default debug flags for @ref nrf_balloc. This is used by the @ref NRF_BALLOC_DEF macro.
|
||||
* Flags can be changed in @ref sdk_config.
|
||||
*/
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
#define NRF_BALLOC_DEFAULT_DEBUG_FLAGS \
|
||||
( \
|
||||
NRF_BALLOC_DEBUG_HEAD_GUARD_WORDS_SET(NRF_BALLOC_CONFIG_HEAD_GUARD_WORDS) | \
|
||||
NRF_BALLOC_DEBUG_TAIL_GUARD_WORDS_SET(NRF_BALLOC_CONFIG_TAIL_GUARD_WORDS) | \
|
||||
NRF_BALLOC_DEBUG_BASIC_CHECKS_SET(NRF_BALLOC_CONFIG_BASIC_CHECKS_ENABLED) | \
|
||||
NRF_BALLOC_DEBUG_DOUBLE_FREE_CHECK_SET(NRF_BALLOC_CONFIG_DOUBLE_FREE_CHECK_ENABLED) | \
|
||||
NRF_BALLOC_DEBUG_DATA_TRASHING_CHECK_SET(NRF_BALLOC_CONFIG_DATA_TRASHING_CHECK_ENABLED) \
|
||||
)
|
||||
#else
|
||||
#define NRF_BALLOC_DEFAULT_DEBUG_FLAGS 0
|
||||
#endif // NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
|
||||
/**@brief Block memory allocator control block.*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t * p_stack_pointer; //!< Current allocation stack pointer.
|
||||
uint8_t max_utilization; //!< Maximum utilization of the memory pool.
|
||||
} nrf_balloc_cb_t;
|
||||
|
||||
/**@brief Block memory allocator pool instance. The pool is made of elements of the same size. */
|
||||
typedef struct
|
||||
{
|
||||
nrf_balloc_cb_t * p_cb; //!< Pointer to the instance control block.
|
||||
uint8_t * p_stack_base; //!< Base of the allocation stack.
|
||||
/**<
|
||||
* Stack is used to store handlers to not allocated elements.
|
||||
*/
|
||||
uint8_t * p_stack_limit; //!< Maximum possible value of the allocation stack pointer.
|
||||
void * p_memory_begin; //!< Pointer to the start of the memory pool.
|
||||
/**<
|
||||
* Memory is used as a heap for blocks.
|
||||
*/
|
||||
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
|
||||
#if NRF_BALLOC_HAS_NAME
|
||||
const char * p_name; //!< Pointer to string with pool name.
|
||||
#endif
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
uint32_t debug_flags; //!< Debugging settings.
|
||||
/**<
|
||||
* Debug flag should be created by @ref NRF_BALLOC_DEBUG.
|
||||
*/
|
||||
#endif // NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
uint16_t block_size; //!< Size of the allocated block (including debug overhead).
|
||||
/**<
|
||||
* Single block contains user element with header and tail
|
||||
* words.
|
||||
*/
|
||||
} nrf_balloc_t;
|
||||
|
||||
/**@brief Get total memory consumed by single block (element size with overhead caused by debug
|
||||
* flags).
|
||||
*
|
||||
* @param[in] _element_size Size of an element.
|
||||
* @param[in] _debug_flags Debug flags.
|
||||
*/
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
#define NRF_BALLOC_BLOCK_SIZE(_element_size, _debug_flags) \
|
||||
( \
|
||||
(sizeof(uint32_t) * NRF_BALLOC_DEBUG_HEAD_GUARD_WORDS_GET(_debug_flags)) + \
|
||||
ALIGN_NUM(sizeof(uint32_t), (_element_size)) + \
|
||||
(sizeof(uint32_t) * NRF_BALLOC_DEBUG_TAIL_GUARD_WORDS_GET(_debug_flags)) \
|
||||
)
|
||||
#else
|
||||
#define NRF_BALLOC_BLOCK_SIZE(_element_size, _debug_flags) \
|
||||
ALIGN_NUM(sizeof(uint32_t), (_element_size))
|
||||
#endif // NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
|
||||
|
||||
/**@brief Get element size ( excluding debugging overhead is present)
|
||||
* flags).
|
||||
*
|
||||
* @param[in] _p_balloc Pointer to balloc instance.
|
||||
*/
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
#define NRF_BALLOC_ELEMENT_SIZE(_p_balloc) \
|
||||
(ALIGN_NUM(sizeof(uint32_t), (_p_balloc)->block_size) - \
|
||||
((sizeof(uint32_t) * NRF_BALLOC_DEBUG_HEAD_GUARD_WORDS_GET((_p_balloc)->debug_flags)) + \
|
||||
(sizeof(uint32_t) * NRF_BALLOC_DEBUG_TAIL_GUARD_WORDS_GET((_p_balloc)->debug_flags))))
|
||||
#else
|
||||
#define NRF_BALLOC_ELEMENT_SIZE(_p_balloc) \
|
||||
(_p_balloc)->block_size
|
||||
#endif // NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
|
||||
#if NRF_BALLOC_CONFIG_DEBUG_ENABLED
|
||||
#define __NRF_BALLOC_ASSIGN_DEBUG_FLAGS(_debug_flags) .debug_flags = (_debug_flags),
|
||||
#else
|
||||
#define __NRF_BALLOC_ASSIGN_DEBUG_FLAGS(_debug_flags)
|
||||
#endif
|
||||
|
||||
#if NRF_BALLOC_HAS_NAME
|
||||
#define __NRF_BALLOC_ASSIGN_POOL_NAME(_name) .p_name = STRINGIFY(_name),
|
||||
#else
|
||||
#define __NRF_BALLOC_ASSIGN_POOL_NAME(_name)
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief Create a block allocator instance with custom debug flags.
|
||||
*
|
||||
* @note This macro reserves memory for the given block allocator instance.
|
||||
*
|
||||
* @param[in] _name Name of the allocator.
|
||||
* @param[in] _element_size Size of one element.
|
||||
* @param[in] _pool_size Size of the pool.
|
||||
* @param[in] _debug_flags Debug flags (@ref NRF_BALLOC_DEBUG).
|
||||
*/
|
||||
#define NRF_BALLOC_DBG_DEF(_name, _element_size, _pool_size, _debug_flags) \
|
||||
STATIC_ASSERT((_pool_size) <= UINT8_MAX); \
|
||||
static uint8_t CONCAT_2(_name, _nrf_balloc_pool_stack)[(_pool_size)]; \
|
||||
static uint32_t CONCAT_2(_name,_nrf_balloc_pool_mem) \
|
||||
[NRF_BALLOC_BLOCK_SIZE(_element_size, _debug_flags) * (_pool_size) / sizeof(uint32_t)]; \
|
||||
static nrf_balloc_cb_t CONCAT_2(_name,_nrf_balloc_cb); \
|
||||
NRF_LOG_INSTANCE_REGISTER(NRF_BALLOC_LOG_NAME, _name, \
|
||||
NRF_BALLOC_CONFIG_INFO_COLOR, \
|
||||
NRF_BALLOC_CONFIG_DEBUG_COLOR, \
|
||||
NRF_BALLOC_CONFIG_INITIAL_LOG_LEVEL, \
|
||||
NRF_BALLOC_CONFIG_LOG_ENABLED ? \
|
||||
NRF_BALLOC_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
|
||||
NRF_SECTION_ITEM_REGISTER(nrf_balloc, const nrf_balloc_t _name) = \
|
||||
{ \
|
||||
.p_cb = &CONCAT_2(_name,_nrf_balloc_cb), \
|
||||
.p_stack_base = CONCAT_2(_name,_nrf_balloc_pool_stack), \
|
||||
.p_stack_limit = CONCAT_2(_name,_nrf_balloc_pool_stack) + (_pool_size), \
|
||||
.p_memory_begin = CONCAT_2(_name,_nrf_balloc_pool_mem), \
|
||||
.block_size = NRF_BALLOC_BLOCK_SIZE(_element_size, _debug_flags), \
|
||||
\
|
||||
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_BALLOC_LOG_NAME, _name) \
|
||||
__NRF_BALLOC_ASSIGN_POOL_NAME(_name) \
|
||||
__NRF_BALLOC_ASSIGN_DEBUG_FLAGS(_debug_flags) \
|
||||
}
|
||||
|
||||
/**@brief Create a block allocator instance.
|
||||
*
|
||||
* @note This macro reserves memory for the given block allocator instance.
|
||||
*
|
||||
* @param[in] _name Name of the allocator.
|
||||
* @param[in] _element_size Size of one element.
|
||||
* @param[in] _pool_size Size of the pool.
|
||||
*/
|
||||
#define NRF_BALLOC_DEF(_name, _element_size, _pool_size) \
|
||||
NRF_BALLOC_DBG_DEF(_name, _element_size, _pool_size, NRF_BALLOC_DEFAULT_DEBUG_FLAGS)
|
||||
|
||||
/**@brief Create a block allocator interface.
|
||||
*
|
||||
* @param[in] _type Type which is allocated.
|
||||
* @param[in] _name Name of the allocator.
|
||||
*/
|
||||
#define NRF_BALLOC_INTERFACE_DEC(_type, _name) \
|
||||
_type * CONCAT_2(_name,_alloc)(void); \
|
||||
void CONCAT_2(_name,_free)(_type * p_element)
|
||||
|
||||
/**@brief Define a custom block allocator interface.
|
||||
*
|
||||
* @param[in] _attr Function attribute that will be added to allocator function definition.
|
||||
* @param[in] _type Type which is allocated.
|
||||
* @param[in] _name Name of the allocator.
|
||||
* @param[in] _p_pool Pool from which data will be allocated.
|
||||
*/
|
||||
#define NRF_BALLOC_INTERFACE_CUSTOM_DEF(_attr, _type, _name, _p_pool) \
|
||||
_attr _type * CONCAT_2(_name,_alloc)(void) \
|
||||
{ \
|
||||
GCC_PRAGMA("GCC diagnostic push") \
|
||||
GCC_PRAGMA("GCC diagnostic ignored \"-Waddress\"") \
|
||||
ASSERT((_p_pool) != NULL); \
|
||||
ASSERT((_p_pool)->block_size >= \
|
||||
NRF_BALLOC_BLOCK_SIZE(sizeof(_type), (_p_pool)->debug_flags)); \
|
||||
GCC_PRAGMA("GCC diagnostic pop") \
|
||||
return (_type *)(nrf_balloc_alloc(_p_pool)); \
|
||||
} \
|
||||
\
|
||||
_attr void CONCAT_2(_name,_free)(_type * p_element) \
|
||||
{ \
|
||||
GCC_PRAGMA("GCC diagnostic push") \
|
||||
GCC_PRAGMA("GCC diagnostic ignored \"-Waddress\"") \
|
||||
ASSERT((_p_pool) != NULL); \
|
||||
ASSERT((_p_pool)->block_size >= \
|
||||
NRF_BALLOC_BLOCK_SIZE(sizeof(_type), (_p_pool)->debug_flags)); \
|
||||
GCC_PRAGMA("GCC diagnostic pop") \
|
||||
nrf_balloc_free((_p_pool), p_element); \
|
||||
}
|
||||
|
||||
/**@brief Define block allocator interface.
|
||||
*
|
||||
* @param[in] _type Type which is allocated.
|
||||
* @param[in] _name Name of the allocator.
|
||||
* @param[in] _p_pool Pool from which data will be allocated.
|
||||
*/
|
||||
#define NRF_BALLOC_INTERFACE_DEF(_type, _name, _p_pool) \
|
||||
NRF_BALLOC_INTERFACE_CUSTOM_DEF(/* empty */, _type, _name, _p_pool)
|
||||
|
||||
/**@brief Define a local block allocator interface.
|
||||
*
|
||||
* @param[in] _type Type which is allocated.
|
||||
* @param[in] _name Name of the allocator.
|
||||
* @param[in] _p_pool Pool from which data will be allocated.
|
||||
*/
|
||||
#define NRF_BALLOC_INTERFACE_LOCAL_DEF(_type, _name, _p_pool) \
|
||||
NRF_BALLOC_INTERFACE_CUSTOM_DEF(static, _type, _name, _p_pool)
|
||||
|
||||
/**@brief Function for initializing a block memory allocator pool.
|
||||
*
|
||||
* @param[out] p_pool Pointer to the pool that is to be initialized.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise error code.
|
||||
*/
|
||||
ret_code_t nrf_balloc_init(nrf_balloc_t const * p_pool);
|
||||
|
||||
/**@brief Function for allocating an element from the pool.
|
||||
*
|
||||
* @note This module guarantees that the returned memory is aligned to 4.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool from which the element will be allocated.
|
||||
*
|
||||
* @return Allocated element or NULL if the specified pool is empty.
|
||||
*/
|
||||
void * nrf_balloc_alloc(nrf_balloc_t const * p_pool);
|
||||
|
||||
/**@brief Function for freeing an element back to the pool.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool.
|
||||
* @param[in] p_element Element to be freed.
|
||||
*/
|
||||
void nrf_balloc_free(nrf_balloc_t const * p_pool, void * p_element);
|
||||
|
||||
/**@brief Function for getting maximum memory pool utilization.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool instance.
|
||||
*
|
||||
* @return Maximum number of elements allocated from the pool.
|
||||
*/
|
||||
__STATIC_INLINE uint8_t nrf_balloc_max_utilization_get(nrf_balloc_t const * p_pool);
|
||||
|
||||
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
|
||||
__STATIC_INLINE uint8_t nrf_balloc_max_utilization_get(nrf_balloc_t const * p_pool)
|
||||
{
|
||||
ASSERT(p_pool != NULL);
|
||||
return p_pool->p_cb->max_utilization;
|
||||
}
|
||||
#endif //SUPPRESS_INLINE_IMPLEMENTATION
|
||||
|
||||
/**@brief Function for getting current memory pool utilization.
|
||||
*
|
||||
* @param[in] p_pool Pointer to the memory pool instance.
|
||||
*
|
||||
* @return Maximum number of elements allocated from the pool.
|
||||
*/
|
||||
__STATIC_INLINE uint8_t nrf_balloc_utilization_get(nrf_balloc_t const * p_pool);
|
||||
|
||||
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
|
||||
__STATIC_INLINE uint8_t nrf_balloc_utilization_get(nrf_balloc_t const * p_pool)
|
||||
{
|
||||
ASSERT(p_pool != NULL);
|
||||
return (p_pool->p_stack_limit - p_pool->p_cb->p_stack_pointer);
|
||||
}
|
||||
#endif //SUPPRESS_INLINE_IMPLEMENTATION
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_BALLOC_H__
|
||||
/** @} */
|
||||
269
components/libraries/block_dev/empty/nrf_block_dev_empty.c
Normal file
269
components/libraries/block_dev/empty/nrf_block_dev_empty.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_BLOCK_DEV_EMPTY)
|
||||
#include "nrf_block_dev_empty.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @ingroup nrf_block_dev
|
||||
* @{
|
||||
*
|
||||
* @brief This module implements block device API. It would behave like:
|
||||
* - /dev/empty for write operations
|
||||
* - /dev/zero for read operations
|
||||
*/
|
||||
|
||||
#if NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_BLOCK_DEV_EMPTY_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_BLOCK_DEV_EMPTY_CONFIG_DEBUG_COLOR
|
||||
#else
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif
|
||||
#include "nrf_log.h"
|
||||
|
||||
|
||||
static ret_code_t block_dev_empty_init(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ev_handler ev_handler,
|
||||
void const * p_context)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_empty_t const * p_empty_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
|
||||
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_empty_dev->p_log, "Init.");
|
||||
|
||||
/* Calculate block device geometry.... */
|
||||
p_work->geometry.blk_size = p_empty_dev->empty_config.block_size;
|
||||
p_work->geometry.blk_count = p_empty_dev->empty_config.block_count;
|
||||
p_work->p_context = p_context;
|
||||
p_work->ev_handler = ev_handler;
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_INIT,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_empty_uninit(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_empty_t const * p_empty_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
|
||||
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_empty_dev->p_log, "Uninit.");
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_UNINIT,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
memset(p_work, 0, sizeof(nrf_block_dev_empty_work_t));
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_empty_read_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
ASSERT(p_blk);
|
||||
nrf_block_dev_empty_t const * p_empty_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
|
||||
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(
|
||||
p_empty_dev->p_log,
|
||||
"Read req from block %"PRIu32" size %"PRIu32"(x%"PRIu32") to %"PRIXPTR,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
|
||||
p_blk->p_buff);
|
||||
|
||||
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(
|
||||
p_empty_dev->p_log,
|
||||
"Out of range read req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
|
||||
return NRF_ERROR_INVALID_ADDR;
|
||||
}
|
||||
|
||||
memset(p_blk->p_buff, 0, p_empty_dev->p_work->geometry.blk_size * p_blk->blk_count);
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
p_blk,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_empty_write_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
ASSERT(p_blk);
|
||||
nrf_block_dev_empty_t const * p_empty_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
|
||||
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(
|
||||
p_empty_dev->p_log,
|
||||
"Write req to block %"PRIu32" size %"PRIu32"(x%"PRIu32") from %"PRIXPTR,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
|
||||
p_blk->p_buff);
|
||||
|
||||
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(
|
||||
p_empty_dev->p_log,
|
||||
"Out of range write req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
|
||||
|
||||
return NRF_ERROR_INVALID_ADDR;
|
||||
}
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
p_blk,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_empty_ioctl(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ioctl_req_t req, void * p_data)
|
||||
{
|
||||
nrf_block_dev_empty_t const * p_empty_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
|
||||
switch (req)
|
||||
{
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
|
||||
{
|
||||
bool * p_flushing = p_data;
|
||||
NRF_LOG_INST_DEBUG(p_empty_dev, "IOCtl: Cache flush");
|
||||
if (p_flushing)
|
||||
{
|
||||
*p_flushing = false;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
|
||||
{
|
||||
if (p_data == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
|
||||
*pp_strings = &p_empty_dev->info_strings;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static nrf_block_dev_geometry_t const * block_dev_empty_geometry(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_empty_t const * p_empty_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
|
||||
nrf_block_dev_empty_work_t const * p_work = p_empty_dev->p_work;
|
||||
|
||||
return &p_work->geometry;
|
||||
}
|
||||
|
||||
const nrf_block_dev_ops_t nrf_block_device_empty_ops = {
|
||||
.init = block_dev_empty_init,
|
||||
.uninit = block_dev_empty_uninit,
|
||||
.read_req = block_dev_empty_read_req,
|
||||
.write_req = block_dev_empty_write_req,
|
||||
.ioctl = block_dev_empty_ioctl,
|
||||
.geometry = block_dev_empty_geometry,
|
||||
};
|
||||
|
||||
/** @} */
|
||||
#endif // NRF_MODULE_ENABLED(NRF_BLOCK_DEV_EMPTY)
|
||||
152
components/libraries/block_dev/empty/nrf_block_dev_empty.h
Normal file
152
components/libraries/block_dev/empty/nrf_block_dev_empty.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_BLOCK_DEV_EMPTY_H__
|
||||
#define NRF_BLOCK_DEV_EMPTY_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nrf_block_dev.h"
|
||||
#include "nrf_log_instance.h"
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_block_dev_empty Empty implementation
|
||||
* @ingroup nrf_block_dev
|
||||
*
|
||||
* This module implements block device API. It works like:
|
||||
* - /dev/empty for write operations
|
||||
* - /dev/zero for read operations
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief EMPTY block device operations
|
||||
* */
|
||||
extern const nrf_block_dev_ops_t nrf_block_device_empty_ops;
|
||||
|
||||
/**
|
||||
* @brief Work structure of EMPTY block device.
|
||||
*/
|
||||
typedef struct {
|
||||
nrf_block_dev_geometry_t geometry; //!< Block device geometry
|
||||
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
|
||||
void const * p_context; //!< Context handle passed to event handler
|
||||
} nrf_block_dev_empty_work_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief EMPTY block device config initializer (@ref nrf_block_dev_empty_config_t)
|
||||
*
|
||||
* @param blk_size Block size
|
||||
* @param blk_count Block count
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_EMPTY_CONFIG(blk_size, blk_count) { \
|
||||
.block_size = (blk_size), \
|
||||
.block_count = (blk_count) \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief EMPTY block device config
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t block_size; //!< Desired block size
|
||||
uint32_t block_count; //!< Desired block count
|
||||
} nrf_block_dev_empty_config_t;
|
||||
|
||||
/**
|
||||
* @brief EMPTY block device
|
||||
* */
|
||||
typedef struct {
|
||||
nrf_block_dev_t block_dev; //!< Block device
|
||||
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
|
||||
nrf_block_dev_empty_config_t empty_config; //!< EMPTY block device config
|
||||
nrf_block_dev_empty_work_t * p_work; //!< EMPTY block device work structure
|
||||
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
|
||||
} nrf_block_dev_empty_t;
|
||||
|
||||
/** @brief Name of the module used for logger messaging.
|
||||
*/
|
||||
#define NRF_BLOCK_DEV_EMPTY_LOG_NAME block_dev_empty
|
||||
|
||||
/**
|
||||
* @brief Defines a EMPTY block device.
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param config Configuration @ref nrf_block_dev_empty_config_t
|
||||
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_EMPTY_DEFINE(name, config, info) \
|
||||
static nrf_block_dev_empty_work_t CONCAT_2(name, _work); \
|
||||
NRF_LOG_INSTANCE_REGISTER(NRF_BLOCK_DEV_EMPTY_LOG_NAME, name, \
|
||||
NRF_BLOCK_DEV_EMPTY_CONFIG_INFO_COLOR, \
|
||||
NRF_BLOCK_DEV_EMPTY_CONFIG_DEBUG_COLOR, \
|
||||
NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_INIT_FILTER_LEVEL, \
|
||||
NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_ENABLED ? \
|
||||
NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
|
||||
static const nrf_block_dev_empty_t name = { \
|
||||
.block_dev = { .p_ops = &nrf_block_device_empty_ops }, \
|
||||
.info_strings = BRACKET_EXTRACT(info), \
|
||||
.empty_config = config, \
|
||||
.p_work = &CONCAT_2(name, _work), \
|
||||
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_BLOCK_DEV_EMPTY_LOG_NAME, name) \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns block device API handle from EMPTY block device.
|
||||
*
|
||||
* @param[in] p_blk_empty EMPTY block device
|
||||
* @return Block device handle
|
||||
*/
|
||||
static inline nrf_block_dev_t const *
|
||||
nrf_block_dev_empty_ops_get(nrf_block_dev_empty_t const * p_blk_empty)
|
||||
{
|
||||
return &p_blk_empty->block_dev;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_BLOCK_DEV_EMPTY_H__ */
|
||||
352
components/libraries/block_dev/nrf_block_dev.h
Normal file
352
components/libraries/block_dev/nrf_block_dev.h
Normal file
@@ -0,0 +1,352 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_BLOCK_DEV_H__
|
||||
#define NRF_BLOCK_DEV_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdk_common.h"
|
||||
#include "nrf_assert.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_block_dev Block device
|
||||
* @{
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief This module implements unified block device API. It could used as a middle layer between
|
||||
* filesystems and memories.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Block device request descriptor item.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t blk_id; //!< Block ID
|
||||
uint32_t blk_count; //!< Block count
|
||||
void * p_buff; //!< Data buffer
|
||||
} nrf_block_req_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper macro to create block device read/write request item
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param block_start Block number start
|
||||
* @param block_count Number of blocks
|
||||
* @param buff Buffer to read/write
|
||||
*/
|
||||
#define NRF_BLOCK_DEV_REQUEST(name, block_start, block_count, buff) \
|
||||
nrf_block_req_t name = { \
|
||||
.blk_id = block_start, \
|
||||
.blk_count = block_count, \
|
||||
.p_buff = buff, \
|
||||
}
|
||||
/**
|
||||
* @brief Block device events.
|
||||
*
|
||||
* Events are propagated when event handler is defined (@ref nrf_blk_dev_init)
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
NRF_BLOCK_DEV_EVT_INIT, /**< Passed to event handler when init is done*/
|
||||
NRF_BLOCK_DEV_EVT_UNINIT, /**< Passed to event handler when uninit is done*/
|
||||
NRF_BLOCK_DEV_EVT_BLK_READ_DONE, /**< Passed to event handler block read operation is done*/
|
||||
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE, /**< Passed to event handler block write operation is done*/
|
||||
} nrf_block_dev_event_type_t;
|
||||
|
||||
typedef enum {
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS = 0, /**< Operation completed succsefully*/
|
||||
NRF_BLOCK_DEV_RESULT_IO_ERROR, /**< I/O error*/
|
||||
NRF_BLOCK_DEV_RESULT_TIMEOUT, /**< Device timeout*/
|
||||
} nrf_block_dev_result_t;
|
||||
|
||||
/**
|
||||
* @brief Block device event
|
||||
* */
|
||||
typedef struct {
|
||||
nrf_block_dev_event_type_t ev_type; //!< Event type
|
||||
nrf_block_dev_result_t result; //!< Operation status
|
||||
nrf_block_req_t const * p_blk_req; //!< Block request
|
||||
void const * p_context; //!< Event context
|
||||
} nrf_block_dev_event_t;
|
||||
|
||||
struct nrf_block_dev_s;
|
||||
|
||||
/**
|
||||
* @brief Block device event handler.
|
||||
*
|
||||
* @param[in] p_blk_dev Block device handle
|
||||
* @param[in] p_event Block device event
|
||||
*/
|
||||
typedef void (* nrf_block_dev_ev_handler)(struct nrf_block_dev_s const * p_blk_dev,
|
||||
nrf_block_dev_event_t const * p_event);
|
||||
|
||||
/**
|
||||
* @brief Block device geometry
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t blk_count; //!< Block count
|
||||
uint32_t blk_size; //!< Block size
|
||||
} nrf_block_dev_geometry_t;
|
||||
|
||||
/**
|
||||
* @brief Block device information strings
|
||||
*/
|
||||
typedef struct {
|
||||
const char * p_vendor; //!< Vendor string
|
||||
const char * p_product; //!< Product string
|
||||
const char * p_revision; //!< Revision string
|
||||
} nrf_block_dev_info_strings_t;
|
||||
|
||||
/**
|
||||
* @brief Block device information config
|
||||
*
|
||||
* @param vendor Vendor string
|
||||
* @param product Product string
|
||||
* @param revision Revision string
|
||||
* */
|
||||
#define NFR_BLOCK_DEV_INFO_CONFIG(vendor, product, revision) ( { \
|
||||
.p_vendor = vendor, \
|
||||
.p_product = product, \
|
||||
.p_revision = revision, \
|
||||
})
|
||||
|
||||
/**
|
||||
* @brief Empty info string initializer
|
||||
* */
|
||||
#define NFR_BLOCK_DEV_INFO_CONFIG_EMPTY \
|
||||
NFR_BLOCK_DEV_INFO_CONFIG(NULL, NULL, NULL)
|
||||
|
||||
/**
|
||||
* @brief Block device IOCTL requests
|
||||
*/
|
||||
typedef enum {
|
||||
NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH = 0, /**< Cache flush IOCTL request*/
|
||||
NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS, /**< Get info strings IOCTL request*/
|
||||
} nrf_block_dev_ioctl_req_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper macro to get block device address from specific instance
|
||||
*
|
||||
* @param instance Block device instance
|
||||
* @param member Block device member name
|
||||
* */
|
||||
#define NRF_BLOCKDEV_BASE_ADDR(instance, member) &(instance).member
|
||||
|
||||
/**
|
||||
* @brief Block device API
|
||||
* */
|
||||
typedef struct nrf_block_dev_s {
|
||||
struct nrf_block_dev_ops_s {
|
||||
/**
|
||||
* @brief @ref nrf_blk_dev_init
|
||||
*/
|
||||
ret_code_t (*init)(struct nrf_block_dev_s const * p_blk_dev,
|
||||
nrf_block_dev_ev_handler ev_handler,
|
||||
void const * p_context);
|
||||
|
||||
/**
|
||||
* @brief @ref nrf_blk_dev_uninit
|
||||
*/
|
||||
ret_code_t (*uninit)(struct nrf_block_dev_s const * p_blk_dev);
|
||||
|
||||
/**
|
||||
* @brief @ref nrf_blk_dev_read_req
|
||||
*/
|
||||
ret_code_t (*read_req)(struct nrf_block_dev_s const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk);
|
||||
|
||||
/**
|
||||
* @brief @ref nrf_blk_dev_write_req
|
||||
*/
|
||||
ret_code_t (*write_req)(struct nrf_block_dev_s const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk);
|
||||
|
||||
/**
|
||||
* @brief @ref nrf_blk_dev_ioctl
|
||||
*/
|
||||
ret_code_t (*ioctl)(struct nrf_block_dev_s const * p_blk_dev,
|
||||
nrf_block_dev_ioctl_req_t req,
|
||||
void * p_data);
|
||||
|
||||
/**
|
||||
* @brief @ref nrf_blk_dev_geometry
|
||||
*/
|
||||
nrf_block_dev_geometry_t const * (*geometry)(struct nrf_block_dev_s const * p_blk_dev);
|
||||
} const * p_ops;
|
||||
} nrf_block_dev_t;
|
||||
|
||||
/**
|
||||
* @brief Internals of @ref nrf_block_dev_t
|
||||
* */
|
||||
typedef struct nrf_block_dev_ops_s nrf_block_dev_ops_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes a block device.
|
||||
*
|
||||
* @param[in] p_blk_dev Block device handle
|
||||
* @param[in] ev_handler Event handler (pass NULL to work in synchronous mode)
|
||||
* @param[in] p_context Context passed to event handler
|
||||
*
|
||||
* @return Standard error code
|
||||
*/
|
||||
static inline ret_code_t nrf_blk_dev_init(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ev_handler ev_handler,
|
||||
void const * p_context)
|
||||
{
|
||||
ASSERT(p_blk_dev->p_ops->init);
|
||||
return p_blk_dev->p_ops->init(p_blk_dev, ev_handler, p_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Un-initializes a block device.
|
||||
*
|
||||
* @param[in] p_blk_dev Block device handle
|
||||
*
|
||||
* @return Standard error code
|
||||
*/
|
||||
static inline ret_code_t nrf_blk_dev_uninit(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev->p_ops->uninit);
|
||||
return p_blk_dev->p_ops->uninit(p_blk_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Block read request.
|
||||
*
|
||||
* In synchronous mode this function will execute the read operation
|
||||
* and wait for its completion. In asynchronous mode the function will only request
|
||||
* the operation and return immediately. Then, the @ref NRF_BLOCK_DEV_EVT_BLK_READ_DONE
|
||||
* event will signal that operation has been completed and the specified buffer contains
|
||||
* valid data.
|
||||
*
|
||||
* @param[in] p_blk_dev Block device handle
|
||||
* @param[in] p_blk Block device request
|
||||
*
|
||||
* @return Standard error code
|
||||
*/
|
||||
static inline ret_code_t nrf_blk_dev_read_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev->p_ops->read_req);
|
||||
ASSERT(p_blk_dev->p_ops->geometry);
|
||||
|
||||
if (p_blk->blk_id >= p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return p_blk_dev->p_ops->read_req(p_blk_dev, p_blk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Block write request.
|
||||
*
|
||||
* In synchronous mode this function will execute the write operation
|
||||
* and wait for its completion. In asynchronous mode the function will only request
|
||||
* the operation and return immediately. Then, the @ref NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE
|
||||
* event will signal that operation has been completed and the specified buffer
|
||||
* can be freed.
|
||||
*
|
||||
* @param[in] p_blk_dev Block device handle
|
||||
* @param[in] p_blk Block device request
|
||||
*
|
||||
* @return Standard error code
|
||||
*/
|
||||
static inline ret_code_t nrf_blk_dev_write_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev->p_ops->write_req);
|
||||
ASSERT(p_blk_dev->p_ops->geometry);
|
||||
|
||||
if (p_blk->blk_id >= p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return p_blk_dev->p_ops->write_req(p_blk_dev, p_blk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IO control function.
|
||||
*
|
||||
* @param[in] p_blk_dev Block device handle
|
||||
* @param[in] req Block device ioctl request
|
||||
* @param[in] p_data Block device ioctl data
|
||||
*
|
||||
* @return Standard error code
|
||||
* */
|
||||
static inline ret_code_t nrf_blk_dev_ioctl(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ioctl_req_t req,
|
||||
void * p_data)
|
||||
{
|
||||
ASSERT(p_blk_dev->p_ops->ioctl);
|
||||
return p_blk_dev->p_ops->ioctl(p_blk_dev, req, p_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a geometry of a block device.
|
||||
*
|
||||
* @param[in] p_blk_dev Block device handle
|
||||
*
|
||||
* @return Block size and count @ref nrf_block_dev_geometry_t
|
||||
*/
|
||||
static inline nrf_block_dev_geometry_t const *
|
||||
nrf_blk_dev_geometry(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev->p_ops->geometry);
|
||||
return p_blk_dev->p_ops->geometry(p_blk_dev);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_BLOCK_DEV_H__ */
|
||||
|
||||
|
||||
829
components/libraries/block_dev/qspi/nrf_block_dev_qspi.c
Normal file
829
components/libraries/block_dev/qspi/nrf_block_dev_qspi.c
Normal file
@@ -0,0 +1,829 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_BLOCK_DEV_QSPI)
|
||||
#include "nrf_serial_flash_params.h"
|
||||
#include "nrf_block_dev_qspi.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @ingroup nrf_block_dev_qspi
|
||||
* @{
|
||||
*
|
||||
* @brief This module implements block device API. It should be used as a reference block device.
|
||||
*/
|
||||
|
||||
#if NRF_BLOCK_DEV_QSPI_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_BLOCK_DEV_QSPI_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_BLOCK_DEV_QSPI_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_BLOCK_DEV_QSPI_CONFIG_DEBUG_COLOR
|
||||
#else
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif
|
||||
#include "nrf_log.h"
|
||||
|
||||
#define QSPI_STD_CMD_WRSR 0x01 /**< Write status register command*/
|
||||
#define QSPI_STD_CMD_RSTEN 0x66 /**< Reset enable command*/
|
||||
#define QSPI_STD_CMD_RST 0x99 /**< Reset command*/
|
||||
#define QSPI_STD_CMD_READ_ID 0x9F /**< Read ID command*/
|
||||
|
||||
#define BD_PAGE_PROGRAM_SIZE 256 /**< Page program size (minimum block size)*/
|
||||
|
||||
#define BD_ERASE_UNIT_INVALID_ID 0xFFFFFFFF /**< Invalid erase unit number*/
|
||||
#define BD_ERASE_UNIT_ERASE_VAL 0xFFFFFFFF /**< Erased memory value*/
|
||||
|
||||
/**
|
||||
* @brief Block to erase unit translation
|
||||
*
|
||||
* @param blk_id Block index
|
||||
* @param blk_size Block size
|
||||
* */
|
||||
#define BD_BLOCK_TO_ERASEUNIT(blk_id, blk_size) \
|
||||
((blk_id) * (blk_size)) / (NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE)
|
||||
|
||||
/**
|
||||
* @brief Blocks per erase unit
|
||||
*
|
||||
* @param blk_size Block size
|
||||
* */
|
||||
#define BD_BLOCKS_PER_ERASEUNIT(blk_size) \
|
||||
(NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE / (blk_size))
|
||||
|
||||
|
||||
static ret_code_t block_dev_qspi_eunit_write(nrf_block_dev_qspi_t const * p_qspi_dev,
|
||||
nrf_block_req_t * p_blk_left);
|
||||
|
||||
|
||||
static void block_dev_qspi_read_from_eunit(nrf_block_dev_qspi_t const * p_qspi_dev)
|
||||
{
|
||||
nrf_block_dev_qspi_work_t const * p_work = p_qspi_dev->p_work;
|
||||
|
||||
/*In write-back mode data that we read might not be the same as in erase unit buffer*/
|
||||
uint32_t eunit_start = BD_BLOCK_TO_ERASEUNIT(p_work->req.blk_id,
|
||||
p_work->geometry.blk_size);
|
||||
|
||||
uint32_t eunit_end = BD_BLOCK_TO_ERASEUNIT(p_work->req.blk_id + p_work->req.blk_count,
|
||||
p_work->geometry.blk_size);
|
||||
|
||||
if ((eunit_start > p_work->erase_unit_idx) || (eunit_end < p_work->erase_unit_idx))
|
||||
{
|
||||
/*Do nothing. Read request doesn't hit current cached erase unit*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*Case 1: Copy data from start erase unit*/
|
||||
if (eunit_start == p_work->erase_unit_idx)
|
||||
{
|
||||
size_t blk = p_work->req.blk_id %
|
||||
BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size);
|
||||
size_t cnt = BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) - blk;
|
||||
size_t off = p_work->geometry.blk_size * blk;
|
||||
|
||||
if (cnt > p_work->req.blk_count)
|
||||
{
|
||||
cnt = p_work->req.blk_count;
|
||||
}
|
||||
|
||||
memcpy(p_work->req.p_buff,
|
||||
p_work->p_erase_unit_buff + off,
|
||||
cnt * p_work->geometry.blk_size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*Case 2: Copy data from end erase unit*/
|
||||
if (eunit_end == p_work->erase_unit_idx)
|
||||
{
|
||||
size_t cnt = (p_work->req.blk_id + p_work->req.blk_count) %
|
||||
BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size);
|
||||
size_t off = (p_work->erase_unit_idx * BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) -
|
||||
p_work->req.blk_id) * p_work->geometry.blk_size;
|
||||
|
||||
if (cnt > p_work->req.blk_count)
|
||||
{
|
||||
cnt = p_work->req.blk_count;
|
||||
}
|
||||
|
||||
memcpy((uint8_t *)p_work->req.p_buff + off,
|
||||
p_work->p_erase_unit_buff,
|
||||
cnt * p_work->geometry.blk_size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*Case 3: Copy data from eunit_start < p_work->erase_unit_idx < eunit_end*/
|
||||
size_t off = (p_work->erase_unit_idx * BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) -
|
||||
p_work->req.blk_id) * p_work->geometry.blk_size;
|
||||
|
||||
memcpy((uint8_t *)p_work->req.p_buff + off,
|
||||
p_work->p_erase_unit_buff,
|
||||
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Active QSPI block device handle. Only one instance.
|
||||
* */
|
||||
static nrf_block_dev_qspi_t const * m_active_qspi_dev;
|
||||
|
||||
static void qspi_handler(nrf_drv_qspi_evt_t event, void * p_context)
|
||||
{
|
||||
if (m_active_qspi_dev != p_context)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nrf_block_dev_qspi_t const * p_qspi_dev = p_context;
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
nrf_block_req_t * p_blk_left = &p_work->left_req;
|
||||
|
||||
switch (p_work->state)
|
||||
{
|
||||
case NRF_BLOCK_DEV_QSPI_STATE_READ_EXEC:
|
||||
{
|
||||
if (p_work->writeback_mode)
|
||||
{
|
||||
block_dev_qspi_read_from_eunit(p_qspi_dev);
|
||||
}
|
||||
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
&p_work->req,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(&p_qspi_dev->block_dev, &ev);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD:
|
||||
{
|
||||
ret_code_t ret;
|
||||
uint32_t erase_unit = BD_BLOCK_TO_ERASEUNIT(p_blk_left->blk_id,
|
||||
p_work->geometry.blk_size);
|
||||
UNUSED_VARIABLE(erase_unit);
|
||||
ASSERT(erase_unit == p_work->erase_unit_idx);
|
||||
|
||||
/* Check if block is in erase unit buffer*/
|
||||
ret = block_dev_qspi_eunit_write(p_qspi_dev, p_blk_left);
|
||||
ASSERT(ret == NRF_SUCCESS);
|
||||
UNUSED_VARIABLE(ret);
|
||||
break;
|
||||
}
|
||||
case NRF_BLOCK_DEV_QSPI_STATE_WRITE_ERASE:
|
||||
case NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC:
|
||||
{
|
||||
/*Clear last programmed block*/
|
||||
uint32_t block_to_program = __CLZ(__RBIT(p_work->erase_unit_dirty_blocks));
|
||||
|
||||
if (p_work->state == NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC)
|
||||
{
|
||||
p_work->erase_unit_dirty_blocks ^= 1u << block_to_program;
|
||||
}
|
||||
|
||||
if (p_work->erase_unit_dirty_blocks == 0)
|
||||
{
|
||||
if (p_work->left_req.blk_count)
|
||||
{
|
||||
/*Load next erase unit*/
|
||||
ret_code_t ret;
|
||||
uint32_t eunit = BD_BLOCK_TO_ERASEUNIT(p_blk_left->blk_id,
|
||||
p_work->geometry.blk_size);
|
||||
|
||||
p_work->erase_unit_idx = eunit;
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD;
|
||||
|
||||
ret = nrf_drv_qspi_read(p_work->p_erase_unit_buff,
|
||||
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE,
|
||||
p_work->erase_unit_idx *
|
||||
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
|
||||
UNUSED_VARIABLE(ret);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*All blocks are programmed. Call event handler if required.*/
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
|
||||
if (p_work->ev_handler && !p_work->cache_flushing)
|
||||
{
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
&p_work->req,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(&p_qspi_dev->block_dev, &ev);
|
||||
}
|
||||
|
||||
p_work->cache_flushing = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*Get next block to program from program mask*/
|
||||
block_to_program = __CLZ(__RBIT(p_work->erase_unit_dirty_blocks));
|
||||
uint32_t dst_address = (p_work->erase_unit_idx * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE) +
|
||||
(block_to_program * p_work->geometry.blk_size);
|
||||
|
||||
const void * p_src_address = p_work->p_erase_unit_buff +
|
||||
block_to_program * p_work->geometry.blk_size;
|
||||
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC;
|
||||
ret_code_t ret = nrf_drv_qspi_write(p_src_address,
|
||||
p_work->geometry.blk_size,
|
||||
dst_address);
|
||||
UNUSED_VARIABLE(ret);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_for_idle(nrf_block_dev_qspi_t const * p_qspi_dev)
|
||||
{
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
while (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
|
||||
{
|
||||
__WFI();
|
||||
}
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_qspi_init(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ev_handler ev_handler,
|
||||
void const * p_context)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_qspi_t const * p_qspi_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
nrf_drv_qspi_config_t const * p_qspi_cfg = &p_qspi_dev->qspi_bdev_config.qspi_config;
|
||||
|
||||
ret_code_t ret = NRF_SUCCESS;
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_qspi_dev->p_log, "Init");
|
||||
|
||||
if (p_qspi_dev->qspi_bdev_config.block_size % BD_PAGE_PROGRAM_SIZE)
|
||||
{
|
||||
/*Unsupported block size*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Unsupported block size because of program page size");
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE % p_qspi_dev->qspi_bdev_config.block_size)
|
||||
{
|
||||
/*Unsupported block size*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Unsupported block size because of erase unit size");
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (m_active_qspi_dev)
|
||||
{
|
||||
/* QSPI instance is BUSY*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot init because QSPI is busy");
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
ret = nrf_drv_qspi_init(p_qspi_cfg, qspi_handler, (void *)p_blk_dev);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI init error: %"PRIu32"", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nrf_qspi_cinstr_conf_t cinstr_cfg = {
|
||||
.opcode = QSPI_STD_CMD_RSTEN,
|
||||
.length = NRF_QSPI_CINSTR_LEN_1B,
|
||||
.io2_level = true,
|
||||
.io3_level = true,
|
||||
.wipwait = true,
|
||||
.wren = true
|
||||
};
|
||||
|
||||
/* Send reset enable */
|
||||
ret = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI reset enable command error: %"PRIu32"", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Send reset command */
|
||||
cinstr_cfg.opcode = QSPI_STD_CMD_RST;
|
||||
ret = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI reset command error: %"PRIu32"", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get 3 byte identification value */
|
||||
uint8_t rdid_buf[3] = {0, 0, 0};
|
||||
cinstr_cfg.opcode = QSPI_STD_CMD_READ_ID;
|
||||
cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_4B;
|
||||
ret = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, rdid_buf);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI get 3 byte id error: %"PRIu32"", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nrf_serial_flash_params_t const * serial_flash_id = nrf_serial_flash_params_get(rdid_buf);
|
||||
|
||||
if (!serial_flash_id)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI FLASH not supported");
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (serial_flash_id->erase_size != NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI FLASH erase unit size not supported");
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Calculate block device geometry.... */
|
||||
uint32_t blk_size = p_qspi_dev->qspi_bdev_config.block_size;
|
||||
uint32_t blk_count = serial_flash_id->size / p_qspi_dev->qspi_bdev_config.block_size;
|
||||
|
||||
if (!blk_count || (blk_count % BD_BLOCKS_PER_ERASEUNIT(blk_size)))
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI FLASH block size not supported");
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
p_work->geometry.blk_size = blk_size;
|
||||
p_work->geometry.blk_count = blk_count;
|
||||
p_work->p_context = p_context;
|
||||
p_work->ev_handler = ev_handler;
|
||||
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
|
||||
p_work->erase_unit_idx = BD_ERASE_UNIT_INVALID_ID;
|
||||
p_work->writeback_mode = (p_qspi_dev->qspi_bdev_config.flags &
|
||||
NRF_BLOCK_DEV_QSPI_FLAG_CACHE_WRITEBACK) != 0;
|
||||
m_active_qspi_dev = p_qspi_dev;
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_INIT,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_qspi_uninit(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_qspi_t const * p_qspi_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_qspi_dev->p_log, "Uninit");
|
||||
|
||||
if (m_active_qspi_dev != p_qspi_dev)
|
||||
{
|
||||
/* QSPI instance is BUSY*/
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
|
||||
{
|
||||
/* Previous asynchronous operation in progress*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot uninit because QSPI is busy");
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_UNINIT,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_DISABLED;
|
||||
nrf_drv_qspi_uninit();
|
||||
|
||||
memset(p_work, 0, sizeof(nrf_block_dev_qspi_work_t));
|
||||
m_active_qspi_dev = NULL;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_qspi_read_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
ASSERT(p_blk);
|
||||
nrf_block_dev_qspi_t const * p_qspi_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
|
||||
ret_code_t ret = NRF_SUCCESS;
|
||||
|
||||
NRF_LOG_INST_DEBUG(
|
||||
p_qspi_dev->p_log,
|
||||
"Read req from block %"PRIu32" size %"PRIu32"(x%"PRIu32") to %"PRIXPTR,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
|
||||
p_blk->p_buff);
|
||||
|
||||
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(
|
||||
p_qspi_dev->p_log,
|
||||
"Out of range read req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
|
||||
return NRF_ERROR_INVALID_ADDR;
|
||||
}
|
||||
|
||||
if (m_active_qspi_dev != p_qspi_dev)
|
||||
{
|
||||
/* QSPI instance is BUSY*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot read because QSPI is busy");
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
|
||||
{
|
||||
/* Previous asynchronous operation in progress*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot read because of ongoing previous operation");
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
p_work->left_req = *p_blk;
|
||||
p_work->req = *p_blk;
|
||||
nrf_block_req_t * p_blk_left = &p_work->left_req;
|
||||
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_READ_EXEC;
|
||||
ret = nrf_drv_qspi_read(p_blk_left->p_buff,
|
||||
p_blk_left->blk_count * p_work->geometry.blk_size,
|
||||
p_blk_left->blk_id * p_work->geometry.blk_size);
|
||||
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI read error: %"PRIu32"", ret);
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
p_blk_left->p_buff = NULL;
|
||||
p_blk_left->blk_count = 0;
|
||||
|
||||
if (!p_work->ev_handler && (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE))
|
||||
{
|
||||
/*Synchronous operation*/
|
||||
wait_for_idle(p_qspi_dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool block_dev_qspi_update_eunit(nrf_block_dev_qspi_t const * p_qspi_dev,
|
||||
size_t off,
|
||||
const void * p_src,
|
||||
size_t len)
|
||||
{
|
||||
ASSERT((len % sizeof(uint32_t)) == 0)
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
|
||||
uint32_t * p_dst32 = (uint32_t *)(p_work->p_erase_unit_buff + off);
|
||||
const uint32_t * p_src32 = p_src;
|
||||
|
||||
bool erase_required = false;
|
||||
len /= sizeof(uint32_t);
|
||||
|
||||
/*Do normal copying until erase unit is not required*/
|
||||
do
|
||||
{
|
||||
if (*p_dst32 != *p_src32)
|
||||
{
|
||||
if (*p_dst32 != BD_ERASE_UNIT_ERASE_VAL)
|
||||
{
|
||||
erase_required = true;
|
||||
}
|
||||
|
||||
/*Mark block as dirty*/
|
||||
p_work->erase_unit_dirty_blocks |= 1u << (off / p_work->geometry.blk_size);
|
||||
}
|
||||
|
||||
*p_dst32++ = *p_src32++;
|
||||
off += sizeof(uint32_t);
|
||||
} while (--len);
|
||||
|
||||
return erase_required;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_qspi_write_start(nrf_block_dev_qspi_t const * p_qspi_dev)
|
||||
{
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
|
||||
if (!p_work->erase_required)
|
||||
{
|
||||
/*Get first block to program from program mask*/
|
||||
uint32_t block_to_program = __CLZ(__RBIT(p_work->erase_unit_dirty_blocks));
|
||||
uint32_t dst_address = (p_work->erase_unit_idx * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE) +
|
||||
(block_to_program * p_work->geometry.blk_size);
|
||||
|
||||
const void * p_src_address = p_work->p_erase_unit_buff +
|
||||
block_to_program * p_work->geometry.blk_size;
|
||||
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC;
|
||||
return nrf_drv_qspi_write(p_src_address,
|
||||
p_work->geometry.blk_size,
|
||||
dst_address);
|
||||
}
|
||||
|
||||
/*Erase is required*/
|
||||
uint32_t address = (p_work->erase_unit_idx * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_WRITE_ERASE;
|
||||
p_work->erase_required = false;
|
||||
|
||||
return nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, address);
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_qspi_eunit_write(nrf_block_dev_qspi_t const * p_qspi_dev,
|
||||
nrf_block_req_t * p_blk_left)
|
||||
{
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
|
||||
size_t blk = p_blk_left->blk_id %
|
||||
BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size);
|
||||
size_t cnt = BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) - blk;
|
||||
size_t off = p_work->geometry.blk_size * blk;
|
||||
|
||||
if (cnt > p_blk_left->blk_count)
|
||||
{
|
||||
cnt = p_blk_left->blk_count;
|
||||
}
|
||||
|
||||
bool erase_required = block_dev_qspi_update_eunit(p_qspi_dev,
|
||||
off,
|
||||
p_blk_left->p_buff,
|
||||
cnt * p_work->geometry.blk_size);
|
||||
if (erase_required)
|
||||
{
|
||||
p_work->erase_required = true;
|
||||
}
|
||||
|
||||
p_blk_left->blk_count -= cnt;
|
||||
p_blk_left->blk_id += cnt;
|
||||
p_blk_left->p_buff = (uint8_t *)p_blk_left->p_buff + cnt * p_work->geometry.blk_size;
|
||||
|
||||
if (p_work->erase_required)
|
||||
{
|
||||
uint32_t blk_size = p_work->geometry.blk_size;
|
||||
p_work->erase_unit_dirty_blocks |= (1u << BD_BLOCKS_PER_ERASEUNIT(blk_size)) - 1;
|
||||
}
|
||||
|
||||
if (p_work->erase_unit_dirty_blocks == 0 || p_work->writeback_mode)
|
||||
{
|
||||
/*No dirty blocks detected. Write end.*/
|
||||
if (p_work->ev_handler && p_blk_left->blk_count == 0)
|
||||
{
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
&p_work->req,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
|
||||
p_work->ev_handler(&p_qspi_dev->block_dev, &ev);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return block_dev_qspi_write_start(p_qspi_dev);
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_qspi_write_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
ASSERT(p_blk);
|
||||
nrf_block_dev_qspi_t const * p_qspi_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
|
||||
ret_code_t ret = NRF_SUCCESS;
|
||||
|
||||
NRF_LOG_INST_DEBUG(
|
||||
p_qspi_dev->p_log,
|
||||
"Write req to block %"PRIu32" size %"PRIu32"(x%"PRIu32") from %"PRIXPTR,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
|
||||
p_blk->p_buff);
|
||||
|
||||
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(
|
||||
p_qspi_dev->p_log,
|
||||
"Out of range write req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
|
||||
return NRF_ERROR_INVALID_ADDR;
|
||||
}
|
||||
|
||||
if (m_active_qspi_dev != p_qspi_dev)
|
||||
{
|
||||
/* QSPI instance is BUSY*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot write because QSPI is busy");
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
|
||||
{
|
||||
/* Previous asynchronous operation in progress*/
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot write because of ongoing previous operation");
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
p_work->left_req = *p_blk;
|
||||
p_work->req = *p_blk;
|
||||
|
||||
nrf_block_req_t * p_blk_left = &p_work->left_req;
|
||||
|
||||
uint32_t erase_unit = BD_BLOCK_TO_ERASEUNIT(p_blk_left->blk_id,
|
||||
p_work->geometry.blk_size);
|
||||
|
||||
/* Check if block is in erase unit buffer*/
|
||||
if (erase_unit == p_work->erase_unit_idx)
|
||||
{
|
||||
ret = block_dev_qspi_eunit_write(p_qspi_dev, p_blk_left);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p_work->writeback_mode)
|
||||
{
|
||||
ret = block_dev_qspi_write_start(p_qspi_dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_work->erase_unit_idx = erase_unit;
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD;
|
||||
|
||||
ret = nrf_drv_qspi_read(p_work->p_erase_unit_buff,
|
||||
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE,
|
||||
erase_unit * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI write error: %"PRIu32"", ret);
|
||||
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!p_work->ev_handler && (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE))
|
||||
{
|
||||
/*Synchronous operation*/
|
||||
wait_for_idle(p_qspi_dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_qspi_ioctl(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ioctl_req_t req,
|
||||
void * p_data)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_qspi_t const * p_qspi_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
|
||||
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
|
||||
|
||||
switch (req)
|
||||
{
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
|
||||
{
|
||||
bool * p_flushing = p_data;
|
||||
NRF_LOG_INST_DEBUG(p_qspi_dev->p_log, "IOCtl: Cache flush");
|
||||
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
|
||||
{
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (!p_work->writeback_mode || p_work->erase_unit_dirty_blocks == 0)
|
||||
{
|
||||
if (p_flushing)
|
||||
{
|
||||
*p_flushing = false;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ret_code_t ret = block_dev_qspi_write_start(p_qspi_dev);
|
||||
if (ret == NRF_SUCCESS)
|
||||
{
|
||||
if (p_flushing)
|
||||
{
|
||||
*p_flushing = true;
|
||||
}
|
||||
p_work->cache_flushing = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
|
||||
{
|
||||
if (p_data == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
|
||||
*pp_strings = &p_qspi_dev->info_strings;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static nrf_block_dev_geometry_t const * block_dev_qspi_geometry(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_qspi_t const * p_qspi_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
|
||||
nrf_block_dev_qspi_work_t const * p_work = p_qspi_dev->p_work;
|
||||
|
||||
return &p_work->geometry;
|
||||
}
|
||||
|
||||
const nrf_block_dev_ops_t nrf_block_device_qspi_ops = {
|
||||
.init = block_dev_qspi_init,
|
||||
.uninit = block_dev_qspi_uninit,
|
||||
.read_req = block_dev_qspi_read_req,
|
||||
.write_req = block_dev_qspi_write_req,
|
||||
.ioctl = block_dev_qspi_ioctl,
|
||||
.geometry = block_dev_qspi_geometry,
|
||||
};
|
||||
|
||||
/** @} */
|
||||
#endif // NRF_MODULE_ENABLED(NRF_BLOCK_DEV_QSPI)
|
||||
185
components/libraries/block_dev/qspi/nrf_block_dev_qspi.h
Normal file
185
components/libraries/block_dev/qspi/nrf_block_dev_qspi.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_BLOCK_DEV_QSPI_H__
|
||||
#define NRF_BLOCK_DEV_QSPI_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nrf_block_dev.h"
|
||||
#include "nrf_drv_qspi.h"
|
||||
#include "nrf_log_instance.h"
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_block_dev_qspi QSPI implementation
|
||||
* @ingroup nrf_block_dev
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief QSPI block device operations
|
||||
* */
|
||||
extern const nrf_block_dev_ops_t nrf_block_device_qspi_ops;
|
||||
|
||||
/**
|
||||
* @brief QSPI block device internal erase unit buffer size
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE (4096)
|
||||
|
||||
/**
|
||||
* @brief Internal Block device state
|
||||
*/
|
||||
typedef enum {
|
||||
NRF_BLOCK_DEV_QSPI_STATE_DISABLED = 0, /**< QSPI block device state DISABLED */
|
||||
NRF_BLOCK_DEV_QSPI_STATE_IDLE, /**< QSPI block device state IDLE */
|
||||
NRF_BLOCK_DEV_QSPI_STATE_READ_EXEC, /**< QSPI block device state READ_EXEC */
|
||||
NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD, /**< QSPI block device state EUNIT_LOAD */
|
||||
NRF_BLOCK_DEV_QSPI_STATE_WRITE_ERASE, /**< QSPI block device state WRITE_ERASE */
|
||||
NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC, /**< QSPI block device state WRITE_EXEC */
|
||||
} nrf_block_dev_qspi_state_t;
|
||||
|
||||
/**
|
||||
* @brief Work structure of QSPI block device
|
||||
*/
|
||||
typedef struct {
|
||||
volatile nrf_block_dev_qspi_state_t state; //!< QSPI block device state
|
||||
|
||||
nrf_block_dev_geometry_t geometry; //!< Block device geometry
|
||||
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
|
||||
void const * p_context; //!< Context handle passed to event handler
|
||||
nrf_block_req_t req; //!< Block READ/WRITE request: original value
|
||||
nrf_block_req_t left_req; //!< Block READ/WRITE request: left value
|
||||
|
||||
bool cache_flushing; //!< QSPI cache flush in progress flag
|
||||
bool writeback_mode; //!< QSPI write-back mode flag
|
||||
bool erase_required; //!< QSPI erase required flag
|
||||
uint32_t erase_unit_idx; //!< QSPI erase unit index
|
||||
uint32_t erase_unit_dirty_blocks; //!< QSPI erase unit dirty blocks mask
|
||||
uint8_t p_erase_unit_buff[NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE]; //!< QSPI erase unit buffer (fixed value)
|
||||
} nrf_block_dev_qspi_work_t;
|
||||
|
||||
/**
|
||||
* @brief QSPI block device flags*/
|
||||
typedef enum {
|
||||
NRF_BLOCK_DEV_QSPI_FLAG_CACHE_WRITEBACK = (1u << 0) //!< Cache write-back mode enable flag
|
||||
} nrf_block_dev_qspi_flag_t;
|
||||
|
||||
/** @brief Name of the module used for logger messaging.
|
||||
*/
|
||||
#define NRF_BLOCK_DEV_QSPI_LOG_NAME block_dev_qspi
|
||||
|
||||
/**
|
||||
* @brief QSPI block device config initializer (@ref nrf_block_dev_qspi_config_t)
|
||||
*
|
||||
* @param blk_size Block size
|
||||
* @param blk_flags Block device flags, @ref nrf_block_dev_qspi_flag_t
|
||||
* @param qspi_drv_config QPSI driver config
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_QSPI_CONFIG(blk_size, blk_flags, qspi_drv_config) { \
|
||||
.block_size = (blk_size), \
|
||||
.flags = (blk_flags), \
|
||||
.qspi_config = qspi_drv_config \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QSPI block device config
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t block_size; //!< Desired block size
|
||||
uint32_t flags; //!< QSPI block device flags
|
||||
nrf_drv_qspi_config_t qspi_config; //!< QSPI configuration
|
||||
} nrf_block_dev_qspi_config_t;
|
||||
|
||||
/**
|
||||
* @brief QSPI block device
|
||||
* */
|
||||
typedef struct {
|
||||
nrf_block_dev_t block_dev; //!< Block device
|
||||
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
|
||||
nrf_block_dev_qspi_config_t qspi_bdev_config; //!< QSPI block device config
|
||||
nrf_block_dev_qspi_work_t * p_work; //!< QSPI block device work structure
|
||||
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
|
||||
} nrf_block_dev_qspi_t;
|
||||
|
||||
/**
|
||||
* @brief Defines a QSPI block device.
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param config Configuration @ref nrf_block_dev_qspi_config_t
|
||||
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_QSPI_DEFINE(name, config, info) \
|
||||
static nrf_block_dev_qspi_work_t CONCAT_2(name, _work); \
|
||||
NRF_LOG_INSTANCE_REGISTER(NRF_BLOCK_DEV_QSPI_LOG_NAME, name, \
|
||||
NRF_BLOCK_DEV_QSPI_CONFIG_INFO_COLOR, \
|
||||
NRF_BLOCK_DEV_QSPI_CONFIG_DEBUG_COLOR, \
|
||||
NRF_BLOCK_DEV_QSPI_CONFIG_LOG_INIT_FILTER_LEVEL, \
|
||||
NRF_BLOCK_DEV_QSPI_CONFIG_LOG_ENABLED ? \
|
||||
NRF_BLOCK_DEV_QSPI_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
|
||||
static const nrf_block_dev_qspi_t name = { \
|
||||
.block_dev = { .p_ops = &nrf_block_device_qspi_ops }, \
|
||||
.info_strings = BRACKET_EXTRACT(info), \
|
||||
.qspi_bdev_config = config, \
|
||||
.p_work = &CONCAT_2(name, _work), \
|
||||
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_BLOCK_DEV_QSPI_LOG_NAME, name) \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns block device API handle from QSPI block device.
|
||||
*
|
||||
* @param[in] p_blk_qspi QSPI block device
|
||||
* @return Block device handle
|
||||
*/
|
||||
static inline nrf_block_dev_t const *
|
||||
nrf_block_dev_qspi_ops_get(nrf_block_dev_qspi_t const * p_blk_qspi)
|
||||
{
|
||||
return &p_blk_qspi->block_dev;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_BLOCK_DEV_QSPI_H__ */
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_serial_flash_params.h"
|
||||
|
||||
static const nrf_serial_flash_params_t m_sflash_params[] = {
|
||||
{ /*MXIC MX25R6435F*/
|
||||
.read_id = { 0xC2, 0x28, 0x17 },
|
||||
.capabilities = 0x00,
|
||||
.size = 8 * 1024 * 1024,
|
||||
.erase_size = 4 * 1024,
|
||||
.program_size = 256,
|
||||
}
|
||||
};
|
||||
|
||||
nrf_serial_flash_params_t const * nrf_serial_flash_params_get(const uint8_t * p_read_id)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(m_sflash_params); ++i)
|
||||
{
|
||||
if (memcmp(m_sflash_params[i].read_id, p_read_id, sizeof(m_sflash_params[i].read_id)) == 0)
|
||||
{
|
||||
return &m_sflash_params[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_SERIAL_FLASH_PARAMS_H__
|
||||
#define NRF_SERIAL_FLASH_PARAMS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdk_common.h"
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_serial_flash_params Serial flash memory parameters
|
||||
* @ingroup nrf_block_dev
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Serial flash memory parameters
|
||||
* */
|
||||
typedef struct {
|
||||
uint8_t read_id[3]; //!< Read identification command (0x9F) result
|
||||
uint8_t capabilities; //!< Serial flash memory capabilities
|
||||
uint32_t size; //!< Serial flash memory size (bytes)
|
||||
uint32_t erase_size; //!< Serial flash memory erase unit size (bytes)
|
||||
uint32_t program_size; //!< Serial flash memory program size (bytes)
|
||||
} nrf_serial_flash_params_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns serial flash memory identification descriptor
|
||||
*
|
||||
* @param p_read_params Memory read identification command result
|
||||
*
|
||||
* @return Serial flash memory descriptor (NULL if not found)
|
||||
* */
|
||||
nrf_serial_flash_params_t const * nrf_serial_flash_params_get(const uint8_t * p_read_params);
|
||||
|
||||
/** @} */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_SERIAL_FLASH_PARAMS_H__ */
|
||||
244
components/libraries/block_dev/ram/nrf_block_dev_ram.c
Normal file
244
components/libraries/block_dev/ram/nrf_block_dev_ram.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_BLOCK_DEV_RAM)
|
||||
#include "nrf_block_dev_ram.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @ingroup nrf_block_dev
|
||||
* @{
|
||||
*
|
||||
* @brief This module implements block device API. It should be used as a reference block device.
|
||||
*/
|
||||
|
||||
#if NRF_BLOCK_DEV_RAM_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_BLOCK_DEV_RAM_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_BLOCK_DEV_RAM_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_INST_DEBUG_COLOR NRF_BLOCK_DEV_RAM_CONFIG_DEBUG_COLOR
|
||||
#else
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif
|
||||
#include "nrf_log.h"
|
||||
|
||||
static ret_code_t block_dev_ram_init(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ev_handler ev_handler,
|
||||
void const * p_context)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
|
||||
nrf_block_dev_ram_work_t * p_work = p_ram_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_ram_dev->p_log, "Init");
|
||||
/* Calculate block device geometry.... */
|
||||
p_work->geometry.blk_size = p_ram_dev->ram_config.block_size;
|
||||
p_work->geometry.blk_count = p_ram_dev->ram_config.size /
|
||||
p_ram_dev->ram_config.block_size;
|
||||
p_work->p_context = p_context;
|
||||
p_work->ev_handler = ev_handler;
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_INIT,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_ram_uninit(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
|
||||
nrf_block_dev_ram_work_t * p_work = p_ram_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_ram_dev->p_log, "Uninit");
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_UNINIT,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
memset(p_work, 0, sizeof(nrf_block_dev_ram_work_t));
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_ram_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk,
|
||||
nrf_block_dev_event_type_t event)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
ASSERT(p_blk);
|
||||
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
|
||||
nrf_block_dev_ram_config_t const * p_ram_config = &p_ram_dev->ram_config;
|
||||
nrf_block_dev_ram_work_t const * p_work = p_ram_dev->p_work;
|
||||
|
||||
NRF_LOG_INST_DEBUG(p_ram_dev->p_log,
|
||||
((event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ?
|
||||
"Read req from block %"PRIu32" size %"PRIu32"(x%"PRIu32") to %"PRIXPTR
|
||||
:
|
||||
"Write req to block %"PRIu32" size %"PRIu32"(x%"PRIu32") from %"PRIXPTR),
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
|
||||
p_blk->p_buff);
|
||||
|
||||
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
|
||||
{
|
||||
NRF_LOG_INST_ERROR(p_ram_dev->p_log,
|
||||
((event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ?
|
||||
"Out of range read req block %"PRIu32" count %"PRIu32" while max is %"PRIu32
|
||||
:
|
||||
"Out of range write req block %"PRIu32" count %"PRIu32", while max is %"PRIu32),
|
||||
p_blk->blk_id,
|
||||
p_blk->blk_count,
|
||||
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
|
||||
return NRF_ERROR_INVALID_ADDR;
|
||||
|
||||
}
|
||||
|
||||
/*Synchronous operation*/
|
||||
uint8_t * p_buff = p_ram_config->p_work_buffer;
|
||||
p_buff += p_blk->blk_id * p_work->geometry.blk_size;
|
||||
|
||||
const void * p_src = (event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ? p_buff : p_blk->p_buff;
|
||||
void * p_dst = (event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ? p_blk->p_buff : p_buff;
|
||||
|
||||
memcpy(p_dst, p_src, p_work->geometry.blk_size * p_blk->blk_count);
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/*Asynchronous operation (simulation)*/
|
||||
const nrf_block_dev_event_t ev = {
|
||||
event,
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS,
|
||||
p_blk,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_ram_read_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
return block_dev_ram_req(p_blk_dev, p_blk, NRF_BLOCK_DEV_EVT_BLK_READ_DONE);
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_ram_write_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
return block_dev_ram_req(p_blk_dev, p_blk, NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE);
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_ram_ioctl(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ioctl_req_t req,
|
||||
void * p_data)
|
||||
{
|
||||
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
|
||||
switch (req)
|
||||
{
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
|
||||
{
|
||||
bool * p_flushing = p_data;
|
||||
NRF_LOG_INST_DEBUG(p_ram_dev->p_log, "IOCtl: Cache flush");
|
||||
if (p_flushing)
|
||||
{
|
||||
*p_flushing = false;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
|
||||
{
|
||||
if (p_data == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
|
||||
*pp_strings = &p_ram_dev->info_strings;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
static nrf_block_dev_geometry_t const * block_dev_ram_geometry(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
|
||||
nrf_block_dev_ram_work_t const * p_work = p_ram_dev->p_work;
|
||||
|
||||
return &p_work->geometry;
|
||||
}
|
||||
|
||||
const nrf_block_dev_ops_t nrf_block_device_ram_ops = {
|
||||
.init = block_dev_ram_init,
|
||||
.uninit = block_dev_ram_uninit,
|
||||
.read_req = block_dev_ram_read_req,
|
||||
.write_req = block_dev_ram_write_req,
|
||||
.ioctl = block_dev_ram_ioctl,
|
||||
.geometry = block_dev_ram_geometry,
|
||||
};
|
||||
|
||||
/** @} */
|
||||
#endif // NRF_MODULE_ENABLED(NRF_BLOCK_DEV_RAM)
|
||||
152
components/libraries/block_dev/ram/nrf_block_dev_ram.h
Normal file
152
components/libraries/block_dev/ram/nrf_block_dev_ram.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_BLOCK_DEV_RAM_H__
|
||||
#define NRF_BLOCK_DEV_RAM_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nrf_block_dev.h"
|
||||
#include "nrf_log_instance.h"
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_block_dev_ram RAM implementation
|
||||
* @ingroup nrf_block_dev
|
||||
* @{
|
||||
|
||||
*
|
||||
* @brief This module implements block device API. It should be used as a reference block device.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief RAM block device operations
|
||||
* */
|
||||
extern const nrf_block_dev_ops_t nrf_block_device_ram_ops;
|
||||
|
||||
/**
|
||||
* @brief Work structure of RAM block device
|
||||
*/
|
||||
typedef struct {
|
||||
nrf_block_dev_geometry_t geometry; //!< Block device geometry
|
||||
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
|
||||
void const * p_context; //!< Context handle passed to event handler
|
||||
} nrf_block_dev_ram_work_t;
|
||||
|
||||
/** @brief Name of the module used for logger messaging.
|
||||
*/
|
||||
#define NRF_BLOCK_DEV_RAM_LOG_NAME block_dev_ram
|
||||
|
||||
/**
|
||||
* @brief RAM block device config initializer (@ref nrf_block_dev_ram_config_t)
|
||||
*
|
||||
* @param blk_size Block size
|
||||
* @param buffer RAM work buffer
|
||||
* @param buffer_size RAM work buffer size
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_RAM_CONFIG(blk_size, buffer, buffer_size) { \
|
||||
.block_size = (blk_size), \
|
||||
.p_work_buffer = (buffer), \
|
||||
.size = (buffer_size), \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ram block device config
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t block_size; //!< Desired block size
|
||||
void * p_work_buffer; //!< Ram work buffer
|
||||
size_t size; //!< Ram work buffer size
|
||||
} nrf_block_dev_ram_config_t;
|
||||
|
||||
/**
|
||||
* @brief Ram block device
|
||||
* */
|
||||
typedef struct {
|
||||
nrf_block_dev_t block_dev; //!< Block device
|
||||
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
|
||||
nrf_block_dev_ram_config_t ram_config; //!< Ram block device config
|
||||
nrf_block_dev_ram_work_t * p_work; //!< Ram block device work structure
|
||||
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
|
||||
} nrf_block_dev_ram_t;
|
||||
|
||||
/**
|
||||
* @brief Defines a RAM block device.
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param config Configuration @ref nrf_block_dev_ram_config_t
|
||||
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_RAM_DEFINE(name, config, info) \
|
||||
static nrf_block_dev_ram_work_t CONCAT_2(name, _work); \
|
||||
NRF_LOG_INSTANCE_REGISTER(NRF_BLOCK_DEV_RAM_LOG_NAME, name, \
|
||||
NRF_BLOCK_DEV_RAM_CONFIG_INFO_COLOR, \
|
||||
NRF_BLOCK_DEV_RAM_CONFIG_DEBUG_COLOR, \
|
||||
NRF_BLOCK_DEV_RAM_CONFIG_LOG_INIT_FILTER_LEVEL, \
|
||||
NRF_BLOCK_DEV_RAM_CONFIG_LOG_ENABLED ? \
|
||||
NRF_BLOCK_DEV_RAM_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
|
||||
static const nrf_block_dev_ram_t name = { \
|
||||
.block_dev = { .p_ops = &nrf_block_device_ram_ops }, \
|
||||
.info_strings = BRACKET_EXTRACT(info), \
|
||||
.ram_config = config, \
|
||||
.p_work = &CONCAT_2(name, _work), \
|
||||
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_BLOCK_DEV_RAM_LOG_NAME, name) \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns block device API handle from RAM block device.
|
||||
*
|
||||
* @param[in] p_blk_ram Ram block device
|
||||
* @return Block device handle
|
||||
*/
|
||||
static inline nrf_block_dev_t const *
|
||||
nrf_block_dev_ram_ops_get(nrf_block_dev_ram_t const * p_blk_ram)
|
||||
{
|
||||
return &p_blk_ram->block_dev;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_BLOCK_DEV_RAM_H__ */
|
||||
399
components/libraries/block_dev/sdc/nrf_block_dev_sdc.c
Normal file
399
components/libraries/block_dev/sdc/nrf_block_dev_sdc.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_block_dev_sdc.h"
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @ingroup nrf_block_dev_sdc
|
||||
* @{
|
||||
*
|
||||
* @brief This module implements block device API. It should be used as a reference block device.
|
||||
*/
|
||||
|
||||
|
||||
static volatile sdc_result_t m_last_result;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Active SDC block device handle. Only one instance.
|
||||
* */
|
||||
static nrf_block_dev_sdc_t const * m_active_sdc_dev;
|
||||
|
||||
static ret_code_t block_dev_sdc_uninit(nrf_block_dev_t const * p_blk_dev);
|
||||
|
||||
static void wait_func(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void sdc_wait()
|
||||
{
|
||||
while (app_sdc_busy_check())
|
||||
{
|
||||
wait_func();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sdc_handler(sdc_evt_t const * p_event)
|
||||
{
|
||||
m_last_result = p_event->result;
|
||||
nrf_block_dev_sdc_t const * p_sdc_dev = m_active_sdc_dev;
|
||||
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
|
||||
|
||||
switch (p_event->type)
|
||||
{
|
||||
case SDC_EVT_INIT:
|
||||
{
|
||||
if (p_event->result != SDC_SUCCESS)
|
||||
{
|
||||
nrf_block_dev_t const * block_dev = &(p_sdc_dev->block_dev);
|
||||
ret_code_t err_code = block_dev_sdc_uninit(block_dev);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
p_work->geometry.blk_count = app_sdc_info_get()->num_blocks;
|
||||
p_work->geometry.blk_size = SDC_SECTOR_SIZE;
|
||||
if (m_active_sdc_dev->p_work->ev_handler)
|
||||
{
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_INIT,
|
||||
((p_event->result == SDC_SUCCESS) ? \
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
p_work->ev_handler(&p_sdc_dev->block_dev, &ev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDC_EVT_READ:
|
||||
if (m_active_sdc_dev->p_work->ev_handler)
|
||||
{
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
|
||||
((p_event->result == SDC_SUCCESS) ? \
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
|
||||
&p_work->req,
|
||||
p_work->p_context
|
||||
};
|
||||
p_work->ev_handler(&p_sdc_dev->block_dev, &ev);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDC_EVT_WRITE:
|
||||
if (m_active_sdc_dev->p_work->ev_handler)
|
||||
{
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
|
||||
((p_event->result == SDC_SUCCESS) ? \
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
|
||||
&p_work->req,
|
||||
p_work->p_context
|
||||
};
|
||||
p_work->ev_handler(&p_sdc_dev->block_dev, &ev);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ret_code_t block_dev_sdc_init(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ev_handler ev_handler,
|
||||
void const * p_context)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_sdc_t const * p_sdc_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
|
||||
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
|
||||
|
||||
if (p_sdc_dev->sdc_bdev_config.block_size != SDC_SECTOR_SIZE)
|
||||
{
|
||||
/* Unsupported block size. */
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (m_active_sdc_dev)
|
||||
{
|
||||
/* SDC instance is busy. */
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
p_work->p_context = p_context;
|
||||
p_work->ev_handler = ev_handler;
|
||||
m_active_sdc_dev = p_sdc_dev;
|
||||
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
err_code = app_sdc_init(&p_sdc_dev->sdc_bdev_config.sdc_config, sdc_handler);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
if (!ev_handler)
|
||||
{
|
||||
/* Synchronous mode - wait for the card. */
|
||||
sdc_wait();
|
||||
err_code = ((m_last_result == SDC_SUCCESS) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
m_active_sdc_dev = NULL;
|
||||
|
||||
if (ev_handler)
|
||||
{
|
||||
/* Call the user handler with an error status. */
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_INIT,
|
||||
NRF_BLOCK_DEV_RESULT_IO_ERROR,
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_sdc_uninit(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_sdc_t const * p_sdc_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
|
||||
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
|
||||
|
||||
if (m_active_sdc_dev != p_sdc_dev)
|
||||
{
|
||||
/* SDC instance is busy. */
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (app_sdc_busy_check())
|
||||
{
|
||||
/* Previous asynchronous operation in progress. */
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
ret_code_t err_code = app_sdc_uninit();
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
/* Free the instance on success. */
|
||||
m_active_sdc_dev = NULL;
|
||||
}
|
||||
|
||||
if (p_work->ev_handler)
|
||||
{
|
||||
/* SDC uninitialization is a synchronous operation. Call event handler. */
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_UNINIT,
|
||||
((err_code == NRF_SUCCESS) ? \
|
||||
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
|
||||
NULL,
|
||||
p_work->p_context
|
||||
};
|
||||
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_sdc_read_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
ASSERT(p_blk);
|
||||
nrf_block_dev_sdc_t const * p_sdc_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
|
||||
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
|
||||
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
if (m_active_sdc_dev != p_sdc_dev)
|
||||
{
|
||||
/* SDC instance is busy. */
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (app_sdc_busy_check())
|
||||
{
|
||||
/* Previous asynchronous operation in progress. */
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
p_work->req = *p_blk;
|
||||
err_code = app_sdc_block_read(p_blk->p_buff, p_blk->blk_id, p_blk->blk_count);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
if (!p_work->ev_handler)
|
||||
{
|
||||
/* Synchronous mode - wait for the card. */
|
||||
sdc_wait();
|
||||
err_code = ((m_last_result == SDC_SUCCESS) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
if ((p_work->ev_handler) && (err_code != NRF_SUCCESS))
|
||||
{
|
||||
/* Call the user handler with an error status. */
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
|
||||
NRF_BLOCK_DEV_RESULT_IO_ERROR,
|
||||
&p_work->req,
|
||||
p_work->p_context
|
||||
};
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_sdc_write_req(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_req_t const * p_blk)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
ASSERT(p_blk);
|
||||
nrf_block_dev_sdc_t const * p_sdc_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
|
||||
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
|
||||
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
if (m_active_sdc_dev != p_sdc_dev)
|
||||
{
|
||||
/* SDC instance is busy. */
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (app_sdc_busy_check())
|
||||
{
|
||||
/* Previous asynchronous operation in progress. */
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
p_work->req = *p_blk;
|
||||
err_code = app_sdc_block_write(p_blk->p_buff, p_blk->blk_id, p_blk->blk_count);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
if (!p_work->ev_handler)
|
||||
{
|
||||
/* Synchronous mode - wait for the card. */
|
||||
sdc_wait();
|
||||
err_code = ((m_last_result == SDC_SUCCESS) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
if ((p_work->ev_handler) && (err_code != NRF_SUCCESS))
|
||||
{
|
||||
/* Call the user handler with an error status. */
|
||||
const nrf_block_dev_event_t ev = {
|
||||
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
|
||||
NRF_BLOCK_DEV_RESULT_IO_ERROR,
|
||||
&p_work->req,
|
||||
p_work->p_context
|
||||
};
|
||||
p_work->ev_handler(p_blk_dev, &ev);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t block_dev_sdc_ioctl(nrf_block_dev_t const * p_blk_dev,
|
||||
nrf_block_dev_ioctl_req_t req,
|
||||
void * p_data)
|
||||
{
|
||||
nrf_block_dev_sdc_t const * p_sdc_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
|
||||
switch (req)
|
||||
{
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
|
||||
{
|
||||
bool * p_flushing = p_data;
|
||||
if (p_flushing)
|
||||
{
|
||||
*p_flushing = false;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
|
||||
{
|
||||
if (p_data == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
|
||||
*pp_strings = &p_sdc_dev->info_strings;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static nrf_block_dev_geometry_t const * block_dev_sdc_geometry(nrf_block_dev_t const * p_blk_dev)
|
||||
{
|
||||
ASSERT(p_blk_dev);
|
||||
nrf_block_dev_sdc_t const * p_sdc_dev =
|
||||
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
|
||||
nrf_block_dev_sdc_work_t const * p_work = p_sdc_dev->p_work;
|
||||
|
||||
return &p_work->geometry;
|
||||
}
|
||||
|
||||
const nrf_block_dev_ops_t nrf_block_device_sdc_ops = {
|
||||
.init = block_dev_sdc_init,
|
||||
.uninit = block_dev_sdc_uninit,
|
||||
.read_req = block_dev_sdc_read_req,
|
||||
.write_req = block_dev_sdc_write_req,
|
||||
.ioctl = block_dev_sdc_ioctl,
|
||||
.geometry = block_dev_sdc_geometry,
|
||||
};
|
||||
|
||||
|
||||
/** @} */
|
||||
139
components/libraries/block_dev/sdc/nrf_block_dev_sdc.h
Normal file
139
components/libraries/block_dev/sdc/nrf_block_dev_sdc.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_block_dev_sdc SDC implementation
|
||||
* @ingroup nrf_block_dev
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NRF_BLOCK_DEV_SDC_H__
|
||||
#define NRF_BLOCK_DEV_SDC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nrf_block_dev.h"
|
||||
#include "app_sdcard.h"
|
||||
|
||||
/**
|
||||
* @brief SDC block device operations
|
||||
* */
|
||||
extern const nrf_block_dev_ops_t nrf_block_device_sdc_ops;
|
||||
|
||||
/**
|
||||
* @brief Work structure of SDC block device
|
||||
*/
|
||||
typedef struct {
|
||||
nrf_block_dev_geometry_t geometry; //!< Block device geometry
|
||||
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
|
||||
nrf_block_req_t req; //!< Block READ/WRITE request
|
||||
void const * p_context; //!< Context handle passed to event handler
|
||||
} nrf_block_dev_sdc_work_t;
|
||||
|
||||
/**
|
||||
* @brief SDC block device config initializer (@ref nrf_block_dev_sdc_config_t)
|
||||
*
|
||||
* @param blk_size Block size
|
||||
* @param sdc_lib_config SDC library config (@ref app_sdc_config_t)
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_SDC_CONFIG(blk_size, sdc_lib_config) \
|
||||
{ \
|
||||
.block_size = (blk_size), \
|
||||
.sdc_config = sdc_lib_config \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief SDC block device config
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t block_size; //!< Desired block size
|
||||
app_sdc_config_t sdc_config; //!< SDC library configuration
|
||||
} nrf_block_dev_sdc_config_t;
|
||||
|
||||
/**
|
||||
* @brief SDC block device
|
||||
* */
|
||||
typedef struct {
|
||||
nrf_block_dev_t block_dev; //!< Block device
|
||||
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
|
||||
nrf_block_dev_sdc_config_t sdc_bdev_config; //!< SDC block device config
|
||||
nrf_block_dev_sdc_work_t * p_work; //!< SDC block device work structure
|
||||
} nrf_block_dev_sdc_t;
|
||||
|
||||
/**
|
||||
* @brief Defines a SDC block device.
|
||||
*
|
||||
* @param name Instance name
|
||||
* @param config Configuration @ref nrf_block_dev_sdc_config_t
|
||||
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
|
||||
* */
|
||||
#define NRF_BLOCK_DEV_SDC_DEFINE(name, config, info) \
|
||||
static nrf_block_dev_sdc_work_t CONCAT_2(name, _work); \
|
||||
static const nrf_block_dev_sdc_t name = { \
|
||||
.block_dev = { .p_ops = &nrf_block_device_sdc_ops }, \
|
||||
.info_strings = BRACKET_EXTRACT(info), \
|
||||
.sdc_bdev_config = config, \
|
||||
.p_work = &CONCAT_2(name, _work), \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns block device API handle from SDC block device.
|
||||
*
|
||||
* @param[in] p_blk_sdc SDC block device
|
||||
* @return Block device handle
|
||||
*/
|
||||
static inline nrf_block_dev_t const *
|
||||
nrf_block_dev_sdc_ops_get(nrf_block_dev_sdc_t const * p_blk_sdc)
|
||||
{
|
||||
return &p_blk_sdc->block_dev;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_BLOCK_DEV_SDC_H__ */
|
||||
772
components/libraries/bootloader/ant_dfu/nrf_dfu_ant.c
Normal file
772
components/libraries/bootloader/ant_dfu/nrf_dfu_ant.c
Normal file
@@ -0,0 +1,772 @@
|
||||
/**
|
||||
* This software is subject to the ANT+ Shared Source License
|
||||
* www.thisisant.com/swlicenses
|
||||
* Copyright (c) Garmin Canada Inc. 2018
|
||||
* 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 Garmin nor the names of its
|
||||
* contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* The following actions are prohibited:
|
||||
*
|
||||
* 1) Redistribution of source code containing the ANT+ Network
|
||||
* Key. The ANT+ Network Key is available to ANT+ Adopters.
|
||||
* Please refer to http://thisisant.com to become an ANT+
|
||||
* Adopter and access the key.
|
||||
*
|
||||
* 2) Reverse engineering, decompilation, and/or disassembly of
|
||||
* software provided in binary form under this license.
|
||||
*
|
||||
* 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 HEREBY
|
||||
* 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; DAMAGE TO ANY DEVICE, 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. SOME STATES DO NOT ALLOW
|
||||
* THE EXCLUSION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE
|
||||
* ABOVE LIMITATIONS MAY NOT APPLY TO YOU.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "sdk_common.h"
|
||||
|
||||
#include "ant_channel_config.h"
|
||||
#include "ant_interface.h"
|
||||
#include "ant_parameters.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "nrf_balloc.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_dfu_handling_error.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
#include "nrf_dfu_transport.h"
|
||||
#include "nrf_dfu_mbr.h"
|
||||
#include "nrf_sdh.h"
|
||||
#include "nrf_sdh_ant.h"
|
||||
#include "nrf_soc.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_ant
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_ant ANT transport for reference DFU.
|
||||
* @ingroup nrf_dfu
|
||||
* @brief Device Firmware Update (DFU) transport layer using ANT.
|
||||
*
|
||||
* Transport documentation:
|
||||
*
|
||||
* The ANT transport uses all of the same opcodes and payload formats as the
|
||||
* UART serial transport. The only differences are the packet header format and
|
||||
* some extra details to deal with retransmissions.
|
||||
*
|
||||
* The device receiving the update is the ANT master. The format of the
|
||||
* broadcast buffer is as follows;
|
||||
* Byte 0: Current Slave -> Master sequence number.
|
||||
* Byte 1: Current Master -> Slave sequence number.
|
||||
* Bytes 2-7: Reserved, set to 0.
|
||||
*
|
||||
* The sequence numbers are used to detect retransmissions, any messages sent
|
||||
* with a sequence number equivalent to the current sequence will be ignored.
|
||||
*
|
||||
* When the slave first connects to the master it should inspect the broadcast
|
||||
* data in order to synchronize its sequence counters.
|
||||
*
|
||||
* All commands/responses are padded out to the nearest 8-byte boundary after
|
||||
* framing, and then sent using either a burst or acknowledged data depending on
|
||||
* length (ack data is used for 8-byte messages). The message transmission is
|
||||
* retried until an EVENT_TRANSFER_TX_COMPLETE event is received.
|
||||
* All messages are framed using the following format:
|
||||
* Bytes 0-1: Message length before padding, little endian, includes header.
|
||||
* Byte 2: Sequence number. Increment for every new message.
|
||||
* Byte 3: Op code. Always 0x60 for responses.
|
||||
* Bytes 4-N: Command/Response payload. This follows the same format as the
|
||||
* UART serial transport, without any SLIP encoding.
|
||||
*
|
||||
* As a final note, the MTU for this protocol is the maximum size of a burst
|
||||
* that can be received.
|
||||
*/
|
||||
|
||||
/** Packet header is always 2 byte length + seq num + op code */
|
||||
#define PKT_HEADER_SIZE 4
|
||||
|
||||
/** Maximum size of the payload in a write command. */
|
||||
#define MAX_WRITE_PAYLOAD (NRF_DFU_ANT_MTU - PKT_HEADER_SIZE)
|
||||
|
||||
/** Bursts are always a multiple of the standard data size. */
|
||||
STATIC_ASSERT_MSG(
|
||||
ALIGN_NUM(ANT_STANDARD_DATA_PAYLOAD_SIZE, NRF_DFU_ANT_MTU) == NRF_DFU_ANT_MTU,
|
||||
"ANT MTU must be a multiple of " STRINGIFY(ANT_STANDARD_DATA_PAYLOAD_SIZE));
|
||||
|
||||
/** Number of buffers to reserve space for with balloc. */
|
||||
#if (NRF_DFU_ANT_BUFFERS_OVERRIDE)
|
||||
#define NUM_BUFFERS NRF_DFU_ANT_BUFFERS
|
||||
#else
|
||||
#define NUM_BUFFERS CEIL_DIV(CODE_PAGE_SIZE, MAX_WRITE_PAYLOAD)
|
||||
#endif
|
||||
|
||||
static uint32_t ant_dfu_init(nrf_dfu_observer_t observer);
|
||||
static uint32_t ant_dfu_close(nrf_dfu_transport_t const * p_exception);
|
||||
|
||||
static ant_channel_config_t m_channel_config = {
|
||||
.channel_number = 0,
|
||||
.channel_type = CHANNEL_TYPE_MASTER,
|
||||
.rf_freq = NRF_DFU_ANT_RF_FREQ,
|
||||
.transmission_type = 1, // Non-shared, no global pages.
|
||||
.device_type = NRF_DFU_ANT_DEV_TYPE,
|
||||
.channel_period = NRF_DFU_ANT_CHANNEL_PERIOD,
|
||||
};
|
||||
|
||||
static nrf_dfu_observer_t m_observer;
|
||||
/** Has transport been initialized by DFU core */
|
||||
static bool m_initialized = false;
|
||||
/** Has the channel started broadcasting */
|
||||
static bool m_started = false;
|
||||
/** Has some data been received on the transport. */
|
||||
static bool m_active = false;
|
||||
|
||||
/** State tracking for rx transfers. */
|
||||
static struct
|
||||
{
|
||||
/** Buffer for holding the command. */
|
||||
uint8_t * buff;
|
||||
/** Amount of data written */
|
||||
size_t offset;
|
||||
/** Sequence of last processed command. */
|
||||
uint8_t seq;
|
||||
} m_rx;
|
||||
|
||||
/** State tracking for tx transfers. */
|
||||
static struct
|
||||
{
|
||||
/** Raw data to send. */
|
||||
uint8_t resp[ALIGN_NUM(ANT_STANDARD_DATA_PAYLOAD_SIZE,
|
||||
PKT_HEADER_SIZE + sizeof(nrf_dfu_response_t))];
|
||||
/** Length of data to send. 0 Indicates no response queued. */
|
||||
size_t len;
|
||||
/** Sequence number of last queued response. */
|
||||
uint8_t seq;
|
||||
/**
|
||||
* Used as burst flag for softdevice, allows to busy loop until all data is
|
||||
* accepted by softdevice.
|
||||
*/
|
||||
volatile bool buffering;
|
||||
/**
|
||||
* Indicate that a new response was generated before the last one was
|
||||
* confirmed.
|
||||
*/
|
||||
bool response_overwritten;
|
||||
/** Data buffer used for broadcast messages. */
|
||||
uint8_t bcast_data[ANT_STANDARD_DATA_PAYLOAD_SIZE];
|
||||
} m_tx;
|
||||
|
||||
/** State tracking for progress notifications. */
|
||||
static struct
|
||||
{
|
||||
/** Requested PRN */
|
||||
uint16_t limit;
|
||||
/** How many more write commands until a CRC should be sent back. */
|
||||
uint16_t remaining;
|
||||
} m_pkt_notify;
|
||||
|
||||
DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const ant_dfu_transport) = {
|
||||
.init_func = ant_dfu_init,
|
||||
.close_func = ant_dfu_close,
|
||||
};
|
||||
|
||||
NRF_BALLOC_DEF(m_buffer_pool, NRF_DFU_ANT_MTU, NUM_BUFFERS);
|
||||
|
||||
static void release_rx_buff(void)
|
||||
{
|
||||
if (m_rx.buff != NULL)
|
||||
{
|
||||
nrf_balloc_free(&m_buffer_pool, m_rx.buff);
|
||||
m_rx.buff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void transmit_response(void)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
size_t full_len = ALIGN_NUM(ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx.len);
|
||||
|
||||
// Pad out with 0's.
|
||||
memset(&m_tx.resp[m_tx.len], 0, full_len - m_tx.len);
|
||||
|
||||
if (full_len > ANT_STANDARD_DATA_PAYLOAD_SIZE)
|
||||
{
|
||||
err_code = sd_ant_burst_handler_request(
|
||||
m_channel_config.channel_number,
|
||||
full_len, m_tx.resp,
|
||||
BURST_SEGMENT_START | BURST_SEGMENT_END);
|
||||
} else
|
||||
{
|
||||
err_code = sd_ant_acknowledge_message_tx(
|
||||
m_channel_config.channel_number,
|
||||
full_len, m_tx.resp);
|
||||
}
|
||||
|
||||
// Wait for buffer to be consumed.
|
||||
// TODO: wait flag management needs to be improved if this will coexist with
|
||||
// other channels.
|
||||
while (err_code == NRF_SUCCESS && m_tx.buffering)
|
||||
{
|
||||
err_code = sd_app_evt_wait();
|
||||
}
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Sending response failed with error %d", err_code);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_bcast_data(void)
|
||||
{
|
||||
memset(m_tx.bcast_data, 0, sizeof(m_tx.bcast_data));
|
||||
m_tx.bcast_data[0] = m_rx.seq;
|
||||
m_tx.bcast_data[1] = m_tx.seq;
|
||||
|
||||
if (NRF_SUCCESS != sd_ant_broadcast_message_tx(
|
||||
m_channel_config.channel_number,
|
||||
sizeof(m_tx.bcast_data), m_tx.bcast_data))
|
||||
{
|
||||
NRF_LOG_WARNING("Unable to update broadcast data.");
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_write_complete(void * p_buf)
|
||||
{
|
||||
nrf_balloc_free(&m_buffer_pool, p_buf);
|
||||
}
|
||||
|
||||
static void prepare_response(nrf_dfu_response_t * p_res)
|
||||
{
|
||||
if (m_tx.len)
|
||||
{
|
||||
NRF_LOG_WARNING("Overwriting previous response.");
|
||||
m_tx.response_overwritten = true;
|
||||
}
|
||||
|
||||
// reserve first 2 bytes for length.
|
||||
m_tx.len = 2;
|
||||
|
||||
m_tx.resp[m_tx.len++] = ++(m_tx.seq);
|
||||
m_tx.resp[m_tx.len++] = NRF_DFU_OP_RESPONSE;
|
||||
m_tx.resp[m_tx.len++] = p_res->request;
|
||||
m_tx.resp[m_tx.len++] = p_res->result;
|
||||
|
||||
if (p_res->result == NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
switch(p_res->request)
|
||||
{
|
||||
case NRF_DFU_OP_PROTOCOL_VERSION:
|
||||
{
|
||||
m_tx.resp[m_tx.len++] = p_res->protocol.version;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_CRC_GET:
|
||||
{
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->crc.offset, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->crc.crc, &m_tx.resp[m_tx.len]);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
{
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->select.max_size, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->select.offset, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->select.crc, &m_tx.resp[m_tx.len]);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_MTU_GET:
|
||||
{
|
||||
m_tx.len += uint16_encode(
|
||||
p_res->mtu.size, &m_tx.resp[m_tx.len]);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_PING:
|
||||
{
|
||||
m_tx.resp[m_tx.len++] = p_res->ping.id;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_HARDWARE_VERSION:
|
||||
{
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->hardware.part, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->hardware.variant, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->hardware.memory.rom_size, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->hardware.memory.rom_page_size, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->hardware.memory.ram_size, &m_tx.resp[m_tx.len]);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_FIRMWARE_VERSION:
|
||||
{
|
||||
m_tx.resp[m_tx.len++] = p_res->firmware.type;
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->firmware.version, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->firmware.addr, &m_tx.resp[m_tx.len]);
|
||||
m_tx.len += uint32_encode(
|
||||
p_res->firmware.len, &m_tx.resp[m_tx.len]);
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (p_res->result == NRF_DFU_RES_CODE_EXT_ERROR)
|
||||
{
|
||||
m_tx.resp[m_tx.len++] = ext_error_get();
|
||||
UNUSED_RETURN_VALUE(ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR));
|
||||
}
|
||||
|
||||
// Finally fill in the length.
|
||||
UNUSED_RETURN_VALUE(uint16_encode(m_tx.len, m_tx.resp));
|
||||
|
||||
// Safety check buffer overflow.
|
||||
ASSERT(m_tx.len <= sizeof(m_tx.resp));
|
||||
|
||||
if (!m_tx.response_overwritten)
|
||||
{
|
||||
// Can send out the response immediately if there wasn't a previous one
|
||||
// queued.
|
||||
transmit_response();
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_response(nrf_dfu_response_t * p_res, void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
NRF_LOG_WARNING("Operation %d had result %d",
|
||||
p_res->request, p_res->result);
|
||||
}
|
||||
|
||||
if (p_res->request == NRF_DFU_OP_OBJECT_WRITE)
|
||||
{
|
||||
if (m_pkt_notify.limit == 0 ||
|
||||
--m_pkt_notify.remaining != 0)
|
||||
{
|
||||
// No packet notification needed, filter out response.
|
||||
return;
|
||||
}
|
||||
|
||||
// Packet Notification time, send a CRC response.
|
||||
m_pkt_notify.remaining = m_pkt_notify.limit;
|
||||
p_res->request = NRF_DFU_OP_CRC_GET;
|
||||
uint32_t offset = p_res->write.offset;
|
||||
uint32_t crc = p_res->write.crc;
|
||||
p_res->crc.offset = offset;
|
||||
p_res->crc.crc = crc;
|
||||
}
|
||||
|
||||
prepare_response(p_res);
|
||||
}
|
||||
|
||||
static uint32_t handle_request(void)
|
||||
{
|
||||
uint16_t len = uint16_decode(m_rx.buff);
|
||||
uint16_t offset = sizeof(uint16_t);
|
||||
|
||||
if (len < PKT_HEADER_SIZE || len > m_rx.offset)
|
||||
{
|
||||
NRF_LOG_WARNING("Ignoring command with invalid length.");
|
||||
return NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
|
||||
uint8_t seq = m_rx.buff[offset++];
|
||||
if (!m_active)
|
||||
{
|
||||
m_active = true;
|
||||
// Close all other transports.
|
||||
UNUSED_RETURN_VALUE(nrf_dfu_transports_close(&ant_dfu_transport));
|
||||
}
|
||||
else if (seq == m_rx.seq)
|
||||
{
|
||||
NRF_LOG_DEBUG("Ignoring repeated command");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
m_rx.seq = seq;
|
||||
|
||||
nrf_dfu_request_t request = {
|
||||
.request = (nrf_dfu_op_t)m_rx.buff[offset++],
|
||||
.callback.response = handle_response,
|
||||
};
|
||||
|
||||
switch(request.request)
|
||||
{
|
||||
case NRF_DFU_OP_OBJECT_CREATE:
|
||||
{
|
||||
request.create.object_type = m_rx.buff[offset++];
|
||||
request.create.object_size = uint32_decode(&m_rx.buff[offset]);
|
||||
offset += sizeof(uint32_t);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_RECEIPT_NOTIF_SET:
|
||||
{
|
||||
request.prn.target = uint16_decode(&m_rx.buff[offset]);
|
||||
offset += sizeof(uint16_t);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
{
|
||||
request.select.object_type = m_rx.buff[offset++];
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_WRITE:
|
||||
{
|
||||
request.write.p_data = &m_rx.buff[offset];
|
||||
request.write.len = len - offset;
|
||||
offset = len;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_PING:
|
||||
{
|
||||
request.ping.id = m_rx.buff[offset++];
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_FIRMWARE_VERSION:
|
||||
{
|
||||
request.firmware.image_number = m_rx.buff[offset++];
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_MTU_GET:
|
||||
{
|
||||
NRF_LOG_DEBUG("ANT DFU: Responding to MTU request with %d",
|
||||
NRF_DFU_ANT_MTU);
|
||||
request.mtu.size = NRF_DFU_ANT_MTU;
|
||||
} break;
|
||||
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset > len)
|
||||
{
|
||||
NRF_LOG_WARNING("Ignoring command with invalid length");
|
||||
return NRF_ERROR_DATA_SIZE;
|
||||
}
|
||||
|
||||
// Some processing that is only safe to do if accepting the command.
|
||||
|
||||
switch (request.request)
|
||||
{
|
||||
case NRF_DFU_OP_RECEIPT_NOTIF_SET:
|
||||
{
|
||||
m_pkt_notify.limit = request.prn.target;
|
||||
m_pkt_notify.remaining = m_pkt_notify.limit;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_CREATE:
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
{
|
||||
m_pkt_notify.remaining = m_pkt_notify.limit;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_WRITE:
|
||||
{
|
||||
// Ownership of buffer is transferred to the write command.
|
||||
request.callback.write = handle_write_complete;
|
||||
m_rx.buff = NULL;
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nrf_dfu_req_handler_on_req(&request);
|
||||
}
|
||||
|
||||
static void handle_tx_transfer_complete(bool success)
|
||||
{
|
||||
if (m_tx.response_overwritten)
|
||||
{
|
||||
// By treating the result as a failure the retransmission will send out
|
||||
// the new response.
|
||||
success = false;
|
||||
m_tx.response_overwritten = false;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
m_tx.len = 0;
|
||||
update_bcast_data();
|
||||
}
|
||||
else
|
||||
{
|
||||
transmit_response();
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_rx_transfer_start()
|
||||
{
|
||||
if (m_rx.buff == NULL)
|
||||
{
|
||||
m_rx.buff = nrf_balloc_alloc(&m_buffer_pool);
|
||||
if (m_rx.buff != NULL)
|
||||
{
|
||||
NRF_LOG_INFO("Allocated buffer %x", m_rx.buff);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_ERROR("Unable to allocate buffer for incoming packet.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Resetting rx pointer.");
|
||||
m_rx.offset = 0;
|
||||
}
|
||||
|
||||
static void handle_rx_transfer_complete(bool success)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
uint32_t err_code = handle_request();
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Error %d handling request.", err_code);
|
||||
}
|
||||
}
|
||||
|
||||
release_rx_buff();
|
||||
}
|
||||
|
||||
static void handle_rx_transfer_data(uint8_t * data, size_t len)
|
||||
{
|
||||
if (m_rx.buff == NULL)
|
||||
{
|
||||
NRF_LOG_DEBUG("Ignoring transfer data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_rx.offset + len > NRF_DFU_ANT_MTU)
|
||||
{
|
||||
NRF_LOG_ERROR("Received packet overflows MTU.");
|
||||
handle_rx_transfer_complete(false);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&m_rx.buff[m_rx.offset], data, len);
|
||||
m_rx.offset += len;
|
||||
}
|
||||
|
||||
static void handle_data_mesg(ANT_MESSAGE * p_msg)
|
||||
{
|
||||
bool is_first = false;
|
||||
bool is_last = false;
|
||||
uint8_t len = ANT_STANDARD_DATA_PAYLOAD_SIZE;
|
||||
|
||||
switch(p_msg->ANT_MESSAGE_ucMesgID)
|
||||
{
|
||||
case MESG_BROADCAST_DATA_ID:
|
||||
{
|
||||
// Broadcast data is ignored.
|
||||
len = 0;
|
||||
} break;
|
||||
|
||||
case MESG_ACKNOWLEDGED_DATA_ID:
|
||||
{
|
||||
is_first = true;
|
||||
is_last = true;
|
||||
} break;
|
||||
|
||||
case MESG_ADV_BURST_DATA_ID:
|
||||
{
|
||||
len = p_msg->ANT_MESSAGE_ucSize - MESG_CHANNEL_NUM_SIZE;
|
||||
} // FALL-THROUGH : both burst types act the same other than len.
|
||||
case MESG_BURST_DATA_ID:
|
||||
{
|
||||
uint8_t seq = p_msg->ANT_MESSAGE_ucChannel & SEQUENCE_NUMBER_MASK;
|
||||
is_first = seq == SEQUENCE_FIRST_MESSAGE;
|
||||
is_last = !!(seq & SEQUENCE_LAST_MESSAGE);
|
||||
} break;
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
if (is_first)
|
||||
{
|
||||
handle_rx_transfer_start();
|
||||
}
|
||||
|
||||
handle_rx_transfer_data(p_msg->ANT_MESSAGE_aucPayload, len);
|
||||
|
||||
if (is_last)
|
||||
{
|
||||
handle_rx_transfer_complete(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ant_dfu_evt_handler(ant_evt_t * p_ant_evt, void * p_context)
|
||||
{
|
||||
// Ignore messages meant for other channels.
|
||||
if (p_ant_evt->channel != m_channel_config.channel_number)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(p_ant_evt->event)
|
||||
{
|
||||
case EVENT_TX:
|
||||
{
|
||||
if (!m_started)
|
||||
{
|
||||
m_started = true;
|
||||
m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
|
||||
}
|
||||
} break;
|
||||
|
||||
case EVENT_TRANSFER_TX_COMPLETED:
|
||||
handle_tx_transfer_complete(true);
|
||||
break;
|
||||
case EVENT_TRANSFER_TX_FAILED:
|
||||
handle_tx_transfer_complete(false);
|
||||
break;
|
||||
|
||||
case EVENT_RX:
|
||||
handle_data_mesg(&p_ant_evt->message);
|
||||
break;
|
||||
|
||||
case EVENT_TRANSFER_RX_FAILED:
|
||||
handle_rx_transfer_complete(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ant_dfu_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
if (m_initialized)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
NRF_SDH_ANT_OBSERVER(ant_dfu_observer, NRF_DFU_ANT_EVT_HANDLER_PRIO,
|
||||
ant_dfu_evt_handler, NULL);
|
||||
|
||||
m_observer = observer;
|
||||
m_tx.seq = m_rx.seq = 0;
|
||||
m_active = false;
|
||||
m_started = false;
|
||||
|
||||
NRF_LOG_DEBUG("Initializing ANT DFU transport");
|
||||
|
||||
err_code = nrf_balloc_init(&m_buffer_pool);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = nrf_dfu_mbr_init_sd();
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
NRF_LOG_DEBUG("Setting up vector table: 0x%08x", BOOTLOADER_START_ADDR);
|
||||
err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_START_ADDR);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
NRF_LOG_DEBUG("Enabling softdevice");
|
||||
err_code = nrf_sdh_enable_request();
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
err_code = nrf_sdh_ant_enable();
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
static uint8_t adv_burst_conf[] = {
|
||||
ADV_BURST_MODE_ENABLE,
|
||||
ADV_BURST_MODES_SIZE_24_BYTES,
|
||||
0, // No required modes.
|
||||
0, 0, // Reserved
|
||||
ADV_BURST_MODES_FREQ_HOP, // Optional Modes
|
||||
0, 0, // Reserved
|
||||
// No optional configs.
|
||||
};
|
||||
err_code = sd_ant_adv_burst_config_set(adv_burst_conf, sizeof(adv_burst_conf));
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
m_channel_config.device_number = NRF_FICR->DEVICEID[0];
|
||||
m_channel_config.transmission_type |= (NRF_FICR->DEVICEID[1] & 0xF) << 4;
|
||||
|
||||
err_code = ant_channel_init(&m_channel_config);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
update_bcast_data();
|
||||
|
||||
err_code = sd_ant_channel_open(m_channel_config.channel_number);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
NRF_LOG_DEBUG("ANT transport intialized");
|
||||
|
||||
m_initialized = true;
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static uint32_t ant_dfu_close(nrf_dfu_transport_t const * p_exception)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
if (p_exception != &ant_dfu_transport && m_initialized)
|
||||
{
|
||||
NRF_LOG_DEBUG("Shutting down ANT DFU transport");
|
||||
|
||||
m_initialized = false;
|
||||
|
||||
err_code = sd_ant_channel_close(m_channel_config.channel_number);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
uint8_t status;
|
||||
do
|
||||
{
|
||||
// The initial wait is safe because the close command above would
|
||||
// have generated at least 1 app event.
|
||||
err_code = sd_app_evt_wait();
|
||||
VERIFY_SUCCESS(err_code);
|
||||
err_code = sd_ant_channel_status_get(
|
||||
m_channel_config.channel_number, &status);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
} while ((status & STATUS_CHANNEL_STATE_MASK) != STATUS_ASSIGNED_CHANNEL);
|
||||
|
||||
err_code = nrf_sdh_disable_request();
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
NRF_LOG_DEBUG("ANT transport disabled.");
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
1261
components/libraries/bootloader/ble_dfu/nrf_dfu_ble.c
Normal file
1261
components/libraries/bootloader/ble_dfu/nrf_dfu_ble.c
Normal file
File diff suppressed because it is too large
Load Diff
121
components/libraries/bootloader/ble_dfu/nrf_dfu_ble.h
Normal file
121
components/libraries/bootloader/ble_dfu/nrf_dfu_ble.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_ble DFU BLE Service
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
* @brief Device Firmware Update (DFU) transport layer for <em>Bluetooth</em> low energy.
|
||||
*
|
||||
* @details The Device Firmware Update (DFU) Service is a GATT-based service that can be used for
|
||||
* performing firmware updates over BLE. Note that this implementation uses
|
||||
* vendor-specific UUIDs for the service and characteristics, and is intended to demonstrate
|
||||
* firmware updates over BLE. See @ref lib_dfu_transport_ble "DFU Transport: BLE" for more information on the service and the profile.
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_BLE_H__
|
||||
#define NRF_DFU_BLE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble_gatts.h"
|
||||
#include "ble.h"
|
||||
#include "nrf_dfu_transport.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This is a 16-bit UUID.
|
||||
#define BLE_DFU_SERVICE_UUID 0xFE59 //!< UUID of the DFU Service.
|
||||
|
||||
// These UUIDs are used with the Nordic base address to create a 128-bit UUID (0x8EC9XXXXF3154F609FB8838830DAEA50).
|
||||
#define BLE_DFU_CTRL_PT_UUID 0x0001 //!< UUID of the DFU Control Point.
|
||||
#define BLE_DFU_PKT_CHAR_UUID 0x0002 //!< UUID of the DFU Packet Characteristic.
|
||||
|
||||
|
||||
/**@brief DFU Service.
|
||||
*
|
||||
* @details This structure contains status information related to the service.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t service_handle; /**< Handle of the DFU Service (as provided by the SoftDevice). */
|
||||
uint8_t uuid_type; /**< UUID type assigned to the DFU Service by the SoftDevice. */
|
||||
ble_gatts_char_handles_t dfu_pkt_handles; /**< Handles related to the DFU Packet Characteristic. */
|
||||
ble_gatts_char_handles_t dfu_ctrl_pt_handles; /**< Handles related to the DFU Control Point Characteristic. */
|
||||
} ble_dfu_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the BLE transport.
|
||||
*
|
||||
* @param[in] observer Callback function for receiving notifications from the BLE transport.
|
||||
*
|
||||
* @retval NRF_SUCCESS If successful.
|
||||
* @return Error code from sub-call on error.
|
||||
*/
|
||||
uint32_t ble_dfu_transport_init(nrf_dfu_observer_t observer);
|
||||
|
||||
/**@brief Function for closing the BLE transport.
|
||||
*
|
||||
* This function disconnects and disables the SoftDevice.
|
||||
*
|
||||
* @param[in] p_exception Optional exception. If the exception refers to this transport,
|
||||
* this function will do nothing. Can be NULL to signify no exception.
|
||||
*
|
||||
* @retval NRF_SUCCESS If successful.
|
||||
* @return Error code from sub-call on error.
|
||||
*/
|
||||
uint32_t ble_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
|
||||
|
||||
/**@brief Function for disconnecting from the BLE peer and starting advertising.
|
||||
*
|
||||
* @retval NRF_SUCCESS If successful.
|
||||
* @return Error code from sub-call on error.
|
||||
*/
|
||||
uint32_t ble_dfu_transport_disconnect(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_BLE_H__
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_svci_bond_sharing Supervisor call interface for bond sharing
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
* @brief The Supervisor call interface is a thread-safe method to call into the current application or into an external application using a Supervisor instruction.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NRF_DFU_BLE_SVCI_BOND_SHARING_H__
|
||||
#define NRF_DFU_BLE_SVCI_BOND_SHARING_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "nrf_svci.h"
|
||||
#include "nrf_svci_async_function.h"
|
||||
#include "sdk_config.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define NRF_DFU_SVCI_SET_PEER_DATA 2
|
||||
#define NRF_DFU_SVCI_SET_ADV_NAME 3
|
||||
|
||||
#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE
|
||||
|
||||
/**@brief Sets up the async SVCI interface for exchanging peer data like bonding and the system attribute table.
|
||||
*
|
||||
* @details The peer data will be stored in flash by the bootloader. This requires memory management and
|
||||
* handling forwarding of system events and state from the main application to the bootloader.
|
||||
*
|
||||
* @note This is only available in the buttonless DFU that supports bond sharing.
|
||||
*/
|
||||
NRF_SVCI_ASYNC_FUNC_DECLARE(NRF_DFU_SVCI_SET_PEER_DATA, nrf_dfu_set_peer_data, nrf_dfu_peer_data_t, nrf_dfu_peer_data_state_t);
|
||||
|
||||
/**@brief Sets up the async SVCI interface for exchanging advertisement name to use when entering DFU mode.
|
||||
*
|
||||
* @details The advertisement name will be stored in flash by the bootloader. This requires memory management
|
||||
* and handling forwarding of system events and state from the main application to the bootloader.
|
||||
*
|
||||
* @note This is only available in the buttonless DFU that does not support bond sharing.
|
||||
*/
|
||||
NRF_SVCI_ASYNC_FUNC_DECLARE(NRF_DFU_SVCI_SET_ADV_NAME, nrf_dfu_set_adv_name, nrf_dfu_adv_name_t, nrf_dfu_set_adv_name_state_t);
|
||||
|
||||
#endif // NRF_DFU_TRANSPORT_BLE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_BLE_SVCI_BOND_SHARING_H__
|
||||
|
||||
/** @} */
|
||||
5
components/libraries/bootloader/dfu/dfu-cc.options
Normal file
5
components/libraries/bootloader/dfu/dfu-cc.options
Normal file
@@ -0,0 +1,5 @@
|
||||
dfu.Hash.hash max_size:32
|
||||
dfu.SignedCommand.signature max_size:64
|
||||
dfu.InitCommand.sd_req max_count:16
|
||||
dfu.InitCommand.boot_validation max_count:3
|
||||
dfu.BootValidation.bytes max_size:64
|
||||
123
components/libraries/bootloader/dfu/dfu-cc.pb.c
Normal file
123
components/libraries/bootloader/dfu/dfu-cc.pb.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.3.6-dev at Tue Sep 11 14:37:18 2018. */
|
||||
|
||||
#include "dfu-cc.pb.h"
|
||||
|
||||
/* @@protoc_insertion_point(includes) */
|
||||
#if PB_PROTO_HEADER_VERSION != 30
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
const bool dfu_init_command_is_debug_default = false;
|
||||
|
||||
|
||||
const pb_field_t dfu_hash_fields[3] = {
|
||||
PB_FIELD( 1, UENUM , REQUIRED, STATIC , FIRST, dfu_hash_t, hash_type, hash_type, 0),
|
||||
PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, dfu_hash_t, hash, hash_type, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t dfu_boot_validation_fields[3] = {
|
||||
PB_FIELD( 1, UENUM , REQUIRED, STATIC , FIRST, dfu_boot_validation_t, type, type, 0),
|
||||
PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, dfu_boot_validation_t, bytes, type, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t dfu_init_command_fields[11] = {
|
||||
PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, dfu_init_command_t, fw_version, fw_version, 0),
|
||||
PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, hw_version, fw_version, 0),
|
||||
PB_FIELD( 3, UINT32 , REPEATED, STATIC , OTHER, dfu_init_command_t, sd_req, hw_version, 0),
|
||||
PB_FIELD( 4, UENUM , OPTIONAL, STATIC , OTHER, dfu_init_command_t, type, sd_req, 0),
|
||||
PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, sd_size, type, 0),
|
||||
PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, bl_size, sd_size, 0),
|
||||
PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, app_size, bl_size, 0),
|
||||
PB_FIELD( 8, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_init_command_t, hash, app_size, &dfu_hash_fields),
|
||||
PB_FIELD( 9, BOOL , OPTIONAL, STATIC , OTHER, dfu_init_command_t, is_debug, hash, &dfu_init_command_is_debug_default),
|
||||
PB_FIELD( 10, MESSAGE , REPEATED, STATIC , OTHER, dfu_init_command_t, boot_validation, is_debug, &dfu_boot_validation_fields),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t dfu_command_fields[3] = {
|
||||
PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, dfu_command_t, op_code, op_code, 0),
|
||||
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_command_t, init, op_code, &dfu_init_command_fields),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t dfu_signed_command_fields[4] = {
|
||||
PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, dfu_signed_command_t, command, command, &dfu_command_fields),
|
||||
PB_FIELD( 2, UENUM , REQUIRED, STATIC , OTHER, dfu_signed_command_t, signature_type, command, 0),
|
||||
PB_FIELD( 3, BYTES , REQUIRED, STATIC , OTHER, dfu_signed_command_t, signature, signature_type, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t dfu_packet_fields[3] = {
|
||||
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, dfu_packet_t, command, command, &dfu_command_fields),
|
||||
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_packet_t, signed_command, command, &dfu_signed_command_fields),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
|
||||
/* Check that field information fits in pb_field_t */
|
||||
#if !defined(PB_FIELD_32BIT)
|
||||
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line.
|
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag
|
||||
* numbers or field sizes that are larger than what can fit in 8 or 16 bit
|
||||
* field descriptors.
|
||||
*/
|
||||
PB_STATIC_ASSERT((pb_membersize(dfu_init_command_t, hash) < 65536 && pb_membersize(dfu_init_command_t, boot_validation[0]) < 65536 && pb_membersize(dfu_command_t, init) < 65536 && pb_membersize(dfu_signed_command_t, command) < 65536 && pb_membersize(dfu_packet_t, command) < 65536 && pb_membersize(dfu_packet_t, signed_command) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_dfu_hash_dfu_boot_validation_dfu_init_command_dfu_command_dfu_signed_command_dfu_packet)
|
||||
#endif
|
||||
|
||||
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
|
||||
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line.
|
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag
|
||||
* numbers or field sizes that are larger than what can fit in the default
|
||||
* 8 bit descriptors.
|
||||
*/
|
||||
PB_STATIC_ASSERT((pb_membersize(dfu_init_command_t, hash) < 256 && pb_membersize(dfu_init_command_t, boot_validation[0]) < 256 && pb_membersize(dfu_command_t, init) < 256 && pb_membersize(dfu_signed_command_t, command) < 256 && pb_membersize(dfu_packet_t, command) < 256 && pb_membersize(dfu_packet_t, signed_command) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_dfu_hash_dfu_boot_validation_dfu_init_command_dfu_command_dfu_signed_command_dfu_packet)
|
||||
#endif
|
||||
|
||||
|
||||
/* @@protoc_insertion_point(eof) */
|
||||
241
components/libraries/bootloader/dfu/dfu-cc.pb.h
Normal file
241
components/libraries/bootloader/dfu/dfu-cc.pb.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.3.6-dev at Tue Sep 11 14:37:18 2018. */
|
||||
|
||||
#ifndef PB_DFU_CC_PB_H_INCLUDED
|
||||
#define PB_DFU_CC_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
|
||||
/* @@protoc_insertion_point(includes) */
|
||||
#if PB_PROTO_HEADER_VERSION != 30
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Enum definitions */
|
||||
typedef enum
|
||||
{
|
||||
DFU_FW_TYPE_APPLICATION = 0,
|
||||
DFU_FW_TYPE_SOFTDEVICE = 1,
|
||||
DFU_FW_TYPE_BOOTLOADER = 2,
|
||||
DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER = 3,
|
||||
DFU_FW_TYPE_EXTERNAL_APPLICATION = 4
|
||||
} dfu_fw_type_t;
|
||||
#define DFU_FW_TYPE_MIN DFU_FW_TYPE_APPLICATION
|
||||
#define DFU_FW_TYPE_MAX DFU_FW_TYPE_EXTERNAL_APPLICATION
|
||||
#define DFU_FW_TYPE_ARRAYSIZE ((dfu_fw_type_t)(DFU_FW_TYPE_EXTERNAL_APPLICATION+1))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DFU_HASH_TYPE_NO_HASH = 0,
|
||||
DFU_HASH_TYPE_CRC = 1,
|
||||
DFU_HASH_TYPE_SHA128 = 2,
|
||||
DFU_HASH_TYPE_SHA256 = 3,
|
||||
DFU_HASH_TYPE_SHA512 = 4
|
||||
} dfu_hash_type_t;
|
||||
#define DFU_HASH_TYPE_MIN DFU_HASH_TYPE_NO_HASH
|
||||
#define DFU_HASH_TYPE_MAX DFU_HASH_TYPE_SHA512
|
||||
#define DFU_HASH_TYPE_ARRAYSIZE ((dfu_hash_type_t)(DFU_HASH_TYPE_SHA512+1))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DFU_OP_CODE_INIT = 1
|
||||
} dfu_op_code_t;
|
||||
#define DFU_OP_CODE_MIN DFU_OP_CODE_INIT
|
||||
#define DFU_OP_CODE_MAX DFU_OP_CODE_INIT
|
||||
#define DFU_OP_CODE_ARRAYSIZE ((dfu_op_code_t)(DFU_OP_CODE_INIT+1))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DFU_VALIDATION_TYPE_NO_VALIDATION = 0,
|
||||
DFU_VALIDATION_TYPE_VALIDATE_GENERATED_CRC = 1,
|
||||
DFU_VALIDATION_TYPE_VALIDATE_SHA256 = 2,
|
||||
DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256 = 3
|
||||
} dfu_validation_type_t;
|
||||
#define DFU_VALIDATION_TYPE_MIN DFU_VALIDATION_TYPE_NO_VALIDATION
|
||||
#define DFU_VALIDATION_TYPE_MAX DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256
|
||||
#define DFU_VALIDATION_TYPE_ARRAYSIZE ((dfu_validation_type_t)(DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256+1))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256 = 0,
|
||||
DFU_SIGNATURE_TYPE_ED25519 = 1
|
||||
} dfu_signature_type_t;
|
||||
#define DFU_SIGNATURE_TYPE_MIN DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256
|
||||
#define DFU_SIGNATURE_TYPE_MAX DFU_SIGNATURE_TYPE_ED25519
|
||||
#define DFU_SIGNATURE_TYPE_ARRAYSIZE ((dfu_signature_type_t)(DFU_SIGNATURE_TYPE_ED25519+1))
|
||||
|
||||
/* Struct definitions */
|
||||
typedef PB_BYTES_ARRAY_T(64) dfu_boot_validation_bytes_t;
|
||||
typedef struct {
|
||||
dfu_validation_type_t type;
|
||||
dfu_boot_validation_bytes_t bytes;
|
||||
/* @@protoc_insertion_point(struct:dfu_boot_validation_t) */
|
||||
} dfu_boot_validation_t;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(32) dfu_hash_hash_t;
|
||||
typedef struct {
|
||||
dfu_hash_type_t hash_type;
|
||||
dfu_hash_hash_t hash;
|
||||
/* @@protoc_insertion_point(struct:dfu_hash_t) */
|
||||
} dfu_hash_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_fw_version;
|
||||
uint32_t fw_version;
|
||||
bool has_hw_version;
|
||||
uint32_t hw_version;
|
||||
pb_size_t sd_req_count;
|
||||
uint32_t sd_req[16];
|
||||
bool has_type;
|
||||
dfu_fw_type_t type;
|
||||
bool has_sd_size;
|
||||
uint32_t sd_size;
|
||||
bool has_bl_size;
|
||||
uint32_t bl_size;
|
||||
bool has_app_size;
|
||||
uint32_t app_size;
|
||||
bool has_hash;
|
||||
dfu_hash_t hash;
|
||||
bool has_is_debug;
|
||||
bool is_debug;
|
||||
pb_size_t boot_validation_count;
|
||||
dfu_boot_validation_t boot_validation[3];
|
||||
/* @@protoc_insertion_point(struct:dfu_init_command_t) */
|
||||
} dfu_init_command_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_op_code;
|
||||
dfu_op_code_t op_code;
|
||||
bool has_init;
|
||||
dfu_init_command_t init;
|
||||
/* @@protoc_insertion_point(struct:dfu_command_t) */
|
||||
} dfu_command_t;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(64) dfu_signed_command_signature_t;
|
||||
typedef struct {
|
||||
dfu_command_t command;
|
||||
dfu_signature_type_t signature_type;
|
||||
dfu_signed_command_signature_t signature;
|
||||
/* @@protoc_insertion_point(struct:dfu_signed_command_t) */
|
||||
} dfu_signed_command_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_command;
|
||||
dfu_command_t command;
|
||||
bool has_signed_command;
|
||||
dfu_signed_command_t signed_command;
|
||||
/* @@protoc_insertion_point(struct:dfu_packet_t) */
|
||||
} dfu_packet_t;
|
||||
|
||||
/* Default values for struct fields */
|
||||
extern const bool dfu_init_command_is_debug_default;
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define DFU_HASH_INIT_DEFAULT {(dfu_hash_type_t)0, {0, {0}}}
|
||||
#define DFU_BOOT_VALIDATION_INIT_DEFAULT {(dfu_validation_type_t)0, {0, {0}}}
|
||||
#define DFU_INIT_COMMAND_INIT_DEFAULT {false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false, (dfu_fw_type_t)0, false, 0, false, 0, false, 0, false, DFU_HASH_INIT_DEFAULT, false, false, 0, {DFU_BOOT_VALIDATION_INIT_DEFAULT, DFU_BOOT_VALIDATION_INIT_DEFAULT, DFU_BOOT_VALIDATION_INIT_DEFAULT}}
|
||||
#define DFU_COMMAND_INIT_DEFAULT {false, (dfu_op_code_t)0, false, DFU_INIT_COMMAND_INIT_DEFAULT}
|
||||
#define DFU_SIGNED_COMMAND_INIT_DEFAULT {DFU_COMMAND_INIT_DEFAULT, (dfu_signature_type_t)0, {0, {0}}}
|
||||
#define DFU_PACKET_INIT_DEFAULT {false, DFU_COMMAND_INIT_DEFAULT, false, DFU_SIGNED_COMMAND_INIT_DEFAULT}
|
||||
#define DFU_HASH_INIT_ZERO {(dfu_hash_type_t)0, {0, {0}}}
|
||||
#define DFU_BOOT_VALIDATION_INIT_ZERO {(dfu_validation_type_t)0, {0, {0}}}
|
||||
#define DFU_INIT_COMMAND_INIT_ZERO {false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false, (dfu_fw_type_t)0, false, 0, false, 0, false, 0, false, DFU_HASH_INIT_ZERO, false, 0, 0, {DFU_BOOT_VALIDATION_INIT_ZERO, DFU_BOOT_VALIDATION_INIT_ZERO, DFU_BOOT_VALIDATION_INIT_ZERO}}
|
||||
#define DFU_COMMAND_INIT_ZERO {false, (dfu_op_code_t)0, false, DFU_INIT_COMMAND_INIT_ZERO}
|
||||
#define DFU_SIGNED_COMMAND_INIT_ZERO {DFU_COMMAND_INIT_ZERO, (dfu_signature_type_t)0, {0, {0}}}
|
||||
#define DFU_PACKET_INIT_ZERO {false, DFU_COMMAND_INIT_ZERO, false, DFU_SIGNED_COMMAND_INIT_ZERO}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define DFU_BOOT_VALIDATION_TYPE_TAG 1
|
||||
#define DFU_BOOT_VALIDATION_BYTES_TAG 2
|
||||
#define DFU_HASH_HASH_TYPE_TAG 1
|
||||
#define DFU_HASH_HASH_TAG 2
|
||||
#define DFU_INIT_COMMAND_FW_VERSION_TAG 1
|
||||
#define DFU_INIT_COMMAND_HW_VERSION_TAG 2
|
||||
#define DFU_INIT_COMMAND_SD_REQ_TAG 3
|
||||
#define DFU_INIT_COMMAND_TYPE_TAG 4
|
||||
#define DFU_INIT_COMMAND_SD_SIZE_TAG 5
|
||||
#define DFU_INIT_COMMAND_BL_SIZE_TAG 6
|
||||
#define DFU_INIT_COMMAND_APP_SIZE_TAG 7
|
||||
#define DFU_INIT_COMMAND_HASH_TAG 8
|
||||
#define DFU_INIT_COMMAND_IS_DEBUG_TAG 9
|
||||
#define DFU_INIT_COMMAND_BOOT_VALIDATION_TAG 10
|
||||
#define DFU_COMMAND_OP_CODE_TAG 1
|
||||
#define DFU_COMMAND_INIT_TAG 2
|
||||
#define DFU_SIGNED_COMMAND_COMMAND_TAG 1
|
||||
#define DFU_SIGNED_COMMAND_SIGNATURE_TYPE_TAG 2
|
||||
#define DFU_SIGNED_COMMAND_SIGNATURE_TAG 3
|
||||
#define DFU_PACKET_COMMAND_TAG 1
|
||||
#define DFU_PACKET_SIGNED_COMMAND_TAG 2
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
extern const pb_field_t dfu_hash_fields[3];
|
||||
extern const pb_field_t dfu_boot_validation_fields[3];
|
||||
extern const pb_field_t dfu_init_command_fields[11];
|
||||
extern const pb_field_t dfu_command_fields[3];
|
||||
extern const pb_field_t dfu_signed_command_fields[4];
|
||||
extern const pb_field_t dfu_packet_fields[3];
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define DFU_HASH_SIZE 36
|
||||
#define DFU_BOOT_VALIDATION_SIZE 68
|
||||
#define DFU_INIT_COMMAND_SIZE 378
|
||||
#define DFU_COMMAND_SIZE 383
|
||||
#define DFU_SIGNED_COMMAND_SIZE 454
|
||||
#define DFU_PACKET_SIZE 843
|
||||
|
||||
/* Message IDs (where set with "msgid" option) */
|
||||
#ifdef PB_MSGID
|
||||
|
||||
#define DFU_CC_MESSAGES \
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
/* @@protoc_insertion_point(eof) */
|
||||
|
||||
#endif
|
||||
82
components/libraries/bootloader/dfu/dfu-cc.proto
Normal file
82
components/libraries/bootloader/dfu/dfu-cc.proto
Normal file
@@ -0,0 +1,82 @@
|
||||
package dfu;
|
||||
|
||||
// Version 0.1
|
||||
|
||||
enum FwType {
|
||||
APPLICATION = 0;
|
||||
SOFTDEVICE = 1;
|
||||
BOOTLOADER = 2;
|
||||
SOFTDEVICE_BOOTLOADER = 3;
|
||||
EXTERNAL_APPLICATION = 4;
|
||||
}
|
||||
|
||||
enum HashType {
|
||||
NO_HASH = 0;
|
||||
CRC = 1;
|
||||
SHA128 = 2;
|
||||
SHA256 = 3;
|
||||
SHA512 = 4;
|
||||
}
|
||||
|
||||
enum OpCode {
|
||||
INIT = 1;
|
||||
}
|
||||
|
||||
enum ValidationType {
|
||||
NO_VALIDATION = 0;
|
||||
VALIDATE_GENERATED_CRC = 1;
|
||||
VALIDATE_SHA256 = 2;
|
||||
VALIDATE_ECDSA_P256_SHA256 = 3;
|
||||
}
|
||||
|
||||
message Hash {
|
||||
required HashType hash_type = 1;
|
||||
required bytes hash = 2;
|
||||
}
|
||||
|
||||
message BootValidation {
|
||||
|
||||
required ValidationType type = 1;
|
||||
required bytes bytes = 2;
|
||||
}
|
||||
|
||||
// Commands data
|
||||
message InitCommand {
|
||||
optional uint32 fw_version = 1;
|
||||
optional uint32 hw_version = 2;
|
||||
repeated uint32 sd_req = 3 [packed = true];
|
||||
optional FwType type = 4;
|
||||
|
||||
optional uint32 sd_size = 5;
|
||||
optional uint32 bl_size = 6;
|
||||
optional uint32 app_size = 7;
|
||||
|
||||
optional Hash hash = 8;
|
||||
|
||||
optional bool is_debug = 9 [default = false];
|
||||
repeated BootValidation boot_validation = 10;
|
||||
}
|
||||
|
||||
// Command type
|
||||
message Command {
|
||||
optional OpCode op_code = 1;
|
||||
optional InitCommand init = 2;
|
||||
}
|
||||
|
||||
// Signed command types
|
||||
enum SignatureType {
|
||||
ECDSA_P256_SHA256 = 0;
|
||||
ED25519 = 1;
|
||||
}
|
||||
|
||||
message SignedCommand {
|
||||
required Command command = 1;
|
||||
required SignatureType signature_type = 2;
|
||||
required bytes signature = 3;
|
||||
}
|
||||
|
||||
// Parent packet type
|
||||
message Packet {
|
||||
optional Command command = 1;
|
||||
optional SignedCommand signed_command = 2;
|
||||
}
|
||||
98
components/libraries/bootloader/dfu/nrf_dfu.c
Normal file
98
components/libraries/bootloader/dfu/nrf_dfu.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_dfu.h"
|
||||
|
||||
#include "nrf_dfu_utils.h"
|
||||
#include "nrf_dfu_transport.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
#include "nrf_log.h"
|
||||
|
||||
static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function calls the user's observer (@ref m_observer) after it is done handling the event.
|
||||
*/
|
||||
static void dfu_observer(nrf_dfu_evt_type_t event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case NRF_DFU_EVT_DFU_COMPLETED:
|
||||
case NRF_DFU_EVT_DFU_ABORTED:
|
||||
#ifndef NRF_DFU_NO_TRANSPORT
|
||||
UNUSED_RETURN_VALUE(nrf_dfu_transports_close(NULL));
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Call user's observer if present. */
|
||||
if (m_user_observer)
|
||||
{
|
||||
m_user_observer(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t nrf_dfu_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
uint32_t ret_val;
|
||||
|
||||
m_user_observer = observer;
|
||||
|
||||
NRF_LOG_INFO("Entering DFU mode.");
|
||||
|
||||
dfu_observer(NRF_DFU_EVT_DFU_INITIALIZED);
|
||||
|
||||
// Initializing transports
|
||||
ret_val = nrf_dfu_transports_init(dfu_observer);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not initalize DFU transport: 0x%08x", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
ret_val = nrf_dfu_req_handler_init(dfu_observer);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
85
components/libraries/bootloader/dfu/nrf_dfu.h
Normal file
85
components/libraries/bootloader/dfu/nrf_dfu.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu DFU modules
|
||||
* @{
|
||||
* @ingroup nrf_bootloader
|
||||
* @brief Modules providing Device Firmware Update (DFU) functionality.
|
||||
*
|
||||
* The DFU module, in combination with the @ref nrf_bootloader module,
|
||||
* can be used to implement a bootloader that supports Device Firmware Updates.
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_H__
|
||||
#define NRF_DFU_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define NRF_DFU_SCHED_EVENT_DATA_SIZE (sizeof(nrf_dfu_request_t))
|
||||
|
||||
|
||||
/** @brief Function for initializing a DFU operation.
|
||||
*
|
||||
* This function initializes a DFU operation and any transports that are registered
|
||||
* in the system.
|
||||
*
|
||||
* @param[in] observer Callback function for receiving DFU notifications.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the DFU operation was successfully initialized.
|
||||
*/
|
||||
uint32_t nrf_dfu_init(nrf_dfu_observer_t observer);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_H__
|
||||
|
||||
/** @} */
|
||||
167
components/libraries/bootloader/dfu/nrf_dfu_flash.c
Normal file
167
components/libraries/bootloader/dfu/nrf_dfu_flash.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nrf_dfu_flash.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
|
||||
#include "nrf_fstorage.h"
|
||||
#include "nrf_fstorage_sd.h"
|
||||
#include "nrf_fstorage_nvmc.h"
|
||||
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_flash
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
void dfu_fstorage_evt_handler(nrf_fstorage_evt_t * p_evt);
|
||||
|
||||
|
||||
NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs) =
|
||||
{
|
||||
.evt_handler = dfu_fstorage_evt_handler,
|
||||
.start_addr = MBR_SIZE,
|
||||
.end_addr = BOOTLOADER_SETTINGS_ADDRESS + BOOTLOADER_SETTINGS_PAGE_SIZE
|
||||
};
|
||||
|
||||
static uint32_t m_flash_operations_pending;
|
||||
|
||||
void dfu_fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
|
||||
{
|
||||
if (NRF_LOG_ENABLED && (m_flash_operations_pending > 0))
|
||||
{
|
||||
m_flash_operations_pending--;
|
||||
}
|
||||
|
||||
if (p_evt->result == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_DEBUG("Flash %s success: addr=%p, pending %d",
|
||||
(p_evt->id == NRF_FSTORAGE_EVT_WRITE_RESULT) ? "write" : "erase",
|
||||
p_evt->addr, m_flash_operations_pending);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("Flash %s failed (0x%x): addr=%p, len=0x%x bytes, pending %d",
|
||||
(p_evt->id == NRF_FSTORAGE_EVT_WRITE_RESULT) ? "write" : "erase",
|
||||
p_evt->result, p_evt->addr, p_evt->len, m_flash_operations_pending);
|
||||
}
|
||||
|
||||
if (p_evt->p_param)
|
||||
{
|
||||
//lint -save -e611 (Suspicious cast)
|
||||
((nrf_dfu_flash_callback_t)(p_evt->p_param))((void*)p_evt->p_src);
|
||||
//lint -restore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_flash_init(bool sd_irq_initialized)
|
||||
{
|
||||
nrf_fstorage_api_t * p_api_impl;
|
||||
|
||||
/* Setup the desired API implementation. */
|
||||
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
|
||||
if (sd_irq_initialized)
|
||||
{
|
||||
NRF_LOG_DEBUG("Initializing nrf_fstorage_sd backend.");
|
||||
p_api_impl = &nrf_fstorage_sd;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
NRF_LOG_DEBUG("Initializing nrf_fstorage_nvmc backend.");
|
||||
p_api_impl = &nrf_fstorage_nvmc;
|
||||
}
|
||||
|
||||
return nrf_fstorage_init(&m_fs, p_api_impl, NULL);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_flash_store(uint32_t dest,
|
||||
void const * p_src,
|
||||
uint32_t len,
|
||||
nrf_dfu_flash_callback_t callback)
|
||||
{
|
||||
ret_code_t rc;
|
||||
|
||||
NRF_LOG_DEBUG("nrf_fstorage_write(addr=%p, src=%p, len=%d bytes), queue usage: %d",
|
||||
dest, p_src, len, m_flash_operations_pending);
|
||||
|
||||
//lint -save -e611 (Suspicious cast)
|
||||
rc = nrf_fstorage_write(&m_fs, dest, p_src, len, (void *)callback);
|
||||
//lint -restore
|
||||
|
||||
if ((NRF_LOG_ENABLED) && (rc == NRF_SUCCESS))
|
||||
{
|
||||
m_flash_operations_pending++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_WARNING("nrf_fstorage_write() failed with error 0x%x.", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_flash_erase(uint32_t page_addr,
|
||||
uint32_t num_pages,
|
||||
nrf_dfu_flash_callback_t callback)
|
||||
{
|
||||
ret_code_t rc;
|
||||
|
||||
NRF_LOG_DEBUG("nrf_fstorage_erase(addr=0x%p, len=%d pages), queue usage: %d",
|
||||
page_addr, num_pages, m_flash_operations_pending);
|
||||
|
||||
//lint -save -e611 (Suspicious cast)
|
||||
rc = nrf_fstorage_erase(&m_fs, page_addr, num_pages, (void *)callback);
|
||||
//lint -restore
|
||||
|
||||
if ((NRF_LOG_ENABLED) && (rc == NRF_SUCCESS))
|
||||
{
|
||||
m_flash_operations_pending++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_WARNING("nrf_fstorage_erase() failed with error 0x%x.", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
132
components/libraries/bootloader/dfu/nrf_dfu_flash.h
Normal file
132
components/libraries/bootloader/dfu/nrf_dfu_flash.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup sdk_nrf_dfu_flash Flash operations
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_FLASH_H__
|
||||
#define NRF_DFU_FLASH_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdk_errors.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief nrf_fstorage event handler function for DFU fstorage operations.
|
||||
*
|
||||
* This function will be called after a flash operation has completed.
|
||||
*/
|
||||
typedef void (*nrf_dfu_flash_callback_t)(void * p_buf);
|
||||
|
||||
|
||||
/**@brief Function for initializing the flash module.
|
||||
*
|
||||
* Depending on whether or not the SoftDevice is present and its IRQ have been initialized,
|
||||
* this function initializes the correct @ref nrf_fstorage backend.
|
||||
*
|
||||
* @param[in] sd_irq_initialized Whether or not the SoftDevice IRQ have been initialized.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
*/
|
||||
ret_code_t nrf_dfu_flash_init(bool sd_irq_initialized);
|
||||
|
||||
|
||||
/**@brief Function for storing data to flash.
|
||||
*
|
||||
* This functions is asynchronous when the SoftDevice is enabled and synchronous when
|
||||
* the SoftDevice is not present or disabled. In both cases, if a callback function is provided,
|
||||
* it will be called when the operation has completed.
|
||||
*
|
||||
* @note The content of @p p_src should be kept in memory until the operation has completed.
|
||||
*
|
||||
* @param[in] dest The address where the data should be stored.
|
||||
* @param[in] p_src Pointer to the address where the data should be copied from.
|
||||
* This address can be in flash or RAM.
|
||||
* @param[in] len The number of bytes to be copied from @p p_src to @p dest.
|
||||
* @param[in] callback Callback function.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_INVALID_STATE If nrf_dfu_flash is not initialized.
|
||||
* @retval NRF_ERROR_INVALID_ADDR If @p p_src or @p dest is not word-aligned.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH If @p len is zero.
|
||||
* @retval NRF_ERROR_NULL If @p p_src is NULL.
|
||||
* @retval NRF_ERROR_NO_MEM If nrf_fstorage is out of memory.
|
||||
*/
|
||||
ret_code_t nrf_dfu_flash_store(uint32_t dest,
|
||||
void const * p_src,
|
||||
uint32_t len,
|
||||
nrf_dfu_flash_callback_t callback);
|
||||
|
||||
|
||||
/**@brief Function for erasing data from flash.
|
||||
*
|
||||
* This functions is asynchronous when the SoftDevice is enabled and synchronous when
|
||||
* the SoftDevice is not present or disabled. In both cases, if a callback function is provided,
|
||||
* it will be called when the operation has completed.
|
||||
*
|
||||
* @param[in] page_addr The address of the first flash page to be deleted.
|
||||
* @param[in] num_pages The number of flash pages to be deleted.
|
||||
* @param[in] callback Callback function.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_INVALID_STATE If nrf_dfu_flash is not initialized.
|
||||
* @retval NRF_ERROR_INVALID_ADDR If @p page_addr is not aligned to a page boundary or the
|
||||
* operation would go beyond the flash memory boundaries.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH If @p num_pages is zero.
|
||||
* @retval NRF_ERROR_NULL If @p page_addr is NULL.
|
||||
* @retval NRF_ERROR_NO_MEM If the queue of nrf_fstorage is full.
|
||||
*/
|
||||
ret_code_t nrf_dfu_flash_erase(uint32_t page_addr, uint32_t num_pages, nrf_dfu_flash_callback_t callback);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // NRF_DFU_FLASH_H__
|
||||
/** @} */
|
||||
61
components/libraries/bootloader/dfu/nrf_dfu_handling_error.c
Normal file
61
components/libraries/bootloader/dfu/nrf_dfu_handling_error.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nrf_dfu_handling_error.h"
|
||||
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
|
||||
static nrf_dfu_ext_error_code_t m_last_error = NRF_DFU_EXT_ERROR_NO_ERROR;
|
||||
|
||||
nrf_dfu_result_t ext_error_set(nrf_dfu_ext_error_code_t error_code)
|
||||
{
|
||||
m_last_error = error_code;
|
||||
|
||||
return NRF_DFU_RES_CODE_EXT_ERROR;
|
||||
}
|
||||
|
||||
nrf_dfu_ext_error_code_t ext_error_get()
|
||||
{
|
||||
nrf_dfu_ext_error_code_t last_error = m_last_error;
|
||||
m_last_error = NRF_DFU_EXT_ERROR_NO_ERROR;
|
||||
|
||||
return last_error;
|
||||
}
|
||||
125
components/libraries/bootloader/dfu/nrf_dfu_handling_error.h
Normal file
125
components/libraries/bootloader/dfu/nrf_dfu_handling_error.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_rescodes DFU result codes
|
||||
* @{
|
||||
* @ingroup sdk_nrf_dfu_transport
|
||||
* @brief When the DFU controller sends requests to the DFU bootloader on
|
||||
* the DFU target, the DFU bootloader answers with any of these result codes.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DFU_HANDLING_ERROR_H__
|
||||
#define DFU_HANDLING_ERROR_H__
|
||||
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**@brief DFU request extended result codes.
|
||||
*
|
||||
* @details When an event returns @ref NRF_DFU_RES_CODE_EXT_ERROR, it also stores an extended error code.
|
||||
* The transport layer can then send the extended error code together with the error code to give
|
||||
* the controller additional information about the cause of the error.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DFU_EXT_ERROR_NO_ERROR = 0x00, /**< No extended error code has been set. This error indicates an implementation problem. */
|
||||
NRF_DFU_EXT_ERROR_INVALID_ERROR_CODE = 0x01, /**< Invalid error code. This error code should never be used outside of development. */
|
||||
NRF_DFU_EXT_ERROR_WRONG_COMMAND_FORMAT = 0x02, /**< The format of the command was incorrect. This error code is not used in the
|
||||
current implementation, because @ref NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED
|
||||
and @ref NRF_DFU_RES_CODE_INVALID_PARAMETER cover all
|
||||
possible format errors. */
|
||||
NRF_DFU_EXT_ERROR_UNKNOWN_COMMAND = 0x03, /**< The command was successfully parsed, but it is not supported or unknown. */
|
||||
NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID = 0x04, /**< The init command is invalid. The init packet either has
|
||||
an invalid update type or it is missing required fields for the update type
|
||||
(for example, the init packet for a SoftDevice update is missing the SoftDevice size field). */
|
||||
NRF_DFU_EXT_ERROR_FW_VERSION_FAILURE = 0x05, /**< The firmware version is too low. For an application or SoftDevice, the version must be greater than
|
||||
or equal to the current version. For a bootloader, it must be greater than the current version.
|
||||
to the current version. This requirement prevents downgrade attacks.*/
|
||||
NRF_DFU_EXT_ERROR_HW_VERSION_FAILURE = 0x06, /**< The hardware version of the device does not match the required
|
||||
hardware version for the update. */
|
||||
NRF_DFU_EXT_ERROR_SD_VERSION_FAILURE = 0x07, /**< The array of supported SoftDevices for the update does not contain
|
||||
the FWID of the current SoftDevice or the first FWID is '0' on a
|
||||
bootloader which requires the SoftDevice to be present. */
|
||||
NRF_DFU_EXT_ERROR_SIGNATURE_MISSING = 0x08, /**< The init packet does not contain a signature. This error code is not used in the
|
||||
current implementation, because init packets without a signature
|
||||
are regarded as invalid. */
|
||||
NRF_DFU_EXT_ERROR_WRONG_HASH_TYPE = 0x09, /**< The hash type that is specified by the init packet is not supported by the DFU bootloader. */
|
||||
NRF_DFU_EXT_ERROR_HASH_FAILED = 0x0A, /**< The hash of the firmware image cannot be calculated. */
|
||||
NRF_DFU_EXT_ERROR_WRONG_SIGNATURE_TYPE = 0x0B, /**< The type of the signature is unknown or not supported by the DFU bootloader. */
|
||||
NRF_DFU_EXT_ERROR_VERIFICATION_FAILED = 0x0C, /**< The hash of the received firmware image does not match the hash in the init packet. */
|
||||
NRF_DFU_EXT_ERROR_INSUFFICIENT_SPACE = 0x0D, /**< The available space on the device is insufficient to hold the firmware. */
|
||||
} nrf_dfu_ext_error_code_t;
|
||||
|
||||
|
||||
/**@brief Function for setting an extended error code that can be retrieved later.
|
||||
*
|
||||
* @details When an extended error occurs in the DFU process, this function can be used to store the error.
|
||||
*
|
||||
* @param error_code The error code to store.
|
||||
*
|
||||
* @retval NRF_DFU_RES_CODE_EXT_ERROR
|
||||
*/
|
||||
nrf_dfu_result_t ext_error_set(nrf_dfu_ext_error_code_t error_code);
|
||||
|
||||
/**@brief Function for getting the most recent extended error code.
|
||||
*
|
||||
* @details This function is used by the transport layer to fetch the most recent extended error code.
|
||||
*
|
||||
* @return The most recent error code. If the function is called again before a new error occurs, @ref NRF_DFU_EXT_ERROR_NO_ERROR is returned.
|
||||
*/
|
||||
nrf_dfu_ext_error_code_t ext_error_get( void );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // DFU_HANDLING_ERROR_H__
|
||||
|
||||
/** @} */
|
||||
105
components/libraries/bootloader/dfu/nrf_dfu_mbr.c
Normal file
105
components/libraries/bootloader/dfu/nrf_dfu_mbr.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_dfu_mbr.h"
|
||||
#include "nrf_mbr.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
|
||||
#define MBR_IRQ_FORWARD_ADDRESS_ADDRESS (0x20000000) //!< The address of the variable that decides where the MBR forwards interrupts
|
||||
|
||||
uint32_t nrf_dfu_mbr_copy_bl(uint32_t * p_src, uint32_t len)
|
||||
{
|
||||
uint32_t ret_val;
|
||||
uint32_t const len_words = len / sizeof(uint32_t);
|
||||
|
||||
sd_mbr_command_t command =
|
||||
{
|
||||
.command = SD_MBR_COMMAND_COPY_BL,
|
||||
.params.copy_bl.bl_src = p_src,
|
||||
.params.copy_bl.bl_len = len_words
|
||||
};
|
||||
|
||||
ret_val = sd_mbr_command(&command);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_mbr_init_sd(void)
|
||||
{
|
||||
uint32_t ret_val;
|
||||
|
||||
sd_mbr_command_t command =
|
||||
{
|
||||
.command = SD_MBR_COMMAND_INIT_SD
|
||||
};
|
||||
|
||||
ret_val = sd_mbr_command(&command);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_mbr_irq_forward_address_set(void)
|
||||
{
|
||||
uint32_t ret_val = NRF_ERROR_INVALID_PARAM;
|
||||
uint32_t address = MBR_SIZE;
|
||||
|
||||
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
|
||||
sd_mbr_command_t command =
|
||||
{
|
||||
.command = SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET,
|
||||
.params.irq_forward_address_set.address = address,
|
||||
};
|
||||
|
||||
ret_val = sd_mbr_command(&command);
|
||||
#endif
|
||||
|
||||
if (ret_val == NRF_ERROR_INVALID_PARAM)
|
||||
{
|
||||
// Manually set the forward address if this MBR doesn't have the command.
|
||||
*(uint32_t *)(MBR_IRQ_FORWARD_ADDRESS_ADDRESS) = address;
|
||||
|
||||
ret_val = NRF_SUCCESS;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
90
components/libraries/bootloader/dfu/nrf_dfu_mbr.h
Normal file
90
components/libraries/bootloader/dfu/nrf_dfu_mbr.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup sdk_nrf_dfu_mbr MBR functions
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_MBR_H__
|
||||
#define NRF_DFU_MBR_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Function for copying the bootloader using an MBR command.
|
||||
*
|
||||
* @param[in] p_src Source address of the bootloader data to copy.
|
||||
* @param[in] len Length of the data to copy in bytes.
|
||||
*
|
||||
* @return This function will return only if the command request could not be run.
|
||||
* See @ref sd_mbr_command_copy_bl_t for possible return values.
|
||||
*/
|
||||
uint32_t nrf_dfu_mbr_copy_bl(uint32_t * p_src, uint32_t len);
|
||||
|
||||
|
||||
/** @brief Function for initializing the SoftDevice using an MBR command.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the SoftDevice was initialized successfully.
|
||||
* Any other return value indicates that the SoftDevice
|
||||
* could not be initialized.
|
||||
*/
|
||||
uint32_t nrf_dfu_mbr_init_sd(void);
|
||||
|
||||
|
||||
/** @brief Function for setting the address of the IRQ table to the app's using an MBR command.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the address of the new irq table was set. Any other
|
||||
* return value indicates that the address could not be set.
|
||||
*/
|
||||
uint32_t nrf_dfu_mbr_irq_forward_address_set(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_MBR_H__
|
||||
|
||||
/** @} */
|
||||
865
components/libraries/bootloader/dfu/nrf_dfu_req_handler.c
Normal file
865
components/libraries/bootloader/dfu/nrf_dfu_req_handler.c
Normal file
@@ -0,0 +1,865 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdk_config.h"
|
||||
#include "nrf_dfu.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
#include "nrf_dfu_handling_error.h"
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "nrf_dfu_utils.h"
|
||||
#include "nrf_dfu_flash.h"
|
||||
#include "nrf_fstorage.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "app_util.h"
|
||||
#include "pb.h"
|
||||
#include "pb_common.h"
|
||||
#include "pb_decode.h"
|
||||
#include "dfu-cc.pb.h"
|
||||
#include "crc32.h"
|
||||
#include "app_scheduler.h"
|
||||
#include "sdk_macros.h"
|
||||
#include "nrf_crypto.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "nrf_dfu_validation.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_req_handler
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define NRF_DFU_PROTOCOL_VERSION (0x01)
|
||||
|
||||
#ifndef NRF_DFU_PROTOCOL_REDUCED
|
||||
#define NRF_DFU_PROTOCOL_REDUCED 0
|
||||
#endif
|
||||
|
||||
STATIC_ASSERT(DFU_SIGNED_COMMAND_SIZE <= INIT_COMMAND_MAX_SIZE);
|
||||
|
||||
static uint32_t m_firmware_start_addr; /**< Start address of the current firmware image. */
|
||||
static uint32_t m_firmware_size_req; /**< The size of the entire firmware image. Defined by the init command. */
|
||||
|
||||
static nrf_dfu_observer_t m_observer;
|
||||
|
||||
|
||||
static void on_dfu_complete(nrf_fstorage_evt_t * p_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_evt);
|
||||
|
||||
NRF_LOG_DEBUG("All flash operations have completed. DFU completed.");
|
||||
|
||||
m_observer(NRF_DFU_EVT_DFU_COMPLETED);
|
||||
}
|
||||
|
||||
|
||||
static nrf_dfu_result_t ext_err_code_handle(nrf_dfu_result_t ret_val)
|
||||
{
|
||||
if (ret_val < NRF_DFU_RES_CODE_EXT_ERROR)
|
||||
{
|
||||
return ret_val;
|
||||
}
|
||||
else
|
||||
{
|
||||
nrf_dfu_ext_error_code_t ext_err =
|
||||
(nrf_dfu_ext_error_code_t)((uint8_t)ret_val - (uint8_t)NRF_DFU_RES_CODE_EXT_ERROR);
|
||||
return ext_error_set(ext_err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !NRF_DFU_PROTOCOL_REDUCED
|
||||
static void on_protocol_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
UNUSED_PARAMETER(p_req);
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_PROTOCOL_VERSION");
|
||||
|
||||
if (NRF_DFU_PROTOCOL_VERSION_MSG)
|
||||
{
|
||||
p_res->protocol.version = NRF_DFU_PROTOCOL_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("NRF_DFU_OP_PROTOCOL_VERSION disabled.");
|
||||
p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_hw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_HARDWARE_VERSION");
|
||||
|
||||
p_res->hardware.part = NRF_FICR->INFO.PART;
|
||||
p_res->hardware.variant = NRF_FICR->INFO.VARIANT;
|
||||
|
||||
/* FICR values are in Kilobytes, we report them in bytes. */
|
||||
p_res->hardware.memory.ram_size = NRF_FICR->INFO.RAM * 1024;
|
||||
p_res->hardware.memory.rom_size = NRF_FICR->INFO.FLASH * 1024;
|
||||
p_res->hardware.memory.rom_page_size = NRF_FICR->CODEPAGESIZE;
|
||||
}
|
||||
|
||||
|
||||
static void on_fw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_FIRMWARE_VERSION");
|
||||
NRF_LOG_DEBUG("Firmware image requested: %d", p_req->firmware.image_number);
|
||||
|
||||
if (NRF_DFU_PROTOCOL_FW_VERSION_MSG)
|
||||
{
|
||||
uint8_t fw_count = 1;
|
||||
|
||||
if (SD_PRESENT)
|
||||
{
|
||||
fw_count++;
|
||||
}
|
||||
|
||||
if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP)
|
||||
{
|
||||
fw_count++;
|
||||
}
|
||||
|
||||
p_res->result = NRF_DFU_RES_CODE_SUCCESS;
|
||||
|
||||
if (p_req->firmware.image_number == 0)
|
||||
{
|
||||
/* Bootloader is always present and it is always image zero. */
|
||||
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_BOOTLOADER;
|
||||
p_res->firmware.version = s_dfu_settings.bootloader_version;
|
||||
p_res->firmware.addr = BOOTLOADER_START_ADDR;
|
||||
p_res->firmware.len = BOOTLOADER_SIZE;
|
||||
}
|
||||
else if ((p_req->firmware.image_number == 1) && SD_PRESENT)
|
||||
{
|
||||
/* If a SoftDevice is present, it will be firmware image one. */
|
||||
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_SOFTDEVICE;
|
||||
p_res->firmware.version = SD_VERSION_GET(MBR_SIZE);
|
||||
p_res->firmware.addr = MBR_SIZE;
|
||||
p_res->firmware.len = SD_SIZE_GET(MBR_SIZE);
|
||||
}
|
||||
else if ((p_req->firmware.image_number < fw_count))
|
||||
{
|
||||
/* Either there is no SoftDevice and the firmware image requested is one,
|
||||
* or there is a SoftDevice and the firmware image requested is two.
|
||||
*/
|
||||
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_APPLICATION;
|
||||
p_res->firmware.version = s_dfu_settings.app_version;
|
||||
p_res->firmware.addr = nrf_dfu_app_start_address();
|
||||
p_res->firmware.len = s_dfu_settings.bank_0.image_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("No such firmware image");
|
||||
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
|
||||
p_res->firmware.version = 0x00;
|
||||
p_res->firmware.addr = 0x00;
|
||||
p_res->firmware.len = 0x00;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("NRF_DFU_OP_FIRMWARE_VERSION disabled.");
|
||||
p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
|
||||
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_ping_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_PING");
|
||||
p_res->ping.id = p_req->ping.id;
|
||||
}
|
||||
|
||||
|
||||
static void on_mtu_get_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_MTU_GET");
|
||||
p_res->mtu.size = p_req->mtu.size;
|
||||
}
|
||||
#endif // !NRF_DFU_PROTOCOL_REDUCED
|
||||
|
||||
|
||||
static void on_prn_set_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
UNUSED_PARAMETER(p_req);
|
||||
UNUSED_PARAMETER(p_res);
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_RECEIPT_NOTIF_SET");
|
||||
}
|
||||
|
||||
|
||||
static void on_abort_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
UNUSED_PARAMETER(p_req);
|
||||
UNUSED_PARAMETER(p_res);
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_ABORT");
|
||||
|
||||
m_observer(NRF_DFU_EVT_DFU_ABORTED);
|
||||
}
|
||||
|
||||
|
||||
/* Set offset and CRC fields in the response for a 'command' message. */
|
||||
static void cmd_response_offset_and_crc_set(nrf_dfu_response_t * const p_res)
|
||||
{
|
||||
ASSERT(p_res);
|
||||
|
||||
/* Copy the CRC and offset of the init packet. */
|
||||
p_res->crc.offset = s_dfu_settings.progress.command_offset;
|
||||
p_res->crc.crc = s_dfu_settings.progress.command_crc;
|
||||
}
|
||||
|
||||
|
||||
static void on_cmd_obj_select_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
UNUSED_PARAMETER(p_req);
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (command)");
|
||||
|
||||
p_res->select.max_size = INIT_COMMAND_MAX_SIZE;
|
||||
cmd_response_offset_and_crc_set(p_res);
|
||||
}
|
||||
|
||||
|
||||
static void on_cmd_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
ASSERT(p_req);
|
||||
ASSERT(p_res);
|
||||
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (command)");
|
||||
|
||||
m_observer(NRF_DFU_EVT_DFU_STARTED);
|
||||
|
||||
nrf_dfu_result_t ret_val = nrf_dfu_validation_init_cmd_create(p_req->create.object_size);
|
||||
p_res->result = ext_err_code_handle(ret_val);
|
||||
}
|
||||
|
||||
|
||||
static void on_cmd_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
ASSERT(p_req);
|
||||
ASSERT(p_req->write.p_data);
|
||||
ASSERT(p_req->write.len);
|
||||
ASSERT(p_res);
|
||||
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (command)");
|
||||
|
||||
nrf_dfu_result_t ret_val;
|
||||
|
||||
ret_val = nrf_dfu_validation_init_cmd_append(p_req->write.p_data, p_req->write.len);
|
||||
p_res->result = ext_err_code_handle(ret_val);
|
||||
|
||||
/* Update response. This is only used when the PRN is triggered and the 'write' message
|
||||
* is answered with a CRC message and these field are copied into the response. */
|
||||
cmd_response_offset_and_crc_set(p_res);
|
||||
|
||||
/* If a callback to free the request payload buffer was provided, invoke it now. */
|
||||
if (p_req->callback.write)
|
||||
{
|
||||
p_req->callback.write((void*)p_req->write.p_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_cmd_obj_execute_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
ASSERT(p_req);
|
||||
ASSERT(p_res);
|
||||
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (command)");
|
||||
|
||||
nrf_dfu_result_t ret_val;
|
||||
ret_val = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
|
||||
p_res->result = ext_err_code_handle(ret_val);
|
||||
|
||||
if (p_res->result == NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
if (nrf_dfu_settings_write_and_backup(NULL) == NRF_SUCCESS)
|
||||
{
|
||||
/* Setting DFU to initialized */
|
||||
NRF_LOG_DEBUG("Writing valid init command to flash.");
|
||||
}
|
||||
else
|
||||
{
|
||||
p_res->result = NRF_DFU_RES_CODE_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_cmd_obj_crc_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
UNUSED_PARAMETER(p_req);
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (command)");
|
||||
|
||||
cmd_response_offset_and_crc_set(p_res);
|
||||
}
|
||||
|
||||
|
||||
/** @brief Function handling command requests from the transport layer.
|
||||
*
|
||||
* @param p_req[in] Pointer to the structure holding the DFU request.
|
||||
* @param p_res[out] Pointer to the structure holding the DFU response.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the command request was executed successfully.
|
||||
* Any other error code indicates that the data request
|
||||
* could not be handled.
|
||||
*/
|
||||
static void nrf_dfu_command_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
ASSERT(p_req);
|
||||
ASSERT(p_res);
|
||||
|
||||
switch (p_req->request)
|
||||
{
|
||||
case NRF_DFU_OP_OBJECT_CREATE:
|
||||
{
|
||||
on_cmd_obj_create_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_CRC_GET:
|
||||
{
|
||||
on_cmd_obj_crc_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_WRITE:
|
||||
{
|
||||
on_cmd_obj_write_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_EXECUTE:
|
||||
{
|
||||
on_cmd_obj_execute_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
{
|
||||
on_cmd_obj_select_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT(false);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_data_obj_select_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (data)");
|
||||
|
||||
p_res->select.crc = s_dfu_settings.progress.firmware_image_crc;
|
||||
p_res->select.offset = s_dfu_settings.progress.firmware_image_offset;
|
||||
|
||||
p_res->select.max_size = DATA_OBJECT_MAX_SIZE;
|
||||
|
||||
NRF_LOG_DEBUG("crc = 0x%x, offset = 0x%x, max_size = 0x%x",
|
||||
p_res->select.crc,
|
||||
p_res->select.offset,
|
||||
p_res->select.max_size);
|
||||
}
|
||||
|
||||
|
||||
static void on_data_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (data)");
|
||||
|
||||
if (!nrf_dfu_validation_init_cmd_present())
|
||||
{
|
||||
/* Can't accept data because DFU isn't initialized by init command. */
|
||||
NRF_LOG_ERROR("Cannot create data object without valid init command");
|
||||
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_req->create.object_size == 0)
|
||||
{
|
||||
NRF_LOG_ERROR("Object size cannot be 0.")
|
||||
p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ((p_req->create.object_size & (CODE_PAGE_SIZE - 1)) != 0)
|
||||
&& (s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size != m_firmware_size_req))
|
||||
{
|
||||
NRF_LOG_ERROR("Object size must be page aligned");
|
||||
p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_req->create.object_size > DATA_OBJECT_MAX_SIZE)
|
||||
{
|
||||
/* It is impossible to handle the command because the size is too large */
|
||||
NRF_LOG_ERROR("Invalid size for object (too large)");
|
||||
p_res->result = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size) >
|
||||
m_firmware_size_req)
|
||||
{
|
||||
NRF_LOG_ERROR("Creating the object with size 0x%08x would overflow firmware size. "
|
||||
"Offset is 0x%08x and firmware size is 0x%08x.",
|
||||
p_req->create.object_size,
|
||||
s_dfu_settings.progress.firmware_image_offset_last,
|
||||
m_firmware_size_req);
|
||||
|
||||
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
|
||||
return;
|
||||
}
|
||||
|
||||
s_dfu_settings.progress.data_object_size = p_req->create.object_size;
|
||||
s_dfu_settings.progress.firmware_image_crc = s_dfu_settings.progress.firmware_image_crc_last;
|
||||
s_dfu_settings.progress.firmware_image_offset = s_dfu_settings.progress.firmware_image_offset_last;
|
||||
s_dfu_settings.write_offset = s_dfu_settings.progress.firmware_image_offset_last;
|
||||
|
||||
/* Erase the page we're at. */
|
||||
if (nrf_dfu_flash_erase((m_firmware_start_addr + s_dfu_settings.progress.firmware_image_offset),
|
||||
CEIL_DIV(p_req->create.object_size, CODE_PAGE_SIZE), NULL) != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Erase operation failed");
|
||||
p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
|
||||
return;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Creating object with size: %d. Offset: 0x%08x, CRC: 0x%08x",
|
||||
s_dfu_settings.progress.data_object_size,
|
||||
s_dfu_settings.progress.firmware_image_offset,
|
||||
s_dfu_settings.progress.firmware_image_crc);
|
||||
}
|
||||
|
||||
|
||||
static void on_data_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (data)");
|
||||
|
||||
if (!nrf_dfu_validation_init_cmd_present())
|
||||
{
|
||||
/* Can't accept data because DFU isn't initialized by init command. */
|
||||
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t const data_object_offset = s_dfu_settings.progress.firmware_image_offset -
|
||||
s_dfu_settings.progress.firmware_image_offset_last;
|
||||
|
||||
if ((p_req->write.len + data_object_offset) > s_dfu_settings.progress.data_object_size)
|
||||
{
|
||||
/* Can't accept data because too much data has been received. */
|
||||
NRF_LOG_ERROR("Write request too long");
|
||||
p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t const write_addr = m_firmware_start_addr + s_dfu_settings.write_offset;
|
||||
/* CRC must be calculated before handing off the data to fstorage because the data is
|
||||
* freed on write completion.
|
||||
*/
|
||||
uint32_t const next_crc =
|
||||
crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_crc);
|
||||
|
||||
ASSERT(p_req->callback.write);
|
||||
|
||||
ret_code_t ret =
|
||||
nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);
|
||||
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
/* When nrf_dfu_flash_store() fails because there is no space in the queue,
|
||||
* stop processing the request so that the peer can detect a CRC error
|
||||
* and retransmit this object. Remember to manually free the buffer !
|
||||
*/
|
||||
p_req->callback.write((void*)p_req->write.p_data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update the CRC of the firmware image. */
|
||||
s_dfu_settings.write_offset += p_req->write.len;
|
||||
s_dfu_settings.progress.firmware_image_offset += p_req->write.len;
|
||||
s_dfu_settings.progress.firmware_image_crc = next_crc;
|
||||
|
||||
/* This is only used when the PRN is triggered and the 'write' message
|
||||
* is answered with a CRC message and these field are copied into the response.
|
||||
*/
|
||||
p_res->write.crc = s_dfu_settings.progress.firmware_image_crc;
|
||||
p_res->write.offset = s_dfu_settings.progress.firmware_image_offset;
|
||||
}
|
||||
|
||||
|
||||
static void on_data_obj_crc_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (data)");
|
||||
NRF_LOG_DEBUG("Offset:%d, CRC:0x%08x",
|
||||
s_dfu_settings.progress.firmware_image_offset,
|
||||
s_dfu_settings.progress.firmware_image_crc);
|
||||
|
||||
p_res->crc.crc = s_dfu_settings.progress.firmware_image_crc;
|
||||
p_res->crc.offset = s_dfu_settings.progress.firmware_image_offset;
|
||||
}
|
||||
|
||||
|
||||
static void on_data_obj_execute_request_sched(void * p_evt, uint16_t event_length)
|
||||
{
|
||||
UNUSED_PARAMETER(event_length);
|
||||
|
||||
ret_code_t ret;
|
||||
nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
|
||||
|
||||
/* Wait for all buffers to be written in flash. */
|
||||
if (nrf_fstorage_is_busy(NULL))
|
||||
{
|
||||
ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), on_data_obj_execute_request_sched);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed to schedule object execute: 0x%x.", ret);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nrf_dfu_response_t res =
|
||||
{
|
||||
.request = NRF_DFU_OP_OBJECT_EXECUTE,
|
||||
};
|
||||
|
||||
if (s_dfu_settings.progress.firmware_image_offset == m_firmware_size_req)
|
||||
{
|
||||
NRF_LOG_DEBUG("Whole firmware image received. Postvalidating.");
|
||||
|
||||
#if NRF_DFU_IN_APP
|
||||
res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
|
||||
#else
|
||||
res.result = nrf_dfu_validation_activation_prepare(m_firmware_start_addr, m_firmware_size_req);
|
||||
#endif
|
||||
|
||||
res.result = ext_err_code_handle(res.result);
|
||||
|
||||
/* Provide response to transport */
|
||||
p_req->callback.response(&res, p_req->p_context);
|
||||
|
||||
ret = nrf_dfu_settings_write_and_backup((nrf_dfu_flash_callback_t)on_dfu_complete);
|
||||
UNUSED_RETURN_VALUE(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.result = NRF_DFU_RES_CODE_SUCCESS;
|
||||
|
||||
/* Provide response to transport */
|
||||
p_req->callback.response(&res, p_req->p_context);
|
||||
|
||||
if (NRF_DFU_SAVE_PROGRESS_IN_FLASH)
|
||||
{
|
||||
/* Allowing skipping settings backup to save time and flash wear. */
|
||||
ret = nrf_dfu_settings_write_and_backup(NULL);
|
||||
UNUSED_RETURN_VALUE(ret);
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", res.result);
|
||||
}
|
||||
|
||||
|
||||
static bool on_data_obj_execute_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (data)");
|
||||
|
||||
uint32_t const data_object_size = s_dfu_settings.progress.firmware_image_offset -
|
||||
s_dfu_settings.progress.firmware_image_offset_last;
|
||||
|
||||
if (s_dfu_settings.progress.data_object_size != data_object_size)
|
||||
{
|
||||
/* The size of the written object was not as expected. */
|
||||
NRF_LOG_ERROR("Invalid data. expected: %d, got: %d",
|
||||
s_dfu_settings.progress.data_object_size,
|
||||
data_object_size);
|
||||
|
||||
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Update the offset and crc values for the last object written. */
|
||||
s_dfu_settings.progress.data_object_size = 0;
|
||||
s_dfu_settings.progress.firmware_image_crc_last = s_dfu_settings.progress.firmware_image_crc;
|
||||
s_dfu_settings.progress.firmware_image_offset_last = s_dfu_settings.progress.firmware_image_offset;
|
||||
|
||||
on_data_obj_execute_request_sched(p_req, 0);
|
||||
|
||||
m_observer(NRF_DFU_EVT_OBJECT_RECEIVED);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool nrf_dfu_data_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
ASSERT(p_req);
|
||||
ASSERT(p_res);
|
||||
|
||||
bool response_ready = true;
|
||||
|
||||
switch (p_req->request)
|
||||
{
|
||||
case NRF_DFU_OP_OBJECT_CREATE:
|
||||
{
|
||||
on_data_obj_create_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_WRITE:
|
||||
{
|
||||
on_data_obj_write_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_CRC_GET:
|
||||
{
|
||||
on_data_obj_crc_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_EXECUTE:
|
||||
{
|
||||
response_ready = on_data_obj_execute_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
{
|
||||
on_data_obj_select_request(p_req, p_res);
|
||||
} break;
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT(false);
|
||||
} break;
|
||||
}
|
||||
|
||||
return response_ready;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling requests to manipulate data or command objects.
|
||||
*
|
||||
* @param[in] p_req Request.
|
||||
* @param[out] p_res Response.
|
||||
*
|
||||
* @return Whether response is ready to be sent.
|
||||
*/
|
||||
static bool nrf_dfu_obj_op(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
|
||||
{
|
||||
/* Keep track of the current object type since write and execute requests don't contain it. */
|
||||
static nrf_dfu_obj_type_t current_object = NRF_DFU_OBJ_TYPE_COMMAND;
|
||||
|
||||
if ( (p_req->request == NRF_DFU_OP_OBJECT_SELECT)
|
||||
|| (p_req->request == NRF_DFU_OP_OBJECT_CREATE))
|
||||
{
|
||||
STATIC_ASSERT(offsetof(nrf_dfu_request_select_t, object_type) ==
|
||||
offsetof(nrf_dfu_request_create_t, object_type),
|
||||
"Wrong object_type offset!");
|
||||
|
||||
current_object = (nrf_dfu_obj_type_t)(p_req->select.object_type);
|
||||
}
|
||||
|
||||
bool response_ready = true;
|
||||
|
||||
switch (current_object)
|
||||
{
|
||||
case NRF_DFU_OBJ_TYPE_COMMAND:
|
||||
nrf_dfu_command_req(p_req, p_res);
|
||||
break;
|
||||
|
||||
case NRF_DFU_OBJ_TYPE_DATA:
|
||||
response_ready = nrf_dfu_data_req(p_req, p_res);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* The select request had an invalid object type. */
|
||||
NRF_LOG_ERROR("Invalid object type in request.");
|
||||
current_object = NRF_DFU_OBJ_TYPE_INVALID;
|
||||
p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
|
||||
break;
|
||||
}
|
||||
|
||||
return response_ready;
|
||||
}
|
||||
|
||||
|
||||
static void nrf_dfu_req_handler_req_process(nrf_dfu_request_t * p_req)
|
||||
{
|
||||
ASSERT(p_req->callback.response);
|
||||
|
||||
bool response_ready = true;
|
||||
|
||||
/* The request handlers assume these values to be set. */
|
||||
nrf_dfu_response_t response =
|
||||
{
|
||||
.request = p_req->request,
|
||||
.result = NRF_DFU_RES_CODE_SUCCESS,
|
||||
};
|
||||
|
||||
|
||||
switch (p_req->request)
|
||||
{
|
||||
#if !NRF_DFU_PROTOCOL_REDUCED
|
||||
case NRF_DFU_OP_PROTOCOL_VERSION:
|
||||
{
|
||||
on_protocol_version_request(p_req, &response);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_HARDWARE_VERSION:
|
||||
{
|
||||
on_hw_version_request(p_req, &response);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_FIRMWARE_VERSION:
|
||||
{
|
||||
on_fw_version_request(p_req, &response);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_PING:
|
||||
{
|
||||
on_ping_request(p_req, &response);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_MTU_GET:
|
||||
{
|
||||
on_mtu_get_request(p_req, &response);
|
||||
} break;
|
||||
#endif
|
||||
case NRF_DFU_OP_RECEIPT_NOTIF_SET:
|
||||
{
|
||||
on_prn_set_request(p_req, &response);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_ABORT:
|
||||
{
|
||||
on_abort_request(p_req, &response);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_CREATE:
|
||||
/* Restart the inactivity timer on CREATE messages. */
|
||||
/* Fallthrough. */
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
case NRF_DFU_OP_OBJECT_WRITE:
|
||||
case NRF_DFU_OP_OBJECT_EXECUTE:
|
||||
case NRF_DFU_OP_CRC_GET:
|
||||
{
|
||||
response_ready = nrf_dfu_obj_op(p_req, &response);
|
||||
} break;
|
||||
|
||||
default:
|
||||
NRF_LOG_INFO("Invalid opcode received: 0x%x.", p_req->request);
|
||||
response.result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (response_ready)
|
||||
{
|
||||
NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", response.result);
|
||||
|
||||
p_req->callback.response(&response, p_req->p_context);
|
||||
|
||||
if (response.result != NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
m_observer(NRF_DFU_EVT_DFU_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void nrf_dfu_req_handler_req(void * p_evt, uint16_t event_length)
|
||||
{
|
||||
nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
|
||||
nrf_dfu_req_handler_req_process(p_req);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_req_handler_on_req(nrf_dfu_request_t * p_req)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
if (p_req->callback.response == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), nrf_dfu_req_handler_req);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_WARNING("Scheduler ran out of space!");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
ret_code_t ret_val;
|
||||
nrf_dfu_result_t result;
|
||||
|
||||
if (observer == NULL)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
|
||||
ret_val = nrf_dfu_flash_init(true);
|
||||
#else
|
||||
ret_val = nrf_dfu_flash_init(false);
|
||||
#endif
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
nrf_dfu_validation_init();
|
||||
if (nrf_dfu_validation_init_cmd_present())
|
||||
{
|
||||
/* Execute a previously received init packed. Subsequent executes will have no effect. */
|
||||
result = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
|
||||
if (result != NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
/* Init packet in flash is not valid! */
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
m_observer = observer;
|
||||
|
||||
/* Initialize extended error handling with "No error" as the most recent error. */
|
||||
result = ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
|
||||
UNUSED_RETURN_VALUE(result);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
345
components/libraries/bootloader/dfu/nrf_dfu_req_handler.h
Normal file
345
components/libraries/bootloader/dfu/nrf_dfu_req_handler.h
Normal file
@@ -0,0 +1,345 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup sdk_nrf_dfu_req_handler Request handling
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_REQ_HANDLER_H__
|
||||
#define NRF_DFU_REQ_HANDLER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "app_util_platform.h"
|
||||
#include "nrf_dfu_flash.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
ANON_UNIONS_ENABLE;
|
||||
|
||||
/**
|
||||
* @brief DFU object types.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DFU_OBJ_TYPE_INVALID, //!< Invalid object type.
|
||||
NRF_DFU_OBJ_TYPE_COMMAND, //!< Command object.
|
||||
NRF_DFU_OBJ_TYPE_DATA, //!< Data object.
|
||||
} nrf_dfu_obj_type_t;
|
||||
|
||||
/**
|
||||
* @brief DFU protocol operation.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DFU_OP_PROTOCOL_VERSION = 0x00, //!< Retrieve protocol version.
|
||||
NRF_DFU_OP_OBJECT_CREATE = 0x01, //!< Create selected object.
|
||||
NRF_DFU_OP_RECEIPT_NOTIF_SET = 0x02, //!< Set receipt notification.
|
||||
NRF_DFU_OP_CRC_GET = 0x03, //!< Request CRC of selected object.
|
||||
NRF_DFU_OP_OBJECT_EXECUTE = 0x04, //!< Execute selected object.
|
||||
NRF_DFU_OP_OBJECT_SELECT = 0x06, //!< Select object.
|
||||
NRF_DFU_OP_MTU_GET = 0x07, //!< Retrieve MTU size.
|
||||
NRF_DFU_OP_OBJECT_WRITE = 0x08, //!< Write selected object.
|
||||
NRF_DFU_OP_PING = 0x09, //!< Ping.
|
||||
NRF_DFU_OP_HARDWARE_VERSION = 0x0A, //!< Retrieve hardware version.
|
||||
NRF_DFU_OP_FIRMWARE_VERSION = 0x0B, //!< Retrieve firmware version.
|
||||
NRF_DFU_OP_ABORT = 0x0C, //!< Abort the DFU procedure.
|
||||
NRF_DFU_OP_RESPONSE = 0x60, //!< Response.
|
||||
NRF_DFU_OP_INVALID = 0xFF,
|
||||
} nrf_dfu_op_t;
|
||||
|
||||
/**
|
||||
* @brief DFU operation result code.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DFU_RES_CODE_INVALID = 0x00, //!< Invalid opcode.
|
||||
NRF_DFU_RES_CODE_SUCCESS = 0x01, //!< Operation successful.
|
||||
NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED = 0x02, //!< Opcode not supported.
|
||||
NRF_DFU_RES_CODE_INVALID_PARAMETER = 0x03, //!< Missing or invalid parameter value.
|
||||
NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES = 0x04, //!< Not enough memory for the data object.
|
||||
NRF_DFU_RES_CODE_INVALID_OBJECT = 0x05, //!< Data object does not match the firmware and hardware requirements, the signature is wrong, or parsing the command failed.
|
||||
NRF_DFU_RES_CODE_UNSUPPORTED_TYPE = 0x07, //!< Not a valid object type for a Create request.
|
||||
NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED = 0x08, //!< The state of the DFU process does not allow this operation.
|
||||
NRF_DFU_RES_CODE_OPERATION_FAILED = 0x0A, //!< Operation failed.
|
||||
NRF_DFU_RES_CODE_EXT_ERROR = 0x0B, //!< Extended error. The next byte of the response contains the error code of the extended error (see @ref nrf_dfu_ext_error_code_t.
|
||||
} nrf_dfu_result_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NRF_DFU_FIRMWARE_TYPE_SOFTDEVICE = 0x00,
|
||||
NRF_DFU_FIRMWARE_TYPE_APPLICATION = 0x01,
|
||||
NRF_DFU_FIRMWARE_TYPE_BOOTLOADER = 0x02,
|
||||
NRF_DFU_FIRMWARE_TYPE_UNKNOWN = 0xFF,
|
||||
} nrf_dfu_firmware_type_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_PROTOCOL_VERSION response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t version; //!< Protocol version.
|
||||
} nrf_dfu_response_protocol_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_HARDWARE_VERSION response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t part; //!< Hardware part, from FICR register.
|
||||
uint32_t variant; //!< Hardware variant, from FICR register.
|
||||
struct
|
||||
{
|
||||
uint32_t rom_size; //!< ROM size, in bytes.
|
||||
uint32_t ram_size; //!< RAM size, in bytes.
|
||||
uint32_t rom_page_size; //!< ROM flash page size, in bytes.
|
||||
} memory;
|
||||
} nrf_dfu_response_hardware_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_FIRMWARE_VERSION response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_dfu_firmware_type_t type; //!< Firmware type.
|
||||
uint32_t version; //!< Firmware version.
|
||||
uint32_t addr; //!< Firmware address in flash.
|
||||
uint32_t len; //!< Firmware length in bytes.
|
||||
} nrf_dfu_response_firmware_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_OBJECT_SELECT response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t offset; //!< Current offset.
|
||||
uint32_t crc; //!< Current CRC.
|
||||
uint32_t max_size; //!< Maximum size of selected object.
|
||||
} nrf_dfu_response_select_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_OBJECT_CREATE response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t offset; //!< Current offset
|
||||
uint32_t crc; //!< Current CRC.
|
||||
} nrf_dfu_response_create_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_OBJECT_WRITE response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t offset; //!< Used only when packet receipt notification is used.
|
||||
uint32_t crc; //!< Used only when packet receipt notification is used.
|
||||
} nrf_dfu_response_write_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_CRC_GET response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t offset; //!< Current offset.
|
||||
uint32_t crc; //!< Current CRC.
|
||||
} nrf_dfu_response_crc_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_PING response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t id; //!< The received ID which is echoed back.
|
||||
} nrf_dfu_response_ping_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_MTU_GET response details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t size; //!< The MTU size as specified by the local transport.
|
||||
} nrf_dfu_response_mtu_t;
|
||||
|
||||
/**
|
||||
* @brief DFU response message.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_dfu_op_t request; //!< Requested operation.
|
||||
nrf_dfu_result_t result; //!< Result of the operation.
|
||||
union
|
||||
{
|
||||
nrf_dfu_response_protocol_t protocol; //!< Protocol version response.
|
||||
nrf_dfu_response_hardware_t hardware; //!< Hardware version response.
|
||||
nrf_dfu_response_firmware_t firmware; //!< Firmware version response.
|
||||
nrf_dfu_response_select_t select; //!< Select object response..
|
||||
nrf_dfu_response_create_t create; //!< Create object response..
|
||||
nrf_dfu_response_write_t write; //!< Write object response.
|
||||
nrf_dfu_response_crc_t crc; //!< CRC response.
|
||||
nrf_dfu_response_ping_t ping; //!< Ping response.
|
||||
nrf_dfu_response_mtu_t mtu; //!< MTU response.
|
||||
};
|
||||
} nrf_dfu_response_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_FIRMWARE_VERSION request details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t image_number; //!< Index of the firmware.
|
||||
} nrf_dfu_request_firmware_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_OBJECT_SELECT request details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t object_type; //!< Object type. See @ref nrf_dfu_obj_type_t.
|
||||
} nrf_dfu_request_select_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_OBJECT_CREATE request details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t object_type; //!< Object type. See @ref nrf_dfu_obj_type_t.
|
||||
uint32_t object_size; //!< Object size in bytes.
|
||||
} nrf_dfu_request_create_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_OBJECT_WRITE request details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t const * p_data; //!< Data.
|
||||
uint16_t len; //!< Length of data in @ref nrf_dfu_request_write_t::p_data.
|
||||
} nrf_dfu_request_write_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_PING request details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t id; //!< Ping ID that will be returned in response.
|
||||
} nrf_dfu_request_ping_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_MTU_GET request details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t size; //!< Transport MTU size in bytes.
|
||||
} nrf_dfu_request_mtu_t;
|
||||
|
||||
/**
|
||||
* @brief @ref NRF_DFU_OP_RECEIPT_NOTIF_SET request details.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t target; //!< Target PRN.
|
||||
} nrf_dfu_request_prn_t;
|
||||
|
||||
|
||||
typedef void (*nrf_dfu_response_callback_t)(nrf_dfu_response_t * p_res, void * p_context);
|
||||
|
||||
/**
|
||||
*@brief DFU request.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_dfu_op_t request; //!< Requested operation.
|
||||
void * p_context;
|
||||
struct
|
||||
{
|
||||
nrf_dfu_response_callback_t response; //!< Callback to call to send the response.
|
||||
nrf_dfu_flash_callback_t write;
|
||||
} callback;
|
||||
union
|
||||
{
|
||||
nrf_dfu_request_firmware_t firmware; //!< Firmware version request.
|
||||
nrf_dfu_request_select_t select; //!< Select object request.
|
||||
nrf_dfu_request_create_t create; //!< Create object request.
|
||||
nrf_dfu_request_write_t write; //!< Write object request.
|
||||
nrf_dfu_request_ping_t ping; //!< Ping.
|
||||
nrf_dfu_request_mtu_t mtu; //!< MTU size request.
|
||||
nrf_dfu_request_prn_t prn; //!< Set receipt notification request.
|
||||
};
|
||||
} nrf_dfu_request_t;
|
||||
|
||||
|
||||
/**@brief Function for initializing the request handling module.
|
||||
*
|
||||
* @param observer Callback function for receiving notifications.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the operation was successful.
|
||||
* @retval NRF_ERROR_INTERNAL If the init packet in flash is not valid.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If observer is not provided.
|
||||
*/
|
||||
ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer);
|
||||
|
||||
|
||||
/**@brief Function for scheduling processing of a DFU request.
|
||||
*
|
||||
* Requests are processed asynchronously by the scheduler.
|
||||
*
|
||||
* @param[in] p_req Request to be handled. The response callback must be non-null.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the command request was executed successfully.
|
||||
* @retval NRF_ERROR_NO_MEM If the scheduler ran out of memory.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If the response callback is NULL.
|
||||
*/
|
||||
ret_code_t nrf_dfu_req_handler_on_req(nrf_dfu_request_t * p_req);
|
||||
|
||||
|
||||
ANON_UNIONS_DISABLE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_REQ_HANDLER_H__
|
||||
|
||||
/** @} */
|
||||
433
components/libraries/bootloader/dfu/nrf_dfu_settings.c
Normal file
433
components/libraries/bootloader/dfu/nrf_dfu_settings.c
Normal file
@@ -0,0 +1,433 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "nrf_dfu_flash.h"
|
||||
#include "nrf_soc.h"
|
||||
#include "crc32.h"
|
||||
#include "nrf_nvmc.h"
|
||||
#include "sdk_config.h"
|
||||
|
||||
|
||||
#define DFU_SETTINGS_VERSION_OFFSET (offsetof(nrf_dfu_settings_t, settings_version)) //<! Offset in the settings struct where the settings version is located.
|
||||
#define DFU_SETTINGS_INIT_COMMAND_OFFSET (offsetof(nrf_dfu_settings_t, init_command)) //<! Offset in the settings struct where the InitCommand is located.
|
||||
#define DFU_SETTINGS_BOOT_VALIDATION_OFFSET (offsetof(nrf_dfu_settings_t, boot_validation_crc)) //<! Offset in the settings struct where the boot validation info is located.
|
||||
#define DFU_SETTINGS_BOOT_VALIDATION_SIZE ((3 * sizeof(boot_validation_t)) + 4)
|
||||
#define DFU_SETTINGS_BOND_DATA_OFFSET_V1 (offsetof(nrf_dfu_settings_t, init_command) + INIT_COMMAND_MAX_SIZE_v1) //<! Offset in the settings struct where the bond data was located in settings version 1.
|
||||
#define DFU_SETTINGS_ADV_NAME_OFFSET_V1 (offsetof(nrf_dfu_settings_t, init_command) + INIT_COMMAND_MAX_SIZE_v1 + NRF_DFU_PEER_DATA_LEN) //<! Offset in the settings struct where the bond data was located in settings version 1.
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_settings
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
/**@brief This variable reserves a page in flash for bootloader settings
|
||||
* to ensure the linker doesn't place any code or variables at this location.
|
||||
*/
|
||||
#if defined (__CC_ARM )
|
||||
|
||||
uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE]
|
||||
__attribute__((at(BOOTLOADER_SETTINGS_ADDRESS)))
|
||||
__attribute__((used));
|
||||
|
||||
#elif defined ( __GNUC__ ) || defined ( __SES_ARM )
|
||||
|
||||
uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE]
|
||||
__attribute__((section(".bootloader_settings_page")))
|
||||
__attribute__((used));
|
||||
|
||||
#elif defined ( __ICCARM__ )
|
||||
|
||||
__no_init __root uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE]
|
||||
@ BOOTLOADER_SETTINGS_ADDRESS;
|
||||
|
||||
#else
|
||||
|
||||
#error Not a valid compiler/linker for m_dfu_settings placement.
|
||||
|
||||
#endif // Compiler specific
|
||||
|
||||
#if defined(NRF52_SERIES)
|
||||
|
||||
/**@brief This variable reserves a page in flash for MBR parameters
|
||||
* to ensure the linker doesn't place any code or variables at this location.
|
||||
*/
|
||||
#if defined ( __CC_ARM )
|
||||
|
||||
uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE]
|
||||
__attribute__((at(NRF_MBR_PARAMS_PAGE_ADDRESS)))
|
||||
__attribute__((used));
|
||||
|
||||
#elif defined ( __GNUC__ ) || defined ( __SES_ARM )
|
||||
|
||||
uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE]
|
||||
__attribute__((section(".mbr_params_page")))
|
||||
__attribute__((used));
|
||||
|
||||
#elif defined ( __ICCARM__ )
|
||||
|
||||
__no_init uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE]
|
||||
@ NRF_MBR_PARAMS_PAGE_ADDRESS;
|
||||
|
||||
#else
|
||||
|
||||
#error Not a valid compiler/linker for m_mbr_params_page placement.
|
||||
|
||||
#endif // Compiler specific
|
||||
|
||||
uint8_t * mp_dfu_settings_backup_buffer = &m_mbr_params_page[0];
|
||||
|
||||
|
||||
#ifndef NRF_DFU_IN_APP
|
||||
#define NRF_DFU_IN_APP 0
|
||||
#endif
|
||||
|
||||
|
||||
#define UICR_PARAM_PAGE_ADDR 0x10001018
|
||||
|
||||
#if !defined(BL_SETTINGS_ACCESS_ONLY) && !NRF_DFU_IN_APP
|
||||
/**@brief This variable has the linker write the MBR parameters page address to the
|
||||
* UICR register. This value will be written in the HEX file and thus to the
|
||||
* UICR when the bootloader is flashed into the chip.
|
||||
*/
|
||||
#if defined ( __CC_ARM )
|
||||
|
||||
uint32_t const m_uicr_mbr_params_page_address
|
||||
__attribute__((at(UICR_PARAM_PAGE_ADDR))) = NRF_MBR_PARAMS_PAGE_ADDRESS;
|
||||
|
||||
#elif defined ( __GNUC__ ) || defined ( __SES_ARM )
|
||||
|
||||
uint32_t const m_uicr_mbr_params_page_address
|
||||
__attribute__ ((section(".uicr_mbr_params_page")))
|
||||
__attribute__ ((used)) = NRF_MBR_PARAMS_PAGE_ADDRESS;
|
||||
|
||||
#elif defined ( __ICCARM__ )
|
||||
|
||||
__root uint32_t const m_uicr_mbr_params_page_address
|
||||
@ UICR_PARAM_PAGE_ADDR = NRF_MBR_PARAMS_PAGE_ADDRESS;
|
||||
|
||||
#else
|
||||
|
||||
#error Not a valid compiler/linker for m_mbr_params_page placement.
|
||||
|
||||
#endif // Compiler specific
|
||||
#endif // #ifndef BL_SETTINGS_ACCESS_ONLY
|
||||
#endif // #if defined( NRF52_SERIES )
|
||||
|
||||
nrf_dfu_settings_t s_dfu_settings;
|
||||
|
||||
static uint32_t settings_crc_get(nrf_dfu_settings_t const * p_settings)
|
||||
{
|
||||
ASSERT(offsetof(nrf_dfu_settings_t, crc) == 0);
|
||||
|
||||
// The crc is calculated from the s_dfu_settings struct, except the crc itself, the init command, bond data, and boot validation.
|
||||
return crc32_compute((uint8_t*)(p_settings) + 4, DFU_SETTINGS_INIT_COMMAND_OFFSET - 4, NULL);
|
||||
}
|
||||
|
||||
|
||||
static bool crc_ok(nrf_dfu_settings_t const * p_settings)
|
||||
{
|
||||
if (p_settings->crc != 0xFFFFFFFF)
|
||||
{
|
||||
// CRC is set. Content must be valid
|
||||
uint32_t crc = settings_crc_get(p_settings);
|
||||
if (crc == p_settings->crc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t boot_validation_crc(nrf_dfu_settings_t const * p_settings)
|
||||
{
|
||||
return crc32_compute((const uint8_t *)&p_settings->boot_validation_softdevice,
|
||||
DFU_SETTINGS_BOOT_VALIDATION_SIZE - 4,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
static bool boot_validation_crc_ok(nrf_dfu_settings_t const * p_settings)
|
||||
{
|
||||
return (boot_validation_crc(p_settings) == p_settings->boot_validation_crc);
|
||||
}
|
||||
|
||||
|
||||
static bool settings_crc_ok(void)
|
||||
{
|
||||
nrf_dfu_settings_t const * p_settings = (nrf_dfu_settings_t const *)m_dfu_settings_buffer;
|
||||
return crc_ok(p_settings);
|
||||
}
|
||||
|
||||
|
||||
static bool settings_backup_crc_ok(void)
|
||||
{
|
||||
nrf_dfu_settings_t const * p_settings = (nrf_dfu_settings_t const *)mp_dfu_settings_backup_buffer;
|
||||
return crc_ok(p_settings) && ((p_settings->settings_version == 1) || boot_validation_crc_ok(p_settings));
|
||||
}
|
||||
|
||||
#define REGION_COPY_BY_MEMBER(start_member, end_member, p_dst_addr) \
|
||||
memcpy(p_dst_addr + offsetof(nrf_dfu_settings_t, start_member), \
|
||||
mp_dfu_settings_backup_buffer + offsetof(nrf_dfu_settings_t, start_member), \
|
||||
offsetof(nrf_dfu_settings_t, end_member) - offsetof(nrf_dfu_settings_t, start_member))
|
||||
|
||||
|
||||
static void settings_forbidden_parts_copy_from_backup(uint8_t * p_dst_addr)
|
||||
{
|
||||
#if NRF_DFU_IN_APP || NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
|
||||
REGION_COPY_BY_MEMBER(settings_version, bank_current, p_dst_addr);
|
||||
REGION_COPY_BY_MEMBER(bank_0, write_offset, p_dst_addr);
|
||||
REGION_COPY_BY_MEMBER(sd_size, progress, p_dst_addr);
|
||||
REGION_COPY_BY_MEMBER(boot_validation_crc, peer_data, p_dst_addr);
|
||||
#else
|
||||
REGION_COPY_BY_MEMBER(settings_version, enter_buttonless_dfu, p_dst_addr);
|
||||
REGION_COPY_BY_MEMBER(init_command, peer_data, p_dst_addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void nrf_dfu_settings_reinit(void)
|
||||
{
|
||||
bool settings_valid = settings_crc_ok();
|
||||
bool settings_backup_valid = settings_backup_crc_ok();
|
||||
|
||||
if (settings_valid)
|
||||
{
|
||||
NRF_LOG_DEBUG("Using settings page.");
|
||||
memcpy(&s_dfu_settings, m_dfu_settings_buffer, sizeof(nrf_dfu_settings_t));
|
||||
if (settings_backup_valid)
|
||||
{
|
||||
NRF_LOG_DEBUG("Copying forbidden parts from backup page.");
|
||||
settings_forbidden_parts_copy_from_backup((uint8_t *)&s_dfu_settings);
|
||||
}
|
||||
}
|
||||
else if (settings_backup_valid)
|
||||
{
|
||||
NRF_LOG_INFO("Restoring settings from backup since the settings page contents are "
|
||||
"invalid (CRC error).");
|
||||
memcpy(&s_dfu_settings,
|
||||
mp_dfu_settings_backup_buffer,
|
||||
sizeof(nrf_dfu_settings_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_WARNING("Resetting bootloader settings since neither the settings page nor the "
|
||||
"backup are valid (CRC error).");
|
||||
memset(&s_dfu_settings, 0x00, sizeof(nrf_dfu_settings_t));
|
||||
s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
|
||||
}
|
||||
|
||||
if (NRF_DFU_SETTINGS_COMPATIBILITY_MODE && !NRF_DFU_IN_APP && (s_dfu_settings.settings_version == 1))
|
||||
{
|
||||
NRF_LOG_INFO("Old settings page detected. Upgrading info.");
|
||||
|
||||
// Old version. Translate.
|
||||
memcpy(&s_dfu_settings.peer_data, (uint8_t *)&s_dfu_settings + DFU_SETTINGS_BOND_DATA_OFFSET_V1, NRF_DFU_PEER_DATA_LEN);
|
||||
memcpy(&s_dfu_settings.adv_name, (uint8_t *)&s_dfu_settings + DFU_SETTINGS_ADV_NAME_OFFSET_V1, NRF_DFU_ADV_NAME_LEN);
|
||||
|
||||
// Initialize with defaults.
|
||||
s_dfu_settings.boot_validation_softdevice.type = NO_VALIDATION;
|
||||
s_dfu_settings.boot_validation_app.type = VALIDATE_CRC;
|
||||
s_dfu_settings.boot_validation_bootloader.type = NO_VALIDATION;
|
||||
memcpy(s_dfu_settings.boot_validation_app.bytes, &s_dfu_settings.bank_0.image_crc, sizeof(uint32_t));
|
||||
|
||||
s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ret_code_t nrf_dfu_settings_init(bool sd_irq_initialized)
|
||||
{
|
||||
NRF_LOG_DEBUG("Calling nrf_dfu_settings_init()...");
|
||||
|
||||
ret_code_t err_code = nrf_dfu_flash_init(sd_irq_initialized);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("nrf_dfu_flash_init() failed with error: %x", err_code);
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
nrf_dfu_settings_reinit();
|
||||
|
||||
err_code = nrf_dfu_settings_write_and_backup(NULL);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("nrf_dfu_settings_write_and_backup() failed with error: %x", err_code);
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static bool settings_forbidden_parts_equal_to_backup(uint8_t * p_compare_addr)
|
||||
{
|
||||
nrf_dfu_settings_t temp_settings;
|
||||
memcpy(&temp_settings, p_compare_addr, sizeof(nrf_dfu_settings_t));
|
||||
settings_forbidden_parts_copy_from_backup((uint8_t *)&temp_settings);
|
||||
return memcmp(&temp_settings, p_compare_addr, sizeof(nrf_dfu_settings_t)) == 0;
|
||||
}
|
||||
|
||||
|
||||
static ret_code_t settings_write(void * p_dst,
|
||||
void const * p_src,
|
||||
nrf_dfu_flash_callback_t callback,
|
||||
nrf_dfu_settings_t * p_dfu_settings_buffer)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
if (memcmp(p_dst, p_src, sizeof(nrf_dfu_settings_t)) == 0)
|
||||
{
|
||||
NRF_LOG_DEBUG("Destination settings are identical to source, write not needed. Skipping.");
|
||||
if (callback != NULL)
|
||||
{
|
||||
callback(NULL);
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
if (NRF_DFU_IN_APP && !settings_forbidden_parts_equal_to_backup((uint8_t *)&s_dfu_settings))
|
||||
{
|
||||
NRF_LOG_WARNING("Settings write aborted since it tries writing to forbidden settings.");
|
||||
return NRF_ERROR_FORBIDDEN;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Writing settings...");
|
||||
NRF_LOG_DEBUG("Erasing old settings at: 0x%08x", p_dst);
|
||||
|
||||
// Not setting the callback function because ERASE is required before STORE
|
||||
// Only report completion on successful STORE.
|
||||
err_code = nrf_dfu_flash_erase((uint32_t)p_dst, 1, NULL);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not erase the settings page!");
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
ASSERT(p_dfu_settings_buffer != NULL);
|
||||
memcpy(p_dfu_settings_buffer, p_src, sizeof(nrf_dfu_settings_t));
|
||||
|
||||
err_code = nrf_dfu_flash_store((uint32_t)p_dst,
|
||||
p_dfu_settings_buffer,
|
||||
sizeof(nrf_dfu_settings_t),
|
||||
callback);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not write the DFU settings page!");
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_settings_write(nrf_dfu_flash_callback_t callback)
|
||||
{
|
||||
static nrf_dfu_settings_t dfu_settings_buffer;
|
||||
s_dfu_settings.crc = settings_crc_get(&s_dfu_settings);
|
||||
s_dfu_settings.boot_validation_crc = boot_validation_crc(&s_dfu_settings);
|
||||
return settings_write(m_dfu_settings_buffer,
|
||||
&s_dfu_settings,
|
||||
callback,
|
||||
&dfu_settings_buffer);
|
||||
}
|
||||
|
||||
|
||||
void settings_backup(nrf_dfu_flash_callback_t callback, void * p_src)
|
||||
{
|
||||
#if NRF_DFU_IN_APP
|
||||
NRF_LOG_INFO("Settings backup not available from app.");
|
||||
#else
|
||||
static nrf_dfu_settings_t dfu_settings_buffer;
|
||||
NRF_LOG_INFO("Backing up settings page to address 0x%x.", mp_dfu_settings_backup_buffer);
|
||||
ASSERT(crc_ok(p_src));
|
||||
ret_code_t err_code = settings_write(mp_dfu_settings_backup_buffer,
|
||||
p_src,
|
||||
callback,
|
||||
&dfu_settings_buffer);
|
||||
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not perform backup of bootloader settings! Error: 0x%x", err_code);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void nrf_dfu_settings_backup(nrf_dfu_flash_callback_t callback)
|
||||
{
|
||||
settings_backup(callback, m_dfu_settings_buffer);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_settings_write_and_backup(nrf_dfu_flash_callback_t callback)
|
||||
{
|
||||
#if NRF_DFU_IN_APP
|
||||
ret_code_t err_code = nrf_dfu_settings_write(callback);
|
||||
#else
|
||||
ret_code_t err_code = nrf_dfu_settings_write(NULL);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
settings_backup(callback, &s_dfu_settings);
|
||||
}
|
||||
#endif
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
__WEAK ret_code_t nrf_dfu_settings_additional_erase(void)
|
||||
{
|
||||
NRF_LOG_WARNING("No additional data erased");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void nrf_dfu_settings_progress_reset(void)
|
||||
{
|
||||
memset(s_dfu_settings.init_command, 0xFF, INIT_COMMAND_MAX_SIZE); // Remove the last init command
|
||||
memset(&s_dfu_settings.progress, 0, sizeof(dfu_progress_t));
|
||||
s_dfu_settings.write_offset = 0;
|
||||
}
|
||||
212
components/libraries/bootloader/dfu/nrf_dfu_settings.h
Normal file
212
components/libraries/bootloader/dfu/nrf_dfu_settings.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_settings DFU settings
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_SETTINGS_H__
|
||||
#define NRF_DFU_SETTINGS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_dfu_flash.h"
|
||||
#include "sdk_config.h"
|
||||
#include "sdk_errors.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief Global settings.
|
||||
*
|
||||
* @note Using this variable is not thread-safe.
|
||||
*
|
||||
*/
|
||||
extern nrf_dfu_settings_t s_dfu_settings;
|
||||
|
||||
|
||||
/**@brief Function for writing DFU settings to flash.
|
||||
*
|
||||
* @param[in] callback Pointer to a function that is called after completing the write operation.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the write process was successfully initiated.
|
||||
* @retval NRF_ERROR_INTERNAL If a flash error occurred.
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_write(nrf_dfu_flash_callback_t callback);
|
||||
|
||||
|
||||
/**@brief Function for backing up the settings.
|
||||
*
|
||||
* This function copies the contents of the settings page (in flash) to a separate page (in flash).
|
||||
* During @ref nrf_dfu_settings_init, the backup is restored if the original is invalid.
|
||||
*
|
||||
* @param[in] callback Pointer to a function that is called after completing the write operation.
|
||||
*/
|
||||
void nrf_dfu_settings_backup(nrf_dfu_flash_callback_t callback);
|
||||
|
||||
|
||||
/**@brief Function for writing DFU settings to flash and to backup.
|
||||
*
|
||||
* This function first calls @ref nrf_dfu_settings_write and then @ref nrf_dfu_settings_backup.
|
||||
*
|
||||
* @param[in] callback Pointer to a function that is called after completing the write and backup operation.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the write process was successfully initiated.
|
||||
* @retval NRF_ERROR_INTERNAL If a flash error occurred during the first write.
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_write_and_backup(nrf_dfu_flash_callback_t callback);
|
||||
|
||||
|
||||
/**@brief Function for initializing the DFU settings structure.
|
||||
*
|
||||
* Initializes the RAM structure from the flash contents.
|
||||
* This function is called as part of @ref nrf_dfu_settings_init.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the initialization was successful.
|
||||
* @retval NRF_ERROR_INTERNAL If a flash error occurred.
|
||||
*/
|
||||
void nrf_dfu_settings_reinit(void);
|
||||
|
||||
|
||||
/**@brief Function for initializing the DFU settings module.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the initialization was successful.
|
||||
* @retval NRF_ERROR_INTERNAL If a flash error occurred.
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_init(bool sd_irq_initialized);
|
||||
|
||||
|
||||
#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE
|
||||
/** @brief Function for storing peer data received through an SVCI call in DFU settings.
|
||||
*
|
||||
* @note The content of the type can be verified by a CRC value stored inside the struct
|
||||
* If the CRC value is 0xFFFFFFFF, it means that no data is set.
|
||||
*
|
||||
* @note The storage operation is an asynchronous progress. Success will be notified
|
||||
* through system events raised by the SoftDevice.
|
||||
*
|
||||
* @param[in] p_data Peer data to be stored in flash.
|
||||
*
|
||||
* @retval NRF_SUCCESS Asynchronous operation was successfully started.
|
||||
* @retval NRF_ERROR_NULL p_data was NULL.
|
||||
* @retval Any other error code reported by SoftDevice API calls.
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_peer_data_write(nrf_dfu_peer_data_t * p_data);
|
||||
|
||||
|
||||
/** @brief Function for copying peer data from DFU settings to RAM.
|
||||
*
|
||||
* @param[in,out] p_data Structure to copy peer data to.
|
||||
*
|
||||
* @retval NRF_SUCCESS Peer data was successfully copied.
|
||||
* @retval NRF_ERROR_NULL p_data was NULL.
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_peer_data_copy(nrf_dfu_peer_data_t * p_data);
|
||||
|
||||
|
||||
/** @brief Function for validating peer data in DFU settings.
|
||||
*
|
||||
* @retval True if peer data is validated by CRC, false if not.
|
||||
*/
|
||||
bool nrf_dfu_settings_peer_data_is_valid(void);
|
||||
|
||||
|
||||
/** @brief Function for storing an advertisement name received through an SVCI call in DFU settings.
|
||||
*
|
||||
* @note The content of the type is verifyable by a CRC-value stored inside the struct.
|
||||
*
|
||||
* @note The storage operation is an asynchronous progress. Success will be notified
|
||||
* through system events raised by the SoftDevice.
|
||||
*
|
||||
* @param[in] p_adv_name Structure holding information about the new advertisement name.
|
||||
*
|
||||
* @retval NRF_SUCCESS Asynchronous operation was successfully started.
|
||||
* @retval NRF_ERROR_NULL p_adv_name was NULL.
|
||||
* @retval Any other error code reported by SoftDevice API calls.
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_adv_name_write(nrf_dfu_adv_name_t * p_adv_name);
|
||||
|
||||
|
||||
/** @brief Function for copying the advertisement name from DFU settings to RAM.
|
||||
*
|
||||
* @param[in,out] p_adv_name Structure to copy the new advertisement name to.
|
||||
*
|
||||
* @retval NRF_SUCCESS Advertisement name was successfully copied.
|
||||
* @retval NRF_ERROR_NULL p_adv_name was NULL.
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_adv_name_copy(nrf_dfu_adv_name_t * p_adv_name);
|
||||
|
||||
|
||||
/** @brief Function for validating advertisement data in DFU settings.
|
||||
*
|
||||
* @retval True if advertisement name is validated by CRC, false if not.
|
||||
*/
|
||||
bool nrf_dfu_settings_adv_name_is_valid(void);
|
||||
|
||||
#endif // NRF_DFU_TRANSPORT_BLE
|
||||
|
||||
/** @brief Function for erasing additional data in DFU settings.
|
||||
*
|
||||
* @note Erasing additional data in DFU settings is only possible
|
||||
* if nrf_dfu_flash is initialized to not use SoftDevice calls.
|
||||
*
|
||||
* @retval NRF_SUCCESS Additional data was successfully erased.
|
||||
* @retval Any other error code reported by nrf_dfu_flash
|
||||
*/
|
||||
ret_code_t nrf_dfu_settings_additional_erase(void);
|
||||
|
||||
/** @brief Function for resetting both init command and DFU transfer progress inside settings structure.
|
||||
*
|
||||
* @note This function does not perform flash operation.
|
||||
* In order to save the reset state, please use @ref nrf_dfu_settings_write function.
|
||||
*/
|
||||
void nrf_dfu_settings_progress_reset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_SETTINGS_H__
|
||||
|
||||
/**@} */
|
||||
185
components/libraries/bootloader/dfu/nrf_dfu_settings_svci.c
Normal file
185
components/libraries/bootloader/dfu/nrf_dfu_settings_svci.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "app_error.h"
|
||||
#include "sdk_macros.h"
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "nrf_nvmc.h"
|
||||
#include "crc32.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_settings_svci
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define DFU_SETTINGS_PEER_DATA_OFFSET offsetof(nrf_dfu_settings_t, peer_data) //<! Offset in the settings struct where the additional peer data is located.
|
||||
#define DFU_SETTINGS_ADV_NAME_OFFSET offsetof(nrf_dfu_settings_t, adv_name) //<! Offset in the settings struct where the additional advertisement name is located.
|
||||
|
||||
extern nrf_dfu_settings_t s_dfu_settings;
|
||||
extern uint8_t m_dfu_settings_buffer[CODE_PAGE_SIZE];
|
||||
|
||||
#if defined(NRF_DFU_BLE_REQUIRES_BONDS) && (NRF_DFU_BLE_REQUIRES_BONDS == 1)
|
||||
|
||||
ret_code_t nrf_dfu_settings_peer_data_write(nrf_dfu_peer_data_t * p_data)
|
||||
{
|
||||
uint32_t ret_val;
|
||||
|
||||
uint32_t * p_peer_data_settings =
|
||||
(uint32_t*) &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET];
|
||||
|
||||
uint32_t crc = (uint32_t)*p_peer_data_settings;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_data);
|
||||
|
||||
if (crc != 0xFFFFFFFF)
|
||||
{
|
||||
// Already written to, must be cleared out
|
||||
// Reset required.
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// Calculate the CRC for the structure excluding the CRC value itself.
|
||||
p_data->crc = crc32_compute((uint8_t*)p_data + 4, sizeof(nrf_dfu_peer_data_t) - 4, NULL);
|
||||
|
||||
// Using SoftDevice call since this function cannot use static memory.
|
||||
ret_val = sd_flash_write(p_peer_data_settings,
|
||||
(uint32_t*)p_data,
|
||||
sizeof(nrf_dfu_peer_data_t)/4);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_settings_peer_data_copy(nrf_dfu_peer_data_t * p_data)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_data);
|
||||
|
||||
memcpy(p_data, &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET], sizeof(nrf_dfu_peer_data_t));
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool nrf_dfu_settings_peer_data_is_valid(void)
|
||||
{
|
||||
nrf_dfu_peer_data_t * p_peer_data =
|
||||
(nrf_dfu_peer_data_t*) &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET];
|
||||
|
||||
// Calculate the CRC for the structure excluding the CRC value itself.
|
||||
uint32_t crc = crc32_compute((uint8_t*)p_peer_data + 4, sizeof(nrf_dfu_peer_data_t) - 4, NULL);
|
||||
|
||||
return (p_peer_data->crc == crc);
|
||||
}
|
||||
|
||||
#else // not NRF_DFU_BLE_REQUIRES_BONDS
|
||||
|
||||
ret_code_t nrf_dfu_settings_adv_name_write(nrf_dfu_adv_name_t * p_adv_name)
|
||||
{
|
||||
uint32_t ret_val;
|
||||
|
||||
uint32_t * p_adv_name_settings =
|
||||
(uint32_t*) &m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET];
|
||||
|
||||
uint32_t crc = (uint32_t)*p_adv_name_settings;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_adv_name);
|
||||
|
||||
if (crc != 0xFFFFFFFF)
|
||||
{
|
||||
// Already written to, must be cleared out.
|
||||
// Reset required
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// Calculate the CRC for the structure excluding the CRC value itself.
|
||||
p_adv_name->crc = crc32_compute((uint8_t *)p_adv_name + 4, sizeof(nrf_dfu_adv_name_t) - 4, NULL);
|
||||
|
||||
// Using SoftDevice call since this function cannot use static memory.
|
||||
ret_val = sd_flash_write(p_adv_name_settings,
|
||||
(uint32_t*) p_adv_name,
|
||||
sizeof(nrf_dfu_adv_name_t)/4);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_dfu_settings_adv_name_copy(nrf_dfu_adv_name_t * p_adv_name)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_adv_name);
|
||||
memcpy(p_adv_name, &m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET], sizeof(nrf_dfu_adv_name_t));
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool nrf_dfu_settings_adv_name_is_valid(void)
|
||||
{
|
||||
nrf_dfu_adv_name_t * p_adv_name =
|
||||
(nrf_dfu_adv_name_t*)&m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET];
|
||||
|
||||
// Calculate the CRC for the structure excluding the CRC value itself.
|
||||
uint32_t crc = crc32_compute((uint8_t*)p_adv_name + 4, sizeof(nrf_dfu_adv_name_t) - 4, NULL);
|
||||
|
||||
return (p_adv_name->crc == crc);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//lint -save -e(14)
|
||||
ret_code_t nrf_dfu_settings_additional_erase(void)
|
||||
{
|
||||
ret_code_t ret_code = NRF_SUCCESS;
|
||||
|
||||
// Check CRC for both types.
|
||||
if ( (s_dfu_settings.peer_data.crc != 0xFFFFFFFF)
|
||||
|| (s_dfu_settings.adv_name.crc != 0xFFFFFFFF))
|
||||
{
|
||||
NRF_LOG_DEBUG("Erasing settings page additional data.");
|
||||
|
||||
// Erasing and resetting the settings page without the peer data/adv data
|
||||
nrf_nvmc_page_erase(BOOTLOADER_SETTINGS_ADDRESS);
|
||||
nrf_nvmc_write_words(BOOTLOADER_SETTINGS_ADDRESS, (uint32_t const *)&s_dfu_settings, DFU_SETTINGS_PEER_DATA_OFFSET / 4);
|
||||
}
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
//lint -restore
|
||||
|
||||
87
components/libraries/bootloader/dfu/nrf_dfu_svci.c
Normal file
87
components/libraries/bootloader/dfu/nrf_dfu_svci.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_sdm.h"
|
||||
#include "app_util.h"
|
||||
|
||||
#define APP_START_ADDR CODE_START
|
||||
|
||||
|
||||
uint32_t nrf_dfu_svci_vector_table_set(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
uint32_t bootloader_addr = BOOTLOADER_ADDRESS;
|
||||
|
||||
if (bootloader_addr != 0xFFFFFFFF)
|
||||
{
|
||||
NRF_LOG_INFO("Setting vector table to bootloader: 0x%08x", bootloader_addr);
|
||||
err_code = sd_softdevice_vector_table_base_set(bootloader_addr);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed running sd_softdevice_vector_table_base_set");
|
||||
return err_code;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
NRF_LOG_ERROR("No bootloader was found");
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_svci_vector_table_unset(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
NRF_LOG_INFO("Setting vector table to main app: 0x%08x", APP_START_ADDR);
|
||||
err_code = sd_softdevice_vector_table_base_set(APP_START_ADDR);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed running sd_softdevice_vector_table_base_set");
|
||||
return err_code;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
212
components/libraries/bootloader/dfu/nrf_dfu_svci_handler.c
Normal file
212
components/libraries/bootloader/dfu/nrf_dfu_svci_handler.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "nrf_svci_async_handler.h"
|
||||
#include "app_error.h"
|
||||
#include "nrf_nvmc.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_dfu_ble_svci_bond_sharing.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "sdk_config.h"
|
||||
|
||||
|
||||
#if (NRF_DFU_TRANSPORT_BLE && NRF_DFU_BLE_REQUIRES_BONDS)
|
||||
|
||||
|
||||
NRF_SVCI_ASYNC_HANDLER_CREATE(NRF_DFU_SVCI_SET_PEER_DATA,
|
||||
nrf_dfu_set_peer_data, nrf_dfu_peer_data_t, nrf_dfu_peer_data_state_t);
|
||||
|
||||
|
||||
static uint32_t nrf_dfu_set_peer_data_handler(nrf_dfu_set_peer_data_svci_async_t * p_async)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_async);
|
||||
|
||||
p_async->async_func = nrf_dfu_set_peer_data_on_call;
|
||||
p_async->sys_evt_handler = nrf_dfu_set_peer_data_on_sys_evt;
|
||||
p_async->state = DFU_PEER_DATA_STATE_INITIALIZED;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t nrf_dfu_set_peer_data_on_call(nrf_dfu_peer_data_t * p_data,
|
||||
nrf_dfu_peer_data_state_t * p_state)
|
||||
{
|
||||
uint32_t ret_val = NRF_ERROR_BUSY;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_state);
|
||||
|
||||
switch (*p_state)
|
||||
{
|
||||
case DFU_PEER_DATA_STATE_INVALID:
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
|
||||
case DFU_PEER_DATA_STATE_INITIALIZED:
|
||||
ret_val = nrf_dfu_settings_peer_data_write(p_data);
|
||||
if (ret_val == NRF_SUCCESS)
|
||||
{
|
||||
*p_state = DFU_PEER_DATA_STATE_WRITE_REQUESTED;
|
||||
}
|
||||
break;
|
||||
|
||||
case DFU_PEER_DATA_STATE_WRITE_REQUESTED:
|
||||
return NRF_ERROR_BUSY;
|
||||
|
||||
case DFU_PEER_DATA_STATE_WRITE_FINISHED:
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
|
||||
case DFU_PEER_DATA_STATE_WRITE_FAILED:
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t nrf_dfu_set_peer_data_on_sys_evt(uint32_t sys_event, nrf_dfu_peer_data_state_t * p_state)
|
||||
{
|
||||
uint32_t ret_val = NRF_ERROR_INVALID_STATE;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_state);
|
||||
|
||||
if (*p_state == DFU_PEER_DATA_STATE_WRITE_REQUESTED)
|
||||
{
|
||||
switch (sys_event)
|
||||
{
|
||||
case NRF_EVT_FLASH_OPERATION_ERROR:
|
||||
return NRF_ERROR_BUSY;
|
||||
|
||||
case NRF_EVT_FLASH_OPERATION_SUCCESS:
|
||||
ret_val = NRF_SUCCESS;
|
||||
(*p_state) = DFU_PEER_DATA_STATE_WRITE_FINISHED;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Event not intended for us
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#elif (NRF_DFU_TRANSPORT_BLE && !NRF_DFU_BLE_REQUIRES_BONDS)
|
||||
|
||||
|
||||
NRF_SVCI_ASYNC_HANDLER_CREATE(NRF_DFU_SVCI_SET_ADV_NAME,
|
||||
nrf_dfu_set_adv_name, nrf_dfu_adv_name_t, nrf_dfu_set_adv_name_state_t);
|
||||
|
||||
|
||||
static uint32_t nrf_dfu_set_adv_name_handler(nrf_dfu_set_adv_name_svci_async_t * p_async)
|
||||
{
|
||||
VERIFY_PARAM_NOT_NULL(p_async);
|
||||
|
||||
p_async->async_func = nrf_dfu_set_adv_name_on_call;
|
||||
p_async->sys_evt_handler = nrf_dfu_set_adv_name_on_sys_evt;
|
||||
p_async->state = DFU_ADV_NAME_STATE_INITIALIZED;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t nrf_dfu_set_adv_name_on_call(nrf_dfu_adv_name_t * p_adv_name,
|
||||
nrf_dfu_set_adv_name_state_t * p_state)
|
||||
{
|
||||
uint32_t ret_val = NRF_ERROR_BUSY;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_state);
|
||||
|
||||
switch (*p_state)
|
||||
{
|
||||
case DFU_ADV_NAME_STATE_INVALID:
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
|
||||
case DFU_ADV_NAME_STATE_INITIALIZED:
|
||||
ret_val = nrf_dfu_settings_adv_name_write(p_adv_name);
|
||||
if (ret_val == NRF_SUCCESS)
|
||||
{
|
||||
*p_state = DFU_ADV_NAME_STATE_WRITE_REQUESTED;
|
||||
}
|
||||
break;
|
||||
|
||||
case DFU_ADV_NAME_STATE_WRITE_REQUESTED:
|
||||
return NRF_ERROR_BUSY;
|
||||
|
||||
case DFU_ADV_NAME_STATE_WRITE_FINISHED:
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
|
||||
case DFU_ADV_NAME_STATE_WRITE_FAILED:
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t nrf_dfu_set_adv_name_on_sys_evt(uint32_t sys_event, nrf_dfu_set_adv_name_state_t * p_state)
|
||||
{
|
||||
uint32_t ret_val = NRF_ERROR_INVALID_STATE;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_state);
|
||||
|
||||
if (*p_state == DFU_ADV_NAME_STATE_WRITE_REQUESTED)
|
||||
{
|
||||
switch (sys_event)
|
||||
{
|
||||
case NRF_EVT_FLASH_OPERATION_ERROR:
|
||||
return NRF_ERROR_BUSY;
|
||||
|
||||
case NRF_EVT_FLASH_OPERATION_SUCCESS:
|
||||
ret_val = NRF_SUCCESS;
|
||||
(*p_state) = DFU_ADV_NAME_STATE_WRITE_FINISHED;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Event not intended for us
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#endif // NRF_DFU_TRANSPORT_BLE && !NRF_DFU_BLE_REQUIRES_BONDS
|
||||
91
components/libraries/bootloader/dfu/nrf_dfu_transport.c
Normal file
91
components/libraries/bootloader/dfu/nrf_dfu_transport.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_dfu_transport.h"
|
||||
#include "nrf_log.h"
|
||||
|
||||
|
||||
#define DFU_TRANS_SECTION_ITEM_GET(i) NRF_SECTION_ITEM_GET(dfu_trans, nrf_dfu_transport_t, (i))
|
||||
#define DFU_TRANS_SECTION_ITEM_COUNT NRF_SECTION_ITEM_COUNT(dfu_trans, nrf_dfu_transport_t)
|
||||
|
||||
NRF_SECTION_DEF(dfu_trans, const nrf_dfu_transport_t);
|
||||
|
||||
|
||||
uint32_t nrf_dfu_transports_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
uint32_t const num_transports = DFU_TRANS_SECTION_ITEM_COUNT;
|
||||
uint32_t ret_val = NRF_SUCCESS;
|
||||
|
||||
NRF_LOG_DEBUG("Initializing transports (found: %d)", num_transports);
|
||||
|
||||
for (uint32_t i = 0; i < num_transports; i++)
|
||||
{
|
||||
nrf_dfu_transport_t * const trans = DFU_TRANS_SECTION_ITEM_GET(i);
|
||||
ret_val = trans->init_func(observer);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_DEBUG("Failed to initialize transport %d, error %d", i, ret_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_transports_close(nrf_dfu_transport_t const * p_exception)
|
||||
{
|
||||
uint32_t const num_transports = DFU_TRANS_SECTION_ITEM_COUNT;
|
||||
uint32_t ret_val = NRF_SUCCESS;
|
||||
|
||||
NRF_LOG_DEBUG("Shutting down transports (found: %d)", num_transports);
|
||||
|
||||
for (uint32_t i = 0; i < num_transports; i++)
|
||||
{
|
||||
nrf_dfu_transport_t * const trans = DFU_TRANS_SECTION_ITEM_GET(i);
|
||||
ret_val = trans->close_func(p_exception);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_DEBUG("Failed to shutdown transport %d, error %d", i, ret_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
134
components/libraries/bootloader/dfu/nrf_dfu_transport.h
Normal file
134
components/libraries/bootloader/dfu/nrf_dfu_transport.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup sdk_nrf_dfu_transport DFU transport
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
* @brief Generic Device Firmware Update (DFU) transport interface.
|
||||
*
|
||||
* @details The DFU transport module defines a generic interface that must
|
||||
* be implemented for each transport layer.
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_TRANSPORT_H__
|
||||
#define NRF_DFU_TRANSPORT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_section.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Forward declaration of nrf_dfu_transport_t */
|
||||
typedef struct nrf_dfu_transport_s nrf_dfu_transport_t;
|
||||
|
||||
/** @brief Function type for initializing a DFU transport.
|
||||
*
|
||||
* @details This function initializes a DFU transport. The implementation
|
||||
* of the function must initialize DFU mode and stay in service
|
||||
* until either the device is reset or the DFU operation is finalized.
|
||||
* When the DFU transport receives requests, it should call @ref nrf_dfu_req_handler_on_req for handling the requests.
|
||||
*
|
||||
* @param observer Callback function for receiving DFU transport notifications.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful for the transport. Any other return code indicates that the DFU transport could not be initialized.
|
||||
*/
|
||||
typedef uint32_t (*nrf_dfu_init_fn_t)(nrf_dfu_observer_t observer);
|
||||
|
||||
|
||||
/** @brief Function type for closing down a DFU transport.
|
||||
*
|
||||
* @details This function closes down a DFU transport in a gentle way.
|
||||
*
|
||||
* @param[in] p_exception If exception matches current transport closing should be omitted.
|
||||
*
|
||||
* @retval NRF_SUCCESS If closing was successful for the transport. Any other return code indicates that the DFU transport could not be closed closed down.
|
||||
*/
|
||||
typedef uint32_t (*nrf_dfu_close_fn_t)(nrf_dfu_transport_t const * p_exception);
|
||||
|
||||
|
||||
|
||||
/** @brief DFU transport registration.
|
||||
*
|
||||
* @details Every DFU transport must provide a registration of the initialization function.
|
||||
*/
|
||||
struct nrf_dfu_transport_s
|
||||
{
|
||||
nrf_dfu_init_fn_t init_func; /**< Registration of the init function to run to initialize a DFU transport. */
|
||||
nrf_dfu_close_fn_t close_func; /**< Registration of the close function to close down a DFU transport. */
|
||||
};
|
||||
|
||||
|
||||
/** @brief Function for initializing all the registered DFU transports.
|
||||
*
|
||||
* @retval NRF_SUCCESS If all DFU transport were initialized successfully.
|
||||
* Any other error code indicates that at least one DFU
|
||||
* transport could not be initialized.
|
||||
*/
|
||||
uint32_t nrf_dfu_transports_init(nrf_dfu_observer_t observer);
|
||||
|
||||
/** @brief Function for closing down all (with optional exception) the registered DFU transports.
|
||||
*
|
||||
* @param[in] p_exception Transport which should not be closed. NULL if all transports should be closed.
|
||||
* @retval NRF_SUCCESS If all DFU transport were closed down successfully.
|
||||
* Any other error code indicates that at least one DFU
|
||||
* transport could not be closed down.
|
||||
*/
|
||||
uint32_t nrf_dfu_transports_close(nrf_dfu_transport_t const * p_exception);
|
||||
|
||||
|
||||
/** @brief Macro for registering a DFU transport by using section variables.
|
||||
*
|
||||
* @details This macro places a variable in a section named "dfu_trans", which
|
||||
* is initialized by @ref nrf_dfu_transports_init.
|
||||
*/
|
||||
#define DFU_TRANSPORT_REGISTER(trans_var) NRF_SECTION_ITEM_REGISTER(dfu_trans, trans_var)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_TRANSPORT_H__
|
||||
|
||||
/** @} */
|
||||
244
components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.c
Normal file
244
components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_dfu_trigger_usb.h"
|
||||
#include "app_usbd.h"
|
||||
#include "app_usbd_nrf_dfu_trigger.h"
|
||||
#include "nrf_drv_clock.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "boards.h"
|
||||
#include "app_util.h"
|
||||
#include "app_usbd_serial_num.h"
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_trigger_usb
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#ifndef BSP_SELF_PINRESET_PIN
|
||||
#error "This module is intended to be used with boards that have the GP pin shortened with the RESET pin."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable power USB detection.
|
||||
*
|
||||
* Configure if the example supports USB port connection.
|
||||
*/
|
||||
#ifndef USBD_POWER_DETECTION
|
||||
#define USBD_POWER_DETECTION true
|
||||
#endif
|
||||
|
||||
#define DFU_FLASH_PAGE_SIZE (NRF_FICR->CODEPAGESIZE)
|
||||
#define DFU_FLASH_PAGE_COUNT (NRF_FICR->CODESIZE)
|
||||
|
||||
// Semantic versioning string.
|
||||
#define VERSION_STRING STRINGIFY(APP_VERSION_MAJOR) "." STRINGIFY(APP_VERSION_MINOR) "." STRINGIFY(APP_VERSION_PATCH) APP_VERSION_PRERELEASE APP_VERSION_METADATA
|
||||
|
||||
static uint8_t m_version_string[] = APP_NAME " " VERSION_STRING; ///< Human-readable version string.
|
||||
static app_usbd_nrf_dfu_trigger_nordic_info_t m_dfu_info; ///< Struct with various information about the current firmware.
|
||||
|
||||
static void dfu_trigger_evt_handler(app_usbd_class_inst_t const * p_inst,
|
||||
app_usbd_nrf_dfu_trigger_user_event_t event)
|
||||
{
|
||||
UNUSED_PARAMETER(p_inst);
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case APP_USBD_NRF_DFU_TRIGGER_USER_EVT_DETACH:
|
||||
NRF_LOG_INFO("DFU Detach request received. Triggering a pin reset.");
|
||||
NRF_LOG_FINAL_FLUSH();
|
||||
nrf_gpio_cfg_output(BSP_SELF_PINRESET_PIN);
|
||||
nrf_gpio_pin_clear(BSP_SELF_PINRESET_PIN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
APP_USBD_NRF_DFU_TRIGGER_GLOBAL_DEF(m_app_dfu,
|
||||
NRF_DFU_TRIGGER_USB_INTERFACE_NUM,
|
||||
&m_dfu_info,
|
||||
m_version_string,
|
||||
dfu_trigger_evt_handler);
|
||||
|
||||
|
||||
static void usbd_user_evt_handler(app_usbd_event_type_t event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case APP_USBD_EVT_DRV_SUSPEND:
|
||||
break;
|
||||
case APP_USBD_EVT_DRV_RESUME:
|
||||
break;
|
||||
case APP_USBD_EVT_STARTED:
|
||||
break;
|
||||
case APP_USBD_EVT_STOPPED:
|
||||
app_usbd_disable();
|
||||
break;
|
||||
case APP_USBD_EVT_POWER_DETECTED:
|
||||
NRF_LOG_INFO("USB power detected");
|
||||
|
||||
if (!nrf_drv_usbd_is_enabled())
|
||||
{
|
||||
app_usbd_enable();
|
||||
}
|
||||
break;
|
||||
case APP_USBD_EVT_POWER_REMOVED:
|
||||
NRF_LOG_INFO("USB power removed");
|
||||
app_usbd_stop();
|
||||
break;
|
||||
case APP_USBD_EVT_POWER_READY:
|
||||
NRF_LOG_INFO("USB ready");
|
||||
app_usbd_start();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void strings_create(void)
|
||||
{
|
||||
uint8_t prev_char = 'a'; // Arbitrary valid char, not '-'.
|
||||
|
||||
// Remove characters that are not supported in semantic version strings.
|
||||
for (size_t i = strlen(APP_NAME) + 1; i < strlen((char*)m_version_string); i++)
|
||||
{
|
||||
if (((m_version_string[i] >= 'a') && (m_version_string[i] <= 'z'))
|
||||
|| ((m_version_string[i] >= 'A') && (m_version_string[i] <= 'Z'))
|
||||
|| ((m_version_string[i] >= '0') && (m_version_string[i] <= '9'))
|
||||
|| (m_version_string[i] == '+')
|
||||
|| (m_version_string[i] == '.')
|
||||
|| (m_version_string[i] == '-'))
|
||||
{
|
||||
// Valid semantic version character.
|
||||
}
|
||||
else if (prev_char == '-')
|
||||
{
|
||||
m_version_string[i] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
m_version_string[i] = '-';
|
||||
}
|
||||
|
||||
prev_char = m_version_string[i];
|
||||
}
|
||||
|
||||
#if !NRF_DFU_TRIGGER_USB_USB_SHARED
|
||||
app_usbd_serial_num_generate();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !(APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)
|
||||
static void usbd_evt_handler(app_usbd_internal_evt_t const * const p_event)
|
||||
{
|
||||
app_usbd_event_execute(p_event);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret_code_t nrf_dfu_trigger_usb_init(void)
|
||||
{
|
||||
ret_code_t ret;
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
m_dfu_info.wAddress = CODE_START;
|
||||
m_dfu_info.wFirmwareSize = CODE_SIZE;
|
||||
m_dfu_info.wVersionMajor = APP_VERSION_MAJOR;
|
||||
m_dfu_info.wVersionMinor = APP_VERSION_MINOR;
|
||||
m_dfu_info.wFirmwareID = APP_ID;
|
||||
m_dfu_info.wFlashPageSize = DFU_FLASH_PAGE_SIZE;
|
||||
m_dfu_info.wFlashSize = m_dfu_info.wFlashPageSize * DFU_FLASH_PAGE_COUNT;
|
||||
|
||||
strings_create();
|
||||
|
||||
if (!NRF_DFU_TRIGGER_USB_USB_SHARED)
|
||||
{
|
||||
static const app_usbd_config_t usbd_config = {
|
||||
|
||||
#if !(APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)
|
||||
.ev_handler = usbd_evt_handler,
|
||||
#endif
|
||||
.ev_state_proc = usbd_user_evt_handler
|
||||
};
|
||||
|
||||
ret = nrf_drv_clock_init();
|
||||
if ((ret != NRF_SUCCESS) && (ret != NRF_ERROR_MODULE_ALREADY_INITIALIZED))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = app_usbd_init(&usbd_config);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
app_usbd_class_inst_t const * class_dfu = app_usbd_nrf_dfu_trigger_class_inst_get(&m_app_dfu);
|
||||
ret = app_usbd_class_append(class_dfu);
|
||||
|
||||
if (!NRF_DFU_TRIGGER_USB_USB_SHARED)
|
||||
{
|
||||
if (USBD_POWER_DETECTION)
|
||||
{
|
||||
ret = app_usbd_power_events_enable();
|
||||
APP_ERROR_CHECK(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");
|
||||
|
||||
app_usbd_enable();
|
||||
app_usbd_start();
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == NRF_SUCCESS)
|
||||
{
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
74
components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.h
Normal file
74
components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_DFU_TRIGGER_USB_H
|
||||
#define NRF_DFU_TRIGGER_USB_H
|
||||
|
||||
#include "sdk_errors.h"
|
||||
|
||||
/**
|
||||
* @defgroup nrf_dfu_trigger_usb USB DFU trigger library
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief @tagAPI52840 USB DFU trigger library is used to enter the bootloader and read the firmware version.
|
||||
*
|
||||
* @details See @ref lib_dfu_trigger_usb for additional documentation.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Function for initializing the USB DFU trigger library.
|
||||
*
|
||||
* @note If the USB is also used for other purposes, then this function must be called after USB is
|
||||
* initialized but before it is enabled. In this case, the configuration flag @ref
|
||||
* NRF_DFU_TRIGGER_USB_USB_SHARED must be set to 1.
|
||||
*
|
||||
* @note Calling this again after the first success has no effect and returns @ref NRF_SUCCESS.
|
||||
*
|
||||
* @note If @ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE is on (1), USB events must be handled manually.
|
||||
* See @ref app_usbd_event_queue_process.
|
||||
*
|
||||
* @retval NRF_SUCCESS On successful initialization.
|
||||
* @return An error code on failure, for example if called at a wrong time.
|
||||
*/
|
||||
ret_code_t nrf_dfu_trigger_usb_init(void);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif //NRF_DFU_TRIGGER_USB_H
|
||||
342
components/libraries/bootloader/dfu/nrf_dfu_types.h
Normal file
342
components/libraries/bootloader/dfu/nrf_dfu_types.h
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup sdk_nrf_dfu_types DFU types
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_TYPES_H__
|
||||
#define NRF_DFU_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "sdk_common.h"
|
||||
#include "nrf.h"
|
||||
#include "nrf_mbr.h"
|
||||
#include "app_util_platform.h"
|
||||
#include "sdk_config.h"
|
||||
|
||||
#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE
|
||||
#include "ble_gap.h"
|
||||
#define SYSTEM_SERVICE_ATT_SIZE 8 /**< Size of the system service attribute length including CRC-16 at the end. */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define INIT_COMMAND_MAX_SIZE 512 /**< Maximum size of the init command stored in dfu_settings. */
|
||||
#define INIT_COMMAND_MAX_SIZE_v1 256 /**< Maximum size of the init command in settings version 1. */
|
||||
|
||||
/** @brief Size of a flash page. This value is used for calculating the size of the reserved
|
||||
* flash space in the bootloader region.
|
||||
*/
|
||||
#if defined(NRF51)
|
||||
#define CODE_PAGE_SIZE (PAGE_SIZE_IN_WORDS * sizeof(uint32_t))
|
||||
#elif defined(NRF52_SERIES)
|
||||
#define CODE_PAGE_SIZE (MBR_PAGE_SIZE_IN_WORDS * sizeof(uint32_t))
|
||||
#else
|
||||
#error "Architecture not set."
|
||||
#endif
|
||||
|
||||
/** @brief Maximum size of a data object.*/
|
||||
#if defined(NRF51)
|
||||
#define DATA_OBJECT_MAX_SIZE (CODE_PAGE_SIZE * 4)
|
||||
#elif defined(NRF52_SERIES) || defined (__SDK_DOXYGEN__)
|
||||
#define DATA_OBJECT_MAX_SIZE (CODE_PAGE_SIZE)
|
||||
#else
|
||||
#error "Architecture not set."
|
||||
#endif
|
||||
|
||||
/** @brief Page location of the bootloader settings address.
|
||||
*/
|
||||
#if defined (NRF51)
|
||||
#define BOOTLOADER_SETTINGS_ADDRESS (0x0003FC00UL)
|
||||
#elif defined( NRF52810_XXAA )
|
||||
#define BOOTLOADER_SETTINGS_ADDRESS (0x0002F000UL)
|
||||
#elif defined( NRF52811_XXAA )
|
||||
#define BOOTLOADER_SETTINGS_ADDRESS (0x0002F000UL)
|
||||
#elif defined( NRF52820_XXAA )
|
||||
#define BOOTLOADER_SETTINGS_ADDRESS (0x0003F000UL)
|
||||
#elif defined( NRF52832_XXAA )
|
||||
#define BOOTLOADER_SETTINGS_ADDRESS (0x0007F000UL)
|
||||
#elif defined( NRF52833_XXAA )
|
||||
#define BOOTLOADER_SETTINGS_ADDRESS (0x0007F000UL)
|
||||
#elif defined(NRF52840_XXAA)
|
||||
#define BOOTLOADER_SETTINGS_ADDRESS (0x000FF000UL)
|
||||
#else
|
||||
#error No valid target set for BOOTLOADER_SETTINGS_ADDRESS.
|
||||
#endif
|
||||
|
||||
#define BOOTLOADER_SETTINGS_PAGE_SIZE (CODE_PAGE_SIZE)
|
||||
#define NRF_MBR_PARAMS_PAGE_SIZE (CODE_PAGE_SIZE)
|
||||
|
||||
/** @brief Page location of the MBR parameters page address.
|
||||
*/
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52840_XXAA_ENGA)
|
||||
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x000FE000UL)
|
||||
#elif defined(NRF52832_XXAA)
|
||||
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0007E000UL)
|
||||
#elif defined(NRF52833_XXAA)
|
||||
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0007E000UL)
|
||||
#elif defined(NRF52810_XXAA)
|
||||
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0002E000UL)
|
||||
#elif defined(NRF52811_XXAA)
|
||||
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0002E000UL)
|
||||
#elif defined(NRF52820_XXAA)
|
||||
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0003E000UL)
|
||||
#endif
|
||||
|
||||
#define BOOTLOADER_SETTINGS_BACKUP_ADDRESS NRF_MBR_PARAMS_PAGE_ADDRESS
|
||||
|
||||
|
||||
#ifndef NRF_DFU_APP_DATA_AREA_SIZE
|
||||
#define NRF_DFU_APP_DATA_AREA_SIZE (CODE_PAGE_SIZE * 3)
|
||||
#endif
|
||||
|
||||
STATIC_ASSERT((NRF_DFU_APP_DATA_AREA_SIZE % CODE_PAGE_SIZE) == 0, "NRF_DFU_APP_DATA_AREA_SIZE must be a multiple of the flash page size.");
|
||||
|
||||
#define DFU_APP_DATA_RESERVED NRF_DFU_APP_DATA_AREA_SIZE // For backward compatibility with 15.0.0.
|
||||
|
||||
/** @brief Total size of the region between the SoftDevice and the bootloader.
|
||||
*/
|
||||
#define DFU_REGION_END(bootloader_start_addr) ((bootloader_start_addr) - (NRF_DFU_APP_DATA_AREA_SIZE))
|
||||
|
||||
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
|
||||
#define DFU_REGION_START (nrf_dfu_bank0_start_addr())
|
||||
#else
|
||||
#define DFU_REGION_START (MBR_SIZE)
|
||||
#endif
|
||||
|
||||
#define DFU_REGION_TOTAL_SIZE ((DFU_REGION_END) - (DFU_REGION_START))
|
||||
|
||||
#define NRF_DFU_CURRENT_BANK_0 0x00
|
||||
#define NRF_DFU_CURRENT_BANK_1 0x01
|
||||
|
||||
#define NRF_DFU_BANK_LAYOUT_DUAL 0x00
|
||||
#define NRF_DFU_BANK_LAYOUT_SINGLE 0x01
|
||||
|
||||
/** @brief DFU bank state codes.
|
||||
*
|
||||
* @details The DFU bank state indicates the content of a bank:
|
||||
* A valid image of a certain type or an invalid image.
|
||||
*/
|
||||
|
||||
#define NRF_DFU_BANK_INVALID 0x00 /**< Invalid image. */
|
||||
#define NRF_DFU_BANK_VALID_APP 0x01 /**< Valid application. */
|
||||
#define NRF_DFU_BANK_VALID_SD 0xA5 /**< Valid SoftDevice. */
|
||||
#define NRF_DFU_BANK_VALID_BL 0xAA /**< Valid bootloader. */
|
||||
#define NRF_DFU_BANK_VALID_SD_BL 0xAC /**< Valid SoftDevice and bootloader. */
|
||||
#define NRF_DFU_BANK_VALID_EXT_APP 0xB1 /**< Valid application designated for a remote node. */
|
||||
|
||||
/** @brief Description of a single bank. */
|
||||
#pragma pack(4)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t image_size; /**< Size of the image in the bank. */
|
||||
uint32_t image_crc; /**< CRC of the image. If set to 0, the CRC is ignored. */
|
||||
uint32_t bank_code; /**< Identifier code for the bank. */
|
||||
} nrf_dfu_bank_t;
|
||||
|
||||
/**@brief DFU progress.
|
||||
*
|
||||
* Be aware of the difference between objects and firmware images. A firmware image consists of multiple objects, each of a maximum size @ref DATA_OBJECT_MAX_SIZE.
|
||||
*
|
||||
* @note The union inside this struct is cleared when CREATE_OBJECT of command type is executed, and when there is a valid post-validation.
|
||||
* In DFU activation (after reset) the @ref dfu_progress_t::update_start_address will be used in case of a SD/SD+BL update.
|
||||
*/
|
||||
ANON_UNIONS_ENABLE;
|
||||
typedef struct
|
||||
{
|
||||
uint32_t command_size; /**< The size of the current init command stored in the DFU settings. */
|
||||
uint32_t command_offset; /**< The offset of the currently received init command data. The offset will increase as the init command is received. */
|
||||
uint32_t command_crc; /**< The calculated CRC of the init command (calculated after the transfer is completed). */
|
||||
uint32_t data_object_size; /**< The size of the last object created. Note that this size is not the size of the whole firmware image.*/
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t firmware_image_crc; /**< CRC value of the current firmware (continuously calculated as data is received). */
|
||||
uint32_t firmware_image_crc_last; /**< The CRC of the last executed object. */
|
||||
uint32_t firmware_image_offset; /**< The offset of the current firmware image being transferred. Note that this offset is the offset in the entire firmware image and not only the current object. */
|
||||
uint32_t firmware_image_offset_last;/**< The offset of the last executed object from the start of the firmware image. */
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint32_t update_start_address; /**< Value indicating the start address of the new firmware (before copy). It's always used, but it's most important for an SD/SD+BL update where the SD changes size or if the DFU process had a power loss when updating a SD with changed size. */
|
||||
};
|
||||
};
|
||||
} dfu_progress_t;
|
||||
ANON_UNIONS_DISABLE;
|
||||
|
||||
/** @brief Event types in the bootloader and DFU process. */
|
||||
typedef enum
|
||||
{
|
||||
NRF_DFU_EVT_DFU_INITIALIZED, /**< Starting DFU. */
|
||||
NRF_DFU_EVT_TRANSPORT_ACTIVATED, /**< Transport activated (e.g. BLE connected, USB plugged in). */
|
||||
NRF_DFU_EVT_TRANSPORT_DEACTIVATED, /**< Transport deactivated (e.g. BLE disconnected, USB plugged out). */
|
||||
NRF_DFU_EVT_DFU_STARTED, /**< DFU process started. */
|
||||
NRF_DFU_EVT_OBJECT_RECEIVED, /**< A DFU data object has been received. */
|
||||
NRF_DFU_EVT_DFU_FAILED, /**< DFU process has failed, been interrupted, or hung. */
|
||||
NRF_DFU_EVT_DFU_COMPLETED, /**< DFU process completed. */
|
||||
NRF_DFU_EVT_DFU_ABORTED, /**< DFU process aborted. */
|
||||
} nrf_dfu_evt_type_t;
|
||||
|
||||
/**
|
||||
* @brief Function for notifying DFU state.
|
||||
*/
|
||||
typedef void (*nrf_dfu_observer_t)(nrf_dfu_evt_type_t notification);
|
||||
|
||||
#define NRF_DFU_PEER_DATA_LEN 64 /**< The length in bytes of nrf_dfu_peer_data_t expected by tools manipulating the settings page. Do not change without changing the settings page version. */
|
||||
#define NRF_DFU_ADV_NAME_LEN 28 /**< The length in bytes of nrf_dfu_adv_name_t expected by tools manipulating the settings page. Do not change without changing the settings page version. */
|
||||
|
||||
#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t crc; /**< CRC of the rest of the parameters in this struct. */
|
||||
ble_gap_id_key_t ble_id; /**< BLE GAP identity key of the device that initiated the DFU process. */
|
||||
ble_gap_enc_key_t enc_key; /**< Encryption key structure containing encrypted diversifier and LTK for reestablishing the bond. */
|
||||
uint8_t sys_serv_attr[SYSTEM_SERVICE_ATT_SIZE]; /**< System service attributes for restoring of Service Changed Indication setting in DFU mode. */
|
||||
} nrf_dfu_peer_data_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DFU_PEER_DATA_STATE_INVALID = 0,
|
||||
DFU_PEER_DATA_STATE_INITIALIZED = 1,
|
||||
DFU_PEER_DATA_STATE_WRITE_REQUESTED = 2,
|
||||
DFU_PEER_DATA_STATE_WRITE_FINISHED = 3,
|
||||
DFU_PEER_DATA_STATE_WRITE_FAILED = 4,
|
||||
} nrf_dfu_peer_data_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t crc; /**< CRC of the rest of the parameters in this struct. Calculated by the bootloader. */
|
||||
uint8_t name[20]; /**< New advertisement name to set. */
|
||||
uint32_t len; /**< Length of the advertisement name. */
|
||||
} nrf_dfu_adv_name_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DFU_ADV_NAME_STATE_INVALID = 0,
|
||||
DFU_ADV_NAME_STATE_INITIALIZED = 1,
|
||||
DFU_ADV_NAME_STATE_WRITE_REQUESTED = 2,
|
||||
DFU_ADV_NAME_STATE_WRITE_FINISHED = 3,
|
||||
DFU_ADV_NAME_STATE_WRITE_FAILED = 4,
|
||||
} nrf_dfu_set_adv_name_state_t;
|
||||
|
||||
#else
|
||||
typedef struct
|
||||
{
|
||||
uint8_t dummy_data[NRF_DFU_PEER_DATA_LEN];
|
||||
} nrf_dfu_peer_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t dummy_data[NRF_DFU_ADV_NAME_LEN];
|
||||
} nrf_dfu_adv_name_t;
|
||||
#endif // NRF_DFU_TRANSPORT_BLE
|
||||
|
||||
STATIC_ASSERT(sizeof(nrf_dfu_peer_data_t) == NRF_DFU_PEER_DATA_LEN, "nrf_dfu_peer_data_t has unexpected length. This can cause incompatibility with tools.");
|
||||
STATIC_ASSERT(sizeof(nrf_dfu_adv_name_t) == NRF_DFU_ADV_NAME_LEN, "nrf_dfu_adv_name_t has unexpected length. This can cause incompatibility with tools.");
|
||||
|
||||
#define SETTINGS_RESERVED_AREA_SIZE 16 /**< The number of words in the reserved area of the DFU settings. */
|
||||
#define SETTINGS_BOOT_VALIDATION_SIZE 64 /**< The number of bytes reserved for boot_validation value. */
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NO_VALIDATION,
|
||||
VALIDATE_CRC,
|
||||
VALIDATE_SHA256,
|
||||
VALIDATE_ECDSA_P256_SHA256,
|
||||
} boot_validation_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
boot_validation_type_t type;
|
||||
uint8_t bytes[SETTINGS_BOOT_VALIDATION_SIZE];
|
||||
} boot_validation_t;
|
||||
|
||||
/**@brief DFU settings for application and bank data.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t crc; /**< CRC for the stored DFU settings, not including the CRC itself. If 0xFFFFFFF, the CRC has never been calculated. */
|
||||
uint32_t settings_version; /**< Version of the current DFU settings struct layout. */
|
||||
uint32_t app_version; /**< Version of the last stored application. */
|
||||
uint32_t bootloader_version; /**< Version of the last stored bootloader. */
|
||||
|
||||
uint32_t bank_layout; /**< Bank layout: single bank or dual bank. This value can change. */
|
||||
uint32_t bank_current; /**< The bank that is currently used. */
|
||||
|
||||
nrf_dfu_bank_t bank_0; /**< Bank 0. */
|
||||
nrf_dfu_bank_t bank_1; /**< Bank 1. */
|
||||
|
||||
uint32_t write_offset; /**< Write offset for the current operation. */
|
||||
uint32_t sd_size; /**< Size of the SoftDevice. */
|
||||
|
||||
dfu_progress_t progress; /**< Current DFU progress. */
|
||||
|
||||
uint32_t enter_buttonless_dfu;
|
||||
uint8_t init_command[INIT_COMMAND_MAX_SIZE]; /**< Buffer for storing the init command. */
|
||||
|
||||
uint32_t boot_validation_crc;
|
||||
boot_validation_t boot_validation_softdevice;
|
||||
boot_validation_t boot_validation_app;
|
||||
boot_validation_t boot_validation_bootloader;
|
||||
|
||||
nrf_dfu_peer_data_t peer_data; /**< Not included in calculated CRC. */
|
||||
nrf_dfu_adv_name_t adv_name; /**< Not included in calculated CRC. */
|
||||
} nrf_dfu_settings_t;
|
||||
|
||||
#pragma pack() // revert pack settings
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_TYPES_H__
|
||||
|
||||
/** @} */
|
||||
220
components/libraries/bootloader/dfu/nrf_dfu_utils.c
Normal file
220
components/libraries/bootloader/dfu/nrf_dfu_utils.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_dfu_utils.h"
|
||||
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "crc32.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_dfu_validation.h"
|
||||
|
||||
void nrf_dfu_bank_invalidate(nrf_dfu_bank_t * const p_bank)
|
||||
{
|
||||
// Set the bank-code to invalid, and reset size/CRC
|
||||
memset(p_bank, 0, sizeof(nrf_dfu_bank_t));
|
||||
|
||||
// Reset write pointer after completed operation
|
||||
s_dfu_settings.write_offset = 0;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
|
||||
void nrf_dfu_softdevice_invalidate(void)
|
||||
{
|
||||
static const uint32_t all_zero = 0UL;
|
||||
|
||||
if (SD_PRESENT && !NRF_DFU_IN_APP)
|
||||
{
|
||||
ret_code_t err_code = nrf_dfu_flash_store(SD_MAGIC_NUMBER_ABS_OFFSET_GET(MBR_SIZE), &all_zero, 4, NULL);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not invalidate SoftDevice.")
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there is an app it must be invalidated since its start address can no longer be resolved.
|
||||
if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP)
|
||||
{
|
||||
s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_INVALID;
|
||||
}
|
||||
// Since the start of bank 0 has now implicitly been moved to the start
|
||||
// of the invalidated SoftDevice, its image size must be increased by the
|
||||
// same amount so the start of bank 1 will be correctly calculated.
|
||||
s_dfu_settings.bank_0.image_size += SD_SIZE_GET(MBR_SIZE) - MBR_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t nrf_dfu_bank0_start_addr(void)
|
||||
{
|
||||
if (SD_PRESENT)
|
||||
{
|
||||
return ALIGN_TO_PAGE(SD_SIZE_GET(MBR_SIZE));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MBR_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_bank1_start_addr(void)
|
||||
{
|
||||
uint32_t bank0_addr = nrf_dfu_bank0_start_addr();
|
||||
return ALIGN_TO_PAGE(bank0_addr + s_dfu_settings.bank_0.image_size);
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_app_start_address(void)
|
||||
{
|
||||
return nrf_dfu_bank0_start_addr();
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_softdevice_start_address(void)
|
||||
{
|
||||
return MBR_SIZE;
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_dfu_cache_prepare(const uint32_t required_size, bool single_bank, bool keep_app, bool keep_softdevice)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
bool cache_too_small;
|
||||
enum
|
||||
{
|
||||
INITIAL_DELETE_APP = 0,
|
||||
APP_DELETED_DELETE_SOFTDEVICE = 1,
|
||||
SOFTDEVICE_DELETED = 2
|
||||
} pass;
|
||||
|
||||
NRF_LOG_DEBUG("Enter nrf_dfu_cache_prepare()");
|
||||
NRF_LOG_DEBUG("required_size: 0x%x.", required_size);
|
||||
NRF_LOG_DEBUG("single_bank: %s.", single_bank ? "true" : "false");
|
||||
NRF_LOG_DEBUG("keep_app: %s.", keep_app ? "true" : "false");
|
||||
NRF_LOG_DEBUG("keep_softdevice: %s.", keep_softdevice ? "true" : "false");
|
||||
NRF_LOG_DEBUG("SD_PRESENT: %s.", SD_PRESENT ? "true" : "false");
|
||||
NRF_LOG_DEBUG("Bank contents:");
|
||||
NRF_LOG_DEBUG("Bank 0 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_0.bank_code, s_dfu_settings.bank_0.image_size);
|
||||
NRF_LOG_DEBUG("Bank 1 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_1.bank_code, s_dfu_settings.bank_1.image_size);
|
||||
|
||||
// Pass 0 deletes the app if necessary or requested, and if so, proceeds to pass 1.
|
||||
// Pass 1 deletes the SoftDevice if necessary or requested, and if so, proceeds to pass 2.
|
||||
// Pass 2 does a last size check.
|
||||
for (pass = INITIAL_DELETE_APP; pass <= SOFTDEVICE_DELETED; pass++)
|
||||
{
|
||||
uint32_t cache_address;
|
||||
const uint32_t bootloader_start_addr = BOOTLOADER_START_ADDR; // Assign to a variable to prevent warning in Keil 4.
|
||||
bool keep_firmware = true;
|
||||
bool delete_more;
|
||||
|
||||
switch (pass)
|
||||
{
|
||||
case INITIAL_DELETE_APP:
|
||||
cache_address = nrf_dfu_bank1_start_addr();
|
||||
|
||||
// If there is no app, keep_app should be assumed false, so we can free up more space.
|
||||
keep_firmware = keep_app && (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP);
|
||||
break;
|
||||
|
||||
case APP_DELETED_DELETE_SOFTDEVICE:
|
||||
cache_address = nrf_dfu_bank0_start_addr();
|
||||
|
||||
// If there is no SoftDevice, keep_SoftDevice should be assumed true, because there is
|
||||
// no point to continuing since the SoftDevice is the last firmware that can be deleted.
|
||||
keep_firmware = keep_softdevice || !SD_PRESENT;
|
||||
break;
|
||||
|
||||
case SOFTDEVICE_DELETED:
|
||||
cache_address = nrf_dfu_softdevice_start_address();
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(false);
|
||||
cache_address = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(cache_address <= DFU_REGION_END(bootloader_start_addr));
|
||||
cache_too_small = required_size > (DFU_REGION_END(bootloader_start_addr) - cache_address);
|
||||
delete_more = cache_too_small || single_bank; // Delete app or SoftDevice only if we need more room, or if single bank is requested.
|
||||
|
||||
NRF_LOG_DEBUG("pass: %d.", pass);
|
||||
NRF_LOG_DEBUG("cache_address: 0x%x.", cache_address);
|
||||
NRF_LOG_DEBUG("cache_too_small: %s.", cache_too_small ? "true" : "false");
|
||||
NRF_LOG_DEBUG("keep_firmware: %s.", keep_firmware ? "true" : "false");
|
||||
NRF_LOG_DEBUG("delete_more: %s.", delete_more ? "true" : "false");
|
||||
|
||||
if (!delete_more || keep_firmware || (pass >= SOFTDEVICE_DELETED))
|
||||
{
|
||||
// Stop, done.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cache_too_small)
|
||||
{
|
||||
NRF_LOG_WARNING("Aborting. Cannot fit new firmware on device");
|
||||
err_code = NRF_ERROR_NO_MEM;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Room was found. Make the necessary preparations for receiving update.
|
||||
|
||||
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
|
||||
if (pass >= SOFTDEVICE_DELETED)
|
||||
{
|
||||
NRF_LOG_DEBUG("Invalidating SoftDevice.");
|
||||
nrf_dfu_softdevice_invalidate();
|
||||
}
|
||||
#endif
|
||||
if (pass >= APP_DELETED_DELETE_SOFTDEVICE)
|
||||
{
|
||||
NRF_LOG_DEBUG("Invalidating app.");
|
||||
nrf_dfu_bank_invalidate(&s_dfu_settings.bank_0);
|
||||
}
|
||||
|
||||
err_code = NRF_SUCCESS;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
154
components/libraries/bootloader/dfu/nrf_dfu_utils.h
Normal file
154
components/libraries/bootloader/dfu/nrf_dfu_utils.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup sdk_nrf_dfu_utils DFU utilities
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
*/
|
||||
|
||||
#ifndef NRF_DFU_UTILS_H__
|
||||
#define NRF_DFU_UTILS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "app_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Round up val to the next page boundary
|
||||
*/
|
||||
#define ALIGN_TO_PAGE(val) ALIGN_NUM((CODE_PAGE_SIZE), (val))
|
||||
|
||||
|
||||
/** @brief Function for getting the start address of bank 0.
|
||||
*
|
||||
* @note Bank 0 starts after the SoftDevice if a SoftDevice is present.
|
||||
*
|
||||
* @return The start address of bank 0.
|
||||
*/
|
||||
uint32_t nrf_dfu_bank0_start_addr(void);
|
||||
|
||||
|
||||
/** @brief Function for getting the start address of bank 1.
|
||||
*
|
||||
* @return The start address of bank 1.
|
||||
*/
|
||||
uint32_t nrf_dfu_bank1_start_addr(void);
|
||||
|
||||
|
||||
/** @brief Function for getting the start address of the app.
|
||||
*
|
||||
* @return The start address of the bootable app.
|
||||
*/
|
||||
uint32_t nrf_dfu_app_start_address(void);
|
||||
|
||||
|
||||
/** @brief Function for getting the start address of the SoftDevice.
|
||||
*
|
||||
* @return The start address of the SoftDevivce.
|
||||
*/
|
||||
uint32_t nrf_dfu_softdevice_start_address(void);
|
||||
|
||||
|
||||
/** @brief Function for finding and preparing a place in flash in which to store a DFU update.
|
||||
*
|
||||
* @details This function checks the size requirements and selects a location for
|
||||
* placing the cache of the DFU images.
|
||||
* The function tries to find enough space after the existing firmwares. If there is not
|
||||
* enough space, the present application is deleted. If there is still not enough space,
|
||||
* the SoftDevice is deleted.
|
||||
* If @p single_bank is true, the default behavior is to immediately delete the app and
|
||||
* SoftDevice as necessary to place the new firmware at its intended location. If the
|
||||
* intended location cannot be made available, or if the update is a bootloader update,
|
||||
* the update will be a dual bank update, and nothing will be deleted by this function
|
||||
* except when needed for size.
|
||||
* If @p keep_app is true, the app is never deleted by this function. Likewise if @p
|
||||
* keep_softdevice is true, the SoftDevice is never deleted by this function.
|
||||
* If the new firmware cannot fit within the constraints, nothing is deleted and the
|
||||
* function fails.
|
||||
*
|
||||
* @param[in] required_size Requirements for the size of the new image.
|
||||
* @param[in] single_bank Whether to put the firmware directly where it's meant to go.
|
||||
* @p keep_app and @p keep_softdevice take precedence over this.
|
||||
* @param[in] keep_app True to ensure the app is not deleted by this function. This
|
||||
* effectively enforces dual bank update.
|
||||
* @param[out] keep_softdevice True to ensure the SoftDevice is not deleted by this function.
|
||||
*
|
||||
* @retval NRF_SUCCESS If a cache location was found for the DFU process.
|
||||
* @retval NRF_ERROR_NO_MEM If there is not enough space available to receive the update.
|
||||
* Nothing has been deleted.
|
||||
*/
|
||||
uint32_t nrf_dfu_cache_prepare(uint32_t required_size, bool single_bank, bool keep_app, bool keep_softdevice);
|
||||
|
||||
|
||||
/**@brief Function for making sure a SoftDevice is not recognized as such anymore.
|
||||
*
|
||||
* @details It works by overwriting the magic number of the SoftDevice with 0s. The
|
||||
* magic number is used throughout the bootloader to detect whether a SoftDevice
|
||||
* is present.
|
||||
*
|
||||
* @warning This function should only be called when both banks are already invalid.
|
||||
* because the (implicit) position of the banks will shift when the SoftDevice
|
||||
* is invalidated.
|
||||
*/
|
||||
void nrf_dfu_softdevice_invalidate(void);
|
||||
|
||||
|
||||
/**@brief Function for making sure a bank is not copied or booted.
|
||||
*
|
||||
* @details This also sets the size of the bank to 0.
|
||||
*
|
||||
* @param[in] p_bank Pointer to the bank to be invalidated.
|
||||
*/
|
||||
void nrf_dfu_bank_invalidate(nrf_dfu_bank_t * const p_bank);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_UTILS_H__
|
||||
|
||||
/** @} */
|
||||
1087
components/libraries/bootloader/dfu/nrf_dfu_validation.c
Normal file
1087
components/libraries/bootloader/dfu/nrf_dfu_validation.c
Normal file
File diff suppressed because it is too large
Load Diff
199
components/libraries/bootloader/dfu/nrf_dfu_validation.h
Normal file
199
components/libraries/bootloader/dfu/nrf_dfu_validation.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_validation Validation
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
*/
|
||||
|
||||
#ifndef __NRF_DFU_VALIDATION_H
|
||||
#define __NRF_DFU_VALIDATION_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "sdk_errors.h"
|
||||
#include "dfu-cc.pb.h"
|
||||
#include "nrf_dfu_handling_error.h"
|
||||
|
||||
/**
|
||||
* @brief Function for module initialization.
|
||||
*
|
||||
* Function checks if there is a valid init packet in DFU settings written in flash.
|
||||
*/
|
||||
void nrf_dfu_validation_init(void);
|
||||
|
||||
/**
|
||||
* @brief Function called on reception of init command creation request.
|
||||
*
|
||||
* @param[in] size Size of incoming init packet.
|
||||
*
|
||||
* @return Operation result. See @ref nrf_dfu_result_t
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_validation_init_cmd_create(uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Function called on reception of fragment of init command.
|
||||
*
|
||||
* @param[in] p_data Init command fragment.
|
||||
* @param[in] length Init command fragment size.
|
||||
*
|
||||
* @return Operation result. See @ref nrf_dfu_result_t
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_validation_init_cmd_append(uint8_t const * p_data, uint32_t length);
|
||||
|
||||
/**
|
||||
* @brief Function for getting init command status.
|
||||
*
|
||||
* @param[out] p_offset Current offset.
|
||||
* @param[out] p_crc Current CRC.
|
||||
* @param[out] p_max_size Maximum size of init command.
|
||||
*/
|
||||
void nrf_dfu_validation_init_cmd_status_get(uint32_t * p_offset,
|
||||
uint32_t * p_crc,
|
||||
uint32_t * p_max_size);
|
||||
|
||||
/**
|
||||
* @brief Function for inquiring whether a valid init command has been received.
|
||||
*
|
||||
* @return true if there is a valid init command. This can be true at boot time
|
||||
* if the device was reset during a DFU operation.
|
||||
*/
|
||||
bool nrf_dfu_validation_init_cmd_present(void);
|
||||
|
||||
/**
|
||||
* @brief Function for validating init command and retrieving the address and length of the firmware.
|
||||
*
|
||||
* If init command is successfully validated Bank 1 details are written to out parameters.
|
||||
*
|
||||
* Until @ref nrf_dfu_validation_init_cmd_create is called, this function can be called
|
||||
* again after the first time without side effects to retrieve address and length.
|
||||
*
|
||||
* @param[out] p_dst_data_addr Start address of received data, if validation is successful.
|
||||
* @param[out] p_data_len Expected length of received data, if validation is successful.
|
||||
*
|
||||
* @return Operation result. See @ref nrf_dfu_result_t
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr,
|
||||
uint32_t * p_data_len);
|
||||
|
||||
/**
|
||||
* @brief Function for validating the init command.
|
||||
*
|
||||
* @return Operation result. See @ref nrf_dfu_result_t.
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_validation_prevalidate(void);
|
||||
|
||||
/**
|
||||
* @brief Function for validating the firmware for booting.
|
||||
*
|
||||
* @param[in] p_validation Validation parameters.
|
||||
* @param[in] data_addr Start address of the firmware.
|
||||
* @param[in] data_len Length of the firmware.
|
||||
*
|
||||
* @return Whether the firmware is valid for booting.
|
||||
*/
|
||||
bool nrf_dfu_validation_boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len);
|
||||
|
||||
/**
|
||||
* @brief Function for postvalidating the update after all data is received.
|
||||
*
|
||||
* @param[in] data_addr Start address of the received data.
|
||||
* @param[in] data_len Length of the received data.
|
||||
*
|
||||
* @return Operation result. See @ref nrf_dfu_result_t.
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_validation_post_data_execute(uint32_t data_addr, uint32_t data_len);
|
||||
|
||||
/**
|
||||
* @brief Function for preparing the update for activation.
|
||||
*
|
||||
* This function is called after a reset, after all data is received. This function also runs
|
||||
* @ref nrf_dfu_validation_post_data_execute internally. If this succeeds, the update is
|
||||
* activated by the activation machinery in the bootloader the next time it runs.
|
||||
*
|
||||
* @note The caller must have permissions to edit the relevant entries in the settings.
|
||||
*
|
||||
* @param[in] data_addr Start address of the received data.
|
||||
* @param[in] data_len Length of the received data.
|
||||
*
|
||||
* @return Operation result. See @ref nrf_dfu_result_t
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_validation_activation_prepare(uint32_t data_addr, uint32_t data_len);
|
||||
|
||||
/**
|
||||
* @brief Function to execute on a validated external app.
|
||||
*
|
||||
* @details This function is called once all data is received with the parameter
|
||||
* @p is_boot set to false. The function is called during bootup with the parameter
|
||||
* set to true.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @note This function requires that @ref NRF_DFU_SUPPORTS_EXTERNAL_APP is set to 1.
|
||||
* It is up to the user to implement this function.
|
||||
*
|
||||
* @warning Parameter @p is_trusted must be used to ensure that no loss of security of process can happen.
|
||||
* This parameter should only be set if the function is called after a root-of-trust
|
||||
* reset on the device.
|
||||
*
|
||||
* Parameter @p is_trusted can be used for the following:
|
||||
* - Ensuring that an external application is run only once (after root-of-trust).
|
||||
* - Ensuring that a bank flag or any other flash access can only happen after root-of-trust.
|
||||
* - Ensuring that the device reaches the correct state after a power failure on the device.
|
||||
*
|
||||
* @param[in] p_init Init command for the firmware upgrade.
|
||||
* @param[in] is_trusted Must be set to true if this is called after root-of-trust boot.
|
||||
* Must be set to false if this is called from DFU mode or background
|
||||
* DFU operation.
|
||||
*
|
||||
* @return Operation result. see @ref nrf_dfu_result_t.
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_validation_post_external_app_execute(dfu_init_command_t const * p_init, bool is_trusted);
|
||||
|
||||
/**
|
||||
* @brief Function to check if there is a valid external app in Bank 1.
|
||||
*
|
||||
* @returns True if valid external app, otherwise false.
|
||||
*/
|
||||
bool nrf_dfu_validation_valid_external_app(void);
|
||||
|
||||
#endif //__NRF_DFU_VALIDATION_H
|
||||
|
||||
/** @} */
|
||||
312
components/libraries/bootloader/dfu/nrf_dfu_ver_validation.c
Normal file
312
components/libraries/bootloader/dfu/nrf_dfu_ver_validation.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "nrf_dfu_utils.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_crypto.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "dfu-cc.pb.h"
|
||||
#include "nrf_dfu_ver_validation.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_ver_validation
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
/** @brief Macro for reading the Firmware ID of a SoftDevice at a given base address.
|
||||
*/
|
||||
#ifndef _SD_FWID_GET
|
||||
#define _SD_FWID_GET(baseaddr) SD_OFFSET_GET_UINT16(baseaddr, 0x0C)
|
||||
#endif
|
||||
|
||||
#define EXT_ERR(err) (nrf_dfu_result_t)((uint32_t)NRF_DFU_RES_CODE_EXT_ERROR + (uint32_t)err)
|
||||
|
||||
static bool sd_req_check(uint32_t const * p_sd_req, uint8_t sd_req_cnt, bool accept_any)
|
||||
{
|
||||
bool result = false;
|
||||
for (uint8_t i = 0; i < sd_req_cnt; i++)
|
||||
{
|
||||
if ((SD_PRESENT && (p_sd_req[i] == _SD_FWID_GET(MBR_SIZE))) ||
|
||||
(accept_any && (p_sd_req[i] == SD_REQ_ANY_VERSION))
|
||||
)
|
||||
{
|
||||
// Found a matching sd_req field. sd_req is ok.
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static bool sd_req_ok(dfu_init_command_t const * p_init)
|
||||
{
|
||||
ASSERT(p_init != NULL);
|
||||
bool result;
|
||||
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
|
||||
// The bootloader needs the SoftDevice, so disabling NRF_DFU_APP_DOWNGRADE_PREVENTION
|
||||
// should not be applied to SoftDevice updates.
|
||||
const bool prevent_downgrade = NRF_DFU_APP_DOWNGRADE_PREVENTION || (p_init->type == DFU_FW_TYPE_SOFTDEVICE);
|
||||
#else
|
||||
const bool prevent_downgrade = NRF_DFU_APP_DOWNGRADE_PREVENTION;
|
||||
#endif
|
||||
|
||||
if (SD_PRESENT)
|
||||
{
|
||||
if (p_init->sd_req_count == 0)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else if (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD)
|
||||
{
|
||||
result = sd_req_check(p_init->sd_req,
|
||||
p_init->sd_req_count,
|
||||
(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION));
|
||||
}
|
||||
else if (p_init->type == DFU_FW_TYPE_APPLICATION)
|
||||
{
|
||||
// The application wants to overwrite the SoftDevice.
|
||||
if (prevent_downgrade && (p_init->sd_req_count > 1) && (p_init->sd_req[0] == SD_REQ_APP_OVERWRITES_SD))
|
||||
{
|
||||
// The application can overwrite the SD if sd_req[0] == 0 and table has the FWID of the current SD.
|
||||
result = sd_req_check(p_init->sd_req, p_init->sd_req_count, false);
|
||||
|
||||
// Prevent BLE/ANT bootloaders from allowing applications overwriting the SoftDevice.
|
||||
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
|
||||
result = false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
else if(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
|
||||
{
|
||||
// Won't accept FW upgrade using external application to
|
||||
// enforce replacing SoftDevice (SD_REQ_APP_OVERWRITES_SD)
|
||||
result = false;
|
||||
}
|
||||
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
else
|
||||
{
|
||||
// Don't allow SoftDevice updates which assume no SD is present already.
|
||||
result = !prevent_downgrade || (p_init->type != DFU_FW_TYPE_SOFTDEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (p_init->sd_req_count && (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD))
|
||||
{
|
||||
// Fail if there is no SD and the update requires SD. The special "any" FWID is valid
|
||||
// for external apps only.
|
||||
result = false;
|
||||
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
result = sd_req_check(p_init->sd_req,
|
||||
p_init->sd_req_count,
|
||||
(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION));
|
||||
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there is no SD and update has SD it is accepted only if it has a fw_version.
|
||||
result = !prevent_downgrade || p_init->has_fw_version;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static bool fw_hash_type_ok(dfu_init_command_t const * p_init)
|
||||
{
|
||||
ASSERT(p_init != NULL);
|
||||
|
||||
return (p_init->hash.hash_type == DFU_HASH_TYPE_SHA256);
|
||||
}
|
||||
|
||||
|
||||
static bool fw_version_required(dfu_fw_type_t new_fw_type)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (new_fw_type == DFU_FW_TYPE_SOFTDEVICE)
|
||||
{
|
||||
result = false; // fw_version is optional in SoftDevice updates. If present, it will be checked against the app version.
|
||||
}
|
||||
else if (new_fw_type == DFU_FW_TYPE_APPLICATION)
|
||||
{
|
||||
result = NRF_DFU_APP_DOWNGRADE_PREVENTION; // fw_version is configurable in app updates.
|
||||
}
|
||||
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
#if !NRF_DFU_EXTERNAL_APP_VERSIONING
|
||||
else if (new_fw_type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif //!NRF_DFU_EXTERNAL_APP_VERSIONING
|
||||
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static bool fw_type_ok(dfu_init_command_t const * p_init)
|
||||
{
|
||||
ASSERT(p_init != NULL);
|
||||
|
||||
return ((p_init->has_type)
|
||||
&& ( (p_init->type == DFU_FW_TYPE_APPLICATION)
|
||||
|| (p_init->type == DFU_FW_TYPE_SOFTDEVICE)
|
||||
|| (p_init->type == DFU_FW_TYPE_BOOTLOADER)
|
||||
|| (p_init->type == DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER)
|
||||
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
|| (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
|
||||
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef NRF_DFU_APP_ACCEPT_SAME_VERSION
|
||||
#define NRF_DFU_APP_ACCEPT_SAME_VERSION 1
|
||||
#endif
|
||||
|
||||
|
||||
// This function assumes p_init->has_fw_version.
|
||||
static bool fw_version_ok(dfu_init_command_t const * p_init)
|
||||
{
|
||||
ASSERT(p_init != NULL);
|
||||
ASSERT(p_init->has_fw_version);
|
||||
|
||||
if ((p_init->type == DFU_FW_TYPE_APPLICATION) ||
|
||||
(p_init->type == DFU_FW_TYPE_SOFTDEVICE))
|
||||
{
|
||||
if (!NRF_DFU_APP_DOWNGRADE_PREVENTION)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((p_init->fw_version > s_dfu_settings.app_version))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((p_init->fw_version == s_dfu_settings.app_version))
|
||||
{
|
||||
return NRF_DFU_APP_ACCEPT_SAME_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
#if NRF_DFU_EXTERNAL_APP_VERSIONING
|
||||
else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
|
||||
{
|
||||
return (p_init->fw_version >= s_dfu_settings.app_version);
|
||||
}
|
||||
#else
|
||||
else if(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif // NRF_DFU_EXTERNAL_APP_VERSIONING
|
||||
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
|
||||
else
|
||||
{
|
||||
return (p_init->fw_version > s_dfu_settings.bootloader_version);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_init_command_t const * p_init)
|
||||
{
|
||||
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
|
||||
if (!fw_type_ok(p_init))
|
||||
{
|
||||
NRF_LOG_ERROR("Invalid firmware type.");
|
||||
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
|
||||
}
|
||||
else if (!fw_hash_type_ok(p_init))
|
||||
{
|
||||
NRF_LOG_ERROR("Invalid hash type.");
|
||||
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_WRONG_HASH_TYPE);
|
||||
}
|
||||
else if (!NRF_DFU_DEBUG ||
|
||||
(NRF_DFU_DEBUG && ((p_init->has_is_debug == false) || (p_init->is_debug == false))))
|
||||
{
|
||||
if (p_init->has_hw_version == false)
|
||||
{
|
||||
NRF_LOG_ERROR("No HW version.");
|
||||
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
|
||||
}
|
||||
else if (p_init->hw_version != NRF_DFU_HW_VERSION)
|
||||
{
|
||||
NRF_LOG_WARNING("Faulty HW version.");
|
||||
ret_val = EXT_ERR( NRF_DFU_EXT_ERROR_HW_VERSION_FAILURE);
|
||||
}
|
||||
|
||||
else if (!sd_req_ok(p_init))
|
||||
{
|
||||
NRF_LOG_WARNING("SD req not met.");
|
||||
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_SD_VERSION_FAILURE);
|
||||
}
|
||||
else if (p_init->has_fw_version)
|
||||
{
|
||||
if (!fw_version_ok(p_init))
|
||||
{
|
||||
NRF_LOG_WARNING("FW version too low.");
|
||||
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_FW_VERSION_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fw_version_required(p_init->type))
|
||||
{
|
||||
NRF_LOG_ERROR("FW version missing.");
|
||||
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
64
components/libraries/bootloader/dfu/nrf_dfu_ver_validation.h
Normal file
64
components/libraries/bootloader/dfu/nrf_dfu_ver_validation.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 __NRF_DFU_VER_VALIDATION_H
|
||||
#define __NRF_DFU_VER_VALIDATION_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf_dfu_handling_error.h"
|
||||
#include "dfu-cc.pb.h"
|
||||
|
||||
/** @brief SD_REQ field value which indicates that Softdevice can be overwritten by the application. */
|
||||
#define SD_REQ_APP_OVERWRITES_SD 0
|
||||
|
||||
/** @brief SD_REQ_ANY_VERSION field value which indicates that any SoftDevice version is valid.
|
||||
*
|
||||
* @note This is used by external application in case SoftDevice version compatibility isn't needed.
|
||||
*/
|
||||
#define SD_REQ_ANY_VERSION (0xFFFE)
|
||||
|
||||
/**
|
||||
* @brief Function for validating version of new firmware.
|
||||
*
|
||||
* @return NRF_DFU_RES_CODE_SUCCESS if successful or error code otherwise
|
||||
*/
|
||||
nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_init_command_t const * p_init);
|
||||
|
||||
#endif //__NRF_DFU_VER_VALIDATION_H
|
||||
528
components/libraries/bootloader/nrf_bootloader.c
Normal file
528
components/libraries/bootloader/nrf_bootloader.c
Normal file
@@ -0,0 +1,528 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_bootloader.h"
|
||||
|
||||
#include "compiler_abstraction.h"
|
||||
#include "nrf.h"
|
||||
#include "boards.h"
|
||||
#include "sdk_config.h"
|
||||
#include "nrf_power.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_dfu.h"
|
||||
#include "nrf_error.h"
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "nrf_dfu_utils.h"
|
||||
#include "nrf_bootloader_wdt.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_bootloader_app_start.h"
|
||||
#include "nrf_bootloader_fw_activation.h"
|
||||
#include "nrf_bootloader_dfu_timers.h"
|
||||
#include "app_scheduler.h"
|
||||
#include "nrf_dfu_validation.h"
|
||||
|
||||
static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
|
||||
static volatile bool m_flash_write_done;
|
||||
|
||||
#define SCHED_QUEUE_SIZE 32 /**< Maximum number of events in the scheduler queue. */
|
||||
#define SCHED_EVENT_DATA_SIZE NRF_DFU_SCHED_EVENT_DATA_SIZE /**< Maximum app_scheduler event size. */
|
||||
|
||||
#if !(defined(NRF_BL_DFU_ENTER_METHOD_BUTTON) && \
|
||||
defined(NRF_BL_DFU_ENTER_METHOD_PINRESET) && \
|
||||
defined(NRF_BL_DFU_ENTER_METHOD_GPREGRET) && \
|
||||
defined(NRF_BL_DFU_ENTER_METHOD_BUTTONLESS)&& \
|
||||
defined(NRF_BL_RESET_DELAY_MS) && \
|
||||
defined(NRF_BL_DEBUG_PORT_DISABLE))
|
||||
#error Configuration file is missing flags. Update sdk_config.h.
|
||||
#endif
|
||||
|
||||
STATIC_ASSERT((NRF_BL_DFU_INACTIVITY_TIMEOUT_MS >= 100) || (NRF_BL_DFU_INACTIVITY_TIMEOUT_MS == 0),
|
||||
"NRF_BL_DFU_INACTIVITY_TIMEOUT_MS must be 100 ms or more, or 0 to indicate that it is disabled.");
|
||||
|
||||
#if defined(NRF_LOG_BACKEND_FLASH_START_PAGE)
|
||||
STATIC_ASSERT(NRF_LOG_BACKEND_FLASH_START_PAGE != 0,
|
||||
"If nrf_log flash backend is used it cannot use space after code because it would collide with settings page.");
|
||||
#endif
|
||||
|
||||
/**@brief Weak implemenation of nrf_dfu_init
|
||||
*
|
||||
* @note This function will be overridden if nrf_dfu.c is
|
||||
* compiled and linked with the project
|
||||
*/
|
||||
#if (__LINT__ != 1)
|
||||
__WEAK uint32_t nrf_dfu_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
NRF_LOG_DEBUG("in weak nrf_dfu_init");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**@brief Weak implementation of nrf_dfu_init
|
||||
*
|
||||
* @note This function must be overridden in application if
|
||||
* user-specific initialization is needed.
|
||||
*/
|
||||
__WEAK uint32_t nrf_dfu_init_user(void)
|
||||
{
|
||||
NRF_LOG_DEBUG("in weak nrf_dfu_init_user");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void flash_write_callback(void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
m_flash_write_done = true;
|
||||
}
|
||||
|
||||
|
||||
static void do_reset(void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
NRF_LOG_FINAL_FLUSH();
|
||||
|
||||
nrf_delay_ms(NRF_BL_RESET_DELAY_MS);
|
||||
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
|
||||
static void bootloader_reset(bool do_backup)
|
||||
{
|
||||
NRF_LOG_DEBUG("Resetting bootloader.");
|
||||
|
||||
if (do_backup)
|
||||
{
|
||||
m_flash_write_done = false;
|
||||
nrf_dfu_settings_backup(do_reset);
|
||||
}
|
||||
else
|
||||
{
|
||||
do_reset(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void inactivity_timeout(void)
|
||||
{
|
||||
NRF_LOG_INFO("Inactivity timeout.");
|
||||
bootloader_reset(true);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling DFU events.
|
||||
*/
|
||||
static void dfu_observer(nrf_dfu_evt_type_t evt_type)
|
||||
{
|
||||
switch (evt_type)
|
||||
{
|
||||
case NRF_DFU_EVT_DFU_STARTED:
|
||||
case NRF_DFU_EVT_OBJECT_RECEIVED:
|
||||
nrf_bootloader_dfu_inactivity_timer_restart(
|
||||
NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS),
|
||||
inactivity_timeout);
|
||||
break;
|
||||
case NRF_DFU_EVT_DFU_COMPLETED:
|
||||
case NRF_DFU_EVT_DFU_ABORTED:
|
||||
bootloader_reset(true);
|
||||
break;
|
||||
case NRF_DFU_EVT_TRANSPORT_DEACTIVATED:
|
||||
// Reset the internal state of the DFU settings to the last stored state.
|
||||
nrf_dfu_settings_reinit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_user_observer)
|
||||
{
|
||||
m_user_observer(evt_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for initializing the event scheduler.
|
||||
*/
|
||||
static void scheduler_init(void)
|
||||
{
|
||||
APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Suspend the CPU until an interrupt occurs.
|
||||
*/
|
||||
static void wait_for_event(void)
|
||||
{
|
||||
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
|
||||
(void)sd_app_evt_wait();
|
||||
#else
|
||||
// Wait for an event.
|
||||
__WFE();
|
||||
// Clear the internal event register.
|
||||
__SEV();
|
||||
__WFE();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**@brief Continually sleep and process tasks whenever woken.
|
||||
*/
|
||||
static void loop_forever(void)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
//feed the watchdog if enabled.
|
||||
nrf_bootloader_wdt_feed();
|
||||
|
||||
app_sched_execute();
|
||||
|
||||
if (!NRF_LOG_PROCESS())
|
||||
{
|
||||
wait_for_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
|
||||
#ifndef BUTTON_PULL
|
||||
#error NRF_BL_DFU_ENTER_METHOD_BUTTON is enabled but not buttons seem to be available on the board.
|
||||
#endif
|
||||
/**@brief Function for initializing button used to enter DFU mode.
|
||||
*/
|
||||
static void dfu_enter_button_init(void)
|
||||
{
|
||||
nrf_gpio_cfg_sense_input(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN,
|
||||
BUTTON_PULL,
|
||||
NRF_GPIO_PIN_SENSE_LOW);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool crc_on_valid_app_required(void)
|
||||
{
|
||||
bool ret = true;
|
||||
if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_SYSTEMOFF_RESET &&
|
||||
(nrf_power_resetreas_get() & NRF_POWER_RESETREAS_OFF_MASK))
|
||||
{
|
||||
nrf_power_resetreas_clear(NRF_POWER_RESETREAS_OFF_MASK);
|
||||
ret = false;
|
||||
}
|
||||
else if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_GPREGRET2 &&
|
||||
((nrf_power_gpregret2_get() & BOOTLOADER_DFU_GPREGRET2_MASK) == BOOTLOADER_DFU_GPREGRET2)
|
||||
&& (nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC_BIT_MASK))
|
||||
{
|
||||
nrf_power_gpregret2_set(nrf_power_gpregret2_get() & ~BOOTLOADER_DFU_SKIP_CRC);
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len, bool do_crc)
|
||||
{
|
||||
if (!do_crc && (p_validation->type == VALIDATE_CRC))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return nrf_dfu_validation_boot_validate(p_validation, data_addr, data_len);
|
||||
}
|
||||
|
||||
|
||||
/** @brief Function for checking if the main application is valid.
|
||||
*
|
||||
* @details This function checks if there is a valid application
|
||||
* located at Bank 0.
|
||||
*
|
||||
* @param[in] do_crc Perform CRC check on application. Only CRC checks
|
||||
can be skipped. For other boot validation types,
|
||||
this parameter is ignored.
|
||||
*
|
||||
* @retval true If a valid application has been detected.
|
||||
* @retval false If there is no valid application.
|
||||
*/
|
||||
static bool app_is_valid(bool do_crc)
|
||||
{
|
||||
if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP)
|
||||
{
|
||||
NRF_LOG_INFO("Boot validation failed. No valid app to boot.");
|
||||
return false;
|
||||
}
|
||||
else if (NRF_BL_APP_SIGNATURE_CHECK_REQUIRED &&
|
||||
(s_dfu_settings.boot_validation_app.type != VALIDATE_ECDSA_P256_SHA256))
|
||||
{
|
||||
NRF_LOG_WARNING("Boot validation failed. The boot validation of the app must be a signature check.");
|
||||
return false;
|
||||
}
|
||||
else if (SD_PRESENT && !boot_validate(&s_dfu_settings.boot_validation_softdevice, MBR_SIZE, s_dfu_settings.sd_size, do_crc))
|
||||
{
|
||||
NRF_LOG_WARNING("Boot validation failed. SoftDevice is present but invalid.");
|
||||
return false;
|
||||
}
|
||||
else if (!boot_validate(&s_dfu_settings.boot_validation_app, nrf_dfu_bank0_start_addr(), s_dfu_settings.bank_0.image_size, do_crc))
|
||||
{
|
||||
NRF_LOG_WARNING("Boot validation failed. App is invalid.");
|
||||
return false;
|
||||
}
|
||||
// The bootloader itself is not checked, since a self-check of this kind gives little to no benefit
|
||||
// compared to the cost incurred on each bootup.
|
||||
|
||||
NRF_LOG_DEBUG("App is valid");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**@brief Function for clearing all DFU enter flags that
|
||||
* preserve state during reset.
|
||||
*
|
||||
* @details This is used to make sure that each of these flags
|
||||
* is checked only once after reset.
|
||||
*/
|
||||
static void dfu_enter_flags_clear(void)
|
||||
{
|
||||
if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
|
||||
(NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk))
|
||||
{
|
||||
// Clear RESETPIN flag.
|
||||
NRF_POWER->RESETREAS |= POWER_RESETREAS_RESETPIN_Msk;
|
||||
}
|
||||
|
||||
if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
|
||||
((nrf_power_gpregret_get() & BOOTLOADER_DFU_GPREGRET_MASK) == BOOTLOADER_DFU_GPREGRET)
|
||||
&& (nrf_power_gpregret_get() & BOOTLOADER_DFU_START_BIT_MASK))
|
||||
{
|
||||
// Clear DFU mark in GPREGRET register.
|
||||
nrf_power_gpregret_set(nrf_power_gpregret_get() & ~BOOTLOADER_DFU_START);
|
||||
}
|
||||
|
||||
if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
|
||||
(s_dfu_settings.enter_buttonless_dfu == 1))
|
||||
{
|
||||
// Clear DFU flag in flash settings.
|
||||
s_dfu_settings.enter_buttonless_dfu = 0;
|
||||
APP_ERROR_CHECK(nrf_dfu_settings_write(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for checking whether to enter DFU mode or not.
|
||||
*/
|
||||
static bool dfu_enter_check(void)
|
||||
{
|
||||
if (!app_is_valid(crc_on_valid_app_required()))
|
||||
{
|
||||
NRF_LOG_DEBUG("DFU mode because app is not valid.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NRF_BL_DFU_ENTER_METHOD_BUTTON &&
|
||||
(nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 0))
|
||||
{
|
||||
NRF_LOG_DEBUG("DFU mode requested via button.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
|
||||
(NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk))
|
||||
{
|
||||
NRF_LOG_DEBUG("DFU mode requested via pin-reset.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
|
||||
(nrf_power_gpregret_get() & BOOTLOADER_DFU_START))
|
||||
{
|
||||
NRF_LOG_DEBUG("DFU mode requested via GPREGRET.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
|
||||
(s_dfu_settings.enter_buttonless_dfu == 1))
|
||||
{
|
||||
NRF_LOG_DEBUG("DFU mode requested via bootloader settings.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
|
||||
static void postvalidate(void)
|
||||
{
|
||||
NRF_LOG_INFO("Postvalidating update after reset.");
|
||||
nrf_dfu_validation_init();
|
||||
|
||||
if (nrf_dfu_validation_init_cmd_present())
|
||||
{
|
||||
uint32_t firmware_start_addr;
|
||||
uint32_t firmware_size;
|
||||
|
||||
// Execute a previously received init packed. Subsequent executes will have no effect.
|
||||
if (nrf_dfu_validation_init_cmd_execute(&firmware_start_addr, &firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
if (nrf_dfu_validation_prevalidate() == NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
if (nrf_dfu_validation_activation_prepare(firmware_start_addr, firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INFO("Postvalidation successful.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_0;
|
||||
UNUSED_RETURN_VALUE(nrf_dfu_settings_write_and_backup(flash_write_callback));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
NRF_LOG_DEBUG("In nrf_bootloader_init");
|
||||
|
||||
ret_code_t ret_val;
|
||||
nrf_bootloader_fw_activation_result_t activation_result;
|
||||
uint32_t initial_timeout;
|
||||
bool dfu_enter = false;
|
||||
|
||||
m_user_observer = observer;
|
||||
|
||||
if (NRF_BL_DEBUG_PORT_DISABLE)
|
||||
{
|
||||
nrf_bootloader_debug_port_disable();
|
||||
}
|
||||
|
||||
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
|
||||
dfu_enter_button_init();
|
||||
#endif
|
||||
|
||||
ret_val = nrf_dfu_settings_init(false);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
|
||||
// Postvalidate if DFU has signaled that update is ready.
|
||||
if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1)
|
||||
{
|
||||
postvalidate();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if an update needs to be activated and activate it.
|
||||
activation_result = nrf_bootloader_fw_activate();
|
||||
|
||||
switch (activation_result)
|
||||
{
|
||||
case ACTIVATION_NONE:
|
||||
initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
|
||||
dfu_enter = dfu_enter_check();
|
||||
break;
|
||||
|
||||
case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
|
||||
initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
|
||||
dfu_enter = true;
|
||||
break;
|
||||
|
||||
case ACTIVATION_SUCCESS:
|
||||
bootloader_reset(true);
|
||||
NRF_LOG_ERROR("Unreachable");
|
||||
return NRF_ERROR_INTERNAL; // Should not reach this.
|
||||
|
||||
case ACTIVATION_ERROR:
|
||||
default:
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if (dfu_enter)
|
||||
{
|
||||
nrf_bootloader_wdt_init();
|
||||
scheduler_init();
|
||||
dfu_enter_flags_clear();
|
||||
|
||||
// Call user-defined init function if implemented
|
||||
ret_val = nrf_dfu_init_user();
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
nrf_bootloader_dfu_inactivity_timer_restart(initial_timeout, inactivity_timeout);
|
||||
|
||||
ret_val = nrf_dfu_init(dfu_observer);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Enter main loop");
|
||||
loop_forever(); // This function will never return.
|
||||
NRF_LOG_ERROR("Unreachable");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Erase additional data like peer data or advertisement name
|
||||
ret_val = nrf_dfu_settings_additional_erase();
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
m_flash_write_done = false;
|
||||
nrf_dfu_settings_backup(flash_write_callback);
|
||||
ASSERT(m_flash_write_done);
|
||||
|
||||
nrf_bootloader_app_start();
|
||||
NRF_LOG_ERROR("Unreachable");
|
||||
}
|
||||
|
||||
// Should not be reached.
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
79
components/libraries/bootloader/nrf_bootloader.h
Normal file
79
components/libraries/bootloader/nrf_bootloader.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
*
|
||||
* @defgroup nrf_bootloader Bootloader modules
|
||||
* @{
|
||||
* @ingroup app_common
|
||||
* @brief Bootloader and DFU modules
|
||||
*
|
||||
* The bootloader module can be used to implement a basic bootloader that
|
||||
* can be extended with, for example, Device Firmware Update (DFU) support
|
||||
* or custom functionality.
|
||||
*/
|
||||
|
||||
#ifndef NRF_BOOTLOADER_H__
|
||||
#define NRF_BOOTLOADER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_dfu.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Function for initializing the bootloader.
|
||||
*
|
||||
* @details This function is the entry point of all bootloader operations.
|
||||
* If DFU functionality is compiled in, the DFU process is initialized
|
||||
* when running this function.
|
||||
*
|
||||
* @note This function does not return unless an error occurred.
|
||||
*
|
||||
* @retval NRF_ERROR_INTERNAL Something went wrong.
|
||||
*/
|
||||
ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_BOOTLOADER_H__
|
||||
/** @} */
|
||||
77
components/libraries/bootloader/nrf_bootloader_app_start.c
Normal file
77
components/libraries/bootloader/nrf_bootloader_app_start.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "nrf.h"
|
||||
#include "nrf_bootloader_app_start.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_dfu_mbr.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
|
||||
// Do the final stages of app_start. Protect flash and run app. See nrf_bootloader_app_start_final.c
|
||||
void nrf_bootloader_app_start_final(uint32_t start_addr);
|
||||
|
||||
void nrf_bootloader_app_start(void)
|
||||
{
|
||||
uint32_t start_addr = MBR_SIZE; // Always boot from end of MBR. If a SoftDevice is present, it will boot the app.
|
||||
NRF_LOG_DEBUG("Running nrf_bootloader_app_start with address: 0x%08x", start_addr);
|
||||
uint32_t err_code;
|
||||
|
||||
// Disable and clear interrupts
|
||||
// Notice that this disables only 'external' interrupts (positive IRQn).
|
||||
NRF_LOG_DEBUG("Disabling interrupts. NVIC->ICER[0]: 0x%x", NVIC->ICER[0]);
|
||||
|
||||
NVIC->ICER[0]=0xFFFFFFFF;
|
||||
NVIC->ICPR[0]=0xFFFFFFFF;
|
||||
#if defined(__NRF_NVIC_ISER_COUNT) && __NRF_NVIC_ISER_COUNT == 2
|
||||
NVIC->ICER[1]=0xFFFFFFFF;
|
||||
NVIC->ICPR[1]=0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
err_code = nrf_dfu_mbr_irq_forward_address_set();
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed running nrf_dfu_mbr_irq_forward_address_set()");
|
||||
}
|
||||
|
||||
NRF_LOG_FLUSH();
|
||||
nrf_bootloader_app_start_final(start_addr);
|
||||
}
|
||||
88
components/libraries/bootloader/nrf_bootloader_app_start.h
Normal file
88
components/libraries/bootloader/nrf_bootloader_app_start.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_bootloader_app Application start
|
||||
* @{
|
||||
* @ingroup nrf_bootloader
|
||||
*/
|
||||
|
||||
#ifndef NRF_BOOTLOADER_APP_START_H__
|
||||
#define NRF_BOOTLOADER_APP_START_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdk_errors.h"
|
||||
|
||||
|
||||
/**@brief Function for using hardware to protect flash from writing and reading.
|
||||
*
|
||||
* @details This function applies write/erase protection to a specific area, using the BPROT or ACL
|
||||
* peripheral, depending on which is available.
|
||||
*
|
||||
* @param[in] address The start address of the area to protect. Must be a flash page
|
||||
* boundary.
|
||||
* @param[in] size The size of the area to protect, in bytes. Must be a multiple
|
||||
* of flash page size.
|
||||
*
|
||||
* @retval NRF_SUCCESS Flash protection applied successfully.
|
||||
* @retval NRF_ERROR_NO_MEM No more ACL instances to use for flash protection.
|
||||
* @retval NRF_ERROR_INVALID_PARAM Address was out of range or size was not a multiple
|
||||
* of flash page size.
|
||||
*/
|
||||
ret_code_t nrf_bootloader_flash_protect(uint32_t address, uint32_t size);
|
||||
|
||||
/**@brief Function for starting another application (and aborting the current one).
|
||||
*
|
||||
* @details This function uses the provided address to swap the stack pointer and then load
|
||||
* the address of the reset handler to be executed. It checks the current system mode
|
||||
* (thread/handler). If in thread mode, it resets into the other application.
|
||||
* If in handler mode, isr_abort is executed to ensure that handler mode is left correctly.
|
||||
* It then jumps into the reset handler of the other application.
|
||||
*
|
||||
* @note This function assumes the SoftDevice has not previously been initialized.
|
||||
*
|
||||
* @note This function will never return, but issues a reset into the provided application.
|
||||
*/
|
||||
void nrf_bootloader_app_start(void);
|
||||
|
||||
#endif // NRF_BOOTLOADER_APP_START_H__
|
||||
|
||||
/** @} */
|
||||
188
components/libraries/bootloader/nrf_bootloader_app_start_final.c
Normal file
188
components/libraries/bootloader/nrf_bootloader_app_start_final.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_config.h"
|
||||
#include "nrf_bootloader_app_start.h"
|
||||
#include <stdint.h>
|
||||
#include "nrf.h"
|
||||
#include "nrf_peripherals.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_dfu_utils.h"
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "nrf_log.h"
|
||||
#include "sdk_config.h"
|
||||
|
||||
|
||||
#define HANDLER_MODE_EXIT 0xFFFFFFF9 // When this is jumped to, the CPU will exit interrupt context
|
||||
// (handler mode), and pop values from the stack into registers.
|
||||
// See ARM's documentation for "Exception entry and return".
|
||||
#define EXCEPTION_STACK_WORD_COUNT 8 // The number of words popped from the stack when
|
||||
// HANDLER_MODE_EXIT is branched to.
|
||||
|
||||
|
||||
/**@brief Function that sets the stack pointer and starts executing a particular address.
|
||||
*
|
||||
* @param[in] new_msp The new value to set in the main stack pointer.
|
||||
* @param[in] addr The address to execute.
|
||||
*/
|
||||
void jump_to_addr(uint32_t new_msp, uint32_t addr)
|
||||
{
|
||||
__set_MSP(new_msp);
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for booting an app as if the chip was reset.
|
||||
*
|
||||
* @param[in] vector_table_addr The address of the app's vector table.
|
||||
*/
|
||||
__STATIC_INLINE void app_start(uint32_t vector_table_addr)
|
||||
{
|
||||
const uint32_t current_isr_num = (__get_IPSR() & IPSR_ISR_Msk);
|
||||
const uint32_t new_msp = *((uint32_t *)(vector_table_addr)); // The app's Stack Pointer is found as the first word of the vector table.
|
||||
const uint32_t reset_handler = *((uint32_t *)(vector_table_addr + sizeof(uint32_t))); // The app's Reset Handler is found as the second word of the vector table.
|
||||
|
||||
__set_CONTROL(0x00000000); // Set CONTROL to its reset value 0.
|
||||
__set_PRIMASK(0x00000000); // Set PRIMASK to its reset value 0.
|
||||
__set_BASEPRI(0x00000000); // Set BASEPRI to its reset value 0.
|
||||
__set_FAULTMASK(0x00000000); // Set FAULTMASK to its reset value 0.
|
||||
|
||||
ASSERT(current_isr_num == 0); // If this is triggered, the CPU is currently in an interrupt.
|
||||
|
||||
// The CPU is in Thread mode (main context).
|
||||
jump_to_addr(new_msp, reset_handler); // Jump directly to the App's Reset Handler.
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_bootloader_flash_protect(uint32_t address, uint32_t size)
|
||||
{
|
||||
if ((size & (CODE_PAGE_SIZE - 1)) || (address > BOOTLOADER_SETTINGS_ADDRESS))
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
#if defined(ACL_PRESENT)
|
||||
|
||||
// Protect using ACL.
|
||||
static uint32_t acl_instance = 0;
|
||||
|
||||
uint32_t const mask = (ACL_ACL_PERM_WRITE_Disable << ACL_ACL_PERM_WRITE_Pos);
|
||||
|
||||
if (acl_instance >= ACL_REGIONS_COUNT)
|
||||
{
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
NRF_ACL->ACL[acl_instance].ADDR = address;
|
||||
NRF_ACL->ACL[acl_instance].SIZE = size;
|
||||
NRF_ACL->ACL[acl_instance].PERM = mask;
|
||||
|
||||
acl_instance++;
|
||||
|
||||
#elif defined (BPROT_PRESENT)
|
||||
|
||||
// Protect using BPROT. BPROT does not support read protection.
|
||||
uint32_t pagenum_start = address / CODE_PAGE_SIZE;
|
||||
uint32_t pagenum_end = pagenum_start + ((size - 1) / CODE_PAGE_SIZE);
|
||||
|
||||
for (uint32_t i = pagenum_start; i <= pagenum_end; i++)
|
||||
{
|
||||
uint32_t config_index = i / 32;
|
||||
uint32_t mask = (1 << (i - config_index * 32));
|
||||
|
||||
switch (config_index)
|
||||
{
|
||||
case 0:
|
||||
NRF_BPROT->CONFIG0 = mask;
|
||||
break;
|
||||
case 1:
|
||||
NRF_BPROT->CONFIG1 = mask;
|
||||
break;
|
||||
#if BPROT_REGIONS_NUM > 64
|
||||
case 2:
|
||||
NRF_BPROT->CONFIG2 = mask;
|
||||
break;
|
||||
case 3:
|
||||
NRF_BPROT->CONFIG3 = mask;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void nrf_bootloader_app_start_final(uint32_t vector_table_addr)
|
||||
{
|
||||
ret_code_t ret_val;
|
||||
|
||||
// Size of the flash area to protect.
|
||||
uint32_t area_size;
|
||||
|
||||
area_size = BOOTLOADER_SIZE + NRF_MBR_PARAMS_PAGE_SIZE;
|
||||
if (!NRF_BL_DFU_ALLOW_UPDATE_FROM_APP && !NRF_BL_DFU_ENTER_METHOD_BUTTONLESS && !NRF_DFU_TRANSPORT_BLE)
|
||||
{
|
||||
area_size += BOOTLOADER_SETTINGS_PAGE_SIZE;
|
||||
}
|
||||
|
||||
ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, area_size);
|
||||
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not protect bootloader and settings pages, 0x%x.", ret_val);
|
||||
}
|
||||
APP_ERROR_CHECK(ret_val);
|
||||
|
||||
ret_val = nrf_bootloader_flash_protect(0,
|
||||
nrf_dfu_bank0_start_addr() + ALIGN_TO_PAGE(s_dfu_settings.bank_0.image_size));
|
||||
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not protect SoftDevice and application, 0x%x.", ret_val);
|
||||
}
|
||||
APP_ERROR_CHECK(ret_val);
|
||||
|
||||
// Run application
|
||||
app_start(vector_table_addr);
|
||||
}
|
||||
268
components/libraries/bootloader/nrf_bootloader_dfu_timers.c
Normal file
268
components/libraries/bootloader/nrf_bootloader_dfu_timers.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_bootloader_dfu_timers.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <nrfx.h>
|
||||
#include "nrf_clock.h"
|
||||
#include "nrf_rtc.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "nrf_log.h"
|
||||
|
||||
|
||||
#define RTC_PRESCALER (0) //!< The value provided to the RTC as the prescaler. 0 corresponds to one tick per clock cycle of the LFCLK (32768 ticks/s).
|
||||
#define RTC_WRAP_TICKS ((1 << 24) - 1) //!< The largest possible value in the RTC counter register.
|
||||
#define MAX_TIMEOUT_TICKS (RTC_WRAP_TICKS) //!< The longest fire timeout allowed. Longer timeouts are handled by multiple firings.
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nrf_bootloader_dfu_timeout_callback_t callback; //!< Callback that is called when this timer times out.
|
||||
uint32_t timeout; //!< The number of ticks from the next firing until the actual timeout. This value will be different from 0 if the original timeout was longer than MAX_TIMEOUT_TICKS, so multiple firings were needed.
|
||||
uint32_t repeated_timeout; //!< If different from 0, this timer will be reactivated with this value after timing out.
|
||||
uint8_t cc_channel; //!< Which CC register this timer uses.
|
||||
} dfu_timer_t;
|
||||
|
||||
|
||||
dfu_timer_t m_timers[2] = {{.cc_channel = 0}, {.cc_channel = 1}}; //!< The timers used by this module.
|
||||
dfu_timer_t * mp_inactivity = &m_timers[0]; //!< Direct pointer to the inactivity timer, for convenience and readability.
|
||||
dfu_timer_t * mp_wdt_feed = &m_timers[1]; //!< Direct pointer to the wdt feed timer, for convenience and readability.
|
||||
uint32_t m_counter_loops = 0; //!< The number of times the RTC counter register has overflowed (wrapped around) since the RTC was started.
|
||||
|
||||
#if RTC_COUNT > 2
|
||||
#define RTC_INSTANCE 2
|
||||
#define RTC_STRUCT NRF_RTC2
|
||||
#define RTC_IRQHandler RTC2_IRQHandler
|
||||
#define RTC_IRQn RTC2_IRQn
|
||||
#define RTC_CC_COUNT NRF_RTC_CC_CHANNEL_COUNT(2))
|
||||
#elif RTC_COUNT > 1
|
||||
#define RTC_INSTANCE 1
|
||||
#define RTC_STRUCT NRF_RTC1
|
||||
#define RTC_IRQHandler RTC1_IRQHandler
|
||||
#define RTC_IRQn RTC1_IRQn
|
||||
#define RTC_CC_COUNT NRF_RTC_CC_CHANNEL_COUNT(1))
|
||||
#else
|
||||
#error Not enough RTC instances.
|
||||
#endif
|
||||
|
||||
/**@brief Function for initializing the timer if it is not already initialized.
|
||||
*/
|
||||
static void timer_init(void)
|
||||
{
|
||||
static bool m_timer_initialized;
|
||||
|
||||
if (!m_timer_initialized)
|
||||
{
|
||||
if (!nrf_clock_lf_is_running())
|
||||
{
|
||||
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
|
||||
}
|
||||
|
||||
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_TICK);
|
||||
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_0);
|
||||
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_1);
|
||||
NRFX_IRQ_PRIORITY_SET(RTC_IRQn, 5);
|
||||
NRFX_IRQ_ENABLE(RTC_IRQn);
|
||||
nrf_rtc_prescaler_set(RTC_STRUCT, RTC_PRESCALER);
|
||||
nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_CLEAR);
|
||||
nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_START);
|
||||
nrf_rtc_int_enable(RTC_STRUCT, RTC_INTENSET_OVRFLW_Msk);
|
||||
|
||||
m_timer_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for scheduling an RTC compare event.
|
||||
*
|
||||
* @param[in] cc_channel Which of the RTC compare registers to use.
|
||||
* @param[in] cc_value The ticks value at which to receive the event.
|
||||
*/
|
||||
static void rtc_update(uint32_t cc_channel, uint32_t cc_value)
|
||||
{
|
||||
ASSERT(cc_channel < NRF_RTC_CC_CHANNEL_COUNT(RTC_INSTANCE));
|
||||
|
||||
nrf_rtc_cc_set(RTC_STRUCT, cc_channel, cc_value);
|
||||
nrf_delay_us(31);
|
||||
nrf_rtc_event_clear(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(cc_channel));
|
||||
nrf_rtc_int_enable(RTC_STRUCT, RTC_CHANNEL_INT_MASK(cc_channel));
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for activating a timer, so that it will be fired.
|
||||
*
|
||||
* This can happen multiple times before the actual timeout happens if the timeout is longer than
|
||||
* @ref MAX_TIMEOUT_TICKS.
|
||||
*
|
||||
* @param[in] p_timer The timer to activate.
|
||||
* @param[in] timeout_ticks The number of ticks until the timeout.
|
||||
*
|
||||
* @retval true If the timer was activated.
|
||||
* @retval false If the timer is already active.
|
||||
*/
|
||||
static void timer_activate(dfu_timer_t * p_timer, uint32_t timeout_ticks)
|
||||
{
|
||||
NRF_LOG_DEBUG("timer_activate (0x%x)", p_timer);
|
||||
|
||||
ASSERT(timeout_ticks <= MAX_TIMEOUT_TICKS);
|
||||
ASSERT(timeout_ticks >= NRF_BOOTLOADER_MIN_TIMEOUT_TICKS);
|
||||
uint32_t next_timeout_ticks = MIN(timeout_ticks, MAX_TIMEOUT_TICKS);
|
||||
uint32_t cc_value = RTC_WRAP(next_timeout_ticks + nrf_rtc_counter_get(RTC_STRUCT));
|
||||
p_timer->timeout = timeout_ticks - next_timeout_ticks;
|
||||
|
||||
if ((p_timer->timeout > 0) && (p_timer->timeout < NRF_BOOTLOADER_MIN_TIMEOUT_TICKS))
|
||||
{
|
||||
p_timer->timeout += NRF_BOOTLOADER_MIN_TIMEOUT_TICKS;
|
||||
cc_value -= NRF_BOOTLOADER_MIN_TIMEOUT_TICKS;
|
||||
}
|
||||
|
||||
rtc_update(p_timer->cc_channel, cc_value);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for deactivating a timer, so that it will not fire.
|
||||
*
|
||||
* @param[in] p_timer The timer to deactivate.
|
||||
*
|
||||
* @retval true If the timer was deactivated.
|
||||
* @retval false If the timer is already inactive.
|
||||
*/
|
||||
static void timer_stop(dfu_timer_t * p_timer)
|
||||
{
|
||||
NRF_LOG_DEBUG("timer_stop (0x%x)", p_timer);
|
||||
nrf_rtc_int_disable(RTC_STRUCT, RTC_CHANNEL_INT_MASK(p_timer->cc_channel));
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for firing a timer.
|
||||
*
|
||||
* This can happen multiple times before the actual timeout happens if the timeout is longer than
|
||||
* @ref MAX_TIMEOUT_TICKS.
|
||||
* This function reactivates the timer if the timer is repeating, or if the timer has not yet
|
||||
* timed out. It then calls the callback if the timer (repeating or not) has timed out.
|
||||
*
|
||||
* @param[in] p_timer The timer to fire.
|
||||
*/
|
||||
static void timer_fire(dfu_timer_t * p_timer)
|
||||
{
|
||||
NRF_LOG_DEBUG("timer_fire (0x%x)", p_timer);
|
||||
|
||||
if (p_timer->timeout != 0)
|
||||
{
|
||||
// The timer has not yet timed out.
|
||||
timer_activate(p_timer, p_timer->timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_timer->repeated_timeout != 0)
|
||||
{
|
||||
timer_activate(p_timer, p_timer->repeated_timeout);
|
||||
}
|
||||
|
||||
if (p_timer->callback != NULL)
|
||||
{
|
||||
p_timer->callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for requesting a timeout.
|
||||
*
|
||||
* The timer will time out @p timeout_ticks ticks from now. When it times out, @p callback
|
||||
* will be called, and if @p p_timer->repeated_timeout is not 0, a new timeout will be scheduled.
|
||||
*
|
||||
* @param[in] p_timer The timer to start.
|
||||
* @param[in] timeout_ticks The number of ticks until the timeout.
|
||||
* @param[in] callback The callback to call when the timer times out.
|
||||
*/
|
||||
static void timer_start(dfu_timer_t * p_timer,
|
||||
uint32_t timeout_ticks,
|
||||
nrf_bootloader_dfu_timeout_callback_t callback)
|
||||
{
|
||||
timer_init(); // Initialize if needed.
|
||||
p_timer->callback = callback;
|
||||
timer_activate(p_timer, timeout_ticks);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Interrupt handler for the RTC (Real Time Clock) used for the DFU timers.
|
||||
*/
|
||||
void RTC_IRQHandler(void)
|
||||
{
|
||||
if (nrf_rtc_event_pending(RTC_STRUCT, NRF_RTC_EVENT_OVERFLOW))
|
||||
{
|
||||
m_counter_loops++;
|
||||
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_OVERFLOW);
|
||||
}
|
||||
|
||||
for (uint32_t channel = 0; channel < 2; channel++)
|
||||
{
|
||||
if (nrf_rtc_event_pending(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(channel)))
|
||||
{
|
||||
nrf_rtc_event_clear(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(channel));
|
||||
timer_stop(&m_timers[channel]);
|
||||
timer_fire(&m_timers[channel]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nrf_bootloader_dfu_inactivity_timer_restart(uint32_t timeout_ticks,
|
||||
nrf_bootloader_dfu_timeout_callback_t callback)
|
||||
{
|
||||
timer_stop(mp_inactivity);
|
||||
if (timeout_ticks != 0)
|
||||
{
|
||||
timer_start(mp_inactivity, timeout_ticks, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nrf_bootloader_wdt_feed_timer_start(uint32_t timeout_ticks,
|
||||
nrf_bootloader_dfu_timeout_callback_t callback)
|
||||
{
|
||||
mp_wdt_feed->repeated_timeout = timeout_ticks;
|
||||
timer_start(mp_wdt_feed, timeout_ticks, callback);
|
||||
}
|
||||
|
||||
|
||||
uint32_t nrf_bootloader_dfu_timer_counter_get(void)
|
||||
{
|
||||
return nrf_rtc_counter_get(RTC_STRUCT) + (m_counter_loops << 24);
|
||||
}
|
||||
111
components/libraries/bootloader/nrf_bootloader_dfu_timers.h
Normal file
111
components/libraries/bootloader/nrf_bootloader_dfu_timers.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_bootloader_dfu_timers Timers for DFU in the bootloader
|
||||
* @{
|
||||
* @ingroup nrf_bootloader
|
||||
*/
|
||||
|
||||
#ifndef NRF_BOOTLOADER_DFU_TIMERS_H__
|
||||
#define NRF_BOOTLOADER_DFU_TIMERS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define NRF_BOOTLOADER_MIN_TIMEOUT_TICKS (150) //!< The shortest timeout allowed. To avoid the timeout not being activated before the time has passed.
|
||||
|
||||
/**@brief Macro for converting milliseconds to timer ticks.
|
||||
*
|
||||
* @param[in] ms The milliseconds to convert.
|
||||
*
|
||||
* @return @p ms converted to ticks.
|
||||
*/
|
||||
#define NRF_BOOTLOADER_MS_TO_TICKS(ms) ((((uint64_t)(ms) * 32768)) / 1000)
|
||||
|
||||
/**@brief Handler called on timeout of a timer requested by the watchdog.
|
||||
*/
|
||||
typedef void (*nrf_bootloader_dfu_timeout_callback_t)(void);
|
||||
|
||||
|
||||
/**@brief Function for restarting the inactivity timer.
|
||||
*
|
||||
* @note Calling this function cancels any previous calls to this function.
|
||||
*
|
||||
* @param[in] timeout_ticks The number of ticks until reset. There are 32768 ticks per second.
|
||||
* If 0 is passed, the timer will be stopped and not restarted.
|
||||
* @param[in] callback Function to be called on timeout.
|
||||
*/
|
||||
void nrf_bootloader_dfu_inactivity_timer_restart(uint32_t timeout_ticks,
|
||||
nrf_bootloader_dfu_timeout_callback_t callback);
|
||||
|
||||
|
||||
/**@brief Function for initializing and starting a repeated timer for feeding the watchdog.
|
||||
*
|
||||
* @param[in] timeout_ticks The number of ticks between each feeding of the watchdog. There are
|
||||
* 32768 ticks per second.
|
||||
* @param[in] callback Function called on every timeout.
|
||||
*/
|
||||
void nrf_bootloader_wdt_feed_timer_start(uint32_t timeout_ticks,
|
||||
nrf_bootloader_dfu_timeout_callback_t callback);
|
||||
|
||||
|
||||
/**@brief Function for retrieving the number of ticks since the RTC was started.
|
||||
*
|
||||
* There are 32768 ticks per second. This value does not wrap, even when the RTC counter wraps.
|
||||
*
|
||||
* @note The value can be 2^24 ticks too small if sampled immediately after the RTC counter wraps,
|
||||
* but before the internal loop counter has been incremented.
|
||||
*
|
||||
* @return The number of ticks since the RTC was started.
|
||||
*/
|
||||
uint32_t nrf_bootloader_dfu_timer_counter_get(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_BOOTLOADER_DFU_TIMERS_H__
|
||||
|
||||
/** @} */
|
||||
441
components/libraries/bootloader/nrf_bootloader_fw_activation.c
Normal file
441
components/libraries/bootloader/nrf_bootloader_fw_activation.c
Normal file
@@ -0,0 +1,441 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nrf_bootloader_fw_activation.h"
|
||||
#include "nrf_dfu_settings.h"
|
||||
#include "nrf_dfu_mbr.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "crc32.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_dfu_utils.h"
|
||||
#include "nrf_bootloader_wdt.h"
|
||||
|
||||
|
||||
static volatile bool m_flash_write_done;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function for copying image. Image is copied in chunks. Frequency of storing progress
|
||||
* in flash is configured by input parameter.
|
||||
*
|
||||
* @param[in] dst_addr Destination address. Must be page aligned.
|
||||
* @param[in] src_addr Source address. Must be higher value than dst_addr.
|
||||
* @param[in] size Image size.
|
||||
* @param[in] progress_update_step Number of copied pages that triggers saving progress to non-volatile memory.
|
||||
* Note that step can be decreased if there is a risk of corruption caused by source
|
||||
* and destination overlapping.
|
||||
*
|
||||
* @return NRF_SUCCESS or error code in case of failure.
|
||||
*/
|
||||
static uint32_t image_copy(uint32_t dst_addr,
|
||||
uint32_t src_addr,
|
||||
uint32_t size,
|
||||
uint32_t progress_update_step)
|
||||
{
|
||||
if (src_addr == dst_addr)
|
||||
{
|
||||
NRF_LOG_DEBUG("No copy needed");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ASSERT(src_addr >= dst_addr);
|
||||
ASSERT(progress_update_step > 0);
|
||||
if (size != 0)
|
||||
{
|
||||
ASSERT((dst_addr % CODE_PAGE_SIZE) == 0);
|
||||
}
|
||||
|
||||
uint32_t max_safe_progress_upd_step = (src_addr - dst_addr)/CODE_PAGE_SIZE;
|
||||
ASSERT(max_safe_progress_upd_step > 0);
|
||||
|
||||
uint32_t ret_val = NRF_SUCCESS;
|
||||
uint32_t pages_left = CEIL_DIV(size, CODE_PAGE_SIZE);
|
||||
|
||||
//Firmware copying is time consuming operation thus watchdog handling is started
|
||||
nrf_bootloader_wdt_init();
|
||||
|
||||
progress_update_step = MIN(progress_update_step, max_safe_progress_upd_step);
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
uint32_t pages;
|
||||
uint32_t bytes;
|
||||
if (pages_left <= progress_update_step)
|
||||
{
|
||||
pages = pages_left;
|
||||
bytes = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
pages = progress_update_step;
|
||||
bytes = progress_update_step * CODE_PAGE_SIZE;
|
||||
}
|
||||
// Erase the target pages
|
||||
ret_val = nrf_dfu_flash_erase(dst_addr, pages, NULL);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// Flash one page
|
||||
NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
|
||||
ret_val = nrf_dfu_flash_store(dst_addr,
|
||||
(uint32_t *)src_addr,
|
||||
ALIGN_NUM(sizeof(uint32_t), bytes),
|
||||
NULL);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
pages_left -= pages;
|
||||
size -= bytes;
|
||||
dst_addr += bytes;
|
||||
src_addr += bytes;
|
||||
s_dfu_settings.write_offset += bytes;
|
||||
|
||||
//store progress in flash on every successful chunk write
|
||||
ret_val = nrf_dfu_settings_write_and_backup(NULL);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed to write image copying progress to settings page.");
|
||||
return ret_val;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/** @brief Function to continue application update.
|
||||
*
|
||||
* @details This function will be called after reset if there is a valid application in Bank1
|
||||
* required to be copied down to Bank 0.
|
||||
*
|
||||
* @return NRF_SUCCESS if continuation was successful, NRF_ERROR_INTERNAL if new firmware does not
|
||||
* contain softdevice or other error coming from modules used by this function.
|
||||
*/
|
||||
static uint32_t app_activate(void)
|
||||
{
|
||||
// This function is only in use when new app is present in Bank 1
|
||||
uint32_t const image_size = s_dfu_settings.bank_1.image_size;
|
||||
|
||||
uint32_t src_addr = s_dfu_settings.progress.update_start_address;
|
||||
uint32_t ret_val = NRF_SUCCESS;
|
||||
uint32_t target_addr = nrf_dfu_bank0_start_addr() + s_dfu_settings.write_offset;
|
||||
uint32_t length_left = (image_size - s_dfu_settings.write_offset);
|
||||
uint32_t crc;
|
||||
|
||||
NRF_LOG_DEBUG("Enter nrf_dfu_app_continue");
|
||||
|
||||
src_addr += s_dfu_settings.write_offset;
|
||||
|
||||
if (src_addr == target_addr)
|
||||
{
|
||||
length_left = 0;
|
||||
}
|
||||
|
||||
ret_val = image_copy(target_addr, src_addr, length_left, NRF_BL_FW_COPY_PROGRESS_STORE_STEP);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed to copy firmware.");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// Check the CRC of the copied data. Enable if so.
|
||||
crc = crc32_compute((uint8_t*)nrf_dfu_bank0_start_addr(), image_size, NULL);
|
||||
|
||||
if (crc == s_dfu_settings.bank_1.image_crc)
|
||||
{
|
||||
NRF_LOG_DEBUG("Setting app as valid");
|
||||
s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_VALID_APP;
|
||||
s_dfu_settings.bank_0.image_crc = crc;
|
||||
s_dfu_settings.bank_0.image_size = image_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_ERROR("CRC computation failed for copied app: "
|
||||
"src crc: 0x%08x, res crc: 0x%08x",
|
||||
s_dfu_settings.bank_1.image_crc,
|
||||
crc);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Function to execute the continuation of a SoftDevice update.
|
||||
*
|
||||
* @return NRF_SUCCESS if continuation was successful, NRF_ERROR_INTERNAL if new firmware does not
|
||||
* contain softdevice or other error coming from modules used by this function.
|
||||
*/
|
||||
static uint32_t sd_activate(void)
|
||||
{
|
||||
uint32_t ret_val = NRF_SUCCESS;
|
||||
uint32_t target_addr = nrf_dfu_softdevice_start_address() + s_dfu_settings.write_offset;
|
||||
uint32_t src_addr = s_dfu_settings.progress.update_start_address;
|
||||
uint32_t sd_size = s_dfu_settings.sd_size;
|
||||
uint32_t length_left = ALIGN_TO_PAGE(sd_size - s_dfu_settings.write_offset);
|
||||
|
||||
NRF_LOG_DEBUG("Enter nrf_bootloader_dfu_sd_continue");
|
||||
|
||||
if (SD_MAGIC_NUMBER_GET(src_addr) != SD_MAGIC_NUMBER)
|
||||
{
|
||||
NRF_LOG_ERROR("Source address does not contain a valid SoftDevice.")
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
// This can be a continuation due to a power failure
|
||||
src_addr += s_dfu_settings.write_offset;
|
||||
|
||||
if (s_dfu_settings.write_offset == sd_size)
|
||||
{
|
||||
NRF_LOG_DEBUG("SD already copied");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
if (s_dfu_settings.write_offset == 0)
|
||||
{
|
||||
NRF_LOG_DEBUG("Updating SD. Old SD ver: %d, New ver: %d",
|
||||
SD_VERSION_GET(MBR_SIZE) / 1000000, SD_VERSION_GET(src_addr) / 1000000);
|
||||
}
|
||||
|
||||
ret_val = image_copy(target_addr, src_addr, length_left, NRF_BL_FW_COPY_PROGRESS_STORE_STEP);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed to copy firmware.");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
ret_val = nrf_dfu_settings_write_and_backup(NULL);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Function to continue bootloader update.
|
||||
*
|
||||
* @details This function will be called after reset if there is a valid bootloader in Bank 0 or Bank 1
|
||||
* required to be relocated and activated through MBR commands.
|
||||
*
|
||||
* @return This function will not return if the bootloader is copied successfully.
|
||||
* After the copy is verified, the device will reset and start the new bootloader.
|
||||
*
|
||||
* @retval NRF_SUCCESS Continuation was successful.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH Invalid length of flash operation.
|
||||
* @retval NRF_ERROR_NO_MEM If no parameter page is provided (see sds for more info).
|
||||
* @retval NRF_ERROR_INVALID_PARAM If an invalid command is given.
|
||||
* @retval NRF_ERROR_INTERNAL Internal error that should not happen.
|
||||
* @retval NRF_ERROR_FORBIDDEN If NRF_UICR->BOOTADDR is not set.
|
||||
*/
|
||||
static uint32_t bl_activate(void)
|
||||
{
|
||||
uint32_t ret_val = NRF_ERROR_INVALID_DATA;
|
||||
nrf_dfu_bank_t * p_bank = &s_dfu_settings.bank_1;
|
||||
uint32_t len = p_bank->image_size;
|
||||
uint32_t src_addr = s_dfu_settings.progress.update_start_address;
|
||||
|
||||
if (p_bank->bank_code == NRF_DFU_BANK_VALID_SD_BL)
|
||||
{
|
||||
src_addr += s_dfu_settings.sd_size;
|
||||
len -= s_dfu_settings.sd_size;
|
||||
}
|
||||
else if (src_addr == 0)
|
||||
{
|
||||
src_addr = nrf_dfu_bank1_start_addr();
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Verifying BL: Addr: 0x%08x, Src: 0x%08x, Len: 0x%08x", BOOTLOADER_START_ADDR, src_addr, len);
|
||||
|
||||
// This code is a configurable workaround for updating SD+BL from SDK 12.x.y - 14.1.0
|
||||
// SoftDevice size increase would lead to unaligned source address when comparing new BL in SD+BL updates.
|
||||
// This workaround is not required once BL is successfully installed with a version that is compiled SDK 14.1.0
|
||||
#if defined(NRF52832_XXAA) && defined(BLE_STACK_SUPPORT_REQD)
|
||||
if ((p_bank->bank_code == NRF_DFU_BANK_VALID_SD_BL) &&
|
||||
(memcmp((void *)BOOTLOADER_START_ADDR, (void *)(src_addr - 0x4000), len) == 0))
|
||||
{
|
||||
ret_val = NRF_SUCCESS;
|
||||
}
|
||||
#endif // defined(NRF52832_XXAA)
|
||||
|
||||
// Check if the BL has already been copied.
|
||||
if ((ret_val != NRF_SUCCESS) &&
|
||||
(memcmp((void *)BOOTLOADER_START_ADDR, (void *)src_addr, len) == 0))
|
||||
{
|
||||
ret_val = NRF_SUCCESS;
|
||||
}
|
||||
|
||||
// If the bootloader is the same as the banked version, the copy is finished
|
||||
if (ret_val == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_DEBUG("No bootloader copy needed, bootloader update complete.");
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("Copying bootloader: Src: 0x%08x, Len: 0x%08x", src_addr, len);
|
||||
NRF_LOG_FLUSH();
|
||||
|
||||
nrf_bootloader_wdt_feed();
|
||||
|
||||
// Bootloader is different than the banked version. Continue copy
|
||||
// Note that if the SD and BL was combined, then the split point between them is in s_dfu_settings.sd_size
|
||||
// On success this function won't return.
|
||||
ret_val = nrf_dfu_mbr_copy_bl((uint32_t*)src_addr, len);
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Request to copy BL failed");
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Function to continue combined bootloader and SoftDevice update.
|
||||
*
|
||||
* @details This function will be called after reset if there is a valid bootloader and SoftDevice in Bank 0 or Bank 1
|
||||
* required to be relocated and activated through MBR commands.
|
||||
*
|
||||
* @retval NRF_SUCCESS Continuation was successful.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH Invalid length.
|
||||
* @retval NRF_ERROR_NO_MEM If UICR.NRFFW[1] is not set (i.e. is 0xFFFFFFFF).
|
||||
* @retval NRF_ERROR_INVALID_PARAM If an invalid command is given.
|
||||
* @retval NRF_ERROR_INTERNAL Indicates that the contents of the memory blocks where not verified correctly after copying.
|
||||
* @retval NRF_ERROR_NULL If the content of the memory blocks differs after copying.
|
||||
* @retval NRF_ERROR_FORBIDDEN If NRF_UICR->BOOTADDR is not set.
|
||||
*/
|
||||
static uint32_t sd_bl_activate()
|
||||
{
|
||||
uint32_t ret_val = NRF_SUCCESS;
|
||||
|
||||
NRF_LOG_DEBUG("Enter nrf_dfu_sd_bl_continue");
|
||||
|
||||
ret_val = sd_activate();
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("SD+BL: SD copy failed");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
ret_val = bl_activate();
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("SD+BL: BL copy failed");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
static void flash_write_callback(void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
m_flash_write_done = true;
|
||||
}
|
||||
|
||||
|
||||
nrf_bootloader_fw_activation_result_t nrf_bootloader_fw_activate(void)
|
||||
{
|
||||
nrf_bootloader_fw_activation_result_t result;
|
||||
uint32_t ret_val = NRF_SUCCESS;
|
||||
nrf_dfu_bank_t * p_bank = &s_dfu_settings.bank_1;
|
||||
bool sd_update = false;
|
||||
|
||||
NRF_LOG_DEBUG("Enter nrf_bootloader_fw_activate");
|
||||
|
||||
switch (p_bank->bank_code)
|
||||
{
|
||||
case NRF_DFU_BANK_VALID_APP:
|
||||
NRF_LOG_DEBUG("Valid App");
|
||||
ret_val = app_activate();
|
||||
break;
|
||||
case NRF_DFU_BANK_VALID_SD:
|
||||
NRF_LOG_DEBUG("Valid SD");
|
||||
ret_val = sd_activate();
|
||||
sd_update = true;
|
||||
break;
|
||||
case NRF_DFU_BANK_VALID_BL:
|
||||
NRF_LOG_DEBUG("Valid BL");
|
||||
ret_val = bl_activate();
|
||||
break;
|
||||
case NRF_DFU_BANK_VALID_SD_BL:
|
||||
NRF_LOG_DEBUG("Valid SD + BL");
|
||||
ret_val = sd_bl_activate();
|
||||
sd_update = true;
|
||||
break;
|
||||
case NRF_DFU_BANK_INVALID:
|
||||
default:
|
||||
NRF_LOG_INFO("No firmware to activate.");
|
||||
return ACTIVATION_NONE;
|
||||
}
|
||||
|
||||
if (ret_val != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Activation failed with error %d (bank code: 0x%x)", ret_val, p_bank->bank_code);
|
||||
result = ACTIVATION_ERROR;
|
||||
}
|
||||
|
||||
// Invalidate bank, marking completion.
|
||||
nrf_dfu_bank_invalidate(p_bank);
|
||||
|
||||
m_flash_write_done = false;
|
||||
ret_val = nrf_dfu_settings_write_and_backup(flash_write_callback);
|
||||
ASSERT(m_flash_write_done); /* At this point flash module is performing blocking operation. It is expected that operation is already performed. */
|
||||
|
||||
if (ret_val == NRF_SUCCESS)
|
||||
{
|
||||
result = ACTIVATION_SUCCESS;
|
||||
if (sd_update && (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP))
|
||||
{
|
||||
//If SD was updated and application is valid we want to stay in DFU to receive application.
|
||||
NRF_LOG_DEBUG("A SoftDevice has just been activated. It's likely that an application will come immediately");
|
||||
result = ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_ERROR("Could not write settings.");
|
||||
result = ACTIVATION_ERROR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_bootloader_fw_activation Firmware activation
|
||||
* @{
|
||||
* @ingroup nrf_bootloader
|
||||
*/
|
||||
|
||||
#ifndef NRF_BOOTLOADER_FW_ACTIVATION_H__
|
||||
#define NRF_BOOTLOADER_FW_ACTIVATION_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ACTIVATION_NONE, //!< No new update was found.
|
||||
ACTIVATION_SUCCESS, //!< Update was successfully activated.
|
||||
ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE, //!< Update was successfully activated, but there might be additional update(s) to be transferred.
|
||||
ACTIVATION_ERROR, //!< Activation of an update failed.
|
||||
} nrf_bootloader_fw_activation_result_t;
|
||||
|
||||
/** @brief Function for activating a firmware received during DFU.
|
||||
*
|
||||
* @details This function initiates or continues the DFU copy-back
|
||||
* routines. These routines are fail-safe operations to activate
|
||||
* either a new SoftDevice, bootloader, combination of SoftDevice and
|
||||
* bootloader, or a new application.
|
||||
*
|
||||
* @details This function relies on accessing MBR commands through supervisor calls.
|
||||
* It does not rely on the SoftDevice for flash operations.
|
||||
*
|
||||
* @note When updating the bootloader or both bootloader and SoftDevice in combination,
|
||||
* this function does not return, but rather initiates a reboot to activate
|
||||
* the new bootloader.
|
||||
*
|
||||
* @retval ACTIVATION_NONE If no update was found.
|
||||
* @retval ACTIVATION_SUCCESS If the firmware update was successfully activated.
|
||||
* @retval ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE If the firmware update was successfully activated,
|
||||
* but there are likely more updates to be transferred.
|
||||
* @retval ACTIVATION_ERROR If the firmware update could not be activated.
|
||||
*/
|
||||
nrf_bootloader_fw_activation_result_t nrf_bootloader_fw_activate(void);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_BOOTLOADER_FW_ACTIVATION_H__
|
||||
|
||||
/** @} */
|
||||
91
components/libraries/bootloader/nrf_bootloader_info.c
Normal file
91
components/libraries/bootloader/nrf_bootloader_info.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_dfu_types.h"
|
||||
#include "nrf_nvmc.h"
|
||||
|
||||
#define UICR_BOOTLOADER_ADDR 0x10001014
|
||||
|
||||
/** @brief This variable ensures that the linker script will write the bootloader start address
|
||||
* to the UICR register. This value will be written in the HEX file and thus written to
|
||||
* UICR when the bootloader is flashed into the chip.
|
||||
*/
|
||||
#if defined (__CC_ARM )
|
||||
#pragma push
|
||||
#pragma diag_suppress 1296
|
||||
uint32_t m_uicr_bootloader_start_address __attribute__((at(UICR_BOOTLOADER_ADDR)))
|
||||
= BOOTLOADER_START_ADDR;
|
||||
#pragma pop
|
||||
#elif defined ( __GNUC__ ) || defined ( __SES_ARM )
|
||||
volatile uint32_t m_uicr_bootloader_start_address __attribute__ ((section(".uicr_bootloader_start_address")))
|
||||
= BOOTLOADER_START_ADDR;
|
||||
#elif defined ( __ICCARM__ )
|
||||
__root const uint32_t m_uicr_bootloader_start_address @ UICR_BOOTLOADER_ADDR
|
||||
= BOOTLOADER_START_ADDR;
|
||||
#endif
|
||||
|
||||
void nrf_bootloader_mbr_addrs_populate(void)
|
||||
{
|
||||
if (*(const uint32_t *)MBR_BOOTLOADER_ADDR == 0xFFFFFFFF)
|
||||
{
|
||||
nrf_nvmc_write_word(MBR_BOOTLOADER_ADDR, BOOTLOADER_START_ADDR);
|
||||
}
|
||||
if (*(const uint32_t *)MBR_PARAM_PAGE_ADDR == 0xFFFFFFFF)
|
||||
{
|
||||
nrf_nvmc_write_word(MBR_PARAM_PAGE_ADDR, NRF_MBR_PARAMS_PAGE_ADDRESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nrf_bootloader_debug_port_disable(void)
|
||||
{
|
||||
if (NRF_UICR->APPROTECT != 0x0)
|
||||
{
|
||||
nrf_nvmc_write_word((uint32_t)&NRF_UICR->APPROTECT, 0x0);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#if (!defined (NRF52810_XXAA) && !defined (NRF52811_XXAA) && !defined (NRF52832_XXAA) && !defined (NRF52832_XXAB))
|
||||
if (NRF_UICR->DEBUGCTRL != 0x0)
|
||||
{
|
||||
nrf_nvmc_write_word((uint32_t)&NRF_UICR->DEBUGCTRL, 0x0);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
210
components/libraries/bootloader/nrf_bootloader_info.h
Normal file
210
components/libraries/bootloader/nrf_bootloader_info.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_bootloader_info Bootloader Information
|
||||
* @{
|
||||
* @ingroup nrf_bootloader
|
||||
*/
|
||||
|
||||
#ifndef NRF_BOOTLOADER_INFO_H__
|
||||
#define NRF_BOOTLOADER_INFO_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "app_util.h"
|
||||
#include "nrf.h"
|
||||
#include "nrf_mbr.h"
|
||||
|
||||
/** @brief Macro for getting the start address of the bootloader image.
|
||||
*
|
||||
* The macro is not a compile time symbol. It cannot be used as a
|
||||
* constant expression, for example, inside a static assert or linker script
|
||||
* at-placement.
|
||||
*/
|
||||
#ifndef BOOTLOADER_START_ADDR
|
||||
#if (__LINT__ == 1)
|
||||
#define BOOTLOADER_START_ADDR (0x3AC00)
|
||||
#elif defined(CODE_START)
|
||||
#define BOOTLOADER_START_ADDR (CODE_START)
|
||||
#else
|
||||
#error Not a valid compiler/linker for BOOTLOADER_START_ADDR.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/** @brief Macro for getting the size of the bootloader image.
|
||||
*/
|
||||
#ifndef BOOTLOADER_SIZE
|
||||
#if (__LINT__ == 1)
|
||||
#define BOOTLOADER_SIZE (0x6000)
|
||||
#elif defined ( NRF51 )
|
||||
#define BOOTLOADER_SIZE (BOOTLOADER_SETTINGS_ADDRESS - BOOTLOADER_START_ADDR)
|
||||
#elif defined( NRF52_SERIES )
|
||||
#define BOOTLOADER_SIZE (NRF_MBR_PARAMS_PAGE_ADDRESS - BOOTLOADER_START_ADDR)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The following macros are for accessing the SoftDevice information structure,
|
||||
// which is found inside the SoftDevice binary.
|
||||
|
||||
/** @brief Macro for converting an offset inside the SoftDevice information struct to an absolute address.
|
||||
*/
|
||||
#define SD_INFO_ABS_OFFSET_GET(baseaddr, offset) ((baseaddr) + (SOFTDEVICE_INFO_STRUCT_OFFSET) + (offset))
|
||||
|
||||
/** @brief Macros for reading a byte or a word at a particular offset inside a SoftDevice information struct.
|
||||
* Use MBR_SIZE as baseaddr when the SoftDevice is installed just above the MBR (the usual case).
|
||||
*/
|
||||
#define SD_OFFSET_GET_UINT32(baseaddr, offset) (*((uint32_t *) SD_INFO_ABS_OFFSET_GET(baseaddr, offset)))
|
||||
#define SD_OFFSET_GET_UINT16(baseaddr, offset) (*((uint16_t *) SD_INFO_ABS_OFFSET_GET(baseaddr, offset)))
|
||||
#define SD_OFFSET_GET_UINT8(baseaddr, offset) (*((uint8_t *) SD_INFO_ABS_OFFSET_GET(baseaddr, offset)))
|
||||
|
||||
|
||||
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
|
||||
#include "nrf_sdm.h"
|
||||
#else
|
||||
/** @brief The offset inside the SoftDevice at which the information struct is placed.
|
||||
* To see the layout of the information struct, see the SoftDevice specification.
|
||||
*/
|
||||
#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000)
|
||||
|
||||
#define SD_INFO_STRUCT_SIZE(baseaddr) SD_OFFSET_GET_UINT8(baseaddr, 0x00)
|
||||
|
||||
/** @brief Macro for reading the size of a SoftDevice at a given base address.
|
||||
*/
|
||||
#ifndef SD_SIZE_GET
|
||||
#define SD_SIZE_GET(baseaddr) SD_OFFSET_GET_UINT32(baseaddr, 0x08)
|
||||
#endif
|
||||
|
||||
/** @brief Macro for reading the version of a SoftDevice at a given base address.
|
||||
* This expression checks the length of the information struct to see if the version is present.
|
||||
* The version number is constructed like this:
|
||||
* major_version * 1000000 + minor_version * 1000 + bugfix_version
|
||||
*/
|
||||
#ifndef SD_VERSION_GET
|
||||
#define SD_VERSION_GET(baseaddr) ((SD_INFO_STRUCT_SIZE(baseaddr) > (0x14)) \
|
||||
? SD_OFFSET_GET_UINT32(baseaddr, 0x14) \
|
||||
: 0)
|
||||
#endif
|
||||
|
||||
/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use
|
||||
* @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the
|
||||
* usual case). */
|
||||
#ifndef SD_ID_GET
|
||||
#define SD_ID_GET(baseaddr) ((SD_INFO_STRUCT_SIZE(baseaddr) > 0x10) \
|
||||
? SD_OFFSET_GET_UINT32(baseaddr, 0x10) : 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/** @brief Macro for reading the magic number of a SoftDevice at a given base address.
|
||||
*/
|
||||
#ifndef SD_MAGIC_NUMBER_GET
|
||||
#define SD_MAGIC_NUMBER_GET(baseaddr) SD_OFFSET_GET_UINT32(baseaddr, 0x04)
|
||||
#endif
|
||||
|
||||
/** @brief Macro for getting the absolute address of the magic number.
|
||||
*/
|
||||
#define SD_MAGIC_NUMBER_ABS_OFFSET_GET(baseaddr) SD_INFO_ABS_OFFSET_GET(baseaddr, 0x04)
|
||||
|
||||
/** @brief The number present at a specific location in all SoftDevices.
|
||||
*/
|
||||
#define SD_MAGIC_NUMBER ((uint32_t)0x51B1E5DB)
|
||||
|
||||
/** @brief Whether a SoftDevice is at its regular location.
|
||||
*/
|
||||
#ifndef SD_PRESENT
|
||||
#define SD_PRESENT ((SD_MAGIC_NUMBER_GET(MBR_SIZE)) == (SD_MAGIC_NUMBER))
|
||||
#endif
|
||||
|
||||
/** @brief The multiplier for the major version of the SoftDevice. See \ref SD_VERSION_GET
|
||||
*/
|
||||
#define SD_MAJOR_VERSION_MULTIPLIER (1000000)
|
||||
|
||||
/** @brief Read the major version of the SoftDevice from the raw version number. See \ref SD_VERSION_GET.
|
||||
*/
|
||||
#define SD_MAJOR_VERSION_EXTRACT(raw_version) ((raw_version)/SD_MAJOR_VERSION_MULTIPLIER)
|
||||
|
||||
|
||||
#define BOOTLOADER_DFU_GPREGRET_MASK (0xF8) /**< Mask for GPGPREGRET bits used for the magic pattern written to GPREGRET register to signal between main app and DFU. */
|
||||
#define BOOTLOADER_DFU_GPREGRET (0xB0) /**< Magic pattern written to GPREGRET register to signal between main app and DFU. The 3 lower bits are assumed to be used for signalling purposes.*/
|
||||
#define BOOTLOADER_DFU_START_BIT_MASK (0x01) /**< Bit mask to signal from main application to enter DFU mode using a buttonless service. */
|
||||
|
||||
#define BOOTLOADER_DFU_GPREGRET2_MASK (0xF8) /**< Mask for GPGPREGRET2 bits used for the magic pattern written to GPREGRET2 register to signal between main app and DFU. */
|
||||
#define BOOTLOADER_DFU_GPREGRET2 (0xA8) /**< Magic pattern written to GPREGRET2 register to signal between main app and DFU. The 3 lower bits are assumed to be used for signalling purposes.*/
|
||||
#define BOOTLOADER_DFU_SKIP_CRC_BIT_MASK (0x01) /**< Bit mask to signal from main application that CRC-check is not needed for image verification. */
|
||||
|
||||
|
||||
#define BOOTLOADER_DFU_START (BOOTLOADER_DFU_GPREGRET | BOOTLOADER_DFU_START_BIT_MASK) /**< Magic number to signal that bootloader should enter DFU mode because of signal from Buttonless DFU in main app.*/
|
||||
#define BOOTLOADER_DFU_SKIP_CRC (BOOTLOADER_DFU_GPREGRET2 | BOOTLOADER_DFU_SKIP_CRC_BIT_MASK) /**< Magic number to signal that CRC can be skipped due to low power modes.*/
|
||||
|
||||
|
||||
/** @brief Macro based on @c NRF_DFU_DEBUG_VERSION that can be checked for true/false instead of defined/not defined.
|
||||
*/
|
||||
#ifndef NRF_DFU_DEBUG
|
||||
#ifdef NRF_DFU_DEBUG_VERSION
|
||||
#define NRF_DFU_DEBUG 1
|
||||
#else
|
||||
#define NRF_DFU_DEBUG 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** @brief Function for populating addresses in the MBR code page.
|
||||
*
|
||||
* This function writes two words to flash if the flash is 0xFFFFFFFF. This is done in code because
|
||||
* doing this through the hex file interferes with flashing algorithms. See nrf_mbr.h.
|
||||
*/
|
||||
void nrf_bootloader_mbr_addrs_populate(void);
|
||||
|
||||
/** @brief Function for checking if the debug port access is disabled.
|
||||
*
|
||||
* If the debug port access is enabled, disable it. This function checks and writes to the UICR
|
||||
* registers APPROTECT and DEBUGCTRL.
|
||||
*/
|
||||
void nrf_bootloader_debug_port_disable(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef NRF_BOOTLOADER_INFO_H__
|
||||
/** @} */
|
||||
121
components/libraries/bootloader/nrf_bootloader_wdt.c
Normal file
121
components/libraries/bootloader/nrf_bootloader_wdt.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_bootloader_wdt.h"
|
||||
#include "nrf_wdt.h"
|
||||
#include "nrf_bootloader_dfu_timers.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_bootloader_wdt
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
|
||||
static void wdt_feed(void)
|
||||
{
|
||||
if (nrf_wdt_started())
|
||||
{
|
||||
for (nrf_wdt_rr_register_t i = NRF_WDT_RR0; i < NRF_WDT_RR7; i++)
|
||||
{
|
||||
if (nrf_wdt_reload_request_is_enabled(i))
|
||||
{
|
||||
nrf_wdt_reload_request_set(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void wdt_feed_timer_handler(void)
|
||||
{
|
||||
NRF_LOG_INFO("Internal feed");
|
||||
wdt_feed();
|
||||
}
|
||||
|
||||
|
||||
void WDT_IRQHandler(void)
|
||||
{
|
||||
nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT);
|
||||
NRF_LOG_FINAL_FLUSH();
|
||||
}
|
||||
|
||||
#define MAX_FLASH_OP_TIME_TICKS 3200 // ~100 ms
|
||||
|
||||
void nrf_bootloader_wdt_init(void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (nrf_wdt_started())
|
||||
{
|
||||
uint32_t wdt_ticks = nrf_wdt_reload_value_get();
|
||||
|
||||
NRF_LOG_INFO("WDT enabled CRV:%d ticks", wdt_ticks);
|
||||
|
||||
//wdt_ticks must be reduced to feed the watchdog before the timeout.
|
||||
uint32_t reduced_timeout_ticks = MAX((int32_t)wdt_ticks - MAX_FLASH_OP_TIME_TICKS,
|
||||
NRF_BOOTLOADER_MIN_TIMEOUT_TICKS);
|
||||
|
||||
/* initial watchdog feed */
|
||||
wdt_feed();
|
||||
|
||||
NRF_LOG_INFO("Starting a timer (%d ticks) for feeding watchdog.", reduced_timeout_ticks);
|
||||
nrf_bootloader_wdt_feed_timer_start(reduced_timeout_ticks, wdt_feed_timer_handler);
|
||||
|
||||
NVIC_EnableIRQ(WDT_IRQn);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_INFO("WDT is not enabled");
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void nrf_bootloader_wdt_feed(void)
|
||||
{
|
||||
if (nrf_wdt_started())
|
||||
{
|
||||
wdt_feed();
|
||||
}
|
||||
}
|
||||
79
components/libraries/bootloader/nrf_bootloader_wdt.h
Normal file
79
components/libraries/bootloader/nrf_bootloader_wdt.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_BOOTLOADER_WDT_H
|
||||
#define NRF_BOOTLOADER_WDT_H
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_bootloader_wdt Automated feeding of the watchdog
|
||||
* @{
|
||||
* @ingroup nrf_bootloader
|
||||
* @brief Module that keeps the WDT from timing out if the WDT has been started in the application.
|
||||
*/
|
||||
|
||||
#include "sdk_errors.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**
|
||||
* @brief Function for checking whether the WDT peripheral is started and for getting its configuration.
|
||||
*
|
||||
* The module uses a timer to start regular feeding of the watchdog. Timer interval
|
||||
* is chosen based on watchdog settings. When @ref nrf_bootloader_wdt_feed is called, internal
|
||||
* feeding is stopped assuming that the application takes responsibity of watchdog feeding.
|
||||
* However, if @ref NRF_BL_WDT_MAX_SCHEDULER_LATENCY_MS or the watchdog is configured to
|
||||
* run during sleep, then internal feeding (from timeout handler context) is kept active.
|
||||
*/
|
||||
void nrf_bootloader_wdt_init(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function for feeding the watchdog (if active).
|
||||
*/
|
||||
void nrf_bootloader_wdt_feed(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif //NRF_BOOTLOADER_WDT_H
|
||||
273
components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c
Normal file
273
components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nrf_dfu_serial.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
#include "nrf_dfu_handling_error.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_serial
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t))
|
||||
|
||||
#if defined(NRF_DFU_PROTOCOL_REDUCED) && NRF_DFU_PROTOCOL_REDUCED
|
||||
#error Serial DFU (UART and USB) cannot function with the reduced protocol set.
|
||||
#endif
|
||||
|
||||
static uint32_t response_ext_err_payload_add(uint8_t * p_buffer, uint32_t buf_offset)
|
||||
{
|
||||
p_buffer[buf_offset] = ext_error_get();
|
||||
(void) ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void response_send(nrf_dfu_serial_t * p_transport,
|
||||
nrf_dfu_response_t const * p_response)
|
||||
{
|
||||
uint8_t index = 0;
|
||||
uint8_t * p_serialized_rsp = p_transport->p_rsp_buf;
|
||||
|
||||
NRF_LOG_DEBUG("Sending Response: [0x%01x, 0x%01x]", p_response->request, p_response->result);
|
||||
|
||||
p_serialized_rsp[index++] = NRF_DFU_OP_RESPONSE;
|
||||
p_serialized_rsp[index++] = p_response->request;
|
||||
p_serialized_rsp[index++] = (uint8_t)(p_response->result);
|
||||
|
||||
if (p_response->result == NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
switch (p_response->request)
|
||||
{
|
||||
case NRF_DFU_OP_PROTOCOL_VERSION:
|
||||
{
|
||||
p_serialized_rsp[index] = p_response->protocol.version;
|
||||
index += sizeof(uint8_t);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_HARDWARE_VERSION:
|
||||
{
|
||||
index += uint32_encode(p_response->hardware.part, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->hardware.variant, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->hardware.memory.rom_size, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->hardware.memory.ram_size, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->hardware.memory.rom_page_size, &p_serialized_rsp[index]);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_FIRMWARE_VERSION:
|
||||
{
|
||||
p_serialized_rsp[index++] = p_response->firmware.type;
|
||||
index += uint32_encode(p_response->firmware.version, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->firmware.addr, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->firmware.len, &p_serialized_rsp[index]);
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_CRC_GET:
|
||||
index += uint32_encode(p_response->crc.offset, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->crc.crc, &p_serialized_rsp[index]);
|
||||
break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
index += uint32_encode(p_response->select.max_size, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->select.offset, &p_serialized_rsp[index]);
|
||||
index += uint32_encode(p_response->select.crc, &p_serialized_rsp[index]);
|
||||
break;
|
||||
|
||||
case NRF_DFU_OP_MTU_GET:
|
||||
index += uint16_encode(p_response->mtu.size, &p_serialized_rsp[index]);
|
||||
break;
|
||||
|
||||
case NRF_DFU_OP_PING:
|
||||
p_serialized_rsp[index] = p_response->ping.id;
|
||||
index += sizeof(uint8_t);
|
||||
break;
|
||||
|
||||
default:
|
||||
// no implementation
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (p_response->result == NRF_DFU_RES_CODE_EXT_ERROR)
|
||||
{
|
||||
index += response_ext_err_payload_add(p_serialized_rsp, index);
|
||||
}
|
||||
|
||||
if (index > NRF_SERIAL_MAX_RESPONSE_SIZE)
|
||||
{
|
||||
NRF_LOG_ERROR("Message is larger than expected.");
|
||||
}
|
||||
|
||||
// Send response.
|
||||
if (p_transport->rsp_func((uint8_t const *)(p_serialized_rsp), index) != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed to send data over serial interface!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dfu_req_handler_rsp_clbk(nrf_dfu_response_t * p_res, void * p_context)
|
||||
{
|
||||
nrf_dfu_serial_t * p_transport = (nrf_dfu_serial_t *)(p_context);
|
||||
|
||||
if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
|
||||
{
|
||||
NRF_LOG_WARNING("DFU request completed with result: 0x%x", p_res->result);
|
||||
}
|
||||
|
||||
switch (p_res->request)
|
||||
{
|
||||
default:
|
||||
/* Reply normally.
|
||||
* Make sure to reply to NRF_DFU_OP_OBJECT_CREATE when running DFU over serial,
|
||||
* otherwise the transfer might run very slow, without an apparent reason.
|
||||
*/
|
||||
break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_WRITE:
|
||||
{
|
||||
p_transport->pkt_notif_target_count--;
|
||||
|
||||
if ( (p_transport->pkt_notif_target == 0)
|
||||
|| (p_transport->pkt_notif_target_count != 0))
|
||||
{
|
||||
/* Do not reply to _OBJECT_WRITE messages. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reply with a CRC message and reset the packet counter. */
|
||||
p_transport->pkt_notif_target_count = p_transport->pkt_notif_target;
|
||||
|
||||
p_res->request = NRF_DFU_OP_CRC_GET;
|
||||
p_res->crc.offset = p_res->write.offset;
|
||||
p_res->crc.crc = p_res->write.crc;
|
||||
} break;
|
||||
}
|
||||
|
||||
response_send(p_transport, p_res);
|
||||
}
|
||||
|
||||
|
||||
void nrf_dfu_serial_on_packet_received(nrf_dfu_serial_t * p_transport,
|
||||
uint8_t const * p_data,
|
||||
uint32_t length)
|
||||
{
|
||||
uint8_t const * p_payload = &p_data[NRF_SERIAL_OPCODE_SIZE];
|
||||
uint16_t const payload_len = (length - NRF_SERIAL_OPCODE_SIZE);
|
||||
|
||||
nrf_dfu_request_t request =
|
||||
{
|
||||
.request = (nrf_dfu_op_t)(p_data[0]),
|
||||
.callback.response = dfu_req_handler_rsp_clbk,
|
||||
.p_context = p_transport
|
||||
};
|
||||
|
||||
bool buf_free = true;
|
||||
|
||||
switch (request.request)
|
||||
{
|
||||
case NRF_DFU_OP_FIRMWARE_VERSION:
|
||||
{
|
||||
request.firmware.image_number = p_payload[0];
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_RECEIPT_NOTIF_SET:
|
||||
{
|
||||
NRF_LOG_DEBUG("Set receipt notif target: %d", p_transport->pkt_notif_target);
|
||||
|
||||
p_transport->pkt_notif_target = uint16_decode(&p_payload[0]);
|
||||
p_transport->pkt_notif_target_count = p_transport->pkt_notif_target;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_SELECT:
|
||||
{
|
||||
request.select.object_type = p_payload[0];
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_CREATE:
|
||||
{
|
||||
// Reset the packet receipt notification on create object
|
||||
p_transport->pkt_notif_target_count = p_transport->pkt_notif_target;
|
||||
|
||||
request.create.object_type = p_payload[0];
|
||||
request.create.object_size = uint32_decode(&p_payload[1]);
|
||||
|
||||
if (request.create.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
|
||||
{
|
||||
/* Activity on the current transport. Close all except the current one. */
|
||||
(void) nrf_dfu_transports_close(p_transport->p_low_level_transport);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_OBJECT_WRITE:
|
||||
{
|
||||
// Buffer will be freed asynchronously
|
||||
buf_free = false;
|
||||
|
||||
request.write.p_data = p_payload;
|
||||
request.write.len = payload_len;
|
||||
request.callback.write = p_transport->payload_free_func;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_MTU_GET:
|
||||
{
|
||||
NRF_LOG_DEBUG("Received serial mtu");
|
||||
request.mtu.size = p_transport->mtu;
|
||||
} break;
|
||||
|
||||
case NRF_DFU_OP_PING:
|
||||
{
|
||||
NRF_LOG_DEBUG("Received ping %d", p_payload[0]);
|
||||
request.ping.id = p_payload[0];
|
||||
} break;
|
||||
|
||||
default:
|
||||
/* Do nothing. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf_free)
|
||||
{
|
||||
p_transport->payload_free_func((void *)(p_payload));
|
||||
}
|
||||
|
||||
ret_code_t ret_code = nrf_dfu_req_handler_on_req(&request);
|
||||
ASSERT(ret_code == NRF_SUCCESS);
|
||||
}
|
||||
111
components/libraries/bootloader/serial_dfu/nrf_dfu_serial.h
Normal file
111
components/libraries/bootloader/serial_dfu/nrf_dfu_serial.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_DFU_SERIAL_H__
|
||||
#define NRF_DFU_SERIAL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
#include "nrf_dfu_transport.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_serial DFU Serial transports shared part
|
||||
* @{
|
||||
* @ingroup nrf_dfu
|
||||
* @brief Shared part of Device Firmware Update (DFU) transport layers using serial interface (UART, USB CDC ACM).
|
||||
*
|
||||
* @defgroup nrf_dfu_serial_uart DFU Serial UART transport
|
||||
* @ingroup nrf_dfu_serial
|
||||
* @brief Configuration for Device Firmware Update (DFU) transport layer using UART.
|
||||
*
|
||||
* @defgroup nrf_dfu_serial_usb DFU Serial USB CDC ACM transport
|
||||
* @ingroup nrf_dfu_serial
|
||||
* @brief Configuration for Device Firmware Update (DFU) transport layer using USB CDC ACM.
|
||||
*
|
||||
*/
|
||||
|
||||
#define NRF_SERIAL_MAX_RESPONSE_SIZE (sizeof(nrf_dfu_response_t))
|
||||
|
||||
/**
|
||||
* Prototype for function for sending response over serial DFU transport.
|
||||
*/
|
||||
typedef ret_code_t (*nrf_serial_rsp_func_t)(uint8_t const * p_data, uint32_t length);
|
||||
|
||||
/**
|
||||
* Prototype for function for freeing RX buffer.
|
||||
*
|
||||
* Function is called when input data is processed.
|
||||
*/
|
||||
typedef void (*nrf_serial_rx_buf_free_func_t)(void * p_buf);
|
||||
|
||||
|
||||
/**@brief DFU serial transport layer state.
|
||||
*
|
||||
* @details This structure contains status information related to the serial transport layer type.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t pkt_notif_target;
|
||||
uint16_t pkt_notif_target_count;
|
||||
nrf_serial_rsp_func_t rsp_func;
|
||||
nrf_serial_rx_buf_free_func_t payload_free_func;
|
||||
uint32_t mtu;
|
||||
uint8_t * p_rsp_buf;
|
||||
nrf_dfu_transport_t const * p_low_level_transport;
|
||||
} nrf_dfu_serial_t;
|
||||
|
||||
void nrf_dfu_serial_on_packet_received(nrf_dfu_serial_t * p_transport,
|
||||
uint8_t const * p_data,
|
||||
uint32_t length);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NRF_DFU_SERIAL_H__
|
||||
238
components/libraries/bootloader/serial_dfu/nrf_dfu_serial_uart.c
Normal file
238
components/libraries/bootloader/serial_dfu/nrf_dfu_serial_uart.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nrf_dfu_serial.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "boards.h"
|
||||
#include "app_util_platform.h"
|
||||
#include "nrf_dfu_transport.h"
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
#include "slip.h"
|
||||
#include "nrf_balloc.h"
|
||||
#include "nrf_drv_uart.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_serial_uart
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_serial_uart DFU Serial UART transport
|
||||
* @ingroup nrf_dfu
|
||||
* @brief Device Firmware Update (DFU) transport layer using UART.
|
||||
*/
|
||||
|
||||
#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t))
|
||||
#define NRF_UART_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1)
|
||||
#define RX_BUF_SIZE (64) //to get 64bytes payload
|
||||
#define OPCODE_OFFSET (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE)
|
||||
#define DATA_OFFSET (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE)
|
||||
#define UART_SLIP_MTU (2 * (RX_BUF_SIZE + 1) + 1)
|
||||
#define BALLOC_BUF_SIZE ((CEIL_DIV((RX_BUF_SIZE+OPCODE_SIZE),sizeof(uint32_t))*sizeof(uint32_t)))
|
||||
|
||||
NRF_BALLOC_DEF(m_payload_pool, (UART_SLIP_MTU + 1), NRF_DFU_SERIAL_UART_RX_BUFFERS);
|
||||
|
||||
static nrf_drv_uart_t m_uart = NRF_DRV_UART_INSTANCE(0);
|
||||
static uint8_t m_rx_byte;
|
||||
|
||||
static nrf_dfu_serial_t m_serial;
|
||||
static slip_t m_slip;
|
||||
static uint8_t m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP];
|
||||
static bool m_active;
|
||||
|
||||
static nrf_dfu_observer_t m_observer;
|
||||
|
||||
static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer);
|
||||
static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
|
||||
|
||||
DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const uart_dfu_transport) =
|
||||
{
|
||||
.init_func = uart_dfu_transport_init,
|
||||
.close_func = uart_dfu_transport_close,
|
||||
};
|
||||
|
||||
static void payload_free(void * p_buf)
|
||||
{
|
||||
uint8_t * p_buf_root = (uint8_t *)p_buf - DATA_OFFSET; //pointer is shifted to point to data
|
||||
nrf_balloc_free(&m_payload_pool, p_buf_root);
|
||||
}
|
||||
|
||||
static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length)
|
||||
{
|
||||
uint32_t slip_len;
|
||||
(void) slip_encode(m_rsp_buf, (uint8_t *)p_data, length, &slip_len);
|
||||
|
||||
return nrf_drv_uart_tx(&m_uart, m_rsp_buf, slip_len);
|
||||
}
|
||||
|
||||
static __INLINE void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len)
|
||||
{
|
||||
ret_code_t ret_code = NRF_ERROR_TIMEOUT;
|
||||
|
||||
// Check if there is byte to process. Zero length transfer means that RXTO occured.
|
||||
if (len)
|
||||
{
|
||||
ret_code = slip_decode_add_byte(&m_slip, p_data[0]);
|
||||
}
|
||||
|
||||
(void) nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
|
||||
|
||||
if (ret_code == NRF_SUCCESS)
|
||||
{
|
||||
nrf_dfu_serial_on_packet_received(p_transport,
|
||||
(uint8_t const *)m_slip.p_buffer,
|
||||
m_slip.current_index);
|
||||
|
||||
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
|
||||
if (p_rx_buf == NULL)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed to allocate buffer");
|
||||
return;
|
||||
}
|
||||
NRF_LOG_INFO("Allocated buffer %x", p_rx_buf);
|
||||
// reset the slip decoding
|
||||
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
|
||||
m_slip.current_index = 0;
|
||||
m_slip.state = SLIP_STATE_DECODING;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context)
|
||||
{
|
||||
switch (p_event->type)
|
||||
{
|
||||
case NRF_DRV_UART_EVT_RX_DONE:
|
||||
on_rx_complete((nrf_dfu_serial_t*)p_context,
|
||||
p_event->data.rxtx.p_data,
|
||||
p_event->data.rxtx.bytes);
|
||||
break;
|
||||
|
||||
case NRF_DRV_UART_EVT_ERROR:
|
||||
APP_ERROR_HANDLER(p_event->data.error.error_mask);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No action.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
if (m_active)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("serial_dfu_transport_init()");
|
||||
|
||||
m_observer = observer;
|
||||
|
||||
err_code = nrf_balloc_init(&m_payload_pool);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
|
||||
|
||||
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
|
||||
m_slip.current_index = 0;
|
||||
m_slip.buffer_len = UART_SLIP_MTU;
|
||||
m_slip.state = SLIP_STATE_DECODING;
|
||||
|
||||
m_serial.rsp_func = rsp_send;
|
||||
m_serial.payload_free_func = payload_free;
|
||||
m_serial.mtu = UART_SLIP_MTU;
|
||||
m_serial.p_rsp_buf = &m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP -
|
||||
NRF_SERIAL_MAX_RESPONSE_SIZE];
|
||||
m_serial.p_low_level_transport = &uart_dfu_transport;
|
||||
|
||||
nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
|
||||
|
||||
uart_config.pseltxd = TX_PIN_NUMBER;
|
||||
uart_config.pselrxd = RX_PIN_NUMBER;
|
||||
uart_config.pselcts = CTS_PIN_NUMBER;
|
||||
uart_config.pselrts = RTS_PIN_NUMBER;
|
||||
uart_config.hwfc = NRF_DFU_SERIAL_UART_USES_HWFC ?
|
||||
NRF_UART_HWFC_ENABLED : NRF_UART_HWFC_DISABLED;
|
||||
uart_config.p_context = &m_serial;
|
||||
|
||||
err_code = nrf_drv_uart_init(&m_uart, &uart_config, uart_event_handler);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed initializing uart");
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed initializing rx");
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("serial_dfu_transport_init() completed");
|
||||
|
||||
m_active = true;
|
||||
|
||||
if (m_observer)
|
||||
{
|
||||
m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception)
|
||||
{
|
||||
if ((m_active == true) && (p_exception != &uart_dfu_transport))
|
||||
{
|
||||
nrf_drv_uart_uninit(&m_uart);
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
368
components/libraries/bootloader/serial_dfu/nrf_dfu_serial_usb.c
Normal file
368
components/libraries/bootloader/serial_dfu/nrf_dfu_serial_usb.c
Normal file
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "nrf_dfu_req_handler.h"
|
||||
#include "nrf_dfu_transport.h"
|
||||
#include "slip.h"
|
||||
#include "nrf_balloc.h"
|
||||
#include "nrf_drv_power.h"
|
||||
#include "nrf_drv_clock.h"
|
||||
#include "nrf_drv_usbd.h"
|
||||
#include "nrf_dfu_serial.h"
|
||||
#include "app_scheduler.h"
|
||||
#include "app_usbd.h"
|
||||
#include "app_usbd_cdc_acm.h"
|
||||
#include "app_usbd_core.h"
|
||||
#include "app_usbd_string_desc.h"
|
||||
#include "app_util_platform.h"
|
||||
#include "app_usbd_serial_num.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME nrf_dfu_serial_usb
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_dfu_serial_usb DFU Serial USB CDC ACM transport
|
||||
* @ingroup nrf_dfu
|
||||
* @brief Device Firmware Update (DFU) transport layer using USB CDC ACM.
|
||||
*/
|
||||
|
||||
#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t))
|
||||
|
||||
#define NRF_USB_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1)
|
||||
|
||||
#define RX_BUF_SIZE (1024)
|
||||
#define SLIP_MTU (2 * (RX_BUF_SIZE + 1) + 1)
|
||||
#define OPCODE_OFFSET (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE)
|
||||
#define DATA_OFFSET (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE)
|
||||
|
||||
#define CDC_ACM_COMM_INTERFACE 0
|
||||
#define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN2
|
||||
#define CDC_ACM_DATA_INTERFACE 1
|
||||
#define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN1
|
||||
#define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1
|
||||
|
||||
/**
|
||||
* @brief Enable power USB detection
|
||||
*
|
||||
* Configure if example supports USB port connection
|
||||
*/
|
||||
#ifndef USBD_POWER_DETECTION
|
||||
#define USBD_POWER_DETECTION true
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Interfaces list passed to @ref APP_USBD_CDC_ACM_GLOBAL_DEF
|
||||
* */
|
||||
#define CDC_ACM_INTERFACES_CONFIG() \
|
||||
APP_USBD_CDC_ACM_CONFIG(CDC_ACM_COMM_INTERFACE, \
|
||||
CDC_ACM_COMM_EPIN, \
|
||||
CDC_ACM_DATA_INTERFACE, \
|
||||
CDC_ACM_DATA_EPIN, \
|
||||
CDC_ACM_DATA_EPOUT)
|
||||
|
||||
/*lint -save -e26 -e64 -e505 -e651 */
|
||||
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
|
||||
app_usbd_cdc_acm_user_event_t event);
|
||||
|
||||
/**@brief CDC_ACM class instance. */
|
||||
APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
|
||||
cdc_acm_user_ev_handler,
|
||||
CDC_ACM_COMM_INTERFACE,
|
||||
CDC_ACM_DATA_INTERFACE,
|
||||
CDC_ACM_COMM_EPIN,
|
||||
CDC_ACM_DATA_EPIN,
|
||||
CDC_ACM_DATA_EPOUT,
|
||||
APP_USBD_CDC_COMM_PROTOCOL_NONE);
|
||||
/*lint -restore */
|
||||
|
||||
NRF_BALLOC_DEF(m_payload_pool, (SLIP_MTU+1), NRF_DFU_SERIAL_USB_RX_BUFFERS);
|
||||
|
||||
static nrf_dfu_serial_t m_serial;
|
||||
static slip_t m_slip;
|
||||
static uint8_t m_rsp_buf[NRF_USB_MAX_RESPONSE_SIZE_SLIP];
|
||||
static uint8_t m_rx_buf[NRF_DRV_USBD_EPSIZE];
|
||||
|
||||
static nrf_dfu_observer_t m_observer;
|
||||
|
||||
static uint32_t usb_dfu_transport_init(nrf_dfu_observer_t observer);
|
||||
static uint32_t usb_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
|
||||
|
||||
|
||||
DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const usb_dfu_transport) =
|
||||
{
|
||||
.init_func = usb_dfu_transport_init,
|
||||
.close_func = usb_dfu_transport_close,
|
||||
};
|
||||
|
||||
|
||||
static void payload_free(void * p_buf)
|
||||
{
|
||||
uint8_t * p_buf_root = ((uint8_t *)(p_buf)) - DATA_OFFSET; //pointer is shifted to point to data
|
||||
nrf_balloc_free(&m_payload_pool, p_buf_root);
|
||||
}
|
||||
|
||||
|
||||
static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length)
|
||||
{
|
||||
ASSERT(p_data);
|
||||
ASSERT(length != 0);
|
||||
|
||||
uint32_t slip_len;
|
||||
|
||||
// Cannot fail if inputs are non-NULL.
|
||||
(void) slip_encode(m_rsp_buf, (uint8_t *)(p_data), length, &slip_len);
|
||||
|
||||
return app_usbd_cdc_acm_write(&m_app_cdc_acm, m_rsp_buf, slip_len);
|
||||
}
|
||||
|
||||
|
||||
static void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len)
|
||||
{
|
||||
ret_code_t ret_code;
|
||||
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
ret_code = slip_decode_add_byte(&m_slip, p_data[i]);
|
||||
if (ret_code != NRF_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
nrf_dfu_serial_on_packet_received(p_transport,
|
||||
(uint8_t const *)(m_slip.p_buffer),
|
||||
m_slip.current_index);
|
||||
|
||||
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
|
||||
if (p_rx_buf == NULL)
|
||||
{
|
||||
NRF_LOG_ERROR("Failed to allocate buffer!");
|
||||
return;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("Allocated buffer %x", p_rx_buf);
|
||||
// reset the slip decoding
|
||||
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
|
||||
m_slip.current_index = 0;
|
||||
m_slip.state = SLIP_STATE_DECODING;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t (headphones)
|
||||
* */
|
||||
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
|
||||
app_usbd_cdc_acm_user_event_t event)
|
||||
{
|
||||
ret_code_t ret_code;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
|
||||
{
|
||||
ret_code = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buf, 1);
|
||||
NRF_LOG_WARNING("Could not read from CDC. Error: 0x%x.", ret_code);
|
||||
} break;
|
||||
|
||||
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
|
||||
{
|
||||
do
|
||||
{
|
||||
on_rx_complete(&m_serial, m_rx_buf, 1);
|
||||
ret_code = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buf, 1);
|
||||
} while (ret_code == NRF_SUCCESS);
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void usbd_dfu_transport_ev_handler(app_usbd_event_type_t event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case APP_USBD_EVT_STOPPED:
|
||||
app_usbd_disable();
|
||||
break;
|
||||
|
||||
case APP_USBD_EVT_POWER_DETECTED:
|
||||
NRF_LOG_INFO("USB power detected");
|
||||
if (!nrf_drv_usbd_is_enabled())
|
||||
{
|
||||
app_usbd_enable();
|
||||
}
|
||||
|
||||
if (m_observer)
|
||||
{
|
||||
m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_USBD_EVT_POWER_REMOVED:
|
||||
NRF_LOG_INFO("USB power removed");
|
||||
app_usbd_stop();
|
||||
if (m_observer)
|
||||
{
|
||||
m_observer(NRF_DFU_EVT_TRANSPORT_DEACTIVATED);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_USBD_EVT_POWER_READY:
|
||||
NRF_LOG_INFO("USB ready");
|
||||
app_usbd_start();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void usbd_sched_event_handler(void * p_event_data, uint16_t event_size)
|
||||
{
|
||||
app_usbd_event_execute(p_event_data);
|
||||
}
|
||||
|
||||
|
||||
static void usbd_event_handler(app_usbd_internal_evt_t const * const p_event)
|
||||
{
|
||||
ret_code_t ret_code;
|
||||
if (p_event->type == APP_USBD_EVT_DRV_SOF)
|
||||
{
|
||||
app_usbd_event_execute(p_event);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code = app_sched_event_put(p_event,
|
||||
sizeof(app_usbd_internal_evt_t),
|
||||
usbd_sched_event_handler);
|
||||
|
||||
if (ret_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not schedule USB event!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint32_t usb_dfu_transport_init(nrf_dfu_observer_t observer)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
/* Execute event directly in interrupt handler */
|
||||
static const app_usbd_config_t usbd_config =
|
||||
{
|
||||
.ev_handler = usbd_event_handler,
|
||||
.ev_state_proc = usbd_dfu_transport_ev_handler
|
||||
};
|
||||
|
||||
(void) nrf_balloc_init(&m_payload_pool); //Result is checked by checking result of _alloc().
|
||||
|
||||
m_observer = observer;
|
||||
|
||||
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
|
||||
if (p_rx_buf == NULL)
|
||||
{
|
||||
NRF_LOG_ERROR("Could not allocate payload pool.");
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
|
||||
m_slip.current_index = 0;
|
||||
m_slip.buffer_len = SLIP_MTU;
|
||||
m_slip.state = SLIP_STATE_DECODING;
|
||||
|
||||
m_serial.rsp_func = rsp_send;
|
||||
m_serial.payload_free_func = payload_free;
|
||||
m_serial.mtu = SLIP_MTU;
|
||||
m_serial.p_rsp_buf = &m_rsp_buf[NRF_USB_MAX_RESPONSE_SIZE_SLIP -
|
||||
NRF_SERIAL_MAX_RESPONSE_SIZE];
|
||||
m_serial.p_low_level_transport = &usb_dfu_transport;
|
||||
|
||||
|
||||
NRF_LOG_DEBUG("Initializing drivers.");
|
||||
|
||||
err_code = nrf_drv_clock_init();
|
||||
if (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED)
|
||||
{
|
||||
VERIFY_SUCCESS(err_code);
|
||||
}
|
||||
|
||||
err_code = nrf_drv_power_init(NULL);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
app_usbd_serial_num_generate();
|
||||
|
||||
err_code = app_usbd_init(&usbd_config);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
|
||||
err_code = app_usbd_class_append(class_cdc_acm);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
NRF_LOG_DEBUG("Starting USB");
|
||||
|
||||
if (USBD_POWER_DETECTION)
|
||||
{
|
||||
err_code = app_usbd_power_events_enable();
|
||||
VERIFY_SUCCESS(err_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("No USB power detection enabled, starting USB now");
|
||||
|
||||
app_usbd_enable();
|
||||
app_usbd_start();
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("USB Transport initialized");
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t usb_dfu_transport_close(nrf_dfu_transport_t const * p_exception)
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
638
components/libraries/bsp/bsp.c
Normal file
638
components/libraries/bsp/bsp.c
Normal file
@@ -0,0 +1,638 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "bsp.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "nordic_common.h"
|
||||
#include "nrf.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_error.h"
|
||||
#include "bsp_config.h"
|
||||
#include "boards.h"
|
||||
|
||||
#ifndef BSP_SIMPLE
|
||||
#include "app_timer.h"
|
||||
#include "app_button.h"
|
||||
#endif // BSP_SIMPLE
|
||||
|
||||
#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
static bsp_indication_t m_stable_state = BSP_INDICATE_IDLE;
|
||||
static bool m_leds_clear = false;
|
||||
static uint32_t m_indication_type = 0;
|
||||
static bool m_alert_on = false;
|
||||
APP_TIMER_DEF(m_bsp_leds_tmr);
|
||||
APP_TIMER_DEF(m_bsp_alert_tmr);
|
||||
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
|
||||
#if BUTTONS_NUMBER > 0
|
||||
#ifndef BSP_SIMPLE
|
||||
static bsp_event_callback_t m_registered_callback = NULL;
|
||||
static bsp_button_event_cfg_t m_events_list[BUTTONS_NUMBER] = {{BSP_EVENT_NOTHING, BSP_EVENT_NOTHING}};
|
||||
APP_TIMER_DEF(m_bsp_button_tmr);
|
||||
static void bsp_button_event_handler(uint8_t pin_no, uint8_t button_action);
|
||||
#endif // BSP_SIMPLE
|
||||
|
||||
#ifndef BSP_SIMPLE
|
||||
static const app_button_cfg_t app_buttons[BUTTONS_NUMBER] =
|
||||
{
|
||||
#ifdef BSP_BUTTON_0
|
||||
{BSP_BUTTON_0, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_0
|
||||
|
||||
#ifdef BSP_BUTTON_1
|
||||
{BSP_BUTTON_1, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_1
|
||||
|
||||
#ifdef BSP_BUTTON_2
|
||||
{BSP_BUTTON_2, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_2
|
||||
|
||||
#ifdef BSP_BUTTON_3
|
||||
{BSP_BUTTON_3, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_3
|
||||
|
||||
#ifdef BSP_BUTTON_4
|
||||
{BSP_BUTTON_4, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_4
|
||||
|
||||
#ifdef BSP_BUTTON_5
|
||||
{BSP_BUTTON_5, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_5
|
||||
|
||||
#ifdef BSP_BUTTON_6
|
||||
{BSP_BUTTON_6, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_6
|
||||
|
||||
#ifdef BSP_BUTTON_7
|
||||
{BSP_BUTTON_7, false, BUTTON_PULL, bsp_button_event_handler},
|
||||
#endif // BUTTON_7
|
||||
|
||||
};
|
||||
#endif // BSP_SIMPLE
|
||||
#endif // BUTTONS_NUMBER > 0
|
||||
|
||||
#if (BUTTONS_NUMBER > 0)
|
||||
bool bsp_button_is_pressed(uint32_t button)
|
||||
{
|
||||
if (button < BUTTONS_NUMBER)
|
||||
{
|
||||
return bsp_board_button_state_get(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If button is not present always return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)
|
||||
/**@brief Function for handling button events.
|
||||
*
|
||||
* @param[in] pin_no The pin number of the button pressed.
|
||||
* @param[in] button_action Action button.
|
||||
*/
|
||||
static void bsp_button_event_handler(uint8_t pin_no, uint8_t button_action)
|
||||
{
|
||||
bsp_event_t event = BSP_EVENT_NOTHING;
|
||||
uint32_t button = 0;
|
||||
uint32_t err_code;
|
||||
static uint8_t current_long_push_pin_no; /**< Pin number of a currently pushed button, that could become a long push if held long enough. */
|
||||
static bsp_event_t release_event_at_push[BUTTONS_NUMBER]; /**< Array of what the release event of each button was last time it was pushed, so that no release event is sent if the event was bound after the push of the button. */
|
||||
|
||||
button = bsp_board_pin_to_button_idx(pin_no);
|
||||
|
||||
if (button < BUTTONS_NUMBER)
|
||||
{
|
||||
switch (button_action)
|
||||
{
|
||||
case APP_BUTTON_PUSH:
|
||||
event = m_events_list[button].push_event;
|
||||
if (m_events_list[button].long_push_event != BSP_EVENT_NOTHING)
|
||||
{
|
||||
err_code = app_timer_start(m_bsp_button_tmr, APP_TIMER_TICKS(BSP_LONG_PUSH_TIMEOUT_MS), (void*)¤t_long_push_pin_no);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
current_long_push_pin_no = pin_no;
|
||||
}
|
||||
}
|
||||
release_event_at_push[button] = m_events_list[button].release_event;
|
||||
break;
|
||||
case APP_BUTTON_RELEASE:
|
||||
(void)app_timer_stop(m_bsp_button_tmr);
|
||||
if (release_event_at_push[button] == m_events_list[button].release_event)
|
||||
{
|
||||
event = m_events_list[button].release_event;
|
||||
}
|
||||
break;
|
||||
case BSP_BUTTON_ACTION_LONG_PUSH:
|
||||
event = m_events_list[button].long_push_event;
|
||||
}
|
||||
}
|
||||
|
||||
if ((event != BSP_EVENT_NOTHING) && (m_registered_callback != NULL))
|
||||
{
|
||||
m_registered_callback(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Handle events from button timer.
|
||||
*
|
||||
* @param[in] p_context parameter registered in timer start function.
|
||||
*/
|
||||
static void button_timer_handler(void * p_context)
|
||||
{
|
||||
bsp_button_event_handler(*(uint8_t *)p_context, BSP_BUTTON_ACTION_LONG_PUSH);
|
||||
}
|
||||
|
||||
|
||||
#endif // (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)
|
||||
|
||||
|
||||
#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
static void leds_off(void)
|
||||
{
|
||||
if (m_alert_on)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < LEDS_NUMBER; i++)
|
||||
{
|
||||
if (i != BSP_LED_ALERT)
|
||||
{
|
||||
bsp_board_led_off(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bsp_board_leds_off();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Configure leds to indicate required state.
|
||||
* @param[in] indicate State to be indicated.
|
||||
*/
|
||||
static uint32_t bsp_led_indication(bsp_indication_t indicate)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
uint32_t next_delay = 0;
|
||||
|
||||
if (m_leds_clear)
|
||||
{
|
||||
m_leds_clear = false;
|
||||
leds_off();
|
||||
}
|
||||
|
||||
switch (indicate)
|
||||
{
|
||||
case BSP_INDICATE_IDLE:
|
||||
leds_off();
|
||||
err_code = app_timer_stop(m_bsp_leds_tmr);
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_SCANNING:
|
||||
case BSP_INDICATE_ADVERTISING:
|
||||
// in advertising blink LED_0
|
||||
if (bsp_board_led_state_get(BSP_LED_INDICATE_INDICATE_ADVERTISING))
|
||||
{
|
||||
bsp_board_led_off(BSP_LED_INDICATE_INDICATE_ADVERTISING);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING ? ADVERTISING_LED_OFF_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_OFF_INTERVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
bsp_board_led_on(BSP_LED_INDICATE_INDICATE_ADVERTISING);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING ? ADVERTISING_LED_ON_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_ON_INTERVAL;
|
||||
}
|
||||
|
||||
m_stable_state = indicate;
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_ADVERTISING_WHITELIST:
|
||||
// in advertising quickly blink LED_0
|
||||
if (bsp_board_led_state_get(BSP_LED_INDICATE_ADVERTISING_WHITELIST))
|
||||
{
|
||||
bsp_board_led_off(BSP_LED_INDICATE_ADVERTISING_WHITELIST);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING_WHITELIST ?
|
||||
ADVERTISING_WHITELIST_LED_OFF_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_OFF_INTERVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
bsp_board_led_on(BSP_LED_INDICATE_ADVERTISING_WHITELIST);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING_WHITELIST ?
|
||||
ADVERTISING_WHITELIST_LED_ON_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_ON_INTERVAL;
|
||||
}
|
||||
m_stable_state = indicate;
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_ADVERTISING_SLOW:
|
||||
// in advertising slowly blink LED_0
|
||||
if (bsp_board_led_state_get(BSP_LED_INDICATE_ADVERTISING_SLOW))
|
||||
{
|
||||
bsp_board_led_off(BSP_LED_INDICATE_ADVERTISING_SLOW);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING_SLOW ? ADVERTISING_SLOW_LED_OFF_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_OFF_INTERVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
bsp_board_led_on(BSP_LED_INDICATE_ADVERTISING_SLOW);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING_SLOW ? ADVERTISING_SLOW_LED_ON_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_ON_INTERVAL;
|
||||
}
|
||||
m_stable_state = indicate;
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_ADVERTISING_DIRECTED:
|
||||
// in advertising very quickly blink LED_0
|
||||
if (bsp_board_led_state_get(BSP_LED_INDICATE_ADVERTISING_DIRECTED))
|
||||
{
|
||||
bsp_board_led_off(BSP_LED_INDICATE_ADVERTISING_DIRECTED);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING_DIRECTED ?
|
||||
ADVERTISING_DIRECTED_LED_OFF_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_OFF_INTERVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
bsp_board_led_on(BSP_LED_INDICATE_ADVERTISING_DIRECTED);
|
||||
next_delay = indicate ==
|
||||
BSP_INDICATE_ADVERTISING_DIRECTED ?
|
||||
ADVERTISING_DIRECTED_LED_ON_INTERVAL :
|
||||
ADVERTISING_SLOW_LED_ON_INTERVAL;
|
||||
}
|
||||
m_stable_state = indicate;
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_BONDING:
|
||||
// in bonding fast blink LED_0
|
||||
bsp_board_led_invert(BSP_LED_INDICATE_BONDING);
|
||||
|
||||
m_stable_state = indicate;
|
||||
err_code =
|
||||
app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(BONDING_INTERVAL), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_CONNECTED:
|
||||
bsp_board_led_on(BSP_LED_INDICATE_CONNECTED);
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_SENT_OK:
|
||||
// when sending shortly invert LED_1
|
||||
m_leds_clear = true;
|
||||
bsp_board_led_invert(BSP_LED_INDICATE_SENT_OK);
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(SENT_OK_INTERVAL), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_SEND_ERROR:
|
||||
// on receving error invert LED_1 for long time
|
||||
m_leds_clear = true;
|
||||
bsp_board_led_invert(BSP_LED_INDICATE_SEND_ERROR);
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(SEND_ERROR_INTERVAL), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_RCV_OK:
|
||||
// when receving shortly invert LED_1
|
||||
m_leds_clear = true;
|
||||
bsp_board_led_invert(BSP_LED_INDICATE_RCV_OK);
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(RCV_OK_INTERVAL), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_RCV_ERROR:
|
||||
// on receving error invert LED_1 for long time
|
||||
m_leds_clear = true;
|
||||
bsp_board_led_invert(BSP_LED_INDICATE_RCV_ERROR);
|
||||
err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(RCV_ERROR_INTERVAL), NULL);
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_FATAL_ERROR:
|
||||
// on fatal error turn on all leds
|
||||
bsp_board_leds_on();
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_ALERT_0:
|
||||
case BSP_INDICATE_ALERT_1:
|
||||
case BSP_INDICATE_ALERT_2:
|
||||
case BSP_INDICATE_ALERT_3:
|
||||
case BSP_INDICATE_ALERT_OFF:
|
||||
err_code = app_timer_stop(m_bsp_alert_tmr);
|
||||
next_delay = (uint32_t)BSP_INDICATE_ALERT_OFF - (uint32_t)indicate;
|
||||
|
||||
// a little trick to find out that if it did not fall through ALERT_OFF
|
||||
if (next_delay && (err_code == NRF_SUCCESS))
|
||||
{
|
||||
if (next_delay > 1)
|
||||
{
|
||||
err_code = app_timer_start(m_bsp_alert_tmr,
|
||||
APP_TIMER_TICKS(((uint16_t)next_delay * ALERT_INTERVAL)),
|
||||
NULL);
|
||||
}
|
||||
bsp_board_led_on(BSP_LED_ALERT);
|
||||
m_alert_on = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bsp_board_led_off(BSP_LED_ALERT);
|
||||
m_alert_on = false;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_USER_STATE_OFF:
|
||||
leds_off();
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_USER_STATE_0:
|
||||
leds_off();
|
||||
bsp_board_led_on(BSP_LED_INDICATE_USER_LED1);
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_USER_STATE_1:
|
||||
leds_off();
|
||||
bsp_board_led_on(BSP_LED_INDICATE_USER_LED2);
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_USER_STATE_2:
|
||||
leds_off();
|
||||
bsp_board_led_on(BSP_LED_INDICATE_USER_LED1);
|
||||
bsp_board_led_on(BSP_LED_INDICATE_USER_LED2);
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
case BSP_INDICATE_USER_STATE_3:
|
||||
|
||||
case BSP_INDICATE_USER_STATE_ON:
|
||||
bsp_board_leds_on();
|
||||
m_stable_state = indicate;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Handle events from leds timer.
|
||||
*
|
||||
* @note Timer handler does not support returning an error code.
|
||||
* Errors from bsp_led_indication() are not propagated.
|
||||
*
|
||||
* @param[in] p_context parameter registered in timer start function.
|
||||
*/
|
||||
static void leds_timer_handler(void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
if (m_indication_type & BSP_INIT_LEDS)
|
||||
{
|
||||
UNUSED_VARIABLE(bsp_led_indication(m_stable_state));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Handle events from alert timer.
|
||||
*
|
||||
* @param[in] p_context parameter registered in timer start function.
|
||||
*/
|
||||
static void alert_timer_handler(void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
bsp_board_led_invert(BSP_LED_ALERT);
|
||||
}
|
||||
#endif // #if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
|
||||
|
||||
/**@brief Configure indicators to required state.
|
||||
*/
|
||||
uint32_t bsp_indication_set(bsp_indication_t indicate)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
|
||||
if (m_indication_type & BSP_INIT_LEDS)
|
||||
{
|
||||
err_code = bsp_led_indication(indicate);
|
||||
}
|
||||
|
||||
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
uint32_t bsp_init(uint32_t type, bsp_event_callback_t callback)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
m_indication_type = type;
|
||||
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
|
||||
#if (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)
|
||||
m_registered_callback = callback;
|
||||
|
||||
// BSP will support buttons and generate events
|
||||
if (type & BSP_INIT_BUTTONS)
|
||||
{
|
||||
uint32_t num;
|
||||
|
||||
for (num = 0; ((num < BUTTONS_NUMBER) && (err_code == NRF_SUCCESS)); num++)
|
||||
{
|
||||
err_code = bsp_event_to_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT);
|
||||
}
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code = app_button_init((app_button_cfg_t *)app_buttons,
|
||||
BUTTONS_NUMBER,
|
||||
APP_TIMER_TICKS(50));
|
||||
}
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code = app_button_enable();
|
||||
}
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code = app_timer_create(&m_bsp_button_tmr,
|
||||
APP_TIMER_MODE_SINGLE_SHOT,
|
||||
button_timer_handler);
|
||||
}
|
||||
}
|
||||
#elif (BUTTONS_NUMBER > 0) && (defined BSP_SIMPLE)
|
||||
bsp_board_init(type);
|
||||
#endif // (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)
|
||||
|
||||
#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
if (type & BSP_INIT_LEDS)
|
||||
{
|
||||
//handle LEDs only. Buttons are already handled.
|
||||
bsp_board_init(BSP_INIT_LEDS);
|
||||
|
||||
// timers module must be already initialized!
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code =
|
||||
app_timer_create(&m_bsp_leds_tmr, APP_TIMER_MODE_SINGLE_SHOT, leds_timer_handler);
|
||||
}
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code =
|
||||
app_timer_create(&m_bsp_alert_tmr, APP_TIMER_MODE_REPEATED, alert_timer_handler);
|
||||
}
|
||||
}
|
||||
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
#ifndef BSP_SIMPLE
|
||||
/**@brief Assign specific event to button.
|
||||
*/
|
||||
uint32_t bsp_event_to_button_action_assign(uint32_t button, bsp_button_action_t action, bsp_event_t event)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
#if BUTTONS_NUMBER > 0
|
||||
if (button < BUTTONS_NUMBER)
|
||||
{
|
||||
if (event == BSP_EVENT_DEFAULT)
|
||||
{
|
||||
// Setting default action: BSP_EVENT_KEY_x for PUSH actions, BSP_EVENT_NOTHING for RELEASE and LONG_PUSH actions.
|
||||
event = (action == BSP_BUTTON_ACTION_PUSH) ? (bsp_event_t)(BSP_EVENT_KEY_0 + button) : BSP_EVENT_NOTHING;
|
||||
}
|
||||
switch (action)
|
||||
{
|
||||
case BSP_BUTTON_ACTION_PUSH:
|
||||
m_events_list[button].push_event = event;
|
||||
break;
|
||||
case BSP_BUTTON_ACTION_LONG_PUSH:
|
||||
m_events_list[button].long_push_event = event;
|
||||
break;
|
||||
case BSP_BUTTON_ACTION_RELEASE:
|
||||
m_events_list[button].release_event = event;
|
||||
break;
|
||||
default:
|
||||
err_code = NRF_ERROR_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
#else
|
||||
err_code = NRF_ERROR_INVALID_PARAM;
|
||||
#endif // BUTTONS_NUMBER > 0
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
#endif // BSP_SIMPLE
|
||||
|
||||
|
||||
uint32_t bsp_buttons_enable()
|
||||
{
|
||||
#if (BUTTONS_NUMBER > 0) && !defined(BSP_SIMPLE)
|
||||
return app_button_enable();
|
||||
#else
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t bsp_buttons_disable()
|
||||
{
|
||||
#if (BUTTONS_NUMBER > 0) && !defined(BSP_SIMPLE)
|
||||
return app_button_disable();
|
||||
#else
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
static uint32_t wakeup_button_cfg(uint32_t button_idx, bool enable)
|
||||
{
|
||||
#if !defined(BSP_SIMPLE)
|
||||
if (button_idx < BUTTONS_NUMBER)
|
||||
{
|
||||
nrf_gpio_pin_sense_t sense = enable ?
|
||||
(BUTTONS_ACTIVE_STATE ? NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW) :
|
||||
NRF_GPIO_PIN_NOSENSE;
|
||||
nrf_gpio_cfg_sense_set(bsp_board_button_idx_to_pin(button_idx), sense);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(button_idx);
|
||||
UNUSED_PARAMETER(enable);
|
||||
#endif
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
|
||||
}
|
||||
uint32_t bsp_wakeup_button_enable(uint32_t button_idx)
|
||||
{
|
||||
return wakeup_button_cfg(button_idx, true);
|
||||
}
|
||||
|
||||
uint32_t bsp_wakeup_button_disable(uint32_t button_idx)
|
||||
{
|
||||
return wakeup_button_cfg(button_idx, false);
|
||||
}
|
||||
307
components/libraries/bsp/bsp.h
Normal file
307
components/libraries/bsp/bsp.h
Normal file
@@ -0,0 +1,307 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup bsp Board Support Package
|
||||
* @{
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief BSP module.
|
||||
* @details This module provides a layer of abstraction from the board.
|
||||
* It allows the user to indicate certain states on LEDs in a simple way.
|
||||
* Module functionality can be modified by defining BSP_SIMPLE to reduce
|
||||
* functionality of this module to enable and read state of the buttons.
|
||||
*/
|
||||
|
||||
#ifndef BSP_H__
|
||||
#define BSP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "boards.h"
|
||||
|
||||
#if !defined(BSP_DEFINES_ONLY) && !defined(BSP_SIMPLE)
|
||||
#include "app_button.h"
|
||||
|
||||
#define BSP_BUTTON_ACTION_PUSH (APP_BUTTON_PUSH) /**< Represents pushing a button. See @ref bsp_button_action_t. */
|
||||
#define BSP_BUTTON_ACTION_RELEASE (APP_BUTTON_RELEASE) /**< Represents releasing a button. See @ref bsp_button_action_t. */
|
||||
#define BSP_BUTTON_ACTION_LONG_PUSH (2) /**< Represents pushing and holding a button for @ref BSP_LONG_PUSH_TIMEOUT_MS milliseconds. See also @ref bsp_button_action_t. */
|
||||
|
||||
#endif
|
||||
|
||||
/* BSP_UART_SUPPORT
|
||||
* This define enables UART support module.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint8_t bsp_button_action_t; /**< The different actions that can be performed on a button. */
|
||||
|
||||
#define BSP_INDICATIONS_LIST { \
|
||||
"BSP_INDICATE_IDLE", \
|
||||
"BSP_INDICATE_SCANNING", \
|
||||
"BSP_INDICATE_ADVERTISING", \
|
||||
"BSP_INDICATE_ADVERTISING_WHITELIST", \
|
||||
"BSP_INDICATE_ADVERTISING_SLOW", \
|
||||
"BSP_INDICATE_ADVERTISING_DIRECTED", \
|
||||
"BSP_INDICATE_BONDING", \
|
||||
"BSP_INDICATE_CONNECTED", \
|
||||
"BSP_INDICATE_SENT_OK", \
|
||||
"BSP_INDICATE_SEND_ERROR", \
|
||||
"BSP_INDICATE_RCV_OK", \
|
||||
"BSP_INDICATE_RCV_ERROR", \
|
||||
"BSP_INDICATE_FATAL_ERROR", \
|
||||
"BSP_INDICATE_ALERT_0", \
|
||||
"BSP_INDICATE_ALERT_1", \
|
||||
"BSP_INDICATE_ALERT_2", \
|
||||
"BSP_INDICATE_ALERT_3", \
|
||||
"BSP_INDICATE_ALERT_OFF", \
|
||||
"BSP_INDICATE_USER_STATE_OFF", \
|
||||
"BSP_INDICATE_USER_STATE_0", \
|
||||
"BSP_INDICATE_USER_STATE_1", \
|
||||
"BSP_INDICATE_USER_STATE_2", \
|
||||
"BSP_INDICATE_USER_STATE_3", \
|
||||
"BSP_INDICATE_USER_STATE_ON" \
|
||||
} /**< See @ref examples_bsp_states for a list of how these states are indicated for the PCA10028/PCA10040 board and the PCA10031 dongle.*/
|
||||
|
||||
|
||||
/**@brief BSP indication states.
|
||||
*
|
||||
* @details See @ref examples_bsp_states for a list of how these states are indicated for the PCA10028/PCA10040 board and the PCA10031 dongle.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BSP_INDICATE_FIRST = 0,
|
||||
BSP_INDICATE_IDLE = BSP_INDICATE_FIRST, /**< See \ref BSP_INDICATE_IDLE.*/
|
||||
BSP_INDICATE_SCANNING, /**< See \ref BSP_INDICATE_SCANNING.*/
|
||||
BSP_INDICATE_ADVERTISING, /**< See \ref BSP_INDICATE_ADVERTISING.*/
|
||||
BSP_INDICATE_ADVERTISING_WHITELIST, /**< See \ref BSP_INDICATE_ADVERTISING_WHITELIST.*/
|
||||
BSP_INDICATE_ADVERTISING_SLOW, /**< See \ref BSP_INDICATE_ADVERTISING_SLOW.*/
|
||||
BSP_INDICATE_ADVERTISING_DIRECTED, /**< See \ref BSP_INDICATE_ADVERTISING_DIRECTED.*/
|
||||
BSP_INDICATE_BONDING, /**< See \ref BSP_INDICATE_BONDING.*/
|
||||
BSP_INDICATE_CONNECTED, /**< See \ref BSP_INDICATE_CONNECTED.*/
|
||||
BSP_INDICATE_SENT_OK, /**< See \ref BSP_INDICATE_SENT_OK.*/
|
||||
BSP_INDICATE_SEND_ERROR, /**< See \ref BSP_INDICATE_SEND_ERROR.*/
|
||||
BSP_INDICATE_RCV_OK, /**< See \ref BSP_INDICATE_RCV_OK.*/
|
||||
BSP_INDICATE_RCV_ERROR, /**< See \ref BSP_INDICATE_RCV_ERROR.*/
|
||||
BSP_INDICATE_FATAL_ERROR, /**< See \ref BSP_INDICATE_FATAL_ERROR.*/
|
||||
BSP_INDICATE_ALERT_0, /**< See \ref BSP_INDICATE_ALERT_0.*/
|
||||
BSP_INDICATE_ALERT_1, /**< See \ref BSP_INDICATE_ALERT_1.*/
|
||||
BSP_INDICATE_ALERT_2, /**< See \ref BSP_INDICATE_ALERT_2.*/
|
||||
BSP_INDICATE_ALERT_3, /**< See \ref BSP_INDICATE_ALERT_3.*/
|
||||
BSP_INDICATE_ALERT_OFF, /**< See \ref BSP_INDICATE_ALERT_OFF.*/
|
||||
BSP_INDICATE_USER_STATE_OFF, /**< See \ref BSP_INDICATE_USER_STATE_OFF.*/
|
||||
BSP_INDICATE_USER_STATE_0, /**< See \ref BSP_INDICATE_USER_STATE_0.*/
|
||||
BSP_INDICATE_USER_STATE_1, /**< See \ref BSP_INDICATE_USER_STATE_1.*/
|
||||
BSP_INDICATE_USER_STATE_2, /**< See \ref BSP_INDICATE_USER_STATE_2.*/
|
||||
BSP_INDICATE_USER_STATE_3, /**< See \ref BSP_INDICATE_USER_STATE_3.*/
|
||||
BSP_INDICATE_USER_STATE_ON, /**< See \ref BSP_INDICATE_USER_STATE_ON.*/
|
||||
BSP_INDICATE_LAST = BSP_INDICATE_USER_STATE_ON
|
||||
} bsp_indication_t;
|
||||
|
||||
/**@brief BSP events.
|
||||
*
|
||||
* @note Events from BSP_EVENT_KEY_0 to BSP_EVENT_KEY_LAST are by default assigned to buttons.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BSP_EVENT_NOTHING = 0, /**< Assign this event to an action to prevent the action from generating an event (disable the action). */
|
||||
BSP_EVENT_DEFAULT, /**< Assign this event to an action to assign the default event to the action. */
|
||||
BSP_EVENT_CLEAR_BONDING_DATA, /**< Persistent bonding data should be erased. */
|
||||
BSP_EVENT_CLEAR_ALERT, /**< An alert should be cleared. */
|
||||
BSP_EVENT_DISCONNECT, /**< A link should be disconnected. */
|
||||
BSP_EVENT_ADVERTISING_START, /**< The device should start advertising. */
|
||||
BSP_EVENT_ADVERTISING_STOP, /**< The device should stop advertising. */
|
||||
BSP_EVENT_WHITELIST_OFF, /**< The device should remove its advertising whitelist. */
|
||||
BSP_EVENT_BOND, /**< The device should bond to the currently connected peer. */
|
||||
BSP_EVENT_RESET, /**< The device should reset. */
|
||||
BSP_EVENT_SLEEP, /**< The device should enter sleep mode. */
|
||||
BSP_EVENT_WAKEUP, /**< The device should wake up from sleep mode. */
|
||||
BSP_EVENT_SYSOFF, /**< The device should enter system off mode (without wakeup). */
|
||||
BSP_EVENT_DFU, /**< The device should enter DFU mode. */
|
||||
BSP_EVENT_KEY_0, /**< Default event of the push action of BSP_BUTTON_0 (only if this button is present). */
|
||||
BSP_EVENT_KEY_1, /**< Default event of the push action of BSP_BUTTON_1 (only if this button is present). */
|
||||
BSP_EVENT_KEY_2, /**< Default event of the push action of BSP_BUTTON_2 (only if this button is present). */
|
||||
BSP_EVENT_KEY_3, /**< Default event of the push action of BSP_BUTTON_3 (only if this button is present). */
|
||||
BSP_EVENT_KEY_4, /**< Default event of the push action of BSP_BUTTON_4 (only if this button is present). */
|
||||
BSP_EVENT_KEY_5, /**< Default event of the push action of BSP_BUTTON_5 (only if this button is present). */
|
||||
BSP_EVENT_KEY_6, /**< Default event of the push action of BSP_BUTTON_6 (only if this button is present). */
|
||||
BSP_EVENT_KEY_7, /**< Default event of the push action of BSP_BUTTON_7 (only if this button is present). */
|
||||
BSP_EVENT_KEY_LAST = BSP_EVENT_KEY_7,
|
||||
} bsp_event_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bsp_event_t push_event; /**< The event to fire on regular button press. */
|
||||
bsp_event_t long_push_event; /**< The event to fire on long button press. */
|
||||
bsp_event_t release_event; /**< The event to fire on button release. */
|
||||
} bsp_button_event_cfg_t;
|
||||
|
||||
/**@brief BSP module event callback function type.
|
||||
*
|
||||
* @details Upon an event in the BSP module, this callback function will be called to notify
|
||||
* the application about the event.
|
||||
*
|
||||
* @param[in] bsp_event_t BSP event type.
|
||||
*/
|
||||
typedef void (* bsp_event_callback_t)(bsp_event_t);
|
||||
|
||||
|
||||
/**@brief Function for initializing BSP.
|
||||
*
|
||||
* @details The function initializes the board support package to allow state indication and
|
||||
* button reaction. Default events are assigned to buttons.
|
||||
* @note Before calling this function, you must initiate the following required modules:
|
||||
* - @ref app_timer for LED support
|
||||
* - @ref app_gpiote for button support
|
||||
*
|
||||
* @param[in] type Type of peripherals used.
|
||||
* @param[in] callback Function to be called when button press/event is detected.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the BSP module was successfully initialized.
|
||||
* @retval NRF_ERROR_INVALID_STATE If the application timer module has not been initialized.
|
||||
* @retval NRF_ERROR_NO_MEM If the maximum number of timers has already been reached.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If GPIOTE has too many users.
|
||||
* @retval NRF_ERROR_INVALID_STATE If button or GPIOTE has not been initialized.
|
||||
*/
|
||||
uint32_t bsp_init(uint32_t type, bsp_event_callback_t callback);
|
||||
|
||||
|
||||
/**@brief Function for checking button states.
|
||||
*
|
||||
* @details This function checks if the button is pressed. If the button ID is out of range,
|
||||
* the function returns false.
|
||||
*
|
||||
* @param[in] button Button ID to check.
|
||||
*
|
||||
* @retval true If the button is pressed.
|
||||
* @retval false If the button is not pressed.
|
||||
*/
|
||||
bool bsp_button_is_pressed(uint32_t button);
|
||||
|
||||
|
||||
/**@brief Function for assigning a specific event to a button.
|
||||
*
|
||||
* @details This function allows redefinition of standard events assigned to buttons.
|
||||
* To unassign events, provide the event @ref BSP_EVENT_NOTHING.
|
||||
*
|
||||
* @param[in] button Button ID to be redefined.
|
||||
* @param[in] action Button action to assign event to.
|
||||
* @param[in] event Event to be assigned to button.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the event was successfully assigned to button.
|
||||
* @retval NRF_ERROR_INVALID_PARAM If the button ID or button action was invalid.
|
||||
*/
|
||||
uint32_t bsp_event_to_button_action_assign(uint32_t button, bsp_button_action_t action, bsp_event_t event);
|
||||
|
||||
|
||||
/**@brief Function for configuring indicators to required state.
|
||||
*
|
||||
* @details This function indicates the required state by means of LEDs (if enabled).
|
||||
*
|
||||
* @note Alerts are indicated independently.
|
||||
*
|
||||
* @param[in] indicate State to be indicated.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the state was successfully indicated.
|
||||
* @retval NRF_ERROR_NO_MEM If the internal timer operations queue was full.
|
||||
* @retval NRF_ERROR_INVALID_STATE If the application timer module has not been initialized,
|
||||
* or internal timer has not been created.
|
||||
*/
|
||||
uint32_t bsp_indication_set(bsp_indication_t indicate);
|
||||
|
||||
|
||||
/**@brief Function for enabling all buttons.
|
||||
*
|
||||
* @details After calling this function, all buttons will generate events when pressed, and
|
||||
* all buttons will be able to wake the system up from sleep mode.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the buttons were successfully enabled.
|
||||
* @retval NRF_ERROR_NOT_SUPPORTED If the board has no buttons or BSP_SIMPLE is defined.
|
||||
* @return A propagated error.
|
||||
*/
|
||||
uint32_t bsp_buttons_enable(void);
|
||||
|
||||
|
||||
/**@brief Function for disabling all buttons.
|
||||
*
|
||||
* @details After calling this function, no buttons will generate events when pressed, and
|
||||
* no buttons will be able to wake the system up from sleep mode.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the buttons were successfully disabled.
|
||||
* @retval NRF_ERROR_NOT_SUPPORTED If the board has no buttons or BSP_SIMPLE is defined.
|
||||
* @return A propagated error.
|
||||
*/
|
||||
uint32_t bsp_buttons_disable(void);
|
||||
|
||||
|
||||
/**@brief Function for enabling wakeup from SYSTEM OFF for given button.
|
||||
*
|
||||
* @details After calling this function, button can be used to wake up the chip.
|
||||
* This function should only be called immediately before going into sleep.
|
||||
*
|
||||
* @param[in] button_idx Index of the button.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the button was successfully enabled.
|
||||
* @retval NRF_ERROR_NOT_SUPPORTED If the board has no buttons or BSP_SIMPLE is defined.
|
||||
*/
|
||||
uint32_t bsp_wakeup_button_enable(uint32_t button_idx);
|
||||
|
||||
|
||||
/**@brief Function for disabling wakeup for the given button.
|
||||
*
|
||||
* @param[in] button_idx index of the button.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the button was successfully disabled.
|
||||
* @retval NRF_ERROR_NOT_SUPPORTED If the board has no buttons or BSP_SIMPLE is defined.
|
||||
*/
|
||||
uint32_t bsp_wakeup_button_disable(uint32_t button_idx);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BSP_H__
|
||||
|
||||
/** @} */
|
||||
172
components/libraries/bsp/bsp_btn_ant.c
Normal file
172
components/libraries/bsp/bsp_btn_ant.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BSP_BTN_ANT)
|
||||
#include "bsp_btn_ant.h"
|
||||
#include "nrf_sdh_ant.h"
|
||||
#include "bsp.h"
|
||||
|
||||
|
||||
static bool m_connected = false; /**< Notify if channel is connected. */
|
||||
static uint8_t m_channel = UINT8_MAX; /**< ANT channel number linked to indication. */
|
||||
static uint8_t m_channel_type; /**< Type of linked ANT channel. */
|
||||
|
||||
/**@brief Function for configuring the buttons for connection.
|
||||
*
|
||||
* @retval NRF_SUCCESS Configured successfully.
|
||||
* @return A propagated error code.
|
||||
*/
|
||||
static ret_code_t connection_buttons_configure(void)
|
||||
{
|
||||
ret_code_t err_code = bsp_event_to_button_action_assign(BSP_BTN_ANT_CONFIG_SLEEP_BTN_ID,
|
||||
BSP_BUTTON_ACTION_RELEASE,
|
||||
BSP_EVENT_DEFAULT);
|
||||
if (err_code == NRF_ERROR_INVALID_PARAM)
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/**@brief Function for configuring the buttons for searching.
|
||||
*
|
||||
* @retval NRF_SUCCESS Configured successfully.
|
||||
* @return A propagated error code.
|
||||
*/
|
||||
static ret_code_t searching_buttons_configure(void)
|
||||
{
|
||||
ret_code_t err_code = bsp_event_to_button_action_assign(BSP_BTN_ANT_CONFIG_SLEEP_BTN_ID,
|
||||
BSP_BUTTON_ACTION_RELEASE,
|
||||
BSP_EVENT_SLEEP);
|
||||
if (err_code == NRF_ERROR_INVALID_PARAM)
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t bsp_btn_ant_sleep_mode_prepare(void)
|
||||
{
|
||||
ret_code_t err_code = bsp_buttons_disable();
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
err_code = bsp_wakeup_button_enable(BSP_BTN_ANT_CONFIG_WAKEUP_BTN_ID);
|
||||
if (err_code == NRF_ERROR_NOT_SUPPORTED)
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for handling ANT events.
|
||||
*
|
||||
* @param[in] p_ant_evt Event received from the ANT stack.
|
||||
* @param[in] p_context Context.
|
||||
*/
|
||||
static void ant_evt_handler(ant_evt_t * p_ant_evt, void * p_context)
|
||||
{
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
if (m_channel != p_ant_evt->channel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_channel_type)
|
||||
{
|
||||
case CHANNEL_TYPE_SLAVE:
|
||||
/* fall through */
|
||||
case CHANNEL_TYPE_SLAVE_RX_ONLY:
|
||||
switch (p_ant_evt->event)
|
||||
{
|
||||
case EVENT_RX:
|
||||
if (!m_connected)
|
||||
{
|
||||
err_code = connection_buttons_configure();
|
||||
}
|
||||
|
||||
m_connected = true;
|
||||
break;
|
||||
|
||||
case EVENT_RX_FAIL_GO_TO_SEARCH:
|
||||
m_connected = false;
|
||||
|
||||
err_code = searching_buttons_configure();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
NRF_SDH_ANT_OBSERVER(m_ant_observer, BSP_BTN_ANT_OBSERVER_PRIO, ant_evt_handler, NULL);
|
||||
|
||||
ret_code_t bsp_btn_ant_init(uint8_t channel, uint8_t channel_type)
|
||||
{
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
m_channel = channel;
|
||||
m_channel_type = channel_type;
|
||||
|
||||
if (!m_connected)
|
||||
{
|
||||
err_code = searching_buttons_configure();
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = connection_buttons_configure();
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(BSP_BTN_ANT)
|
||||
91
components/libraries/bsp/bsp_btn_ant.h
Normal file
91
components/libraries/bsp/bsp_btn_ant.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup bsp_btn_ant BSP: ANT Button Module
|
||||
* @{
|
||||
* @ingroup bsp
|
||||
*
|
||||
* @brief Module for controlling ANT behavior through button actions.
|
||||
*
|
||||
* @details The application must propagate ANT events to the ANT Button Module.
|
||||
* Based on these events, the ANT Button Module configures the Board Support Package
|
||||
* to generate BSP events for certain button actions. These BSP events should then be
|
||||
* handled by the application's BSP event handler.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BSP_BTN_ANT_H__
|
||||
#define BSP_BTN_ANT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdk_errors.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Function for initializing the ANT Button Module.
|
||||
*
|
||||
* Before calling this function, the BSP module must be initialized with buttons.
|
||||
*
|
||||
* @param[in] channel ANT channel number.
|
||||
* @param[in] channel_type ANT channel type (see Assign Channel Parameters in ant_parameters.h: @ref ant_parameters).
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful. Otherwise, a propagated error code is
|
||||
* returned.
|
||||
*/
|
||||
ret_code_t bsp_btn_ant_init(uint8_t channel, uint8_t channel_type);
|
||||
|
||||
/**@brief Function for setting up wakeup buttons before going into sleep mode.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the buttons were prepared successfully. Otherwise, a propagated error
|
||||
* code is returned.
|
||||
*/
|
||||
ret_code_t bsp_btn_ant_sleep_mode_prepare(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSP_BTN_ANT_H__ */
|
||||
|
||||
/** @} */
|
||||
254
components/libraries/bsp/bsp_btn_ble.c
Normal file
254
components/libraries/bsp/bsp_btn_ble.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "bsp_btn_ble.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include "bsp.h"
|
||||
|
||||
#define BTN_ID_WAKEUP 0 /**< ID of button used to wake up the application. */
|
||||
#define BTN_ID_SLEEP 0 /**< ID of button used to put the application into sleep mode. */
|
||||
#define BTN_ID_DISCONNECT 0 /**< ID of button used to gracefully terminate a connection on long press. */
|
||||
#define BTN_ID_WAKEUP_BOND_DELETE 1 /**< ID of button used to wake up the application and delete all bonding information. */
|
||||
#define BTN_ID_WHITELIST_OFF 1 /**< ID of button used to turn off usage of the whitelist. */
|
||||
|
||||
#define BTN_ACTION_SLEEP BSP_BUTTON_ACTION_RELEASE /**< Button action used to put the application into sleep mode. */
|
||||
#define BTN_ACTION_DISCONNECT BSP_BUTTON_ACTION_LONG_PUSH /**< Button action used to gracefully terminate a connection on long press. */
|
||||
#define BTN_ACTION_WHITELIST_OFF BSP_BUTTON_ACTION_LONG_PUSH /**< Button action used to turn off usage of the whitelist. */
|
||||
|
||||
/**@brief This macro will return from the current function if err_code
|
||||
* is not NRF_SUCCESS or NRF_ERROR_INVALID_PARAM.
|
||||
*/
|
||||
#define RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code) \
|
||||
do \
|
||||
{ \
|
||||
if (((err_code) != NRF_SUCCESS) && ((err_code) != NRF_ERROR_INVALID_PARAM)) \
|
||||
{ \
|
||||
return err_code; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
/**@brief This macro will return from the current function if err_code
|
||||
* is not NRF_SUCCESS or NRF_ERROR_NOT_SUPPORTED.
|
||||
*/
|
||||
#define RETURN_ON_ERROR_NOT_NOT_SUPPORTED(err_code) \
|
||||
do \
|
||||
{ \
|
||||
if (((err_code) != NRF_SUCCESS) && ((err_code) != NRF_ERROR_NOT_SUPPORTED)) \
|
||||
{ \
|
||||
return err_code; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
/**@brief This macro will call the registered error handler if err_code
|
||||
* is not NRF_SUCCESS and the error handler is not NULL.
|
||||
*/
|
||||
#define CALL_HANDLER_ON_ERROR(err_code) \
|
||||
do \
|
||||
{ \
|
||||
if (((err_code) != NRF_SUCCESS) && (m_error_handler != NULL)) \
|
||||
{ \
|
||||
m_error_handler(err_code); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
static bsp_btn_ble_error_handler_t m_error_handler = NULL; /**< Error handler registered by the user. */
|
||||
static uint32_t m_num_connections = 0; /**< Number of connections the device is currently in. */
|
||||
|
||||
|
||||
/**@brief Function for configuring the buttons for connection.
|
||||
*
|
||||
* @retval NRF_SUCCESS Configured successfully.
|
||||
* @return A propagated error code.
|
||||
*/
|
||||
static uint32_t connection_buttons_configure()
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
err_code = bsp_event_to_button_action_assign(BTN_ID_SLEEP,
|
||||
BTN_ACTION_SLEEP,
|
||||
BSP_EVENT_DEFAULT);
|
||||
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
|
||||
|
||||
err_code = bsp_event_to_button_action_assign(BTN_ID_WHITELIST_OFF,
|
||||
BTN_ACTION_WHITELIST_OFF,
|
||||
BSP_EVENT_WHITELIST_OFF);
|
||||
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
|
||||
|
||||
|
||||
err_code = bsp_event_to_button_action_assign(BTN_ID_DISCONNECT,
|
||||
BTN_ACTION_DISCONNECT,
|
||||
BSP_EVENT_DISCONNECT);
|
||||
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for configuring the buttons for advertisement.
|
||||
*
|
||||
* @retval NRF_SUCCESS Configured successfully.
|
||||
* @return A propagated error code.
|
||||
*/
|
||||
static uint32_t advertising_buttons_configure()
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
err_code = bsp_event_to_button_action_assign(BTN_ID_DISCONNECT,
|
||||
BTN_ACTION_DISCONNECT,
|
||||
BSP_EVENT_DEFAULT);
|
||||
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
|
||||
|
||||
err_code = bsp_event_to_button_action_assign(BTN_ID_WHITELIST_OFF,
|
||||
BTN_ACTION_WHITELIST_OFF,
|
||||
BSP_EVENT_WHITELIST_OFF);
|
||||
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
|
||||
|
||||
err_code = bsp_event_to_button_action_assign(BTN_ID_SLEEP,
|
||||
BTN_ACTION_SLEEP,
|
||||
BSP_EVENT_SLEEP);
|
||||
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for extracting the BSP event valid at startup.
|
||||
*
|
||||
* @details When a button was used to wake up the device, the button press will not generate an
|
||||
* interrupt. This function reads which button was pressed at startup, and returns the
|
||||
* appropriate BSP event.
|
||||
*
|
||||
* @param[out] p_startup_event Where to put the extracted BSP event.
|
||||
*/
|
||||
static void startup_event_extract(bsp_event_t * p_startup_event)
|
||||
{
|
||||
// React to button states
|
||||
if (bsp_button_is_pressed(BTN_ID_WAKEUP_BOND_DELETE))
|
||||
{
|
||||
*p_startup_event = BSP_EVENT_CLEAR_BONDING_DATA;
|
||||
}
|
||||
else if (bsp_button_is_pressed(BTN_ID_WAKEUP))
|
||||
{
|
||||
*p_startup_event = BSP_EVENT_WAKEUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p_startup_event = BSP_EVENT_NOTHING;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t bsp_btn_ble_sleep_mode_prepare(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
err_code = bsp_wakeup_button_enable(BTN_ID_WAKEUP);
|
||||
RETURN_ON_ERROR_NOT_NOT_SUPPORTED(err_code);
|
||||
|
||||
err_code = bsp_wakeup_button_enable(BTN_ID_WAKEUP_BOND_DELETE);
|
||||
RETURN_ON_ERROR_NOT_NOT_SUPPORTED(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function for handling BLE events.
|
||||
*
|
||||
* @param[in] p_ble_evt Event received from the BLE stack.
|
||||
* @param[in] p_context Context.
|
||||
*/
|
||||
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
if (m_num_connections == 0)
|
||||
{
|
||||
err_code = connection_buttons_configure();
|
||||
CALL_HANDLER_ON_ERROR(err_code);
|
||||
}
|
||||
|
||||
m_num_connections++;
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
m_num_connections--;
|
||||
|
||||
if (m_num_connections == 0)
|
||||
{
|
||||
err_code = advertising_buttons_configure();
|
||||
CALL_HANDLER_ON_ERROR(err_code);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NRF_SDH_BLE_OBSERVER(m_ble_observer, BSP_BTN_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
|
||||
|
||||
|
||||
uint32_t bsp_btn_ble_init(bsp_btn_ble_error_handler_t error_handler, bsp_event_t * p_startup_bsp_evt)
|
||||
{
|
||||
uint32_t err_code = NRF_SUCCESS;
|
||||
|
||||
m_error_handler = error_handler;
|
||||
|
||||
if (p_startup_bsp_evt != NULL)
|
||||
{
|
||||
startup_event_extract(p_startup_bsp_evt);
|
||||
}
|
||||
|
||||
if (m_num_connections == 0)
|
||||
{
|
||||
err_code = advertising_buttons_configure();
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
100
components/libraries/bsp/bsp_btn_ble.h
Normal file
100
components/libraries/bsp/bsp_btn_ble.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup bsp_btn_ble BSP: BLE Button Module
|
||||
* @{
|
||||
* @ingroup bsp
|
||||
*
|
||||
* @brief Module for controlling BLE behavior through button actions.
|
||||
*
|
||||
* @details The application must propagate BLE events to the BLE Button Module.
|
||||
* Based on these events, the BLE Button Module configures the Board Support Package
|
||||
* to generate BSP events for certain button actions. These BSP events should then be
|
||||
* handled by the application's BSP event handler.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BSP_BTN_BLE_H__
|
||||
#define BSP_BTN_BLE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ble.h"
|
||||
#include "bsp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief BLE Button Module error handler type. */
|
||||
typedef void (*bsp_btn_ble_error_handler_t) (uint32_t nrf_error);
|
||||
|
||||
/**@brief Function for initializing the BLE Button Module.
|
||||
*
|
||||
* Before calling this function, the BSP module must be initialized with buttons.
|
||||
*
|
||||
* @param[out] error_handler Error handler to call in case of internal errors in BLE Button
|
||||
* Module.
|
||||
* @param[out] p_startup_bsp_evt If not a NULL pointer, the value is filled with an event
|
||||
* (or BSP_EVENT_NOTHING) derived from the buttons pressed on
|
||||
* startup. For example, if the bond delete wakeup button was pressed
|
||||
* to wake up the device, *p_startup_bsp_evt is set to
|
||||
* @ref BSP_EVENT_CLEAR_BONDING_DATA.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful. Otherwise, a propagated error code is
|
||||
* returned.
|
||||
*/
|
||||
uint32_t bsp_btn_ble_init(bsp_btn_ble_error_handler_t error_handler, bsp_event_t * p_startup_bsp_evt);
|
||||
|
||||
/**@brief Function for setting up wakeup buttons before going into sleep mode.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the buttons were prepared successfully. Otherwise, a propagated error
|
||||
* code is returned.
|
||||
*/
|
||||
uint32_t bsp_btn_ble_sleep_mode_prepare(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSP_BTN_BLE_H__ */
|
||||
|
||||
/** @} */
|
||||
77
components/libraries/bsp/bsp_cli.c
Normal file
77
components/libraries/bsp/bsp_cli.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "bsp_cli.h"
|
||||
|
||||
static bsp_event_callback_t m_bsp_cli_callback = NULL;
|
||||
|
||||
static void cmd_btn(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
uint32_t id;
|
||||
ASSERT(m_bsp_cli_callback != NULL);
|
||||
|
||||
sscanf(argv[1], "%"SCNu32, &id);
|
||||
bsp_event_t ev = (bsp_event_t)(BSP_EVENT_KEY_0 + id);
|
||||
m_bsp_cli_callback(ev);
|
||||
}
|
||||
|
||||
static void cmd_evt(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
uint32_t id;
|
||||
ASSERT(m_bsp_cli_callback != NULL);
|
||||
|
||||
sscanf(argv[1], "%"SCNu32, &id);
|
||||
bsp_event_t ev = (bsp_event_t)id;
|
||||
m_bsp_cli_callback(ev);
|
||||
}
|
||||
|
||||
ret_code_t bsp_cli_init(bsp_event_callback_t callback)
|
||||
{
|
||||
m_bsp_cli_callback = callback;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_bsp)
|
||||
{
|
||||
NRF_CLI_CMD(btn, NULL, "BSP button event key", cmd_btn),
|
||||
NRF_CLI_CMD(evt, NULL, "BSP event id", cmd_evt),
|
||||
NRF_CLI_SUBCMD_SET_END
|
||||
};
|
||||
NRF_CLI_CMD_REGISTER(bsp, &m_sub_bsp, "bsp", NULL);
|
||||
83
components/libraries/bsp/bsp_cli.h
Normal file
83
components/libraries/bsp/bsp_cli.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup bsp_cli BSP over CLI Module
|
||||
* @{
|
||||
* @ingroup bsp
|
||||
*
|
||||
* @brief Module for sending BSP events over CLI.
|
||||
*
|
||||
* @details The module uses Command Line Interface and enables user to send events
|
||||
* to BSP. They are later handled by the event handler provided.
|
||||
* Available commands:
|
||||
* - bsp btn X (where X is button number) - sends BSP_EVENT_KEY_X
|
||||
* - bsp evt X (where X is event number) - sends BSP event with X id
|
||||
*/
|
||||
|
||||
#ifndef BSP_CLI_H__
|
||||
#define BSP_CLI_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nrf_cli.h"
|
||||
#include "bsp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Function for initializing the BSP over CLI Module.
|
||||
*
|
||||
* Before calling this function, the BSP module must be initialized.
|
||||
*
|
||||
* @param[in] callback Function to be called when event is recevied.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful.
|
||||
*/
|
||||
|
||||
ret_code_t bsp_cli_init(bsp_event_callback_t callback);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSP_CLI_H__ */
|
||||
|
||||
/** @} */
|
||||
135
components/libraries/bsp/bsp_config.h
Normal file
135
components/libraries/bsp/bsp_config.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup bsp Board Support Package
|
||||
* @{
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief BSP module.
|
||||
* @details This module provides a layer of abstraction from the board.
|
||||
* It allows the user to indicate certain states on LEDs in a simple way.
|
||||
* Module functionality can be modified by additional defines:
|
||||
* - BSP_SIMPLE - reduces functionality of this module to enable
|
||||
* and read state of the buttons.
|
||||
* - BSP_UART_SUPPORT - enables support for UART.
|
||||
*/
|
||||
|
||||
#ifndef BSP_CONFIG_H__
|
||||
#define BSP_CONFIG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "boards.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(BSP_DEFINES_ONLY) && !defined(BSP_SIMPLE)
|
||||
#include "app_button.h"
|
||||
|
||||
#define BSP_BUTTON_ACTION_PUSH (APP_BUTTON_PUSH) /**< Represents pushing a button. See @ref bsp_button_action_t. */
|
||||
#define BSP_BUTTON_ACTION_RELEASE (APP_BUTTON_RELEASE) /**< Represents releasing a button. See @ref bsp_button_action_t. */
|
||||
#define BSP_BUTTON_ACTION_LONG_PUSH (2) /**< Represents pushing and holding a button for @ref BSP_LONG_PUSH_TIMEOUT_MS milliseconds. See also @ref bsp_button_action_t. */
|
||||
#endif
|
||||
|
||||
#define BSP_MS_TO_TICK(MS) (m_app_ticks_per_100ms * (MS / 100))
|
||||
|
||||
|
||||
#define BUTTON_ERASE_BONDING BSP_BUTTON_0_MASK
|
||||
#define BUTTON_ERASE_ALL BSP_BUTTON_1_MASK
|
||||
#define BUTTON_ADVERTISE BSP_BUTTON_0_MASK
|
||||
#define BUTTON_CLEAR_EVT BSP_BUTTON_1_MASK
|
||||
#define BUTTON_CAPSLOCK BSP_BUTTON_2_MASK
|
||||
#define BSP_BUTTONS_ALL 0xFFFFFFFF
|
||||
#define BSP_BUTTONS_NONE 0
|
||||
|
||||
#define BSP_LONG_PUSH_TIMEOUT_MS (1000) /**< The time to hold for a long push (in milliseconds). */
|
||||
/**@brief Types of BSP initialization.
|
||||
*/
|
||||
|
||||
#define ADVERTISING_LED_ON_INTERVAL 200
|
||||
#define ADVERTISING_LED_OFF_INTERVAL 1800
|
||||
|
||||
#define ADVERTISING_DIRECTED_LED_ON_INTERVAL 200
|
||||
#define ADVERTISING_DIRECTED_LED_OFF_INTERVAL 200
|
||||
|
||||
#define ADVERTISING_WHITELIST_LED_ON_INTERVAL 200
|
||||
#define ADVERTISING_WHITELIST_LED_OFF_INTERVAL 800
|
||||
|
||||
#define ADVERTISING_SLOW_LED_ON_INTERVAL 400
|
||||
#define ADVERTISING_SLOW_LED_OFF_INTERVAL 4000
|
||||
|
||||
#define BONDING_INTERVAL 100
|
||||
|
||||
#define SENT_OK_INTERVAL 100
|
||||
#define SEND_ERROR_INTERVAL 500
|
||||
|
||||
#define RCV_OK_INTERVAL 100
|
||||
#define RCV_ERROR_INTERVAL 500
|
||||
|
||||
#define ALERT_INTERVAL 200
|
||||
|
||||
#define BSP_LED_INDICATE_SENT_OK BSP_BOARD_LED_1
|
||||
#define BSP_LED_INDICATE_SEND_ERROR BSP_BOARD_LED_1
|
||||
#define BSP_LED_INDICATE_RCV_OK BSP_BOARD_LED_1
|
||||
#define BSP_LED_INDICATE_RCV_ERROR BSP_BOARD_LED_1
|
||||
#define BSP_LED_INDICATE_CONNECTED BSP_BOARD_LED_0
|
||||
#define BSP_LED_INDICATE_BONDING BSP_BOARD_LED_0
|
||||
#define BSP_LED_INDICATE_ADVERTISING_DIRECTED BSP_BOARD_LED_0
|
||||
#define BSP_LED_INDICATE_ADVERTISING_SLOW BSP_BOARD_LED_0
|
||||
#define BSP_LED_INDICATE_ADVERTISING_WHITELIST BSP_BOARD_LED_0
|
||||
#define BSP_LED_INDICATE_INDICATE_ADVERTISING BSP_BOARD_LED_0
|
||||
|
||||
#define BSP_LED_INDICATE_USER_LED1 BSP_BOARD_LED_0
|
||||
#define BSP_LED_INDICATE_USER_LED2 BSP_BOARD_LED_1
|
||||
#define BSP_LED_INDICATE_USER_LED3 BSP_BOARD_LED_2
|
||||
#define BSP_LED_INDICATE_USER_LED4 BSP_BOARD_LED_3
|
||||
|
||||
#define BSP_LED_ALERT BSP_BOARD_LED_2
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BSP_CONFIG_H__
|
||||
|
||||
/** @} */
|
||||
84
components/libraries/bsp/bsp_nfc.c
Normal file
84
components/libraries/bsp/bsp_nfc.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "bsp_nfc.h"
|
||||
#include "bsp.h"
|
||||
#include "nrf.h"
|
||||
#include "app_util_platform.h"
|
||||
|
||||
#ifndef BSP_SIMPLE
|
||||
#define BTN_ACTION_SLEEP BSP_BUTTON_ACTION_RELEASE /**< Button action used to put the application into sleep mode. */
|
||||
|
||||
ret_code_t bsp_nfc_btn_init(uint32_t sleep_button)
|
||||
{
|
||||
uint32_t err_code = bsp_event_to_button_action_assign(sleep_button,
|
||||
BTN_ACTION_SLEEP,
|
||||
BSP_EVENT_SLEEP);
|
||||
return err_code;
|
||||
}
|
||||
|
||||
ret_code_t bsp_nfc_btn_deinit(uint32_t sleep_button)
|
||||
{
|
||||
uint32_t err_code = bsp_event_to_button_action_assign(sleep_button,
|
||||
BTN_ACTION_SLEEP,
|
||||
BSP_EVENT_DEFAULT);
|
||||
return err_code;
|
||||
}
|
||||
|
||||
ret_code_t bsp_nfc_sleep_mode_prepare(void)
|
||||
{
|
||||
#if defined(NFCT_PRESENT)
|
||||
// Check if peripheral is not used.
|
||||
CRITICAL_REGION_ENTER();
|
||||
#ifdef NRF52832_XXAA
|
||||
if ((*(uint32_t *)0x40005410 & 0x07) == 0)
|
||||
#else
|
||||
if ((NRF_NFCT->NFCTAGSTATE & NFCT_NFCTAGSTATE_NFCTAGSTATE_Msk)
|
||||
== NFCT_NFCTAGSTATE_NFCTAGSTATE_Disabled)
|
||||
#endif // NRF52832_XXAA
|
||||
{
|
||||
NRF_NFCT->TASKS_SENSE = 1;
|
||||
}
|
||||
CRITICAL_REGION_EXIT();
|
||||
return NRF_SUCCESS;
|
||||
#else
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
#endif //BSP_SIMPLE
|
||||
107
components/libraries/bsp/bsp_nfc.h
Normal file
107
components/libraries/bsp/bsp_nfc.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/**@file
|
||||
*
|
||||
* @defgroup bsp_nfc NFC BSP Module
|
||||
* @{
|
||||
* @ingroup bsp
|
||||
*
|
||||
* @brief Module for setting the NFCT peripheral as a wakeup source.
|
||||
*
|
||||
* @details The application must notify this module before going into System OFF mode.
|
||||
* Based on this notification, the NFC BSP Module sets the NFCT peripheral as a wakeup source
|
||||
* through the Board Support Package. Additionally, any BSP Button can be configured to
|
||||
* generate BSP sleep events. This module is applicable only if NFCT is used exclusively for
|
||||
* wakeup. If NFCT is used for a different purpose, this module cannot be used.
|
||||
*/
|
||||
|
||||
#ifndef BSP_NFC_H__
|
||||
#define BSP_NFC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdk_errors.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@brief Function for initializing the NFC Button Module.
|
||||
*
|
||||
* Before calling this function, the BSP module must be initialized with buttons. The chosen
|
||||
* button is used to generate @ref BSP_EVENT_SLEEP events.
|
||||
*
|
||||
* @param[in] sleep_button Button ID used to generate @ref BSP_EVENT_SLEEP event.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful. Otherwise, a propagated error
|
||||
* code is returned.
|
||||
*/
|
||||
ret_code_t bsp_nfc_btn_init(uint32_t sleep_button);
|
||||
|
||||
/**@brief Function for deinitializing the NFC Button Module.
|
||||
*
|
||||
* Before calling this function, the BSP module must be initialized with buttons. The chosen
|
||||
* button is used to generate default @ref BSP_EVENT_DEFAULT events.
|
||||
*
|
||||
* @param[in] sleep_button Button ID used to restore default event generation.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful. Otherwise, a propagated error
|
||||
* code is returned.
|
||||
*/
|
||||
ret_code_t bsp_nfc_btn_deinit(uint32_t sleep_button);
|
||||
|
||||
/**@brief Function for setting up NFCT peripheral as wake-up source.
|
||||
*
|
||||
* This function must be called before going into System OFF mode.
|
||||
*
|
||||
* @note This function is only applicable if NFCT is used exclusively for wakeup.
|
||||
* If NFCT is used for a different purpose, this function cannot be used.
|
||||
*
|
||||
* @retval NRF_SUCCESS If NFCT peripheral was prepared successfully. Otherwise,
|
||||
* a propagated error code is returned.
|
||||
*/
|
||||
ret_code_t bsp_nfc_sleep_mode_prepare(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSP_NFC_H__ */
|
||||
|
||||
/** @} */
|
||||
349
components/libraries/button/app_button.c
Normal file
349
components/libraries/button/app_button.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(BUTTON)
|
||||
#include "app_button.h"
|
||||
#include "app_timer.h"
|
||||
#include "app_error.h"
|
||||
#include "nrf_drv_gpiote.h"
|
||||
#include "nrf_assert.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME app_button
|
||||
#if APP_BUTTON_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL APP_BUTTON_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR APP_BUTTON_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR APP_BUTTON_CONFIG_DEBUG_COLOR
|
||||
#else //APP_BUTTON_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif //APP_BUTTON_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
/*
|
||||
* For each pin state machine is used. Since GPIOTE PORT event is common for all pin is might be
|
||||
* missed. Module relies on interrupt from GPIOTE only to active periodic app_timer in which pin
|
||||
* is sampled. Timer is stopped when there is no active buttons (all buttons are in idle state).
|
||||
*
|
||||
* Transition to the new state is based on currently sampled button value. State machine has
|
||||
* following transitions:
|
||||
*
|
||||
* -----------------------------------------------------
|
||||
* | value | current state | new state |
|
||||
* |---------------------------------------------------|
|
||||
* | 0 | IDLE | IDLE |
|
||||
* | 1 | IDLE | PRESS_ARMED |
|
||||
* | 0 | PRESS_ARMED | IDLE |
|
||||
* | 1 | PRESS_ARMED | PRESS_DETECTED |
|
||||
* | 1 | PRESS_DETECTED | PRESSED (push event) |
|
||||
* | 0 | PRESS_DETECTED | PRESS_ARMED |
|
||||
* | 0 | PRESSED | RELEASE_DETECTED |
|
||||
* | 1 | PRESSED | PRESSED |
|
||||
* | 0 | RELEASE_DETECTED | IDLE (release event) |
|
||||
* | 1 | RELEASE_DETECTED | PRESSED |
|
||||
* -----------------------------------------------------
|
||||
*
|
||||
*/
|
||||
static app_button_cfg_t const * mp_buttons = NULL; /**< Button configuration. */
|
||||
static uint8_t m_button_count; /**< Number of configured buttons. */
|
||||
static uint32_t m_detection_delay; /**< Delay before a button is reported as pushed. */
|
||||
APP_TIMER_DEF(m_detection_delay_timer_id); /**< Polling timer id. */
|
||||
|
||||
static uint64_t m_pin_active;
|
||||
|
||||
#define BIT_PER_PIN 4
|
||||
#define PINS 32*GPIO_COUNT
|
||||
|
||||
STATIC_ASSERT(BIT_PER_PIN == 4);
|
||||
|
||||
static uint8_t m_pin_states[PINS*BIT_PER_PIN/8];
|
||||
|
||||
typedef enum {
|
||||
BTN_IDLE,
|
||||
BTN_PRESS_ARMED,
|
||||
BTN_PRESS_DETECTED,
|
||||
BTN_PRESSED,
|
||||
BTN_RELEASE_DETECTED
|
||||
} btn_state_t;
|
||||
|
||||
/* Retrieve given pin state. States are stored in pairs (4 bit per pin) in byte array. */
|
||||
static btn_state_t state_get(uint8_t pin)
|
||||
{
|
||||
uint8_t pair_state = m_pin_states[pin >> 1];
|
||||
uint8_t state = (pin & 0x1) ? (pair_state >> BIT_PER_PIN) : (pair_state & 0x0F);
|
||||
|
||||
return (btn_state_t)state;
|
||||
}
|
||||
|
||||
/* Set pin state. */
|
||||
static void state_set(uint8_t pin, btn_state_t state)
|
||||
{
|
||||
uint8_t mask = (pin & 1) ? 0x0F : 0xF0;
|
||||
uint8_t state_mask = (pin & 1) ?
|
||||
((uint8_t)state << BIT_PER_PIN) : (uint8_t)state;
|
||||
m_pin_states[pin >> 1] &= mask;
|
||||
m_pin_states[pin >> 1] |= state_mask;
|
||||
}
|
||||
|
||||
/* Find configuration structure for given pin. */
|
||||
static app_button_cfg_t const * button_get(uint8_t pin)
|
||||
{
|
||||
for (int i = 0; i < m_button_count; i++)
|
||||
{
|
||||
app_button_cfg_t const * p_btn = &mp_buttons[i];
|
||||
if (pin == p_btn->pin_no) {
|
||||
return p_btn;
|
||||
}
|
||||
}
|
||||
|
||||
/* If button is not found then configuration is wrong. */
|
||||
ASSERT(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usr_event(uint8_t pin, uint8_t type)
|
||||
{
|
||||
app_button_cfg_t const * p_btn = button_get(pin);
|
||||
|
||||
if (p_btn && p_btn->button_handler)
|
||||
{
|
||||
NRF_LOG_DEBUG("Pin %d %s", pin, (type == APP_BUTTON_PUSH) ? "pressed" : "released");
|
||||
p_btn->button_handler(pin, type);
|
||||
}
|
||||
}
|
||||
|
||||
/* State machine processing. */
|
||||
void evt_handle(uint8_t pin, uint8_t value)
|
||||
{
|
||||
switch(state_get(pin))
|
||||
{
|
||||
case BTN_IDLE:
|
||||
if (value)
|
||||
{
|
||||
NRF_LOG_DEBUG("Pin %d idle->armed", pin);
|
||||
state_set(pin, BTN_PRESS_ARMED);
|
||||
CRITICAL_REGION_ENTER();
|
||||
m_pin_active |= 1ULL << pin;
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* stay in IDLE */
|
||||
}
|
||||
break;
|
||||
case BTN_PRESS_ARMED:
|
||||
state_set(pin, value ? BTN_PRESS_DETECTED : BTN_IDLE);
|
||||
NRF_LOG_DEBUG("Pin %d armed->%s", pin, value ? "detected" : "idle");
|
||||
break;
|
||||
case BTN_PRESS_DETECTED:
|
||||
if (value)
|
||||
{
|
||||
state_set(pin, BTN_PRESSED);
|
||||
usr_event(pin, APP_BUTTON_PUSH);
|
||||
}
|
||||
else
|
||||
{
|
||||
state_set(pin, BTN_PRESS_ARMED);
|
||||
}
|
||||
NRF_LOG_DEBUG("Pin %d detected->%s", pin, value ? "pressed" : "armed");
|
||||
break;
|
||||
case BTN_PRESSED:
|
||||
if (value == 0)
|
||||
{
|
||||
NRF_LOG_DEBUG("Pin %d pressed->release_detected", pin);
|
||||
state_set(pin, BTN_RELEASE_DETECTED);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* stay in pressed */
|
||||
}
|
||||
break;
|
||||
case BTN_RELEASE_DETECTED:
|
||||
if (value)
|
||||
{
|
||||
state_set(pin, BTN_PRESSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
state_set(pin, BTN_IDLE);
|
||||
usr_event(pin, APP_BUTTON_RELEASE);
|
||||
CRITICAL_REGION_ENTER();
|
||||
m_pin_active &= ~(1ULL << pin);
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
NRF_LOG_DEBUG("Pin %d release_detected->%s", pin, value ? "pressed" : "idle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_start(void)
|
||||
{
|
||||
uint32_t err_code = app_timer_start(m_detection_delay_timer_id, m_detection_delay/2, NULL);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_WARNING("Failed to start app_timer (err:%d)", err_code);
|
||||
}
|
||||
}
|
||||
|
||||
static void detection_delay_timeout_handler(void * p_context)
|
||||
{
|
||||
for (int i = 0; i < m_button_count; i++)
|
||||
{
|
||||
app_button_cfg_t const * p_btn = &mp_buttons[i];
|
||||
bool is_set = nrf_drv_gpiote_in_is_set(p_btn->pin_no);
|
||||
bool is_active = !((p_btn->active_state == APP_BUTTON_ACTIVE_HIGH) ^ is_set);
|
||||
evt_handle(p_btn->pin_no, is_active);
|
||||
}
|
||||
|
||||
if (m_pin_active)
|
||||
{
|
||||
timer_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("No active buttons, stopping timer");
|
||||
}
|
||||
}
|
||||
|
||||
/* GPIOTE event is used only to start periodic timer when first button is activated. */
|
||||
static void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
|
||||
{
|
||||
app_button_cfg_t const * p_btn = button_get(pin);
|
||||
bool is_set = nrf_drv_gpiote_in_is_set(p_btn->pin_no);
|
||||
bool is_active = !((p_btn->active_state == APP_BUTTON_ACTIVE_HIGH) ^ is_set);
|
||||
|
||||
/* If event indicates that pin is active and no other pin is active start the timer. All
|
||||
* action happens in timeout event.
|
||||
*/
|
||||
if (is_active && (m_pin_active == 0))
|
||||
{
|
||||
NRF_LOG_DEBUG("First active button, starting periodic timer");
|
||||
timer_start();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t app_button_init(app_button_cfg_t const * p_buttons,
|
||||
uint8_t button_count,
|
||||
uint32_t detection_delay)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
if (detection_delay < 2*APP_TIMER_MIN_TIMEOUT_TICKS)
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!nrf_drv_gpiote_is_init())
|
||||
{
|
||||
err_code = nrf_drv_gpiote_init();
|
||||
VERIFY_SUCCESS(err_code);
|
||||
}
|
||||
|
||||
/* Save configuration. */
|
||||
mp_buttons = p_buttons;
|
||||
m_button_count = button_count;
|
||||
m_detection_delay = detection_delay;
|
||||
|
||||
memset(m_pin_states, 0, sizeof(m_pin_states));
|
||||
m_pin_active = 0;
|
||||
|
||||
while (button_count--)
|
||||
{
|
||||
app_button_cfg_t const * p_btn = &p_buttons[button_count];
|
||||
|
||||
#if defined(BUTTON_HIGH_ACCURACY_ENABLED) && (BUTTON_HIGH_ACCURACY_ENABLED == 1)
|
||||
nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(p_btn->hi_accuracy);
|
||||
#else
|
||||
nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
|
||||
#endif
|
||||
config.pull = p_btn->pull_cfg;
|
||||
|
||||
err_code = nrf_drv_gpiote_in_init(p_btn->pin_no, &config, gpiote_event_handler);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
}
|
||||
|
||||
/* Create polling timer. */
|
||||
return app_timer_create(&m_detection_delay_timer_id,
|
||||
APP_TIMER_MODE_SINGLE_SHOT,
|
||||
detection_delay_timeout_handler);
|
||||
}
|
||||
|
||||
uint32_t app_button_enable(void)
|
||||
{
|
||||
ASSERT(mp_buttons);
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < m_button_count; i++)
|
||||
{
|
||||
nrf_drv_gpiote_in_event_enable(mp_buttons[i].pin_no, true);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t app_button_disable(void)
|
||||
{
|
||||
ASSERT(mp_buttons);
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < m_button_count; i++)
|
||||
{
|
||||
nrf_drv_gpiote_in_event_disable(mp_buttons[i].pin_no);
|
||||
}
|
||||
CRITICAL_REGION_ENTER();
|
||||
m_pin_active = 0;
|
||||
CRITICAL_REGION_EXIT();
|
||||
|
||||
/* Make sure polling timer is not running. */
|
||||
return app_timer_stop(m_detection_delay_timer_id);
|
||||
}
|
||||
|
||||
|
||||
bool app_button_is_pushed(uint8_t button_id)
|
||||
{
|
||||
ASSERT(button_id <= m_button_count);
|
||||
ASSERT(mp_buttons != NULL);
|
||||
|
||||
app_button_cfg_t const * p_btn = &mp_buttons[button_id];
|
||||
bool is_set = nrf_drv_gpiote_in_is_set(p_btn->pin_no);
|
||||
|
||||
return !(is_set ^ (p_btn->active_state == APP_BUTTON_ACTIVE_HIGH));
|
||||
}
|
||||
#endif //NRF_MODULE_ENABLED(BUTTON)
|
||||
140
components/libraries/button/app_button.h
Normal file
140
components/libraries/button/app_button.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (c) 2012 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
/** @file
|
||||
*
|
||||
* @defgroup app_button Button Handler
|
||||
* @{
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief Buttons handling module.
|
||||
*
|
||||
* @details The button handler uses the @ref app_gpiote to detect that a button has been
|
||||
* pushed. To handle debouncing, it will start a timer in the GPIOTE event handler.
|
||||
* The button will only be reported as pushed if the corresponding pin is still active when
|
||||
* the timer expires. If there is a new GPIOTE event while the timer is running, the timer
|
||||
* is restarted.
|
||||
*
|
||||
* @note The app_button module uses the app_timer module. The user must ensure that the queue in
|
||||
* app_timer is large enough to hold the app_timer_stop() / app_timer_start() operations
|
||||
* which will be executed on each event from GPIOTE module (2 operations), as well as other
|
||||
* app_timer operations queued simultaneously in the application.
|
||||
*
|
||||
* @note Even if the scheduler is not used, app_button.h will include app_scheduler.h, so when
|
||||
* compiling, app_scheduler.h must be available in one of the compiler include paths.
|
||||
*/
|
||||
|
||||
#ifndef APP_BUTTON_H__
|
||||
#define APP_BUTTON_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf.h"
|
||||
#include "app_error.h"
|
||||
#include "nrf_gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define APP_BUTTON_PUSH 1 /**< Indicates that a button is pushed. */
|
||||
#define APP_BUTTON_RELEASE 0 /**< Indicates that a button is released. */
|
||||
#define APP_BUTTON_ACTIVE_HIGH 1 /**< Indicates that a button is active high. */
|
||||
#define APP_BUTTON_ACTIVE_LOW 0 /**< Indicates that a button is active low. */
|
||||
|
||||
/**@brief Button event handler type. */
|
||||
typedef void (*app_button_handler_t)(uint8_t pin_no, uint8_t button_action);
|
||||
|
||||
/**@brief Button configuration structure. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t pin_no; /**< Pin to be used as a button. */
|
||||
uint8_t active_state; /**< APP_BUTTON_ACTIVE_HIGH or APP_BUTTON_ACTIVE_LOW. */
|
||||
#if defined(BUTTON_HIGH_ACCURACY_ENABLED) && (BUTTON_HIGH_ACCURACY_ENABLED == 1)
|
||||
bool hi_accuracy; /**< True if GPIOTE high accuracy (IN_EVENT) is used. */
|
||||
#endif
|
||||
nrf_gpio_pin_pull_t pull_cfg; /**< Pull-up or -down configuration. */
|
||||
app_button_handler_t button_handler; /**< Handler to be called when button is pushed. */
|
||||
} app_button_cfg_t;
|
||||
|
||||
/**@brief Function for initializing the Buttons.
|
||||
*
|
||||
* @details This function will initialize the specified pins as buttons, and configure the Button
|
||||
* Handler module as a GPIOTE user (but it will not enable button detection).
|
||||
*
|
||||
* @note app_button_enable() function must be called in order to enable the button detection.
|
||||
*
|
||||
* @param[in] p_buttons Array of buttons to be used (NOTE: Must be static!).
|
||||
* @param[in] button_count Number of buttons.
|
||||
* @param[in] detection_delay Delay from a GPIOTE event until a button is reported as pushed.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
uint32_t app_button_init(app_button_cfg_t const * p_buttons,
|
||||
uint8_t button_count,
|
||||
uint32_t detection_delay);
|
||||
|
||||
/**@brief Function for enabling button detection.
|
||||
*
|
||||
* @retval NRF_SUCCESS Module successfully enabled.
|
||||
*/
|
||||
uint32_t app_button_enable(void);
|
||||
|
||||
/**@brief Function for disabling button detection.
|
||||
*
|
||||
* @retval NRF_SUCCESS Button detection successfully disabled. Error code otherwise.
|
||||
*/
|
||||
uint32_t app_button_disable(void);
|
||||
|
||||
/**@brief Function for checking if a button is currently being pushed.
|
||||
*
|
||||
* @param[in] button_id Button index (in the app_button_cfg_t array given to app_button_init) to be checked.
|
||||
*
|
||||
* @return Button state.
|
||||
*/
|
||||
bool app_button_is_pushed(uint8_t button_id);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // APP_BUTTON_H__
|
||||
|
||||
/** @} */
|
||||
317
components/libraries/cli/ble_uart/nrf_cli_ble_uart.c
Normal file
317
components/libraries/cli/ble_uart/nrf_cli_ble_uart.c
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_BLE_UART)
|
||||
#include "nrf_cli_ble_uart.h"
|
||||
#include "ble_nus.h"
|
||||
#include "nrf_ringbuf.h"
|
||||
#include "app_timer.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "nrf_ble_gatt.h"
|
||||
#define NRF_LOG_MODULE_NAME cli_ble
|
||||
|
||||
#if NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_CLI_BLE_UART_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_CLI_BLE_UART_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_CLI_BLE_UART_CONFIG_DEBUG_COLOR
|
||||
|
||||
#else //NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif //NRF_CLI_BLE_UART_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#if NRF_CLI_BLE_UART_MAX_CLIENTS > NRF_SDH_BLE_TOTAL_LINK_COUNT
|
||||
#error "Too few BLE peripheral links are supported by the BLE SDH module for the maximal number \
|
||||
of BLE transport instances"
|
||||
#endif
|
||||
|
||||
#define NRF_CLI_BLE_UART_TIMEOUT_MS 50
|
||||
#define OVERHEAD_LENGTH (OPCODE_LENGTH + HANDLE_LENGTH)
|
||||
|
||||
BLE_NUS_DEF(m_nus, NRF_CLI_BLE_UART_MAX_CLIENTS);
|
||||
BLE_LINK_CTX_MANAGER_DEF(m_link_ctx_storage,
|
||||
NRF_CLI_BLE_UART_MAX_CLIENTS,
|
||||
sizeof(nrf_cli_ble_uart_internal_t *));
|
||||
|
||||
static void tx_try(nrf_cli_ble_uart_internal_t * p_instance, uint32_t threshold)
|
||||
{
|
||||
uint8_t * p_out_data;
|
||||
size_t out_data_len =
|
||||
nrf_ble_gatt_eff_mtu_get(p_instance->p_gatt, p_instance->p_cb->conn_handle) -
|
||||
OVERHEAD_LENGTH;
|
||||
|
||||
ret_code_t err_code = nrf_ringbuf_get(p_instance->p_tx_ringbuf,
|
||||
&p_out_data,
|
||||
&out_data_len,
|
||||
true);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
if (out_data_len >= threshold)
|
||||
{
|
||||
size_t req_data_len = out_data_len;
|
||||
err_code = ble_nus_data_send(&m_nus,
|
||||
p_out_data,
|
||||
(uint16_t*)&out_data_len,
|
||||
p_instance->p_cb->conn_handle);
|
||||
|
||||
if ((err_code == NRF_ERROR_BUSY) || (err_code == NRF_ERROR_RESOURCES))
|
||||
{
|
||||
out_data_len = 0;
|
||||
}
|
||||
NRF_LOG_INFO("Conn_handle:%d TX req_len: %d, len: %d",
|
||||
p_instance->p_cb->conn_handle, req_data_len, out_data_len);
|
||||
NRF_LOG_HEXDUMP_DEBUG(p_out_data, out_data_len);
|
||||
err_code = nrf_ringbuf_free(p_instance->p_tx_ringbuf, out_data_len);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = nrf_ringbuf_free(p_instance->p_tx_ringbuf, 0);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void nus_data_handler(ble_nus_evt_t * p_nus_evt)
|
||||
{
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
nrf_cli_ble_uart_internal_t * p_instance;
|
||||
nrf_cli_ble_uart_internal_t ** pp_instance;
|
||||
|
||||
err_code = blcm_link_ctx_get(&m_link_ctx_storage, p_nus_evt->conn_handle, (void *) &pp_instance);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
|
||||
p_instance = *pp_instance;
|
||||
|
||||
switch (p_nus_evt->type)
|
||||
{
|
||||
case BLE_NUS_EVT_RX_DATA:
|
||||
{
|
||||
NRF_LOG_INFO("Conn_handle:%d, Received: %d",
|
||||
p_instance->p_cb->conn_handle, p_nus_evt->params.rx_data.length);
|
||||
NRF_LOG_HEXDUMP_DEBUG(p_nus_evt->params.rx_data.p_data, p_nus_evt->params.rx_data.length);
|
||||
size_t len = ((size_t) p_nus_evt->params.rx_data.length) & 0x0000FFFF;
|
||||
err_code = nrf_ringbuf_cpy_put(p_instance->p_rx_ringbuf,
|
||||
p_nus_evt->params.rx_data.p_data,
|
||||
(size_t *)&len);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
|
||||
p_instance->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY, p_instance->p_cb->p_context);
|
||||
break;
|
||||
}
|
||||
case BLE_NUS_EVT_TX_RDY:
|
||||
{
|
||||
//TX_Complete
|
||||
uint32_t max_tx_len = nrf_ble_gatt_eff_mtu_get(p_instance->p_gatt,
|
||||
p_instance->p_cb->conn_handle) -
|
||||
OVERHEAD_LENGTH;
|
||||
tx_try(p_instance, max_tx_len);
|
||||
p_instance->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_instance->p_cb->p_context);
|
||||
break;
|
||||
}
|
||||
case BLE_NUS_EVT_COMM_STARTED:
|
||||
p_instance->p_cb->service_started = true;
|
||||
err_code = app_timer_start(*p_instance->p_timer,
|
||||
APP_TIMER_TICKS(NRF_CLI_BLE_UART_TIMEOUT_MS),
|
||||
p_instance);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
NRF_LOG_INFO("Conn_handle:%d, communication started", p_instance->p_cb->conn_handle);
|
||||
break;
|
||||
case BLE_NUS_EVT_COMM_STOPPED:
|
||||
(void)app_timer_stop(*p_instance->p_timer);
|
||||
p_instance->p_cb->service_started = false;
|
||||
NRF_LOG_INFO("Conn_handle:%d, communication stopped", p_instance->p_cb->conn_handle);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_handler(void * p_context)
|
||||
{
|
||||
nrf_cli_ble_uart_internal_t * p_instance = (nrf_cli_ble_uart_internal_t *) p_context;
|
||||
tx_try(p_instance, 1);
|
||||
|
||||
ret_code_t err_code = app_timer_start(*p_instance->p_timer,
|
||||
APP_TIMER_TICKS(NRF_CLI_BLE_UART_TIMEOUT_MS), (void *)p_instance);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
UNUSED_VARIABLE(err_code);
|
||||
UNUSED_PARAMETER(p_context);
|
||||
}
|
||||
|
||||
ret_code_t nrf_cli_ble_uart_service_init(void)
|
||||
{
|
||||
ble_nus_init_t nus_init;
|
||||
|
||||
memset(&nus_init, 0, sizeof(nus_init));
|
||||
nus_init.data_handler = nus_data_handler;
|
||||
|
||||
return ble_nus_init(&m_nus, &nus_init);
|
||||
}
|
||||
|
||||
static ret_code_t cli_ble_uart_init(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_config,
|
||||
nrf_cli_transport_handler_t evt_handler,
|
||||
void * p_context)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
nrf_cli_ble_uart_internal_t ** pp_instance;
|
||||
nrf_cli_ble_uart_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
|
||||
nrf_cli_ble_uart_config_t * p_ble_uart_config = (nrf_cli_ble_uart_config_t *)p_config;
|
||||
|
||||
p_instance->p_cb->handler = evt_handler;
|
||||
p_instance->p_cb->p_context = p_context;
|
||||
p_instance->p_cb->service_started = false;
|
||||
p_instance->p_cb->conn_handle = p_ble_uart_config->conn_handle;
|
||||
|
||||
NRF_LOG_INFO("Conn_handle:%d init.", p_ble_uart_config->conn_handle);
|
||||
nrf_ringbuf_init(p_instance->p_rx_ringbuf);
|
||||
nrf_ringbuf_init(p_instance->p_tx_ringbuf);
|
||||
|
||||
err_code = blcm_link_ctx_get(&m_link_ctx_storage,
|
||||
p_ble_uart_config->conn_handle,
|
||||
(void *) &pp_instance);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
*pp_instance = p_instance;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_ble_uart_uninit(nrf_cli_transport_t const * p_transport)
|
||||
{
|
||||
nrf_cli_ble_uart_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
|
||||
|
||||
NRF_LOG_INFO("Conn_handle:%d uninit.", p_instance->p_cb->conn_handle);
|
||||
ret_code_t ret = app_timer_stop(*p_instance->p_timer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ret_code_t cli_ble_uart_enable(nrf_cli_transport_t const * p_transport, bool blocking)
|
||||
{
|
||||
nrf_cli_ble_uart_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
|
||||
|
||||
|
||||
NRF_LOG_INFO("Conn_handle:%d, enable blocking:%d", blocking, p_instance->p_cb->conn_handle);
|
||||
if (blocking)
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
if (!p_instance->p_cb->timer_created)
|
||||
{
|
||||
err_code = app_timer_create(p_instance->p_timer,
|
||||
APP_TIMER_MODE_SINGLE_SHOT,
|
||||
timer_handler);
|
||||
p_instance->p_cb->timer_created = true;
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
static ret_code_t cli_ble_uart_read(nrf_cli_transport_t const * p_transport,
|
||||
void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
nrf_cli_ble_uart_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
|
||||
*p_cnt = length;
|
||||
ret_code_t err_code = nrf_ringbuf_cpy_get(p_instance->p_rx_ringbuf, p_data, p_cnt);
|
||||
|
||||
if (*p_cnt)
|
||||
{
|
||||
NRF_LOG_INFO("Conn_handle:%d, read req_len:%d read_len: %d",
|
||||
p_instance->p_cb->conn_handle,
|
||||
length,
|
||||
*p_cnt);
|
||||
NRF_LOG_HEXDUMP_DEBUG(p_data, *p_cnt);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t cli_ble_uart_write(nrf_cli_transport_t const * p_transport,
|
||||
const void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
nrf_cli_ble_uart_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, nrf_cli_ble_uart_internal_t, transport);
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
if (p_instance->p_cb->service_started)
|
||||
{
|
||||
*p_cnt = length;
|
||||
err_code = nrf_ringbuf_cpy_put(p_instance->p_tx_ringbuf, p_data, p_cnt);
|
||||
|
||||
NRF_LOG_INFO("Conn_handle:%d, write req:%d, buffered:%d",
|
||||
p_instance->p_cb->conn_handle, length, *p_cnt);
|
||||
NRF_LOG_HEXDUMP_DEBUG(p_data, *p_cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_INFO("Conn_handle:%d, write req:%d. Notifications not enabled",
|
||||
p_instance->p_cb->conn_handle, length);
|
||||
*p_cnt = length;
|
||||
p_instance->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_instance->p_cb->p_context);
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
|
||||
const nrf_cli_transport_api_t nrf_cli_ble_uart_transport_api = {
|
||||
.init = cli_ble_uart_init,
|
||||
.uninit = cli_ble_uart_uninit,
|
||||
.enable = cli_ble_uart_enable,
|
||||
.read = cli_ble_uart_read,
|
||||
.write = cli_ble_uart_write,
|
||||
};
|
||||
|
||||
#endif //NRF_MODULE_ENABLED(NRF_CLI_BLE_UART)
|
||||
123
components/libraries/cli/ble_uart/nrf_cli_ble_uart.h
Normal file
123
components/libraries/cli/ble_uart/nrf_cli_ble_uart.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_CLI_BLE_UART_H__
|
||||
#define NRF_CLI_BLE_UART_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nrf_cli.h"
|
||||
#include "ble.h"
|
||||
#include "app_timer.h"
|
||||
#include "nrf_ringbuf.h"
|
||||
#include "nordic_common.h"
|
||||
#include "nrf_ble_gatt.h"
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_cli_ble_uart BLE UART command line interface transport layer
|
||||
* @ingroup nrf_cli
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Command line interface transport.
|
||||
*/
|
||||
|
||||
ret_code_t nrf_cli_ble_uart_service_init(void);
|
||||
|
||||
extern const nrf_cli_transport_api_t nrf_cli_ble_uart_transport_api;
|
||||
|
||||
typedef struct nrf_cli_ble_uart_internal_s nrf_cli_ble_uart_internal_t;
|
||||
|
||||
typedef struct {
|
||||
nrf_cli_transport_handler_t handler;
|
||||
void * p_context;
|
||||
uint16_t conn_handle;
|
||||
bool timer_created;
|
||||
bool service_started;
|
||||
} nrf_cli_ble_uart_internal_cb_t;
|
||||
|
||||
|
||||
struct nrf_cli_ble_uart_internal_s {
|
||||
nrf_cli_transport_t transport;
|
||||
nrf_cli_ble_uart_internal_cb_t * p_cb;
|
||||
app_timer_id_t const * p_timer;
|
||||
nrf_ringbuf_t const * p_rx_ringbuf;
|
||||
nrf_ringbuf_t const * p_tx_ringbuf;
|
||||
nrf_ble_gatt_t const * p_gatt;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint16_t conn_handle;
|
||||
} nrf_cli_ble_uart_config_t;
|
||||
|
||||
/**@brief CLI Bluetooth transport definition.
|
||||
*
|
||||
* @param _name Name of the instance.
|
||||
* @param _p_gatt Pointer to the nrf_ble_gatt module.
|
||||
* @param _tx_buf_sz Size of TX ring buffer.
|
||||
* @param _rx_buf_sz Size of RX ring buffer.
|
||||
*/
|
||||
#define NRF_CLI_BLE_UART_DEF(_name, _p_gatt, _tx_buf_sz, _rx_buf_sz) \
|
||||
APP_TIMER_DEF(CONCAT_2(_name, _timer)); \
|
||||
NRF_RINGBUF_DEF(CONCAT_2(_name,_tx_ringbuf), _tx_buf_sz); \
|
||||
NRF_RINGBUF_DEF(CONCAT_2(_name,_rx_ringbuf), _rx_buf_sz); \
|
||||
static nrf_cli_ble_uart_internal_cb_t CONCAT_2(_name, _cb); \
|
||||
static const nrf_cli_ble_uart_internal_t _name = { \
|
||||
.transport = {.p_api = &nrf_cli_ble_uart_transport_api}, \
|
||||
.p_cb = &CONCAT_2(_name, _cb), \
|
||||
.p_timer = &CONCAT_2(_name, _timer), \
|
||||
.p_rx_ringbuf = &CONCAT_2(_name,_rx_ringbuf), \
|
||||
.p_tx_ringbuf = &CONCAT_2(_name,_tx_ringbuf), \
|
||||
.p_gatt = _p_gatt, \
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_CLI_BLE_UART_H__ */
|
||||
243
components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.c
Normal file
243
components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_CDC_ACM)
|
||||
#include "nrf_cli_cdc_acm.h"
|
||||
#include "nrf_queue.h"
|
||||
#include "app_error.h"
|
||||
#include "nrf_assert.h"
|
||||
|
||||
|
||||
#if APP_USBD_CONFIG_EVENT_QUEUE_ENABLE
|
||||
#error "Current CLI CDC implementation supports only USB with event queue disabled (see APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)"
|
||||
#endif
|
||||
|
||||
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
|
||||
app_usbd_cdc_acm_user_event_t event);
|
||||
|
||||
/*lint -save -e26 -e40 -e64 -e123 -e505 -e651*/
|
||||
|
||||
/**
|
||||
* @brief CDC_ACM class instance.
|
||||
* */
|
||||
APP_USBD_CDC_ACM_GLOBAL_DEF(nrf_cli_cdc_acm,
|
||||
cdc_acm_user_ev_handler,
|
||||
NRF_CLI_CDC_ACM_COMM_INTERFACE,
|
||||
NRF_CLI_CDC_ACM_DATA_INTERFACE,
|
||||
NRF_CLI_CDC_ACM_COMM_EPIN,
|
||||
NRF_CLI_CDC_ACM_DATA_EPIN,
|
||||
NRF_CLI_CDC_ACM_DATA_EPOUT,
|
||||
APP_USBD_CDC_COMM_PROTOCOL_AT_V250
|
||||
);
|
||||
|
||||
/*lint -restore*/
|
||||
|
||||
NRF_QUEUE_DEF(uint8_t,
|
||||
m_rx_queue,
|
||||
2*NRF_DRV_USBD_EPSIZE,
|
||||
NRF_QUEUE_MODE_OVERFLOW);
|
||||
|
||||
static char m_rx_buffer[NRF_DRV_USBD_EPSIZE];
|
||||
|
||||
static nrf_cli_cdc_acm_internal_t * mp_internal;
|
||||
|
||||
/**
|
||||
* @brief Set new buffer and process any data if already present
|
||||
*
|
||||
* This is internal function.
|
||||
* The result of its execution is the library waiting for the event of the new data.
|
||||
* If there is already any data that was returned from the CDC internal buffer
|
||||
* it would be processed here.
|
||||
*/
|
||||
static void cdc_acm_process_and_prepare_buffer(app_usbd_cdc_acm_t const * p_cdc_acm)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (!nrf_queue_is_empty(&m_rx_queue))
|
||||
{
|
||||
mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY, mp_internal->p_cb->p_context);
|
||||
}
|
||||
ret_code_t ret = app_usbd_cdc_acm_read_any(&nrf_cli_cdc_acm,
|
||||
m_rx_buffer,
|
||||
sizeof(m_rx_buffer));
|
||||
if (ret == NRF_SUCCESS)
|
||||
{
|
||||
size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
|
||||
size_t qsize = nrf_queue_in(&m_rx_queue, m_rx_buffer, size);
|
||||
ASSERT(size == qsize);
|
||||
UNUSED_VARIABLE(qsize);
|
||||
}
|
||||
else if (ret == NRF_ERROR_IO_PENDING)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
APP_ERROR_CHECK(ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief User event handler.
|
||||
* */
|
||||
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
|
||||
app_usbd_cdc_acm_user_event_t event)
|
||||
{
|
||||
app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
|
||||
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
|
||||
{
|
||||
/*Setup first transfer*/
|
||||
cdc_acm_process_and_prepare_buffer(p_cdc_acm);
|
||||
break;
|
||||
}
|
||||
case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
|
||||
mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, mp_internal->p_cb->p_context);
|
||||
break;
|
||||
case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
|
||||
mp_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, mp_internal->p_cb->p_context);
|
||||
break;
|
||||
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
|
||||
{
|
||||
/*Get amount of data transfered*/
|
||||
size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
|
||||
size_t qsize = nrf_queue_in(&m_rx_queue, m_rx_buffer, size);
|
||||
ASSERT(size == qsize);
|
||||
UNUSED_VARIABLE(qsize);
|
||||
|
||||
/*Setup next transfer*/
|
||||
cdc_acm_process_and_prepare_buffer(p_cdc_acm);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ret_code_t cli_cdc_acm_init(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_config,
|
||||
nrf_cli_transport_handler_t evt_handler,
|
||||
void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_config);
|
||||
nrf_cli_cdc_acm_internal_t * p_internal =
|
||||
CONTAINER_OF(p_transport, nrf_cli_cdc_acm_internal_t, transport);
|
||||
p_internal->p_cb->handler = evt_handler;
|
||||
p_internal->p_cb->p_context = p_context;
|
||||
|
||||
mp_internal = p_internal;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_cdc_acm_uninit(nrf_cli_transport_t const * p_transport)
|
||||
{
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_cdc_acm_enable(nrf_cli_transport_t const * p_transport,
|
||||
bool blocking)
|
||||
{
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
if (blocking)
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static ret_code_t cli_cdc_acm_read(nrf_cli_transport_t const * p_transport,
|
||||
void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
size_t size = nrf_queue_out(&m_rx_queue, p_data, length);
|
||||
*p_cnt = size;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_cdc_acm_write(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
ret_code_t ret;
|
||||
|
||||
ret = app_usbd_cdc_acm_write(&nrf_cli_cdc_acm, p_data, length);
|
||||
if (ret == NRF_SUCCESS || ret == NRF_ERROR_INVALID_STATE)
|
||||
{
|
||||
*p_cnt = length;
|
||||
ret = NRF_SUCCESS;
|
||||
}
|
||||
else if (ret == NRF_ERROR_BUSY)
|
||||
{
|
||||
*p_cnt = 0;
|
||||
ret = NRF_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const nrf_cli_transport_api_t nrf_cli_cdc_acm_transport_api = {
|
||||
.init = cli_cdc_acm_init,
|
||||
.uninit = cli_cdc_acm_uninit,
|
||||
.enable = cli_cdc_acm_enable,
|
||||
.read = cli_cdc_acm_read,
|
||||
.write = cli_cdc_acm_write,
|
||||
};
|
||||
|
||||
#endif // NRF_MODULE_ENABLED(NRF_CLI_CDC_ACM)
|
||||
95
components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.h
Normal file
95
components/libraries/cli/cdc_acm/nrf_cli_cdc_acm.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_CLI_CDC_ACM_H__
|
||||
#define NRF_CLI_CDC_ACM_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nrf_cli.h"
|
||||
#include "app_usbd_cdc_acm.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_cli_cdc_acm CDC ACM command line interface transport layer
|
||||
* @ingroup nrf_cli
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Command line interface transport.
|
||||
*/
|
||||
extern const nrf_cli_transport_api_t nrf_cli_cdc_acm_transport_api;
|
||||
|
||||
/**
|
||||
* @brief Command line interface class instance.
|
||||
*/
|
||||
extern const app_usbd_cdc_acm_t nrf_cli_cdc_acm;
|
||||
|
||||
typedef struct {
|
||||
nrf_cli_transport_handler_t handler;
|
||||
void * p_context;
|
||||
} nrf_cli_cdc_acm_internal_cb_t;
|
||||
|
||||
typedef struct {
|
||||
nrf_cli_transport_t transport;
|
||||
nrf_cli_cdc_acm_internal_cb_t * p_cb;
|
||||
} nrf_cli_cdc_acm_internal_t;
|
||||
|
||||
/**@brief CLI USB transport definition */
|
||||
#define NRF_CLI_CDC_ACM_DEF(_name_) \
|
||||
static nrf_cli_cdc_acm_internal_cb_t CONCAT_2(_name_, _cb); \
|
||||
static const nrf_cli_cdc_acm_internal_t _name_ = { \
|
||||
.transport = {.p_api = &nrf_cli_cdc_acm_transport_api}, \
|
||||
.p_cb = &CONCAT_2(_name_, _cb), \
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_CLI_CDC_ACM_H__ */
|
||||
164
components/libraries/cli/cli_utils_cmds.c
Normal file
164
components/libraries/cli/cli_utils_cmds.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "nrf_cli.h"
|
||||
#include "nrf_log.h"
|
||||
|
||||
static void cmd_reset(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
UNUSED_PARAMETER(argc);
|
||||
UNUSED_PARAMETER(argv);
|
||||
|
||||
if (nrf_cli_help_requested(p_cli))
|
||||
{
|
||||
nrf_cli_help_print(p_cli, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
|
||||
static void cmd_error(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
UNUSED_PARAMETER(argc);
|
||||
UNUSED_PARAMETER(argv);
|
||||
|
||||
if (nrf_cli_help_requested(p_cli))
|
||||
{
|
||||
nrf_cli_help_print(p_cli, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
|
||||
static void cmd_app_size(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
UNUSED_PARAMETER(argc);
|
||||
UNUSED_PARAMETER(argv);
|
||||
|
||||
if (nrf_cli_help_requested(p_cli))
|
||||
{
|
||||
nrf_cli_help_print(p_cli, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
nrf_cli_fprintf(p_cli,
|
||||
NRF_CLI_NORMAL,
|
||||
"Application address:%d (0x%08X), size: %d (0x%08X)\r\n",
|
||||
CODE_START,
|
||||
CODE_START,
|
||||
CODE_SIZE,
|
||||
CODE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
static void cmd_log_msg_error(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
if (nrf_cli_help_requested(p_cli))
|
||||
{
|
||||
nrf_cli_help_print(p_cli, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (argc-1)
|
||||
{
|
||||
case 0:
|
||||
NRF_LOG_ERROR("test error message");
|
||||
break;
|
||||
case 1:
|
||||
NRF_LOG_ERROR("test error message: %d", strtol(argv[1], NULL, 10));
|
||||
break;
|
||||
case 2:
|
||||
NRF_LOG_ERROR("test error message: %d %d", strtol(argv[1], NULL, 10),
|
||||
strtol(argv[2], NULL, 10));
|
||||
break;
|
||||
default:
|
||||
NRF_LOG_ERROR("test error message with more than 3 arguments");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void cmd_log_msg_warning(nrf_cli_t const * p_cli, size_t argc, char **argv)
|
||||
{
|
||||
if (nrf_cli_help_requested(p_cli))
|
||||
{
|
||||
nrf_cli_help_print(p_cli, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (argc-1)
|
||||
{
|
||||
case 0:
|
||||
NRF_LOG_WARNING("test warning message");
|
||||
break;
|
||||
case 1:
|
||||
NRF_LOG_WARNING("test warning message: %d", strtol(argv[1], NULL, 10));
|
||||
break;
|
||||
case 2:
|
||||
NRF_LOG_WARNING("test warning message: %d %d", strtol(argv[1], NULL, 10),
|
||||
strtol(argv[2], NULL, 10));
|
||||
break;
|
||||
default:
|
||||
NRF_LOG_WARNING("test warning message with more than 3 arguments");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Command set array
|
||||
* */
|
||||
|
||||
NRF_CLI_CMD_REGISTER(reset, NULL, "System reset.", cmd_reset);
|
||||
|
||||
NRF_CLI_CMD_REGISTER(error, NULL, "Trigger error.", cmd_error);
|
||||
|
||||
NRF_CLI_CMD_REGISTER(app_size, NULL, "Print application size.", cmd_app_size);
|
||||
|
||||
NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_log_msg)
|
||||
{
|
||||
NRF_CLI_CMD(error, NULL, "Error log message with parameters", cmd_log_msg_error),
|
||||
NRF_CLI_CMD(warning, NULL, "Warning log message with parameters", cmd_log_msg_warning),
|
||||
NRF_CLI_SUBCMD_SET_END
|
||||
};
|
||||
|
||||
NRF_CLI_CMD_REGISTER(log_msg, &m_sub_log_msg, "Trigger log message with decimal arguments", NULL);
|
||||
252
components/libraries/cli/libuarte/nrf_cli_libuarte.c
Normal file
252
components/libraries/cli/libuarte/nrf_cli_libuarte.c
Normal file
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#include "nrf_cli_libuarte.h"
|
||||
#include "nrf_libuarte_async.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "nrf_atomic.h"
|
||||
#define NRF_LOG_MODULE_NAME cli_libuarte
|
||||
#if NRF_CLI_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_CLI_LIBUARTE_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_CLI_LIBUARTE_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_CLI_LIBUARTE_CONFIG_DEBUG_COLOR
|
||||
#else //NRF_CLI_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif //NRF_CLI_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
static cli_libuarte_internal_t * mp_internal;
|
||||
static nrf_atomic_flag_t m_uart_busy;
|
||||
|
||||
NRF_LIBUARTE_ASYNC_DEFINE(libuarte,
|
||||
NRF_CLI_LIBUARTE_UARTE_INSTANCE,
|
||||
NRF_CLI_LIBUARTE_TIMER_INSTANCE,
|
||||
NRF_CLI_LIBUARTE_TIMEOUT_RTC_INSTANCE,
|
||||
NRF_CLI_LIBUARTE_TIMEOUT_TIMER_INSTANCE,
|
||||
3, 255);
|
||||
|
||||
static void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_event)
|
||||
{
|
||||
cli_libuarte_internal_t * p_internal = mp_internal;
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
size_t len;
|
||||
UNUSED_VARIABLE(err_code);
|
||||
switch (p_event->type)
|
||||
{
|
||||
case NRF_LIBUARTE_ASYNC_EVT_ERROR:
|
||||
NRF_LOG_WARNING("(evt) ERROR");
|
||||
|
||||
break;
|
||||
|
||||
case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
|
||||
{
|
||||
len = (size_t)((uint32_t)p_event->data.rxtx.length & 0x0000FFFF);
|
||||
err_code = nrf_ringbuf_cpy_put(p_internal->p_rx_ringbuf,
|
||||
p_event->data.rxtx.p_data,
|
||||
&len);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
|
||||
if (len != p_event->data.rxtx.length)
|
||||
{
|
||||
NRF_LOG_WARNING("Data lost, no room in RX ringbuf");
|
||||
}
|
||||
nrf_libuarte_async_rx_free(&libuarte, p_event->data.rxtx.p_data, p_event->data.rxtx.length);
|
||||
|
||||
if (p_event->data.rxtx.length)
|
||||
{
|
||||
NRF_LOG_DEBUG("(evt) RXRDY length:%d", p_event->data.rxtx.length);
|
||||
NRF_LOG_HEXDUMP_DEBUG(p_event->data.rxtx.p_data, p_event->data.rxtx.length);
|
||||
p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY,
|
||||
p_internal->p_cb->p_context);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
|
||||
err_code = nrf_ringbuf_free(p_internal->p_tx_ringbuf, p_event->data.rxtx.length);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
uint8_t * p_data;
|
||||
len = 255;
|
||||
err_code = nrf_ringbuf_get(p_internal->p_tx_ringbuf, &p_data, &len, true);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
if (len)
|
||||
{
|
||||
NRF_LOG_DEBUG("(evt) Started TX (%d).", len);
|
||||
err_code = nrf_libuarte_async_tx(&libuarte, p_data, len);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uart_busy = false;
|
||||
}
|
||||
p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_internal->p_cb->p_context);
|
||||
NRF_LOG_DEBUG("(evt) TX completed (%d)", p_event->data.rxtx.length);
|
||||
break;
|
||||
|
||||
default:
|
||||
NRF_LOG_ERROR("(evt) Unknown event");
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ret_code_t cli_libuarte_init(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_config,
|
||||
nrf_cli_transport_handler_t evt_handler,
|
||||
void * p_context)
|
||||
{
|
||||
cli_libuarte_internal_t * p_internal = CONTAINER_OF(p_transport,
|
||||
cli_libuarte_internal_t,
|
||||
transport);
|
||||
mp_internal = p_internal;
|
||||
m_uart_busy = false;
|
||||
|
||||
p_internal->p_cb->handler = evt_handler;
|
||||
p_internal->p_cb->p_context = p_context;
|
||||
p_internal->p_cb->blocking = false;
|
||||
|
||||
cli_libuarte_config_t const * p_cli_libuarte_config = (cli_libuarte_config_t *)p_config;
|
||||
nrf_libuarte_async_config_t uart_async_config = {
|
||||
.tx_pin = p_cli_libuarte_config->tx_pin,
|
||||
.rx_pin = p_cli_libuarte_config->rx_pin,
|
||||
.baudrate = p_cli_libuarte_config->baudrate,
|
||||
.parity = p_cli_libuarte_config->parity,
|
||||
.hwfc = p_cli_libuarte_config->hwfc,
|
||||
.timeout_us = 100,
|
||||
.int_prio = APP_IRQ_PRIORITY_LOW
|
||||
};
|
||||
ret_code_t err_code = nrf_libuarte_async_init(&libuarte, &uart_async_config, uart_event_handler, NULL);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
nrf_ringbuf_init(p_internal->p_rx_ringbuf);
|
||||
nrf_ringbuf_init(p_internal->p_tx_ringbuf);
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t cli_libuarte_uninit(nrf_cli_transport_t const * p_transport)
|
||||
{
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
nrf_libuarte_async_uninit(&libuarte);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_libuarte_enable(nrf_cli_transport_t const * p_transport,
|
||||
bool blocking)
|
||||
{
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
if (blocking)
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
nrf_libuarte_async_enable(&libuarte);
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_libuarte_read(nrf_cli_transport_t const * p_transport,
|
||||
void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
cli_libuarte_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, cli_libuarte_internal_t, transport);
|
||||
|
||||
*p_cnt = length;
|
||||
ret_code_t err_code = nrf_ringbuf_cpy_get(p_instance->p_rx_ringbuf, p_data, p_cnt);
|
||||
|
||||
if (*p_cnt)
|
||||
{
|
||||
NRF_LOG_DEBUG("Read %d bytes (requested %d)", *p_cnt, length);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t cli_libuarte_write(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
cli_libuarte_internal_t * p_instance = CONTAINER_OF(p_transport,
|
||||
cli_libuarte_internal_t,
|
||||
transport);
|
||||
*p_cnt = length;
|
||||
ret_code_t err_code = nrf_ringbuf_cpy_put(p_instance->p_tx_ringbuf, p_data, p_cnt);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_DEBUG("Requested write: %d, copied to ringbuf: %d.", length, *p_cnt);
|
||||
|
||||
if (nrf_atomic_flag_set_fetch(&m_uart_busy))
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
|
||||
uint8_t * p_buf;
|
||||
size_t len = 255;
|
||||
if (nrf_ringbuf_get(p_instance->p_tx_ringbuf, &p_buf, &len, true) == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_DEBUG("Started TX (%d).", len);
|
||||
|
||||
err_code = nrf_libuarte_async_tx(&libuarte, p_buf, len);
|
||||
if (p_instance->p_cb->blocking && (err_code == NRF_SUCCESS))
|
||||
{
|
||||
(void)nrf_ringbuf_free(p_instance->p_tx_ringbuf, len);
|
||||
m_uart_busy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
|
||||
const nrf_cli_transport_api_t cli_libuarte_transport_api = {
|
||||
.init = cli_libuarte_init,
|
||||
.uninit = cli_libuarte_uninit,
|
||||
.enable = cli_libuarte_enable,
|
||||
.read = cli_libuarte_read,
|
||||
.write = cli_libuarte_write,
|
||||
};
|
||||
|
||||
112
components/libraries/cli/libuarte/nrf_cli_libuarte.h
Normal file
112
components/libraries/cli/libuarte/nrf_cli_libuarte.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_LOG_BACKEND_LIBUARTE_H__
|
||||
#define NRF_LOG_BACKEND_LIBUARTE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nrf_cli.h"
|
||||
#include "nrf_ringbuf.h"
|
||||
#include "app_timer.h"
|
||||
#include "nrf_uarte.h"
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_cli_libuarte libUARTE command line interface transport layer.
|
||||
* @ingroup nrf_cli
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Command line interface transport.
|
||||
* */
|
||||
extern const nrf_cli_transport_api_t cli_libuarte_transport_api;
|
||||
|
||||
typedef struct cli_libuarte_internal_s cli_libuarte_internal_t;
|
||||
|
||||
typedef struct {
|
||||
nrf_cli_transport_handler_t handler;
|
||||
void * p_context;
|
||||
bool blocking;
|
||||
} cli_libuarte_internal_cb_t;
|
||||
|
||||
struct cli_libuarte_internal_s {
|
||||
nrf_cli_transport_t transport;
|
||||
cli_libuarte_internal_cb_t * p_cb;
|
||||
nrf_ringbuf_t const * p_rx_ringbuf;
|
||||
nrf_ringbuf_t const * p_tx_ringbuf;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t tx_pin;
|
||||
uint32_t rx_pin;
|
||||
nrf_uarte_hwfc_t hwfc; ///< Flow control configuration.
|
||||
nrf_uarte_parity_t parity; ///< Parity configuration.
|
||||
nrf_uarte_baudrate_t baudrate; ///< Baudrate.
|
||||
} cli_libuarte_config_t;
|
||||
|
||||
/**@brief CLI libUARTE transport definition.
|
||||
*
|
||||
* @param _name Name of instance.
|
||||
* @param _tx_buf_sz Size of TX ring buffer.
|
||||
* @param _rx_buf_sz Size of RX ring buffer.
|
||||
*/
|
||||
#define NRF_CLI_LIBUARTE_DEF(_name, _tx_buf_sz, _rx_buf_sz) \
|
||||
NRF_RINGBUF_DEF(CONCAT_2(_name,_tx_ringbuf), _tx_buf_sz); \
|
||||
NRF_RINGBUF_DEF(CONCAT_2(_name,_rx_ringbuf), _rx_buf_sz); \
|
||||
static cli_libuarte_internal_cb_t CONCAT_2(_name, _cb); \
|
||||
static const cli_libuarte_internal_t _name = { \
|
||||
.transport = {.p_api = &cli_libuarte_transport_api}, \
|
||||
.p_cb = &CONCAT_2(_name, _cb), \
|
||||
.p_rx_ringbuf = &CONCAT_2(_name,_rx_ringbuf), \
|
||||
.p_tx_ringbuf = &CONCAT_2(_name,_tx_ringbuf), \
|
||||
}
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_LOG_BACKEND_LIBUARTE_H__ */
|
||||
3700
components/libraries/cli/nrf_cli.c
Normal file
3700
components/libraries/cli/nrf_cli.c
Normal file
File diff suppressed because it is too large
Load Diff
704
components/libraries/cli/nrf_cli.h
Normal file
704
components/libraries/cli/nrf_cli.h
Normal file
@@ -0,0 +1,704 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_CLI_H__
|
||||
#define NRF_CLI_H__
|
||||
|
||||
#include "sdk_common.h"
|
||||
#include "nrf_cli_types.h"
|
||||
#include "nrf_section.h"
|
||||
#include "nrf_log_backend_interface.h"
|
||||
#include "nrf_queue.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "app_util_platform.h"
|
||||
#include "nrf_memobj.h"
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
|
||||
#include "task_manager.h"
|
||||
#endif
|
||||
|
||||
#include "nrf_fprintf.h"
|
||||
#include "nrf_fprintf_format.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NRF_CLI_RX_BUFF_SIZE 16
|
||||
|
||||
/* CLI reserves top task manager flags, bits 0...18 are available for application. */
|
||||
#define NRF_CLI_TRANSPORT_TX_RDY_TASK_EVT (1UL << 19)
|
||||
#define NRF_CLI_TRANSPORT_RX_RDY_TASK_EVT (1UL << 20)
|
||||
#define NRF_CLI_LOG_PENDING_TASK_EVT (1UL << 21)
|
||||
#define NRF_CLI_CMD_EXECUTE_EVT (1UL << 22)
|
||||
#define NRF_CLI_KILL_TASK_EVT (1UL << 23)
|
||||
|
||||
#define NRF_CLI_TASK_EVTS (NRF_CLI_TRANSPORT_TX_RDY_TASK_EVT | \
|
||||
NRF_CLI_TRANSPORT_RX_RDY_TASK_EVT | \
|
||||
NRF_CLI_LOG_PENDING_TASK_EVT | \
|
||||
NRF_CLI_CMD_EXECUTE_EVT | \
|
||||
NRF_CLI_KILL_TASK_EVT)
|
||||
/**
|
||||
* @defgroup nrf_cli Command Line Interface
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief Module for unified command line handling.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Aliases to: @ref nrf_cli, @ref nrf_cli_cmd_entry, and @ref nrf_cli_static_entry.
|
||||
* Must be created here to satisfy module declaration order dependencies.
|
||||
*/
|
||||
typedef struct nrf_cli nrf_cli_t;
|
||||
typedef struct nrf_cli_cmd_entry nrf_cli_cmd_entry_t;
|
||||
typedef struct nrf_cli_static_entry nrf_cli_static_entry_t;
|
||||
|
||||
/**
|
||||
* @brief CLI dynamic command descriptor.
|
||||
*
|
||||
* @details Function shall fill the received @ref nrf_cli_static_entry structure with requested (idx)
|
||||
* dynamic subcommand data. If there is more than one dynamic subcommand available,
|
||||
* the function shall ensure that the returned commands: p_static->p_syntax are sorted in
|
||||
* alphabetical order. If idx exceeds the available dynamic subcommands, the function must write
|
||||
* to p_static->p_syntax NULL value. This will indicate to the CLI module that
|
||||
* there are no more dynamic commands to read.
|
||||
*/
|
||||
typedef void (*nrf_cli_dynamic_get)(size_t idx, nrf_cli_static_entry_t * p_static);
|
||||
|
||||
/**
|
||||
* @brief CLI command descriptor.
|
||||
*/
|
||||
struct nrf_cli_cmd_entry
|
||||
{
|
||||
bool is_dynamic;
|
||||
union
|
||||
{
|
||||
nrf_cli_dynamic_get p_dynamic_get; //!< Pointer to function returning dynamic commands.
|
||||
nrf_cli_static_entry_t const * p_static; //!< Pointer to array of static commands.
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief CLI command handler prototype.
|
||||
*/
|
||||
typedef void (*nrf_cli_cmd_handler)(nrf_cli_t const * p_cli, size_t argc, char **argv);
|
||||
|
||||
/**
|
||||
* @brief CLI static command descriptor.
|
||||
*/
|
||||
struct nrf_cli_static_entry
|
||||
{
|
||||
char const * p_syntax; //!< Command syntax strings.
|
||||
char const * p_help; //!< Command help string.
|
||||
|
||||
nrf_cli_cmd_entry_t const * p_subcmd; //!< Pointer to subcommand.
|
||||
|
||||
nrf_cli_cmd_handler handler; //!< Command handler.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Macro for defining and adding a root command (level 0).
|
||||
*
|
||||
* @note Each root command shall have unique syntax.
|
||||
*
|
||||
* @param[in] p_syntax Command syntax (for example: history).
|
||||
* @param[in] p_subcmd Pointer to a subcommands array.
|
||||
* @param[in] p_help Pointer to a command help string.
|
||||
* @param[in] p_handler Pointer to a function handler.
|
||||
*/
|
||||
#define NRF_CLI_CMD_REGISTER(p_syntax, p_subcmd, p_help, p_handler) \
|
||||
nrf_cli_static_entry_t const CONCAT_3(nrf_cli_, p_syntax, _raw) = \
|
||||
NRF_CLI_CMD(p_syntax, p_subcmd, p_help, p_handler); \
|
||||
NRF_SECTION_ITEM_REGISTER(cli_command, \
|
||||
nrf_cli_cmd_entry_t const CONCAT_3(nrf_cli_, p_syntax, _const)) = { \
|
||||
.is_dynamic = false, \
|
||||
.u = {.p_static = &CONCAT_3(nrf_cli_, p_syntax, _raw)} \
|
||||
}; \
|
||||
NRF_SECTION_ITEM_REGISTER(cli_sorted_cmd_ptrs, char const * CONCAT_2(p_syntax, _str_ptr))
|
||||
|
||||
/**
|
||||
* @brief Macro for creating a subcommand set. It must be used outside of any function body.
|
||||
*
|
||||
* @param[in] name Name of the subcommand set.
|
||||
*/
|
||||
#define NRF_CLI_CREATE_STATIC_SUBCMD_SET(name) \
|
||||
/*lint -save -e85 -e31*/ \
|
||||
static nrf_cli_static_entry_t const CONCAT_2(name, _raw)[]; \
|
||||
static nrf_cli_cmd_entry_t const name = { \
|
||||
.is_dynamic = false, \
|
||||
.u = {.p_static = CONCAT_2(name, _raw) } \
|
||||
}; \
|
||||
static nrf_cli_static_entry_t const CONCAT_2(name, _raw)[] = /*lint -restore*/
|
||||
|
||||
/**
|
||||
* @brief Define ending subcommands set.
|
||||
*
|
||||
*/
|
||||
#define NRF_CLI_SUBCMD_SET_END {NULL}
|
||||
|
||||
/**
|
||||
* @brief Macro for creating a dynamic entry.
|
||||
*
|
||||
* @param[in] name Name of the dynamic entry.
|
||||
* @param[in] p_get Pointer to the function returning dynamic commands array @ref nrf_cli_dynamic_get.
|
||||
*/
|
||||
#define NRF_CLI_CREATE_DYNAMIC_CMD(name, p_get) \
|
||||
/*lint -save -e19*/ \
|
||||
static nrf_cli_cmd_entry_t const name = { \
|
||||
.is_dynamic = true, \
|
||||
.u = { .p_dynamic_get = p_get } \
|
||||
}; /*lint -restore*/
|
||||
|
||||
/** @brief Macro for creating subcommands when C++ compiler is used.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* NRF_CLI_CPP_CREATE_STATIC_SUBCMD_SET(cmd_syntax,
|
||||
* NRF_CLI_CMD(abc, ...),
|
||||
* NRF_CLI_CMD(def, ...),
|
||||
* NRF_CLI_SUBCMD_SET_END
|
||||
* );
|
||||
* @endcode
|
||||
*/
|
||||
#define NRF_CLI_CPP_CREATE_STATIC_SUBCMD_SET(name, ...) \
|
||||
static nrf_cli_static_entry_t const CONCAT_2(name, _raw)[] = { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
static nrf_cli_cmd_entry_t const name = { \
|
||||
.is_dynamic = false, \
|
||||
.u = { .p_static = CONCAT_2(name, _raw) } \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a CLI command (@ref nrf_cli_static_entry).
|
||||
*
|
||||
* @param[in] _p_syntax Command syntax (for example: history).
|
||||
* @param[in] _p_subcmd Pointer to a subcommands array.
|
||||
* @param[in] _p_help Pointer to a command help string.
|
||||
* @param[in] _p_handler Pointer to a function handler.
|
||||
*/
|
||||
#define NRF_CLI_CMD(_p_syntax, _p_subcmd, _p_help, _p_handler) { \
|
||||
.p_syntax = (const char *) STRINGIFY(_p_syntax), \
|
||||
.p_help = (const char *) _p_help, \
|
||||
.p_subcmd = _p_subcmd, \
|
||||
.handler = _p_handler \
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal @brief Internal CLI state in response to data received from the terminal.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_CLI_RECEIVE_DEFAULT,
|
||||
NRF_CLI_RECEIVE_ESC,
|
||||
NRF_CLI_RECEIVE_ESC_SEQ,
|
||||
NRF_CLI_RECEIVE_TILDE_EXP
|
||||
} nrf_cli_receive_t;
|
||||
|
||||
|
||||
/**
|
||||
* @internal @brief Internal CLI state.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_CLI_STATE_UNINITIALIZED, //!< State uninitialized.
|
||||
NRF_CLI_STATE_INITIALIZED, //!< State initialized but not active.
|
||||
NRF_CLI_STATE_ACTIVE, //!< State active.
|
||||
NRF_CLI_STATE_PANIC_MODE_ACTIVE, //!< State panic mode activated.
|
||||
NRF_CLI_STATE_PANIC_MODE_INACTIVE //!< State panic mode requested but not supported.
|
||||
} nrf_cli_state_t;
|
||||
|
||||
/**
|
||||
* @brief Event type from CLI transport.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_CLI_TRANSPORT_EVT_RX_RDY,
|
||||
NRF_CLI_TRANSPORT_EVT_TX_RDY
|
||||
} nrf_cli_transport_evt_t;
|
||||
|
||||
typedef void (*nrf_cli_transport_handler_t)(nrf_cli_transport_evt_t evt_type, void * p_context);
|
||||
|
||||
typedef struct nrf_cli_transport_s nrf_cli_transport_t;
|
||||
|
||||
/**
|
||||
* @brief Unified CLI transport interface.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* @brief Function for initializing the CLI transport interface.
|
||||
*
|
||||
* @param[in] p_transport Pointer to the transfer instance.
|
||||
* @param[in] p_config Pointer to instance configuration.
|
||||
* @param[in] evt_handler Event handler.
|
||||
* @param[in] p_context Pointer to the context passed to event handler.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t (*init)(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_config,
|
||||
nrf_cli_transport_handler_t evt_handler,
|
||||
void * p_context);
|
||||
|
||||
/**
|
||||
* @brief Function for uninitializing the CLI transport interface.
|
||||
*
|
||||
* @param[in] p_transport Pointer to the transfer instance.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t (*uninit)(nrf_cli_transport_t const * p_transport);
|
||||
|
||||
/**
|
||||
* @brief Function for reconfiguring the transport to work in blocking mode.
|
||||
*
|
||||
* @param p_transport Pointer to the transfer instance.
|
||||
* @param blocking If true, the transport is enabled in blocking mode.
|
||||
*
|
||||
* @return NRF_SUCCESS on successful enabling, error otherwise (also if not supported).
|
||||
*/
|
||||
ret_code_t (*enable)(nrf_cli_transport_t const * p_transport,
|
||||
bool blocking);
|
||||
|
||||
/**
|
||||
* @brief Function for writing data to the transport interface.
|
||||
*
|
||||
* @param[in] p_transport Pointer to the transfer instance.
|
||||
* @param[in] p_data Pointer to the source buffer.
|
||||
* @param[in] length Source buffer length.
|
||||
* @param[in] p_cnt Pointer to the sent bytes counter.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t (*write)(nrf_cli_transport_t const * p_transport,
|
||||
const void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt);
|
||||
|
||||
/**
|
||||
* @brief Function for reading data from the transport interface.
|
||||
*
|
||||
* @param[in] p_transport Pointer to the transfer instance.
|
||||
* @param[in] p_data Pointer to the destination buffer.
|
||||
* @param[in] length Destination buffer length.
|
||||
* @param[in] p_cnt Pointer to the received bytes counter.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t (*read)(nrf_cli_transport_t const * p_transport,
|
||||
void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt);
|
||||
|
||||
} nrf_cli_transport_api_t;
|
||||
|
||||
struct nrf_cli_transport_s
|
||||
{
|
||||
nrf_cli_transport_api_t const * p_api;
|
||||
};
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
|
||||
/**
|
||||
* @brief CLI history object header.
|
||||
*/
|
||||
typedef PACKED_STRUCT
|
||||
{
|
||||
nrf_memobj_t * p_prev; //!< Pointer to the next object.
|
||||
nrf_memobj_t * p_next; //!< Pointer to the previous object.
|
||||
nrf_cli_cmd_len_t cmd_len; //!< Command length.
|
||||
} nrf_cli_memobj_header_t;
|
||||
#endif
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t log_lost_cnt; //!< Lost log counter.
|
||||
} nrf_cli_statistics_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @internal @brief Flags for internal CLI usage.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t insert_mode : 1; //!< Enables or disables console insert mode for text introduction.
|
||||
uint32_t show_help : 1; //!< Shows help if the command was called with -h or --help parameter.
|
||||
uint32_t use_colors : 1; //!< Enables or disables colored syntax.
|
||||
uint32_t echo : 1; //!< Enables or disables CLI echo.
|
||||
uint32_t processing : 1; //!< CLI is executing process function.
|
||||
uint32_t tx_rdy : 1;
|
||||
uint32_t last_nl : 8; //!< The last received newline character.
|
||||
} nrf_cli_flag_t;
|
||||
STATIC_ASSERT(sizeof(nrf_cli_flag_t) == sizeof(uint32_t));
|
||||
|
||||
/**
|
||||
* @internal @brief Union for internal CLI usage.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
uint32_t value;
|
||||
nrf_cli_flag_t flag;
|
||||
} nrf_cli_internal_t;
|
||||
|
||||
/**
|
||||
* @brief CLI instance context.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_cli_state_t state; //!< Internal module state.
|
||||
nrf_cli_receive_t receive_state; //!< Escape sequence indicator.
|
||||
|
||||
nrf_cli_static_entry_t active_cmd; //!< Currently executed command
|
||||
|
||||
nrf_cli_vt100_ctx_t vt100_ctx; //!< VT100 color and cursor position, terminal width.
|
||||
|
||||
nrf_cli_cmd_len_t cmd_buff_len; //!< Command length.
|
||||
nrf_cli_cmd_len_t cmd_buff_pos; //!< Command buffer cursor position.
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_WILDCARD)
|
||||
nrf_cli_cmd_len_t cmd_tmp_buff_len; //!< Command length in tmp buffer
|
||||
#endif
|
||||
|
||||
char cmd_buff[NRF_CLI_CMD_BUFF_SIZE]; //!< Command input buffer.
|
||||
char temp_buff[NRF_CLI_CMD_BUFF_SIZE]; //!< Temporary buffer used by various functions.
|
||||
char printf_buff[NRF_CLI_PRINTF_BUFF_SIZE]; //!< Printf buffer size.
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_STATISTICS)
|
||||
nrf_cli_statistics_t statistics; //!< CLI statistics.
|
||||
#endif
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_USES_TASK_MANAGER)
|
||||
task_id_t task_id;
|
||||
#endif
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
|
||||
nrf_memobj_t * p_cmd_list_head; //!< Pointer to the head of history list.
|
||||
nrf_memobj_t * p_cmd_list_tail; //!< Pointer to the tail of history list.
|
||||
nrf_memobj_t * p_cmd_list_element; //!< Pointer to an element of history list.
|
||||
#endif
|
||||
volatile nrf_cli_internal_t internal; //!< Internal CLI data
|
||||
} nrf_cli_ctx_t;
|
||||
|
||||
extern const nrf_log_backend_api_t nrf_log_backend_cli_api;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nrf_queue_t const * p_queue;
|
||||
void * p_context;
|
||||
nrf_cli_t const * p_cli;
|
||||
} nrf_cli_log_backend_t;
|
||||
|
||||
#if NRF_CLI_LOG_BACKEND && NRF_MODULE_ENABLED(NRF_LOG)
|
||||
#define NRF_LOG_BACKEND_CLI_DEF(_name_, _queue_size_) \
|
||||
NRF_QUEUE_DEF(nrf_log_entry_t, \
|
||||
CONCAT_2(_name_, _queue),_queue_size_, NRF_QUEUE_MODE_NO_OVERFLOW); \
|
||||
static nrf_cli_log_backend_t CONCAT_2(cli_log_backend,_name_) = { \
|
||||
.p_queue = &CONCAT_2(_name_, _queue), \
|
||||
}; \
|
||||
NRF_LOG_BACKEND_DEF(_name_, nrf_log_backend_cli_api, &CONCAT_2(cli_log_backend,_name_))
|
||||
|
||||
#define NRF_CLI_BACKEND_PTR(_name_) &CONCAT_2(_name_, _log_backend)
|
||||
#else
|
||||
#define NRF_LOG_BACKEND_CLI_DEF(_name_, _queue_sz_)
|
||||
#define NRF_CLI_BACKEND_PTR(_name_) NULL
|
||||
#endif
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_HISTORY)
|
||||
/* Header consists memory for cmd length and pointer to: prev and next element. */
|
||||
#define NRF_CLI_HISTORY_HEADER_SIZE (sizeof(nrf_cli_memobj_header_t))
|
||||
|
||||
#define NRF_CLI_HISTORY_MEM_OBJ(name) \
|
||||
NRF_MEMOBJ_POOL_DEF(CONCAT_2(name, _cmd_hist_memobj), \
|
||||
NRF_CLI_HISTORY_HEADER_SIZE + \
|
||||
NRF_CLI_HISTORY_ELEMENT_SIZE, \
|
||||
NRF_CLI_HISTORY_ELEMENT_COUNT)
|
||||
|
||||
#define NRF_CLI_MEMOBJ_PTR(_name_) &CONCAT_2(_name_, _cmd_hist_memobj)
|
||||
#else
|
||||
#define NRF_CLI_MEMOBJ_PTR(_name_) NULL
|
||||
#define NRF_CLI_HISTORY_MEM_OBJ(name)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief CLI instance internals.
|
||||
*
|
||||
* @ref nrf_cli_t
|
||||
*/
|
||||
struct nrf_cli
|
||||
{
|
||||
char const * const p_name; //!< Terminal name.
|
||||
|
||||
nrf_cli_transport_t const * p_iface; //!< Transport interface.
|
||||
nrf_cli_ctx_t * p_ctx; //!< Internal context.
|
||||
nrf_log_backend_t const * p_log_backend; //!< Logger backend.
|
||||
nrf_fprintf_ctx_t * p_fprintf_ctx; //!< fprintf context.
|
||||
nrf_memobj_pool_t const * p_cmd_hist_mempool; //!< Memory reserved for commands history.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Macro for defining a command line interface instance.
|
||||
*
|
||||
* @param[in] name Instance name.
|
||||
* @param[in] cli_prefix CLI prefix string.
|
||||
* @param[in] p_transport_iface Pointer to the transport interface.
|
||||
* @param[in] newline_ch Deprecated parameter, not used any more. Any uint8_t value can be used.
|
||||
* @param[in] log_queue_size Logger processing queue size.
|
||||
*/
|
||||
#define NRF_CLI_DEF(name, cli_prefix, p_transport_iface, newline_ch, log_queue_size) \
|
||||
static nrf_cli_t const name; \
|
||||
static nrf_cli_ctx_t CONCAT_2(name, _ctx); \
|
||||
NRF_FPRINTF_DEF(CONCAT_2(name, _fprintf_ctx), \
|
||||
&name, \
|
||||
CONCAT_2(name, _ctx).printf_buff, \
|
||||
NRF_CLI_PRINTF_BUFF_SIZE, \
|
||||
false, \
|
||||
nrf_cli_print_stream); \
|
||||
NRF_LOG_BACKEND_CLI_DEF(CONCAT_2(name, _log_backend), log_queue_size); \
|
||||
NRF_CLI_HISTORY_MEM_OBJ(name); \
|
||||
/*lint -save -e31*/ \
|
||||
static nrf_cli_t const name = { \
|
||||
.p_name = cli_prefix, \
|
||||
.p_iface = p_transport_iface, \
|
||||
.p_ctx = &CONCAT_2(name, _ctx), \
|
||||
.p_log_backend = NRF_CLI_BACKEND_PTR(name), \
|
||||
.p_fprintf_ctx = &CONCAT_2(name, _fprintf_ctx), \
|
||||
.p_cmd_hist_mempool = NRF_CLI_MEMOBJ_PTR(name), \
|
||||
} /*lint -restore*/
|
||||
|
||||
/**
|
||||
* @brief Function for initializing a transport layer and internal CLI state.
|
||||
*
|
||||
* @param[in] p_cli Pointer to CLI instance.
|
||||
* @param[in] p_transport_config Configuration forwarded to the transport during initialization.
|
||||
* @param[in] use_colors Enables colored prints.
|
||||
* @param[in] log_backend If true, the console will be used as logger backend.
|
||||
* @param[in] init_lvl Default severity level for the logger.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t nrf_cli_init(nrf_cli_t const * p_cli,
|
||||
void const * p_transport_config,
|
||||
bool use_colors,
|
||||
bool log_backend,
|
||||
nrf_log_severity_t init_lvl);
|
||||
|
||||
ret_code_t nrf_cli_task_create(nrf_cli_t const * p_cli);
|
||||
|
||||
/**
|
||||
* @brief Function for uninitializing a transport layer and internal CLI state.
|
||||
* If function returns NRF_ERROR_BUSY, you must call @ref nrf_cli_process before calling
|
||||
* nrf_cli_uninit again.
|
||||
*
|
||||
* @param p_cli Pointer to CLI instance.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t nrf_cli_uninit(nrf_cli_t const * p_cli);
|
||||
|
||||
/**
|
||||
* @brief Function for starting CLI processing.
|
||||
*
|
||||
* @param p_cli Pointer to the CLI instance.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t nrf_cli_start(nrf_cli_t const * p_cli);
|
||||
|
||||
/**
|
||||
* @brief Function for stopping CLI processing.
|
||||
*
|
||||
* @param p_cli Pointer to CLI instance.
|
||||
*
|
||||
* @return Standard error code.
|
||||
*/
|
||||
ret_code_t nrf_cli_stop(nrf_cli_t const * p_cli);
|
||||
|
||||
/**
|
||||
* @brief CLI colors for @ref nrf_cli_fprintf function.
|
||||
*/
|
||||
#define NRF_CLI_DEFAULT NRF_CLI_VT100_COLOR_DEFAULT /**< Turn off character attributes. */
|
||||
#define NRF_CLI_NORMAL NRF_CLI_VT100_COLOR_WHITE /**< Normal color printf. */
|
||||
#define NRF_CLI_INFO NRF_CLI_VT100_COLOR_GREEN /**< Info color printf. */
|
||||
#define NRF_CLI_OPTION NRF_CLI_VT100_COLOR_CYAN /**< Option color printf. */
|
||||
#define NRF_CLI_WARNING NRF_CLI_VT100_COLOR_YELLOW /**< Warning color printf. */
|
||||
#define NRF_CLI_ERROR NRF_CLI_VT100_COLOR_RED /**< Error color printf. */
|
||||
|
||||
/**
|
||||
* @brief Printf-like function which sends formatted data stream to the CLI.
|
||||
* This function shall not be used outside of the CLI module or CLI command context.
|
||||
*
|
||||
* @param[in] p_cli Pointer to the CLI instance.
|
||||
* @param[in] color Printf color.
|
||||
* @param[in] p_fmt Format string.
|
||||
* @param[in] ... List of parameters to print.
|
||||
*/
|
||||
void nrf_cli_fprintf(nrf_cli_t const * p_cli,
|
||||
nrf_cli_vt100_color_t color,
|
||||
char const * p_fmt,
|
||||
...);
|
||||
|
||||
/**
|
||||
* @brief Print an info message to the CLI.
|
||||
*
|
||||
* See @ref nrf_cli_fprintf.
|
||||
*
|
||||
* @param[in] _p_cli Pointer to the CLI instance.
|
||||
* @param[in] _ft Format string.
|
||||
* @param[in] ... List of parameters to print.
|
||||
*/
|
||||
#define nrf_cli_info(_p_cli, _ft, ...) \
|
||||
nrf_cli_fprintf(_p_cli, NRF_CLI_INFO, _ft "\n", ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Print a normal message to the CLI.
|
||||
*
|
||||
* See @ref nrf_cli_fprintf.
|
||||
*
|
||||
* @param[in] _p_cli Pointer to the CLI instance.
|
||||
* @param[in] _ft Format string.
|
||||
* @param[in] ... List of parameters to print.
|
||||
*/
|
||||
#define nrf_cli_print(_p_cli, _ft, ...) \
|
||||
nrf_cli_fprintf(_p_cli, NRF_CLI_DEFAULT, _ft "\n", ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Print a warning message to the CLI.
|
||||
*
|
||||
* See @ref nrf_cli_fprintf.
|
||||
*
|
||||
* @param[in] _p_cli Pointer to the CLI instance.
|
||||
* @param[in] _ft Format string.
|
||||
* @param[in] ... List of parameters to print.
|
||||
*/
|
||||
#define nrf_cli_warn(_p_cli, _ft, ...) \
|
||||
nrf_cli_fprintf(_p_cli, NRF_CLI_WARNING, _ft "\n", ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Print an error message to the CLI.
|
||||
*
|
||||
* See @ref nrf_cli_fprintf.
|
||||
*
|
||||
* @param[in] _p_cli Pointer to the CLI instance.
|
||||
* @param[in] _ft Format string.
|
||||
* @param[in] ... List of parameters to print.
|
||||
*/
|
||||
#define nrf_cli_error(_p_cli, _ft, ...) \
|
||||
nrf_cli_fprintf(_p_cli, NRF_CLI_ERROR, _ft "\n", ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Process function, which should be executed when data is ready in the transport interface.
|
||||
*
|
||||
* @param[in] p_cli Pointer to the CLI instance.
|
||||
*/
|
||||
void nrf_cli_process(nrf_cli_t const * p_cli);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Option descriptor.
|
||||
*/
|
||||
typedef struct nrf_cli_getopt_option
|
||||
{
|
||||
char const * p_optname; //!< Option long name.
|
||||
char const * p_optname_short; //!< Option short name.
|
||||
char const * p_optname_help; //!< Option help string.
|
||||
} nrf_cli_getopt_option_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Option structure initializer @ref nrf_cli_getopt_option.
|
||||
*
|
||||
* @param[in] _p_optname Option name long.
|
||||
* @param[in] _p_shortname Option name short.
|
||||
* @param[in] _p_help Option help string.
|
||||
*/
|
||||
#define NRF_CLI_OPT(_p_optname, _p_shortname, _p_help) { \
|
||||
.p_optname = _p_optname, \
|
||||
.p_optname_short = _p_shortname, \
|
||||
.p_optname_help = _p_help, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Informs that a command has been called with -h or --help option.
|
||||
*
|
||||
* @param[in] p_cli Pointer to the CLI instance.
|
||||
*
|
||||
* @return True if help has been requested.
|
||||
*/
|
||||
__STATIC_INLINE bool nrf_cli_help_requested(nrf_cli_t const * p_cli);
|
||||
|
||||
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
|
||||
__STATIC_INLINE bool nrf_cli_help_requested(nrf_cli_t const * p_cli)
|
||||
{
|
||||
return p_cli->p_ctx->internal.flag.show_help;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Prints the current command help.
|
||||
* @details Function will print a help string with: the currently entered command, its options,
|
||||
* and subcommands (if they exist).
|
||||
*
|
||||
* @param[in] p_cli Pointer to the CLI instance.
|
||||
* @param[in] p_opt Pointer to the optional option array.
|
||||
* @param[in] opt_len Option array size.
|
||||
*/
|
||||
void nrf_cli_help_print(nrf_cli_t const * p_cli,
|
||||
nrf_cli_getopt_option_t const * p_opt,
|
||||
size_t opt_len);
|
||||
|
||||
/**
|
||||
* @internal @brief This function shall not be used directly, it is required by the
|
||||
* nrf_fprintf module.
|
||||
*
|
||||
* @param[in] p_user_ctx Pointer to the context for the CLI instance.
|
||||
* @param[in] p_data Pointer to the data buffer.
|
||||
* @param[in] data_len Data buffer size.
|
||||
*/
|
||||
void nrf_cli_print_stream(void const * p_user_ctx, char const * p_data, size_t data_len);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_CLI_H__ */
|
||||
102
components/libraries/cli/nrf_cli_types.h
Normal file
102
components/libraries/cli/nrf_cli_types.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_CLI_TYPES_H__
|
||||
#define NRF_CLI_TYPES_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "sdk_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (NRF_CLI_CMD_BUFF_SIZE > 65535)
|
||||
typedef uint32_t nrf_cli_cmd_len_t;
|
||||
#elif (NRF_CLI_CMD_BUFF_SIZE > 255)
|
||||
typedef uint16_t nrf_cli_cmd_len_t;
|
||||
#else
|
||||
typedef uint8_t nrf_cli_cmd_len_t;
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NRF_CLI_VT100_COLOR_DEFAULT,
|
||||
NRF_CLI_VT100_COLOR_BLACK,
|
||||
NRF_CLI_VT100_COLOR_RED,
|
||||
NRF_CLI_VT100_COLOR_GREEN,
|
||||
NRF_CLI_VT100_COLOR_YELLOW,
|
||||
NRF_CLI_VT100_COLOR_BLUE,
|
||||
NRF_CLI_VT100_COLOR_MAGENTA,
|
||||
NRF_CLI_VT100_COLOR_CYAN,
|
||||
NRF_CLI_VT100_COLOR_WHITE,
|
||||
|
||||
VT100_COLOR_END
|
||||
} nrf_cli_vt100_color_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nrf_cli_vt100_color_t col; // text color
|
||||
nrf_cli_vt100_color_t bgcol; // background color
|
||||
} nrf_cli_vt100_colors_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nrf_cli_cmd_len_t cur_x; // horizontal cursor position in edited command line
|
||||
nrf_cli_cmd_len_t cur_x_end; // horizontal cursor position at the end of command
|
||||
nrf_cli_cmd_len_t cur_y; // vertical cursor position in edited command
|
||||
nrf_cli_cmd_len_t cur_y_end; // vertical cursor position at the end of command
|
||||
nrf_cli_cmd_len_t terminal_hei; // terminal screen height
|
||||
nrf_cli_cmd_len_t terminal_wid; // terminal screen width
|
||||
uint8_t name_len; // console name length
|
||||
} nrf_cli_multiline_cons_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nrf_cli_multiline_cons_t cons;
|
||||
nrf_cli_vt100_colors_t col;
|
||||
nrf_cli_cmd_len_t printed_cmd; // printed commands counter
|
||||
} nrf_cli_vt100_ctx_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_CLI_TYPES_H__ */
|
||||
|
||||
632
components/libraries/cli/nrf_cli_vt100.h
Normal file
632
components/libraries/cli/nrf_cli_vt100.h
Normal file
@@ -0,0 +1,632 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_CLI_VT100_H__
|
||||
#define NRF_CLI_VT100_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NRF_CLI_VT100_ASCII_ESC (0x1b)
|
||||
#define NRF_CLI_VT100_ASCII_DEL (0x7F)
|
||||
#define NRF_CLI_VT100_ASCII_BSPACE (0x08)
|
||||
#define NRF_CLI_VT100_ASCII_CTRL_A (0x1)
|
||||
#define NRF_CLI_VT100_ASCII_CTRL_C (0x03)
|
||||
#define NRF_CLI_VT100_ASCII_CTRL_E (0x5)
|
||||
#define NRF_CLI_VT100_ASCII_CTRL_L (0x0C)
|
||||
#define NRF_CLI_VT100_ASCII_CTRL_U (0x15)
|
||||
#define NRF_CLI_VT100_ASCII_CTRL_W (0x17)
|
||||
|
||||
|
||||
#define NRF_CLI_VT100_SETNL \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', '0', 'h', '\0' \
|
||||
} /* Set new line mode */
|
||||
#define NRF_CLI_VT100_SETAPPL \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '1', 'h', '\0' \
|
||||
} /* Set cursor key to application */
|
||||
#define NRF_CLI_VT100_SETCOL_132 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '3', 'h', '\0' \
|
||||
} /* Set number of columns to 132 */
|
||||
#define NRF_CLI_VT100_SETSMOOTH \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '4', 'h', '\0' \
|
||||
} /* Set smooth scrolling */
|
||||
#define NRF_CLI_VT100_SETREVSCRN \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '5', 'h', '\0' \
|
||||
} /* Set reverse video on screen */
|
||||
#define NRF_CLI_VT100_SETORGREL \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '6', 'h', '\0' \
|
||||
} /* Set origin to relative */
|
||||
#define NRF_CLI_VT100_SETWRAP_ON \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '7', 'h', '\0' \
|
||||
} /* Set auto-wrap mode */
|
||||
#define NRF_CLI_VT100_SETWRAP_OFF \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '7', 'l', '\0' \
|
||||
} /* Set auto-wrap mode */
|
||||
|
||||
#define NRF_CLI_VT100_SETREP \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '8', 'h', '\0' \
|
||||
} /* Set auto-repeat mode */
|
||||
#define NRF_CLI_VT100_SETINTER \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '9', 'h', '\0' \
|
||||
} /* Set interlacing mode */
|
||||
|
||||
#define NRF_CLI_VT100_SETLF \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', '0', 'l', '\0' \
|
||||
} /* Set line feed mode */
|
||||
#define NRF_CLI_VT100_SETCURSOR \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '1', 'l', '\0' \
|
||||
} /* Set cursor key to cursor */
|
||||
#define NRF_CLI_VT100_SETVT52 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '2', 'l', '\0' \
|
||||
} /* Set VT52 (versus ANSI) */
|
||||
#define NRF_CLI_VT100_SETCOL_80 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '3', 'l', '\0' \
|
||||
} /* Set number of columns to 80 */
|
||||
#define NRF_CLI_VT100_SETJUMP \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '4', 'l', '\0' \
|
||||
} /* Set jump scrolling */
|
||||
#define NRF_CLI_VT100_SETNORMSCRN \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '5', 'l', '\0' \
|
||||
} /* Set normal video on screen */
|
||||
#define NRF_CLI_VT100_SETORGABS \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '6', 'l', '\0' \
|
||||
} /* Set origin to absolute */
|
||||
#define NRF_CLI_VT100_RESETWRAP \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '7', 'l', '\0' \
|
||||
} /* Reset auto-wrap mode */
|
||||
#define NRF_CLI_VT100_RESETREP \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '8', 'l', '\0' \
|
||||
} /* Reset auto-repeat mode */
|
||||
#define NRF_CLI_VT100_RESETINTER \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '9', 'l', '\0' \
|
||||
} /* Reset interlacing mode */
|
||||
|
||||
#define NRF_CLI_VT100_ALTKEYPAD \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '=', '\0' \
|
||||
} /* Set alternate keypad mode */
|
||||
#define NRF_CLI_VT100_NUMKEYPAD \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '>', '\0' \
|
||||
} /* Set numeric keypad mode */
|
||||
|
||||
#define NRF_CLI_VT100_SETUKG0 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '(', 'A', '\0' \
|
||||
} /* Set United Kingdom G0 character set */
|
||||
#define NRF_CLI_VT100_SETUKG1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, ')', 'A', '\0' \
|
||||
} /* Set United Kingdom G1 character set */
|
||||
#define NRF_CLI_VT100_SETUSG0 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '(', 'B', '\0' \
|
||||
} /* Set United States G0 character set */
|
||||
#define NRF_CLI_VT100_SETUSG1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, ')', 'B', '\0' \
|
||||
} /* Set United States G1 character set */
|
||||
#define NRF_CLI_VT100_SETSPECG0 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '(', '0', '\0' \
|
||||
} /* Set G0 special chars. & line set */
|
||||
#define NRF_CLI_VT100_SETSPECG1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, ')', '0', '\0' \
|
||||
} /* Set G1 special chars. & line set */
|
||||
#define NRF_CLI_VT100_SETALTG0 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '(', '1', '\0' \
|
||||
} /* Set G0 alternate character ROM */
|
||||
#define NRF_CLI_VT100_SETALTG1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, ')', '1', '\0' \
|
||||
} /* Set G1 alternate character ROM */
|
||||
#define NRF_CLI_VT100_SETALTSPECG0 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '(', '2', '\0' \
|
||||
} /* Set G0 alt char ROM and spec. graphics */
|
||||
#define NRF_CLI_VT100_SETALTSPECG1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, ')', '2', '\0' \
|
||||
} /* Set G1 alt char ROM and spec. graphics */
|
||||
|
||||
#define NRF_CLI_VT100_SETSS2 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'N', '\0' \
|
||||
} /* Set single shift 2 */
|
||||
#define NRF_CLI_VT100_SETSS3 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', '\0' \
|
||||
} /* Set single shift 3 */
|
||||
|
||||
#define NRF_CLI_VT100_MODESOFF \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', 'm', '\0' \
|
||||
} /* Turn off character attributes */
|
||||
#define NRF_CLI_VT100_MODESOFF_ \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '0', 'm', '\0' \
|
||||
} /* Turn off character attributes */
|
||||
#define NRF_CLI_VT100_BOLD \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '1', 'm', '\0' \
|
||||
} /* Turn bold mode on */
|
||||
#define NRF_CLI_VT100_LOWINT \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', 'm', '\0' \
|
||||
} /* Turn low intensity mode on */
|
||||
#define NRF_CLI_VT100_UNDERLINE \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '4', 'm', '\0' \
|
||||
} /* Turn underline mode on */
|
||||
#define NRF_CLI_VT100_BLINK \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '5', 'm', '\0' \
|
||||
} /* Turn blinking mode on */
|
||||
#define NRF_CLI_VT100_REVERSE \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '7', 'm', '\0' \
|
||||
} /* Turn reverse video on */
|
||||
#define NRF_CLI_VT100_INVISIBLE \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '8', 'm', '\0' \
|
||||
} /* Turn invisible text mode on */
|
||||
|
||||
#define NRF_CLI_VT100_SETWIN(t, b) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', (t), ';', (b), 'r', '\0' \
|
||||
} /* Set top and bottom line#s of a window */
|
||||
|
||||
#define NRF_CLI_VT100_CURSORUP(n) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', (n), 'A', '\0' \
|
||||
} /* Move cursor up n lines */
|
||||
#define NRF_CLI_VT100_CURSORDN(n) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', (n), 'B', '\0' \
|
||||
} /* Move cursor down n lines */
|
||||
#define NRF_CLI_VT100_CURSORRT(n) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', (n), 'C', '\0' \
|
||||
} /* Move cursor right n lines */
|
||||
#define NRF_CLI_VT100_CURSORLF(n) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', (n), 'D', '\0' \
|
||||
} /* Move cursor left n lines */
|
||||
#define NRF_CLI_VT100_CURSORHOME \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', 'H', '\0' \
|
||||
} /* Move cursor to upper left corner */
|
||||
#define NRF_CLI_VT100_CURSORHOME_ \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', ';', 'H', '\0' \
|
||||
} /* Move cursor to upper left corner */
|
||||
#define NRF_CLI_VT100_CURSORPOS(v, h) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', (v), ';', (h), 'H', '\0' \
|
||||
} /* Move cursor to screen location v,h */
|
||||
|
||||
#define NRF_CLI_VT100_HVHOME \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', 'f', '\0' \
|
||||
} /* Move cursor to upper left corner */
|
||||
#define NRF_CLI_VT100_HVHOME_ \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', ';', 'f', '\0' \
|
||||
} /* Move cursor to upper left corner */
|
||||
#define NRF_CLI_VT100_HVPOS(v, h) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', (v), ';', (h), 'f', '\0' \
|
||||
} /* Move cursor to screen location v,h */
|
||||
#define NRF_CLI_VT100_INDEX \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'D', '\0' \
|
||||
} /* Move/scroll window up one line */
|
||||
#define NRF_CLI_VT100_REVINDEX \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'M', '\0' \
|
||||
} /* Move/scroll window down one line */
|
||||
#define NRF_CLI_VT100_NEXTLINE \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'E', '\0' \
|
||||
} /* Move to next line */
|
||||
#define NRF_CLI_VT100_SAVECURSOR \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '7', '\0' \
|
||||
} /* Save cursor position and attributes */
|
||||
#define NRF_CLI_VT100_RESTORECURSOR \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '8', '\0' \
|
||||
} /* Restore cursor position and attribute */
|
||||
|
||||
#define NRF_CLI_VT100_TABSET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'H', '\0' \
|
||||
} /* Set a tab at the current column */
|
||||
#define NRF_CLI_VT100_TABCLR \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', 'g', '\0' \
|
||||
} /* Clear a tab at the current column */
|
||||
#define NRF_CLI_VT100_TABCLR_ \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '0', 'g', '\0' \
|
||||
} /* Clear a tab at the current column */
|
||||
#define NRF_CLI_VT100_TABCLRALL \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '3', 'g', '\0' \
|
||||
} /* Clear all tabs */
|
||||
|
||||
#define NRF_CLI_VT100_DHTOP \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '#', '3', '\0' \
|
||||
} /* Double-height letters, top half */
|
||||
#define NRF_CLI_VT100_DHBOT \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '#', '4', '\0' \
|
||||
} /* Double-height letters, bottom hal */
|
||||
#define NRF_CLI_VT100_SWSH \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '#', '5', '\0' \
|
||||
} /* Single width, single height letters */
|
||||
#define NRF_CLI_VT100_DWSH \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '#', '6', '\0' \
|
||||
} /* Double width, single height letters */
|
||||
|
||||
#define NRF_CLI_VT100_CLEAREOL \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', 'K', '\0' \
|
||||
} /* Clear line from cursor right */
|
||||
#define NRF_CLI_VT100_CLEAREOL_ \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '0', 'K', '\0' \
|
||||
} /* Clear line from cursor right */
|
||||
#define NRF_CLI_VT100_CLEARBOL \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '1', 'K', '\0' \
|
||||
} /* Clear line from cursor left */
|
||||
#define NRF_CLI_VT100_CLEARLINE \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', 'K', '\0' \
|
||||
} /* Clear entire line */
|
||||
|
||||
#define NRF_CLI_VT100_CLEAREOS \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', 'J', '\0' \
|
||||
} /* Clear screen from cursor down */
|
||||
#define NRF_CLI_VT100_CLEAREOS_ \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '0', 'J', '\0' \
|
||||
} /* Clear screen from cursor down */
|
||||
#define NRF_CLI_VT100_CLEARBOS \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '1', 'J', '\0' \
|
||||
} /* Clear screen from cursor up */
|
||||
#define NRF_CLI_VT100_CLEARSCREEN \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', 'J', '\0' \
|
||||
} /* Clear entire screen */
|
||||
|
||||
#define NRF_CLI_VT100_DEVSTAT \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '5', 'n', '\0' \
|
||||
} /* Device status report */
|
||||
#define NRF_CLI_VT100_TERMOK \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '0', 'n', '\0' \
|
||||
} /* Response: terminal is OK */
|
||||
#define NRF_CLI_VT100_TERMNOK \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '3', 'n', '\0' \
|
||||
} /* Response: terminal is not OK */
|
||||
|
||||
#define NRF_CLI_VT100_GETCURSOR \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '6', 'n', '\0' \
|
||||
} /* Get cursor position */
|
||||
#define NRF_CLI_VT100_CURSORPOSAT \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, (v), ';', (h), 'R', '\0' \
|
||||
} /* Response: cursor is at v,h */
|
||||
|
||||
#define NRF_CLI_VT100_IDENT \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', 'c', '\0' \
|
||||
} /* Identify what terminal type */
|
||||
#define NRF_CLI_VT100_IDENT_ \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '0', 'c', '\0' \
|
||||
} /* Identify what terminal type */
|
||||
#define NRF_CLI_VT100_GETTYPE \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '?', '1', ';', (n), '0', 'c', '\0'\
|
||||
} /* Response: terminal type code n */
|
||||
|
||||
#define NRF_CLI_VT100_RESET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'c', '\0' \
|
||||
} /* Reset terminal to initial state */
|
||||
|
||||
#define NRF_CLI_VT100_ALIGN \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '#', '8', '\0' \
|
||||
} /* Screen alignment display */
|
||||
#define NRF_CLI_VT100_TESTPU \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '1', 'y', '\0' \
|
||||
} /* Confidence power up test */
|
||||
#define NRF_CLI_VT100_TESTLB \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '2', 'y', '\0' \
|
||||
} /* Confidence loopback test */
|
||||
#define NRF_CLI_VT100_TESTPUREP \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '9', 'y', '\0' \
|
||||
} /* Repeat power up test */
|
||||
#define NRF_CLI_VT100_TESTLBREP \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', ';', '1', '0', 'y', '\0' \
|
||||
} /* Repeat loopback test */
|
||||
|
||||
#define NRF_CLI_VT100_LEDSOFF \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '0', 'q', '\0' \
|
||||
} /* Turn off all four leds */
|
||||
#define NRF_CLI_VT100_LED1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '1', 'q', '\0' \
|
||||
} /* Turn on LED #1 */
|
||||
#define NRF_CLI_VT100_LED2 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '2', 'q', '\0' \
|
||||
} /* Turn on LED #2 */
|
||||
#define NRF_CLI_VT100_LED3 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '3', 'q', '\0' \
|
||||
} /* Turn on LED #3 */
|
||||
#define NRF_CLI_VT100_LED4 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '4', 'q', '\0' \
|
||||
} /* Turn on LED #4 */
|
||||
|
||||
/* Function Keys */
|
||||
|
||||
#define NRF_CLI_VT100_PF1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'P', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_PF2 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'Q', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_PF3 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'R', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_PF4 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'S', '\0' \
|
||||
}
|
||||
|
||||
/* Arrow keys */
|
||||
|
||||
#define NRF_CLI_VT100_UP_RESET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'A', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_UP_SET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'A', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_DOWN_RESET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'B', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_DOWN_SET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'B', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_RIGHT_RESET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'C', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_RIGHT_SET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'C', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_LEFT_RESET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'D', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_LEFT_SET \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'D', '\0' \
|
||||
}
|
||||
|
||||
/* Numeric Keypad Keys */
|
||||
|
||||
#define NRF_CLI_VT100_NUMERIC_0 \
|
||||
{ \
|
||||
'0', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_0 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'p', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_1 \
|
||||
{ \
|
||||
'1', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_1 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'q', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_2 \
|
||||
{ \
|
||||
'2', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_2 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'r', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_3 \
|
||||
{ \
|
||||
'3', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_3 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 's', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_4 \
|
||||
{ \
|
||||
'4', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_4 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 't', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_5 \
|
||||
{ \
|
||||
'5', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_5 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'u', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_6 \
|
||||
{ \
|
||||
'6', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_6 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'v', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_7 \
|
||||
{ \
|
||||
'7', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_7 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'w', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_8 \
|
||||
{ \
|
||||
'8', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_8 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'x', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_9 \
|
||||
{ \
|
||||
'9', '\0'
|
||||
#define NRF_CLI_VT100_ALT_9 \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'y' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_MINUS \
|
||||
{ \
|
||||
'-', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_MINUS \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'm', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_COMMA \
|
||||
{ \
|
||||
',', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_COMMA \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'l', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_PERIOD \
|
||||
{ \
|
||||
'.', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_PERIOD \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'n', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_NUMERIC_ENTER \
|
||||
{ \
|
||||
ASCII_CR \
|
||||
}
|
||||
#define NRF_CLI_VT100_ALT_ENTER \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, 'O', 'M', '\0' \
|
||||
}
|
||||
|
||||
#define NRF_CLI_VT100_COLOR(__col) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '1', ';', '3', '0' + (__col), 'm', '\0' \
|
||||
}
|
||||
#define NRF_CLI_VT100_BGCOLOR(__col) \
|
||||
{ \
|
||||
NRF_CLI_VT100_ASCII_ESC, '[', '4', '0' + (__col), 'm', '\0' \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_CLI_VT100_H__ */
|
||||
|
||||
223
components/libraries/cli/rtt/nrf_cli_rtt.c
Normal file
223
components/libraries/cli/rtt/nrf_cli_rtt.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_RTT)
|
||||
#include <SEGGER_RTT_Conf.h>
|
||||
#include <SEGGER_RTT.h>
|
||||
#include "nrf_cli_rtt.h"
|
||||
#include "nrf_assert.h"
|
||||
#include "nrf_delay.h"
|
||||
|
||||
#define RTT_RX_TIMEOUT 100
|
||||
|
||||
static bool m_host_present;
|
||||
|
||||
static void timer_handler(void * p_context)
|
||||
{
|
||||
nrf_cli_rtt_internal_t * p_internal = (nrf_cli_rtt_internal_t *)p_context;
|
||||
if (SEGGER_RTT_HasData(0))
|
||||
{
|
||||
p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY, p_internal->p_cb->p_context);
|
||||
}
|
||||
p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_internal->p_cb->p_context);
|
||||
|
||||
ret_code_t err_code = app_timer_start(*p_internal->p_timer,
|
||||
APP_TIMER_TICKS(RTT_RX_TIMEOUT),
|
||||
p_context);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
UNUSED_VARIABLE(err_code);
|
||||
}
|
||||
|
||||
static ret_code_t cli_rtt_init(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_config,
|
||||
nrf_cli_transport_handler_t evt_handler,
|
||||
void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_config);
|
||||
|
||||
nrf_cli_rtt_internal_t * p_internal =
|
||||
CONTAINER_OF(p_transport, nrf_cli_rtt_internal_t, transport);
|
||||
p_internal->p_cb->handler = evt_handler;
|
||||
p_internal->p_cb->p_context = p_context;
|
||||
p_internal->p_cb->timer_created = false;
|
||||
|
||||
SEGGER_RTT_Init();
|
||||
|
||||
m_host_present = true;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_rtt_uninit(nrf_cli_transport_t const * p_transport)
|
||||
{
|
||||
nrf_cli_rtt_internal_t * p_internal =
|
||||
CONTAINER_OF(p_transport, nrf_cli_rtt_internal_t, transport);
|
||||
|
||||
return app_timer_stop(*p_internal->p_timer);
|
||||
}
|
||||
|
||||
static ret_code_t cli_rtt_enable(nrf_cli_transport_t const * p_transport,
|
||||
bool blocking)
|
||||
{
|
||||
nrf_cli_rtt_internal_t * p_internal =
|
||||
CONTAINER_OF(p_transport, nrf_cli_rtt_internal_t, transport);
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
if (p_internal->p_cb->timer_created)
|
||||
{
|
||||
err_code = app_timer_stop(*p_internal->p_timer); //Timer may be running or inactive
|
||||
if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE))
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (!blocking)
|
||||
{
|
||||
if (!p_internal->p_cb->timer_created)
|
||||
{
|
||||
err_code = app_timer_create(p_internal->p_timer,
|
||||
APP_TIMER_MODE_SINGLE_SHOT,
|
||||
timer_handler);
|
||||
p_internal->p_cb->timer_created = true;
|
||||
}
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code = app_timer_start(*p_internal->p_timer,
|
||||
APP_TIMER_TICKS(RTT_RX_TIMEOUT),
|
||||
p_internal);
|
||||
SEGGER_RTT_Init();
|
||||
}
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
static ret_code_t cli_rtt_read(nrf_cli_transport_t const * p_transport,
|
||||
void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
|
||||
size_t rcnt = SEGGER_RTT_Read(NRF_CLI_RTT_TERMINAL_ID, p_data, length);
|
||||
*p_cnt = rcnt;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
static ret_code_t cli_rtt_write(nrf_cli_transport_t const * p_transport,
|
||||
const void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
UNUSED_PARAMETER(p_transport);
|
||||
|
||||
if (!(CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk))
|
||||
{
|
||||
/* If an RTT session is not active, but the RTT console is processed, the program may hang.
|
||||
* Workaround: If the debugger is not connected, always return NRF_SUCCESS.
|
||||
*/
|
||||
*p_cnt = length;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
size_t idx = 0;
|
||||
uint32_t processed;
|
||||
uint32_t watchdog_counter = NRF_CLI_RTT_TX_RETRY_CNT;
|
||||
const uint8_t * p_buffer = (const uint8_t *)p_data;
|
||||
do {
|
||||
processed = SEGGER_RTT_Write(NRF_CLI_RTT_TERMINAL_ID, &p_buffer[idx], length);
|
||||
if (processed == 0)
|
||||
{
|
||||
/* There are two possible reasons for not writing any data to RTT:
|
||||
* - The host is not connected and not reading the data.
|
||||
* - The buffer got full and will be read by the host.
|
||||
* These two situations are distinguished using the following algorithm.
|
||||
* At the begining, the module assumes that the host is active,
|
||||
* so when no data is read, it busy waits and retries.
|
||||
* If, after retrying, the host reads the data, the module assumes that the host is active.
|
||||
* If it fails, the module assumes that the host is inactive and stores that information. On next
|
||||
* call, only one attempt takes place. The host is marked as active if the attempt is successful.
|
||||
*/
|
||||
if (!m_host_present)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
nrf_delay_ms(NRF_CLI_RTT_TX_RETRY_DELAY_MS);
|
||||
watchdog_counter--;
|
||||
if (watchdog_counter == 0)
|
||||
{
|
||||
m_host_present = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_host_present = true;
|
||||
idx += processed;
|
||||
length -= processed;
|
||||
} while (length);
|
||||
|
||||
if (idx > 0)
|
||||
{
|
||||
*p_cnt = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p_cnt = length;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
const nrf_cli_transport_api_t nrf_cli_rtt_transport_api = {
|
||||
.init = cli_rtt_init,
|
||||
.uninit = cli_rtt_uninit,
|
||||
.enable = cli_rtt_enable,
|
||||
.read = cli_rtt_read,
|
||||
.write = cli_rtt_write,
|
||||
};
|
||||
|
||||
#endif
|
||||
100
components/libraries/cli/rtt/nrf_cli_rtt.h
Normal file
100
components/libraries/cli/rtt/nrf_cli_rtt.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 NRF_CLI_RTT_H__
|
||||
#define NRF_CLI_RTT_H__
|
||||
|
||||
#include "nrf_cli.h"
|
||||
#include "app_timer.h"
|
||||
#include "nordic_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup nrf_cli_rtt RTT command line interface transport layer
|
||||
* @ingroup nrf_cli
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Command line interface transport.
|
||||
*/
|
||||
extern const nrf_cli_transport_api_t nrf_cli_rtt_transport_api;
|
||||
|
||||
/**
|
||||
* @brief CLI RTT transport control block structure.
|
||||
*/
|
||||
typedef struct {
|
||||
nrf_cli_transport_handler_t handler; //!< Event handler
|
||||
void * p_context; //!< User context.
|
||||
bool timer_created;//!< Flag indicating whether a timer is created.
|
||||
} nrf_cli_rtt_internal_cb_t;
|
||||
|
||||
/**
|
||||
* @brief CLI RTT transport instance structure.
|
||||
*/
|
||||
typedef struct {
|
||||
nrf_cli_transport_t transport; //!< Transport structure.
|
||||
nrf_cli_rtt_internal_cb_t * p_cb; //!< Pointer to the instance control block.
|
||||
app_timer_id_t const * p_timer; //!< Pointer to the app_timer instance.
|
||||
} nrf_cli_rtt_internal_t;
|
||||
|
||||
/**@brief CLI RTT transport definition */
|
||||
#define NRF_CLI_RTT_DEF(_name_) \
|
||||
APP_TIMER_DEF(CONCAT_2(_name_, _timer)); \
|
||||
static nrf_cli_rtt_internal_cb_t CONCAT_2(_name_, _cb); \
|
||||
static const nrf_cli_rtt_internal_t _name_ = { \
|
||||
.transport = {.p_api = &nrf_cli_rtt_transport_api}, \
|
||||
.p_cb = &CONCAT_2(_name_, _cb), \
|
||||
.p_timer = &CONCAT_2(_name_, _timer) \
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_CLI_RTT_H__ */
|
||||
308
components/libraries/cli/uart/nrf_cli_uart.c
Normal file
308
components/libraries/cli/uart/nrf_cli_uart.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/**
|
||||
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* 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, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, 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 Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
|
||||
*
|
||||
*/
|
||||
#include "sdk_common.h"
|
||||
#if NRF_MODULE_ENABLED(NRF_CLI_UART)
|
||||
#include "nrf_cli_uart.h"
|
||||
#include "nrf_drv_uart.h"
|
||||
#include "nrf_assert.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME cli_uart
|
||||
|
||||
#define NRF_LOG_LEVEL (NRF_CLI_UART_CONFIG_LOG_ENABLED ? NRF_CLI_UART_CONFIG_LOG_LEVEL : 0)
|
||||
#define NRF_LOG_INFO_COLOR NRF_CLI_UART_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_CLI_UART_CONFIG_DEBUG_COLOR
|
||||
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define CLI_UART_RX_TIMEOUT 100
|
||||
|
||||
static ret_code_t rx_try(nrf_cli_uart_internal_t * p_internal)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
size_t len = 255;
|
||||
uint8_t * p_data;
|
||||
|
||||
err_code = nrf_ringbuf_alloc(p_internal->p_rx_ringbuf, &p_data, &len, true);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
|
||||
if ((err_code == NRF_SUCCESS) && len)
|
||||
{
|
||||
err_code = nrf_drv_uart_rx(p_internal->p_uart, p_data, len);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code = app_timer_start(*p_internal->p_timer,
|
||||
APP_TIMER_TICKS(CLI_UART_RX_TIMEOUT),
|
||||
p_internal);
|
||||
}
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static void uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context)
|
||||
{
|
||||
nrf_cli_uart_internal_t * p_internal = (nrf_cli_uart_internal_t *)p_context;
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
UNUSED_VARIABLE(err_code);
|
||||
uint8_t * p_data;
|
||||
size_t len = 255;
|
||||
switch (p_event->type)
|
||||
{
|
||||
case NRF_DRV_UART_EVT_ERROR:
|
||||
NRF_LOG_WARNING("id:%d, evt: ERROR:%d",
|
||||
p_internal->p_uart->inst_idx,
|
||||
p_event->data.error.error_mask);
|
||||
err_code = nrf_ringbuf_put(p_internal->p_rx_ringbuf, p_event->data.error.rxtx.bytes);
|
||||
ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NO_MEM));
|
||||
err_code = rx_try(p_internal);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
|
||||
break;
|
||||
|
||||
case NRF_DRV_UART_EVT_RX_DONE:
|
||||
err_code = nrf_ringbuf_put(p_internal->p_rx_ringbuf, p_event->data.rxtx.bytes);
|
||||
ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NO_MEM));
|
||||
|
||||
if (p_event->data.rxtx.bytes)
|
||||
{
|
||||
NRF_LOG_INFO("id:%d, evt: RXRDY len:%d",
|
||||
p_internal->p_uart->inst_idx,
|
||||
p_event->data.rxtx.bytes);
|
||||
NRF_LOG_HEXDUMP_DEBUG(p_event->data.rxtx.p_data, p_event->data.rxtx.bytes);
|
||||
p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_RX_RDY,
|
||||
p_internal->p_cb->p_context);
|
||||
}
|
||||
err_code = rx_try(p_internal);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
|
||||
break;
|
||||
|
||||
case NRF_DRV_UART_EVT_TX_DONE:
|
||||
err_code = nrf_ringbuf_free(p_internal->p_tx_ringbuf, p_event->data.rxtx.bytes);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
len = 255;
|
||||
err_code = nrf_ringbuf_get(p_internal->p_tx_ringbuf, &p_data, &len, true);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
if (len)
|
||||
{
|
||||
NRF_LOG_INFO("id:%d, evt uart_tx, len:%d", p_internal->p_uart->inst_idx, len);
|
||||
err_code = nrf_drv_uart_tx(p_internal->p_uart, p_data, len);
|
||||
ASSERT(err_code == NRF_SUCCESS);
|
||||
}
|
||||
p_internal->p_cb->handler(NRF_CLI_TRANSPORT_EVT_TX_RDY, p_internal->p_cb->p_context);
|
||||
NRF_LOG_INFO("id:%d, evt: TXRDY, len:%d",
|
||||
p_internal->p_uart->inst_idx,
|
||||
p_event->data.rxtx.bytes);
|
||||
break;
|
||||
|
||||
default:
|
||||
NRF_LOG_ERROR("Unknown event");
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_handler(void * p_context)
|
||||
{
|
||||
nrf_cli_uart_internal_t * p_internal = (nrf_cli_uart_internal_t *)p_context;
|
||||
NRF_LOG_DEBUG("id:%d, evt: Timeout", p_internal->p_uart->inst_idx);
|
||||
nrf_drv_uart_rx_abort(p_internal->p_uart);
|
||||
}
|
||||
|
||||
static ret_code_t cli_uart_init(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_config,
|
||||
nrf_cli_transport_handler_t evt_handler,
|
||||
void * p_context)
|
||||
{
|
||||
nrf_cli_uart_internal_t * p_internal =
|
||||
CONTAINER_OF(p_transport,
|
||||
nrf_cli_uart_internal_t,
|
||||
transport);
|
||||
p_internal->p_cb->handler = evt_handler;
|
||||
p_internal->p_cb->p_context = p_context;
|
||||
p_internal->p_cb->timer_created = false;
|
||||
p_internal->p_cb->blocking = false;
|
||||
|
||||
nrf_drv_uart_config_t * p_uart_config = (nrf_drv_uart_config_t *)p_config;
|
||||
memcpy(&p_internal->p_cb->uart_config, p_uart_config, sizeof(nrf_drv_uart_config_t));
|
||||
p_uart_config->p_context = (void *)p_internal;
|
||||
ret_code_t err_code = nrf_drv_uart_init(p_internal->p_uart,
|
||||
p_uart_config,
|
||||
uart_event_handler);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
nrf_ringbuf_init(p_internal->p_rx_ringbuf);
|
||||
nrf_ringbuf_init(p_internal->p_tx_ringbuf);
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t cli_uart_uninit(nrf_cli_transport_t const * p_transport)
|
||||
{
|
||||
nrf_cli_uart_internal_t * p_internal =
|
||||
CONTAINER_OF(p_transport,
|
||||
nrf_cli_uart_internal_t,
|
||||
transport);
|
||||
|
||||
nrf_drv_uart_uninit(p_internal->p_uart);
|
||||
|
||||
return app_timer_stop(*p_internal->p_timer);
|
||||
}
|
||||
|
||||
static ret_code_t cli_uart_enable(nrf_cli_transport_t const * p_transport,
|
||||
bool blocking)
|
||||
{
|
||||
nrf_cli_uart_internal_t * p_internal =
|
||||
CONTAINER_OF(p_transport,
|
||||
nrf_cli_uart_internal_t,
|
||||
transport);
|
||||
ret_code_t err_code = NRF_SUCCESS;
|
||||
|
||||
if (p_internal->p_cb->timer_created)
|
||||
{
|
||||
err_code = app_timer_stop(*p_internal->p_timer); //Timer may be running or inactive
|
||||
if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE))
|
||||
{
|
||||
return err_code;
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = NRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (blocking)
|
||||
{
|
||||
nrf_drv_uart_uninit(p_internal->p_uart);
|
||||
err_code = nrf_drv_uart_init(p_internal->p_uart, &p_internal->p_cb->uart_config, NULL);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
p_internal->p_cb->blocking = true;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!p_internal->p_cb->timer_created)
|
||||
{
|
||||
err_code = app_timer_create(p_internal->p_timer,
|
||||
APP_TIMER_MODE_SINGLE_SHOT,
|
||||
timer_handler);
|
||||
p_internal->p_cb->timer_created = true;
|
||||
}
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
err_code = rx_try(p_internal);
|
||||
}
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t cli_uart_read(nrf_cli_transport_t const * p_transport,
|
||||
void * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
nrf_cli_uart_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, nrf_cli_uart_internal_t, transport);
|
||||
|
||||
*p_cnt = length;
|
||||
ret_code_t err_code = nrf_ringbuf_cpy_get(p_instance->p_rx_ringbuf, p_data, p_cnt);
|
||||
|
||||
if (*p_cnt)
|
||||
{
|
||||
NRF_LOG_INFO("id:%d, read:%d", p_instance->p_uart->inst_idx, *p_cnt);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static ret_code_t cli_uart_write(nrf_cli_transport_t const * p_transport,
|
||||
void const * p_data,
|
||||
size_t length,
|
||||
size_t * p_cnt)
|
||||
{
|
||||
ASSERT(p_cnt);
|
||||
nrf_cli_uart_internal_t * p_instance =
|
||||
CONTAINER_OF(p_transport, nrf_cli_uart_internal_t, transport);
|
||||
ret_code_t err_code;
|
||||
*p_cnt = length;
|
||||
err_code = nrf_ringbuf_cpy_put(p_instance->p_tx_ringbuf, p_data, p_cnt);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INFO("id:%d, write, req:%d, done:%d",
|
||||
p_instance->p_uart->inst_idx,
|
||||
length,
|
||||
*p_cnt);
|
||||
|
||||
if (!nrf_drv_uart_tx_in_progress(p_instance->p_uart))
|
||||
{
|
||||
uint8_t * p_buf;
|
||||
size_t len = 255;
|
||||
if (nrf_ringbuf_get(p_instance->p_tx_ringbuf, &p_buf, &len, true) == NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_INFO("id:%d, uart_tx, len:%d", p_instance->p_uart->inst_idx, len);
|
||||
|
||||
err_code = nrf_drv_uart_tx(p_instance->p_uart, p_buf, len);
|
||||
if (p_instance->p_cb->blocking && (err_code == NRF_SUCCESS))
|
||||
{
|
||||
(void)nrf_ringbuf_free(p_instance->p_tx_ringbuf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
|
||||
const nrf_cli_transport_api_t nrf_cli_uart_transport_api = {
|
||||
.init = cli_uart_init,
|
||||
.uninit = cli_uart_uninit,
|
||||
.enable = cli_uart_enable,
|
||||
.read = cli_uart_read,
|
||||
.write = cli_uart_write,
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user