STM Урок 91. LAN. W5500. HTTP Server. Часть 3

 

Урок 91

 

Часть 3

 

LAN. W5500. HTTP Server

 

В предыдущей части урока мы написали функцию инициализации микросхемы, а также начали писать функцию приёма и обработки сетевых пакетов.

 

Так как мы сочиняем сервер HTTP, то давайте всю работу с данным протоколом вынесем в отдельный модуль для чего создадим файлы httpd.h и httpd.c следующего содержания

 

httpd.h

#ifndef HTTPD_H_

#define HTTPD_H_

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

#include "stm32f4xx_hal.h"

#include <string.h>

#include <stdlib.h>

#include <stdint.h>

#include "fatfs.h"

#include "w5500.h"

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

#endif /* HTTPD_H_ */

 

httpd.c

#include "httpd.h"

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

extern UART_HandleTypeDef huart2;

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

extern char str1[60];

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

 

Также подключим данную библиотеку в файле w5500.h в самом низу файла

 

void w5500_packetReceive(void);

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

#include "httpd.h"

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

 

В файле httpd.h добавим структуру для свойств пакета HTTP, а также макросы для типов документов

 

#include "w5500.h"

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

typedef struct http_sock_prop {

volatile uint8_t data_stat;//статус передачи данных

volatile uint32_t data_size;//размер данных для передачи

volatile uint16_t last_data_part_size;//размер последней части данных для передачи

volatile uint16_t cnt_data_part;//общее количество частей данных для передачи

volatile uint16_t cnt_rem_data_part;//количество оставшихся частей данных для передачи

volatile uint32_t total_count_bytes;//количество переданных байтов документа

volatile uint8_t http_doc;//вариант документа для передачи

volatile uint8_t prt_tp;//вариант документа для передачи

char fname[20];//имя файла (документа)

} http_sock_prop_ptr;

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

//Варианты документов HTTP

#define EXISTING_HTML 0

#define E404_HTML 1

#define EXISTING_JPG 2

#define EXISTING_ICO 3

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

 

В файле httpd.c добавим переменную нашей структуры, а также подключим структуру свойств TCP

 

extern char str1[60];

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

http_sock_prop_ptr httpsockprop[2];

extern tcp_prop_ptr tcpprop;

 

В файле w5500.c подключим также переменную структуры свойств HTTP

 

tcp_prop_ptr tcpprop;

extern http_sock_prop_ptr httpsockprop[2];

 

В файле w5500.h добавим макроподстановки для состояний передачи данных

 

} tcp_prop_ptr;

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

//Статусы передачи данных

#define DATA_COMPLETED 0 //передача данных закончена

#define DATA_ONE 1 //передаём единственный пакет

#define DATA_FIRST 2 //передаём первый пакет

#define DATA_MIDDLE 3 //передаём средний пакет

#define DATA_LAST 4 //передаём последний пакет

#define DATA_END 5 //закрываем соединение после передачи данных

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

 

В файле w5500.c в функции приёма пакета в теле нашего условия состояния сокета добавим ещё одно условие состояния передачи данных

 

if(GetSocketStatus(tcpprop.cur_sock)==SOCK_ESTABLISHED)

{

  if(httpsockprop[tcpprop.cur_sock].data_stat == DATA_COMPLETED)

  {

  }

}

 

В теле данного условия мы будем принимать запрос HTTP при условии, что данные от нас все переданы. И, так как макрос данного состояния у нас имеет значение 0, то инициализировать состояние при старте программы нам не нужно и мы сразу же войдём в тело данного условия.

Над функцией инициализации добавим новую функцию определения размера принятых данных в TCP-пакете, используя для этого специальный регистр сокета

 

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

uint16_t GetSizeRX(uint8_t sock_num)

{

  uint16_t len;

  uint8_t opcode=0;

  opcode = (((sock_num<<2)|BSB_S0)<<3)|OM_FDM1;

  len = (w5500_readReg(opcode,Sn_RX_RSR0)<<8|w5500_readReg(opcode,Sn_RX_RSR1));

  return len;

}

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

 

Далее в теле уже нового условия мы узнаем размер принятых данных, отобразим его в терминальной программе, и если он будет нулевой, то есть никаких данных в TCP-пакете нет, то мы выходим из функции

 

if(httpsockprop[tcpprop.cur_sock].data_stat == DATA_COMPLETED)

{

  //Отобразим размер принятых данных

  len = GetSizeRX(0);

  sprintf(str1,"len_rx_buf:0x%04Xrn",len);

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

  //Если пришел пустой пакет, то уходим из функции

  if(!len) return;

}

 

Соберём код, прошьём контроллер и попробуем запросить любую страницу. Хотя, конечно, наш сервер пока никак не ответит, но мы хотя бы увидим, что пришел пакет определённой длины

 

image30

В терминальной программе мы видим бесконечно-поступающие данные с размером длины данных, то есть, пока мы данные не обработаем, мы так и будем попадать в это условие. причём это независимо, закроется ли или нет наше соединение

 

image31

 

Мы также видим в WareShark, что запрос от клиента был только один

 

image32

 

И прекратить этот «бесконечный цикл» удаётся только перезагрузкой контроллера.

Но хотя бы мы видим, что запрос к нам пришёл.

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

 

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

uint16_t GetReadPointer(uint8_t sock_num)

{

  uint16_t point;

  uint8_t opcode;

  opcode = (((sock_num<<2)|BSB_S0)<<3)|OM_FDM1;

  point = (w5500_readReg(opcode,Sn_RX_RD0)<<8|w5500_readReg(opcode,Sn_RX_RD1));

  return point;

}

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

 

Добавим для данной функции прототип. Он нам пригодится в другом модуле.

 

 

Давайте также в функции чтения и обработки сетевых пакетов узнаем адрес данных в буфере их приёма в теле того же условия, также отобразив его в терминальной программе

 

if(!len) return;

//здесь обмениваемся информацией: на запрос документа от клиента отправляем ему запрошенный документ

//указатель на начало чтения приёмного буфера

point = GetReadPointer(tcpprop.cur_sock);

sprintf(str1,"Sn_RX_RD:0x%04Xrn",point);

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

 

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

 

image33

 

Адрес у нас пока нулевой. Ну оно и понятно. Это самый первый запрос и он не обработан. Поэтому адрес меняться пока не будет.

Добавим глобальный массив для временного буфера

 

extern char str1[60];

char tmpbuf[30];

 

В файле w5500.h добавим структуру для буфера передачи

 

} tcp_prop_ptr;

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

typedef struct data_sect {

  volatile uint16_t addr;

  volatile uint8_t opcode;

  uint8_t data[];

} data_sect_ptr;

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

 

Также добавим макросы для вариантов протоколов TCP. Пока их будет только два — неизвестный и HTTP

 

#define DATA_END 5 //закрываем соединение после передачи данных

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

//Варианты протоколов TCP

#define PRT_TCP_UNCNOWN 0

#define PRT_TCP_HTTP 1

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

 

Вернёмся в файл w5500.c и после функции чтения регистра добавим ещё несколько функций чтения

 

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

void w5500_readBuf(data_sect_ptr *datasect, uint16_t len)

{

  SS_SELECT();

  HAL_SPI_Transmit(&hspi1, (uint8_t*) datasect, 3, 0xFFFFFFFF);

  HAL_SPI_Receive(&hspi1, (uint8_t*) datasect, len, 0xFFFFFFFF);

  SS_DESELECT();

}

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

uint8_t w5500_readSockBufByte(uint8_t sock_num, uint16_t point)

{

  uint8_t opcode, bt;

  opcode = (((sock_num<<2)|BSB_S0_RX)<<3)|OM_FDM1;

  bt = w5500_readReg(opcode, point);

  return bt;

}

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

void w5500_readSockBuf(uint8_t sock_num, uint16_t point, uint8_t *buf, uint16_t len)

{

  data_sect_ptr *datasect = (void*)buf;

  datasect->opcode = (((sock_num<<2)|BSB_S0_RX)<<3)|OM_FDM0;

  datasect->addr = be16toword(point);

  w5500_readBuf(datasect,len);

}

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

 

Первая из этих функций читает из буфера, используя метод чтения данных переменной длины, Вторая — читает один байт из буфера определённого сокета, а третья — несколько байт из определённого сокета.

На вторую функцию — w5500_readSockBufByte — добавим прототип в заголовочном файле.

Теперь в функции чтения и обработки сетевых пакетов добавим ещё код в наше условие, который будет определять, что это именно запрос HTTP

 

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

w5500_readSockBuf(tcpprop.cur_sock, point, (uint8_t*)tmpbuf, 5);

if (strncmp(tmpbuf,"GET /", 5) == 0)

{

  HAL_UART_Transmit(&huart2,(uint8_t*)"HTTPrn",6,0x1000);

  httpsockprop[tcpprop.cur_sock].prt_tp = PRT_TCP_HTTP;

}

 

При совпадении строк мы отобразим аббревиатуру «HTTP» в терминальной программе, а также инициализируем поле структуры определённым протоколом.

 

 

В файле httpd.c добавим функцию ответа на запрос HTTP, в котором найдём адрес вхождения символа «/«

 

extern tcp_prop_ptr tcpprop;

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

void http_request(void)

{

  uint16_t point;

  uint8_t RXbyte;

  uint16_t i=0;

  char *ss1;

  int ch1='.';

 

  // ищем первый "/" в HTTP заголовке

  point = GetReadPointer(tcpprop.cur_sock);

  i = 0;

  while (RXbyte != (uint8_t)'/')

  {

    RXbyte = w5500_readSockBufByte(tcpprop.cur_sock,point+i);

    i++;

  }

}

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

 

 

Создадим для данной функции прототип и вызовем её в функции чтения пакета в нашем условии в файле w5500.c

 

httpsockprop[tcpprop.cur_sock].prt_tp = PRT_TCP_HTTP;

http_request();

 

Чтобы в дальнейшем нам не запутаться в местах добавления условий, давайте выйдем сразу из тел двух условий и добавим ещё два условия заранее

 

        http_request();

      }

    }

    else if(httpsockprop[tcpprop.cur_sock].data_stat==DATA_MIDDLE)

    {

      if(httpsockprop[tcpprop.cur_sock].prt_tp == PRT_TCP_HTTP)

      {

      }

    }

    else if(httpsockprop[tcpprop.cur_sock].data_stat==DATA_LAST)

    {

      if(httpsockprop[tcpprop.cur_sock].prt_tp == PRT_TCP_HTTP)

      {

      }

    }

  }

}

 

Данные условия будут срабатывать, если будет установлен один из статусов передачи — передача среднего пакета и или передача последнего пакета данных. Аналогично мы работали с пакетами в уроках по протоколу HTTP с модулем enc28j60.

В файле httpd.c подключим временный буфер

 

extern char str1[60];

extern char tmpbuf[30];

 

Продолжим писать функцию ответа на запрос HTTP.

Считаем следующий символ после слеша и, если будет пробел — то это запрос главной страницы. Установим соответствующий тип документа в поле структуры

 

  i++;

}

point+=i;

RXbyte = w5500_readSockBufByte(tcpprop.cur_sock,point);

if(RXbyte==(uint8_t)' ')

{

  strcpy(httpsockprop[tcpprop.cur_sock].fname,"index.htm");

  httpsockprop[tcpprop.cur_sock].http_doc = EXISTING_HTML;

}

else

{

}

 

Напишем тело условия, работающее в противном случае

 

else

{

  // ищем следующий пробел (" ") в HTTP заголовке, таким образом считывая имя документа из запроса

  i=0;

  while (1)

  {

    tmpbuf[i] = w5500_readSockBufByte(tcpprop.cur_sock, point+i);

    if(tmpbuf[i] == (uint8_t)' ') break;

    i++;

  }

  tmpbuf[i] = 0; //закончим строку

  strcpy(httpsockprop[tcpprop.cur_sock].fname,tmpbuf);

}

 

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

Продолжаем функцию дальше. Отобразим имя файла, которое запросил клиент, в терминальной программе

 

  strcpy(httpsockprop[tcpprop.cur_sock].fname,tmpbuf);

}

HAL_UART_Transmit(&huart2,(uint8_t*)httpsockprop[tcpprop.cur_sock].fname,strlen(httpsockprop[tcpprop.cur_sock].fname),0x1000);

HAL_UART_Transmit(&huart2,(uint8_t*)"rn",2,0x1000);

 

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

 

image34  image35

 

Всё нормально читается.

Теперь в файле main.c добавим некоторые глобальные переменные для работы с файловой системой, а также подключим строковый массив

 

/* Private variables ---------------------------------------------------------*/

extern char SDPath[4]; /* logical drive path */

FATFS SDFatFs;//указатель на объект

extern char str1[60];

/* USER CODE END PV */

 

В функции main() также добавим локальную переменную для результата

 

/* USER CODE BEGIN 1 */

FRESULT result; //результат выполнения

/* USER CODE END 1 */

 

В этой же функции примонтируем наш носитель на карте SD и отобразим результат в терминальной программе

 

/* USER CODE BEGIN 2 */

result=f_mount(&SDFatFs,(TCHAR const*)SDPath,0);

sprintf(str1,"f_mount: %drn",result);

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

net_ini();

 

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

 

image36

 

Всё нормально примонтировалось.

Вернёмся в файл httpd.c и добавим необходимые глобальные переменные для работы с файловой системой

 

extern tcp_prop_ptr tcpprop;

FIL MyFile;

FRESULT result; //результат выполнения

uint32_t bytesread;

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

 

Продолжим нашу функцию ответа на запрос HTTP.

Откроем требуемый файл с карты и узнаем его размер. Также покажем это в терминальной программе

 

HAL_UART_Transmit(&huart2,(uint8_t*)"rn",2,0x1000);

f_close(&MyFile);

result=f_open(&MyFile,httpsockprop[tcpprop.cur_sock].fname,FA_READ); //Попытка открыть файл

sprintf(str1,"f_open: %drn",result);

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

sprintf(str1,"f_size: %lurn",MyFile.fsize);

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

 

Прежде чем открыть файл, мы закрываем предыдущий. Можно это делать и в других местах, но у меня лучше всего работает именно так.

Опять соберём проект, прошьём контроллер и попробуем запросить какой-ниубдь существующий документ

 

image37

 

Размер определяется нормально.

Я создал несколько страниц html различного размера, чтобы протестировать наш проект с запросом документов, состоящих из разного количества пакетов.

Добавим несколько типов заголовков HTTP для ответа в виде голобальных массивов, а также массив со страницей, передаваемой в случае отстуствия запрашиваемого документа

 

uint32_t bytesread;

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

const char http_header[] = { "HTTP/1.1 200 OKrnContent-Type: text/htmlrnrn"};

const char jpg_header[] = {"HTTP/1.0 200 OKrnServer: nginxrnContent-Type: image/jpegrnConnection: closernrn"};

const char icon_header[] = { "HTTP/1.1 200 OKrnContent-Type: image/x-iconrnrn"};

const char error_header[] = {"HTTP/1.0 404 File not foundrnServer: nginxrnContent-Type: text/htmlrnConnection: closernrn"};

char *header;

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

const uint8_t e404_htm[] = {

0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0a,0x20,0x20,0x3c,0x68,0x65,0x61,0x64,0x3e,0x0a,

0x20,0x20,0x20,0x20,0x3c,0x74,0x69,0x74,0x6c,0x65,0x3e,0x34,0x30,0x34,0x20,0x4e,

0x6f,0x74,0x20,0x46,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,

0x0a,0x20,0x20,0x3c,0x2f,0x68,0x65,0x61,0x64,0x3e,0x0a,0x3c,0x62,0x6f,0x64,0x79,

0x3e,0x0a,0x3c,0x68,0x31,0x20,0x73,0x74,0x79,0x6c,0x65,0x3d,0x22,0x74,0x65,0x78,

0x74,0x2d,0x61,0x6c,0x69,0x67,0x6e,0x3a,0x20,0x63,0x65,0x6e,0x74,0x65,0x72,0x3b,

0x22,0x3e,0x34,0x30,0x34,0x20,0x45,0x72,0x72,0x6f,0x72,0x20,0x46,0x69,0x6c,0x65,

0x20,0x4e,0x6f,0x74,0x20,0x46,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x31,0x3e,0x0a,

0x3c,0x68,0x32,0x20,0x73,0x74,0x79,0x6c,0x65,0x3d,0x22,0x74,0x65,0x78,0x74,0x2d,

0x61,0x6c,0x69,0x67,0x6e,0x3a,0x20,0x63,0x65,0x6e,0x74,0x65,0x72,0x3b,0x22,0x3e,

0x20,0x54,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,

0x65,0x20,0x6c,0x6f,0x6f,0x6b,0x69,0x6e,0x67,0x20,0x66,0x6f,0x72,0x20,0x6d,0x69,

0x67,0x68,0x74,0x20,0x68,0x61,0x76,0x65,0x20,0x62,0x65,0x65,0x6e,0x20,0x72,0x65,

0x6d,0x6f,0x76,0x65,0x64,0x2c,0x20,0x3c,0x62,0x72,0x20,0x2f,0x3e,0x68,0x61,0x64,

0x20,0x69,0x74,0x73,0x20,0x6e,0x61,0x6d,0x65,0x20,0x63,0x68,0x61,0x6e,0x67,0x65,

0x64,0x2c,0x20,0x6f,0x72,0x20,0x69,0x73,0x20,0x74,0x65,0x6d,0x70,0x6f,0x72,0x61,

0x72,0x69,0x6c,0x79,0x20,0x75,0x6e,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,

0x2e,0x3c,0x2f,0x68,0x32,0x3e,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x3c,0x2f,

0x68,0x74,0x6d,0x6c,0x3e};

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

 

Продолжаем писать нашу функцию ответа на запрос HTTP. Если документ открылся, то мы изучим его расширение и выставим необходимый статус, а если нет, то установим статус ошибки существования документа на сервере. Также подсчитаем заранее длину ответа HTTP для того, чтобы определить потом, во сколько пакетов и окон он уместится

 

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

if (result==FR_OK)

{

  //изучим расширение файла

  ss1 = strchr(httpsockprop[tcpprop.cur_sock].fname,ch1);

  ss1++;

  if (strncmp(ss1,"jpg", 3) == 0)

  {

    httpsockprop[tcpprop.cur_sock].http_doc = EXISTING_JPG;

    //сначала включаем в размер размер заголовка

    httpsockprop[tcpprop.cur_sock].data_size = strlen(jpg_header);

  }

  if (strncmp(ss1,"ico", 3) == 0)

  {

    httpsockprop[tcpprop.cur_sock].http_doc = EXISTING_ICO;

    //сначала включаем в размер размер заголовка

    httpsockprop[tcpprop.cur_sock].data_size = strlen(icon_header);

  }

  else

  {

    httpsockprop[tcpprop.cur_sock].http_doc = EXISTING_HTML;

    //сначала включаем в размер размер заголовка

    httpsockprop[tcpprop.cur_sock].data_size = strlen(http_header);

  }

  //затем размер самого документа

  httpsockprop[tcpprop.cur_sock].data_size += MyFile.fsize;

}

else

{

  httpsockprop[tcpprop.cur_sock].http_doc = E404_HTML;

  //сначала включаем в размер размер заголовка

  httpsockprop[tcpprop.cur_sock].data_size = strlen(error_header);

  //затем размер самого документа

  httpsockprop[tcpprop.cur_sock].data_size += sizeof(e404_htm);

}

 

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

 

 

 

 

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

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

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

 

 

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

STM LAN. W5500. HTTP Server

 

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

STM LAN. W5500. HTTP Server

8 комментариев к “STM Урок 91. LAN. W5500. HTTP Server. Часть 3

  1. Здравствуйте.

    Откуда поле "MyFile.fsize"?

    Тип: FIL <C:\…\STM32Cube_FW_F4_V1.17.0\Middlewares\Third_Party\FatFs\src\ff.h>

    typedef struct {
        _FDID    obj;            /* Object identifier (must be the 1st member to detect invalid object pointer) */
        BYTE    flag;            /* File status flags */
        BYTE    err;            /* Abort flag (error code) */
        FSIZE_t    fptr;            /* File read/write pointer (Zeroed on file open) */
        DWORD    clust;            /* Current cluster of fpter (invalid when fptr is 0) */
        DWORD    sect;            /* Sector number appearing in buf[] (0:invalid) */
    #if !_FS_READONLY
        DWORD    dir_sect;        /* Sector number containing the directory entry */
        BYTE*    dir_ptr;        /* Pointer to the directory entry in the win[] */
    #endif
    #if _USE_FASTSEEK
        DWORD*    cltbl;            /* Pointer to the cluster link map table (nulled on open, set by application) */
    #endif
    #if !_FS_TINY
        BYTE    buf[_MAX_SS];    /* File private data read/write window */
    #endif
    } FIL;

    • А вот и ответ нашелся.

      В новой версии библиотеки ввели #define f_size(fp) ((fp)->obj.objsize)

      Спасибо автору за очень полезную работу.

    • Оттуда, что Вы, видимо обновили версию Cube MX, чего не в коем случае делать на нужно, не сохранив перед этим дистрибутив предыдущей версии.

      В новой версии 4.23 был добавлен новый релиз библиотеки FATFS, который кардинально отличается от предыдущего, и, по всей видимости он ещё не адаптирован нормально к библиотеке HAL. Размер можно померить и по-другому, но если Вы уберёте вообще эти строки с размерами, то Вы увидите, что файлы у Вас вообще не открываются. Это происходит потому, что в новой библиотеке FATFS сначала происходит определение статуса диска, а только потом его инициализации, а как известно именно в инициализации диска происходит инициализация самой шины. То есть шина у нас неинициализирована, а мы уже туда какие-то команды подаём. Можете проверить логическим анализатором, что у Вас вообще нет никакого обмена по шине SDIO. Так что откатывайтесь на 4.22.1 и работайте с этим уроком. Так как там прикручена такая библиотека FATFS, где у структуры FIL есть поле с размером.

  2. дошел до открытия страницы в браузере и посылки запроса через адресную строку.
    1. Комп посылает данные на порт 443. почему так?
    2. Не понял в какой момент МК попадает ф функцию w5500_packetReceive? Вроде все по шагам, согласно тексту делал. Добывил вызов этой функции в главном теле main.c, что-то заработало, порт поменял в программе на тот по которому стучит комп — 443.
    3. стучусь по 192.168.0.2/1 в wireshark вижу отправляет len=1, but in terminal I see.. а в терминале вижу 0x0205 ааа??!!!, пойду возьму бубен…

    sprintf(str1,»Sn_RX_RD:0x%04Xrn»,point); не надо ли тут слеши? /r/n

    • и в терминал выводит len_rx_buf:0x 0205 только один раз и все, даже если еще раз в браузере зайти. повторно отправка идет вижу в Wireshare, длину не выводит в терминал

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

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

*