Implementación de PPPOS en stm32f4-discovery

Una vez, antes de mí, había una tarea para proporcionar acceso a Internet en el STM32 teniendo para esto solo un puerto COM. Para resolver este problema, necesitaba PPP o, para ser precisos, PPPoS (Protocolo punto a punto sobre serie, una de las formas de implementar PPP, se usa cuando se conecta a través del puerto COM).

En el proceso de resolver la tarea que tenía ante mí, me encontré con algunas dificultades, una de las cuales, en mi opinión, era la cobertura insuficiente de los problemas relacionados con PPPoS en Internet. Con esta publicación intentaré cerrar la brecha designada, en la medida en que lo permita mi modesto conocimiento.

Este artículo describe cómo crear un proyecto para System Workbench para STM32 desde cero. Muestra un ejemplo de trabajo con UART. Hay ejemplos de código para implementar PPP. Y, por supuesto, un ejemplo de enviar un mensaje a una computadora vecina.

Introduccion


PPP (Protocolo punto a punto) es un protocolo de enlace de datos de dos puntos del modelo de red OSI. Por lo general, se usa para establecer comunicación directa entre dos nodos de red, y puede proporcionar autenticación de conexión, cifrado y compresión de datos. Se utiliza en muchos tipos de redes físicas: cable de módem nulo, línea telefónica, celular, etc.

A menudo hay subespecies del protocolo PPP, como el Protocolo punto a punto a través de Ethernet (PPPoE), que se utiliza para conectarse a través de Ethernet y, a veces, a través de DSL; y el Protocolo punto a punto sobre ATM (PPPoA), que se utiliza para la conexión a través de la Capa de adaptación ATM 5 (AAL5), que es la principal alternativa PPPoE para DSL.

PPP es una familia de protocolos: Protocolo de control de enlace (LCP), Protocolo de control de red (NCP), Protocolos de autenticación (PAP, CHAP), PPP multicanal (MLPPP).

De Wikipedia

Preparación


Para resolver el problema necesitamos:

Hierro:


  1. Placa de depuración stm32f4_discovery:

  2. Adaptador USB a miniUSB para conectar la placa a una computadora.
  3. Dos adaptadores USBtoUART FT232:

  4. Dos cables de extensión USB también son útiles, no necesariamente, sino simplemente convenientes.

Suave:


  1. Máquina virtual VirtualBox. Puedes descargarlo aquí . También descargamos e instalamos el paquete de extensión para VirtualBox.
  2. Dos discos de instalación con los sistemas operativos Windows y Linux. Tomamos Windows aquí , Linux aquí .

    Después de instalar el sistema operativo, deberá instalar complementos para el sistema operativo invitado. Para la tarea tenemos suficientes sistemas 32x, no puede engañar con la inclusión de la virtualización.
  3. Para Windows, necesitamos un programa que pueda aceptar solicitudes y responderlas a través de TCP / IP, y un programa de terminal para trabajar con un puerto COM. Descargue PacketSender aquí (haga clic en "No, gracias, déjeme descargar"). El terminal está aquí . Además, necesitamos STM32CubeMX para la configuración inicial del proyecto. Descargar desde st.com (después del registro, el enlace se enviará por correo electrónico).
  4. Ponemos System Workbench para STM32 en el sistema operativo principal. Descargar desde aquí (se requiere registro).

Etapa 1. Creando un proyecto


En primer lugar, abra STM32CubeMX y cree un nuevo proyecto allí para nuestra placa de descubrimiento stm32f4. Encienda RCC, Ethernet (ETH), SYS, USART2, USART3, luego encienda FREERTOS y LWIP.




Para el diagnóstico, necesitamos LED en el tablero. Para esto, configure las patas de PD12-PD15 como GPIO_Output.



En la pestaña Configuración del reloj, configure la frecuencia, como en la imagen a continuación.



A continuación, en la pestaña Configuración, configure los puertos USART. Trabajaremos con ellos en modo DMA. Tenemos dos puertos USART, uno que usaremos para transmitir y recibir datos a través de PPP, el segundo para el registro. Para que funcionen, necesitamos configurar DMA en RX y TX para ambos puertos. Para todas las patas de ajuste de DMA, establezca Medio en prioridad. Para USART2 leg RX, configure el modo en "Circular". El resto de la configuración se deja por defecto.



También deberá habilitar la interrupción global para ambos puertos en la pestaña "Configuración de NVIC".

Esto completa la configuración inicial del proyecto en STM32CubeMX. Guardamos el archivo del proyecto y hacemos la generación del código para System Workbench para STM32.



Implementación


Ahora verifiquemos que el código descargado se compila y funciona. Para hacer esto, en el archivo main.c en la función "StartDefaultTask", reemplazamos el cuerpo del bucle infinito for (;;) con el código LED de encendido y apagado.

Debería ser así:

/* 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 */ } 

Compilamos el firmware y miramos. Los cuatro LED deben parpadear en el tablero.

Etapa 2. Trabajar con USART


Nuestra siguiente tarea es verificar el correcto funcionamiento de nuestro USART.

Lo primero que debemos hacer es conectar nuestro FT232 al descubrimiento. Para hacer esto, observe en qué patas están divorciadas las interfaces USART. Lo tengo PD6 y PD5 para USART2_RX y USART2_TX respectivamente.



Además de PD9 y PD8 para USART3_RX y USART3_TX, respectivamente.



Además, necesitamos un pie GND.

Encontramos estos pines en el tablero y los conectamos a los pines FT232, mientras que el pin GND en el tablero puede ser cualquiera, el pin RX en el tablero debe estar conectado al pin TX en el FT232, y el pin TX en el tablero debe estar conectado al pin RX en el FT232. Las conclusiones restantes no se utilizan.

Queda por conectar nuestro FT232 a los puertos USB de la computadora, así como también conectar la placa de descubrimiento a través del conector miniUSB a la computadora (que no debe confundirse con microUSB).

Después de conectar FT232, el sistema operativo principal instalará los controladores para ellos, después de lo cual estos dispositivos deberán ser enviados al invitado de Windows en la máquina virtual.

Ahora agregamos el código del programa que se necesita para el funcionamiento de nuestro USART. Para hacer esto, agregaremos cuatro archivos: usart.h, usart.c, logger.h, logger.c.

Contenido del archivo:

archivo 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_ */ 

archivo 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; } 

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

archivo 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)); } 

Necesitamos usart para transmitir y recibir datos en usart2. Será nuestra interfaz principal para comunicarnos con un servidor PPP.

Necesitamos Logger para implementar el registro enviando mensajes a la terminal. La función void usart_Open (void) forma una cola e inicia la tarea de dar servicio a esta cola. Esta función debe completarse antes de usar USART. Entonces todo es simple, la función bool usart_Send (char * bArray, int size_bArray) envía datos al puerto, y
uint16_t usart_Recv (char * bArray, uint16_t maxLength) los obtiene de la cola en la que la función void usart_rxTask (void) los ha agregado amablemente.

Para el registrador, todavía es más simple; no hay necesidad de obtener datos, por lo tanto, ni la cola ni la tarea de mantenimiento de la cola son necesarias.

Al comienzo del archivo main.h , debe agregar varias definiciones que describan el tipo bool, que no está disponible en C.

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

Ahora es el momento de verificar la funcionalidad del código resultante. Para hacer esto, en el archivo main.c , cambie el código de la tarea ya conocida "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 */ } 

Además, necesitamos dar más memoria a la pila de nuestra tarea. Para hacer esto, en la llamada a la función osThreadDef (), el archivo main.c, necesita corregir 128 por 128 * 10 para obtener esto:

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

Compilamos y flasheamos. Los LED parpadean de la misma manera que en la tarea anterior.

Para ver el resultado de nuestro trabajo, debe ejecutar el programa Terminal en nuestra máquina virtual. Una instancia del programa para el puerto de registro, la segunda para el principal. Mire en el administrador de dispositivos qué números de puerto se asignaron a su FT232. Si a los números se les ha asignado más de 10, reasigne.

Cuando inicia la segunda instancia del programa, puede producirse un error, cierre la ventana con el error y continúe trabajando con el programa.

Para ambos puertos establecemos una conexión a 115200 baudios, bits de datos - 8, paridad - ninguno, bits de parada - 1, apretón de manos - ninguno.

Si hizo todo correctamente, en la ventana de terminal para usart2 se transmitirá el mensaje "Enviar mensaje". El mismo mensaje se duplicará en la ventana de terminal para el registrador solo con el prefijo "ENVIAR -"

Si en la ventana de terminal para usart2 escribe texto en el campo "Enviar" y hace clic en el botón correspondiente a la derecha de este campo, en la ventana del registrador verá el mismo mensaje con el prefijo "RECV -"

En la imagen a continuación: a la izquierda está el registrador, a la derecha está usart2.



Etapa 3. Comenzando con PPP


Como parte de esta tarea, crearemos una conexión PPP. En primer lugar, habilite el uso de PPP, cambie el valor de la definición PPP_SUPPORT en el archivo ppp_opts.h a 1. Luego redefinimos las definiciones necesarias en el archivo 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 */ 

Al mismo tiempo, las definiciones antiguas deben comentarse.

Ahora modificamos el archivo lwip.c, inserte el siguiente código en el bloque "/ * 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 */ 

Luego, en la función MX_LWIP_Init (), en el bloque "/ * USER CODE BEGIN 3 * /" agregamos una llamada a la función pppConnect ().

Además, debe aumentar el tamaño del almacenamiento dinámico, para esto, en el archivo FreeRTOSConfig.h, debe comentar la definición de configTOTAL_HEAP_SIZE y, al final del archivo, en el / * CÓDIGO DE USUARIO COMIENZA Define * / block, declararlo con un nuevo 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 */ 

Además, en el archivo usart.c, cambie el valor de la definición Q_USART2_SIZE a 2048.

La configuración de la conexión comienza con la función MX_LWIP_Init (); se creó automáticamente; acabamos de agregarle una llamada a la función pppConnect (). En esta función, se inician las tareas que sirven a la conexión PPPOS. Las funciones pppos_create () necesitan pasar las direcciones de las funciones que servirán para enviar mensajes y la salida de información sobre el cambio del estado de la conexión. Para nosotros, estas son las funciones ppp_output_cb () y ppp_link_status_cb (), respectivamente. Además, la función pppConnect () iniciará la tarea de atender los mensajes recibidos. Al final de su operación, la función pppConnect () esperará a que se establezca una conexión con el servidor y luego completará su operación.

El trabajo con la red se realizará a un nivel superior, tan pronto como LWIP decida que es necesario enviar un mensaje a la red, la función ppp_output_cb () se llamará automáticamente. La respuesta de la red será recibida por la función PppGetTask (), como parte de la tarea de atender los mensajes entrantes, y transferida a las entrañas de LWIP. Si el estado de la conexión cambia, la función ppp_link_status_cb () se llamará automáticamente.

Finalmente, modificaremos la tarea StartDefaultTask. Ahora debería verse así:

 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 */ } 

Hecho, puedes compilar y flashear.

En este punto, debe iniciar el servidor PPP. Para hacer esto, primero debe implementar una máquina virtual con Linux. Usé Ubuntu 16.04 x32. Después de instalar el sistema operativo, debe configurar el uso del puerto COM.

En esta parte, no necesitamos una máquina virtual con Windows, podemos apagarla de manera segura. Conectamos ambos FT232 en Linux.

En Linux, antes de comenzar a trabajar con un puerto COM, debe permitir que el usuario lo use. Para hacer esto, ejecute el siguiente comando:

 sudo addgroup USERNAME dialout 

donde USERNAME es el nombre del usuario actual.

Para ver los puertos disponibles en el sistema COM, debe ejecutar el comando:

 dmesg | grep tty 



Vemos que hay dos puertos ttyUSB en el sistema. No podemos decir de inmediato cuál es el registrador y cuál es usart2. Solo necesita verificarlos a su vez.

Primero, ejecute los comandos para leer desde un puerto:

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

luego de otro:

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

Donde vemos esa imagen, eso es registrador.



Puede salir de esta ventana, no nos molestará.

A continuación, debe permitir que los paquetes enviados desde nuestra placa salgan de los límites de su subred. Para hacer esto, configure iptables. Realizamos las siguientes acciones:

1. Abra una nueva ventana de consola
2. Necesita averiguar su ip y el nombre de la interfaz de red (ejecute el comando ifconfig )



3. Ejecute los comandos de configuración 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 

donde enp0s3 es el nombre de la interfaz de red
192.168.10.196 - su dirección IP
/ proc / sys / net / ipv4 / - ruta al archivo correspondiente.

Estos comandos pueden reescribirse en un archivo por lotes y ejecutarlo cada vez antes de iniciar el servidor PPP. Puede agregarlo a la ejecución automática, pero no lo hice.

Ahora estamos listos para iniciar el servidor, solo queda crear un archivo de configuración. Lo llamé " pppd.conf ", sugiero usar la siguiente configuración:

 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 

Reescribimos la configuración en un archivo y luego puede iniciar el servidor. Esto se hace con el comando sudo pppd file ./pppd.conf

El servidor PPPD debe iniciarse antes del inicio del descubrimiento, por lo que después del inicio de PPPD debe hacer clic en el botón "Restablecer" ubicado en la placa.

Si hizo todo correctamente, verá la siguiente imagen:



Ejecutando pppd a la izquierda, registrador a la derecha.

Etapa 4. Enviamos una bolsa


En esta etapa, necesitamos ambas máquinas virtuales. Linux para pppd y Windows para recibir el paquete. Para simplificar la tarea, necesita que ambas máquinas estén en la misma subred, la solución ideal sería especificar una conexión de puente de red para ambas máquinas en la configuración de red de VirtualBox y desactivar el firewall en Windows.

Iniciamos las máquinas virtuales y configuramos la conexión ppp de la placa de descubrimiento con pppd. En Windows, descubrimos la dirección IP de la máquina (comando ipconfig), la obtuve 192.168.10.97.

Inicie Packet Sender y configúrelo de la siguiente manera:



Ahora nuevamente, modifique la tarea StartDefaultTask en el archivo 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 valor de la variable addr, usamos la dirección de la máquina Windows, número de puerto 6565.
Mensaje enviado "Mensaje de prueba TCP / IP". Respuesta "Se recibió el mensaje".

Aquí puede ver que las funciones PPP no se utilizan directamente para enviar y recibir mensajes. Todo el trabajo se lleva a cabo en un nivel superior, y nuestras funciones se llaman automáticamente.

Compilamos y flasheamos.

El resultado de conectarse a pppd es visible en una máquina Linux:



Las solicitudes recibidas y las respuestas enviadas se pueden ver en el programa Packet Sender en una máquina con Windows:



Bueno, eso es todo, el paquete enviado por nosotros desde la placa de descubrimiento fue al puerto COM, llegó al servidor pppd, se envió al puerto 6565 de Windows de la máquina, allí se recibió con éxito, en respuesta a él se envió otro paquete que pasó este camino en la dirección opuesta y fue adoptado con éxito en el tablero. También podría enviar mensajes a cualquier máquina en Internet.

→ El código completo del proyecto se puede descargar aquí

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


All Articles