/**
 * @file comms_sband_csp.c
 *
 * @brief #TODO
 *
 * @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/interfaces/csp_if.h"
#include "csp/arch/csp_time.h"
#include"comms_csw.h"
#include "comms_ipc.h"
#include"comms_sband_csp.h"
#include "comms_sband_init.h"
#include"errno.h"
#include"exo_common.h"
#include <csp/csp.h>
#include"logger.h"

uint8 PLACE_IN_EXT_RAM_MEM pat_chng = 0;
uint32_t PLACE_IN_EXT_RAM_MEM csp_data_count = 0;

/**
 * @brief This function is used for sending CSP ping for S-Band Module
 * @brief Sends a CSP ping command over S-Band.
 * 
 * @param[in] tc_cmd Pointer to the ping command packet data.
 *
 * This function sends a CSP ping command packet over the S-Band link.
 * It is used to test connectivity over the S-Band CSP interface.
 */
void sband_csp_ping(uint8_t *tc_cmd)
{
    comms_sync_s *sync_data=(comms_sync_s*)tc_cmd;
    //uint8_t type;
    //uint32_t size;
    //uint32_t periodicity;
    //uint32_t pld_count;
    uint32_t csp_ping_count = 0;
    int32_t result = 0;
   if(sync_data->type == 9)
   {

    /* Send ping to server, timeout 1000 mS, ping size 100 bytes */
    DEBUG_CPRINT(("\t\r\n Ping Start Time= "));
    log_id(LOG_INFO_L1,LOG_COMMS,PING_START_TIME_eq_);
csp_ping:
    result = csp_ping(sync_data->node, sync_data->periodicity,sync_data->size, CSP_O_NONE);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
    DEBUG_CPRINT(("\t CSP PING address: %u, result %lu [mS]",sync_data->node, result));
    log_id_with_two_arg(LOG_INFO_L1,LOG_COMMS,CSP_PING_ADDRESS__u8__RESULT__S32,sync_data->node,result);
#pragma GCC diagnostic pop

    if(result > 0)
    {
        DEBUG_CPRINT(("\n\r CSP PING SUCCESS\n"));
        log_id(LOG_INFO_L1,LOG_COMMS,CSP_PING_SUCCESS);
    }
    else
    {
        DEBUG_CPRINT(("\n\r CSP PING FAILURE\n"));
        log_id(LOG_ERROR,LOG_COMMS,CSP_PING_FAILURE);
    }

    csp_ping_count++;
    //DEBUG_CPRINT(("##CSP PING COUNT## %ld",csp_ping_count));
    if(csp_ping_count < sync_data->pld_count)
    {
        goto csp_ping;
    }

    DEBUG_CPRINT(("\n\r CSP PING TEST Complete\n"));
    log_id(LOG_INFO_L1,LOG_COMMS,CSP_PING_TEST_COMPLETE);
}
}
/**
 * @brief This function is used for sending CSP transmission data from the S-Band
 * @brief Transmits CSP data over S-Band.
 *
 * This function handles transmission of CSP packets over the S-Band link.
 * It takes care of packet segmentation if needed and initiating the 
 * S-Band TX to send the CSP packet data.
 */
void sband_csp_tx_data(void)
{
    /* Send data packet (string) to server */

    /* 1. Connect to host on 'SRS4_SPACE_ADDRESS', port MY_SERVER_PORT with regular UDP-like protocol and 1000 ms timeout */
    csp_conn_t * conn = csp_connect(CSP_PRIO_NORM, SRS4_CAN_TX_ADDRESS, SRS4_CAN_TX_DATA_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"));
        log_id(LOG_WARNING,LOG_COMMS,CONNECTION_FAILED);
        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"));
        log_id(LOG_WARNING,LOG_COMMS,FAILED_TO_GET_CSP_BUFFER);
        return;
    }

    /* 3. Copy data to packet */
    memcpy(packet->data, "Hello world ", 12);
    memcpy(packet->data + 12, &csp_data_count, 1);
    memset(packet->data + 13, 0, 1);
    csp_data_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));
    log_string(LOG_INFO_L1,LOG_COMMS,"PACKET_SENT");
    log_string(LOG_INFO_L1,LOG_COMMS,"packet->data");
    /* 6. Close connection */

    csp_close(conn);
}

/**
 * @brief Updates CSP port and address for S-Band.
 *
 * @param[in] csp_tx_port Pointer to CSP port value. 
 * @param[in] csp_tx_addr Pointer to CSP address value.
 *
 * This function updates the CSP port and address used by the S-Band
 * interface for transmitting CSP packets.
 */
void comms_sband_upd_port_addr(uint8_t *csp_tx_port, uint8_t *csp_tx_addr)
{
    *csp_tx_port = SRS4_CAN_TX_DATA_PORT;
    *csp_tx_addr = SRS4_CAN_TX_ADDRESS;
}

/**
 * @brief Updates CSP port and address for S-Band simulator.
 *
 * @param[in] csp_tx_port Pointer to CSP port value. 
 * @param[in] csp_tx_addr Pointer to CSP address value.
 *
 * This function updates the CSP port and address used by the S-Band
 * simulator for transmitting CSP packets.
 */ 
void comms_sband_sim_upd_port_addr(uint8_t *csp_tx_port, uint8_t *csp_tx_addr)
{
    *csp_tx_port = SRS4_ETH_TX_DATA_PORT;
    *csp_tx_addr = SRS4_ETH_TX_ADDRESS;
}

/**
 * @brief  This function is used to get CSP - TM property of CSP library
 * @brief Gets CSP telemetry data.
 *
 * @param[out] csp_tm Pointer to CSP telemetry data structure.
 * @param[out] size Pointer to returned size of CSP TM data.
 * 
 * @return Execution status.
 *
 * This function reads the CSP telemetry data and returns it to the caller.
 */
int32_t sdr_get_csp_tm_prop(s_comms_csp_tm  *csp_tm, uint16_t *size)
{
    csp_upd_tm();

    os_memcpy(csp_tm, &csp_tm_global, sizeof(s_comms_csp_tm));

/*    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].mtu %d",csp_tm->csp_int[0].mtu));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].tx %d",csp_tm->csp_int[0].tx));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].rx %d",csp_tm->csp_int[0].rx));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].tx_error %d",csp_tm->csp_int[0].tx_error));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].rx_error %d",csp_tm->csp_int[0].rx_error));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].drop %d",csp_tm->csp_int[0].drop));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].autherr %d",csp_tm->csp_int[0].autherr));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].frame %d", csp_tm->csp_int[0].frame));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].txbytes %d", csp_tm->csp_int[0].txbytes));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[0].rxbytes %d",csp_tm->csp_int[0].rxbytes));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].mtu %d",csp_tm->csp_int[1].mtu));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].tx %d",csp_tm->csp_int[1].tx));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].rx %d",csp_tm->csp_int[1].rx));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].tx_error %d",csp_tm->csp_int[1].tx_error));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].rx_error %d",csp_tm->csp_int[1].rx_error));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].drop %d",csp_tm->csp_int[1].drop));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].autherr %d",csp_tm->csp_int[1].autherr));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].frame %d", csp_tm->csp_int[1].frame));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].txbytes %d", csp_tm->csp_int[1].txbytes));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[1].rxbytes %d",csp_tm->csp_int[1].rxbytes));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].mtu %d",csp_tm->csp_int[2].mtu));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].tx %d",csp_tm->csp_int[2].tx));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].rx %d",csp_tm->csp_int[2].rx));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].tx_error %d",csp_tm->csp_int[2].tx_error));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].rx_error %d",csp_tm->csp_int[2].rx_error));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].drop %d",csp_tm->csp_int[2].drop));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].autherr %d",csp_tm->csp_int[2].autherr));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].frame %d", csp_tm->csp_int[2].frame));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].txbytes %d", csp_tm->csp_int[2].txbytes));
    DEBUG_CPRINT(("\ncsp_tm->csp_int[2].rxbytes %d",csp_tm->csp_int[2].rxbytes));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_nomem %d", csp_tm->csp_err_nomem));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_inval %d", csp_tm->csp_err_inval));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_timedout %d", csp_tm->csp_err_timedout));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_used %d", csp_tm->csp_err_used));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_notsup %d", csp_tm->csp_err_notsup));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_busy %d", csp_tm->csp_err_busy));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_already %d", csp_tm->csp_err_already));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_reset %d", csp_tm->csp_err_reset));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_nobufs %d", csp_tm->csp_err_nobufs));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_tx %d", csp_tm->csp_err_tx));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_driver %d", csp_tm->csp_err_driver));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_again %d", csp_tm->csp_err_again));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_hmac %d", csp_tm->csp_err_hmac));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_xtea %d", csp_tm->csp_err_xtea));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_crc32 %d", csp_tm->csp_err_crc32));
    DEBUG_CPRINT(("\ncsp_tm->csp_err_sfp %d", csp_tm->csp_err_sfp));*/

    return 0;
}

/**
 * @brief Sends data over specified radio interface. 
 *
 * @param[in] radio_id Radio interface ID (UHF/S-Band).
 * @param[in] pld_len Payload data length in bytes.
 * @param[in] pld_ptr Pointer to payload data.
 *
 * This function allows forcing transmission of input data over the 
 * specified radio interface (UHF/S-Band).
 */
void comms_force_tx_ipc(uint8_t radio_id, uint16_t pld_len, uint8_t* pld_ptr)
{
    switch(radio_id)
    {
        case COMMS_S_BAND:
        case COMMS_SBAND_IQS:
            {
                sband_send_ipc_pld(radio_id,COMMS_SBAND_TX,pld_len,pld_ptr);
            }
            break;
        case COMMS_UHF:
        case GS2_BACK_DOOR_SOC:
            {
                sband_send_ipc_pld(radio_id,COMMS_UHF_TX,pld_len,pld_ptr);
            }
            break;
    }
}

/**
 * @brief Transmits custom pattern over RF interface for testing.
 *
 * @param[in] data Pointer to pattern data to transmit.
 * 
 * @return Execution status.
 *
 * This function allows transmitting a custom data pattern over the
 * RF interface for testing purposes.
 */
uint8_t comms_cust_pattern_rf_tx(uint8_t* data)
{

    uint32_t seq = 0; 
    uint32_t count = 0;
    uint32_t buff_idx=0;
    uint8_t* sync_data=NULL;
    uint8_t radio_id = data[TC_RADIO_MOD_IDX];
    comms_sync_s* sync = (comms_sync_s*)&data[TC_PLD_IDX];
    sync_data = (uint8_t*)os_malloc(sync->size);
    switch(sync->type)
    {
        case 1:
            memset(sync_data,0,sync->size);
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                count++;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat"
                 DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                 log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
 #pragma GCC diagnostic pop
              comms_force_tx_ipc(radio_id,sync->size,sync_data);
              os_delay(sync->periodicity * 10);
            }
            break;
        case 2:
            memset(sync_data,1,sync->size);
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                count++;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat"
                 DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                 log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
 #pragma GCC diagnostic pop
              comms_force_tx_ipc(radio_id,sync->size, sync_data);
              os_delay(sync->periodicity * 10);
            }
            break;
        case 3:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                for(int start=0;start<sync->size;start++)
                {
                    sync_data[start] = start+1;
                }
                count++;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat"
                 DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                 log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
 #pragma GCC diagnostic pop
                comms_force_tx_ipc(radio_id,sync->size, sync_data);
              os_delay(sync->periodicity * 10);
            }
            break;
        case 4:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                uint8_t temp = sync->size;
                for(uint32_t start=0;start<sync->size;start++)
                {
                    sync_data[start] = temp;
                    temp--;
                }
                count++;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat"
                 DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                 log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
 #pragma GCC diagnostic pop
               comms_force_tx_ipc(radio_id,sync->size, sync_data);
              os_delay(sync->periodicity * 10);
            }
            break;
        case 5:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                memset(&sync_data[buff_idx],0,sync->size-1);
                buff_idx=buff_idx+sync->size;
                count++;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat"
                 DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                 log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
 #pragma GCC diagnostic pop
               comms_force_tx_ipc(radio_id,sync->size, sync_data);
              os_delay(sync->periodicity * 10);
            }
            break;
        case 6:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                memset(&sync_data[buff_idx],1,sync->size-1);
                buff_idx=buff_idx+sync->size;
                count++;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat"
                 DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                 log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
 #pragma GCC diagnostic pop
                comms_force_tx_ipc(radio_id,sync->size, sync_data);
              os_delay(sync->periodicity * 10);
            }
            break;
        case 7:
                   for (seq = 0; seq <sync->pld_count; seq++)
                    {
                        buff_idx=0;
                        sync_data[buff_idx]=seq;
                        buff_idx++;

                        for(int start=0;start<sync->size-1;start++)
                        {
                            sync_data[buff_idx] = start;
                            buff_idx++;
                        }

                        DEBUG_CPRINT(("\n"));
                        count++;
         #pragma GCC diagnostic push
         #pragma GCC diagnostic ignored "-Wformat"
                         DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                         log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
         #pragma GCC diagnostic pop
                 		comms_force_tx_ipc(radio_id,sync->size, sync_data);
                 		//sband_xlink_tx(sync_data,sync->size,1);
                 		 os_delay(sync->periodicity * 10);
                    }

                    break;

        case 8:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                for(int start=sync->size-2;start>=0;start--)
                {
                    sync_data[buff_idx] = start;
                    buff_idx++;
                }
                count++;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat"
                 DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                 log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
 #pragma GCC diagnostic pop
               comms_force_tx_ipc(radio_id,sync->size, sync_data);
              os_delay(sync->periodicity * 10);
            }
            break;
        case 10:
        	for (seq = 0; seq <sync->pld_count; seq++)
        	{
        		                os_delay(sync->periodicity * 10);
                //TODO: COMMS Beacon tx forcing
                //comms_sband_beacon_tx(uint8_t *beacon_data, uint16_t size)
            }
            break;
        case 11:
                   for (seq = 0; seq <sync->pld_count; seq++)
                    {
                        buff_idx=0;
                        sync_data[buff_idx]=seq;
                        buff_idx++;
                		if (pat_chng == 0)
                		{
                        for(int start=0;start<sync->size-1;start++)
                        {
                            sync_data[buff_idx] = start;
                            buff_idx++;
                        }
                			pat_chng = 1;
                		}
                		else if (pat_chng == 1)
                		{
                			for(int start=0;start<sync->size-1;start++)
                			{
                				sync_data[buff_idx] = 0xAA;
                				buff_idx++;
                			}
                			pat_chng = 2;
                		}
                		else if (pat_chng == 2)
                		{
                			for(int start=0;start<sync->size-1;start++)
                			{
                				sync_data[buff_idx] = 0xBB;
                				buff_idx++;
                			}
                			pat_chng = 3;
                		}
                		else if (pat_chng == 3)
                		{
                			for(int start=0;start<sync->size-1;start++)
                			{
                				sync_data[buff_idx] = 0xCC;
                				buff_idx++;
                			}
                			pat_chng = 0;
                		}
                        DEBUG_CPRINT(("\n"));
                        count++;
         #pragma GCC diagnostic push
         #pragma GCC diagnostic ignored "-Wformat"
                         DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
                         log_id_with_one_arg(LOG_INFO_L2,LOG_COMMS,CSP_PING_COUNT__u32_,count);
         #pragma GCC diagnostic pop
                 		comms_force_tx_ipc(radio_id,sync->size, sync_data);
                 		//sband_xlink_tx(sync_data,sync->size,1);
                 		 os_delay(sync->periodicity * 10);
                    }

                    break;
    }
    DEBUG_CPRINT(("OBC comms sync data:"));
    os_free(sync_data);
    return 0;
}
