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 2.0

Ethernet LAN Сетевой Модуль можно купить здесь (модуль SD SPI в подарок) ENC28J60 Ethernet LAN Сетевой Модуль.

 

 

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

 

AVR LAN. ENC28J60

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

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

*