/******************************************************************************
* File Name: main.c
*
* Description: This is the source code for the PSoC 4 MSC CapSense 
* signals processing with Neural Networks.
*
* Related Document: See README.md
*
*******************************************************************************
* Copyright 2021-2023, 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 header files
 ******************************************************************************/
#include "cy_pdl.h"
#include "cybsp.h"
#include "cycfg.h"
#include "cycfg_capsense.h"

#include "button_nn.h"
#include "position_nn.h"
#include "gestures_nn.h"

/*******************************************************************************
* Macros
*******************************************************************************/
#define CAPSENSE_MSC0_INTR_PRIORITY      (3u)
#define CAPSENSE_MSC1_INTR_PRIORITY      (3u)
#define CY_ASSERT_FAILED                 (0u)
#define MSC_CAPSENSE_WIDGET_INACTIVE     (0u)

/* EZI2C interrupt priority must be higher than CapSense interrupt. */
#define EZI2C_INTR_PRIORITY              (2u)

#define CYBSP_UART_HW                    (SCB1)
#define tcpwm_0_cnt_6_CNT                ((TCPWM_CNT_Type*) &tcpwm_0_cnt_6_HW->CNT[tcpwm_0_cnt_6_NUM])
#define tcpwm_0_cnt_7_CNT                ((TCPWM_CNT_Type*) &tcpwm_0_cnt_7_HW->CNT[tcpwm_0_cnt_7_NUM])
#define PWM_MAX_VALUE                    (32000)

/* IIR filter coefficients for position filtering */
#define IIR_FILTER_SHIFT                (8u)
#define IIR_POSITION_SHIFT              (2u)

/* Sizes of arrays used with NN models */
#define BTN_NN_OUT_SIZE                 (2u)
#define POS_NN_IN_SIZE                  (8u)
#define GEST_NN_OUT_SIZE                (3u)

/* Thresholds that define hysteresis for button on/off */
#define BTN_TRESH_ON                   (0.9)
#define BTN_TRESH_OFF                  (0.89)


/* return values from Imagimob generated code */
#define IPWIN_RET_SUCCESS               (0)
#define IPWIN_RET_NODATA                (-1)

/*******************************************************************************
* Global Variables
********************************************************************************/
cy_stc_scb_ezi2c_context_t ezi2c_context;
cy_stc_scb_uart_context_t CYBSP_UART_context;
#if CY_CAPSENSE_BIST_EN
/* Variables to hold sensor parasitic capacitances and status*/
uint32_t button0_cp = 0, button1_cp = 0;
cy_en_capsense_bist_status_t button0_cp_status, button1_cp_status;
#endif /* CY_CAPSENSE_BIST_EN */

/*******************************************************************************
* Function Prototypes
*******************************************************************************/
static void initialize_capsense(void);
static void capsense_msc0_isr(void);
static void capsense_msc1_isr(void);
static void ezi2c_isr(void);
static void initialize_capsense_tuner(void);
void setBrightness(uint32_t brightness, uint8_t pwmNum);
void sendVisualizationString(CySCB_Type *base, uint32_t n);

#if CY_CAPSENSE_BIST_EN
static void measure_sensor_cp(void);
#endif /* CY_CAPSENSE_BIST_EN */

const cy_stc_scb_uart_config_t CYBSP_UART_config =
{
    .uartMode = CY_SCB_UART_STANDARD,
    .enableMutliProcessorMode = false,
    .smartCardRetryOnNack = false,
    .irdaInvertRx = false,
    .irdaEnableLowPowerReceiver = false,
    .enableLinMode = false,
    .oversample = 8,
    .enableMsbFirst = false,
    .dataWidth = 8UL,
    .parity = CY_SCB_UART_PARITY_NONE,
    .stopBits = CY_SCB_UART_STOP_BITS_1,
    .enableInputFilter = false,
    .breakWidth = 11UL,
    .breakLevel = false,
    .dropOnFrameError = false,
    .dropOnParityError = false,
    .receiverAddress = 0x0UL,
    .receiverAddressMask = 0x0UL,
    .acceptAddrInFifo = false,
    .enableCts = false,
    .ctsPolarity = CY_SCB_UART_ACTIVE_LOW,
    .rtsRxFifoLevel = 0UL,
    .rtsPolarity = CY_SCB_UART_ACTIVE_LOW,
    .rxFifoTriggerLevel = 7UL,
    .rxFifoIntEnableMask = 0UL,
    .txFifoTriggerLevel = 7UL,
    .txFifoIntEnableMask = 0UL,
};


/*******************************************************************************
* Function Name: main
********************************************************************************
* Summary:
*  System entrance point. This function performs
*  - initial setup of device
*  - initialize CapSense
*  - perform Cp measurement if Built-in Self test (BIST) is enabled
*  - initialize tuner communication
*  - scan touch input continuously
*
* Return:
*  int
*
*******************************************************************************/

int main(void)
{
	cy_rslt_t result = CY_RSLT_SUCCESS;
	int32_t idxSns;

	float button_signal;
	float button_nn_out[BTN_NN_OUT_SIZE] = {0};
	float position_nn_in[POS_NN_IN_SIZE] = {0};
	float position_nn_out;
	float position_filtered;
	float gestures_nn_out[GEST_NN_OUT_SIZE] = {0};

	uint8_t filter_idx = 0;
	int32_t positionFiltScaled = 0;

	int slider_mode = 1; // 1 for gesture mode, 0 for position mode
	uint32_t prev_widget_status = 0;
	uint16_t classical_alg_pos;

	BTN_NN_init();
	POS_NN_init();
	GES_NN_init();

	/* Initialize the device and board peripherals */
	result = cybsp_init();

	/* Board init failed. Stop program execution */
	if (result != CY_RSLT_SUCCESS)
	{
		CY_ASSERT(CY_ASSERT_FAILED);
	}

	/* Enable global interrupts */
	__enable_irq();

	/* Initialize PWM using the config structure generated using device configurator*/
	if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(tcpwm_0_cnt_6_HW, tcpwm_0_cnt_6_NUM, &tcpwm_0_cnt_6_config))
	{
		CY_ASSERT(0);
	}
	if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(tcpwm_0_cnt_7_HW, tcpwm_0_cnt_7_NUM, &tcpwm_0_cnt_7_config))
	{
		CY_ASSERT(0);
	}

	/* Enable the initialized PWM */
	Cy_TCPWM_PWM_Enable(tcpwm_0_cnt_6_HW, tcpwm_0_cnt_6_NUM);
	Cy_TCPWM_PWM_Enable(tcpwm_0_cnt_7_HW, tcpwm_0_cnt_7_NUM);

	/* Start the PWM */
	Cy_TCPWM_TriggerReloadOrIndex(tcpwm_0_cnt_6_HW, tcpwm_0_cnt_6_MASK);
	Cy_TCPWM_TriggerReloadOrIndex(tcpwm_0_cnt_7_HW, tcpwm_0_cnt_7_MASK);

	/* Initialize EZI2C */
	initialize_capsense_tuner();

	/* Initialize MSC CapSense */
	initialize_capsense();

#if CY_CAPSENSE_BIST_EN
	/* Measure the self capacitance of sensor electrode using BIST */
	measure_sensor_cp();
#endif /* CY_CAPSENSE_BIST_EN */

	/* Initialize the UART */
	Cy_SCB_UART_Init(CYBSP_UART_HW, &CYBSP_UART_config, &CYBSP_UART_context);

	Cy_SCB_UART_Enable(CYBSP_UART_HW);

	/* Start the first scan */
	Cy_CapSense_ScanAllSlots(&cy_capsense_context);

	setBrightness(0, tcpwm_0_cnt_6_NUM);
	setBrightness(0, tcpwm_0_cnt_7_NUM);

	if (slider_mode == 1) {
		/* Light up the slider mode indicator LED*/
		Cy_GPIO_Write(CYBSP_USER_LED_PORT, CYBSP_USER_LED_NUM, CYBSP_LED_STATE_ON);
	}

	for (;;)
	{
		/* Start the next scan */
		Cy_CapSense_ScanAllSlots(&cy_capsense_context);
		while(CY_CAPSENSE_NOT_BUSY != Cy_CapSense_IsBusy(&cy_capsense_context)) {}

		/* Changing slider mode (POSITION/GESTURES) */
		if(MSC_CAPSENSE_WIDGET_INACTIVE != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_BUTTON1_WDGT_ID, &cy_capsense_context)){
			prev_widget_status = 1;
		}else{
			if (prev_widget_status==1){
				if (slider_mode==0){
					slider_mode = 1;
					Cy_GPIO_Write(CYBSP_USER_LED_PORT, CYBSP_USER_LED_NUM, CYBSP_LED_STATE_ON);
				}else{
					slider_mode = 0;
					Cy_GPIO_Write(CYBSP_USER_LED_PORT, CYBSP_USER_LED_NUM, CYBSP_LED_STATE_OFF);
				}
			}
			prev_widget_status = 0;
		}

		/* CAPSENSE processing */
		/* copy data for dummy slider */
		for (idxSns = cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDERML_WDGT_ID].numSns; idxSns-- != 0;)
		{
			cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDERML_WDGT_ID].ptrSnsContext[idxSns].raw = cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDER0_WDGT_ID].ptrSnsContext[idxSns].raw;
		}
		for (idxSns = cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDERML_WDGT_ID].numSns; idxSns-- != 0;)
		{
			position_nn_in[idxSns] = cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDER0_WDGT_ID].ptrSnsContext[idxSns].diff;
		}
		/* Process all widgets */
		Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);
		cy_capsense_context.ptrWdConfig[CY_CAPSENSE_BUTTONML_WDGT_ID].ptrSnsContext[0].status = 30;

		/* Process gesture for the widget */
		Cy_CapSense_DecodeWidgetGestures(CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context);

		cy_capsense_context.ptrWdContext[CY_CAPSENSE_LINEARSLIDERML_WDGT_ID].wdTouch.ptrPosition[0u].x = cy_capsense_context.ptrWdContext[CY_CAPSENSE_LINEARSLIDER0_WDGT_ID].wdTouch.ptrPosition[0u].x;

		if(MSC_CAPSENSE_WIDGET_INACTIVE == Cy_CapSense_IsWidgetActive(CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context) && MSC_CAPSENSE_WIDGET_INACTIVE == Cy_CapSense_IsWidgetActive(CY_CAPSENSE_BUTTON0_WDGT_ID, &cy_capsense_context)){
			setBrightness(0, tcpwm_0_cnt_6_NUM);
			setBrightness(0, tcpwm_0_cnt_7_NUM);
		}

		/* Button NN  */
		button_signal = cy_capsense_context.ptrWdConfig[CY_CAPSENSE_BUTTON0_WDGT_ID].ptrSnsContext[0].diff;
		BTN_NN_enqueue(&button_signal);
		if (IPWIN_RET_NODATA != BTN_NN_dequeue(button_nn_out)){
			if (button_nn_out[1] > BTN_TRESH_ON){
				setBrightness(PWM_MAX_VALUE, tcpwm_0_cnt_6_NUM);
				cy_capsense_context.ptrWdConfig[CY_CAPSENSE_BUTTONML_WDGT_ID].ptrSnsContext[0].status = 31;
			}

			if (button_nn_out[0] > BTN_TRESH_OFF) {
				if (MSC_CAPSENSE_WIDGET_INACTIVE == Cy_CapSense_IsWidgetActive(CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context)) {
					setBrightness(0, tcpwm_0_cnt_6_NUM);
					cy_capsense_context.ptrWdConfig[CY_CAPSENSE_BUTTONML_WDGT_ID].ptrSnsContext[0].status = 30;
				}
			}
		}

		/* Button classical algorithm */
		if (MSC_CAPSENSE_WIDGET_INACTIVE != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_BUTTON0_WDGT_ID, &cy_capsense_context)) {
			setBrightness(PWM_MAX_VALUE, tcpwm_0_cnt_7_NUM);
		}

		/* Position classical algorithm */
		classical_alg_pos = cy_capsense_context.ptrWdContext[CY_CAPSENSE_LINEARSLIDER0_WDGT_ID].wdTouch.ptrPosition[0u].x;

		/* Position NN */
		POS_NN_compute(position_nn_in, &position_nn_out);

		/* Position filtering */
		if(MSC_CAPSENSE_WIDGET_INACTIVE != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_LINEARSLIDERML_WDGT_ID, &cy_capsense_context)){
			if (filter_idx == 0)
			{
				positionFiltScaled = (uint32_t)position_nn_out << IIR_FILTER_SHIFT;
				filter_idx++;
			}
			else{
				positionFiltScaled += ((uint32_t)position_nn_out << (IIR_FILTER_SHIFT - IIR_POSITION_SHIFT)) - (positionFiltScaled >> IIR_POSITION_SHIFT);
				cy_capsense_context.ptrWdContext[CY_CAPSENSE_LINEARSLIDERML_WDGT_ID].wdTouch.ptrPosition[0u].x = (uint16_t)(positionFiltScaled >> IIR_FILTER_SHIFT);
				position_filtered = cy_capsense_context.ptrWdContext[CY_CAPSENSE_LINEARSLIDERML_WDGT_ID].wdTouch.ptrPosition[0u].x;
			}
		}else{
			filter_idx = 0;
		}

		if (slider_mode == 0) {
			if (MSC_CAPSENSE_WIDGET_INACTIVE != Cy_CapSense_IsWidgetActive(CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context)) {
				setBrightness(cy_capsense_context.ptrWdContext[CY_CAPSENSE_LINEARSLIDERML_WDGT_ID].wdTouch.ptrPosition[0u].x, tcpwm_0_cnt_6_NUM);
				setBrightness(classical_alg_pos, tcpwm_0_cnt_7_NUM);
			}
		}

		/* Gestures NN */
		if (slider_mode == 1) {
			if(MSC_CAPSENSE_WIDGET_INACTIVE == Cy_CapSense_IsWidgetActive(CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context)){
				GES_NN_init();
			}

			GES_NN_enqueue(&position_filtered);

			if (IPWIN_RET_NODATA != GES_NN_dequeue(gestures_nn_out)){
				if (gestures_nn_out[1] > gestures_nn_out[2] && gestures_nn_out[1] >gestures_nn_out[0] ){
					setBrightness(PWM_MAX_VALUE, tcpwm_0_cnt_7_NUM);
					setBrightness(0, tcpwm_0_cnt_6_NUM);
				}
				if (gestures_nn_out[2] > gestures_nn_out[1] && gestures_nn_out[2] >gestures_nn_out[0]  ){
					setBrightness(PWM_MAX_VALUE, tcpwm_0_cnt_6_NUM);
					setBrightness(0, tcpwm_0_cnt_7_NUM);
				}
			}
		}

		/* Establishes synchronized communication with the CapSense Tuner tool */
		Cy_CapSense_RunTuner(&cy_capsense_context);
	}
}


/*******************************************************************************
* Function Name: initialize_capsense
********************************************************************************
* Summary:
*  This function initializes the CapSense and configures the CapSense
*  interrupt.
*
*******************************************************************************/
static void initialize_capsense(void)
{
    cy_capsense_status_t status = CY_CAPSENSE_STATUS_SUCCESS;

    /* CapSense interrupt configuration MSC 0 */
    const cy_stc_sysint_t capsense_msc0_interrupt_config =
    {
        .intrSrc = CY_MSC0_IRQ,
        .intrPriority = CAPSENSE_MSC0_INTR_PRIORITY,
    };

    /* CapSense interrupt configuration MSC 1 */
    const cy_stc_sysint_t capsense_msc1_interrupt_config =
    {
        .intrSrc = CY_MSC1_IRQ,
        .intrPriority = CAPSENSE_MSC1_INTR_PRIORITY,
    };

    /* Capture the MSC HW block and initialize it to the default state. */
    status = Cy_CapSense_Init(&cy_capsense_context);

    if (CY_CAPSENSE_STATUS_SUCCESS == status)
    {
        /* Initialize CapSense interrupt for MSC 0 */
        Cy_SysInt_Init(&capsense_msc0_interrupt_config, capsense_msc0_isr);
        NVIC_ClearPendingIRQ(capsense_msc0_interrupt_config.intrSrc);
        NVIC_EnableIRQ(capsense_msc0_interrupt_config.intrSrc);

        /* Initialize CapSense interrupt for MSC 1 */
        Cy_SysInt_Init(&capsense_msc1_interrupt_config, capsense_msc1_isr);
        NVIC_ClearPendingIRQ(capsense_msc1_interrupt_config.intrSrc);
        NVIC_EnableIRQ(capsense_msc1_interrupt_config.intrSrc);

        /* Initialize the CapSense firmware modules. */
        status = Cy_CapSense_Enable(&cy_capsense_context);
    }

    if(status != CY_CAPSENSE_STATUS_SUCCESS)
    {
        /* This status could fail before tuning the sensors correctly.
         * Ensure that this function passes after the CapSense sensors are tuned
         * as per procedure give in the Readme.md file */
    }
}


/*******************************************************************************
* Function Name: capsense_msc0_isr
********************************************************************************
* Summary:
*  Wrapper function for handling interrupts from CapSense MSC0 block.
*
*******************************************************************************/
static void capsense_msc0_isr(void)
{
    Cy_CapSense_InterruptHandler(CY_MSC0_HW, &cy_capsense_context);
}


/*******************************************************************************
* Function Name: capsense_msc1_isr
********************************************************************************
* Summary:
*  Wrapper function for handling interrupts from CapSense MSC1 block.
*
*******************************************************************************/
static void capsense_msc1_isr(void)
{
    Cy_CapSense_InterruptHandler(CY_MSC1_HW, &cy_capsense_context);
}


/*******************************************************************************
* Function Name: initialize_capsense_tuner
********************************************************************************
* Summary:
* EZI2C module to communicate with the CapSense Tuner tool.
*
*******************************************************************************/
static void initialize_capsense_tuner(void)
{
    cy_en_scb_ezi2c_status_t status = CY_SCB_EZI2C_SUCCESS;

    /* EZI2C interrupt configuration structure */
    const cy_stc_sysint_t ezi2c_intr_config =
    {
        .intrSrc = CYBSP_EZI2C_IRQ,
        .intrPriority = EZI2C_INTR_PRIORITY,
    };

    /* Initialize the EzI2C firmware module */
    status = Cy_SCB_EZI2C_Init(CYBSP_EZI2C_HW, &CYBSP_EZI2C_config, &ezi2c_context);

    if(status != CY_SCB_EZI2C_SUCCESS)
    {
        CY_ASSERT(CY_ASSERT_FAILED);
    }

    Cy_SysInt_Init(&ezi2c_intr_config, ezi2c_isr);
    NVIC_EnableIRQ(ezi2c_intr_config.intrSrc);

    /* Set the CapSense data structure as the I2C buffer to be exposed to the
     * master on primary slave address interface. Any I2C host tools such as
     * the Tuner or the Bridge Control Panel can read this buffer but you can
     * connect only one tool at a time.
     */
    Cy_SCB_EZI2C_SetBuffer1(CYBSP_EZI2C_HW, (uint8_t *)&cy_capsense_tuner,
                            sizeof(cy_capsense_tuner), sizeof(cy_capsense_tuner),
                            &ezi2c_context);

    Cy_SCB_EZI2C_Enable(CYBSP_EZI2C_HW);
}


/*******************************************************************************
* Function Name: ezi2c_isr
********************************************************************************
* Summary:
* Wrapper function for handling interrupts from EZI2C block.
*
*******************************************************************************/
static void ezi2c_isr(void)
{
    Cy_SCB_EZI2C_Interrupt(CYBSP_EZI2C_HW, &ezi2c_context);
}


#if CY_CAPSENSE_BIST_EN
/*******************************************************************************
* Function Name: measure_sensor_cp
********************************************************************************
* Summary:
*  Measures the self capacitance of the sensor electrode (Cp) in Femto Farad and
*  stores its value in the variable button0_cp and button1_cp.
*
*******************************************************************************/
static void measure_sensor_cp(void)
{
    /* Measure the self capacitance of sensor 0 electrode */
    button0_cp_status = Cy_CapSense_MeasureCapacitanceSensorElectrode(CY_CAPSENSE_BUTTON0_WDGT_ID,
                                                  CY_CAPSENSE_BUTTON0_SNS0_ID, &cy_capsense_context);
    button0_cp = cy_capsense_context.ptrWdConfig[CY_CAPSENSE_BUTTON0_WDGT_ID].ptrEltdCapacitance[CY_CAPSENSE_BUTTON0_SNS0_ID];

    /* Measure the self capacitance of sensor 1 electrode */
    button1_cp_status = Cy_CapSense_MeasureCapacitanceSensorElectrode(CY_CAPSENSE_BUTTON1_WDGT_ID,
                                                  CY_CAPSENSE_BUTTON1_SNS0_ID, &cy_capsense_context);
    button1_cp = cy_capsense_context.ptrWdConfig[CY_CAPSENSE_BUTTON1_WDGT_ID].ptrEltdCapacitance[CY_CAPSENSE_BUTTON1_SNS0_ID];
}
#endif /* CY_CAPSENSE_BIST_EN */

void setBrightness(uint32_t brightness, uint8_t pwmNum)
{
	brightness = 160 * brightness;
    if (brightness > PWM_MAX_VALUE)
    {
        brightness = PWM_MAX_VALUE;
    }

    if (pwmNum == tcpwm_0_cnt_6_NUM)
    {
    	Cy_TCPWM_PWM_SetCompare0(tcpwm_0_cnt_6_HW, tcpwm_0_cnt_6_NUM, brightness);
    }
    else
    {
    	Cy_TCPWM_PWM_SetCompare0(tcpwm_0_cnt_7_HW, tcpwm_0_cnt_7_NUM, brightness);
    }
}

void sendVisualizationString(CySCB_Type *base, uint32_t n)
{
    char visualizationString[103];
    uint32_t i;

    n = (n > 100) ? 100 : n;

    for(i = 0; i < n; ++i)
    {
        visualizationString[i] = '#';
    }

    for(; i < 100; ++i)
    {
        visualizationString[i] = '_';
    }

    visualizationString[100] = '\r';
    visualizationString[101] = '\n';

    visualizationString[102] = '\0';

    Cy_SCB_UART_PutString(base, visualizationString);
}
/* [] END OF FILE */
