1104 lines
46 KiB
C
1104 lines
46 KiB
C
|
/**
|
||
|
* 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 APP_USBD_CLASS_BASE_H__
|
||
|
#define APP_USBD_CLASS_BASE_H__
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <stddef.h>
|
||
|
|
||
|
#include "app_usbd_types.h"
|
||
|
#include "nrf_drv_usbd.h"
|
||
|
#include "nrf_assert.h"
|
||
|
#include "app_util.h"
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* @defgroup app_usbd_class_base USBD Class Base module
|
||
|
* @ingroup app_usbd
|
||
|
*
|
||
|
* @brief @tagAPI52840 The base for any class instance is defined in this module.
|
||
|
*
|
||
|
* @details Any class instance must start from base class instance structure.
|
||
|
* This makes them compatible with USBD library independently of the
|
||
|
* implementation details.
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Endpoint configuration.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
nrf_drv_usbd_ep_t address; //!< Endpoint address
|
||
|
} app_usbd_class_ep_conf_t;
|
||
|
|
||
|
/**
|
||
|
* @brief Interface configuration.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
uint8_t number; //!< Interface number
|
||
|
uint8_t ep_cnt; //!< Endpoint number
|
||
|
uint8_t ep_offset; //!< Offset of the first endpoint
|
||
|
/**< Offset in bytes of the first endpoint.
|
||
|
* The offset is calculated from the address of this interface structure
|
||
|
*/
|
||
|
} app_usbd_class_iface_conf_t;
|
||
|
|
||
|
/**
|
||
|
* @brief Instance variable data.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
app_usbd_class_inst_t const * p_next; //!< Pointer to the next instance
|
||
|
app_usbd_class_inst_t const * p_sof_next; //!< Pointer to the next SOF event requiring instance
|
||
|
app_usbd_sof_interrupt_handler_t sof_handler; //!< Instance specific SOF interrupt handler
|
||
|
} app_usbd_class_data_t;
|
||
|
|
||
|
/**
|
||
|
* @brief Class descriptor context.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
uint32_t line; //!< Number of line to resume writing descriptors from
|
||
|
uint8_t data_buffer; //!< Data from last call of feeder
|
||
|
} app_usbd_class_descriptor_ctx_t;
|
||
|
|
||
|
/**
|
||
|
* @brief Class descriptor state.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
uint8_t * p_buffer; //!< Pointer to buffer
|
||
|
uint32_t current_size; //!< Current size of descriptor
|
||
|
uint32_t maximum_size; //!< Maximum size of descriptor
|
||
|
app_usbd_class_descriptor_ctx_t * p_context; //!< Pointer to context
|
||
|
} app_usbd_class_descriptor_state_t;
|
||
|
|
||
|
/**
|
||
|
* @brief Class interface function set.
|
||
|
* */
|
||
|
typedef struct {
|
||
|
/**
|
||
|
* @brief Instance callback function.
|
||
|
*
|
||
|
* The function used by every class instance.
|
||
|
* @param[in,out] p_inst Instance of the class.
|
||
|
* @param[in] p_event Event to process.
|
||
|
*
|
||
|
* @return Standard error code.
|
||
|
*
|
||
|
* @note If given event is not supported by class, return @ref NRF_ERROR_NOT_SUPPORTED
|
||
|
*/
|
||
|
ret_code_t (* event_handler)(app_usbd_class_inst_t const * const p_inst,
|
||
|
app_usbd_complex_evt_t const * const p_event);
|
||
|
|
||
|
/**
|
||
|
* @brief Instance feed descriptors.
|
||
|
*
|
||
|
* Feeds whole descriptor of the instance.
|
||
|
* @param[in] p_ctx Class descriptor context.
|
||
|
* @param[in,out] p_inst Instance of the class.
|
||
|
* @param[out] p_buff Buffer for descriptor.
|
||
|
* @param[in] max_size Requested size of the descriptor.
|
||
|
*
|
||
|
* @return True if not finished feeding the descriptor, false if done.
|
||
|
*/
|
||
|
bool (* feed_descriptors)(app_usbd_class_descriptor_ctx_t * p_ctx,
|
||
|
app_usbd_class_inst_t const * p_inst,
|
||
|
uint8_t * p_buff,
|
||
|
size_t max_size);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Select interface
|
||
|
*
|
||
|
* Function called when class interface has to be selected.
|
||
|
*
|
||
|
* This function would be called for every interface when:
|
||
|
* - SET_INTERFACE command is processed by the default handler
|
||
|
* - SET_CONFIG(1) command is processed by the default handler
|
||
|
*
|
||
|
* @note Remember to disable all the endpoints that are not used
|
||
|
* in the selected configuration.
|
||
|
* @note If this function pointer is NULL default procedure would
|
||
|
* just enable all the interface endpoints and selecting
|
||
|
* alternate configurations other than 0 would generate error.
|
||
|
* @note Calling the function with alternate setting 0 has to always succeed.
|
||
|
*
|
||
|
* @param[in,out] p_inst Instance of the class
|
||
|
* @param[in] iface_idx Index of the interface inside class structure
|
||
|
* @param[in] alternate Alternate setting that should be selected
|
||
|
*
|
||
|
* @return Function has to return @ref NRF_SUCCESS when it has successfully proceed
|
||
|
* interface selection.
|
||
|
* If it returns @ref NRF_ERROR_NOT_SUPPORTED, default function would be used
|
||
|
* to proceed the request - just like there would be NULL pointer in this field.
|
||
|
* Any other kind of error would make library to STALL the request.
|
||
|
*/
|
||
|
ret_code_t (* iface_select)(app_usbd_class_inst_t const * const p_inst,
|
||
|
uint8_t iface_idx,
|
||
|
uint8_t alternate);
|
||
|
|
||
|
/**
|
||
|
* @brief Deselect interface.
|
||
|
*
|
||
|
* Function called when the class interface has to be deselected.
|
||
|
*
|
||
|
* This function would be called for every interface when:
|
||
|
* - Library start internal event is processed by the default handler
|
||
|
* - RESET event is processed by the default handler
|
||
|
* - SET_ADDRESS is processed by the default handler
|
||
|
* - SET_CONFIG(0) is processed by the default handler
|
||
|
*
|
||
|
* @note Just after this function is called all the interface
|
||
|
* endpoints would be disabled.
|
||
|
* This function does not has to take care about it.
|
||
|
* @note If this function pointer is NULL default procedure would
|
||
|
* just disable all the interface endpoints.
|
||
|
*
|
||
|
* @param[in,out] p_inst Instance of the class.
|
||
|
* @param[in] iface_idx Index of the interface inside class structure.
|
||
|
*/
|
||
|
void (* iface_deselect)(app_usbd_class_inst_t const * const p_inst, uint8_t iface_idx);
|
||
|
|
||
|
/**
|
||
|
* @brief Get current interface.
|
||
|
*
|
||
|
* Function called when class interface has to return its alternate settings
|
||
|
* in reaction on GET_INTERFACE command.
|
||
|
* It should be defined in a pair with @ref app_usbd_class_methods_t::iface_select.
|
||
|
*
|
||
|
* @param[in] p_inst Instance of the class.
|
||
|
* @param[in] iface_idx Index of the interface inside class structure.
|
||
|
*
|
||
|
* @return Current alternate setting of the selected interface.
|
||
|
*
|
||
|
* @note For the classes that support this function, when an interface that has not alternate
|
||
|
* configurations has been selected this function has to return 0 - default alternate setting.
|
||
|
*
|
||
|
* @note If this function pointer it NULL default procedure would return alternate interface
|
||
|
* value 0.
|
||
|
*/
|
||
|
uint8_t (* iface_selection_get)(app_usbd_class_inst_t const * const p_inst, uint8_t iface_idx);
|
||
|
|
||
|
} app_usbd_class_methods_t;
|
||
|
|
||
|
/**
|
||
|
* @brief The instance structure itself.
|
||
|
*
|
||
|
* The structure of base class instance.
|
||
|
*/
|
||
|
struct app_usbd_class_inst_s
|
||
|
{
|
||
|
app_usbd_class_data_t * p_data; //!< Pointer to non-constant data
|
||
|
app_usbd_class_methods_t const * p_class_methods; //!< Class interface methods
|
||
|
struct
|
||
|
{
|
||
|
uint8_t cnt; //!< Number of defined interfaces
|
||
|
uint8_t config[]; //!< Interface configuration data followed by endpoint data
|
||
|
} iface; //!< Interface structure
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Get total number of interfaces.
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
static inline uint8_t app_usbd_class_iface_count_get(app_usbd_class_inst_t const * const p_inst)
|
||
|
{
|
||
|
return p_inst->iface.cnt;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Interface accessing function.
|
||
|
*
|
||
|
* Get interface pointer.
|
||
|
* Interfaces create continuous array in the memory so it is possible to get
|
||
|
* interface with index 0 and then just iterate to the next one.
|
||
|
*
|
||
|
* @param p_inst Pointer to the class instance
|
||
|
* @param iface_idx Index of the instance to get.
|
||
|
* This is not the interface identifier.
|
||
|
* Technically it is the index of the interface in the class description array.
|
||
|
* @return Pointer to the interface configuration parameters or NULL if given index is out of interface scope for given class.
|
||
|
*/
|
||
|
static inline app_usbd_class_iface_conf_t const * app_usbd_class_iface_get(
|
||
|
app_usbd_class_inst_t const * const p_inst,
|
||
|
uint8_t iface_idx)
|
||
|
{
|
||
|
ASSERT(NULL != p_inst);
|
||
|
if (iface_idx >= (app_usbd_class_iface_count_get(p_inst)))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
app_usbd_class_iface_conf_t const * p_interface =
|
||
|
(app_usbd_class_iface_conf_t const * )(p_inst->iface.config);
|
||
|
return &(p_interface[iface_idx]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Get interface number.
|
||
|
*
|
||
|
* @param p_iface Pointer to interface structure.
|
||
|
*
|
||
|
* @return Interface number from interface configuration structure.
|
||
|
*/
|
||
|
static inline uint8_t app_usbd_class_iface_number_get(
|
||
|
app_usbd_class_iface_conf_t const * const p_iface)
|
||
|
{
|
||
|
return p_iface->number;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Get number of endpoints in interface.
|
||
|
*
|
||
|
* @param p_iface Pointer to interface structure.
|
||
|
*
|
||
|
* @return Number of endpoints used by given interface.
|
||
|
*/
|
||
|
static inline uint8_t app_usbd_class_iface_ep_count_get(
|
||
|
app_usbd_class_iface_conf_t const * const p_iface)
|
||
|
{
|
||
|
return p_iface->ep_cnt;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Interface Endpoint accessing function.
|
||
|
*
|
||
|
* @param p_iface Interface configuration pointer.
|
||
|
* @param ep_idx Endpoint index.
|
||
|
*
|
||
|
* @return Endpoint information structure pointer or NULL if given index is outside of endpoints for selected interface.
|
||
|
*
|
||
|
* @sa app_usbd_class_iface_get
|
||
|
*/
|
||
|
static inline app_usbd_class_ep_conf_t const * app_usbd_class_iface_ep_get(
|
||
|
app_usbd_class_iface_conf_t const * const p_iface,
|
||
|
uint8_t ep_idx)
|
||
|
{
|
||
|
ASSERT(NULL != p_iface);
|
||
|
if (ep_idx >= p_iface->ep_cnt)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
app_usbd_class_ep_conf_t const * p_ep =
|
||
|
(app_usbd_class_ep_conf_t const * )(((uint8_t const *)p_iface) + p_iface->ep_offset);
|
||
|
return &(p_ep[ep_idx]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Translate endpoint address to class index.
|
||
|
*
|
||
|
* @param p_iface Interface configuration pointer.
|
||
|
* @param ep_address Endpoint address.
|
||
|
*
|
||
|
* @return Endpoint index or number of endpoints if not found.
|
||
|
*
|
||
|
*/
|
||
|
static inline uint8_t app_usbd_class_iface_ep_idx_get(
|
||
|
app_usbd_class_iface_conf_t const * const p_iface,
|
||
|
nrf_drv_usbd_ep_t ep_address)
|
||
|
{
|
||
|
ASSERT(NULL != p_iface);
|
||
|
app_usbd_class_ep_conf_t const * p_ep =
|
||
|
(app_usbd_class_ep_conf_t const * )(((uint8_t const *)p_iface) + p_iface->ep_offset);
|
||
|
|
||
|
uint8_t i;
|
||
|
for (i = 0; i < p_iface->ep_cnt; ++i)
|
||
|
{
|
||
|
if (ep_address == p_ep[i].address)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Get the selected endpoint address.
|
||
|
*
|
||
|
* @param p_ep Endpoint configuration structure.
|
||
|
*
|
||
|
* @return Endpoint address
|
||
|
*/
|
||
|
static inline nrf_drv_usbd_ep_t app_usbd_class_ep_address_get(app_usbd_class_ep_conf_t const * p_ep)
|
||
|
{
|
||
|
return (nrf_drv_usbd_ep_t)p_ep->address;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Get the pointer to the writable instance data.
|
||
|
*
|
||
|
* @param p_inst Instance pointer.
|
||
|
* @return Pointer to writable instance data.
|
||
|
*/
|
||
|
static inline app_usbd_class_data_t * app_usbd_class_data_access(
|
||
|
app_usbd_class_inst_t const * const p_inst)
|
||
|
{
|
||
|
return p_inst->p_data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @name Internal macros for argument mapping
|
||
|
*
|
||
|
* Functions to be used as a mapping macro for @ref MACRO_MAP, @ref MACRO_MAP_FOR or @ref MACRO_MAP_FOR_PARAM
|
||
|
* @{
|
||
|
*/
|
||
|
/**
|
||
|
* @brief Count the number of endpoints in given configuration.
|
||
|
*
|
||
|
* Config should be given as a interface configuration in a brackets:
|
||
|
* @code
|
||
|
* (interface_nr, ep1, ep2, ep3)
|
||
|
* @endcode
|
||
|
* Number of endpoints may vary from 0 to a few (technically up to 16, but it seems not to make sense to use more than 4).
|
||
|
* Interface number is always present.
|
||
|
*
|
||
|
* @param iface_config Single interface configuration (in brackets).
|
||
|
*
|
||
|
* @return Number of endpoints in interface. This is computed value - can be used by compiler but not by preprocessor.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_CONF_IFACE_EP_COUNT_(iface_config) \
|
||
|
(NUM_VA_ARGS(BRACKET_EXTRACT(iface_config)) - 1)
|
||
|
|
||
|
/**
|
||
|
* @brief Adds the number of endpoints in given config to the current value.
|
||
|
*
|
||
|
* This is basically @ref APP_USBD_CLASS_CONF_IFACE_EP_COUNT_ with plus sign added.
|
||
|
*
|
||
|
* @param iface_config See parameters documentation in @ref APP_USBD_CLASS_CONF_IFACE_EP_COUNT_
|
||
|
*
|
||
|
* @return Plus sign followed by number of endpoints in interface.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_CONF_IFACE_EP_COUNT_
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_CONF_IFACE_EP_PLUS_COUNT_(iface_config) \
|
||
|
+ APP_USBD_CLASS_CONF_IFACE_EP_COUNT_(iface_config)
|
||
|
|
||
|
/**
|
||
|
* @brief Create variable for endpoint.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Extract endpoints given interface configuration.
|
||
|
*
|
||
|
* This macro gets single endpoint configuration and extracts all the endpoints.
|
||
|
* It also adds comma on the end of extracted endpoints.
|
||
|
* This way when this macro is called few times it generates nice list of all endpoints
|
||
|
* that may be used to array initialization.
|
||
|
*
|
||
|
* @param iface_config Single interface configuration in brackets.
|
||
|
* The format should be similar like described in @ref APP_USBD_CLASS_CONF_IFACE_EP_COUNT_.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_IFACE_EP_EXTRACT_(iface_config) \
|
||
|
CONCAT_2(APP_USBD_CLASS_IFACE_EP_EXTRACT_, \
|
||
|
NUM_VA_ARGS_IS_MORE_THAN_1(BRACKET_EXTRACT(iface_config))) \
|
||
|
(BRACKET_EXTRACT(iface_config))
|
||
|
|
||
|
/**
|
||
|
* @brief Auxiliary macro for @ref APP_USBD_CLASS_IFACE_EP_EXTRACT_
|
||
|
*
|
||
|
* This macro is called when interface has no endpoints.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_IFACE_EP_EXTRACT_0(iface_nr)
|
||
|
|
||
|
/**
|
||
|
* @brief Auxiliary macro for @ref APP_USBD_CLASS_IFACE_EP_EXTRACT_
|
||
|
*
|
||
|
* This macro is called when interface has at least one endpoint.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_IFACE_EP_EXTRACT_1(...) \
|
||
|
APP_USBD_CLASS_IFACE_EP_EXTRACT_1_(__VA_ARGS__)
|
||
|
|
||
|
#define APP_USBD_CLASS_IFACE_EP_EXTRACT_1_(iface_nr, ...) \
|
||
|
MACRO_MAP_REC(APP_USBD_CLASS_IFACE_EP_EXTRACT_1__, __VA_ARGS__)
|
||
|
|
||
|
#define APP_USBD_CLASS_IFACE_EP_EXTRACT_1__(ep) \
|
||
|
{(nrf_drv_usbd_ep_t) (ep)},
|
||
|
|
||
|
/**
|
||
|
* @brief Generate configuration for single interface.
|
||
|
*
|
||
|
* This macro extract configuration for single interface.
|
||
|
* The configuration is inside curly brackets and comma is added on the end.
|
||
|
* This mean it can be directly used to init array of interface configurations.
|
||
|
*
|
||
|
* @param iface_config Single interface configuration.
|
||
|
* @param N Currently processed configuration.
|
||
|
* @param iface_configs All interfaces configuration in brackets.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_(iface_config, N, iface_configs) \
|
||
|
CONCAT_2(APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_, \
|
||
|
NUM_VA_ARGS_IS_MORE_THAN_1(BRACKET_EXTRACT(iface_config))) \
|
||
|
(N, iface_configs, BRACKET_EXTRACT(iface_config))
|
||
|
|
||
|
/**
|
||
|
* @brief Macro used when there was an error extracting number of configs.
|
||
|
*
|
||
|
* Throws a syntax error.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_x(iface_config, N, iface_configs) \
|
||
|
[N] = !!!iface_config!!!
|
||
|
/**
|
||
|
* @brief Auxiliary macro for @ref APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_
|
||
|
*
|
||
|
* This macro is called when interface has no endpoints.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_0(N, iface_configs, iface_nr) \
|
||
|
APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_0_(N, iface_configs, iface_nr)
|
||
|
#define APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_0_(N, iface_configs, iface_nr) \
|
||
|
{ .number = iface_nr, .ep_cnt = 0, .ep_offset = 0 },
|
||
|
|
||
|
/**
|
||
|
* @brief Auxiliary macro for @ref APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_
|
||
|
*
|
||
|
* This macro is called when interface has at last one endpoint.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_1(N, iface_configs, ...) \
|
||
|
APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_1_(N, iface_configs, __VA_ARGS__)
|
||
|
#define APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_1_(N, iface_configs, iface_nr, ...) \
|
||
|
{ .number = iface_nr, .ep_cnt = NUM_VA_ARGS(__VA_ARGS__), \
|
||
|
.ep_offset = APP_USBD_CLASS_CONF_TOTAL_EP_COUNT_N(N, iface_configs) * \
|
||
|
sizeof(app_usbd_class_ep_conf_t) \
|
||
|
+ ((NUM_VA_ARGS(BRACKET_EXTRACT(iface_configs)) - N) * \
|
||
|
sizeof(app_usbd_class_iface_conf_t)) \
|
||
|
},
|
||
|
|
||
|
/** @} */
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @name Macros that uses mapping macros internally
|
||
|
*
|
||
|
* Auxiliary macros that uses mapping macros to make some calculations or realize other functionality.
|
||
|
* Mapped here for easier unit testing and to hide complex mapping functions calling.
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Count total number of endpoints.
|
||
|
*
|
||
|
* @param iface_configs List of interface configurations like explained
|
||
|
* in documentation for @ref APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
*
|
||
|
* @return The equation to calculate the number of endpoints by compiler.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_CONF_TOTAL_EP_COUNT(iface_configs) \
|
||
|
(0 MACRO_MAP(APP_USBD_CLASS_CONF_IFACE_EP_PLUS_COUNT_, BRACKET_EXTRACT(iface_configs)))
|
||
|
|
||
|
/**
|
||
|
* @brief Count total number of endpoint up-to interface index.
|
||
|
*
|
||
|
* The version of @ref APP_USBD_CLASS_CONF_TOTAL_EP_COUNT macro which takes the
|
||
|
* number of interfaces to analyze.
|
||
|
*
|
||
|
* @param N Number of interfaces to analyze.
|
||
|
* @param iface_configs List of interface configurations like explained
|
||
|
* in documentation for @ref APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
*
|
||
|
* @return The equation to calculate the number of endpoints by compiler.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_CONF_TOTAL_EP_COUNT_N(N, iface_configs) \
|
||
|
(0 MACRO_MAP_N(N, APP_USBD_CLASS_CONF_IFACE_EP_PLUS_COUNT_, BRACKET_EXTRACT(iface_configs)))
|
||
|
|
||
|
/**
|
||
|
* @brief Extract configurations for interfaces.
|
||
|
*
|
||
|
* This macro extracts the configurations for every interface.
|
||
|
* Basically uses the @ref APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_ macro on every
|
||
|
* configuration found.
|
||
|
*
|
||
|
* This should generate interface configuration initialization data
|
||
|
* in comma separated initializers in curly braces.
|
||
|
*
|
||
|
* @param iface_configs List of interface configurations like explained
|
||
|
* in documentation for @ref APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
*
|
||
|
* @return Comma separated initialization data for all interfaces.
|
||
|
*/
|
||
|
/*lint -emacro( (40), APP_USBD_CLASS_IFACES_CONFIG_EXTRACT) */
|
||
|
#define APP_USBD_CLASS_IFACES_CONFIG_EXTRACT(iface_configs) \
|
||
|
MACRO_MAP_FOR_PARAM(iface_configs, \
|
||
|
APP_USBD_CLASS_IFACE_CONFIG_EXTRACT_, \
|
||
|
BRACKET_EXTRACT(iface_configs))
|
||
|
|
||
|
/**
|
||
|
* @brief Extract all endpoints.
|
||
|
*
|
||
|
* Macro that extracts all endpoints from every interface.
|
||
|
*
|
||
|
* @param iface_configs List of interface configurations like explained
|
||
|
* in documentation for @ref APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
*
|
||
|
* @return Comma separated list of endpoints.
|
||
|
*/
|
||
|
/*lint -emacro( (40), APP_USBD_CLASS_IFACES_EP_EXTRACT) */
|
||
|
#define APP_USBD_CLASS_IFACES_EP_EXTRACT(iface_configs) \
|
||
|
MACRO_MAP(APP_USBD_CLASS_IFACE_EP_EXTRACT_, BRACKET_EXTRACT(iface_configs))
|
||
|
|
||
|
|
||
|
/** @} */
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief USBD instance of class mnemonic.
|
||
|
*
|
||
|
* Macro that generates mnemonic for the name of the structure that describes instance for selected class.
|
||
|
*
|
||
|
* @param type_name The name of the instance without _t postfix.
|
||
|
*
|
||
|
* @return The name with the right postfix to create the name for the type for the class.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INSTANCE_TYPE(type_name) CONCAT_2(type_name, _t)
|
||
|
|
||
|
/**
|
||
|
* @brief USBD data for instance class mnemonic.
|
||
|
*
|
||
|
* The mnemonic of the variable type that holds writable part of the class instance.
|
||
|
*
|
||
|
* @param type_name The name of the instance without _t postfix.
|
||
|
*
|
||
|
* @return The name with the right postfix to create the name for the data type for the class.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_DATA_TYPE(type_name) CONCAT_2(type_name, _data_t)
|
||
|
|
||
|
/**
|
||
|
* @brief Declare class specific member of class instance.
|
||
|
*
|
||
|
* @param type Type of the attached class configuration.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC(type) type class_part;
|
||
|
|
||
|
/**
|
||
|
* @brief Used if there is no class specific configuration.
|
||
|
*
|
||
|
* This constant can be used if there is no specific configuration inside created instance.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE
|
||
|
|
||
|
/**
|
||
|
* @brief Declare class specific member of class data.
|
||
|
*
|
||
|
* @param type Type of the attached class data.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_DATA_TYPEDEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_DATA_SPECIFIC_DEC(type) APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC(type)
|
||
|
|
||
|
/**
|
||
|
* @brief Used if there is no class specific data.
|
||
|
*
|
||
|
* This constant can be used if there is no specific writable data inside created instance.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_DATA_TYPEDEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_DATA_SPECIFIC_DEC_NONE APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Instance structure declaration.
|
||
|
*
|
||
|
* The macro that declares a variable type that would be used to store given class instance.
|
||
|
* Class instance stores all the data from @ref app_usbd_class_inst_t and overlaid data for specified class.
|
||
|
*
|
||
|
* The structure of interface configuration data:
|
||
|
* @code
|
||
|
* (
|
||
|
* (iface1_nr, (ep1, ep2, ep3)),
|
||
|
(iface2_nr),
|
||
|
(iface3_nr, (ep4))
|
||
|
* )
|
||
|
* @endcode
|
||
|
*
|
||
|
* @param type_name The name of the instance without _t postfix.
|
||
|
* @param interfaces_configs List of interface configurations like explained above.
|
||
|
* @param class_config_dec Result of the macro
|
||
|
* @ref APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC or
|
||
|
* @ref APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE
|
||
|
*
|
||
|
* @return The definition of the structure type that holds all the required data.
|
||
|
*
|
||
|
* @note It should not be used directly in the final application. See @ref APP_USBD_CLASS_DATA_TYPEDEF instead.
|
||
|
*
|
||
|
* @note APP_USBD_CLASS_DATA_TYPEDEF has to be called first for the compilation to success.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_TYPEDEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INSTANCE_TYPEDEF(type_name, interfaces_configs, class_config_dec) \
|
||
|
typedef union CONCAT_2(type_name, _u) \
|
||
|
{ \
|
||
|
app_usbd_class_inst_t base; \
|
||
|
struct \
|
||
|
{ \
|
||
|
APP_USBD_CLASS_DATA_TYPE(type_name) * p_data; \
|
||
|
app_usbd_class_methods_t const * p_class_methods; \
|
||
|
struct \
|
||
|
{ \
|
||
|
uint8_t cnt; \
|
||
|
app_usbd_class_iface_conf_t \
|
||
|
config[NUM_VA_ARGS(BRACKET_EXTRACT(interfaces_configs))]; \
|
||
|
app_usbd_class_ep_conf_t \
|
||
|
ep[APP_USBD_CLASS_CONF_TOTAL_EP_COUNT(interfaces_configs)]; \
|
||
|
} iface; \
|
||
|
class_config_dec \
|
||
|
} specific; \
|
||
|
} APP_USBD_CLASS_INSTANCE_TYPE(type_name)
|
||
|
|
||
|
/**
|
||
|
* @brief Same as @ref APP_USBD_CLASS_INSTANCE_TYPEDEF but for class with EP0 only.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INSTANCE_NO_EP_TYPEDEF(type_name, interfaces_configs, class_config_dec) \
|
||
|
typedef union CONCAT_2(type_name, _u) \
|
||
|
{ \
|
||
|
app_usbd_class_inst_t base; \
|
||
|
struct \
|
||
|
{ \
|
||
|
APP_USBD_CLASS_DATA_TYPE(type_name) * p_data; \
|
||
|
app_usbd_class_methods_t const * p_class_methods; \
|
||
|
struct \
|
||
|
{ \
|
||
|
uint8_t cnt; \
|
||
|
app_usbd_class_iface_conf_t \
|
||
|
config[NUM_VA_ARGS(BRACKET_EXTRACT(interfaces_configs))]; \
|
||
|
} iface; \
|
||
|
class_config_dec \
|
||
|
} specific; \
|
||
|
} APP_USBD_CLASS_INSTANCE_TYPE(type_name)
|
||
|
|
||
|
/**
|
||
|
* @brief Writable data structure declaration.
|
||
|
*
|
||
|
* The macro that declares a variable type that would be used to store given class writable data.
|
||
|
* Writable data contains base part of the type @ref app_usbd_class_data_t followed by
|
||
|
* class specific data.
|
||
|
*
|
||
|
* @param type_name The name of the type without _t postfix.
|
||
|
* @param class_data_dec Result of the macro
|
||
|
* @ref APP_USBD_CLASS_DATA_SPECIFIC_DEC or
|
||
|
* @ref APP_USBD_CLASS_DATA_SPECIFIC_DEC_NONE
|
||
|
*
|
||
|
* @return The definition of the structure type that holds all the required writable data.
|
||
|
*
|
||
|
* @note It should not be used directly in the final application. See @ref APP_USBD_CLASS_DATA_TYPEDEF instead.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_TYPEDEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_DATA_TYPEDEF(type_name, class_data_dec) \
|
||
|
typedef struct \
|
||
|
{ \
|
||
|
app_usbd_class_data_t base; \
|
||
|
class_data_dec \
|
||
|
}APP_USBD_CLASS_DATA_TYPE(type_name)
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Declare all data types required by the class instance.
|
||
|
*
|
||
|
* Macro that declares data type first and then instance type.
|
||
|
*
|
||
|
* @param type_name The name of the type without _t postfix.
|
||
|
* @param interface_configs List of interface configurations like in @ref APP_USBD_CLASS_INSTANCE_TYPEDEF.
|
||
|
* @param class_config_dec Result of the macro
|
||
|
* @ref APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC or
|
||
|
* @ref APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE
|
||
|
* @param class_data_dec Result of the macro
|
||
|
* @ref APP_USBD_CLASS_DATA_SPECIFIC_DEC or
|
||
|
* @ref APP_USBD_CLASS_DATA_SPECIFIC_DEC_NONE
|
||
|
*
|
||
|
* @return Declaration of the data type for the instance and instance itself.
|
||
|
*
|
||
|
* @sa APP_USBD_CLASS_DATA_TYPEDEF
|
||
|
* @sa APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_TYPEDEF(type_name, interface_configs, class_config_dec, class_data_dec) \
|
||
|
APP_USBD_CLASS_DATA_TYPEDEF(type_name, class_data_dec); \
|
||
|
APP_USBD_CLASS_INSTANCE_TYPEDEF(type_name, interface_configs, class_config_dec)
|
||
|
|
||
|
/**
|
||
|
* @brief Same as @ref APP_USBD_CLASS_TYPEDEF but for class with EP0 only.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_NO_EP_TYPEDEF(type_name, \
|
||
|
interface_configs, \
|
||
|
class_config_dec, \
|
||
|
class_data_dec) \
|
||
|
APP_USBD_CLASS_DATA_TYPEDEF(type_name, class_data_dec); \
|
||
|
APP_USBD_CLASS_INSTANCE_NO_EP_TYPEDEF(type_name, interface_configs, class_config_dec)
|
||
|
|
||
|
/**
|
||
|
* @brief Forward declaration of type defined by @ref APP_USBD_CLASS_TYPEDEF
|
||
|
*
|
||
|
* @param type_name The name of the type without _t postfix.
|
||
|
* */
|
||
|
#define APP_USBD_CLASS_FORWARD(type_name) union CONCAT_2(type_name, _u)
|
||
|
|
||
|
/**
|
||
|
* @brief Generate the initialization data for.
|
||
|
*
|
||
|
* Macro that generates the initialization data for instance.
|
||
|
*
|
||
|
* @param p_ram_data Pointer to writable instance data structure.
|
||
|
* @param class_methods Class methods.
|
||
|
* @param interfaces_configs Exactly the same interface config data that in @ref APP_USBD_CLASS_INSTANCE_TYPEDEF
|
||
|
* @param class_config_part Configuration part. The data should be inside brackets.
|
||
|
* Any data here would be removed from brackets and then put as an initialization
|
||
|
* data for class_part member of instance structure.
|
||
|
*
|
||
|
* @note It should not be used directly in the final application. See @ref APP_USBD_CLASS_INST_DEF instead.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INSTANCE_INITVAL(p_ram_data, \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part) \
|
||
|
{ \
|
||
|
.specific = { \
|
||
|
.p_data = p_ram_data, \
|
||
|
.p_class_methods = class_methods, \
|
||
|
.iface = { \
|
||
|
.cnt = NUM_VA_ARGS(BRACKET_EXTRACT(interfaces_configs)), \
|
||
|
.config = { APP_USBD_CLASS_IFACES_CONFIG_EXTRACT(interfaces_configs) }, \
|
||
|
.ep = { APP_USBD_CLASS_IFACES_EP_EXTRACT(interfaces_configs) } \
|
||
|
}, \
|
||
|
BRACKET_EXTRACT(class_config_part) \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Same as @ref APP_USBD_CLASS_INSTANCE_INITVAL but for class with EP0 only.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INSTANCE_NO_EP_INITVAL(p_ram_data, \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part) \
|
||
|
{ \
|
||
|
.specific = { \
|
||
|
.p_data = p_ram_data, \
|
||
|
.p_class_methods = class_methods, \
|
||
|
.iface = { \
|
||
|
.cnt = NUM_VA_ARGS(BRACKET_EXTRACT(interfaces_configs)), \
|
||
|
.config = { APP_USBD_CLASS_IFACES_CONFIG_EXTRACT(interfaces_configs) } \
|
||
|
}, \
|
||
|
BRACKET_EXTRACT(class_config_part) \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Define the base class instance.
|
||
|
*
|
||
|
* Macro that defines whole instance variable and fill it with initialization data.
|
||
|
*
|
||
|
* The tricky part is @c class_config_part.
|
||
|
* The configuration data here has to be placed inside brackets.
|
||
|
* Then any type of values can be used depending on the type used in @ref APP_USBD_CLASS_TYPEDEF.
|
||
|
* If instance does not has any specyfic data, use just empty bracket here.
|
||
|
* @code
|
||
|
* APP_USBD_CLASS_TYPEDEF(
|
||
|
* some_base_class,
|
||
|
* CLASS_BASE_CONFIGURATION,
|
||
|
* APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE,
|
||
|
* APP_USBD_CLASS_DATA_SPECIFIC_DEC_NONE
|
||
|
* );
|
||
|
* APP_USBD_CLASS_INST_DEF(
|
||
|
* some_base_class_inst,
|
||
|
* some_base_class,
|
||
|
* base_class_event_handler,
|
||
|
* CLASS_BASE_CONFIGURATION,
|
||
|
* () // Empty configuration
|
||
|
* );
|
||
|
* @endcode
|
||
|
*
|
||
|
* If the type of instance configuration is simple type, just provide initialization value:
|
||
|
* @code
|
||
|
* APP_USBD_CLASS_TYPEDEF(
|
||
|
* some_base_class,
|
||
|
* CLASS_BASE_CONFIGURATION,
|
||
|
* APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE,
|
||
|
* APP_USBD_CLASS_DATA_SPECIFIC_DEC(uint8_t)
|
||
|
* );
|
||
|
* APP_USBD_CLASS_INST_DEF(
|
||
|
* some_base_class_inst,
|
||
|
* some_base_class,
|
||
|
* base_class_event_handler,
|
||
|
* CLASS_BASE_CONFIGURATION,
|
||
|
* (12) // Example values
|
||
|
* );
|
||
|
* @endcode
|
||
|
*
|
||
|
* If the type of instance configuration is structure, provide initialization value for the whole structure:
|
||
|
* @code
|
||
|
* typedef structure
|
||
|
* {
|
||
|
* uint32_t p1;
|
||
|
* uint8_t p2;
|
||
|
* }my_config_t;
|
||
|
*
|
||
|
* APP_USBD_CLASS_TYPEDEF(
|
||
|
* some_base_class,
|
||
|
* CLASS_BASE_CONFIGURATION,
|
||
|
* APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE,
|
||
|
* APP_USBD_CLASS_DATA_SPECIFIC_DEC(my_config_t)
|
||
|
* );
|
||
|
* APP_USBD_CLASS_INST_DEF(
|
||
|
* some_base_class_inst,
|
||
|
* some_base_class,
|
||
|
* base_class_event_handler,
|
||
|
* CLASS_BASE_CONFIGURATION,
|
||
|
* ({12, 3}) // Example values
|
||
|
* );
|
||
|
* @endcode
|
||
|
*
|
||
|
* @param instance_name The name of created instance variable.
|
||
|
* It would be constant variable and its type would be app_usbd_class_inst_t.
|
||
|
* @param type_name The name of the variable type. It has to be the same type that was passed to
|
||
|
* @ref APP_USBD_CLASS_TYPEDEF
|
||
|
* @param class_methods Class unified interface.
|
||
|
* @param interfaces_configs The same configuration data that the one passed to @ref APP_USBD_CLASS_TYPEDEF
|
||
|
* @param class_config_part Configuration data to the type that was declared by class_data_dec when calling
|
||
|
* @ref APP_USBD_CLASS_TYPEDEF.
|
||
|
* Configuration data has to be provided in brackets.
|
||
|
* It would be extracted from brackets and placed in initialization part of configuration structure.
|
||
|
* See detailed description of this macro for more informations.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INST_DEF(instance_name, \
|
||
|
type_name, \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part) \
|
||
|
static APP_USBD_CLASS_DATA_TYPE(type_name) CONCAT_2(instance_name, _data); \
|
||
|
static const APP_USBD_CLASS_INSTANCE_TYPE(type_name) instance_name = \
|
||
|
APP_USBD_CLASS_INSTANCE_INITVAL( \
|
||
|
&CONCAT_2(instance_name, _data), \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part)
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Define the base class instance in global scope.
|
||
|
*
|
||
|
* This is the same macro like @ref APP_USBD_CLASS_INST_DEF but it creates the instance
|
||
|
* without static keyword.
|
||
|
*
|
||
|
* @param instance_name See documentation for @ref APP_USBD_CLASS_INST_DEF
|
||
|
* @param type_name See documentation for @ref APP_USBD_CLASS_INST_DEF
|
||
|
* @param class_methods See documentation for @ref APP_USBD_CLASS_INST_DEF
|
||
|
* @param interfaces_configs See documentation for @ref APP_USBD_CLASS_INST_DEF
|
||
|
* @param class_config_part See documentation for @ref APP_USBD_CLASS_INST_DEF
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INST_GLOBAL_DEF(instance_name, \
|
||
|
type_name, \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part) \
|
||
|
static APP_USBD_CLASS_DATA_TYPE(type_name) CONCAT_2(instance_name, _data); \
|
||
|
const APP_USBD_CLASS_INSTANCE_TYPE(type_name) instance_name = \
|
||
|
APP_USBD_CLASS_INSTANCE_INITVAL( \
|
||
|
&CONCAT_2(instance_name, _data), \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part)
|
||
|
|
||
|
/**
|
||
|
* @brief Same as @ref APP_USBD_CLASS_INST_GLOBAL_DEF but for class with EP0 only.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_INST_NO_EP_GLOBAL_DEF(instance_name, \
|
||
|
type_name, \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part) \
|
||
|
static APP_USBD_CLASS_DATA_TYPE(type_name) CONCAT_2(instance_name, _data); \
|
||
|
const APP_USBD_CLASS_INSTANCE_TYPE(type_name) instance_name = \
|
||
|
APP_USBD_CLASS_INSTANCE_NO_EP_INITVAL( \
|
||
|
&CONCAT_2(instance_name, _data), \
|
||
|
class_methods, \
|
||
|
interfaces_configs, \
|
||
|
class_config_part)
|
||
|
/**
|
||
|
* @brief Access class specific configuration.
|
||
|
*
|
||
|
* Macro that returns class specific configuration.
|
||
|
*
|
||
|
* @param[in] p_inst Instance pointer.
|
||
|
*
|
||
|
* @return A pointer for class specific part of the instance.
|
||
|
*
|
||
|
* @note If macro is used on the instance that has no class specific configuration
|
||
|
* an error would be generated during compilation.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_GET_SPECIFIC_CONFIG(p_inst) (&((p_inst)->specific.class_part))
|
||
|
|
||
|
/**
|
||
|
* @brief Access class specific data.
|
||
|
*
|
||
|
* @param[in] p_inst Instance pointer.
|
||
|
*
|
||
|
* @return A pointer for class specific part of writable data.
|
||
|
*
|
||
|
* @note If macro is used on the instance that has no class specific data
|
||
|
* an error would be generated during compilation.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_GET_SPECIFIC_DATA(p_inst) (&(((p_inst)->specific.p_data)->class_part))
|
||
|
|
||
|
/**
|
||
|
* @brief Macro to get base instance from class specific instance.
|
||
|
*
|
||
|
* This macro may be used on class specific instance to get base instance that
|
||
|
* can be processed by base instance access functions.
|
||
|
* Class specific instance can be just casted to class base instance,
|
||
|
* but then we would totally lost type safety.
|
||
|
*
|
||
|
* A little more safe is to use pointer to base member of class instance.
|
||
|
* This would generate an error when used on any variable that has no base member
|
||
|
* and would generate also error if this base member is wrong type.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_BASE_INSTANCE(p_inst) (&((p_inst)->base))
|
||
|
|
||
|
/*lint -emacro(142 438 616 646, APP_USBD_CLASS_DESCRIPTOR_INIT, APP_USBD_CLASS_DESCRIPTOR_BEGIN, APP_USBD_CLASS_DESCRIPTOR_YIELD, APP_USBD_CLASS_DESCRIPTOR_END, APP_USBD_CLASS_DESCRIPTOR_WRITE)*/
|
||
|
|
||
|
/**
|
||
|
* @brief Initialize class descriptor.
|
||
|
*
|
||
|
* @param[in] p_ctx Class descriptor context.
|
||
|
*/
|
||
|
|
||
|
#define APP_USBD_CLASS_DESCRIPTOR_INIT(p_ctx) \
|
||
|
(p_ctx)->line = 0;
|
||
|
|
||
|
/**
|
||
|
* @brief Begin class descriptor.
|
||
|
*
|
||
|
* @param[in] p_ctx Class descriptor context.
|
||
|
* @param[in] p_buff Buffer to write into.
|
||
|
* @param[in] max_size Size of the buffer.
|
||
|
*/
|
||
|
|
||
|
#define APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size) \
|
||
|
ASSERT((p_ctx) != NULL); \
|
||
|
app_usbd_class_descriptor_state_t this_descriptor_feed; \
|
||
|
this_descriptor_feed.p_buffer = (p_buff); \
|
||
|
this_descriptor_feed.current_size = 0; \
|
||
|
this_descriptor_feed.maximum_size = (max_size); \
|
||
|
this_descriptor_feed.p_context = (p_ctx); \
|
||
|
switch ((this_descriptor_feed.p_context)->line) \
|
||
|
{ \
|
||
|
case 0: \
|
||
|
;
|
||
|
|
||
|
/**
|
||
|
* @brief Yield class descriptor
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#define APP_USBD_CLASS_DESCRIPTOR_YIELD() \
|
||
|
do \
|
||
|
{ \
|
||
|
(this_descriptor_feed.p_context)->line = __LINE__; \
|
||
|
return true; \
|
||
|
case __LINE__: \
|
||
|
; \
|
||
|
} while (0)
|
||
|
|
||
|
/*lint -emacro(438 527, APP_USBD_CLASS_DESCRIPTOR_END)*/
|
||
|
|
||
|
/**
|
||
|
* @brief End class descriptor.
|
||
|
*
|
||
|
* This function has to be called at the end of class descriptor feeder function.
|
||
|
* No other operations in feeder function can be done after calling it.
|
||
|
*/
|
||
|
|
||
|
#define APP_USBD_CLASS_DESCRIPTOR_END() \
|
||
|
APP_USBD_CLASS_DESCRIPTOR_YIELD(); \
|
||
|
} \
|
||
|
(this_descriptor_feed.p_context)->line = 0; \
|
||
|
return false;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Write descriptor using protothreads.
|
||
|
*
|
||
|
* This function writes one byte to the buffer with offset. If buffer is full
|
||
|
* it yields.
|
||
|
*
|
||
|
* It is used by the class descriptor feeders internally.
|
||
|
*
|
||
|
* @ref APP_USBD_CLASS_DESCRIPTOR_BEGIN has to be called before using this function.
|
||
|
* @ref APP_USBD_CLASS_DESCRIPTOR_END has to be called after last use of this function.
|
||
|
*
|
||
|
* @param data Byte to be written to buffer.
|
||
|
*/
|
||
|
#define APP_USBD_CLASS_DESCRIPTOR_WRITE(data) \
|
||
|
do \
|
||
|
{ \
|
||
|
(this_descriptor_feed.p_context)->data_buffer = (data); \
|
||
|
if (this_descriptor_feed.current_size >= this_descriptor_feed.maximum_size) \
|
||
|
{ \
|
||
|
APP_USBD_CLASS_DESCRIPTOR_YIELD(); \
|
||
|
} \
|
||
|
if(this_descriptor_feed.p_buffer != NULL) \
|
||
|
{ \
|
||
|
*(this_descriptor_feed.p_buffer + this_descriptor_feed.current_size) = \
|
||
|
(this_descriptor_feed.p_context)->data_buffer; \
|
||
|
} \
|
||
|
this_descriptor_feed.current_size++; \
|
||
|
} while(0);
|
||
|
|
||
|
/** @} */
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#endif /* APP_USBD_CLASS_BASE_H__ */
|