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 можно приобрести здесь STM32F103C8T6

Программатор недорогой можно купить здесь ST-Link V2

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

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

 

 

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

STM LAN. ENC28J60

 

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

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 не будет опубликован. Обязательные поля помечены *

*