ESP-NETIF |
Добавил(а) microsin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Библиотека ESP-NETIF предназначена для решения двух задач: • Предоставить слой абстракции для приложений, работающих поверх стека TCP/IP. Это позволит приложениям в будущем выбирать между стеками IP. В настоящее время (на момент перевода документации [1], версия ESP-IDF v5.0.1) система разработки ESP-IDF реализует ESP-NETIF только для API-стека lwIP TCP/IP. Однако адаптер сам по себе не привязан к конкретной реализации TCP/IP, и позволяет использовать различные реализации. Также можно применять пользовательский стек TCP/IP с ESP-IDF при условии, что он реализует BSD API. Дополнительную информацию о создании ESP-IDF без lwIP см. components/esp_netif_stack/README.md. Некоторые API-функции ESP-NETIF предназначены для вызова из кода приложения. Например, чтобы получить или установить интерфейс IP-адресов и конфигурировать DHCP. Другие функции предназначены для внутреннего использования слоем сетевого драйвера ESP-IDF. Во многих случаях приложениям не нужно напрямую вызывать API-функции ESP-NETIF, поскольку они вызываются обработчиками по умолчанию для сетевых событий (default network event handlers). Архитектура библиотеки ESP-NETIF: | (A) КОД ПОЛЬЗОВАТЕЛЯ | | Apps | .................| init settings events | . +----------------------------------------+ . . | * . . | * --------+ +===========================+ * +-----------------------+ | | new/config get/set/apps | * | init | | | |...*.....| Apps (DHCP, SNTP) | | |---------------------------| * | | init | | |**** | | start |************| event handler |*********| DHCP | stop | | | | | | |---------------------------| | | | | | | NETIF | +-----| | | +-----------------+ | | glue|---<----|---| esp_netif_transmit |--<------| netif_output | | | | | | | | | | | |--->----|---| esp_netif_receive |-->------| netif_input | | | | | | | + ----------------+ | | |...<....|...| esp_netif_free_rx_buffer |...<.....| буфер пакета | +-----| | | | | | | | | | | | | (D) | (B) | | | | (C) | +-----------------------+ --------+ | | +===========================+ КОММУНИКАЦИОННЫЙ| | СЕТЕВОЙ СТЕК ДРАЙВЕР | | ESP-NETIF | | +------------------+ | | +---------------------------+.........| open/close | | | | | | | | -<--| l2tap_write |-----<---| write | | | | | | ---->--| esp_vfs_l2tap_eth_filter |----->---| read | | | | | | (E) | +------------------+ +---------------------------+ КОД ПОЛЬЗОВАТЕЛЯ ESP-NETIF L2 TAP Легенда потока событий событиями: ......... Линия инициализации из кода пользователя для ESP-NETIF и коммуникационного драйвера. [Взаимодействие с библиотекой ESP-NETIF] Шаблон кода пользователя. Все взаимодействие приложения с определенным драйвером IO для среды обмена и сконфигурированным стеком TCP/IP абстрагировано API-вызовами ESP-NETIF следующим образом: A) Код инициализации. 1a. Инициализирует IO-драйвер. 2a. Создает новый экземпляр ESP-NETIF и конфигурирует его со следующими объектами: - Специфические для ESP-NETIF опции (флаги, поведение, имя). 3a. Связывается дескриптор IO-драйвера с экземпляром ESP-NETIF, созданном шагами выше. 4a. Конфигурируются обработчики событий. - Используются обработчики по умолчанию для общих интерфейсов, определенных в драйверах IO; либо определяется специальный обработчик для пользовательского поведения или новых интерфейсов. B) Взаимодействие с сетевыми интерфейсами через ESP-NETIF API. 1b. Извлекаются и устанавливаются параметры, связанные с TCP/IP (DHCP, IP, и т. д.). 2b. Принимаются события IP (connect или disconnect). 3b. Осуществляется управление времени жизни приложения (поднять или опустить сетевой интерфейс). Communication Driver, IO Driver и Media Driver. Драйвер коммуникации играет следующие 2 важные роли, относящиеся к ESP-NETIF: 1. Обработчики событий (event handlers): определяет шаблоны поведения при взаимодействии с ESP-NETIF (например ethernet link-up -> включить netif). 2. Пристыковка (Glue) слоя IO: адаптация входных или выходных функций для использования ESP-NETIF передачи, приема и освобождения буфера приема. - Устанавливает driver_transmit для соответствующего объекта ESP-NETIF, чтобы уходящие из сетевого стека пакеты передавались драйверу IO. ESP-NETIF. Библиотека ESP-NETIF обрабатывает взаимодействие между драйвером IO и сетевым стеком, передавая данные пакета между ними. Она предоставляет набор интерфейсов для подсоединения драйвера к объекту ESP-NETIF во время работы кода (runtime) и конфигурирует сетевой стек во время компиляции. Дополнительно предоставляется набор API-функций для управления временем жизни сетевого интерфейса и его свойствами TCP/IP. В качестве обзора, публичный интерфейс ESP-NETIF можно поделить на 6 групп: 1. API-функции инициализации (для создания и конфигурирования экземпляра ESP-NETIF). 2. API ввода и вывода (для перемещения данных между драйвером IO и сетевым стеком). 3. Event или Action API. - Используется для управления циклом жизни сетевого интерфейса. 4. API-функции для установки/извлечения (set/get) базовых свойств сетевого интерфейса. 5. API абстракции от сетевого стека: позволяет организовать взаимодействие со стеком TCP/IP для пользователя. - Включение/выключение сетевого интерфейса (up/down). 6. Driver conversion utilities API. Network Stack. Сетевой стек не имеет общего взаимодействия с кодом приложения в контексте общедоступных интерфейсов, и он должен полностью абстрагироваться через API ESP-NETIF. Интерфейс ESP-NETIF L2 TAP. Интерфейс ESP-NETIF L2 TAP это механизм ESP-IDF, используемый для доступа к слою обмена данными (Data Link Layer, L2 в модели OSI/ISO), когда кадр принимается или передается приложением пользователя. Его типичным использованием в мире встраиваемых систем может быть реализация протоколов, не связанных с IP, например, PTP, Wake on LAN. Следует отметить, что в настоящее время поддерживается только Ethernet (IEEE 802.3). С точки зрения пользователя к интерфейсу ESP-NETIF L2 TAP осуществляется доступ с помощью дескрипторов файла VFS, когда предлагается взаимодействие по принципу работы с файлами (с использованием функций наподобие open(), read(), write(), и т. д.). Подробности см. в описании компонента виртуальной файловой системы (Virtual FileSystem, VFS) [2]. Доступно только одно устройство интерфейса ESP-NETIF L2 TAP (path name). Однако можно одновременно открыть несколько дескрипторов файла с различными конфигурациями, поскольку интерфейс ESP-NETIF L2 TAP может понять традиционную точку входа в инфраструктуру Layer 2. Важно иметь специфичную конфигурацию конкретного дескриптора файла. Он может быть сконфигурирован для предоставления доступа к определенному сетевому интерфейсу, идентифицированному if_key (например, ETH_DEF), и фильтрации только определенных кадров на основе их типа (например, типа Ethernet в случае IEEE 802.3). Фильтрация только определенных кадров имеет решающее значение, поскольку TAP ESP-NETIF L2 должен существовать вместе со стеком IP, и поэтому трафик, связанный с IP (IP, ARP и т. д.), не должен передаваться непосредственно пользовательскому приложению. Несмотря на то, что эта опция по-прежнему является конфигурируемой, она не рекомендуется в стандартных сценариях использования. Фильтрация также выгодна с точки зрения приложения пользователя, поскольку оно получает доступ только к интересным для приложения типам кадров, а оставшийся трафик либо передается другим дескрипторам файлов ТАР L2, либо стеку IP. [Руководство по использованию интерфейса ESP-NETIF L2 TAP] Инициализация. Чтобы можно было использовать интерфейс ESP-NETIF L2 TAP, он должен быть предварительно разрешен в Kconfig опцией CONFIG_ESP_NETIF_L2_TAP, и затем зарегистрирован esp_vfs_l2tap_intf_register() до того, как будет применена любая из функций VFS [2]. open(). Как только ESP-NETIF L2 TAP был зарегистрирован, его можно открыть по указанному пути "/dev/net/tap" (path name). Один и тот же путь можно открыть несколько раз до величины CONFIG_ESP_NETIF_L2_TAP_MAX_FDS, и несколько файловых дескрипторов могут получить доступ к кадрам Data Link Layer (L2). ESP-NETIF L2 TAP может быть открыт с флагом статуса файла O_NONBLOCK, чтобы вызов read() не был блокирующим. Имейте в виду, что в текущей реализации вызов write() может заблокировать работу кода, когда происходит доступ к сетевому интерфейсу, потому что он является общим ресурсом для нескольких дескрипторов файла ESP-NETIF L2 TAP и стеком IP, и в настоящий момент не реализован механизм очередей. Флаг статуса файла можно получить и изменить с помощью fcntl(). В случае успеха open() вернет новый дескриптор файла (неотрицательное целое число). В случае ошибки будет возвращено значение -1, и установится переменная errno для обозначения причины ошибки. ioctl(). Новый открытый дескриптор файла ESP-NETIF L2 TAP перед использованием нужно сконфигурировать для своего применения, потому что он пока что не привязан ни к какому сетевому интерфейсу, и для него не сконфигурирован фильтр типа кадра. Для этого доступны следующие опции конфигурации: L2TAP_S_INTF_DEVICE - привязывает дескриптор файла к определенному сетевому интерфейсу, который идентифицируется по его if_key. ESP-NETIF Network Interface if_key передается в ioctl() через третий параметр. Обратите внимание, что if_key сетевого интерфейса в ESP-IDF можно найти в esp_netif/include/esp_netif_defaults.h. L2TAP_S_DEVICE_DRV_HNDL - другой способ привязать дескриптор файла к определенному сетевому интерфейсу. В этом случае сетевой интерфейс идентифицируется напряму по его дескриптору драйвера ввода/вывода (IO Driver handle, например esp_eth_handle_t в случае интерфейса Ethernet). Дескриптор драйвера IO передается в ioctl() через третий параметр. L2TAP_S_RCV_FILTER - установит фильтр на кадры по типу, чтобы они передавались дескриптору файла. В случае кадров Ethernet, кадры фильтруются на основе поля длины Length и типа Ethernet. В случае, когда значение фильтра установлено меньше или равным 0x05DC, поле типа Ethernet учитывается для представления IEEE802.3 Length Field, и все кадры со значениями в интервале < 0, 0x05DC> в этом поле передаются в дескриптор файла. Тогда ожидается, что разрешение логического управления на слое соединения (IEEE802.2 logical link control, LLC) выполняется приложением пользователя. В случае, когда значение фильтра больше 0x05DC, поле типа Ethernet учитывается для представления идентификации протокола, и дескриптору файла передаются только те кадры, у которых совпадает это значение. Все упомянутые выше опции конфигурации имеют комплементарные функции для установки и чтения текущих настроек. Предупреждение: дескриптор файла должен быть сначала привязан к определенному сетевому интерфейсу через L2TAP_S_INTF_DEVICE или L2TAP_S_DEVICE_DRV_HNDL, чтобы сделать доступной опцию L2TAP_S_RCV_FILTER. Замечания: 1. Кадры, помеченные как VLAN, в текущей реализации не распознаются. Если пользователю надо обрабатывать кадры VLAN, то для них нужно установить фильтр, соответствующий тегу VLAN (например 0x8100 или 0x88A8), и обрабатывать кадры с метками VLAN в приложении пользователя. В случае успеха ioctl() вернет 0. В случае ошибки будет возвращено значение -1, и установится errno для индикации ошибки. * EBADF - недопустимый дескриптор файла. fcntl(). Функция fcntl() используется для манипуляций над свойствами открытого дескриптора файла ESP-NETIF L2 TAP. Следующие команды управляют флагами статуса, связанными с дескриптором файла: F_GETFD - функция возвратит флаги дескриптора файла, и третий аргумент игнорируется. В случае успеха ioctl() возвратит 0. В случае ошибки будет возвращено значение -1, и установится errno для индикации ошибки. * EBADF - недопустимый дескриптор файла. read(). К открытому и сконфигурированному дескриптору файла ESP-NETIF L2 TAP можно обращаться вызовами read(), чтобы получить приходящие кадры. Операция чтения (read) может быть либо блокирующей, либо неблокирующей, базируясь на реальном состоянии флага статуса файла O_NONBLOCK. Когда этот флаг статуса файла установлен для блокирования, операция чтения ждет, пока не будет принят кадр, и контекст переключится на другие задачи. Когда флаг статуса файла установлен на non-blocking, операция чтения выполнит немедленный возврат. В таком случае либо будет сразу возвращен кадр, если он уже находится в очереди приема, либо функция покажет, что очередь приема пуста. Количество постановок в очередь кадров, связанных с одним дескриптором файла, ограничивается Kconfig-опцией CONFIG_ESP_NETIF_L2_TAP_RX_QUEUE_SIZE. Как только количество поставленных в очередь кадров достигнет сконфигурированного порога, новые поступающие кадры отбрасываются, пока очередь не освободиться настолько, чтобы принять поступающий трафик (Tail Drop queue management). В случае успеха read() возвратит количество прочитанных байт. Будет возвращено значение 0, когда размер буфера назначения 0. В случае ошибки будет возвращено значение -1, и установится errno для индикации ошибки. * EBADF - недопустимый дескриптор файла. write(). Сырой кадр Data Link Layer (L2) может быть передан в сетевой интерфейс через открытый и сконфигурированный дескриптор файла ESP-NETIF L2 TAP. Приложение пользователя отвечает за конструирование всего кадра целиком кроме полей, которые автоматически будут добавлены на слое устройства физического интерфейса. Приложением пользователя должны быть сконструированы следующие поля в случае линка Ethernet: MAC-адреса источника/назначения, тип Ethernet, реальный заголовок протокола, и данные пользователя. Длина этих полей следующая:
Другими словами, интерфейсом ESP-NETIF L2 TAP не производится никакая дополнительная обработка кадра. Делается только проверка, что тип Ethernet кадра такой же, что и в фильтре, сконфигурированном в дескрипторе файла. Если тип Ethernet отличается, то будет возвращена ошибка, и кадр не будет отправлен. Обратите внимание, что write() может заблокировать выполнение кода, потому что в текущей реализации сетевой интерфейс является общим ресурсом между несколькими дескрипторами файла ESP-NETIF L2 TAP и стеком IP, и для этого в текущей реализации используется механизм очередей. В случае успеха write() вернет количество записанных байт. Будет возвращен 0, когда размер входного буфера нулевой. В случае ошибки будет возвращено значение -1, и установится errno для индикации ошибки. * EBADF - недопустимый дескриптор файла. close(). Открытый дескриптор файла ESP-NETIF L2 TAP может быть закрыт вызовом close(), чтобы освободить выделенные для этого ресурсы. Реализация ESP-NETIF L2 TAP может заблокировать выполнение кода при вызове close(). С другой стороны, если библиотека thread-safe, и вызов close() может быть из другой задачи, отличающейся от той, где реально используется дескриптор файла. Если произошла такая ситуация, и одна задача заблокирована в операции ввода/вывода, и другая задача пытается закрыть дескриптор файла, то первая задача разблокируется, и операция чтения первой задачи завершится с ошибкой. В случае успеха close() возвратит. В случае ошибки будет возвращено значение -1, и установится errno для индикации ошибки. * EBADF - недопустимый дескриптор файла. select(). Эта операция используется по стандарту, просто нужно разрешить опцию CONFIG_VFS_SUPPORT_SELECT, чтобы функция select() была доступна. [SNTP API] Краткое общее описание SNTP, его код инициализации и базовые режимы приведены в секции "Синхронизация времени SNTP" документации [3]. В этой секции приведены дополнительные подробности, касающиеся специальных случаев использования службы SNTP, такие как статически сконфигурированные серверы, или использование серверов, сконфигурированных через DHCP, или оба этих сконфигурированных варианта. Рабочий процесс обычно очень прост: 1. Инициализируется и конфигурируется служба с помощью вызова esp_netif_sntp_init(). 2. Служба запускается вызовом esp_netif_sntp_start(). Этот шаг не нужен, если мы задали использовать автоматически запускаемую службу на предыдущем шаге (по умолчанию). Полезно запускать службу явно после соединения, если мы хотим использовать сервера времени, получаемые через DHCP. Обратите внимание, что эта опция должна быть разрешена перед подключением, однако служба SNTP должна быть запущена после подключения. 3. Ожидание момента синхронизации времени с помощью вызова esp_netif_sntp_sync_wait() (только если это необходимо). 4. Остановка и уничтожение службы с помощью esp_netif_sntp_deinit(). Basic Mode со статически определенным сервером (серверами). Инициализируйте модуль с конфигурацией по умолчанию после подключения к сети. Обратите внимание, что есть возможность предоставить несколько серверов NTP в структуре конфигурации: esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2, ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org")); esp_netif_sntp_init(&config); Примечание: если мы хотим конфигурировать несколько серверов SNTP, то должны обновить lwIP-конфигурацию CONFIG_LWIP_SNTP_MAX_SERVERS. Использование серверов SNTP, полученных через DHCP. Сначала мы должны обновить опцию конфигурации CONFIG_LWIP_DHCP_GET_NTP_SRV библиотеки lwIP. Затем нужно инициализировать модуль SNTP с опцией DHCP, и без указания сервера NTP: esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(0, {} ); config.start = false; // явный запуск службы SNTP config.server_from_dhcp = true; // принять предложение (опцию) NTP от сервера DHCP esp_netif_sntp_init(&config); Затем, как произошел connect, мы могли бы запустить службу: esp_netif_sntp_start(); Примечание: также можно запустить эту службу во время инициализации (по умолчанию config.start=true). Это вероятно вызовет сбой начального запроса SNTP (поскольку мы еще не подключены к сети), и приведет к некоторому времени ожидания для последующих запросов. Использование и статических, и динамических серверов. Этот вариант очень похож на показанный выше сценарий (когда DHCP предоставляет адрес сервера SNTP), но в этой конфигурации нам нужно убедиться, что была обновлена статическая конфигурация сервера, когда адреса серверов NTP были получены через DHCP. Нижележащий код lwIP очистит остаток списка серверов NTP, когда принята информация, предоставленная DHCP. Таким образом, модуль ESP-NETIF SNTP сохраняет статически сконфигурированный сервер (серверы), и переконфигурирует список серверов после получения лизинга DHCP. Типовая конфигурация может выглядеть примерно так, как показано ниже, с предоставлением специального события IP_EVENT для обновления конфигурации в структуре config и индекса первого сервера для переконфигурирования (например, установка config.index_of_first_server=1 сохранит предоставленный через DHCP сервер по индексу 0, и статически сконфигурированный сервер по индексу 1). esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); // Запуск сервиса SNTP будет осуществляться специальным API-вызовом (после соединения с сетью): config.start = false; // Принимать адреса серверов NTP, предоставленные лизингом DHCP: config.server_from_dhcp = true; // Позволить esp-netif обновить сконфигурированный сервер (серверы) SNTP после получения
// лизинга DHCP: config.renew_servers_after_new_IP = true; // Обновить время из сервера 1, не трогая сервер 0 (полученный от DHCP): config.index_of_first_server = 1; // IP-событие, на котором мы обновляем конфигурацию: config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; В этом случае мы запустим службу SNTP вызовом esp_netif_sntp_start(), когда произойдет подключение к сети. [Руководство по программированию с применением ESP-NETIF] Просмотрите следующие примеры, чтобы понимать процесс инициализации интерфейса по умолчанию: • Wi-Fi Station: wifi/getting_started/station/main/station_example_main.c Для более специфических случаев обратитесь к руководству [4]. Инициализация Wi-Fi по умолчанию. Код инициализации, как и регистрация обработчиков для интерфейсов по умолчанию, таких как softAP (точка доступа Wi-Fi, режим STA) и station (станция Wi-Fi, режим AP), предоставляется в отдельных API-функциях, чтобы упростить обычный код запуска (startup code) для большинства приложений: • esp_netif_create_default_wifi_sta() Обратите внимание, что эти функции возвратят дескриптор (handle) esp_netif, например указатель на объект сетевого интерфейса, выделенный и сконфигурированный настройками по умолчанию, что как следствие означает: • Созданный объект должен быть уничтожен, если приложением предоставлена деинициализация сети, с помощью вызова esp_netif_destroy_default_wifi(). [Справочник по API-функциям ESP-NETIF] Заголовочный файл: components/esp_netif/include/esp_netif.h. Ниже приведено общее описание назначения функций. Более подробное описание функций и их параметров, а также описание используемых типов данных, структур и макросов см. в документации [1].
Примечание (*): эта API-функция может напрямую использоваться как обработчик события (event handler). Функции SNTP. Заголовочный файл: components/esp_netif/include/esp_netif_sntp.h.
Функции IP-адреса. Заголовочный файл: components/esp_netif/include/esp_netif_ip_addr.h.
Функции L2 TAP. Заголовочный файл: components/esp_netif/include/esp_vfs_l2tap.h.
Функции Wi-Fi. Заголовочный файл: components/esp_wifi/include/esp_wifi_default.h.
[Ссылки] 1. ESP-NETIF site:espressif.com. |