/******************************************************************************
* File Name:   uartd.c
*
* Description: This file contains functions for streaming data over a serial
*              UART interface.
*
*******************************************************************************
* Copyright 2024-2025, Cypress Semiconductor Corporation (an Infineon company) or
* an affiliate of Cypress Semiconductor Corporation.  All rights reserved.
*
* This software, including source code, documentation and related
* materials ("Software") is owned by Cypress Semiconductor Corporation
* or one of its affiliates ("Cypress") and is protected by and subject to
* worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ("EULA").
* If no EULA applies, Cypress hereby grants you a personal, non-exclusive,
* non-transferable license to copy, modify, and compile the Software
* source code solely for use in connection with Cypress's
* integrated circuit products.  Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress
* reserves the right to make changes to the Software without notice. Cypress
* does not assume any liability arising out of the application or use of the
* Software or any product or circuit described in the Software. Cypress does
* not authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ("High Risk Product"). By
* including Cypress's product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
*******************************************************************************/

#include "cy_scb_uart.h"
#include "cycfg_peripherals.h"
#include "protocol/protocol.h"
#include "uartd.h"

cy_stc_scb_uart_context_t CYBSP_UART_context;

/*******************************************************************************
* Local Function Prototypes
*******************************************************************************/
static bool _uartd_read(pb_istream_t* stream, pb_byte_t* buf, size_t count);
static bool _uartd_write(pb_ostream_t* stream, const pb_byte_t* buf, size_t count);

/*******************************************************************************
* Functions
*******************************************************************************/

/*******************************************************************************
* Function Name: _uartd_read
********************************************************************************
* Summary:
*   Reads data from the serial interface into the provided buffer.
*   This is called by the protocol engine to receive commands.
*   It returns once 'count' number of bytes are read. 
*   While it is waiting for data it calls protocol_call_device_poll().
*
* Parameters:
*   stream: Pointer to the input stream.
*   buf: Pointer to the buffer where the read data will be stored.
*   count: Number of bytes to read.
*
* Return:
*   True if reading is successful, otherwise false.
*
*******************************************************************************/

/*******************************************************************************
* Some local notes on this.
* Through the protocol_process_request it tries to read 1 byte at a time.
* If there is a byte in the incoming buffer it returns immediately.
* If there is none the while loop blocks until the byte was sent from the host.
* This mean that we cant have the polling request somewhere else since this
* loop will be the main action. Once the protocol_process_request have got
* enough data it returns to the main and is called immediately again and
* thus a new byte will be asked for. In general we really dont have control
* over how frequent this polling will happen. In many cases it will be fast
* enough.
*******************************************************************************/

static bool _uartd_read(pb_istream_t* stream, pb_byte_t* buf, size_t count)
{
	uint32_t bytes_read;

    if (count == 0)
    {
        return true;
    }

    uartd_t *uart = (uartd_t*)stream->state;

    bytes_read = Cy_SCB_UART_GetArray(SCB1, buf, count);
	protocol_call_device_poll(uart->protocol, &uart->ostream);
    while(bytes_read < count) {
		bytes_read += Cy_SCB_UART_GetArray(SCB1, &buf[bytes_read], count-bytes_read);
		if (bytes_read < count) {
			protocol_call_device_poll(uart->protocol, &uart->ostream);
		}
	};

    return true;
}

/*******************************************************************************
* Function Name: _uartd_write
********************************************************************************
* Summary:
*   Writes data from the provided buffer to the serial interface.
*   This is called by the protocol engine as devices are generating data.
*   We don't have to do anything else than writing the buf over our 
*   communication channel (UART in this case).
*
* Parameters:
*   stream: Pointer to the output stream.
*   buf: Pointer to the buffer containing the data to be written.
*   count: Number of bytes to write.
*
* Return:
*   True if writing is successful, otherwise false.
*
*******************************************************************************/
static bool _uartd_write(pb_ostream_t* stream, const pb_byte_t* buf, size_t count)
{
    Cy_SCB_UART_PutArrayBlocking(SCB1, (void *)buf, count);

    return true;
}

/*******************************************************************************
* Function Name: uartd_create
********************************************************************************
* Summary:
*   Creates and initializes a new streaming instance.
*
* Parameters:
*   protocol: Pointer to the protocol handle.
*
* Return:
*   Pointer to the newly created streaming instance.
*
*******************************************************************************/
uartd_t* uartd_create(protocol_t *protocol)
{
    uartd_t* uart = malloc(sizeof(uartd_t));

    if(uart == NULL)
    {
        return NULL;
    }

    uart->protocol = protocol;

	/* Initialize the UART */
	Cy_SCB_UART_Init(SCB1, &scb_1_config, &CYBSP_UART_context);
	Cy_SCB_UART_Enable(SCB1);

    uart->istream = (pb_istream_t){ &_uartd_read, (void*)uart, SIZE_MAX, 0 };
    uart->ostream = (pb_ostream_t){ &_uartd_write, (void*)uart, SIZE_MAX, 0, NULL };

    return uart;
}

/*******************************************************************************
* Function Name: uartd_free
********************************************************************************
* Summary:
*   Frees the allocated resources for the streaming instance.
*
* Parameters:
*   streaming: Pointer to the streaming instance.
*
*******************************************************************************/
void uartd_free(uartd_t* uart)
{
    free(uart);
}

/* [] END OF FILE */
