pinebuds/services/ble_stack/common/api/co_utils.h

502 lines
20 KiB
C

#ifndef _CO_UTILS_H_
#define _CO_UTILS_H_
/**
****************************************************************************************
* @defgroup CO_UTILS Utilities
* @ingroup COMMON
* @brief Common utilities
*
* This module contains the common utilities functions and macros.
*
* @{
****************************************************************************************
*/
/*
* INCLUDE FILES
****************************************************************************************
*/
#include <stdint.h> // standard definitions
#include <stddef.h> // standard definitions
#include "co_bt.h" // common bt definitions
#include "rwip_config.h" // SW configuration
#include "compiler.h" // for inline functions
/*
* MACRO DEFINITIONS
****************************************************************************************
*/
/// Number of '1' bits in a byte
#define NB_ONE_BITS(byte) (one_bits[byte & 0x0F] + one_bits[byte >> 4])
/// Get the number of elements within an array, give also number of rows in a 2-D array
#define ARRAY_LEN(array) (sizeof((array))/sizeof((array)[0]))
/// Get the number of columns within a 2-D array
#define ARRAY_NB_COLUMNS(array) (sizeof((array[0]))/sizeof((array)[0][0]))
/// Macro for LMP message handler function declaration or definition
#define LMP_MSG_HANDLER(msg_name) __STATIC int lmp_##msg_name##_handler(struct lmp_##msg_name const *param, \
ke_task_id_t const dest_id)
/// Macro for LMP message handler function declaration or definition
#define LLCP_MSG_HANDLER(msg_name) __STATIC int llcp_##msg_name##_handler(struct llcp_##msg_name const *param, \
ke_task_id_t const dest_id)
/// Macro for HCI message handler function declaration or definition (for multi-instantiated tasks)
#define HCI_CMD_HANDLER_C(cmd_name, param_struct) __STATIC int hci_##cmd_name##_cmd_handler(param_struct const *param, \
ke_task_id_t const dest_id, \
uint16_t opcode)
/// Macro for HCI message handler function declaration or definition (with parameters)
#define HCI_CMD_HANDLER(cmd_name, param_struct) __STATIC int hci_##cmd_name##_cmd_handler(param_struct const *param, \
uint16_t opcode)
/// Macro for HCI message handler function declaration or definition (with parameters)
#define HCI_CMD_HANDLER_TAB(task) __STATIC const struct task##_hci_cmd_handler task##_hci_command_handler_tab[] =
/// MACRO to build a subversion field from the Minor and Release fields
#define CO_SUBVERSION_BUILD(minor, release) (((minor) << 8) | (release))
/// Macro to get a structure from one of its structure field
//#define CONTAINER_OF(ptr, type, member) ((type *)( (char *)ptr - offsetof(type,member) ))
/*
* ENUMERATIONS DEFINITIONS
****************************************************************************************
*/
/// Status returned by generic packer-unpacker
enum CO_UTIL_PACK_STATUS
{
CO_UTIL_PACK_OK,
CO_UTIL_PACK_IN_BUF_OVFLW,
CO_UTIL_PACK_OUT_BUF_OVFLW,
CO_UTIL_PACK_WRONG_FORMAT,
CO_UTIL_PACK_ERROR,
};
/*
* FUNCTION DECLARATIONS
****************************************************************************************
*/
/*
* TYPE DEFINITIONS
****************************************************************************************
*/
/*
* CONSTANT DECLARATIONS
****************************************************************************************
*/
/// Number of '1' bits in values from 0 to 15, used to fasten bit counting
extern const unsigned char one_bits[16];
/// Conversion table Sleep Clock Accuracy to PPM
extern const uint16_t co_sca2ppm[];
/// NULL BD address
extern const struct bd_addr co_null_bdaddr;
/// Default BD address
extern const struct bd_addr co_default_bdaddr;
/*
* OPERATIONS ON BT CLOCK
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Clocks addition with 2 operands
*
* @param[in] clock_a 1st operand value (in BT slots)
* @param[in] clock_b 2nd operand value (in BT slots)
* @return result operation result (in BT slots)
****************************************************************************************
*/
#define CLK_ADD_2(clock_a, clock_b) ((uint32_t)(((clock_a) + (clock_b)) & RWIP_MAX_CLOCK_TIME))
/**
****************************************************************************************
* @brief Clocks addition with 3 operands
*
* @param[in] clock_a 1st operand value (in BT slots)
* @param[in] clock_b 2nd operand value (in BT slots)
* @param[in] clock_c 3rd operand value (in BT slots)
* @return result operation result (in BT slots)
****************************************************************************************
*/
#define CLK_ADD_3(clock_a, clock_b, clock_c) ((uint32_t)(((clock_a) + (clock_b) + (clock_c)) & RWIP_MAX_CLOCK_TIME))
/**
****************************************************************************************
* @brief Clocks subtraction
*
* @param[in] clock_a 1st operand value (in BT slots)
* @param[in] clock_b 2nd operand value (in BT slots)
* @return result operation result (in BT slots)
****************************************************************************************
*/
#define CLK_SUB(clock_a, clock_b) ((uint32_t)(((clock_a) - (clock_b)) & RWIP_MAX_CLOCK_TIME))
/**
****************************************************************************************
* @brief Clocks time difference
*
* @param[in] clock_a 1st operand value (in BT half-slots)
* @param[in] clock_b 2nd operand value (in BT half-slots)
* @return result return the time difference from clock A to clock B
* - result < 0 => clock_b is in the past
* - result == 0 => clock_a is equal to clock_b
* - result > 0 => clock_b is in the future
****************************************************************************************
*/
#define CLK_DIFF(clock_a, clock_b) ( (CLK_SUB((clock_b), (clock_a)) > ((RWIP_MAX_CLOCK_TIME+1) >> 1)) ? \
((int32_t)((-CLK_SUB((clock_a), (clock_b))))) : ((int32_t)((CLK_SUB((clock_b), (clock_a))))) )
/// macro to extract a field from a value containing several fields
/// @param[in] __r bit field value
/// @param[in] __f field name
/// @return the value of the register masked and shifted
#define GETF(__r, __f) \
(( (__r) & (__f##_MASK) ) >> (__f##_LSB))
/// macro to set a field value into a value containing several fields.
/// @param[in] __r bit field value
/// @param[in] __f field name
/// @param[in] __v value to put in field
#define SETF(__r, __f, __v) \
do { \
ASSERT_INFO( ( ( ( (__v) << (__f##_LSB) ) & ( ~(__f##_MASK) ) ) ) == 0 ,(__f##_MASK), (__v)); \
__r = (((__r) & ~(__f##_MASK)) | (__v) << (__f##_LSB)); \
} while (0)
/// macro to extract a bit field from a value containing several fields
/// @param[in] __r bit field value
/// @param[in] __b bit field name
/// @return the value of the register masked and shifted
#define GETB(__r, __b) \
(( (__r) & (__b##_BIT) ) >> (__b##_POS))
/// macro to set a bit field value into a value containing several fields.
/// @param[in] __r bit field value
/// @param[in] __b bit field name
/// @param[in] __v value to put in field
#define SETB(__r, __b, __v) \
do { \
ASSERT_ERR( ( ( ( (__v) << (__b##_POS) ) & ( ~(__b##_BIT) ) ) ) == 0 ); \
__r = (((__r) & ~(__b##_BIT)) | (__v) << (__b##_POS)); \
} while (0)
#if (BLE_EMB_PRESENT)
/**
******************************************************************************
* @brief Compare 2 BLE instants (connection event counter)
* @param[in] instant_a 1st operand value (connection event counter)
* @param[in] instant_b 2nd operand value (connection event counter)
* @return result True: B is greater or equal to A | False: B is smaller than A
******************************************************************************
*/
#define CO_BLE_INSTANT_PASSED(instant_a, instant_b) ((uint16_t)(instant_b - instant_a) < 32767)
#endif //BLE_EMB_PRESENT
/*
* FUNCTION DECLARATIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Read an aligned 32 bit word.
* @param[in] ptr32 The address of the first byte of the 32 bit word.
* @return The 32 bit value.
****************************************************************************************
*/
__STATIC __INLINE uint32_t co_read32(void const *ptr32)
{
return *((uint32_t*)ptr32);
}
/**
****************************************************************************************
* @brief Read an aligned 16 bits word.
* @param[in] ptr16 The address of the first byte of the 16 bits word.
* @return The 16 bits value.
****************************************************************************************
*/
__STATIC __INLINE uint16_t co_read16(void const *ptr16)
{
return *((uint16_t*)ptr16);
}
/**
****************************************************************************************
* @brief Write an aligned 32 bits word.
* @param[in] ptr32 The address of the first byte of the 32 bits word.
* @param[in] value The value to write.
****************************************************************************************
*/
__STATIC __INLINE void co_write32(void const *ptr32, uint32_t value)
{
*(uint32_t*)ptr32 = value;
}
/**
****************************************************************************************
* @brief Write an aligned 16 bits word.
* @param[in] ptr16 The address of the first byte of the 16 bits word.
* @param[in] value The value to write.
****************************************************************************************
*/
__STATIC __INLINE void co_write16(void const *ptr16, uint32_t value)
{
*(uint16_t*)ptr16 = value;
}
/**
****************************************************************************************
* @brief Write a 8 bits word.
* @param[in] ptr8 The address of the first byte of the 8 bits word.
* @param[in] value The value to write.
****************************************************************************************
*/
__STATIC __INLINE void co_write8(void const *ptr8, uint32_t value)
{
*(uint8_t*)ptr8 = value;
}
/**
****************************************************************************************
* @brief Read a packed 16 bits word.
* @param[in] ptr16 The address of the first byte of the 16 bits word.
* @return The 16 bits value.
****************************************************************************************
*/
__STATIC __INLINE uint16_t co_read16p(void const *ptr16)
{
uint16_t value = ((uint8_t *)ptr16)[0] | ((uint8_t *)ptr16)[1] << 8;
return value;
}
/**
****************************************************************************************
* @brief Read a packed 24 bits word.
* @param[in] ptr24 The address of the first byte of the 24 bits word.
* @return The 24 bits value.
****************************************************************************************
*/
__STATIC __INLINE uint32_t co_read24p(void const *ptr24)
{
uint16_t addr_l, addr_h;
addr_l = co_read16p(ptr24);
addr_h = *((uint8_t *)ptr24 + 2) & 0x00FF;
return ((uint32_t)addr_l | (uint32_t)addr_h << 16);
}
/**
****************************************************************************************
* @brief Write a packed 24 bits word.
* @param[in] ptr24 The address of the first byte of the 24 bits word.
* @param[in] value The value to write.
****************************************************************************************
*/
__STATIC __INLINE void co_write24p(void const *ptr24, uint32_t value)
{
uint8_t *ptr=(uint8_t*)ptr24;
*ptr++ = (uint8_t)(value&0xff);
*ptr++ = (uint8_t)((value&0xff00)>>8);
*ptr++ = (uint8_t)((value&0xff0000)>>16);
}
/**
****************************************************************************************
* @brief Read a packed 32 bits word.
* @param[in] ptr32 The address of the first byte of the 32 bits word.
* @return The 32 bits value.
****************************************************************************************
*/
__STATIC __INLINE uint32_t co_read32p(void const *ptr32)
{
uint16_t addr_l, addr_h;
addr_l = co_read16p(ptr32);
addr_h = co_read16p((uint8_t *)ptr32 + 2);
return ((uint32_t)addr_l | (uint32_t)addr_h << 16);
}
/**
****************************************************************************************
* @brief Write a packed 32 bits word.
* @param[in] ptr32 The address of the first byte of the 32 bits word.
* @param[in] value The value to write.
****************************************************************************************
*/
__STATIC __INLINE void co_write32p(void const *ptr32, uint32_t value)
{
uint8_t *ptr=(uint8_t*)ptr32;
*ptr++ = (uint8_t)(value&0xff);
*ptr++ = (uint8_t)((value&0xff00)>>8);
*ptr++ = (uint8_t)((value&0xff0000)>>16);
*ptr = (uint8_t)((value&0xff000000)>>24);
}
/**
****************************************************************************************
* @brief Write a packed 16 bits word.
* @param[in] ptr16 The address of the first byte of the 16 bits word.
* @param[in] value The value to write.
****************************************************************************************
*/
__STATIC __INLINE void co_write16p(void const *ptr16, uint16_t value)
{
uint8_t *ptr=(uint8_t*)ptr16;
*ptr++ = value&0xff;
*ptr = (value&0xff00)>>8;
}
#if RW_DEBUG
/**
****************************************************************************************
* @brief Convert bytes to hexadecimal string
*
* @param[out] dest Pointer to the destination string (must be 2x longer than input table)
* @param[in] src Pointer to the bytes table
* @param[in] nb_bytes Number of bytes to display in the string
****************************************************************************************
*/
void co_bytes_to_string(char* dest, uint8_t* src, uint8_t nb_bytes);
#endif //RW_DEBUG
/**
****************************************************************************************
* @brief Compares two Bluetooth device addresses
*
* This function checks if the two bd address are equal.
*
* @param[in] bd_address1 Pointer on the first bd address to be compared.
* @param[in] bd_address2 Pointer on the second bd address to be compared.
*
* @return result of the comparison (true: equal | false: different).
****************************************************************************************
*/
bool co_bdaddr_compare(struct bd_addr const *bd_address1, struct bd_addr const *bd_address2);
#if (BLE_EMB_PRESENT)
/**
******************************************************************************
* @brief Count the number of good channels in a LE map
* @param[in] map Channel Map (bit fields for the 40 BT RF channels)
* @return Number of good channels
******************************************************************************
*/
uint8_t co_nb_good_le_channels(const struct le_chnl_map* map);
#endif //BLE_EMB_PRESENT
#if (BT_EMB_PRESENT)
/**
******************************************************************************
* @brief Convert an duration in baseband slot to a duration in number of ticks.
* @param[in] slot_cnt Duration in number of baseband slot
* @return Duration (in number of ticks).
******************************************************************************
*/
uint32_t co_slot_to_duration(uint16_t slot_cnt);
/**
******************************************************************************
* @brief Count the number of good channels in a map
* @param[in] map Channel Map (bit fields for the 79 BT RF channels)
* @return Number of good channels
******************************************************************************
*/
uint8_t co_nb_good_channels(const struct chnl_map* map);
#endif //BT_EMB_PRESENT
/**
****************************************************************************************
* @brief Pack parameters from a C structure to a packed buffer
*
* This function packs parameters according to a specific format. It takes care of the
* endianess, padding, required by the compiler.
*
* Format strings are the mechanism used to specify the expected layout when packing and unpacking data. They are built
* up from Format Characters, which specify the type of data being packed/unpacked.
* - B : byte - 8bits value
* - H : word - 16bits value
* - L : long - 32-bits value
* - XXB: table of several bytes, where XX is the byte number, in decimal
*
* Example: "BBLH12BL" => 1 byte | 1 byte | 1 long | 1 short | 12-bytes table | 1 long
*
* Note: the function works in the same buffer
*
* @param[out] out Output Data Buffer
* @param[in] in Input Data Buffer
* @param[out] out_len Output size of packed data (in bytes)
* @param[in] in_len Input buffer size (in bytes)
* @param[in] format Parameters format
*
* @return Status of the packing operation
*****************************************************************************************
*/
enum CO_UTIL_PACK_STATUS co_util_pack(uint8_t* out, uint8_t* in, uint16_t* out_len, uint16_t in_len, const char* format);
/**
****************************************************************************************
* @brief Unpack parameters from an unpacked buffer to a C structure
*
* This function unpacks parameters according to a specific format. It takes care of the
* endianess, padding, required by the compiler.
*
* Format strings are the mechanism used to specify the expected layout when packing and unpacking data. They are built
* up from Format Characters, which specify the type of data being packed/unpacked.
* - B : byte - 8bits value
* - H : word - 16bits value
* - L : long - 32-bits value
* - XXB: table of several bytes, where XX is the byte number, in decimal
*
* Example: "BBLH12BL" => 1 byte | 1 byte | 1 long | 1 short | 12-bytes table | 1 long
*
* Note: the output buffer provided must be large enough to contain the unpacked data.
* Note2: if a NULL output buffer is provided, the function does not copy the unpacked parameters. It still parses the
* format string and input buffer to return the number of unpacked bytes. Can be used to compute the expected unpacked
* buffer size.
*
* @param[out] out Unpacked parameters buffer
* @param[in] in Packed parameters buffer
* @param[inout] out_len Input: buffer size / Output: size of unpacked data (in bytes)
* @param[in] in_len Size of the packed data (in bytes)
* @param[in] format Parameters format
*
* @return Status of the unpacking operation
*****************************************************************************************
*/
enum CO_UTIL_PACK_STATUS co_util_unpack(uint8_t* out, uint8_t* in, uint16_t* out_len, uint16_t in_len, const char* format);
/// @} CO_UTILS
#endif // _CO_UTILS_H_