/**
 * @file api_resp_orig.c
 *
 * @brief This file contains functions that helps to create
 *        the telecommand frame
 *
 * The functions provided in the file helps to create tele command
 * frame with crc and encryptions.
 *
 * @copyright Copyright 2023 Antaris, Inc.
 */
/*********************************************************************/
#include <api_resp_common.h>
#include <crc_8.h>

/**
 * @brief This API initializes the s_api_resp_frame by setting all the values
 *         of it's members to zero.
 */
int8_t api_resp_orig_init(s_api_resp_frame *api_resp_orig)
{
    int8_t status;

    if(NULL != api_resp_orig)
    {
        memset(api_resp_orig, 0, sizeof(s_api_resp_frame));
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the start of frame passed in sof value to
 * to the sof members of passed in s_api_resp_frame type struct.
 */
int8_t api_resp_orig_cfg_sof(s_api_resp_frame *api_resp_orig, uint8_t sof1,
                                                              uint8_t sof2)
{
    int8_t status;

    if(NULL != api_resp_orig)
    {
        api_resp_orig->sof1 = sof1;
        api_resp_orig->sof2 = sof2;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the api_resp_ctrl value to the api_resp_ctrl member
 */
int8_t api_resp_orig_cfg_api_resp_ctrl(s_api_resp_frame *api_resp_orig,
        uint8_t api_resp_ctrl)
{
    int8_t status;

    if(NULL != api_resp_orig)
    {
        api_resp_orig->api_resp_ctrl = api_resp_ctrl;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the passed in api_resp_id value to the api_resp_id
 *  member of passed in s_api_resp_frame type struct.
 */
int8_t api_resp_orig_cfg_api_resp_id(s_api_resp_frame *api_resp_orig,
        uint8_t api_resp_id)
{
    int8_t status;

    if(NULL != api_resp_orig)
    {
        api_resp_orig->api_resp_id = api_resp_id;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the passed in api_resp_len value to the api_resp_len
 *  member of passed in s_api_resp_frame type struct.
 */
int8_t api_resp_orig_cfg_api_resp_len(s_api_resp_frame *api_resp_orig,
        uint16_t api_resp_len)
{
    int8_t status;

    if(NULL != api_resp_orig)
    {
        api_resp_orig->api_resp_len = api_resp_len;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the passed in value to the api_resp_len member
 * of passed in s_api_resp_frame type struct.
 */
int8_t api_resp_orig_cfg_api_resp_data(s_api_resp_frame *api_resp_orig,
        uint8_t *data)
{
    int8_t status;

    if((NULL != api_resp_orig) && (NULL != data))
    {
        api_resp_orig->api_resp_data = data;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the passed in crc_8 value to the crc_8 member
 * of passed in s_api_resp_frame type struct.
 */
int8_t api_resp_orig_cfg_crc_8(s_api_resp_frame *api_resp_orig, uint8_t crc_8)
{
    int8_t status;

    if(NULL != api_resp_orig)
    {
        api_resp_orig->crc_8 = crc_8;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the passed in end of frame (eof) to the eof member
 * member of passed in s_api_resp_frame type struct.
 */
int8_t api_resp_orig_cfg_eof(s_api_resp_frame *api_resp_orig, uint8_t eof)
{
    int8_t status;

    if(NULL != api_resp_orig)
    {
        api_resp_orig->eof = eof;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}


/**
 * @brief This API calculates the crc for the passed in input_str
 *         for the input size and stores the crc value to the val parameter
 *         equal to size input value.
 */
int8_t api_resp_orig_compute_crc(const uint8_t *input_str, uint8_t *val,
        size_t size)
{

    int8_t status;

    if((NULL != input_str) && (NULL != val))
    {
        *val = CRC8(input_str, size);
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API copies the structure data to the output buffer(dst). While
 * copying it takes care of the extension bit for the required members.
 */
int32_t api_resp_pack(uint8_t *dst, s_api_resp_frame *api_resp_orig)
{
    int32_t size = 0;

    if((NULL != dst) && (NULL != api_resp_orig))
    {
        memcpy(&dst[size], &api_resp_orig->sof1,
                                                  sizeof(api_resp_orig->sof1));
        size += sizeof(api_resp_orig->sof1);

        memcpy(&dst[size], &api_resp_orig->sof2,
                                                  sizeof(api_resp_orig->sof2));
        size += sizeof(api_resp_orig->sof2);

        memcpy(&dst[size], &api_resp_orig->api_resp_ctrl,
                sizeof(api_resp_orig->api_resp_ctrl));
        size += sizeof(api_resp_orig->api_resp_ctrl);
        if(api_resp_orig->api_resp_ctrl & API_REQ_RESP_SYNC_BIT)
        {
            api_resp_orig->time_stamp = adcs_get_utc_epoch();

            memcpy(&dst[size], &api_resp_orig->time_stamp,
                    sizeof(api_resp_orig->time_stamp));

            size += sizeof(api_resp_orig->time_stamp);
        }

        memcpy(&dst[size],&api_resp_orig->api_resp_id,
                sizeof(api_resp_orig->api_resp_id));
        size += sizeof(api_resp_orig->api_resp_id);

        memcpy(&dst[size],&api_resp_orig->api_resp_len,
                sizeof(api_resp_orig->api_resp_len));
        size += sizeof(api_resp_orig->api_resp_len);


        memcpy(&dst[size],api_resp_orig->api_resp_data,
                api_resp_orig->api_resp_len);
        size += api_resp_orig->api_resp_len;
        api_resp_orig_compute_crc(dst, &api_resp_orig->crc_8, size);

        memcpy(&dst[size], &api_resp_orig->crc_8,
                sizeof(api_resp_orig->crc_8));
        size += sizeof(api_resp_orig->crc_8);
        memcpy(&dst[size], &api_resp_orig->eof, sizeof(api_resp_orig->eof));
        size += sizeof(api_resp_orig->eof);
    }
    else
    {
        size = API_REQ_RESP_LIB_NULL_PTR;
    }

    return size;
}
