Implementação de PPPOS no stm32f4-discovery

Uma vez, antes de mim, havia uma tarefa para fornecer acesso à Internet no STM32, tendo para isso apenas uma porta COM. Para resolver esse problema, eu precisava do PPP, ou, para ser mais preciso, do PPPoS (Protocolo Ponto a Ponto sobre Serial - uma das maneiras de implementar o PPP, ele é usado na conexão via porta COM).

No processo de resolução da tarefa que me foi apresentada, encontrei algumas dificuldades, uma das quais, na minha opinião, era uma cobertura insuficiente de questões relacionadas ao PPPoS na Internet. Com este post, tentarei preencher a lacuna designada, tanto quanto meu conhecimento modesto permitir.

Este artigo descreve como criar um projeto para o System Workbench for STM32 do zero. Mostra um exemplo de trabalho com o UART. Existem exemplos de código para implementar o PPP. E, claro, um exemplo de envio de uma mensagem para um computador vizinho.

1. Introdução


O PPP (Protocolo ponto a ponto) é um protocolo de link de dados de dois pontos do modelo de rede OSI. Geralmente é usado para estabelecer comunicação direta entre dois nós da rede e pode fornecer autenticação de conexão, criptografia e compactação de dados. Usado em muitos tipos de redes físicas: cabo de modem nulo, linha telefônica, celular, etc.

Frequentemente, existem subespécies do protocolo PPP, como o protocolo ponto a ponto pela Ethernet (PPPoE), usado para conectar via Ethernet e, às vezes, por DSL; e Protocolo ponto a ponto sobre ATM (PPPoA), usado para conexão via ATM Adaptation Layer 5 (AAL5), que é a principal alternativa de PPPoE para DSL.

O PPP é uma família de protocolos: Protocolo de Controle de Link (LCP), Protocolo de Controle de Rede (NCP), Protocolos de Autenticação (PAP, CHAP), PPP Multicanal (MLPPP).

Da Wikipedia .

Preparação


Para resolver o problema, precisamos:

Ferro:


  1. Placa de depuração stm32f4_discovery:

  2. Adaptador USB para miniUSB para conectar a placa a um computador.
  3. Dois adaptadores USBtoUART FT232:

  4. Dois cabos de extensão USB também são úteis, não necessariamente, mas apenas convenientes.

Suave:


  1. Máquina virtual VirtualBox. Você pode baixá-lo aqui . Também baixamos e instalamos o Extension Pack for VirtualBox.
  2. Dois discos de instalação com os sistemas operacionais Windows e Linux. Nós levamos o Windows aqui , o Linux aqui .

    Depois de instalar o sistema operacional, você precisará instalar complementos para o sistema operacional convidado. Para a tarefa, temos sistemas 32x suficientes, você não pode se enganar com a inclusão da virtualização.
  3. Para o Windows, precisamos de um programa que possa aceitar solicitações e responder a elas via TCP / IP e um programa de terminal para trabalhar com uma porta COM. Faça o download do PacketSender aqui (clique em “Não, obrigado, deixe-me baixar.”), O terminal está aqui . Além disso, precisamos do STM32CubeMX para a configuração inicial do projeto. Download em st.com (após o registro, o link será enviado por e-mail).
  4. Colocamos o System Workbench for STM32 no sistema operacional principal. Baixe aqui (é necessário registro).

Etapa 1. Criando um Projeto


Primeiro, abra o STM32CubeMX e crie um novo projeto para a nossa placa stm32f4-discovery. Ligue RCC, Ethernet (ETH), SYS, USART2, USART3 e, em seguida, ligue FREERTOS e LWIP.




Para diagnósticos, precisamos de LEDs na placa. Para isso, configure as pernas do PD12-PD15 como GPIO_Output.



Na guia Configuração do relógio, defina a frequência, como na figura abaixo.



Em seguida, na guia Configuração, configure as portas USART. Vamos trabalhar com eles no modo DMA. Temos duas portas USART, uma que usaremos para transmitir e receber dados via PPP, a segunda para registro. Para fazê-los funcionar, precisamos configurar o DMA no RX e TX para ambas as portas. Para todas as pernas de ajuste do DMA, defina Médio como prioridade. Para a perna USART2 RX, defina o modo para "Circular". O restante das configurações são deixadas por padrão.



Você também precisará ativar a interrupção global para ambas as portas na guia “NVIC Settings”.

Isso conclui a configuração inicial do projeto no STM32CubeMX. Salvamos o arquivo do projeto e geramos o código para o System Workbench for STM32.



Implementação


Agora vamos verificar se o código baixado é compilado e funciona. Para fazer isso, no arquivo main.c na função "StartDefaultTask", substituímos o corpo do loop infinito para (; ;;) pelo código de ativação e desativação do LED.

Deve ser assim:

/* StartDefaultTask function */ void StartDefaultTask(void const * argument) { /* init code for LWIP */ MX_LWIP_Init(); /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); } /* USER CODE END 5 */ } 

Nós compilamos o firmware e olhamos. Todos os quatro LEDs devem piscar no quadro.

Etapa 2. Trabalhar com USART


Nossa próxima tarefa é verificar a operação correta do nosso USART.

A primeira coisa que precisamos fazer é conectar nosso FT232 à descoberta. Para fazer isso, observe quais pernas as interfaces USART são divorciadas. Eu tenho PD6 e PD5 para USART2_RX e USART2_TX, respectivamente.



Assim como PD9 e PD8 para USART3_RX e USART3_TX, respectivamente.



Além disso, precisamos de um pé GND.

Nós encontramos esses pinos na placa e os conectamos aos pinos do FT232, enquanto o pino GND na placa pode ser qualquer, o pino RX na placa deve estar conectado ao pino TX no FT232 e o pino TX na placa deve estar conectado ao pino RX no FT232. As demais conclusões não são usadas.

Resta conectar o FT232 às portas USB do computador, bem como conectar a própria placa de descoberta através do conector miniUSB ao computador (não confunda com microUSB).

Após conectar o FT232, o sistema operacional principal instalará os drivers para eles, após o que esses dispositivos precisarão ser encaminhados ao convidado do Windows na máquina virtual.

Agora adicionamos o código do programa necessário para a operação do nosso USART. Para fazer isso, adicionaremos quatro arquivos: usart.h, usart.c, logger.h, logger.c.

Conteúdo do arquivo:

arquivo usart.h
 #ifndef _USART_ #define _USART_ #include "stm32f4xx_hal.h" void usart_Open(void); bool usart_Send(char* bArray, int size_bArray); uint16_t usart_Recv(char* bArray, uint16_t maxLength); #endif /* _USART_ */ 

arquivo usart.c
 #include "usart.h" #include "logger.h" #include "cmsis_os.h" #define Q_USART2_SIZE 200 xQueueHandle g_qUsart; osThreadId g_usart_rxTaskHandle; extern UART_HandleTypeDef huart2; void usart_rxTask(void); uint8_t bGet[Q_USART2_SIZE] = {0}; uint16_t g_tail = 0; void usart_Open(void) { g_qUsart = xQueueCreate( Q_USART2_SIZE, sizeof( unsigned char ) ); osThreadDef(usart_rxTask_NAME, usart_rxTask, osPriorityNormal, 0, Q_USART2_SIZE/4+128); g_usart_rxTaskHandle = osThreadCreate(osThread(usart_rxTask_NAME), NULL); HAL_UART_Receive_DMA(&huart2, bGet, Q_USART2_SIZE); } void usart_rxTask(void) { for(;;) { uint16_t length = Q_USART2_SIZE - huart2.hdmarx->Instance->NDTR; while(length - g_tail) { uint8_t tmp = bGet[g_tail]; xQueueSendToBack( g_qUsart, &tmp, 100 ); g_tail++; if (g_tail == Q_USART2_SIZE) g_tail = 0; } } } bool usart_Send(char* bArray, int size_bArray) { HAL_StatusTypeDef status; status = HAL_UART_Transmit_DMA(&huart2, bArray, size_bArray); while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY) { if (HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_RX) break; osDelay(1); } if (status == HAL_OK) return true; return false; } uint16_t usart_Recv(char* bArray, uint16_t maxLength) { uint8_t tmp = 0; uint16_t length = 0; while(uxQueueMessagesWaiting(g_qUsart)) { xQueueReceive( g_qUsart, &tmp, 100 ); bArray[length] = tmp; length++; if (length >= maxLength) break; } return length; } 

arquivo logger.h
 #ifndef _LOGGER_ #define _LOGGER_ void logger(const char *format, ...); #endif /* _LOGGER_ */ 

arquivo logger.c
 #include "logger.h" #include "stm32f4xx_hal.h" #include <stdarg.h> extern UART_HandleTypeDef huart3; #define MAX_STRING_SIZE 1024 HAL_StatusTypeDef logger_Send(char* bArray, uint32_t size_bArray) { HAL_StatusTypeDef status; for(int i=0;i<5;i++) { status = HAL_UART_Transmit_DMA(&huart3, bArray, size_bArray); if (status == HAL_OK) break; osDelay(2); } while (HAL_UART_GetState(&huart3) != HAL_UART_STATE_READY) { osDelay(1); } return status; } void logger(const char *format, ...) { char buffer[MAX_STRING_SIZE]; va_list args; va_start (args, format); vsprintf(buffer, format, args); va_end(args); buffer[MAX_STRING_SIZE-1]=0; logger_Send(buffer, strlen(buffer)); } 

Precisamos de arte para transmitir e receber dados sobre arte2. Será a nossa principal interface de comunicação com um servidor PPP.

Precisamos do Logger para implementar o log enviando mensagens para o terminal. A função void usart_Open (void) forma uma fila e inicia a tarefa de atender a essa fila. Esta função deve ser concluída antes de usar o USART. Então tudo é simples, a função bool usart_Send (char * bArray, int size_bArray) envia dados para a porta e
uint16_t usart_Recv (char * bArray, uint16_t maxLength) os obtém da fila na qual a função void usart_rxTask (void) os adicionou gentilmente.

Para o criador de logs, ainda é mais simples; não há necessidade de obter dados; portanto, nem a tarefa de manutenção da fila nem a fila são necessárias.

No início do arquivo main.h , você precisa adicionar várias definições que descrevem o tipo de bool, que não está disponível em C.

 /* USER CODE BEGIN Includes */ typedef unsigned char bool; #define true 1 #define false 0 /* USER CODE END Includes */ 

Agora é hora de verificar a funcionalidade do código resultante. Para fazer isso, no arquivo main.c , altere o código da tarefa já conhecida "StartDefaultTask"

 /* USER CODE BEGIN 4 */ #include "usart.h" #include "logger.h" #define MAX_MESSAGE_LENGTH 100 /* USER CODE END 4 */ /* StartDefaultTask function */ void StartDefaultTask(void const * argument) { /* init code for LWIP */ MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); /* Infinite loop */ uint8_t send[] = "Send message\r\n"; uint8_t recv[MAX_MESSAGE_LENGTH] = {0}; uint16_t recvLength = 0; for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); if (usart_Send(send, sizeof(send)-1)) logger("SEND - %s", send); recvLength = usart_Recv(recv, MAX_MESSAGE_LENGTH-1); if (recvLength) { recv[recvLength] = 0; logger("RECV - %s\r\n", recv); } } /* USER CODE END 5 */ } 

Além disso, precisamos dar mais memória à pilha de nossa tarefa. Para fazer isso, na chamada para a função osThreadDef (), o arquivo main.c, é necessário corrigir 128 por 128 * 10 para obter isso:

 osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, <b>128*10</b>); 

Nós compilamos e flash. Os LEDs piscam da mesma maneira que na tarefa anterior.

Para ver o resultado do nosso trabalho, você precisa executar o programa Terminal em nossa máquina virtual. Uma instância do programa para a porta de log, a segunda para a principal. Procure no gerenciador de dispositivos quais números de porta foram atribuídos ao seu FT232. Se os números tiverem sido atribuídos com mais de 10, reatribua.

Quando você inicia a segunda instância do programa, pode ocorrer um erro, feche a janela com o erro e continue trabalhando com o programa.

Para ambas as portas, estabelecemos uma conexão em 115200 baud, bits de dados - 8, paridade - nenhum, bits de parada - 1, handshake - nenhum.

Se você fez tudo corretamente, na janela do terminal para usart2 a mensagem "Enviar mensagem" será transmitida. A mesma mensagem será duplicada na janela do terminal para o logger apenas com o prefixo "SEND -"

Se na janela do terminal para usart2 você digitar algum texto no campo "Enviar" e clicar no botão correspondente à direita desse campo, na janela do logger você verá a mesma mensagem com o prefixo "RECV -"

Na figura abaixo: à esquerda está o logger, à direita está usart2.



Etapa 3. Introdução ao PPP


Como parte dessa tarefa, criaremos uma conexão PPP. Primeiro, habilite o uso do PPP, altere o valor do PPP_SUPPORT definido no arquivo ppp_opts.h para 1. Em seguida, redefinimos as definições necessárias no arquivo lwipopts.h,

 /* USER CODE BEGIN 1 */ #define MEMP_NUM_SYS_TIMEOUT 8 #define CHECKSUM_GEN_IP 1 #define CHECKSUM_GEN_TCP 1 /* USER CODE END 1 */ 

Ao mesmo tempo, as definições antigas precisam ser comentadas.

Agora, modificamos o arquivo lwip.c, insira o seguinte código no bloco "/ * USER CODE BEGIN 0 * /":

 /* USER CODE BEGIN 0 */ #include "usart.h" #include "pppos.h" #include "sio.h" #include "dns.h" #include "ppp.h" static ppp_pcb *ppp; struct netif pppos_netif; void PppGetTask(void const * argument) { uint8_t recv[2048]; uint16_t length = 0; for(;;) { length=usart_Recv(recv, 2048); if (length) { pppos_input(ppp, recv, length); logger("read - PppGetTask() len = %d\n", length); } osDelay(10); } } #include "ip4_addr.h" #include "dns.h" static void ppp_link_status_cb(ppp_pcb *pcb, int err_code, void *ctx) { struct netif *pppif = ppp_netif(pcb); LWIP_UNUSED_ARG(ctx); switch(err_code) { case PPPERR_NONE: /* No error. */ { logger("ppp_link_status_cb: PPPERR_NONE\n\r"); logger(" our_ip4addr = %s\n\r", ip4addr_ntoa(netif_ip4_addr(pppif))); logger(" his_ipaddr = %s\n\r", ip4addr_ntoa(netif_ip4_gw(pppif))); logger(" netmask = %s\n\r", ip4addr_ntoa(netif_ip4_netmask(pppif))); } break; case PPPERR_PARAM: /* Invalid parameter. */ logger("ppp_link_status_cb: PPPERR_PARAM\n"); break; case PPPERR_OPEN: /* Unable to open PPP session. */ logger("ppp_link_status_cb: PPPERR_OPEN\n"); break; case PPPERR_DEVICE: /* Invalid I/O device for PPP. */ logger("ppp_link_status_cb: PPPERR_DEVICE\n"); break; case PPPERR_ALLOC: /* Unable to allocate resources. */ logger("ppp_link_status_cb: PPPERR_ALLOC\n"); break; case PPPERR_USER: /* User interrupt. */ logger("ppp_link_status_cb: PPPERR_USER\n"); break; case PPPERR_CONNECT: /* Connection lost. */ logger("ppp_link_status_cb: PPPERR_CONNECT\n"); break; case PPPERR_AUTHFAIL: /* Failed authentication challenge. */ logger("ppp_link_status_cb: PPPERR_AUTHFAIL\n"); break; case PPPERR_PROTOCOL: /* Failed to meet protocol. */ logger("ppp_link_status_cb: PPPERR_PROTOCOL\n"); break; case PPPERR_PEERDEAD: /* Connection timeout. */ logger("ppp_link_status_cb: PPPERR_PEERDEAD\n"); break; case PPPERR_IDLETIMEOUT: /* Idle Timeout. */ logger("ppp_link_status_cb: PPPERR_IDLETIMEOUT\n"); break; case PPPERR_CONNECTTIME: /* PPPERR_CONNECTTIME. */ logger("ppp_link_status_cb: PPPERR_CONNECTTIME\n"); break; case PPPERR_LOOPBACK: /* Connection timeout. */ logger("ppp_link_status_cb: PPPERR_LOOPBACK\n"); break; default: logger("ppp_link_status_cb: unknown errCode %d\n", err_code); break; } } // Callback used by ppp connection static u32_t ppp_output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(ctx); if (len > 0) { if (!usart_Send(data, len)) return 0x05; } logger("write - ppp_output_cb() len = %d\n", len); return len; } void pppConnect(void) { ppp = pppos_create(&pppos_netif, ppp_output_cb, ppp_link_status_cb, NULL); ppp_set_default(ppp); osThreadId PppGetTaskHandle; osThreadDef(PPP_GET_TASK_NAME, PppGetTask, osPriorityNormal, 0, 128*10); PppGetTaskHandle = osThreadCreate(osThread(PPP_GET_TASK_NAME), NULL); err_t err = ppp_connect(ppp,0); if (err == ERR_ALREADY) { logger("Connected successfully"); } for(int i=0;i<40;i++) { osDelay(500); if (ppp->phase >= PPP_PHASE_RUNNING) break; } } /* USER CODE END 0 */ 

Então, na função MX_LWIP_Init (), no bloco “/ * USER CODE BEGIN 3 * /”, adicionamos uma chamada à função pppConnect ().

Além disso, você precisa aumentar o tamanho da pilha, para isso, no arquivo FreeRTOSConfig.h, você deve comentar a definição configTOTAL_HEAP_SIZE e, no final do arquivo, no bloco / * USER CODE BEGIN Define * / bloco, declare-o com um novo valor.

 /* USER CODE BEGIN Defines */ /* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ #define configTOTAL_HEAP_SIZE ((size_t)1024*30) /* USER CODE END Defines */ 

Além disso, no arquivo usart.c, altere o valor da definição Q_USART2_SIZE para 2048.

A configuração da conexão começa com a função MX_LWIP_Init (); foi criada automaticamente; apenas adicionamos uma chamada à função pppConnect (). Nesta função, as tarefas que atendem à conexão PPPOS são iniciadas. As funções pppos_create () precisam receber os endereços das funções que servirão para o envio de mensagens e a saída de informações sobre a alteração do status da conexão. Para nós, essas são as funções ppp_output_cb () e ppp_link_status_cb (), respectivamente. Além disso, a função pppConnect () iniciará a tarefa de atender às mensagens recebidas. No final de sua operação, a função pppConnect () aguardará o estabelecimento de uma conexão com o servidor e concluirá sua operação.

O trabalho com a rede será realizado em um nível superior, assim que o LWIP decidir que é necessário enviar uma mensagem para a rede, a função ppp_output_cb () será chamada automaticamente. A resposta da rede será recebida pela função PppGetTask (), como parte da tarefa de atender as mensagens recebidas, e transferida para as entranhas do LWIP. Se o status da conexão mudar, a função ppp_link_status_cb () será chamada automaticamente.

Por fim, modificaremos a tarefa StartDefaultTask. Agora deve ficar assim:

 void StartDefaultTask(void const * argument) { /* init code for LWIP */ // MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); MX_LWIP_Init(); /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); } /* USER CODE END 5 */ } 

Feito, você pode compilar e fazer o flash.

Neste ponto, você precisa iniciar o servidor PPP. Para fazer isso, você deve primeiro implantar uma máquina virtual com Linux. Eu usei o Ubuntu 16.04 x32. Depois de instalar o sistema operacional, você precisa configurar o uso da porta COM.

Nesta parte, não precisamos de uma máquina virtual com Windows, podemos desativá-la com segurança. Nós conectamos o FT232 no Linux.

No Linux, antes de começar a trabalhar com uma porta COM, é necessário permitir que o usuário a use. Para fazer isso, execute o seguinte comando:

 sudo addgroup USERNAME dialout 

onde USERNAME é o nome do usuário atual.

Para ver as portas disponíveis no sistema COM, você precisa executar o comando:

 dmesg | grep tty 



Vemos que existem duas portas ttyUSB no sistema. Não podemos dizer imediatamente qual é o logger e qual é o usart2. Você só precisa verificá-los por vez.

Primeiro, execute os comandos para ler de uma porta:

 stty -F /dev/ttyUSB0 115200 cat /dev/ttyUSB0 

depois de outro:

 stty -F /dev/ttyUSB1 115200 cat /dev/ttyUSB1 

Onde vemos essa imagem, isso é logger.



Você pode sair desta janela, isso não vai nos incomodar.

Em seguida, você precisa permitir que os pacotes enviados de nossa placa deixem os limites de suas sub-redes. Para fazer isso, configure o iptables. Realizamos as seguintes ações:

1. Abra uma nova janela do console
2. Você precisa descobrir o seu ip e o nome da interface de rede (execute o comando ifconfig )



3. Execute os comandos de configuração nat

 sudo echo 1 | sudo tee -a /proc/sys/net/ipv4/ip_forward > /dev/null sudo echo 1 | sudo tee -a /proc/sys/net/ipv4/ip_dynaddr > /dev/null sudo iptables -F FORWARD sudo iptables -F -t nat sudo iptables -t nat -A POSTROUTING -o enp0s3 -j SNAT --to-source 192.168.10.196 sudo iptables -t nat -L 

em que enp0s3 é o nome da interface de rede
192.168.10.196 - seu endereço IP
/ proc / sys / net / ipv4 / - caminho para o arquivo correspondente.

Esses comandos podem ser reescritos em um arquivo em lotes e executados sempre antes de iniciar o servidor PPP. Você pode adicioná-lo à execução automática, mas não o fiz.

Agora estamos prontos para iniciar o servidor, resta apenas criar um arquivo de configurações. Eu chamei de “ pppd.conf ”, sugiro usar as seguintes configurações:

 nodetach noauth passive local debug lock 192.168.250.1:192.168.250.2 /dev/ttyUSB1 115200 lcp-echo-interval 10 lcp-echo-failure 1 cdtrcts 

Reescrevemos as configurações em um arquivo e você pode iniciar o servidor. Isso é feito com o comando sudo pppd file ./pppd.conf

O servidor PPPD deve ser iniciado antes do início da descoberta; portanto, após o início do PPPD, você precisa clicar no botão "Redefinir" localizado na placa.

Se você fez tudo corretamente, verá a seguinte imagem:



Executando pppd à esquerda, registrador à direita.

Etapa 4. Enviamos uma sacola


Nesta fase, precisamos das duas máquinas virtuais. Linux para pppd e Windows para receber o pacote. Para simplificar a tarefa, é necessário que ambas as máquinas estejam na mesma sub-rede, a solução ideal seria especificar uma conexão de ponte de rede para ambas as máquinas nas configurações de rede do VirtualBox e desativar o firewall no Windows.

Iniciamos as máquinas virtuais e configuramos a conexão ppp da placa de descoberta com o pppd. No Windows, descobrimos o endereço IP da máquina (comando ipconfig), obtive-o 192.168.10.97.

Inicie o Packet Sender e configure-o da seguinte maneira:



Agora, novamente, modifique a tarefa StartDefaultTask no arquivo main.c.

 /* USER CODE BEGIN 4 */ #include "logger.h" #include "sockets.h" typedef uint32_t SOCKET; /* USER CODE END 4 */ /* StartDefaultTask function */ void StartDefaultTask(void const * argument) { /* init code for LWIP */ // MX_LWIP_Init(); /* USER CODE BEGIN 5 */ usart_Open(); MX_LWIP_Init(); /* Infinite loop */ uint8_t sendStr[]="Test message TCP/IP."; uint8_t resvStr[100]={0}; int resvLength = 0; struct sockaddr_in sockAddr; sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons( 6565 ); uint32_t addr = inet_addr("192.168.10.97"); sockAddr.sin_addr.s_addr = addr; SOCKET socket = NULL; int nError = 0; /* Infinite loop */ for(;;) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); osDelay(1000); socket = socket( AF_INET, SOCK_STREAM, 0 ); nError = connect( socket, (struct sockaddr*)&sockAddr, sizeof(sockAddr) ); if ( nError == 0 ) { nError = send( socket, sendStr, sizeof(sendStr)-1, 0 ); if ( nError < 0 ) logger("SEND ERROR %d\n", nError); else { logger("SEND - %s\n", sendStr); resvLength = 0; while(resvLength < 1) resvLength = lwip_recv( socket, resvStr, sizeof(resvStr), MSG_WAITALL); resvStr[resvLength]=0; logger("GET - %s\n", resvStr); } lwip_close(socket); } else logger("CONNECT ERROR %d\n", nError); } /* USER CODE END 5 */ } 

Como o valor da variável addr, usamos o endereço da máquina Windows, número da porta 6565.
Mensagem enviada “Mensagem de teste TCP / IP.”, Resposta “A mensagem foi recebida.”

Aqui você pode ver que as funções PPP não são usadas diretamente para enviar e receber mensagens. Todo o trabalho ocorre em um nível superior e nossas funções são chamadas automaticamente.

Nós compilamos e flash.

O resultado da conexão com o pppd é visível em uma máquina Linux:



Solicitações recebidas e respostas enviadas podem ser vistas no programa Packet Sender em uma máquina Windows:



Bem, isso é tudo, o pacote enviado por nós da placa de descoberta foi para a porta COM, chegou ao servidor pppd, foi enviado à porta 6565 do Windows da máquina, foi recebido com sucesso, em resposta a ele foi enviado outro pacote que passou por este direção oposta e foi adotada com sucesso no quadro. Você também pode enviar mensagens para qualquer máquina na Internet.

→ O código completo do projeto pode ser baixado aqui

Source: https://habr.com/ru/post/pt419037/


All Articles