text: /**
   * Copyright (c) 2017 - 2019, 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)                         \
      {                                                                       \
          default:                                                            \
              ;                                                               \
          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__ */
  