blob: 28c7dcea4588e1560eb4dccd05dbbc5b4eaaea0f [file] [log] [blame]
/**
****************************************************************************************
*
* @file co_utils.h
*
* @brief Common utilities definitions
*
* Copyright (C) RivieraWaves 2009-2015
* Copyright (C) Atmosic 2023
*
****************************************************************************************
*/
#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 "rwip.h" // SW configuration
#include "compiler.h" // for inline functions
/*
* MACRO DEFINITIONS
****************************************************************************************
*/
/// Common constants - bit field definitions
#define BIT0 0x0001
#define BIT1 0x0002
#define BIT2 0x0004
#define BIT3 0x0008
#define BIT4 0x0010
#define BIT5 0x0020
#define BIT6 0x0040
#define BIT7 0x0080
#define BIT8 0x0100
#define BIT9 0x0200
#define BIT10 0x0400
#define BIT11 0x0800
#define BIT12 0x1000
#define BIT13 0x2000
#define BIT14 0x4000
#define BIT15 0x8000
/// 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) ))
/// Increment value and make sure it's never greater or equals max (else wrap to 0)
#define CO_VAL_INC(_val, _max) \
(_val) = (_val) + 1; \
if((_val) >= (_max)) (_val) = 0
/*
* 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,
};
/// Rate information
/*@TRACE*/
enum phy_rate
{
/// 1 Mbits/s Rate
CO_RATE_1MBPS = 0,
/// 2 Mbits/s Rate
CO_RATE_2MBPS = 1,
/// 125 Kbits/s Rate
CO_RATE_125KBPS = 2,
/// 500 Kbits/s Rate
CO_RATE_500KBPS = 3,
/// Undefined rate (used for reporting when no packet is received)
CO_RATE_UNDEF = 4,
CO_RATE_MAX = 4,
};
/*
* 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;
/// Table for converting rate to PHY
extern const uint8_t co_rate_to_phy[];
/// Table for converting PHY to rate (Warning: the coded PHY is converted to 125K by default)
extern const uint8_t co_phy_to_rate[];
/// Convert PHY mask (with one single bit set) to a value
extern const uint8_t co_phy_mask_to_value[];
/// Convert PHY a value to the corresponding mask bit
extern const uint8_t co_phy_value_to_mask[];
/// Convert Rate value to the corresponding PHY mask bit
extern const uint8_t co_rate_to_phy_mask[];
/// Convert Rate value to byte duration in us
extern const uint8_t co_rate_to_byte_dur_us[];
/*
* OPERATIONS ON BT CLOCK
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Clocks addition with 2 operands
*
* @param[in] clock_a 1st operand value (in BT half-slots)
* @param[in] clock_b 2nd operand value (in BT half-slots)
* @return result operation result (in BT half-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 half-slots)
* @param[in] clock_b 2nd operand value (in BT half-slots)
* @param[in] clock_c 3rd operand value (in BT half-slots)
* @return result operation result (in BT half-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 half-slots)
* @param[in] clock_b 2nd operand value (in BT half-slots)
* @return result operation result (in BT half-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)
/// macro to toggle a bit into a value containing several bits.
/// @param[in] __r bit field value
/// @param[in] __b bit field name
#define TOGB(__r, __b) \
do { \
__r = ((__r) ^ (__b##_BIT)); \
} while (0)
/**
****************************************************************************************
* @brief Check if clock_a is equal to clock_b
*
* @param[in] clock_a Clock A value (in BT half-slots)
* @param[in] clock_b Clock B value (in BT half-slots)
* @return result True: clock_a lower than or equal to clock_b | False: else
****************************************************************************************
*/
#define CLK_EQ(clock_a, clock_b) (clock_b == clock_a)
/**
****************************************************************************************
* @brief Check if clock_a is lower than or equal to clock_b
*
* @param[in] clock_a Clock A value (in BT half-slots)
* @param[in] clock_b Clock B value (in BT half-slots)
* @return result True: clock_a lower than or equal to clock_b | False: else
****************************************************************************************
*/
#define CLK_LOWER_EQ(clock_a, clock_b) (CLK_SUB(clock_b, clock_a) < (RWIP_MAX_CLOCK_TIME >> 1))
/**
****************************************************************************************
* @brief Check if clock A is lower than or equal to clock B (with half-us precision)
*
* @param[in] int_a Integer part of clock A (in BT half-slots)
* @param[in] fract_a Fractional part of clock A (in half-us) (range: 0 to 624)
* @param[in] int_b Integer part of clock B (in BT half-slots)
* @param[in] fract_b Fractional part of clock B (in half-us) (range: 0 to 624)
* @return result True: clock A lower than or equal to clock B | False: else
****************************************************************************************
*/
#define CLK_LOWER_EQ_HUS(int_a, fract_a, int_b, fract_b) ( CLK_GREATER_THAN(int_b, int_a) \
|| ( CLK_EQ(int_a, int_b) \
&& (fract_a <= fract_b) ) ) \
/**
****************************************************************************************
* @brief Check if clock_a is greater than clock_b
*
* @param[in] clock_a Clock A value (in BT half-slots)
* @param[in] clock_b Clock B value (in BT half-slots)
* @return result True: clock_a is greater than clock_b | False: else
****************************************************************************************
*/
#define CLK_GREATER_THAN(clock_a, clock_b) !(CLK_LOWER_EQ(clock_a, clock_b))
/**
****************************************************************************************
* @brief Check if clock A is greater than clock B (with half-us precision)
*
* @param[in] int_a Integer part of clock A (in BT half-slots)
* @param[in] fract_a Fractional part of clock A (in half-us) (range: 0 to 624)
* @param[in] int_b Integer part of clock B (in BT half-slots)
* @param[in] fract_b Fractional part of clock B (in half-us) (range: 0 to 624)
* @return result True: clock A greater than clock B | False: else
****************************************************************************************
*/
#define CLK_GREATER_THAN_HUS(int_a, fract_a, int_b, fract_b) ( CLK_GREATER_THAN(int_a, int_b) \
|| ( CLK_EQ(int_a, int_b) \
&& (fract_a > fract_b) ) ) \
#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)
/**
******************************************************************************
* @brief Compute difference between two event counter
* @param[in] evt_cnt_a 1st operand value (connection event counter)
* @param[in] evt_cnt_b 2nd operand value (connection event counter)
* @return result return the time difference from evt_cnt_a to evt_cnt_b
* - result < 0 => evt_cnt_b is in the past
* - result == 0 => evt_cnt_a is equal to evt_cnt_b
* - result > 0 => evt_cnt_b is in the future
******************************************************************************
*/
#define CO_BLE_EVT_CNT_DIFF(evt_cnt_a, evt_cnt_b) ((((uint16_t) (evt_cnt_b)) - ((uint16_t) (evt_cnt_a)) > 32768) \
? ((int16_t)(-(((uint16_t) (evt_cnt_a)) - ((uint16_t) (evt_cnt_b))))) \
: ((int16_t)(-(((uint16_t) (evt_cnt_b)) - ((uint16_t) (evt_cnt_a))))))
#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.
****************************************************************************************
*/
__INLINE uint32_t co_read32(void const *ptr32)
{
return *((uint32_t const *)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.
****************************************************************************************
*/
__INLINE uint16_t co_read16(void const *ptr16)
{
return *((uint16_t const *)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.
****************************************************************************************
*/
__INLINE void co_write32(void *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.
****************************************************************************************
*/
__INLINE void co_write16(void *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.
****************************************************************************************
*/
__INLINE void co_write8(void *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.
****************************************************************************************
*/
__INLINE uint16_t co_read16p(void const *ptr16)
{
uint16_t value = ((uint8_t const *)ptr16)[0] | ((uint8_t const *)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.
****************************************************************************************
*/
__INLINE uint32_t co_read24p(void const *ptr24)
{
uint16_t addr_l, addr_h;
addr_l = co_read16p(ptr24);
addr_h = *((uint8_t const *)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.
****************************************************************************************
*/
__INLINE void co_write24p(void *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.
****************************************************************************************
*/
__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 const *)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.
****************************************************************************************
*/
__INLINE void co_write32p(void *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.
****************************************************************************************
*/
__INLINE void co_write16p(void *ptr16, uint16_t value)
{
uint8_t *ptr=(uint8_t*)ptr16;
*ptr++ = value&0xff;
*ptr = (value&0xff00)>>8;
}
#if (RW_DEBUG || DISPLAY_SUPPORT)
/**
****************************************************************************************
* @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 || DISPLAY_SUPPORT)
/**
****************************************************************************************
* @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 a 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(uint32_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.
*
* By default output format is LSB but it can be changed with first character of format string
* - < : LSB output format
* - > : MSB output format
*
* 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
* - D : 24 bits value
* - XXB: table of several bytes, where XX is the byte number, in decimal
* - XXG: Number of several bytes, where XX is the byte number, in decimal - subject to be swapped according to endianess
* - nB : table size over 1 byte, followed by the table of bytes
* - NB : table size over 2 bytes, followed by the table of bytes
*
* Example: "BBLH12BLnB" => 1 byte | 1 byte | 1 long | 1 short | 12-bytes table | 1 long | table size over 1 byte | n-bytes table
*
* 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
*****************************************************************************************
*/
uint8_t 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.
*
* By default input format is LSB but it can be changed with first character of format string
* - < : LSB input format
* - > : MSB input format
*
* 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
* - D : 24 bits value
* - XXB: table of several bytes, where XX is the byte number, in decimal
* - XXG: Number of several bytes, where XX is the byte number, in decimal - subject to be swapped according to endianess
* - nB : table size over 1 byte, followed by the table of bytes
* - NB : table size over 2 bytes, followed by the table of bytes
*
* Example: "BBLH12BLnB" => 1 byte | 1 byte | 1 long | 1 short | 12-bytes table | 1 long | table size over 1 byte | n-bytes table
*
* 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
*****************************************************************************************
*/
uint8_t co_util_unpack(uint8_t* out, uint8_t* in, uint16_t* out_len, uint16_t in_len, const char* format);
#if (BLE_EMB_PRESENT)
/**
*****************************************************************************************
* @brief Get BLE packet duration in us according to PHY and packet size
*
* @param[in] len PDU size in octets
* @param[in] rate PHY Rate (@see enum lld_phy)
*
* @return packet duration in us.
*****************************************************************************************
*/
uint16_t co_ble_pkt_dur_in_us(uint8_t len, uint8_t rate);
#endif // (BLE_EMB_PRESENT)
/// @} CO_UTILS
#endif // _CO_UTILS_H_