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



 

Урок 40

 

Часть 10

 

LAN. ENC28J60

 

В предыдущей части нашего урока мы написали функцию расчета контрольной суммы, а также написали функцию чтения IP-пакетов.

 

Теперь разберёмся с пакетами ICMP.

В функции ip_read мы всё же добавим переменную для результата и вернём его, так сказать, на будущее

 

uint8_t icmp_read(enc28j60_frame_ptr *frame, uint16_t len)

{

  uint8_t res = 0;

  return res;

}

 

Поставим в этой функции пока указатель на пакет IP

 

uint8_t res = 0;

ip_pkt_ptr *ip_pkt = (void*)frame->data;

 

Вот формат заголовка ICMP

 

image12

 

Существует несколько типов сообщений ICMP:

0 — эхо-ответ,

3 — узел назначения недостижим,

5 — перенаправление маршрута,

8 — эхо-запрос,

9 — сообщение о маршрутизаторе,

10 — запрос сообщения о маршрутизаторе,

11 — истечение жизни пакета,

12 — проблемы с параметрами,

13 — запрос отметки времени,

14 — ответ отметки времени.

 

 

Из всего данного разнообразия сообщений нам пока будут нужны 2 — это эхо-ответ (0) и эхо-запрос (8), которые используются при работе утилиты ping.

Код пакета в случаях эхо-запросов и ответов — 0. В других случаях будут другие коды, но мы их в рамках нашего занятия пока не рассматривает.

Контрольная сумма пакета рассчитывается так же как и в случае IP, но не совсем так. В контрольную сумму включается весь пакет вместе с данными.

Следующие 2 поля устанавливаются хостом, и поэтому ими мы также не заморачиваемся. Их в эхо-ответе оставляют такими же как и пришли.

В поле данных как правило тестовый набор байтов, который должен возвратиться также неизменным.

Также ICMP-пакеты используются при диагностике маршрутов в трассировке.

В заголовочном файле net.h добавим структуру для заголовка icmp-пакета

 

//——————————————

typedef struct icmp_pkt {

uint8_t msg_tp; //тип сообщения

uint8_t msg_cd; //код сообщения

uint16_t cs; //контрольная сумма заголовка

uint16_t id; //идентификатор пакета

uint16_t num; //номер пакета

uint8_t data[]; //данные

} icmp_pkt_ptr;

//——————————————

 

Также добавим типы сообщений

 

#define IP_UDP 17

//——————————————

#define ICMP_REQ 8

#define ICMP_REPLY 0

 

В функции icmp_read в файле net.c установим указатель на пакет ICMP

 

ip_pkt_ptr *ip_pkt = (void*)frame->data;

icmp_pkt_ptr *icmp_pkt = (void*)ip_pkt->data;

 

Отфильтруем пакет по длине и типу сообщения — эхо-запрос

 

icmp_pkt_ptr *icmp_pkt = (void*)ip_pkt->data;

//Отфильтруем пакет по длине и типу сообщения — эхо-запрос

if((len >= sizeof(icmp_pkt_ptr)) && (icmp_pkt->msg_tp == ICMP_REQ))

{

}

 

 

Выведем сообщение в терминальной программе, что у нас именно такой запрос

 

if((len >= sizeof(icmp_pkt_ptr)) && (icmp_pkt->msg_tp == ICMP_REQ))

{

  sprintf(str1,«ipcmp requestrn»);

  USART_TX((uint8_t*)str1,strlen(str1));

}

 

Соберём код, прошьём контроллер и посмотрим результат

 

image13

 

Попробуем ответить. Заменим тип сообщения запрос на ответ

 

USART_TX((uint8_t*)str1,strlen(str1));

icmp_pkt->msg_tp = ICMP_REPLY;

 

Посчитаем контрольную сумму

 

icmp_pkt->msg_tp = ICMP_REPLY;

icmp_pkt->cs=0;

icmp_pkt->cs=checksum((void*)icmp_pkt,len)

 

Теперь напишем функцию отправки IP-пакета, так как отдельная функция для отправки ICMP-пакета нам не нужна, ибо мы его уже сформировали. Заготовка функции подобна функции отправки пакета

 

//———————————————————

uint8_t ip_send(enc28j60_frame_ptr *frame, uint16_t len)

{

  uint8_t res = 0;

  return res;

}

//———————————————————

 

Вызовем данную функцию в функции icmp_read

 

  icmp_pkt->cs=checksum((void*)icmp_pkt,len);

  ip_send(frame,len+sizeof(ip_pkt_ptr));

}

 

Вернёмся теперь в функцию ip_send и установим указатель на пакет IP

 

uint8_t res = 0;

ip_pkt_ptr *ip_pkt = (void*)(frame->data);

 

Заполним заголовок IP

ip_pkt_ptr *ip_pkt = (void*)(frame->data);

// Заполним заголовок пакета IP

ip_pkt->len = be16toword(len);

ip_pkt->fl_frg_of = 0;

ip_pkt->ttl = 128;

ip_pkt->cs = 0;

ip_pkt->ipaddr_dst= ip_pkt->ipaddr_src;

ip_pkt->ipaddr_src = IP_ADDR;

ip_pkt->cs = checksum((void*)ip_pkt, sizeof(ip_pkt_ptr));

 

И отправим фрейм

 

ip_pkt->cs = checksum((void*)ip_pkt, sizeof(ip_pkt_ptr));

//отправим фрейм

eth_send(frame, len);

return res;

 

Соберём код. Прошьём контроллер. Посмотрим результат

 

image14

 

Всё работает!

Остальные протоколы мы поизучаем когда-нибудь позже, а то уже и так наше изучение затянулось. Возможно, будет UDP, TCP, DHCP.

А пока всем творческих успехов. Всем спасибо за внимание!

 

 

Предыдущая часть Программирование МК 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

4 комментария на “AVR Урок 40. LAN. ENC28J60. Часть 10
  1. Sergey:

    Если всё это освою — буду молодец.
    Автору большущая благодарность!!!
    Мне понравилась последовательность изложения материала.
    И удачи всем в этом очень нужном деле.

  2. Да большое спасибо ! Ваш проект сразу скомпилировался на Atmel Studio 7 и все взлетело (только на ардуино UNO). Даже толком не успел вникнуть в код….
    Все за один день.
    Рекомендую!
    Тут картинка как подключал : https://kkmspb.ru/development/microcontrollers/Ethernet/ENC28J60.php

  3. Иван:

    Всем привет! Подключаю ENC28J60 к Atmega328P, делаю всё по примеру, но у меня компьютер упорно не хочет видеть IP, который мы задаём в коде. Причем IP под другим номером определяется и пингуется, но он статический, а не динамический. Также на Terminal приходят пакеты IP и arp, а вот arprequest, mac_src, ip_src, mac_dst и ip scr упорно не приходят.
    Я уже даже просто скачал готовый проект (Который в описании к этому уроку) и перепрошил контроллер, результат тот же. Что я могу не так делать?
    p.s. Спасибо вам за ваши уроки!

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

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

*