/***************************************************************************//**
 @defgroup lip_udp UDP
 @ingroup  lip_lvl_transport
 @brief Модуль стека @c lip, реализующий протокол  UDP в соответствии
    с @rfc{768}.\n
  Зависит от: @ref lip_ip

  Протокол @ref lip_udp является проколом [транспортного уровня](@ref lip_lvl_transport).
  В отличии от @ref lip_tcp, передача по @ref lip_udp осуществляется пакетами (дейтаграммами),
  а не потоком.

  В связи с тем, что @ref lip_udp предоставляет лишь минимум сервиса поверх
  @ref lip_ip, стек реализует низкоуровневое API для работы с UDP, которое
  требует минимальное количество памяти, в отличии от стандартного API сокетов.

  Для приема и обработки UDP-пакетов, посланных на определенный UDP-порт,
  нужно вызвать lip_udp_port_listen(), передав функции номер порта и указатель на
  функцию типа #t_lip_udp_in_proc_cb, которая будет вызываться каждый раз,
  когда принят действительный пакет на заданный порт.

  При этом в [файле конфигурации](@ref lip_conf) необходимо задать максимальное
  количество прослушиваемых UDP-портов с помощью макроса #LIP_UDP_MAX_DYN_PORTS.
  Если уже прослушивается максимальное количество портов, то lip_udp_port_listen()
  вернет ошибку. На один порт можно назначить только одну функцию.

  Если прослушивание данного порта больше не требуется, то можно вызвать
  функцию lip_udp_port_unlisten().

  Для передачи UDP-пакета, необходимо заполнить структуру #t_lip_udp_info требуемыми
  параметрами. При этом рекомендуется сперва обнулить всю структуру с помощью
  memset(), а после заполнить требуемые поля. Таким образом, при внесении новых
  полей в будущих версиях, они не останутся непроинициализированными.

  После этого необходимо вызвать функцию lip_udp_prepare(), которая подготовит UDP-пакет
  и вернет указатель на буфер, который нужно заполнить данными протокола верхнего
  уровня, и его размер. После того, как буфер будет заполнен, вызывается lip_udp_flush()
  с указанием размера пакета, после чего пакет отправляется.

  Между lip_udp_prepare() и lip_udp_flush() нельзя вызывать lip_pull(). Эти действия
  делаются как правило в одной функции. Каждому lip_udp_flush() должен предшествовать
  lip_udp_prepare(), однако возможно вызвать lip_udp_prepare() и не вызывать
  lip_udp_flush(), например, если при заполнении данных произошло событие,
  требующее не посылать этот пакет.
  Следующий lip_udp_prepare() удалит все результаты предыдущего.
******************************************************************************/

/***************************************************************************//**
 @addtogroup lip_udp
 @{
 @file lip_udp.h
 @brief Файл содержит определения функций и макросов для модуля @ref lip_udp,
   которые могут быть использованы в приложении.
 @author Borisov Alexey <borisov@lcard.ru>
*******************************************************************************/

#ifndef LIP_UDP_H_
#define LIP_UDP_H_

#include "lip/lip_defs.h"
#include "lip/net/lip_ip.h"


/** Информация для UDP-модуля. Содержит как UDP, так и IP информацию.
    Передается UDP-модулем, принявшим UDP-пакет в зарегистрированный
    callback типа #t_lip_udp_in_proc_cb.
    Передается UDP-модулю при формировании пакета в lip_udp_prepare() */
typedef struct {
    uint16_t src_port; /**< UDP-порт источника */
    uint16_t dst_port; /**< UDP-порт назначения */
    const uint8_t *src_addr; /**< Указетель на IP-адрес источника. При приеме
                                  может указывать на место в принятом пакете,
                                  поэтому при необходимости использовать его в
                                  дальнейшем, нужно скопировать адрес.
                                  При передаче может быть 0
                                  для автоматического выбора. */
    const uint8_t *dst_addr; /**< IP-адрес назначения */
    t_lip_ip_type ip_type; /**< тип IP-адреса */
    uint32_t flags; /**< флаги, как IP-уровня, так и UDP */
    uint16_t data_size; /**< размер данных (при передаче не имеет значения) */
    uint8_t ip_ttl;   /**< TTL для IP-уровня (при передаче может быть 0 для
                           автоматического выбора) */
    uint8_t ip_tos;   /**< Type Of Service IP-уровня */
} t_lip_udp_info;




/** Тип callback-функции, вызываемой при приеме UDP-пакета, если она зарегистрирована
    на заданный порт с помощью lip_udp_port_listen()
    @param[in] pkt   Указатель на начало данных в пакете (сразу за UDP-заголовком)
    @param[in] size  Размер данных в пакете (без UDP заголовка и заголовков нижнего уровня)
    @param[in] info  Структура с информацией UDP и IP уровней о принятом пакете
    @return код ошибки */
typedef t_lip_errs (*t_lip_udp_in_proc_cb)(uint8_t *pkt, size_t size, const t_lip_udp_info *info);

/** @brief начать прослушивание UDP-порта */
t_lip_errs lip_udp_port_listen(uint16_t port, t_lip_udp_in_proc_cb callback);
/** @brief завершить прослушивание UDP-порта */
void lip_udp_port_unlisten(uint16_t port);
/** @brief подготовить UDP-пакет для передачи */
void *lip_udp_prepare(const t_lip_udp_info *tx_info, int *max_size);
/** @brief передать заранее подготовленный пакет */
t_lip_errs lip_udp_flush(int size);


#endif /* LIP_UDP_H_ */

/** @}*/
