1. Add an API to set Provisioner static oob value 2. Add an API to deinit BLE Mesh stack 3. Add an API to set Provisioner unicast address 4. Add an API to provision devices with fixed address 5. Add an API to store node composition data 6. Add an API to get node with device uuid 7. Add an API to get node with unicast address 8. Add an API to delete node with device uuid 9. Add an API to delete node with unicast address 10. Add an API for Provisioner to update local AppKey 11. Add an API for Provisioner to update local NetKey 12. Support Provisioner persistent functionality 13. Fix Provisioner entering IV Update procedure 14. Fix an issue which may cause client failing to send msg 15. Use bt_mesh.flags to indicate device role 16. Remove several useless macros 17. Callback RSSI of received mesh provisioning packets 18. Modify the Provisioner disable function 19. Change some log level from debug to info 20. Add parameters to Provisioner bind AppKey completion event 21. Fix node ignoring relay messages issue 22. Support using a specific partition for BLE Mesh 23. Fix compile warning when proxy related macros are disabled 24. Clean up BLE Mesh stack included header files 25. NULL can be input if client message needs no parameters 26. Fix compile warning when BT log is disabled 27. Initilize BLE Mesh stack local variables 28. Support using PSRAM for BLE Mesh mutex, queue and task 29. Add a menuconfig option to enable using memory from PSRAM 30. Clean up sdkconfig.defaults of BLE Mesh examples
443 lines
13 KiB
C
443 lines
13 KiB
C
/*
|
|
* Copyright (c) 2011-2014, Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Misc utilities
|
|
*
|
|
* Misc utilities usable by the kernel and application code.
|
|
*/
|
|
|
|
#ifndef _BLE_MESH_UTIL_H_
|
|
#define _BLE_MESH_UTIL_H_
|
|
|
|
#include <stddef.h>
|
|
#include "soc/soc.h"
|
|
#include "mesh_types.h"
|
|
#include "mesh_trace.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* Helper to pass a int as a pointer or vice-versa.
|
|
* Those are available for 32 bits architectures:
|
|
*/
|
|
#define POINTER_TO_UINT(x) ((u32_t) (x))
|
|
#define UINT_TO_POINTER(x) ((void *) (x))
|
|
#define POINTER_TO_INT(x) ((s32_t) (x))
|
|
#define INT_TO_POINTER(x) ((void *) (x))
|
|
|
|
/* Evaluates to 0 if cond is true-ish; compile error otherwise */
|
|
#define ZERO_OR_COMPILE_ERROR(cond) ((int) sizeof(char[1 - 2 * !(cond)]) - 1)
|
|
|
|
/* Evaluates to 0 if array is an array; compile error if not array (e.g.
|
|
* pointer)
|
|
*/
|
|
#define IS_ARRAY(array) \
|
|
ZERO_OR_COMPILE_ERROR( \
|
|
!__builtin_types_compatible_p(__typeof__(array), \
|
|
__typeof__(&(array)[0])))
|
|
|
|
/* Evaluates to number of elements in an array; compile error if not
|
|
* an array (e.g. pointer)
|
|
*/
|
|
#define ARRAY_SIZE(array) \
|
|
((unsigned long) (IS_ARRAY(array) + \
|
|
(sizeof(array) / sizeof((array)[0]))))
|
|
|
|
/* Evaluates to 1 if ptr is part of array, 0 otherwise; compile error if
|
|
* "array" argument is not an array (e.g. "ptr" and "array" mixed up)
|
|
*/
|
|
#define PART_OF_ARRAY(array, ptr) \
|
|
((ptr) && ((ptr) >= &array[0] && (ptr) < &array[ARRAY_SIZE(array)]))
|
|
|
|
#define CONTAINER_OF(ptr, type, field) \
|
|
((type *)(((char *)(ptr)) - offsetof(type, field)))
|
|
|
|
/* round "x" up/down to next multiple of "align" (which must be a power of 2) */
|
|
#define ROUND_UP(x, align) \
|
|
(((unsigned long)(x) + ((unsigned long)align - 1)) & \
|
|
~((unsigned long)align - 1))
|
|
#define ROUND_DOWN(x, align) ((unsigned long)(x) & ~((unsigned long)align - 1))
|
|
|
|
#define ceiling_fraction(numerator, divider) \
|
|
(((numerator) + ((divider) - 1)) / (divider))
|
|
|
|
/* Internal helpers only used by the sys_* APIs further below */
|
|
#ifndef __bswap_16
|
|
#define __bswap_16(x) ((u16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
|
|
#endif
|
|
|
|
#ifndef __bswap_32
|
|
#define __bswap_32(x) ((u32_t) ((((x) >> 24) & 0xff) | \
|
|
(((x) >> 8) & 0xff00) | \
|
|
(((x) & 0xff00) << 8) | \
|
|
(((x) & 0xff) << 24)))
|
|
#endif
|
|
|
|
#ifndef __bswap_64
|
|
#define __bswap_64(x) ((u64_t) ((((x) >> 56) & 0xff) | \
|
|
(((x) >> 40) & 0xff00) | \
|
|
(((x) >> 24) & 0xff0000) | \
|
|
(((x) >> 8) & 0xff000000) | \
|
|
(((x) & 0xff000000) << 8) | \
|
|
(((x) & 0xff0000) << 24) | \
|
|
(((x) & 0xff00) << 40) | \
|
|
(((x) & 0xff) << 56)))
|
|
#endif
|
|
|
|
#define sys_le16_to_cpu(val) (val)
|
|
#define sys_cpu_to_le16(val) (val)
|
|
#define sys_be16_to_cpu(val) __bswap_16(val)
|
|
#define sys_cpu_to_be16(val) __bswap_16(val)
|
|
#define sys_le32_to_cpu(val) (val)
|
|
#define sys_cpu_to_le32(val) (val)
|
|
#define sys_le64_to_cpu(val) (val)
|
|
#define sys_cpu_to_le64(val) (val)
|
|
#define sys_be32_to_cpu(val) __bswap_32(val)
|
|
#define sys_cpu_to_be32(val) __bswap_32(val)
|
|
#define sys_be64_to_cpu(val) __bswap_64(val)
|
|
#define sys_cpu_to_be64(val) __bswap_64(val)
|
|
|
|
#ifndef MAX
|
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#ifndef MIN
|
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#ifndef BIT
|
|
#define BIT(n) (1UL << (n))
|
|
#endif
|
|
|
|
#ifndef BIT_MASK
|
|
#define BIT_MASK(n) (BIT(n) - 1)
|
|
#endif
|
|
|
|
/**
|
|
* @brief Check for macro definition in compiler-visible expressions
|
|
*
|
|
* This trick was pioneered in Linux as the config_enabled() macro.
|
|
* The madness has the effect of taking a macro value that may be
|
|
* defined to "1" (e.g. CONFIG_MYFEATURE), or may not be defined at
|
|
* all and turning it into a literal expression that can be used at
|
|
* "runtime". That is, it works similarly to
|
|
* "defined(CONFIG_MYFEATURE)" does except that it is an expansion
|
|
* that can exist in a standard expression and be seen by the compiler
|
|
* and optimizer. Thus much ifdef usage can be replaced with cleaner
|
|
* expressions like:
|
|
*
|
|
* if (IS_ENABLED(CONFIG_MYFEATURE))
|
|
* myfeature_enable();
|
|
*
|
|
* INTERNAL
|
|
* First pass just to expand any existing macros, we need the macro
|
|
* value to be e.g. a literal "1" at expansion time in the next macro,
|
|
* not "(1)", etc... Standard recursive expansion does not work.
|
|
*/
|
|
#define IS_ENABLED(config_macro) _IS_ENABLED1(config_macro)
|
|
|
|
/* Now stick on a "_XXXX" prefix, it will now be "_XXXX1" if config_macro
|
|
* is "1", or just "_XXXX" if it's undefined.
|
|
* ENABLED: _IS_ENABLED2(_XXXX1)
|
|
* DISABLED _IS_ENABLED2(_XXXX)
|
|
*/
|
|
#define _IS_ENABLED1(config_macro) _IS_ENABLED2(_XXXX##config_macro)
|
|
|
|
/* Here's the core trick, we map "_XXXX1" to "_YYYY," (i.e. a string
|
|
* with a trailing comma), so it has the effect of making this a
|
|
* two-argument tuple to the preprocessor only in the case where the
|
|
* value is defined to "1"
|
|
* ENABLED: _YYYY, <--- note comma!
|
|
* DISABLED: _XXXX
|
|
*/
|
|
#define _XXXX1 _YYYY,
|
|
|
|
/* Then we append an extra argument to fool the gcc preprocessor into
|
|
* accepting it as a varargs macro.
|
|
* arg1 arg2 arg3
|
|
* ENABLED: _IS_ENABLED3(_YYYY, 1, 0)
|
|
* DISABLED _IS_ENABLED3(_XXXX 1, 0)
|
|
*/
|
|
#define _IS_ENABLED2(one_or_two_args) _IS_ENABLED3(one_or_two_args 1, 0)
|
|
|
|
/* And our second argument is thus now cooked to be 1 in the case
|
|
* where the value is defined to 1, and 0 if not:
|
|
*/
|
|
#define _IS_ENABLED3(ignore_this, val, ...) val
|
|
|
|
/* ESP Toolchain doesn't support section */
|
|
#define ___in_section(a, b, c)
|
|
#define __in_section(a, b, c) ___in_section(a, b, c)
|
|
|
|
#define __in_section_unique(seg) ___in_section(seg, __FILE__, __COUNTER__)
|
|
|
|
#define popcount(x) __builtin_popcount(x)
|
|
|
|
/**
|
|
*
|
|
* @brief find most significant bit set in a 32-bit word
|
|
*
|
|
* This routine finds the first bit set starting from the most significant bit
|
|
* in the argument passed in and returns the index of that bit. Bits are
|
|
* numbered starting at 1 from the least significant bit. A return value of
|
|
* zero indicates that the value passed is zero.
|
|
*
|
|
* @return most significant bit set, 0 if @a op is 0
|
|
*/
|
|
|
|
#if defined(__GNUC__)
|
|
static inline unsigned int find_msb_set(u32_t op)
|
|
{
|
|
if (!op) {
|
|
return 0;
|
|
}
|
|
return 32 - __builtin_clz(op);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
*
|
|
* @brief find least significant bit set in a 32-bit word
|
|
*
|
|
* This routine finds the first bit set starting from the least significant bit
|
|
* in the argument passed in and returns the index of that bit. Bits are
|
|
* numbered starting at 1 from the least significant bit. A return value of
|
|
* zero indicates that the value passed is zero.
|
|
*
|
|
* @return least significant bit set, 0 if @a op is 0
|
|
*/
|
|
|
|
#if defined(__GNUC__)
|
|
static inline unsigned int find_lsb_set(u32_t op)
|
|
{
|
|
return __builtin_ffs(op);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief Put a 16-bit integer as big-endian to arbitrary location.
|
|
*
|
|
* Put a 16-bit integer, originally in host endianness, to a
|
|
* potentially unaligned memory location in big-endian format.
|
|
*
|
|
* @param val 16-bit integer in host endianness.
|
|
* @param dst Destination memory address to store the result.
|
|
*/
|
|
static inline void sys_put_be16(u16_t val, u8_t dst[2])
|
|
{
|
|
dst[0] = val >> 8;
|
|
dst[1] = val;
|
|
}
|
|
|
|
/**
|
|
* @brief Put a 32-bit integer as big-endian to arbitrary location.
|
|
*
|
|
* Put a 32-bit integer, originally in host endianness, to a
|
|
* potentially unaligned memory location in big-endian format.
|
|
*
|
|
* @param val 32-bit integer in host endianness.
|
|
* @param dst Destination memory address to store the result.
|
|
*/
|
|
static inline void sys_put_be32(u32_t val, u8_t dst[4])
|
|
{
|
|
sys_put_be16(val >> 16, dst);
|
|
sys_put_be16(val, &dst[2]);
|
|
}
|
|
|
|
/**
|
|
* @brief Put a 16-bit integer as little-endian to arbitrary location.
|
|
*
|
|
* Put a 16-bit integer, originally in host endianness, to a
|
|
* potentially unaligned memory location in little-endian format.
|
|
*
|
|
* @param val 16-bit integer in host endianness.
|
|
* @param dst Destination memory address to store the result.
|
|
*/
|
|
static inline void sys_put_le16(u16_t val, u8_t dst[2])
|
|
{
|
|
dst[0] = val;
|
|
dst[1] = val >> 8;
|
|
}
|
|
|
|
/**
|
|
* @brief Put a 32-bit integer as little-endian to arbitrary location.
|
|
*
|
|
* Put a 32-bit integer, originally in host endianness, to a
|
|
* potentially unaligned memory location in little-endian format.
|
|
*
|
|
* @param val 32-bit integer in host endianness.
|
|
* @param dst Destination memory address to store the result.
|
|
*/
|
|
static inline void sys_put_le32(u32_t val, u8_t dst[4])
|
|
{
|
|
sys_put_le16(val, dst);
|
|
sys_put_le16(val >> 16, &dst[2]);
|
|
}
|
|
|
|
/**
|
|
* @brief Put a 64-bit integer as little-endian to arbitrary location.
|
|
*
|
|
* Put a 64-bit integer, originally in host endianness, to a
|
|
* potentially unaligned memory location in little-endian format.
|
|
*
|
|
* @param val 64-bit integer in host endianness.
|
|
* @param dst Destination memory address to store the result.
|
|
*/
|
|
static inline void sys_put_le64(u64_t val, u8_t dst[8])
|
|
{
|
|
sys_put_le32(val, dst);
|
|
sys_put_le32(val >> 32, &dst[4]);
|
|
}
|
|
|
|
/**
|
|
* @brief Get a 16-bit integer stored in big-endian format.
|
|
*
|
|
* Get a 16-bit integer, stored in big-endian format in a potentially
|
|
* unaligned memory location, and convert it to the host endianness.
|
|
*
|
|
* @param src Location of the big-endian 16-bit integer to get.
|
|
*
|
|
* @return 16-bit integer in host endianness.
|
|
*/
|
|
static inline u16_t sys_get_be16(const u8_t src[2])
|
|
{
|
|
return ((u16_t)src[0] << 8) | src[1];
|
|
}
|
|
|
|
/**
|
|
* @brief Get a 32-bit integer stored in big-endian format.
|
|
*
|
|
* Get a 32-bit integer, stored in big-endian format in a potentially
|
|
* unaligned memory location, and convert it to the host endianness.
|
|
*
|
|
* @param src Location of the big-endian 32-bit integer to get.
|
|
*
|
|
* @return 32-bit integer in host endianness.
|
|
*/
|
|
static inline u32_t sys_get_be32(const u8_t src[4])
|
|
{
|
|
return ((u32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
|
|
}
|
|
|
|
/**
|
|
* @brief Get a 16-bit integer stored in little-endian format.
|
|
*
|
|
* Get a 16-bit integer, stored in little-endian format in a potentially
|
|
* unaligned memory location, and convert it to the host endianness.
|
|
*
|
|
* @param src Location of the little-endian 16-bit integer to get.
|
|
*
|
|
* @return 16-bit integer in host endianness.
|
|
*/
|
|
static inline u16_t sys_get_le16(const u8_t src[2])
|
|
{
|
|
return ((u16_t)src[1] << 8) | src[0];
|
|
}
|
|
|
|
/**
|
|
* @brief Get a 32-bit integer stored in little-endian format.
|
|
*
|
|
* Get a 32-bit integer, stored in little-endian format in a potentially
|
|
* unaligned memory location, and convert it to the host endianness.
|
|
*
|
|
* @param src Location of the little-endian 32-bit integer to get.
|
|
*
|
|
* @return 32-bit integer in host endianness.
|
|
*/
|
|
static inline u32_t sys_get_le32(const u8_t src[4])
|
|
{
|
|
return ((u32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
|
|
}
|
|
|
|
/**
|
|
* @brief Get a 64-bit integer stored in little-endian format.
|
|
*
|
|
* Get a 64-bit integer, stored in little-endian format in a potentially
|
|
* unaligned memory location, and convert it to the host endianness.
|
|
*
|
|
* @param src Location of the little-endian 64-bit integer to get.
|
|
*
|
|
* @return 64-bit integer in host endianness.
|
|
*/
|
|
static inline u64_t sys_get_le64(const u8_t src[8])
|
|
{
|
|
return ((u64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
|
|
}
|
|
|
|
const char *bt_hex(const void *buf, size_t len);
|
|
|
|
void mem_rcopy(u8_t *dst, u8_t const *src, u16_t len);
|
|
|
|
void _set(void *to, uint8_t val, unsigned int len);
|
|
|
|
unsigned int _copy(uint8_t *to, unsigned int to_len,
|
|
const uint8_t *from, unsigned int from_len);
|
|
|
|
void _set(void *to, uint8_t val, unsigned int len);
|
|
|
|
uint8_t _double_byte(uint8_t a);
|
|
|
|
int _compare(const uint8_t *a, const uint8_t *b, size_t size);
|
|
|
|
/**
|
|
* @brief Swap one buffer content into another
|
|
*
|
|
* Copy the content of src buffer into dst buffer in reversed order,
|
|
* i.e.: src[n] will be put in dst[end-n]
|
|
* Where n is an index and 'end' the last index in both arrays.
|
|
* The 2 memory pointers must be pointing to different areas, and have
|
|
* a minimum size of given length.
|
|
*
|
|
* @param dst A valid pointer on a memory area where to copy the data in
|
|
* @param src A valid pointer on a memory area where to copy the data from
|
|
* @param length Size of both dst and src memory areas
|
|
*/
|
|
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
|
|
{
|
|
u8_t *pdst = (u8_t *)dst;
|
|
const u8_t *psrc = (const u8_t *)src;
|
|
|
|
__ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
|
|
(psrc > pdst && (pdst + length) <= psrc)),
|
|
"Source and destination buffers must not overlap");
|
|
|
|
psrc += length - 1;
|
|
|
|
for (; length > 0; length--) {
|
|
*pdst++ = *psrc--;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Swap buffer content
|
|
*
|
|
* In-place memory swap, where final content will be reversed.
|
|
* I.e.: buf[n] will be put in buf[end-n]
|
|
* Where n is an index and 'end' the last index of buf.
|
|
*
|
|
* @param buf A valid pointer on a memory area to swap
|
|
* @param length Size of buf memory area
|
|
*/
|
|
static inline void sys_mem_swap(void *buf, size_t length)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < (length / 2); i++) {
|
|
u8_t tmp = ((u8_t *)buf)[i];
|
|
|
|
((u8_t *)buf)[i] = ((u8_t *)buf)[length - 1 - i];
|
|
((u8_t *)buf)[length - 1 - i] = tmp;
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* _BLE_MESH_UTIL_H_ */
|