Lwip на mbed-os 5 не устанавливает правильное соединение с Ethernet

Моя цель — отправлять UDP-пакеты с микроконтроллера (системной платы) на ПК — так просто. Обновить: Я успешно достиг цели. Я объясню здесь, как я это сделал, и проблемы, с которыми я столкнулся изначально. Большое спасибо сообществу StackOverflow и людям из группы LinkedIn ARM, которые выручили меня!


1. ОБЗОР СИСТЕМЫ

Моя система выглядит следующим образом:

1.1 Сторона микроконтроллера

  • Плата Nucleo_F767ZI с микроконтроллером STM32F767ZI. Эта плата имеет разъем Ethernet.
  • Операционная система Mbed-OS 5.
  • Библиотека lwip (которая является частью операционной системы Mbed-OS 5).

1.2 ПК сторона 

  • Windows 10, 64-битная.
  • Свободный порт Ethernet (интернет через WiFi, поэтому этот порт Ethernet не используется).
  • Wireshark, чтобы увидеть, действительно ли микроконтроллер отправляет UDP-пакеты. Их интерпретация будет сделана позже в Python. Сначала я хочу увидеть пакеты в Wireshark.

1.3 Соединения
Первоначально я подключил плату нуклео непосредственно к своему компьютеру, без участия маршрутизатора или коммутатора. Такая настройка требует «статической конфигурации IP». Я бы настроил на ПК IP-адрес «192.168.1.10», а на микроконтроллере — «192.168.1.20». Я знаю, что это может сработать, потому что я делал это раньше с помощью микроконтроллера PIC.
Но эта ситуация немного отличается. У меня на микроконтроллере работает небольшая операционная система: mbed-os v5. Эта операционная система использует Lwip (облегченный стек IP). Хотя должна быть возможность настроить «статический IP-адрес», программное обеспечение в настоящее время не поддерживает его. Более подробную информацию можно найти здесь: https://developer.mbed.org/questions/74145/EthernetInterfaceinit-mbed-os-5x-not-wor/. Поскольку нет способа настроить статический IP-адрес на микроконтроллере, вам нужен сервер DHCP. Микроконтроллер подключается к сети без IP-адреса и передает пакет с вопросом: «Какой IP-адрес мне следует использовать в этой сети?». Если микроконтроллер не получит ответ, он несколько раз передаст вопрос и в конце концов сдастся.
Если к сети подключен DHCP-сервер, он получит вопрос и передаст бесплатный IP-адрес. Так что это то, что вам нужно. Существует несколько способов предоставить такой сервер DHCP:

  • Установите DHCP-сервер на ПК с Windows. Это единственный способ сохранить коммутаторы и маршрутизаторы вне поля зрения. Плата с ядром подключена напрямую к ПК. Когда микроконтроллер передает вопрос, ПК с Windows передает IP-адрес. После этого может начаться общение.
  • Киньте Raspberry PI в игру. Raspberry PI должен запустить DHCP-сервер. Подключите три устройства (ПК с Windows, Raspberry PI и Nucleo Board) к коммутатору.
  • Купи простой роутер. Домашние маршрутизаторы имеют встроенный DHCP-сервер. Подключите ПК с Windows и плату Nucleo к портам локальной сети этого маршрутизатора.

Я решил пойти на третий вариант. На следующем рисунке показаны подключения к моему маршрутизатору Netgear R7000:

Маршрутизатор Netgear R7000

 

2. НАСТРОЙКА МАРШРУТА

DHCP-сервер внутри маршрутизатора будет раздавать IP-адреса всем подключенным к нему устройствам. Мой маршрутизатор будет передавать IP-адрес «192.168.1.2» первому устройству, «192.168.1.3» второму и т. Д. Вплоть до «192.168.1.254». Но это немного проблематично. Как ПК и микроконтроллер могут узнать IP-адреса друг друга? Возможно, есть более умные решения, но я нашел следующий подход.
У каждого DHCP-сервера есть таблица с «зарезервированными IP-адресами». В этой таблице вы можете добавить устройства и назначить им статический IP-адрес. Поэтому всякий раз, когда это устройство запрашивает IP-адрес, DHCP-сервер просматривает таблицу и передает тот, который вы настроили. Но как DHCP-сервер распознает устройство? Он может распознать устройство по его MAC-адресу. Каждое устройство имеет глобально уникальный MAC-адрес в 6 байтов.
Вот как я добавил свой ПК с Windows и мой микроконтроллер в таблицу:

  • ШАГ 1. Подключите компьютер к одному из портов LAN маршрутизатора. Включите роутер.
  • ШАГ 2. Убедитесь, что все WiFi на вашем компьютере отключены. Я испытал много проблем с этим. (*)
  • ШАГ 3: Откройте браузер и перейдите к «192.168.1.1». Это моя домашняя страница роутеров. Это может отличаться для вашего роутера.
  • ШАГ 4: Вход (мой логин по умолчанию для моих маршрутизаторов — «admin» для имени пользователя и «password» для пароля)
  • ШАГ 5: Добавьте ПК с Windows и плату микроконтроллера к столу. Вы должны сначала посмотреть их MAC-адреса (**):

Конфигурация маршрутизатора Netgear R7000

2.1 Отключить все WiFi (*)
Это должен быть простой шаг, но Windows усложняет. Windows может быть достаточно упрямой и автоматически подключаться к WiFi-сетям, даже если вы сняли флажок подключаться автоматически коробка! Чтобы заставить Windows слушать вас, вы можете использовать терминал cmd. Откройте терминал cmd с правами администратора. Затем введите следующую команду, чтобы увидеть все ваши профили WiFi:

> netsh wlan show profiles

Примените следующую команду для тех WiFi профилей, что ваш компьютер упорно подключающихся к:

> netsh wlan set profileparameter name="someWifiName" connectionmode=manual

Теперь вы можете отключиться от этой сети Wi-Fi, и Windows больше не будет автоматически подключаться.

2.2 Найдите MAC-адрес вашего ПК (**)
Так я нашел MAC-адрес своего компьютера. Имейте в виду, что компьютер может иметь несколько MAC-адресов. Один для вашего порта Ethernet будет отличаться от вашего беспроводного соединения! Тип ipconfig /all в терминале Windows cmd. Я получил следующий вывод:

# Note: this is the correct item!
# --------------------------------
Ethernet adapter Local Area Connection:

Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix  . :
Description . . . . . . . . . . . : Intel(R) Ethernet Connection (2) I219-LM
Physical Address. . . . . . . . . : C8-xx-xx-xx-xx-01   # Replaced some numbers by x for security :-)
DHCP Enabled. . . . . . . . . . . : Yes
Autoconfiguration Enabled . . . . : Yes

Убедитесь, что вы смотрите на правильный пункт в списке соединений. Ethernet adapter Local Area Connection является правильным для моего компьютера, потому что описание сетевой карты соответствует ожидаемому: Intel(R) Ethernet Connection (2) I219-LM, Раньше я смотрел на другой элемент в списке, помеченный Ethernet adapter Ethernet:

# Note: this is the wrong item!
# ------------------------------
Ethernet adapter Ethernet:

Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix  . :
Description . . . . . . . . . . . : TAP-Windows Adapter V9
Physical Address. . . . . . . . . : 00-xx-xx-xx-xx-F7
DHCP Enabled. . . . . . . . . . . : No
Autoconfiguration Enabled . . . . : Yes

Г-н Джоэл С. (см. Его ответ ниже) уведомил меня, что сетевая карта из этого пункта TAP-Windows Adapter V9, Видимо, это виртуальная сетевая карта. Это заставило меня потерять много времени. Спасибо мистер Джоэл С. за помощь!
Пожалуйста, убедитесь, что DHCP включен а также Автоконфигурация включена включены!

2.3 Найдите MAC-адрес вашей платы Nucleo (**)
Я нашел MAC-адрес моей платы Nucleo со следующим кодом:

#include "lwip-interface/EthernetInterface.h"
//1. Make an ethernet object
EthernetInterface eth;

//2. Try to connect
eth.connect();            // <- This line will not work now,
//    but at least it will help you to find out your
//    own MAC-address.

//3. Print the MAC-address
logger.printf("Controller MAC Address is: %s\r\n", eth.get_mac_address());

Вывод на печать, который я получил через мой последовательный порт (некоторые цифры я заменил на x для безопасности):

Controller MAC Address is: 00:xx:xx:xx:xx:40

 
 

3. МИКРОКОНТРОЛЛЕРНЫЙ КОД

Это код, который работает на микроконтроллере. мой main.cpp файл основан на коде, найденном на форуме Mbed-os по адресу https://forums.mbed.com/t/udp-receive-with-nucleo-f767zi/1806.

#include <string>
using std::string;
#include "mbed.h"#include "lwip-interface/EthernetInterface.h"
static Serial logger(USBTX, USBRX);
static DigitalOut led1(LED1);

// IP addresses
#define IP_COMPUTER  "192.168.1.10"     // Make sure these IP addresses correspond to the
#define IP_NUCLEO    "192.168.1.20"     // table of 'reserved IP addresses' you have setup in
// your routers DHCP server!

// Ethernet settings
const int PORT_T = 50000;
const int PORT_R = 50001;
EthernetInterface eth;

static void udp_tx_thread_func();
static void udp_rx_thread_func();
static Thread udp_tx_thread;
static Thread udp_rx_thread;int main()
{
// 1. Initialize the serial logger
logger.baud(115200);
logger.printf("\r\n\r\nApplication started\r\n");

// 2. Initialize and start the UDP connection
eth.connect();
logger.printf("Controller MAC Address is: %s\r\n", eth.get_mac_address());
logger.printf("Controller IP Address is:  %s\r\n", eth.get_ip_address());
Thread::wait(200);

udp_tx_thread.start(udp_tx_thread_func);
udp_rx_thread.start(udp_rx_thread_func);while (true)
{
led1 = !led1;
Thread::wait(500);
}
}

//------------------ Ethernet --------------------------------------------------

static void udp_tx_thread_func()
{
UDPSocket socket(&eth);
SocketAddress sock_addr(IP_COMPUTER, PORT_T);
static uint32_t out_buffer[3];while(true)
{
Thread::wait(100);

// Send 3 values of 32-bit each
out_buffer[0] = 150500;
out_buffer[1] = 255300;
out_buffer[2] = 54;int ret = socket.sendto(sock_addr, &out_buffer[0], 12);    // 3 values of 32-bit equals 12 bytes
//logger.printf("sendto return: %d\r\n", ret);
}
}

static void udp_rx_thread_func()
{
UDPSocket socket(&eth);
SocketAddress sock_addr;
int bind = socket.bind(PORT_R);
logger.printf("bind return: %d\n", bind);

char buffer[256];
while(true)
{
//logger.printf("\nWait for packet...\n");
int n = socket.recvfrom(&sock_addr, buffer, sizeof(buffer));
buffer[n] = '\0';
//logger.printf("Packet from \"%s\": %s\n", sock_addr.get_ip_address(), buffer);

Thread::wait(500);
}

}

 

4. РЕЗУЛЬТАТЫ

4.1 Результаты Wireshark
В Wireshark я вижу потоки UDP-пакетов на Local Area Connection! Huray!

4.2 Python-код
Код Python для перехвата пакетов UDP выглядит следующим образом:

import sys
import os
import socket
import dataprocessing.datastruct as datastructdef main():
# 1. Configure the IP address
# -----------------------------
myAddr = ('192.168.1.10', 50000)

# 2. Create a UDP socket
# -----------------------
sock = None
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1.5)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(myAddr)
print('UDPsock @: ' + str(sock.getsockname()))
sys.stdout.flush()

except Exception as e:
print('Could not bind to the UDP socket.')
print(e)
sys.stdout.flush()

while (true):
try:
data, address = sock.recvfrom(256)  # buffer size is 256 bytes
bytedata = bytearray(data)

# Each 32-bit number is cut in 8-bit pieces. Bring them back together.
value_01 = bytedata[0] + 256*bytedata[1] + 65536*bytedata[2] + 16777216*bytedata[3]
value_02 = bytedata[4] + 256*bytedata[5] + 65536*bytedata[6] + 16777216*bytedata[7]
value_03 = bytedata[8] + 256*bytedata[9] + 65536*bytedata[10] + 16777216*bytedata[11]

print("Value 01: %d", value_01)
print("Value 02: %d", value_02)
print("Value 03: %d", value_03)

except socket.error as err:
print(err)

if __name__== '__main__':
print("")
print("Start UDP catcher")
print("-----------------")
main()

 

5. ДАВАЙТЕ WIFI И ETHERNET COEXIST

Пакеты UDP от микроконтроллера поступают на ваш порт Ethernet (проходя через маршрутизатор). В то же время вы можете подключиться к некоторой сети Wi-Fi для доступа в Интернет. Проблема в том, что любой браузер попытается получить доступ через порт Ethernet — игнорируя WiFi.
Решение состоит в том, чтобы сделать ваши браузеры ПЕРВОЙ попыткой использовать Wi-Fi для достижения IP-адреса, следующую попытку через порт Ethernet. Это делается с помощью «Метрики интерфейса» на панели управления. Увеличьте это число немного:

введите описание изображения здесь

0

Решение

Соединение, которое вы пометили Ethernet на самом деле соединение TAP (например, виртуальная карта Ethernet). Ваше фактическое соединение с Ethernet помечено Local Area Connection; это соединение, которое вам нужно будет настроить и наблюдать с помощью Wireshark и т. д.

Что касается всего остального, связанного с Mbed-OS, я лично не занимался этим.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector