blob: 280deca784b0e3a5d0152b1fb6fb4132d02b4ff8 [file] [log] [blame]
/*
* Copyright (c) 2017 FH Dortmund.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Description:
* A4MCAR Project - TCP Server implementation and TCP Server task in Low Level Module using XMOS xCORE-200 eXplorerKIT
*
* Authors:
* M. Ozcelikors <mozcelikors@gmail.com>
*
* Contributors:
* This code uses the following repository as skeleton:
* https://github.com/Pajeh/XMOS_gigabit_tcp_reflect
*
* Update History:
*
*/
#include "ethernet_app.h"
#include <xtcp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "string_itoa.h"
#include "core_debug.h"
/***
* Function Name: Task_EthernetAppTCPServer
* Function Description : This task implements a TCP server to handle a two-way communication between low level module and high level module.
* High-level sends ----> a driving command to override driving behavior.
* Low-level sends ----> core usage information of Low-Level module that are retrieved by using core_stats_interface_tile0
* and core_stats_interface_tile1
*
* Argument Type Description
* c_xtcp chanend Channel end to communicate with the xtcp task which is responsible for implementing the TCP protocol communication
* cmd_from_ethernet_to_override client ethernet_to_cmdparser_if Driving command that is to be sent through Ethernet Server is received using this interface.
* core_stats_interface_tile0 server core_stats_if A server interface that is used for receiving core usage information (for Tile 0) from the task that is responsible for core monitoring.
* core_stats_interface_tile1 server core_stats_if A server interface that is used for receiving core usage information (for Tile 1) from the task that is responsible for core monitoring.
*/
void Task_EthernetAppTCPServer(chanend c_xtcp, client ethernet_to_cmdparser_if cmd_from_ethernet_to_override, server core_stats_if core_stats_interface_tile0,
server core_stats_if core_stats_interface_tile1)
{
xtcp_connection_t conn; // A temporary variable to hold connections associated with an event
xtcp_connection_t responding_connection; // The connection to the remote end we are responding to
int send_flag = FALSE; // This flag is set when the thread is in the middle of sending a response packet
// The buffers for incoming data, outgoing responses and outgoing broadcast messages
char rx_buffer[RX_BUFFER_SIZE];
char tx_buffer[RX_BUFFER_SIZE];
int response_len; // The length of the response the thread is sending
// Maintain track of two connections. Initially they are not initialized
// which can be represented by setting their ID to -1
responding_connection.id = INIT_VAL;
// Instruct server to listen and create new connections on the incoming port
xtcp_listen(c_xtcp, INCOMING_PORT, XTCP_PROTOCOL_TCP);
//Core usage info
short int core_usage_tile0[8], core_usage_tile1[8];
int connected = 0; //Connection flag
//Timer to delay send operation
timer tmr;
unsigned int time, delay = 5000 * MILLISECOND;
tmr :> time;
int string_ptr = 0;
int string_ptr2 = 0;
char str_buffer[4];
PrintCoreAndTileInformation("Task_EthernetAppTCPServer");
while (1)
{
select
{
case tmr when timerafter(time) :> void : // Timer event
if (!send_flag && connected==1)
{
//When client is connected and timer is ready, construct the tx_buffer
string_ptr = 0;
for ( int k = 0; k <= 7; k++)
{
string_ptr2 = 0;
itoa (core_usage_tile0[k], str_buffer, 4, 10);
//printf("%s ",str_buffer);
while (str_buffer[string_ptr2] != '\0')
{
tx_buffer[string_ptr] = str_buffer[string_ptr2];
string_ptr += 1;
string_ptr2 += 1;
}
if (k!=7)
{
tx_buffer[string_ptr] = ',';
string_ptr += 1;
}
}
tx_buffer[string_ptr] = ',';
string_ptr += 1;
for ( int k = 0; k <= 7; k++)
{
string_ptr2 = 0;
itoa (core_usage_tile1[k], str_buffer, 4, 10);
//printf("%s ",str_buffer);
while (str_buffer[string_ptr2] != '\0')
{
tx_buffer[string_ptr] = str_buffer[string_ptr2];
string_ptr += 1;
string_ptr2 += 1;
}
if (k!=7)
{
tx_buffer[string_ptr] = ',';
string_ptr += 1;
}
}
tx_buffer[string_ptr] = 'E';
string_ptr += 1;
//printf("%s \n",tx_buffer);
response_len = string_ptr;
//Once tx_buffer is ready, initialize TCP sending
xtcp_init_send(c_xtcp, conn);
send_flag = TRUE;
}
time += delay;
//printf("h\n");
break;
case core_stats_interface_tile0.ShareCoreUsage (unsigned int core0, unsigned int core1, unsigned int core2, unsigned int core3, unsigned int core4, unsigned int core5, unsigned int core6, unsigned int core7):
//Event to receive core utilization information from core monitoring task when ready (for Tile 0)
core_usage_tile0[0]=core0;
core_usage_tile0[1]=core1;
core_usage_tile0[2]=core2;
core_usage_tile0[3]=core3;
core_usage_tile0[4]=core4;
core_usage_tile0[5]=core5;
core_usage_tile0[6]=core6;
core_usage_tile0[7]=core7;
break;
case core_stats_interface_tile1.ShareCoreUsage (unsigned int core0, unsigned int core1, unsigned int core2, unsigned int core3, unsigned int core4, unsigned int core5, unsigned int core6, unsigned int core7):
//Event to receive core utilization information from core monitoring task when ready (for Tile 1)
core_usage_tile1[0]=core0;
core_usage_tile1[1]=core1;
core_usage_tile1[2]=core2;
core_usage_tile1[3]=core3;
core_usage_tile1[4]=core4;
core_usage_tile1[5]=core5;
core_usage_tile1[6]=core6;
core_usage_tile1[7]=core7;
break;
// Respond to an event from the TCP server
case xtcp_event(c_xtcp, conn):
switch (conn.event)
{
case XTCP_IFUP:
case XTCP_IFDOWN:
break;
case XTCP_NEW_CONNECTION:
// The tcp server is giving us a new connection.
// This is a new connection to the listening port
#ifdef DEBUG
printstr("New connection to listening port:");
printintln(conn.local_port);
#endif
printstr("New connection to listening port:");
printintln(conn.local_port);
//Connected flag:
connected = 1;
time += 2000 * MILLISECOND; //Delay sending a bit
if (responding_connection.id == INIT_VAL)
{
responding_connection = conn;
}
else
{printstr("Cannot handle new connection");
#ifdef DEBUG
printstr("Cannot handle new connection");
#endif
xtcp_close(c_xtcp, conn);
}
break;
case XTCP_RECV_DATA:
// When we get a packet in:
//
// - fill the tx buffer
// - initiate a send on that connection
//
response_len = xtcp_recv_count(c_xtcp, rx_buffer, RX_BUFFER_SIZE);
rx_buffer[response_len] = 0;
#ifdef DEBUG
printstr("Got data: ");
printint(response_len);
printstrln(" bytes");
#endif
//Send data to bluetooth command parser to override the command -optional
//printstrln(rx_buffer);
cmd_from_ethernet_to_override.SendCmd(rx_buffer, ETHERNET_TO_RN42_INTERFACE_COMMANDLENGTH);
#ifdef DEBUG
printstr("Responding: ");
printstrln(rx_buffer);}
#endif
break;
case XTCP_REQUEST_DATA:
case XTCP_RESEND_DATA:
case XTCP_SENT_DATA:
// The tcp server wants data for the reponding connection
if (send_flag == TRUE)
{
#ifdef DEBUG
printstr("Resending data pf length ");
printintln(response_len);
#endif
xtcp_send(c_xtcp, tx_buffer, response_len);
}
else
{
xtcp_complete_send(c_xtcp);
}
break;
case XTCP_TIMED_OUT:
case XTCP_ABORTED:
case XTCP_CLOSED:
#ifdef DEBUG
printstr("Closed connection:");
printintln(conn.id);
#endif
xtcp_close(c_xtcp, conn);
responding_connection.id = INIT_VAL;
send_flag = FALSE;
connected = 0;
break;
case XTCP_ALREADY_HANDLED:
break;
}
break;
}
}
}