STM Урок 68. LAN. ENC28J60. Часть 9



 

Урок 68

 

Часть 9

 

LAN. ENC28J60

 

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

 

Добавим в функцию чтения IP-пакета фильтрацию по версии протокола, длине заголовка и соответствию адреса получателя нашему IP, и вернём результат

 

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

  if((ip_pkt->verlen==0x45)&&(!memcmp(ip_pkt->ipaddr_dst,ipaddr,4)))

  {

  }

  return res;

}

 

Вычислим размер данных в байтах

 

if((ip_pkt->verlen==0x45)&&(!memcmp(ip_pkt->ipaddr_dst,ipaddr,4)))

{

  //длина данных

  len = be16toword(ip_pkt->len) - sizeof(ip_pkt_ptr);

 

Сравним контрольную сумму из поля контрольной суммой с расчитанной нами пока в текстовом виде

 

len = be16toword(ip_pkt->len) - sizeof(ip_pkt_ptr);

sprintf(str1,"rnip_cs 0x%04Xrn", ip_pkt->cs);

HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);

ip_pkt->cs=0;

sprintf(str1,"ip_cs 0x%04Xrn", checksum((void*)ip_pkt,sizeof(ip_pkt_ptr)));

HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);

 

Вызовем нашу функцию в функции eth_read

 

else if(frame->type==ETH_IP)

{

  ...

  ip_read(frame,len-sizeof(ip_pkt_ptr));

}

 

Соберём код, прошьём контроллер и сверим пришедшую и расчитанную контрольную сумму опять с помощью утилиты ping

 

image38

 

Всё сходится. Отлично!

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

 

sprintf(str1,"rnip_cs 0x%04Xrn", ip_pkt->cs);

HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);

ip_pkt->cs=0;

sprintf(str1,"ip_cs 0x%04Xrn", checksum((void*)ip_pkt,sizeof(ip_pkt_ptr)));

HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);

 

 

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

 

len = be16toword(ip_pkt->len) - sizeof(ip_pkt_ptr);

if (ip_pkt->prt==IP_ICMP)

{

}

else if (ip_pkt->prt==IP_TCP)

{

}

else if (ip_pkt->prt==IP_UDP)

{

}

 

Добавим функцию чтения ICMP-пакета

 

//--------------------------------------------------

uint8_t icmp_read(enc28j60_frame_ptr *frame, uint16_t len)

{

}

//--------------------------------------------------

 

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

 

if (ip_pkt->prt==IP_ICMP)

{

  icmp_read(frame,len);

}

 

Теперь разберёмся с пакетами 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

 

image39

 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

} ip_pkt_ptr;

//--------------------------------------------------

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,"icmp requestrn");

  HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);

}

 

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

 

image40

 

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

 

HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);

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;

}

//--------------------------------------------------

 

В следующей части нашего урока мы закончим работу над ответом на пинг нашего модуля ENC28J60.

 

 

Предыдущая часть Программирование МК STM32 Следующая часть

 

 

Техническая документация:

Документация на микросхему ENC28J60

Перечень ошибок ENC28J60 (Errata)

 

 

Отладочную плату можно приобрести здесь STM32F103C8T6

Ethernet LAN Сетевой Модуль можно купить здесь ENC28J60 Ethernet LAN

Переходник USB to TTL можно приобрести здесь USB to TTL ftdi ft232rl

 

 

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

 

STM LAN. ENC28J60

 

3 комментария на “STM Урок 68. LAN. ENC28J60. Часть 9
  1. Pavel:

    Уважаемый автор, я перелопатил ваши коды и запустил UDP в оба направления. Если интересно, свяжитесь со мной, можем довести проект до логического завершения. Я пока TCP буду делать.
    С уважением, Павел
    pasha-net@narod.ru

  2. Valerii:

    Здравствуйте
    Дошел по вашим видео до этого урока, контроллер выводит два сообщенияв терминал и виснет. Контрольную сумму не выводит.Прошу выслать код урока 68.8 по возможности на почту bob_vz@маил.ру или ссылку на скачку.
    потратил куча времени а код не работает, нужно разобраться где проблема в желези или коде.
    еще кеил подчеркивеет enc28j60_packetReceive и другие функции с ошибкой ( declared implicitly)писал код по урокам
    помогите разобраться.
    почему у вас нет кодов к урокам ?

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

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

*