Урок 40
Часть 6
LAN. ENC28J60
В предыдущей части нашего урока мы написали функцию приёма кадров канального уровня и проверили её на практике в терминальной программе.
Нас на данный момент интересуют два типа сетевых протокола — IP (0x0800) и ARP (0x0806), причём пока поконкретней мы разберёмся именно с ARP.
Поэтому добавим макросы в заголовочный файл net.h
#define be16toword(a) ((((a)>>8)&0xff)|(((a)<<8)&0xff00))
//——————————————
#define ETH_ARP be16toword(0x0806)
#define ETH_IP be16toword(0x0800)
Допишем код в функцию eth_read, который определит тип протокола и отобразит тип в терминальной программе
USART_TX((uint8_t*)str1,strlen(str1));
if (frame->type==ETH_ARP) USART_TX((uint8_t*)«; arp»,5);
if (frame->type==ETH_IP) USART_TX((uint8_t*)«; ip»,4);
USART_TX((uint8_t*)«rn»,2);
Соберём код и посмотрим
Теперь мы уже наглядно видим, какой у нас протокол и кто прислал кадр.
Дальнейшая задача — прочитать структуру заголовка ARP, а это у нас уже следующий уровень — не канальный, а сетевой.
ARP (Address Resolution Protocol) или протокол разрешения адресов — это протокол, который служит для того, чтобы сетевое устройство могло определить чей-то физический адрес (MAC) по сетевому адресу (IP). Для этого устройство посылает широковещательный запрос (с адресом приёмника FF-FF-FF-FF-FF-FF, соостоящим из всех единиц), в котором спрашивает: «Какой физический адрес имеет устройство с таким-то IP-адресом?». Требуется это для того, чтобы устройства могли общаться по физическому уровню, который ничего не знает об IP-адресах. Поэтому устройство и отправляет такой запрос. Его получают все компьютеры (или какие-то другие устройства) в данной локальной сети, и устройство, узнавшее свой сетевой адрес, обязано отправить ответ.
Теперь разберём конкретно, как это делается. Структура заголовка ARP:
Поэтому добавим структуру для заголовка ARP
} enc28j60_frame_ptr;
//——————————————
typedef struct arp_msg {
uint16_t net_tp;
uint16_t proto_tp;
uint8_t macaddr_len;
uint8_t ipaddr_len;
uint16_t op;
uint8_t macaddr_src[6];
uint32_t ipaddr_src;
uint8_t macaddr_dst[6];
uint32_t ipaddr_dst;
} arp_msg_ptr;
Вернёмся теперь в файл net.c и добавим функцию для чтения пакета arp чуть выше функции чтения кадра
//———————————————————
uint8_t arp_read(enc28j60_frame_ptr *frame, uint16_t len)
{
}
//———————————————————
Возвращать будем 1 в том случае, если модуль узнает свой адрес в запросе.
Вызовем эту функцию в функции eth_read, добавив фигурные скобки для тела условия
if (frame->type==ETH_ARP)
{
USART_TX((uint8_t*)«; arp»,5);
arp_read(frame, len — sizeof(enc28j60_frame_ptr));
}
if (frame->type==ETH_IP) USART_TX((uint8_t*)«; ip»,4);
Добавим переменную для результата и поставим указатель на пакет arp, для этого добавим соответствующий код в функцию arp_read
void arp_read(enc28j60_frame_ptr *frame, uint16_t len)
{
uint8_t res = 0;
arp_msg_ptr *msg = (void*)(frame->data);
Добавим ещё некоторые макросы в файл net.h
#define ETH_IP be16toword(0x0800)
//——————————————
#define ARP_ETH be16toword(0x0001)
#define ARP_IP be16toword(0x0800)
#define ARP_REQUEST be16toword(1)
#define ARP_REPLY be16toword(2)
Ещё добавим макрос для объединения адреса IP из байтов в 32-битную величину
#define be16toword(a) ((((a)>>8)&0xff)|(((a)<<8)&0xff00))
//——————————————
#define ip_join(a,b,c,d) ( ((uint32_t)a) | ((uint32_t)b << 8) |
((uint32_t)c << 16) | ((uint32_t)d << 24) )
Также добавим здесь же макрос для задания желаемого IP-адреса для нашего устройства
void net_poll(void);
//——————————————
#define IP_ADDR ip_join(192,168,1,193)
Вообщем, на данный момент адрес у нас будет статический. Может мы когда-то и дойдём до запроса DHCP к серверу для получения динамического адреса, но пока нам точно до этого далеко.
Вернёмся в файл реализации функций net.c и добавим в нашу функцию ряд условий для фильтрования лишних пакетов, не соответствующих нашим требований, правдо пока этот фильтр пустотелый, а также вернём результат
arp_msg_ptr *msg = (void*)(frame->data);
if(len >= sizeof(arp_msg_ptr))
{
if( (msg->net_tp == ARP_ETH) && (msg->proto_tp == ARP_IP) )
{
if( (msg->op == ARP_REQUEST) && (msg->ipaddr_dst == IP_ADDR) )
{
}
}
}
return res;
Вообщем здесь мы хотим работать только с пакетом типа ARP, причём именно с запросом, и также убираем то, что не соответствует нашему сетевому адресу.
В следующей части нашего урока мы напишем ещё две нужные функции и код для отображения некоторых частей заголовка ARP-запроса.
Предыдущая часть Программирование МК AVR Следующая часть
Техническая документация:
Документация на микросхему ENC28J60
Перечень ошибок ENC28J60 (Errata)
Приобрести плату Atmega 328p Pro Mini можно здесь.
Приобрести программатор USBASP USBISP с адаптером можно здесь USBASP USBISP 3.3 с адаптером
Ethernet LAN Сетевой Модуль можно купить здесь ENC28J60 Ethernet LAN Сетевой Модуль.
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добавить комментарий