AVR Урок 40. LAN. ENC28J60. Часть 6



 

Урок 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);

 

Соберём код и посмотрим

 

image01

 

Теперь мы уже наглядно видим, какой у нас протокол и кто прислал кадр.

Дальнейшая задача — прочитать структуру заголовка ARP, а это у нас уже следующий уровень — не канальный, а сетевой.

 

 

ARP (Address Resolution Protocol) или протокол разрешения адресов — это протокол, который служит для того, чтобы сетевое устройство могло определить чей-то физический адрес (MAC) по сетевому адресу (IP). Для этого устройство посылает широковещательный запрос (с адресом приёмника FF-FF-FF-FF-FF-FF, соостоящим из всех единиц), в котором спрашивает: «Какой физический адрес имеет устройство с таким-то IP-адресом?». Требуется это для того, чтобы устройства могли общаться по физическому уровню, который ничего не знает об IP-адресах. Поэтому устройство и отправляет такой запрос. Его получают все компьютеры (или какие-то другие устройства) в данной локальной сети, и устройство, узнавшее свой сетевой адрес, обязано отправить ответ.

Теперь разберём конкретно, как это делается. Структура заголовка ARP:

 

image08

 

Поэтому добавим структуру для заголовка 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 (нажмите на картинку)

AVR LAN. ENC28J60

 

Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)

AVR LAN. ENC28J60

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*