Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2743
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

Разработка IoT-приложений

723

typedef struct wiz_NetInfo_t {

 

uint8_t mac[6];

/* Mac-адрес отправителя (источника)

*/

uint8_t ip[4];

/* IP-адрес отправителя (источника)

*/

uint8_t sn[4];

/* Маска подсети

*/

uint8_t gw[4];

/* IP-адрес шлюза (необязательно)

*/

uint8_t dns[4];

/* IP-адрес DNS-сервера (необязательно)

*/

dhcp_mode dhcp;

/* 1 - Статический, 2 - DHCP (необязательно)

*/

} wiz_NetInfo;

 

 

Я не буду здесь подробно описывать эти поля, поскольку они действительно говорят сами за себя. Например, чтобы сконфигурировать W5500 таким образом, чтобы он мог подключаться к подсети 192.168.1.0/24, можно действовать следующим образом:

wiz_NetInfo netInfo = {.mac = {0x00, 0x08,

0xdc, 0xab, 0xcd, 0xef},

// Mac-адрес

.ip = {192, 168, 1,

192},

// IP-адрес

.sn =

{255,

255,

255, 0},

// Маска подсети

.gw =

{192,

168,

1,

1}};

// Адрес шлюза

wizchip_setnetinfo(&netInfo);

Обратите внимание, что в этом примере мы используем произвольный MACадрес. Данная процедура разрешена для закрытой (private) и тестовой среды, но полностью запрещена, если вы планируете продавать свой продукт на базе W5500. В этом случае вам необходимо купить действующий пул MAC-адресов у IEEE (пулы начинаются с пакетов по 4096 адресов примерно за 650 долларов США18). В качестве альтернативы Microchip продает предварительно запрограммированные ИС19 с действующими MAC-адресами IEEE EUI-48 и EUI-64 (они работают как I²C EEPROM). Для мелкосерийных партий они являются хорошей альтернативой покупке обычных MAC-адресов.

26.2.2. API-интерфейсы сокетов

Модуль ioLibrary_Driver предоставляет API-интерфейс для управления сокетами, который напоминает API сокетов BSD. Несмотря на то что он несовместим с ним, если вы уже работали с API-интерфейсом BSD, то вам будет очень легко начать работать с ним.

Чтобы инициализировать новый сокет, мы можем воспользоваться функцией:

int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);

где:

sn: соответствует номеру сокета, и он может меняться от 0 до 7, если вы использу-

ете микросхему W5500, которая предоставляет 8 сокетов.

protocol: этот параметр определяет тип протокола сокета. W5500 может обрабаты-

вать три типа протоколов: сокеты TCP, UDP и RAW20. Таким образом, этот параметр может принимать одно из значений Sn_MR_TCP, Sn_MR_UDP и Sn_MR_MACRAW.

18http://standards.ieee.org/develop/regauth/oui36/index.html

19http://www.microchip.com/design-centers/memory/serial-eeprom/getting-started/with-mac-address-chips

20Сокет RAW – это сокет, который позволяет обмениваться пакетами напрямую с использованием протокола IP и без какого-либо транспортного уровня, специфичного для протокола (то есть TCP или UDP).

SF_MULTI_ENABLE

Разработка IoT-приложений

724

port: задает номер порта, связанный с сокетом.

flag: это комбинация (логическое ИЛИ) дополнительных параметров конфигура-

ции, перечисленных в таблице 1.

В случае успеха функция socket() возвращает значение sn, в противном случае она может вернуть SOCKERR_SOCKNUM, чтобы указать о недопустимом номере сокета, SOCKERR_SOCKMODE, чтобы указать о недопустимом протоколе, или SOCKERR_SOCKFLAG, чтобы указать о недопустимом параметре flag.

Таблица 1: Значения флага сокета

Режим Описание

SF_IO_NONBLOCK Конфигурация сокета в неблокирующем режиме

SF_ETHER_OWN W5500 может принимать только широковещательные пакеты (broadcast packets) или пакеты, отправленные самому себе. Данный параметр применим только к сокету RAW.

SF_IGMP_VER2

Включение IGMP версии 2, если протокол сокета – UDP, при этом если также задан режим

SF_MULTI_ENABLE

SF_TCP_NODELAY

Включение режима мультивещания (multicast mode), если протокол сокета – UDP

Конфигурация сокета TCP таким образом, чтобы пакет ACK отправлялся только после того, как принимается пакет данных от удаленного узла

SF_BROAD_BLOCK

SF_MULTI_BLOCK

Запрет сокету получать широковещательные пакеты, если протокол сокета – UDP или RAW.

Запрещает сокету получать широковещательные пакеты, если протокол сокета – RAW

SF_IPv6_BLOCK

SF_UNI_BLOCK

Запрещает сокету получать пакеты IPv6, если протокол сокета – RAW

Запрет сокету получать одноадресные пакеты (unicast packets), если протокол сокета – UDP.

Для того чтобы закрыть сокет и деконфигурировать его используется функция:

int8_t close(int8_t sn);

Прочитайте внимательно

Обратите внимание, что если вы используете функции ввода-вывода из стандартной библиотеки Си, то эта функция выйдет из строя из-за сигнатуры функции close() стандартной библиотеки Си, которая предназначена для приема и возврата типа int. Будет сгенерировано много ошибок компилятора. К сожалению, ребята из WIZnet выбрали неудачное имя и сигнатуру. Вы можете обойти данную проблему, изменив библиотеку путем объявления функции close() другим способом:

int close(int sn);

Сокет W5500 имеет четко определенное состояние, и бывает действительно полезно получать его, чтобы лучше понять состояние соединения. Макрос:

Разработка IoT-приложений

725

getSn_SR(sn);

автоматически получает состояние сокета из его регистров. Возможные значения состояния для микросхемы W5500 перечислены в таблице 2.

 

Таблица 2: Значения состояний сокета

Состояние

Описание

 

 

SOCK_CLOSED

Закрыт

SOCK_INIT

В состоянии инициализации

SOCK_LISTEN

Прослушивание

SOCK_ESTABLISHED

Соединение установлено

SOCK_CLOSE_WAIT

Состояние закрытия

SOCK_UDP

Сокет UDP

SOCK_SYNSENT

Пакет запроса на соединение (SYN), отправленный

 

удаленному узлу

SOCK_SYNRECV

Пакет запроса на соединение (SYN), полученный от

 

удаленного узла

SOCK_FIN_WAIT

Запущена процедура закрытия сокета

SOCK_CLOSING

Закрытие сокета

SOCK_TIME_WAIT

Ожидание закрытия сокета

SOCK_LAST_ACK

Сокет все еще открыт, но удаленный узел закрыл

 

соединение

26.2.2.1. Управление сокетами в режиме TCP

После настройки протокола и режима сокета мы можем начать соединение с удаленным узлом (клиентское приложение) или перевести сокет в режим прослушивания, чтобы принимать соединения от удаленного узла (серверное приложение).

Чтобы начать соединение с удаленным узлом, мы можем воспользоваться функцией:

int8_t connect(uint8_t sn, uint8_t * addr, uint16_t port);

sn: соответствует сокету, сконфигурированному функцией socket().

addr: массив из четырех байт, соответствующий адресу IPv4 удаленного узла.

port: номер порта удаленного узла.

Вслучае успеха функция connect() возвращает значение SOCK_OK. В противном случае существует перечень возможных значений ошибок. Взгляните на файл socket.h.

Когда соединение с удаленным узлом установлено, мы можем отправить последовательность байт, воспользовавшись функцией:

int32_t send(uint8_t sn, uint8_t * buf, uint16_t len);

где buf – массив байтов, имеющий длину len.

И наоборот, чтобы получить массив байтов от удаленного узла, мы можем воспользоваться функцией:

int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len);