/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file app_netxduo.c * @author MCD Application Team * @brief NetXDuo applicative file ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "app_netxduo.h" /* Private includes ----------------------------------------------------------*/ #include "nxd_dhcp_client.h" /* USER CODE BEGIN Includes */ #include "nx_stm32_eth_config.h" #include "main.h" #define APP_TCP_SOCKET_NUM 2 /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* Define Threadx global data structures. */ TX_THREAD AppTCPThread; //TX_THREAD AppTCPThread2; TX_THREAD AppLinkThread; /* Define NetX global data structures. */ ULONG IpAddress; ULONG NetMask; static NX_TCP_SOCKET g_tcp_sck[2]; #define APP_TCP_PORT 5000 #define APP_TCP_LOG 1 TX_QUEUE g_tcp_q; /* App memory pointer. */ CHAR *pointer; /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ TX_THREAD NxAppThread; NX_PACKET_POOL NxAppPool; NX_IP NetXDuoEthIpInstance; TX_SEMAPHORE DHCPSemaphore; NX_DHCP DHCPClient; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ static VOID App_Main_Thread_Entry (ULONG thread_input); static VOID ip_address_change_notify_callback(NX_IP *ip_instance, VOID *ptr); /* USER CODE BEGIN PFP */ /* TCP thread entry */ static VOID tcp_thread_entry(ULONG thread_input); /* Link thread entry */ static VOID App_Link_Thread_Entry(ULONG thread_input); static ULONG g_not_listening = TX_FALSE; static VOID g_tcp_sck_listen_cb(NX_TCP_SOCKET *, UINT); static VOID g_tcp_sck_receive_cb(NX_TCP_SOCKET *); static VOID g_tcp_sck_disconn_cb(NX_TCP_SOCKET *); /* USER CODE END PFP */ /** * @brief Application NetXDuo Initialization. * @param memory_ptr: memory pointer * @retval int */ UINT MX_NetXDuo_Init(VOID *memory_ptr) { UINT ret = NX_SUCCESS; TX_BYTE_POOL *byte_pool = (TX_BYTE_POOL*)memory_ptr; /* USER CODE BEGIN App_NetXDuo_MEM_POOL */ /* USER CODE END App_NetXDuo_MEM_POOL */ /* USER CODE BEGIN 0 */ printf("Nx_TCP_Echo_Server application started..\r\n"); /* USER CODE END 0 */ /* Initialize the NetXDuo system. */ CHAR *pointer; nx_system_initialize(); /* Allocate the memory for packet_pool. */ if (tx_byte_allocate(byte_pool, (VOID **) &pointer, NX_APP_PACKET_POOL_SIZE, TX_NO_WAIT) != TX_SUCCESS) { return TX_POOL_ERROR; } /* Create the Packet pool to be used for packet allocation, * If extra NX_PACKET are to be used the NX_APP_PACKET_POOL_SIZE should be increased */ ret = nx_packet_pool_create(&NxAppPool, "NetXDuo App Pool", DEFAULT_PAYLOAD_SIZE, pointer, NX_APP_PACKET_POOL_SIZE); if (ret != NX_SUCCESS) { return NX_POOL_ERROR; } /* Allocate the memory for Ip_Instance */ if (tx_byte_allocate(byte_pool, (VOID **) &pointer, Nx_IP_INSTANCE_THREAD_SIZE, TX_NO_WAIT) != TX_SUCCESS) { return TX_POOL_ERROR; } /* Create the main NX_IP instance */ ret = nx_ip_create(&NetXDuoEthIpInstance, "NetX Ip instance", NX_APP_DEFAULT_IP_ADDRESS, NX_APP_DEFAULT_NET_MASK, &NxAppPool, nx_stm32_eth_driver, pointer, Nx_IP_INSTANCE_THREAD_SIZE, NX_APP_INSTANCE_PRIORITY); if (ret != NX_SUCCESS) { return NX_NOT_SUCCESSFUL; } /* Allocate the memory for ARP */ if (tx_byte_allocate(byte_pool, (VOID **) &pointer, DEFAULT_ARP_CACHE_SIZE, TX_NO_WAIT) != TX_SUCCESS) { return TX_POOL_ERROR; } /* Enable the ARP protocol and provide the ARP cache size for the IP instance */ /* USER CODE BEGIN ARP_Protocol_Initialization */ /* USER CODE END ARP_Protocol_Initialization */ ret = nx_arp_enable(&NetXDuoEthIpInstance, (VOID *)pointer, DEFAULT_ARP_CACHE_SIZE); if (ret != NX_SUCCESS) { return NX_NOT_SUCCESSFUL; } /* Enable the ICMP */ /* USER CODE BEGIN ICMP_Protocol_Initialization */ /* USER CODE END ICMP_Protocol_Initialization */ ret = nx_icmp_enable(&NetXDuoEthIpInstance); if (ret != NX_SUCCESS) { return NX_NOT_SUCCESSFUL; } /* Enable TCP Protocol */ /* USER CODE BEGIN TCP_Protocol_Initialization */ /* USER CODE END TCP_Protocol_Initialization */ ret = nx_tcp_enable(&NetXDuoEthIpInstance); if (ret != NX_SUCCESS) { return NX_NOT_SUCCESSFUL; } /* Enable the UDP protocol required for DHCP communication */ /* USER CODE BEGIN UDP_Protocol_Initialization */ /* USER CODE END UDP_Protocol_Initialization */ ret = nx_udp_enable(&NetXDuoEthIpInstance); if (ret != NX_SUCCESS) { return NX_NOT_SUCCESSFUL; } /* Allocate the memory for main thread */ if (tx_byte_allocate(byte_pool, (VOID **) &pointer, NX_APP_THREAD_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) { return TX_POOL_ERROR; } /* Create the main thread */ ret = tx_thread_create(&NxAppThread, "NetXDuo App thread", App_Main_Thread_Entry , 0, pointer, NX_APP_THREAD_STACK_SIZE, NX_APP_THREAD_PRIORITY, NX_APP_THREAD_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START); if (ret != TX_SUCCESS) { return TX_THREAD_ERROR; } /* Create the DHCP client */ /* USER CODE BEGIN DHCP_Protocol_Initialization */ /* USER CODE END DHCP_Protocol_Initialization */ ret = nx_dhcp_create(&DHCPClient, &NetXDuoEthIpInstance, "DHCP Client"); if (ret != NX_SUCCESS) { return NX_DHCP_ERROR; } /* set DHCP notification callback */ tx_semaphore_create(&DHCPSemaphore, "DHCP Semaphore", 0); /* USER CODE BEGIN MX_NetXDuo_Init */ /* Allocate the memory for TCP server thread */ if (tx_byte_allocate(byte_pool, (VOID **) &pointer,2 * DEFAULT_MEMORY_SIZE, TX_NO_WAIT) != TX_SUCCESS) { return TX_POOL_ERROR; } /* create the TCP server thread */ ret = tx_thread_create(&AppTCPThread, "App TCP Thread", tcp_thread_entry, 0, pointer, 2 * DEFAULT_MEMORY_SIZE, DEFAULT_PRIORITY, DEFAULT_PRIORITY, TX_NO_TIME_SLICE, TX_DONT_START); if (ret != TX_SUCCESS) { return TX_THREAD_ERROR; } /* Allocate the memory for Link thread */ if (tx_byte_allocate(byte_pool, (VOID **) &pointer,2 * DEFAULT_MEMORY_SIZE, TX_NO_WAIT) != TX_SUCCESS) { return TX_POOL_ERROR; } /* create the Link thread */ ret = tx_thread_create(&AppLinkThread, "App Link Thread", App_Link_Thread_Entry, 0, pointer, 2 * DEFAULT_MEMORY_SIZE, LINK_PRIORITY, LINK_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START); if (ret != TX_SUCCESS) { return TX_THREAD_ERROR; } /* USER CODE END MX_NetXDuo_Init */ return ret; } /** * @brief ip address change callback. * @param ip_instance: NX_IP instance * @param ptr: user data * @retval none */ static VOID ip_address_change_notify_callback(NX_IP *ip_instance, VOID *ptr) { /* USER CODE BEGIN ip_address_change_notify_callback */ /* USER CODE END ip_address_change_notify_callback */ /* release the semaphore as soon as an IP address is available */ tx_semaphore_put(&DHCPSemaphore); } /** * @brief Main thread entry. * @param thread_input: ULONG user argument used by the thread entry * @retval none */ static VOID App_Main_Thread_Entry (ULONG thread_input) { /* USER CODE BEGIN Nx_App_Thread_Entry 0 */ /* USER CODE END Nx_App_Thread_Entry 0 */ UINT ret = NX_SUCCESS; /* USER CODE BEGIN Nx_App_Thread_Entry 1 */ /* USER CODE END Nx_App_Thread_Entry 1 */ /* register the IP address change callback */ ret = nx_ip_address_change_notify(&NetXDuoEthIpInstance, ip_address_change_notify_callback, NULL); if (ret != NX_SUCCESS) { /* USER CODE BEGIN IP address change callback error */ Error_Handler(); /* USER CODE END IP address change callback error */ } /* start the DHCP client */ ret = nx_dhcp_start(&DHCPClient); if (ret != NX_SUCCESS) { /* USER CODE BEGIN DHCP client start error */ Error_Handler(); /* USER CODE END DHCP client start error */ } /* wait until an IP address is ready */ if(tx_semaphore_get(&DHCPSemaphore, NX_APP_DEFAULT_TIMEOUT) != TX_SUCCESS) { /* USER CODE BEGIN DHCPSemaphore get error */ Error_Handler(); /* USER CODE END DHCPSemaphore get error */ } /* USER CODE BEGIN Nx_App_Thread_Entry 2 */ ret = nx_ip_address_get(&NetXDuoEthIpInstance, &IpAddress, &NetMask); /* print the IP address and the net mask */ PRINT_IP_ADDRESS(IpAddress); if (ret != TX_SUCCESS) { Error_Handler(); } /* the network is correctly initialized, start the TCP server thread */ tx_thread_resume(&AppTCPThread); // tx_thread_resume(&AppTCPThread2); /* this thread is not needed any more, we relinquish it */ tx_thread_relinquish(); return; /* USER CODE END Nx_App_Thread_Entry 2 */ } /* USER CODE BEGIN 1 */ /** * @brief TCP listen call back * @param socket_ptr: NX_TCP_SOCKET socket registered for the callback * @param port: UINT the port on which the socket is listening * @retval none */ /** * @brief TCP server thread entry * @param thread_input: ULONG thread parameter * @retval none */ static VOID tcp_thread_entry(ULONG thread_input) { UINT status; /* Create all sockets */ for (INT i = 0; i < APP_TCP_SOCKET_NUM; i++) { status = nx_tcp_socket_create(&NetXDuoEthIpInstance, g_tcp_sck + i, "TCP Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 512, NX_NULL, g_tcp_sck_disconn_cb); if (NX_SUCCESS != status) { __BKPT(0); } } #if APP_TCP_LOG printf( "Created %u TCP socket%s on port %lu\n", APP_TCP_SOCKET_NUM, APP_TCP_SOCKET_NUM > 1 ? "s" : "", APP_TCP_PORT); #endif /* Start listening on the first socket */ status = nx_tcp_server_socket_listen(&NetXDuoEthIpInstance, APP_TCP_PORT, g_tcp_sck, 0, g_tcp_sck_listen_cb); if (NX_SUCCESS != status) { __BKPT(0); } while (1) { #if APP_TCP_INSTANT_ECHO /* Everything else is handled from TCP callbacks dispatched from * IP instance thread */ tx_thread_suspend(tx_thread_identify()); #else /* Receive pointers to TCP socket and network packet from * TCP callback */ ULONG msg[2]; status = tx_queue_receive(&g_tcp_q, msg, TX_WAIT_FOREVER); if (TX_SUCCESS == status) { NX_TCP_SOCKET * p_sck = (NX_TCP_SOCKET *) msg[0]; NX_PACKET * p_packet = (NX_PACKET *) msg[1]; status = nx_tcp_socket_send(p_sck, p_packet, NX_NO_WAIT); if (NX_SUCCESS != status) { nx_packet_release(p_packet); } } else { /* Unrecoverable error */ tx_thread_suspend(tx_thread_identify()); } #endif } } static void g_tcp_sck_listen_cb(NX_TCP_SOCKET * p_sck, UINT port) { /* Incoming connection, accept and queueing new requests */ nx_tcp_server_socket_accept(p_sck, NX_NO_WAIT); nx_tcp_server_socket_unlisten(&NetXDuoEthIpInstance, port); nx_tcp_socket_receive_notify(p_sck, g_tcp_sck_receive_cb); #if APP_TCP_LOG ULONG ip, client_port; nx_tcp_socket_peer_info_get(p_sck, &ip, &client_port); printf("[TCP %x] Incoming connection from %lu.%lu.%lu.%lu:%lu\n\r", p_sck, (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip) & 0xFF, client_port); #endif /* Attempt to find another idle socket to start listening on */ ULONG state = 0; for (INT i = 0; i < APP_TCP_SOCKET_NUM; i++) { /* Get socket state value */ nx_tcp_socket_info_get(g_tcp_sck + i, 0, 0, 0, 0, 0, 0, 0, &state, 0, 0, 0); /* Start lisnening if socket is idle */ if (NX_TCP_CLOSED == state) { nx_tcp_server_socket_listen(&NetXDuoEthIpInstance, port, g_tcp_sck + i, 0, g_tcp_sck_listen_cb); break; } } /* Ran out of sockets, set appropriate flag to let next socket to * disconnect know that it should start listening right away. */ if (NX_TCP_CLOSED != state) { g_not_listening = TX_TRUE; } } static void g_tcp_sck_receive_cb(NX_TCP_SOCKET * p_sck) { NX_PACKET * p_packet; /* This callback is invoked when data is already received. Retrieving * packet with no suspension. */ nx_tcp_socket_receive(p_sck, &p_packet, NX_NO_WAIT); #if APP_TCP_LOG ULONG ip, client_port; nx_tcp_socket_peer_info_get(p_sck, &ip, &client_port); printf("[TCP %x] Incoming packet (%lu bytes) from %lu.%lu.%lu.%lu:%lu\n\r", p_sck, p_packet->nx_packet_length, (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip) & 0xFF, client_port); #endif #if APP_TCP_INSTANT_ECHO /* Send packet back on the same TCP socket */ nx_tcp_socket_send(p_sck, p_packet, NX_NO_WAIT); #else ULONG msg[2] = { (ULONG) p_sck, (ULONG) p_packet }; /* Sent TCP socket and packet pointers to user thread */ if (TX_SUCCESS != tx_queue_send(&g_tcp_q, msg, TX_NO_WAIT)) { nx_packet_release(p_packet); } #endif } static void g_tcp_sck_disconn_cb(NX_TCP_SOCKET * p_sck) { #if APP_TCP_LOG printf("[TCP %x] Client disconnected\n\r", p_sck); #endif nx_tcp_server_socket_unaccept(p_sck); /* If all sockets are busy, start listening again */ if (TX_TRUE == g_not_listening) { nx_tcp_server_socket_listen(&NetXDuoEthIpInstance, APP_TCP_PORT, p_sck, 0, g_tcp_sck_listen_cb); g_not_listening = TX_FALSE; } } /** * @brief Link thread entry * @param thread_input: ULONG thread parameter * @retval none */ static VOID App_Link_Thread_Entry(ULONG thread_input) { ULONG actual_status; UINT linkdown = 0, status; while(1) { /* Get Physical Link stackavailtus. */ status = nx_ip_interface_status_check(&NetXDuoEthIpInstance, 0, NX_IP_LINK_ENABLED, &actual_status, 10); if(status == NX_SUCCESS) { if(linkdown == 1) { linkdown = 0; status = nx_ip_interface_status_check(&NetXDuoEthIpInstance, 0, NX_IP_ADDRESS_RESOLVED, &actual_status, 10); if(status == NX_SUCCESS) { /* The network cable is connected again. */ printf("The network cable is connected again.\n\r"); /* Print TCP Echo Server is available again. */ printf("TCP Echo Server is available again.\n\r"); } else { /* The network cable is connected. */ printf("The network cable is connected.\n\r"); /* Send command to Enable Nx driver. */ nx_ip_driver_direct_command(&NetXDuoEthIpInstance, NX_LINK_ENABLE, &actual_status); /* Restart DHCP Client. */ nx_dhcp_stop(&DHCPClient); nx_dhcp_start(&DHCPClient); } } } else { if(0 == linkdown) { linkdown = 1; /* The network cable is not connected. */ printf("The network cable is not connected.\n\r"); } } tx_thread_sleep(NX_ETH_CABLE_CONNECTION_CHECK_PERIOD); } } /* USER CODE END 1 */