network/tcp_multiclient/main.c
/*
* EVALUATION AND USE OF THIS SOFTWARE IS SUBJECT TO THE TERMS AND
* CONDITIONS OF THE CONTROLLING LICENSE AGREEMENT FOUND AT LICENSE.md
* IN THIS SDK. IF YOU DO NOT AGREE TO THE LICENSE TERMS AND CONDITIONS,
* PLEASE RETURN ALL SOURCE FILES TO SILICON LABORATORIES.
* (c) Copyright 2018, Silicon Laboratories Inc. All rights reserved.
*/
/*
* Documentation for this app is available online.
* See https://docs.silabs.com/gecko-os/4/standard/latest/sdk/examples/network/tcp-multiclient
*/
#include "gos.h"
#include "example_app_util.h"
#define UART_RX_TIMEOUT 100
#define UART_RX_THRESHOLD_LENGTH 1000
#define APPLICATION_START_LINE "\r\nTCP Multi-Client example starting ..."
static uint32_t client_handle_mask;
static uint8_t uart_rx_buffer[4096];
static uint32_t uart_rx_timestamp;
/*************************************************************************************************/
void gos_app_init(void)
{
gos_result_t result;
GOS_LOG(APPLICATION_START_LINE);
{
GOS_LOG("Failed to load settings, err:%d", result);
return;
}
if (GOS_FAILED(result, example_app_util_network_up(GOS_INTERFACE_ANY, false, network_event_handler)))
{
}
}
/*************************************************************************************************/
static void network_event_handler(bool is_up)
{
if (is_up == true)
{
gos_result_t result;
uint32_t port;
gos_tcp_register_server_event_handlers(tcp_client_connect_handler, tcp_client_disconnect_handler, tcp_client_receive_handler);
client_handle_mask = 0;
GOS_LOG("Starting TCP Server...");
{
GOS_LOG("Failed to start TCP Server: %d", result);
return;
}
GOS_LOG("TCP Multi-client Server listening on: %s:%u", example_app_util_get_network_interface_ip_address_str(), port);
GOS_LOG("- All data sent to the UART will be forwarded to all connected clients");
GOS_LOG("- All client data will be forwarded to the UART");
}
else
{
client_handle_mask = 0;
set_uart_data_forwarding_enabled(false);
}
}
/*************************************************************************************************/
{
if (client_handle_mask == 0)
{
set_uart_data_forwarding_enabled(true);
}
client_handle_mask |= (1 << handle);
GOS_LOG("TCP Client-%d connected", handle);
}
/*************************************************************************************************/
{
GOS_LOG("TCP Client-%d disconnected", handle);
client_handle_mask &= ~(1 << handle);
if (client_handle_mask == 0)
{
set_uart_data_forwarding_enabled(false);
}
}
/*************************************************************************************************/
{
gos_handle_t handle_mask = client_handle_mask;
for (gos_handle_t handle = 0; handle_mask != 0; ++handle, handle_mask >>= 1)
{
if (handle_mask & 0x01)
{
gos_result_t result;
gos_buffer_t buffer =
{
.size = INT32_MAX
};
{
{
GOS_LOG("Failed to read from client TCP stream %d, err:%d", handle, result);
}
}
{
}
}
}
}
/*************************************************************************************************/
static void set_uart_data_forwarding_enabled(bool enabled)
{
if (enabled)
{
GOS_LOG("Disabling command console");
gos_uart_set_rx_callback(PLATFORM_STD_UART, uart_rx_callback);
}
else
{
gos_uart_clear_rx_callback(PLATFORM_STD_UART, uart_rx_callback);
GOS_LOG("Enabling command console");
gos_cmd_set_console_enabled(true);
}
}
/*************************************************************************************************
* This is called from the UART RX IRQ. It is called for each received UART RX character.
* It is extremely important only minimal work in done in this callback.
* To avoid starving the system, we only invoke the uart_rx_event_handler() when:
* - The time elapsed since the last RX event handler is >= UART_RX_TIMEOUT
* - The number of RX pending bytes >= UART_RX_THRESHOLD_LENGTH
*/
{
UNUSED_PARAMETER(arg);
uint32_t bytes_read = 0;
bool invoke_rx_event = false;
if ((now - uart_rx_timestamp) >= UART_RX_TIMEOUT)
{
// if the time elapsed since the last rx event was invoked is greater than UART_RX_TIMEOUT
// then invoke the rx event again
invoke_rx_event = true;
}
else
{
gos_uart_peek_bytes(PLATFORM_STD_UART, NULL, &bytes_read);
if (bytes_read >= UART_RX_THRESHOLD_LENGTH)
{
// if the number of RX bytes pending is greater than UART_RX_THRESHOLD_LENGTH
// then invoke the rx event
invoke_rx_event = true;
}
}
if (invoke_rx_event)
{
// update the RX event timestamp and issue the RX event
uart_rx_timestamp = now;
}
}
/*************************************************************************************************/
static void uart_rx_event_handler(void *arg)
{
gos_result_t result;
uint32_t bytes_read = 0;
{
return;
}
else if (bytes_read == 0)
{
return;
}
uart_rx_buffer,
bytes_read,
&bytes_read, GOS_NO_WAIT)))
{
return;
}
else if (bytes_read == 0)
{
return;
}
gos_handle_t handle_mask = client_handle_mask;
for (gos_handle_t handle = 0; handle_mask != 0; ++handle, handle_mask >>= 1)
{
if (handle_mask & 0x01)
{
{
GOS_LOG("Failed to forward data to client: %d, err:%d)", handle, result);
{
// if the network isn't up then no point in reading more client streams
return;
}
}
}
}
}