Middleware for using TCP on RZ MPUs.
FreeRTOS Plus TCP is a TCP stack created for use with FreeRTOS.
This module provides the NetworkInterface required to use FreeRTOS Plus TCP with the Ethernet (r_gether) driver.
Configuration | Options | Default | Description |
Print debug messages |
| Disable | If ipconfigHAS_DEBUG_PRINTF is set to 1 then FreeRTOS_debug_printf should be defined to the function used to print out the debugging messages. |
Backward Compatible Mode |
| Yes | Run the code in backward compatible mode |
Enable IPV6 |
| Disable | Stack supports handling IPv6 packets (including handling IPv6 header, ND, RA, and so on) when enabled |
Print info messages |
| Disable | Set to 1 to print out non debugging messages, for example the output of the FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 then FreeRTOS_printf should be set to the function used to print out the messages. |
Byte order of the target MCU | pdFREERTOS_LITTLE_ENDIAN | pdFREERTOS_LITTLE_ENDIAN | Define the byte order of the target MCU |
IP/TCP/UDP checksums |
| Enable | If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software stack repeating the checksum calculations. |
Receive Block Time | Value must be a non-negative integer | 10000 | Amount of time FreeRTOS_recv() will block for. The timeouts can be set per socket, using setsockopt(). |
Send Block Time | Value must be a non-negative integer | 10000 | Amount of time FreeRTOS_send() will block for. The timeouts can be set per socket, using setsockopt(). |
DNS caching |
| Enable | DNS caching |
DNS Request Attempts | Value must be an integer | 2 | When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low and also DNS may use small timeouts. |
IP stack task priority | Manual Entry | configMAX_PRIORITIES - 2 | Set the priority of the task that executes the IP stack. |
Stack size in words (not bytes) | Manual Entry | configMINIMAL_STACK_SIZE * 5 | The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP stack. |
Network Events call vApplicationIPNetworkEventHook |
| Enable | vApplicationIPNetworkEventHook is called when the network connects or disconnects. |
Max UDP send block time | Manual Entry | 15000 / portTICK_PERIOD_MS | Max UDP send block time |
Use DHCP |
| Enable | If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP address, netmask, DNS server address and gateway address from a DHCP server. |
DHCP Register Hostname |
| Enable | Register hostname when using DHCP |
DHCP Uses Unicast |
| Enable | DHCP uses unicast. |
DHCP Send Discover After Auto IP |
| Disable | DHCP Send Discover After Auto IP |
DHCP callback function |
| Disable | Provide an implementation of the DHCP callback function(xApplicationDHCPHook) |
Interval between transmissions | Manual Entry | 120000 / portTICK_PERIOD_MS | When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at increasing time intervals until either a reply is received from a DHCP server and accepted, or the interval between transmissions reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD. |
ARP Cache Entries | Value must be an integer | 6 | The maximum number of entries that can exist in the ARP table at any one time |
ARP Request Retransmissions | Value must be an integer | 5 | ARP requests that do not result in an ARP response will be re-transmitted a maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is aborted. |
Maximum time before ARP table entry becomes stale | Value must be an integer | 150 | The maximum time between an entry in the ARP table being created or refreshed and the entry being removed because it is stale |
Use string for IP Address |
| Enable | Take an IP in decimal dot format (for example, "192.168.0.1") as its parameter FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets (for example, 192, 168, 0, 1) as its parameters |
Total number of available network buffers | Value must be an integer | 10 | Define the total number of network buffer that are available to the IP stack |
Set the maximum number of events | Please enter a valid function name without spaces or funny characters | ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 | Set the maximum number of events that can be queued for processing at any one time. The event queue must be a minimum of 5 greater than the total number of network buffers |
Enable FreeRTOS_sendto() without calling Bind |
| Disable | Set to 1 then calling FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP stack automatically binding the socket to a port number from the range socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() on a socket that has not yet been bound will result in the send operation being aborted. |
TTL values for UDP packets | Value must be an integer | 128 | Define the Time To Live (TTL) values used in outgoing UDP packets |
TTL values for TCP packets | Value must be an integer | 128 | Defines the Time To Live (TTL) values used in outgoing TCP packets |
Use TCP and all its features |
| Enable | Use TCP and all its features |
Let TCP use windowing mechanism |
| Disable | Let TCP use windowing mechanism |
Maximum number of bytes the payload of a network frame can contain | Value must be an integer | 1500 | Maximum number of bytes the payload of a network frame can contain |
Basic DNS client or resolver |
| Enable | Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used through the FreeRTOS_gethostbyname() API function. |
Reply to incoming ICMP echo (ping) requests |
| Enable | If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will generate replies to incoming ICMP echo (ping) requests. |
FreeRTOS_SendPingRequest() is available |
| Disable | If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the FreeRTOS_SendPingRequest() API function is available. |
FreeRTOS_select() (and associated) API function is available |
| Disable | If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() (and associated) API function is available |
Filter out non Ethernet II frames. |
| Enable | If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames that are not in Ethernet II format will be dropped. This option is included for potential future IP stack developments |
Responsibility of the Ethernet interface to filter out packets |
| Disable | If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the responsibility of the Ethernet interface to filter out packets that are of no interest. |
Send RST packets, when receive unknown packets. |
| Enable | TCP will not send RST packets in reply to TCP unknown or out-of-order packets |
Block time to simulate MAC interrupts | Please enter a valid function name without spaces or funny characters | 20 / portTICK_PERIOD_MS | The windows simulator cannot really simulate MAC interrupts, and needs to block occasionally to allow other tasks to run |
Access 32-bit fields in the IP packets | Value must be an integer | 2 | To access 32-bit fields in the IP packets with 32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. This has to do with the contents of the IP-packets: all 32-bit fields are 32-bit-aligned, plus 16-bit |
Size of the pool of TCP window descriptors | Value must be an integer | 240 | Define the size of the pool of TCP window descriptors |
Size of Rx buffer for TCP sockets | Value must be an integer | 3000 | Define the size of Rx buffer for TCP sockets |
Size of Tx buffer for TCP sockets | Value must be an integer | 3000 | Define the size of Tx buffer for TCP sockets |
TCP keep-alive |
| Enable | TCP keep-alive is avaiable or not |
TCP keep-alive interval | Value must be an integer | 120 | TCP keep-alive interval in second |
The socket semaphore to unblock the MQTT task (USER_SEMAPHORE) |
| Disable | The socket semaphore is used to unblock the MQTT task |
The socket semaphore to unblock the MQTT task (WAKE_CALLBACK) |
| Enable | The socket semaphore is used to unblock the MQTT task |
The socket semaphore to unblock the MQTT task (USE_CALLBACKS) |
| Disable | The socket semaphore is used to unblock the MQTT task |
The socket semaphore to unblock the MQTT task (TX_DRIVER) |
| Disable | The socket semaphore is used to unblock the MQTT task |
The socket semaphore to unblock the MQTT task (RX_DRIVER) |
| Disable | The socket semaphore is used to unblock the MQTT task |
Possible optimisation for expert users |
| Disable | Possible optimisation for expert users - requires network driver support. It is is useful when there is high network traffic. If non-zero value then instead of passing received packets into the IP task one at a time the network interface can chain received packets together and pass them into the IP task in one go. If set to 0 then only one buffer will be sent at a time. |
In order to use the NetworkInterface implementation provided by Renesas for RZ/A devices:
This is a example to send/receive PING between two ports of ETHER in an application.
#define RANDOM_MASK_7FFF (0x7fffUL)
#define RANDOM_MASK_0003 (0x0003UL)
#define SHIFT_15BITS (15)
#define SHIFT_30BITS (30)
#define PING_TIMEOUT (500)
#define PING_REQ_TIMEOUT (100)
#define TASK_DELAY_TIME (100)
#define MAX_VALUE_32BITS (0xFFFFFFFFUL)
static char * gp_remote_ip_address = USR_TEST_PING_IP;
static uint8_t ucMACAddress[2][6];
static uint8_t ucIPAddress[2][4];
static uint8_t ucNetMask[2][4];
static uint8_t ucGatewayAddress[2][4];
static uint8_t ucDNSServerAddress[2][4];
static uint32_t usr_print_ability = RESET_VALUE;
uint32_t usr_ping_count = RESET_VALUE;
ping_data_t ping_data = {RESET_VALUE, RESET_VALUE, RESET_VALUE};
uint32_t timer_counter = RESET_VALUE;
ping_status_t ping_status[USR_PING_COUNT + 1] = {RESET_VALUE};
static char const * const link_status[] =
{
"10Mbps Half Duplex\r\n",
"10Mbps Full Duplex\r\n",
"100Mbps Half Duplex\r\n",
"100Mbps Full Duplex\r\n",
"1000Mbps Half Duplex\r\n",
"1000Mbps Full Duplex\r\n",
"Illegal Value\r\n",
"Illegal Value\r\n"
};
static NetworkInterface_t xInterfaces[2];
extern void * __freertos_plus_tcp_array_start;
extern void * __freertos_plus_tcp_array_end;
BaseType_t xApplicationGetRandomNumber (uint32_t * pulNumber)
{
uint32_t ulResult = (uint32_t) (
((((uint32_t) user_rand()) & RANDOM_MASK_7FFF)) |
((((uint32_t) user_rand()) & RANDOM_MASK_7FFF) << SHIFT_15BITS) |
((((uint32_t) user_rand()) & RANDOM_MASK_0003) << SHIFT_30BITS));
*pulNumber = ulResult;
return pdPASS;
}
uint32_t ulApplicationGetNextSequenceNumber (uint32_t ulSourceAddress,
uint16_t usSourcePort,
uint32_t ulDestinationAddress,
uint16_t usDestinationPort)
{
return (ulSourceAddress + ulDestinationAddress + usSourcePort + usDestinationPort) && ulRand();
}
BaseType_t vSendPing (const char * pcIPAddress)
{
uint32_t ulIPAddress = RESET_VALUE;
ulIPAddress = FreeRTOS_inet_addr(pcIPAddress);
return FreeRTOS_SendPingRequest(ulIPAddress, BYTES_DATA_SEND, PING_REQ_TIMEOUT / portTICK_PERIOD_MS);
}
void vApplicationPingReplyHook (ePingReplyStatus_t eStatus, uint16_t usIdentifier)
{
switch (eStatus)
{
case eSuccess:
{
ping_status[usIdentifier].status = PING_SUCCESS;
break;
}
case eInvalidData:
default:
{
ping_status[usIdentifier].status = INVALID_DATA;
break;
}
}
ping_status[usIdentifier].id = usIdentifier;
ping_status[usIdentifier].time = timer_counter;
}
void rm_freertos_plus_tcp_example (void * pvParameters)
{
BaseType_t status = pdFALSE;
network_interface_instance_t ** p_network_instance_list;
uint32_t max_network_instance;
p_network_instance_list = (network_interface_instance_t **) &__freertos_plus_tcp_array_start;
max_network_instance =
(uint32_t) ((uintptr_t) &__freertos_plus_tcp_array_end - (uintptr_t) &__freertos_plus_tcp_array_start) /
sizeof(uintptr_t);
for (uint32_t loop = 0; loop < max_network_instance; loop++)
{
memcpy(ucMACAddress[loop], p_network_instance_list[loop]->pxEther->p_cfg->p_mac_address,
sizeof(ucMACAddress[0]));
memcpy(ucIPAddress[loop], p_network_instance_list[loop]->ucIpv4, sizeof(ucIPAddress[0]));
memcpy(ucNetMask[loop], p_network_instance_list[loop]->ucMask, sizeof(ucNetMask[0]));
memcpy(ucGatewayAddress[loop], p_network_instance_list[loop]->ucGateway, sizeof(ucGatewayAddress[0]));
memcpy(ucDNSServerAddress[loop], p_network_instance_list[loop]->ucDns, sizeof(ucDNSServerAddress[0]));
}
APP_PRINT(BANNER_INFO,
EP_VERSION,
version.version_id_b.
major,
version.version_id_b.
minor,
version.version_id_b.
patch);
APP_PRINT(ETH_PREINIT);
print_ipconfig();
pxFillInterfaceDescriptor(0, &(xInterfaces[0]));
pxFillInterfaceDescriptor(1, &(xInterfaces[1]));
status = FreeRTOS_IPInit_Multi();
if (pdFALSE == status)
{
APP_ERR_PRINT("FreeRTOS_IPInit Failed");
APP_ERR_TRAP(status);
}
APP_PRINT(ETH_POSTINIT);
while (true)
{
if (SUCCESS == isNetworkUp())
{
if (!(PRINT_UP_MSG_DISABLE & usr_print_ability))
{
uint32_t connection_status;
APP_PRINT("\r\nNetwork is Up");
usr_print_ability |= PRINT_UP_MSG_DISABLE;
usr_print_ability &= (uint32_t) ~PRINT_DOWN_MSG_DISABLE;
if (p_network_instance_list[0]->pxEther->p_cfg->p_ether_phy_instance->p_cfg->channel == 0)
{
connection_status = (R_EMAC0->CXR32 >> 1) & 0x7;
}
else
{
connection_status = (R_EMAC1->CXR32 >> 1) & 0x7;
}
FreeRTOS_OutputARPRequest(FreeRTOS_inet_addr(gp_remote_ip_address));
APP_PRINT("\r\nConnecton: %s\r\n", link_status[connection_status]);
}
if (!(PRINT_NWK_USR_MSG_DISABLE & usr_print_ability))
{
print_ipconfig();
}
if (!(PRINT_NWK_USR_MSG_DISABLE & usr_print_ability))
{
APP_PRINT(ETH_CHECK_CONNECT);
APP_PRINT("\r\nPinging %s with %d bytes of data:", (char *) gp_remote_ip_address, BYTES_DATA_SEND);
}
while (usr_ping_count < USR_PING_COUNT)
{
timer_counter = 0;
uint32_t request_num;
request_num = (uint32_t) vSendPing(gp_remote_ip_address);
if (request_num == pdFAIL)
{
ping_data.lost++;
}
else
{
ping_data.sent++;
while ((timer_counter < PING_TIMEOUT) && (ping_status[request_num].status == NO_PING))
{
vTaskDelay(1);
timer_counter++;
}
if (ping_status[request_num].status == NO_PING)
{
if (timer_counter >= PING_TIMEOUT)
{
ping_data.lost++;
APP_PRINT("\r\nRequest timed out!");
}
}
else
{
if (request_num == ping_status[request_num].id)
{
ping_data.received++;
switch (ping_status[request_num].status)
{
case PING_SUCCESS:
{
APP_PRINT("\r\nReply from %s: bytes=%d time=%dms",
(char *) gp_remote_ip_address,
BYTES_DATA_SEND,
ping_status[request_num].time);
break;
}
case INVALID_DATA:
{
APP_PRINT("\r\nReply from %s: Invalid Data, time=%dms",
(char *) gp_remote_ip_address,
ping_status[request_num].time);
break;
}
default:
{
break;
}
}
}
}
}
usr_ping_count++;
}
if (!(PRINT_NWK_USR_MSG_DISABLE & usr_print_ability))
{
print_pingResult();
usr_print_ability |= PRINT_NWK_USR_MSG_DISABLE;
}
}
else
{
if (!(PRINT_DOWN_MSG_DISABLE & usr_print_ability))
{
APP_PRINT("\r\nNetwork is Down");
usr_print_ability |= PRINT_DOWN_MSG_DISABLE;
usr_print_ability &= (uint32_t) ~PRINT_UP_MSG_DISABLE;
usr_print_ability &= (uint32_t) ~PRINT_NWK_USR_MSG_DISABLE;
usr_ping_count = RESET_VALUE;
ping_data.sent = RESET_VALUE;
ping_data.received = RESET_VALUE;
ping_data.lost = RESET_VALUE;
memset(ping_status, 0, sizeof(ping_status));
#if (0)
IPStackEvent_t xNetworkDownEvent;
xNetworkDownEvent.eEventType = eNetworkDownEvent;
xSendEventStructToIPTask(&xNetworkDownEvent, 0);
#endif
}
else
{
APP_PRINT(".");
fflush(stdout);
}
}
vTaskDelay(TASK_DELAY_TIME);
}
}
uint32_t max_time (ping_status_t pings_status[])
{
uint32_t max = RESET_VALUE;
for (uint8_t i = 0; i <= USR_PING_COUNT; i++)
{
if ((pings_status[i].status != NO_PING) && (max < pings_status[i].time))
{
max = pings_status[i].time;
}
}
return max;
}
uint32_t min_time (ping_status_t pings_status[])
{
uint32_t min = MAX_VALUE_32BITS;
for (uint8_t i = 0; i <= USR_PING_COUNT; i++)
{
if ((pings_status[i].status != NO_PING) && (min > pings_status[i].time))
{
min = pings_status[i].time;
}
}
return min;
}
uint32_t average_time (ping_status_t pings_status[])
{
uint32_t average = 0;
for (uint8_t i = 0; i <= USR_PING_COUNT; i++)
{
if (pings_status[i].status != NO_PING)
{
average += pings_status[i].time;
}
}
average = average / USR_PING_COUNT;
return average;
}
void print_pingResult (void)
{
APP_PRINT("\r\n\r\nPing Statistics for %s:", gp_remote_ip_address);
APP_PRINT("\r\n Packets: Sent = %02d, Received = %02d, Lost = %d (%d%% loss)\r\n",
ping_data.sent,
ping_data.received,
ping_data.lost,
ping_data.lost * 100 / ping_data.sent);
APP_PRINT("\r\nApproximate round trip times in milli-seconds:");
APP_PRINT("\r\n Maximum = %dms, Minimum = %dms, Average = %dms\r\n",
max_time(ping_status),
min_time(ping_status),
average_time(ping_status));
}
void print_ipconfig (void)
{
APP_PRINT("\r\nEthernet adapter for Renesas "KIT_NAME ":\r\n");
APP_PRINT("\tDescription . . . . . . . . . . . : Renesas "KIT_NAME " Ethernet\r\n");
APP_PRINT("\tPort 0\r\n");
APP_PRINT("\tPhysical Address. . . . . . . . . : %02x-%02x-%02x-%02x-%02x-%02x\r\n",
ucMACAddress[0][0],
ucMACAddress[0][1],
ucMACAddress[0][2],
ucMACAddress[0][3],
ucMACAddress[0][4],
ucMACAddress[0][5]);
APP_PRINT("\tIPv4 Address. . . . . . . . . . . : %d.%d.%d.%d\r\n",
ucIPAddress[0][0],
ucIPAddress[0][1],
ucIPAddress[0][2],
ucIPAddress[0][3]);
APP_PRINT("\tSubnet Mask . . . . . . . . . . . : %d.%d.%d.%d\r\n",
ucNetMask[0][0],
ucNetMask[0][1],
ucNetMask[0][2],
ucNetMask[0][3]);
APP_PRINT("\tDefault Gateway . . . . . . . . . : %d.%d.%d.%d\r\n",
ucGatewayAddress[0][0],
ucGatewayAddress[0][1],
ucGatewayAddress[0][2],
ucGatewayAddress[0][3]);
APP_PRINT("\tDNS Servers . . . . . . . . . . . : %d.%d.%d.%d\r\n",
ucDNSServerAddress[0][0],
ucDNSServerAddress[0][1],
ucDNSServerAddress[0][2],
ucDNSServerAddress[0][3]);
APP_PRINT("\r\n");
APP_PRINT("\tPort 1\r\n");
APP_PRINT("\tPhysical Address. . . . . . . . . : %02x-%02x-%02x-%02x-%02x-%02x\r\n",
ucMACAddress[1][0],
ucMACAddress[1][1],
ucMACAddress[1][2],
ucMACAddress[1][3],
ucMACAddress[1][4],
ucMACAddress[1][5]);
APP_PRINT("\tIPv4 Address. . . . . . . . . . . : %d.%d.%d.%d\r\n",
ucIPAddress[1][0],
ucIPAddress[1][1],
ucIPAddress[1][2],
ucIPAddress[1][3]);
APP_PRINT("\tSubnet Mask . . . . . . . . . . . : %d.%d.%d.%d\r\n",
ucNetMask[1][0],
ucNetMask[1][1],
ucNetMask[1][2],
ucNetMask[1][3]);
APP_PRINT("\tDefault Gateway . . . . . . . . . : %d.%d.%d.%d\r\n",
ucGatewayAddress[1][0],
ucGatewayAddress[1][1],
ucGatewayAddress[1][2],
ucGatewayAddress[1][3]);
APP_PRINT("\tDNS Servers . . . . . . . . . . . : %d.%d.%d.%d\r\n",
ucDNSServerAddress[1][0],
ucDNSServerAddress[1][1],
ucDNSServerAddress[1][2],
ucDNSServerAddress[1][3]);
}
void dnsQuerryFunc (char * domain)
{
uint32_t ulIPAddress = RESET_VALUE;
int8_t cBuffer[16] = {RESET_VALUE};
ulIPAddress = FreeRTOS_gethostbyname(domain);
if (ulIPAddress != 0)
{
FreeRTOS_inet_ntoa(ulIPAddress, (char *) cBuffer);
APP_PRINT("\r\nDNS Lookup for \"%s\" is : %s \r\n", domain, cBuffer);
}
else
{
APP_PRINT("\r\nDNS Lookup failed for \"%s\" \r\n", domain);
}
}
uint32_t isNetworkUp (void)
{
BaseType_t networkUp[2] = {pdFALSE, pdFALSE};
uint32_t network_status = (IP_LINK_UP | ETHERNET_LINK_UP);
network_interface_instance_t ** p_network_instance_list;
uint32_t max_network_instance;
p_network_instance_list = (network_interface_instance_t **) &__freertos_plus_tcp_array_start;
max_network_instance =
(uint32_t) ((uintptr_t) &__freertos_plus_tcp_array_end - (uintptr_t) &__freertos_plus_tcp_array_start) /
sizeof(uintptr_t);
uint32_t loop;
for (loop = 0; loop < max_network_instance; loop++)
{
eth_link_status[loop] = p_network_instance_list[loop]->pxEther->p_api->linkProcess(
p_network_instance_list[loop]->pxEther->p_ctrl);
networkUp[loop] = FreeRTOS_IsEndPointUp(&(p_network_instance_list[loop]->xEndPoint));
}
if ((FSP_SUCCESS == eth_link_status[0]) && (FSP_SUCCESS == eth_link_status[1]) && (pdTRUE == networkUp[0]) &&
(pdTRUE == networkUp[1]))
{
}
else
{
if (FSP_SUCCESS != eth_link_status[0])
{
network_status |= ETHERNET_LINK_DOWN;
}
else if (FSP_SUCCESS == eth_link_status[0])
{
network_status |= ETHERNET_LINK_UP;
}
else
{
}
if (pdTRUE != networkUp[0])
{
network_status |= IP_LINK_DOWN;
}
else if (pdTRUE == networkUp[0])
{
network_status |= IP_LINK_UP;
}
else
{
}
}
return network_status;
}
#if (ipconfigDHCP_REGISTER_HOSTNAME == 1)
const char * pcApplicationHostnameHook (void)
{
return KIT_NAME;
}
#endif
void vApplicationIPNetworkEventHook (eIPCallbackEvent_t eNetworkEvent)
{
static BaseType_t xTasksAlreadyCreated = pdFALSE;
if (eNetworkEvent == eNetworkUp)
{
if (xTasksAlreadyCreated == pdFALSE)
{
xTasksAlreadyCreated = pdTRUE;
}
}
}