/**
 * @file exo_stack_example.c
 *
 * @brief This file contains test function definitions for communication protocols.
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "csp_if.h"
#include "csp_time.h"
#include "csp_system.h"
#include "exo_stack_example.h"


#define MY_SERVER_PORT		11             ///< Server port number

static uint8_t server_address = 11;
static unsigned int server_received = 0;

os_sem_handle_ptr csp_serv_sem;

/**
 * @brief This function for CSP server thread.
 */
void Server(void *argument);

/**
 * @brief This function for CSP client thread.
 */
void client(void *argument);

/* Definitions for myTask02 */
osThreadId_t myTask02Handle;
const osThreadAttr_t myTask02_attributes = {
		.name = "myTask02",
		.stack_size = T_STACK_5K,
		.priority = (osPriority_t) P_DEFAULT_PRIO,
};

csp_socket_t *sock;

/**
 * @brief This API is use to initialize the CSP server.
 */
void CSP_Server_Init()
{
	sock = csp_socket(CSP_SO_NONE);
	DEBUG_CPRINT(("Server task started\n"));
	csp_bind(sock, CSP_ANY);
	csp_listen(sock, 10);
}


/**
 * @brief This API is use to initialize the CSP client.
 */
void server_proc()
{
	csp_conn_t *conn;
	if ((conn = csp_accept(sock, 10000)) == NULL) {
		osDelay(1);
		return;
	}
	csp_packet_t *packet;
	while ((packet = csp_read(conn, 50)) != NULL) {
		switch (csp_conn_dport(conn)) {
		case MY_SERVER_PORT:
			DEBUG_CPRINT(("Packet received on MY_SERVER_PORT: %s\n", (char *) packet->data));
			csp_buffer_free(packet);
			++server_received;
			break;
		default:
			csp_service_handler(conn,packet);
			break;
		}
	}
	csp_close(conn);
	osDelay(1);
}

unsigned int count;

/**
 * @brief This API for CSP client thread.
 */
void client_proc()
{
	DEBUG_CPRINT(("\t\r\n Ping Start Time= "));
	int result = csp_ping(server_address, 2000, 10, CSP_O_NONE);
	DEBUG_CPRINT(("\t address: %u, result %d [mS]", server_address, result));
	(void) result;
	osDelay(2000);
#if 0
	/* Send reboot request to server, the server has no actual implementation of csp_sys_reboot() and fails to reboot */
	//csp_reboot(server_address);
	//DEBUG_CPRINT(("reboot system request sent to address: %u\n", server_address));

	/* Send data packet (string) to server */

	/* 1. Connect to host on 'server_address', port MY_SERVER_PORT with regular UDP-like protocol and 1000 ms timeout */
	csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, server_address, MY_SERVER_PORT, 1000, CSP_O_NONE);

	/** Connection used for Space data transfer from S-Band module */
	//csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, 10, 11, 1000, CSP_O_NONE);
	if (conn == NULL) {
		/* Connect failed */
		DEBUG_CPRINT(("\r\n\rConnection failed\n"));
		return;
	}

	/* 2. Get packet buffer for message/data */
	csp_packet_t * packet = csp_buffer_get(100);
	if (packet == NULL) {
		/* Could not get buffer element */
		DEBUG_CPRINT(("\r\n\rFailed to get CSP buffer\n"));
		return;
	}

	/* 3. Copy data to packet */
	memcpy(packet->data, "Hello world ", 12);
	memcpy(packet->data + 12, &count, 1);
	memset(packet->data + 13, 0, 1);
	//memcpy(packet->data, &count, 1);
	//memset(packet->data+1, 0, 1);
	count++;

	/* 4. Set packet length */
	packet->length = (strlen((char *) packet->data) + 1); /* include the 0 termination */

	/* 5. Send packet */
	csp_send(conn, packet,0xFFFF);
	DEBUG_CPRINT(("\tPacket Sent - %s",packet->data));
	/* 6. Close connection */

	csp_close(conn);
#endif
}

/**
 * @brief This function for CSP client thread.
 */
void client(void *argument)
{
	count = 'A';
	for(;;)
	{
		client_proc();
		osDelay(1000);
	}
}

/**
 * @brief This function for CSP server thread.
 */
void Server(void *argument)
{
	CSP_Server_Init();
	count = 'A';
	for(;;)
	{
		os_sem_take(csp_serv_sem,os_wait_forever);
		server_proc();
		osDelay(10);
	}
}

/**
 * @brief This API use to test the CSP server.
 */
void csp_server_test()
{
	myTask02Handle = osThreadNew(Server, NULL, &myTask02_attributes);
	os_sem_create_bin(&csp_serv_sem, "CSP_SERV_SEM");
}

/**
 * @brief This API use to test the CSP client.
 */
void csp_client_test()
{
	myTask02Handle = osThreadNew(client, NULL, &myTask02_attributes);
}
