/** ****************************************************************************** * @file ll_aton_NN_interface.h * @author SRA Artificial Intelligence & Embedded Architectures * @brief Interface that defines a NN generated by the AtoNN Compiler. ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ #ifndef __LL_ATON_NN_INTERFACE_H #define __LL_ATON_NN_INTERFACE_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include "ll_aton_config.h" #include "ll_aton_attributes.h" #include "ll_aton_util.h" /* this is needed to avoid some compilers (e.g. KEIL) that observe a strict semantic about conversion of * pointers to integers in cost initializers */ typedef union { unsigned char *p; uintptr_t i; } __LL_address_t; typedef void (*EpochBlock_FuncPtr_t)(const void *epoch_block); typedef enum LL_ATON_RT_RetValues { LL_ATON_RT_NO_WFE = 0, LL_ATON_RT_WFE, LL_ATON_RT_DONE, } LL_ATON_RT_RetValues_t; typedef enum LL_ATON_RT_Callbacktype { LL_ATON_RT_Callbacktype_PRE_START, /**< Callback called before start_epoch_block */ LL_ATON_RT_Callbacktype_POST_START, /**< Callback called after start_epoch_block */ LL_ATON_RT_Callbacktype_PRE_END, /**< Callback called before end_epoch_block */ LL_ATON_RT_Callbacktype_POST_END, /**< Callback called after end_epoch_block */ LL_ATON_RT_Callbacktype_NN_Init, /**< Callback called after `LL_ATON_RT_Init_Network`, * NOTE: 3rd parameter passed is `NULL` */ LL_ATON_RT_Callbacktype_NN_DeInit, /**< Callback called after `LL_ATON_RT_DeInit_Network`, * NOTE: 3rd parameter passed is `NULL` */ LL_ATON_RT_Callbacktype_RT_Init, /**< Callback called after `LL_ATON_RT_RuntimeInit` */ LL_ATON_RT_Callbacktype_RT_Deinit, /**< Callback called before `LL_ATON_RT_RuntimeDeInit` */ } LL_ATON_RT_Callbacktype_t; typedef enum LL_ATON_User_IO_Result { LL_ATON_User_IO_NOERROR, /**< */ LL_ATON_User_IO_WRONG_ALIGN, /**< */ LL_ATON_User_IO_WRONG_SIZE, /**< */ LL_ATON_User_IO_WRONG_INDEX, /**< */ } LL_ATON_User_IO_Result_t; typedef enum { EpochBlock_Flags_NONE = 0x0, /**< */ EpochBlock_Flags_epoch_start = (0x1 << 0), /**< First EpochBlock of an Epoch */ EpochBlock_Flags_epoch_end = (0x1 << 1), /**< Last EpochBlock of an Epoch */ EpochBlock_Flags_blob = (0x1 << 2), /**< Item is an Epoch Blob */ EpochBlock_Flags_last_eb = (0x1 << 3), /**< Last EpochBlock */ EpochBlock_Flags_pure_hw = (0x1 << 4), /**< Pure HW EpochBlock */ EpochBlock_Flags_pure_sw = (0x1 << 5), /**< Pure SW EpochBlock */ EpochBlock_Flags_hybrid = (0x1 << 6), /**< Hybrid EpochBlock (i.e. mixed HW/SW) */ EpochBlock_Flags_internal = (0x1 << 7), /**< ATON lib internal EpochBlock (used to implement hybrid epochs) */ } EpochBlock_Flags_t; typedef struct { EpochBlock_FuncPtr_t start_epoch_block; /**< Method to execute the EpochBlock */ EpochBlock_FuncPtr_t end_epoch_block; /**< Method to be executed when the EpochBlock ends */ uintptr_t blob_address; /**< Blob address (in case this EpochBlock represents an epoch blob) */ uint32_t wait_mask; /**< Mask needed to check when an EpochBlock ends * - if epoch blob: number (not bitmask) of epoch controller unit to use * - otherwise: bitmask with all output streaming engines to wait for before ending epoch */ uint16_t flags; /**< EpochBlock flags */ #ifdef LL_ATON_EB_DBG_INFO int16_t epoch_num; /**< Epoch number / First epoch number within blob */ int16_t last_epoch_num; /**< Epoch number / Last epoch number within blob */ uint32_t in_streng_mask; /**< Debug information about input streaming engines used in epoch */ uint32_t out_streng_mask; /**< Debug information about output streaming engines used in epoch */ uint64_t estimated_npu_cycles; /**< Debug information estimates for NPU cycles in epoch w/o memory penalty */ uint64_t estimated_tot_cycles; /**< Debug information estimates for NPU cycles in epoch w/ memory penalty */ #endif // LL_ATON_EB_DBG_INFO } EpochBlock_ItemTypeDef; /** * @brief Checks if the pointed element is the last one of an array of `const EpochBlock_ItemTypeDef` * */ static inline bool EpochBlock_IsLastEpochBlock(const EpochBlock_ItemTypeDef *eb); /** * @brief Checks if the pointed element is the first EpochBlock of an Epoch * */ static inline bool EpochBlock_IsEpochStart(const EpochBlock_ItemTypeDef *eb); /** * @brief Checks if the pointed element is the last EpochBlock of an Epoch * */ static inline bool EpochBlock_IsEpochEnd(const EpochBlock_ItemTypeDef *eb); /** * @brief Checks if the pointed element is the an Epoch Blob * */ static inline bool EpochBlock_IsEpochBlob(const EpochBlock_ItemTypeDef *eb); /** * @brief Checks if the pointed element is pure SW epoch * */ static inline bool EpochBlock_IsEpochPureSW(const EpochBlock_ItemTypeDef *eb); /** * @brief Checks if the pointed element is a pure HW or mixed SW/HW epoch * */ static inline bool EpochBlock_IsEpochPureHW(const EpochBlock_ItemTypeDef *eb); /** * @brief Checks if the pointed element is a hybrid epoch * */ static inline bool EpochBlock_IsEpochHybrid(const EpochBlock_ItemTypeDef *eb); /** * @brief Checks if the pointed element is an internal epoch * */ static inline bool EpochBlock_IsEpochInternal(const EpochBlock_ItemTypeDef *eb); /** * @brief Returns the Epoch controller id to use * */ static inline uint32_t EpochBlock_EpochControllerUnit(const EpochBlock_ItemTypeDef *eb); /** * @brief Returns the address of the configuration of the epoch controller (the blob address) * */ static inline uintptr_t EpochBlock_EpochBlobAddr(const EpochBlock_ItemTypeDef *eb); /** * @brief ATON buffer types definition */ typedef enum { DataType_UNDEFINED = 0, DataType_FLOAT = 1, DataType_UINT8 = 2, DataType_INT8 = 3, DataType_UINT16 = 4, DataType_INT16 = 5, DataType_INT32 = 6, DataType_INT64 = 7, DataType_STRING = 8, DataType_BOOL = 9, DataType_FLOAT16 = 10, DataType_DOUBLE = 11, DataType_UINT32 = 12, DataType_UINT64 = 13, DataType_COMPLEX64 = 14, DataType_COMPLEX128 = 15, DataType_BFLOAT16 = 16, DataType_FXP = 100 // AtoNN specific } Buffer_DataType_TypeDef; /** * @brief ATON buffer Channel position */ typedef enum { CHPos_UNDEFINED = 0, /**< No channel present */ CHPos_First = 1, /**< Channel First ( ...B C H W )*/ CHPos_Last = 2, /**< Channel Last ( ...B H W C ) */ CHPos_Mixed = 3, /**< Channel with Batch(b) ( ...B C/b H W b ) */ } Buffer_CHPos_TypeDef; /** * @brief ATON buffer definition */ typedef struct { const char *name; /**< Buffer name. NULL if end of list */ __LL_address_t addr_base; /**< Buffer base address */ uint32_t offset_start; /**< Offset of the buffer start address from the base address */ uint32_t offset_end; /**< Offset of the buffer end address from the base address * (first bytes address beyond buffer length) */ uint32_t offset_limit; /**< Offset of the limiter address from the base address, * (needed for configuring streaming engines) */ uint8_t is_user_allocated; /**< */ uint8_t is_param; /**< */ uint16_t epoch; /**< */ uint32_t batch; /**< */ const uint32_t *mem_shape; /**< shape as seen by the user in memory (only valid for input/output buffers) */ uint16_t mem_ndims; /**< Number of dimensions of mem_shape (Length of mem_shape) */ Buffer_CHPos_TypeDef chpos; /**< Position of channels dimension in mem shape */ Buffer_DataType_TypeDef type; /**< */ int8_t Qm; /**< */ int8_t Qn; /**< */ uint8_t Qunsigned; /**< */ uint8_t ndims; /**< */ uint8_t nbits; /**< */ uint8_t per_channel; /**< */ const uint32_t *shape; /**< */ const float *scale; /**< */ const int16_t *offset; /**< This can become int8 or uint8 based on the Qunsigned field. * (This field Must have the same format of the quantized value) */ } LL_Buffer_InfoTypeDef; /** * @brief returns the base address of the mem pool the buffer is allocated in * */ static inline unsigned char *LL_Buffer_addr_base(const LL_Buffer_InfoTypeDef *buf); /** * @brief returns the start address of the buffer * */ static inline unsigned char *LL_Buffer_addr_start(const LL_Buffer_InfoTypeDef *buf); /** * @brief returns the end address of the buffer * */ static inline unsigned char *LL_Buffer_addr_end(const LL_Buffer_InfoTypeDef *buf); /** * @brief returns the limit address of the buffer * */ static inline unsigned char *LL_Buffer_addr_limit(const LL_Buffer_InfoTypeDef *buf); /** * @brief returns the length of the buffer * */ static inline uint32_t LL_Buffer_len(const LL_Buffer_InfoTypeDef *buf); /** * @brief returns the buffer elements number of bits * */ static inline uint32_t LL_Buffer_bits(const LL_Buffer_InfoTypeDef *buf); /** @defgroup ATONN_COMPILER Functions autogenerated by the AtoNN compiler * @{ */ /** * @brief Initialize a Network internal structures for the Epoch Controller * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @retval returns if the action succeded or an error occured */ extern bool LL_ATON_EC_Network_Init_Default(void); /** * @brief Update a Network internal structures for the Epoch Controller before the execution of an Inference * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @retval returns if the action succeded or an error occured */ extern bool LL_ATON_EC_Inference_Init_Default(void); /** * @brief Sets user allocated inputs (one at a time) * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @param num zero base index of the input buffer to set * @param buffer pointer to the area used to store this input * @param size size of the memory reserved for this input */ extern LL_ATON_User_IO_Result_t LL_ATON_Set_User_Input_Buffer_Default(uint32_t num, void *buffer, uint32_t size); /** * @brief Gets user allocated inputs (one at a time) * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @param num zero base index of the input buffer to get * @retval returns a pointer to the specified user allocated input */ extern void *LL_ATON_Get_User_Input_Buffer_Default(uint32_t num); /** * @brief Sets user allocated outputs (one at a time) * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @param num zero base index of the output buffer to set * @param buffer pointer to the area used to store this output * @param size size of the memory reserved for this output */ extern LL_ATON_User_IO_Result_t LL_ATON_Set_User_Output_Buffer_Default(uint32_t num, void *buffer, uint32_t size); /** * @brief Gets user allocated inputs (one at a time) * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @param num zero base index of the output buffer to get * @retval returns a pointer to the specified user allocated output */ extern void *LL_ATON_Get_User_Output_Buffer_Default(uint32_t num); /** * @brief Returns an array of structures describing the epoch blocks of the NN to execute * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @retval returns a pointer to an array of `const EpochBlock_ItemTypeDef`, * if `flags` contain `EpochBlock_Flags_last_eb` identifies the last (empty) EpochBlock (i.e. we are done) * (see helper function `EpochBlock_IsLastEpochBlock()`) */ extern const EpochBlock_ItemTypeDef *LL_ATON_EpochBlockItems_Default(void); /** * @brief Returns an array of structures describing input buffers * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @retval returns a pointer to the array of LL_Buffer_InfoTypeDef, name is NULL for the last one */ extern const LL_Buffer_InfoTypeDef *LL_ATON_Output_Buffers_Info_Default(void); /** * @brief Returns an array of structures describing output buffers * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @retval Returns a pointer to the array of LL_Buffer_InfoTypeDef, name is NULL for the last one */ extern const LL_Buffer_InfoTypeDef *LL_ATON_Input_Buffers_Info_Default(void); /** * @brief Returns an array of structures describing epoch output transient buffers * @note This function is generated by the AtoNN compiler when called without a network name * (i.e. without option `--network-name`) * @note Use macro `LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name)` instead when the network has been generated * (by the AtoNN compiler) with a network name (i.e. with option `--network-name`) * @retval Returns a pointer to the array of LL_Buffer_InfoTypeDef, name is NULL for the last one */ extern const LL_Buffer_InfoTypeDef *LL_ATON_Internal_Buffers_Info_Default(void); /** * @brief Declare the function prototypes for named NN interface functions generated by the AtoNN compiler * @param network_name name of the network as provided by option `--network-name` */ #define LL_ATON_DECLARE_NAMED_NN_PROTOS(network_name) \ extern bool LL_ATON_EC_Network_Init_##network_name(void); \ extern bool LL_ATON_EC_Inference_Init_##network_name(void); \ extern LL_ATON_User_IO_Result_t LL_ATON_Set_User_Input_Buffer_##network_name(uint32_t num, void *buffer, \ uint32_t size); \ extern void *LL_ATON_Get_User_Input_Buffer_##network_name(uint32_t num); \ extern LL_ATON_User_IO_Result_t LL_ATON_Set_User_Output_Buffer_##network_name(uint32_t num, void *buffer, \ uint32_t size); \ extern void *LL_ATON_Get_User_Output_Buffer_##network_name(uint32_t num); \ extern const EpochBlock_ItemTypeDef *LL_ATON_EpochBlockItems_##network_name(void); \ extern const LL_Buffer_InfoTypeDef *LL_ATON_Output_Buffers_Info_##network_name(void); \ extern const LL_Buffer_InfoTypeDef *LL_ATON_Input_Buffers_Info_##network_name(void); \ extern const LL_Buffer_InfoTypeDef *LL_ATON_Internal_Buffers_Info_##network_name(void); /** * @brief Type definitions for NN interface functions */ typedef bool (*NN_EC_Hook_TypeDef)(void); typedef LL_ATON_User_IO_Result_t (*NN_InputSetter_TypeDef)(uint32_t num, void *buffer, uint32_t size); typedef void *(*NN_InputGetter_TypeDef)(uint32_t num); typedef LL_ATON_User_IO_Result_t (*NN_OutputSetter_TypeDef)(uint32_t num, void *buffer, uint32_t size); typedef void *(*NN_OutputGetter_TypeDef)(uint32_t num); typedef const EpochBlock_ItemTypeDef *(*NN_EpochBlockItems_TypeDef)(void); typedef const LL_Buffer_InfoTypeDef *(*NN_Buffers_Info_TypeDef)(void); typedef void (*TraceRuntime_FuncPtr_t)(LL_ATON_RT_Callbacktype_t ctype); struct __nn_instance_struct; // forward declaration typedef struct __nn_instance_struct NN_Instance_TypeDef; typedef void (*TraceEpochBlock_FuncPtr_t)(LL_ATON_RT_Callbacktype_t ctype, const NN_Instance_TypeDef *nn_instance, const EpochBlock_ItemTypeDef *epoch_block); typedef struct { const char *network_name; NN_EC_Hook_TypeDef ec_network_init; NN_EC_Hook_TypeDef ec_inference_init; NN_InputSetter_TypeDef input_setter; NN_InputGetter_TypeDef input_getter; NN_OutputSetter_TypeDef output_setter; NN_OutputGetter_TypeDef output_getter; NN_EpochBlockItems_TypeDef epoch_block_items; NN_Buffers_Info_TypeDef output_buffers_info; NN_Buffers_Info_TypeDef input_buffers_info; NN_Buffers_Info_TypeDef internal_buffers_info; } NN_Interface_TypeDef; typedef struct { const EpochBlock_ItemTypeDef *volatile current_epoch_block; // pointer to current epoch block const EpochBlock_ItemTypeDef *volatile first_epoch_block; // pointer to first epoch block in current epoch list const EpochBlock_ItemTypeDef *volatile next_epoch_block; // pointer to epoch block to be inserted const EpochBlock_ItemTypeDef *volatile saved_current_epoch_block; // pointer to saved current epoch list const EpochBlock_ItemTypeDef *volatile saved_first_epoch_block; // pointer to saved first epoch block in current epoch list bool inference_started; // inference has been started #if (LL_ATON_RT_MODE == LL_ATON_RT_ASYNC) volatile uint32_t triggered_events; // currently triggered events/IRQs in current epoch volatile bool current_epoch_block_started; // has current epoch block already been started #endif // (LL_ATON_RT_MODE == LL_ATON_RT_ASYNC) #ifndef NDEBUG volatile uint32_t nr_of_epoch_blocks; // number of epoch blocks in network (includes also terminating empty epoch block) volatile uint32_t saved_nr_of_epoch_blocks; // number of epoch blocks in saved network (includes also terminating // empty epoch block) #endif // NDEBUG TraceEpochBlock_FuncPtr_t epoch_callback_function; // epoch callback function #if defined(LL_ATON_RT_RELOC) uint32_t inst_reloc; #endif } NN_Execution_State_TypeDef; struct __nn_instance_struct { const NN_Interface_TypeDef *network; NN_Execution_State_TypeDef exec_state; }; /** * @brief Declare and fill a constant named NN interface object * @param nn_if_name name of the network as provided by option `--network-name` */ #define LL_ATON_DECLARE_NAMED_NN_INTERFACE(nn_if_name) \ LL_ATON_DECLARE_NAMED_NN_PROTOS(nn_if_name); \ \ static const NN_Interface_TypeDef NN_Interface_##nn_if_name = { \ .network_name = #nn_if_name, \ .ec_network_init = &LL_ATON_EC_Network_Init_##nn_if_name, \ .ec_inference_init = &LL_ATON_EC_Inference_Init_##nn_if_name, \ .input_setter = &LL_ATON_Set_User_Input_Buffer_##nn_if_name, \ .input_getter = &LL_ATON_Get_User_Input_Buffer_##nn_if_name, \ .output_setter = &LL_ATON_Set_User_Output_Buffer_##nn_if_name, \ .output_getter = &LL_ATON_Get_User_Output_Buffer_##nn_if_name, \ .epoch_block_items = &LL_ATON_EpochBlockItems_##nn_if_name, \ .output_buffers_info = &LL_ATON_Output_Buffers_Info_##nn_if_name, \ .input_buffers_info = &LL_ATON_Input_Buffers_Info_##nn_if_name, \ .internal_buffers_info = &LL_ATON_Internal_Buffers_Info_##nn_if_name} /** * @brief Declare and fill a non-constant named NN execution instance * @param nn_exec_name typically name of the network as provided by option `--network-name` * @param _nn_if_name pointer to network interface */ #define LL_ATON_DECLARE_NAMED_NN_INSTANCE(nn_exec_name, _nn_if_name) \ static NN_Instance_TypeDef NN_Instance_##nn_exec_name = {.network = _nn_if_name, .exec_state = {0}} /** * @brief Declare and fill a non-constant named NN execution instance and constant network interface, * which get linked together (by this macro). * @param nn_name name of the network as provided by option `--network-name` */ #define LL_ATON_DECLARE_NAMED_NN_INSTANCE_AND_INTERFACE(nn_name) \ LL_ATON_DECLARE_NAMED_NN_INTERFACE(nn_name); \ LL_ATON_DECLARE_NAMED_NN_INSTANCE(nn_name, &NN_Interface_##nn_name); /** * @} */ static inline bool EpochBlock_IsLastEpochBlock(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_last_eb) != 0); } static inline bool EpochBlock_IsEpochStart(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_epoch_start) != 0); } static inline bool EpochBlock_IsEpochEnd(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_epoch_end) != 0); } static inline bool EpochBlock_IsEpochBlob(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_blob) != 0); } static inline bool EpochBlock_IsEpochPureSW(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_pure_sw) != 0); } static inline bool EpochBlock_IsEpochPureHW(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_pure_hw) != 0); } static inline bool EpochBlock_IsEpochHybrid(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_hybrid) != 0); } static inline bool EpochBlock_IsEpochInternal(const EpochBlock_ItemTypeDef *eb) { return ((eb->flags & EpochBlock_Flags_internal) != 0); } static inline uint32_t EpochBlock_EpochControllerUnit(const EpochBlock_ItemTypeDef *eb) { LL_ATON_ASSERT(EpochBlock_IsEpochBlob(eb)); return eb->wait_mask; } static inline uintptr_t EpochBlock_EpochBlobAddr(const EpochBlock_ItemTypeDef *eb) { LL_ATON_ASSERT(EpochBlock_IsEpochBlob(eb)); return eb->blob_address; } static inline unsigned char *LL_Buffer_addr_base(const LL_Buffer_InfoTypeDef *buf) { if (buf->is_user_allocated) { unsigned char **tmp = (unsigned char **)buf->addr_base.p; return *tmp; } return buf->addr_base.p; } static inline unsigned char *LL_Buffer_addr_start(const LL_Buffer_InfoTypeDef *buf) { return LL_Buffer_addr_base(buf) + buf->offset_start; } static inline unsigned char *LL_Buffer_addr_end(const LL_Buffer_InfoTypeDef *buf) { return LL_Buffer_addr_base(buf) + buf->offset_end; } static inline unsigned char *LL_Buffer_addr_limit(const LL_Buffer_InfoTypeDef *buf) { return LL_Buffer_addr_base(buf) + buf->offset_limit; } static inline uint32_t LL_Buffer_len(const LL_Buffer_InfoTypeDef *buf) { return buf->offset_end - buf->offset_start; } static inline uint32_t LL_Buffer_bits(const LL_Buffer_InfoTypeDef *buf) { return buf->Qm + buf->Qn + (buf->Qunsigned ? 0 : 1); } #ifdef __cplusplus } #endif #endif /** * @} */