// >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// ------------------------------------------------------------------
// Copyright (c) 2019-2024 by Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// ------------------------------------------------------------------
//
// IMPORTANT: THIS FILE IS USED BY OR GENERATED BY the LATTICE PROPEL
// DEVELOPMENT SUITE, WHICH INCLUDES PROPEL BUILDER AND PROPEL SDK.
//
// Lattice grants permission to use this code pursuant to the
// terms of the Lattice Propel License Agreement.
//
// DISCLAIMER:
//
//  LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER
//  EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE
//  PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE 
//  SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR
//  FITNESS FOR A PARTICULAR PURPOSE.  LATTICE DOES NOT WARRANT THAT THE
//  FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE'S REQUIREMENTS, OR THAT
//  LICENSEE'S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE
//  OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS
//  HEREIN WILL BE CORRECTED.  LICENSEE ASSUMES RESPONSIBILITY FOR 
//  SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE
//  PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM.  LICENSEE
//  ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE
//  OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL 
//  ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR
//  ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE 
//  SOFTWARE.  IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT,
//  INDIRECT,SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
//  PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF
//  LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE'S
//  SOLE LIABILITY, AND LICENSEE'S SOLE REMEDY, IS SET FORTH ABOVE.  
//  LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR
//  USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY
//  RIGHTS, INCLUDING ANY PATENT. IT IS THE USER'S RESPONSIBILITY TO VERIFY
//  THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE
//  USE OF FORMAL SOFTWARE VALIDATION METHODS.
// ------------------------------------------------------------------

#include "hal.h"
#include "utils.h"
#include <stdio.h>
#include "sys_platform.h"
#include <riscv_errors.h>
#include "i2c_master.h"

struct i2cm_instance i2c_controller_inst;

#ifdef UART_INST_BASE_ADDR
#include "uart.h"

#ifndef _UART_NO_INTERRUPTS_
#include "pic.h"
#endif
#endif

#ifdef GPIO_INST_BASE_ADDR
#include "gpio.h"
struct gpio_instance gpio_inst;
#endif

#if (defined UART_INST_BASE_ADDR)
struct uart_instance uart_core_uart;
#elif (defined LOCAL_UART_INST_BASE_ADDR)
struct local_uart_instance local_uart_core;
#endif

static int lscc_uart_putc(char c, FILE *file)
{
#ifdef LSCC_STDIO_UART_APB
		int ret = EOF;
#if (defined UART_INST_BASE_ADDR)
		ret = uart_putc(&uart_core_uart, c);
		if (c == '\n' && ret == 0)
			ret = uart_putc(&uart_core_uart, '\r');
#elif (defined LOCAL_UART_INST_BASE_ADDR)
		ret = local_uart_putc(&local_uart_core, c);
		if (c == '\n' && ret == 0)
			ret = local_uart_putc(&local_uart_core, '\r');
#endif
		return ret;
#else
		return EOF;
#endif
}


static int lscc_uart_getc(FILE *file)
{
	(void) file;
	return EOF;
}


static int lscc_uart_flush(FILE *file)
{
	(void) file;
	return 0;
}


static void bsp_init(void)
{
#ifdef GPIO_INST_BASE_ADDR
	//initialize GPIO
	gpio_inst.instance_name = GPIO_INST_NAME;
	gpio_init(&gpio_inst, GPIO_INST_BASE_ADDR, GPIO_INST_LINES_NUM, GPIO_INST_GPIO_DIRS);
#endif

#if (defined UART_INST_BASE_ADDR)
#ifndef _UART_NO_INTERRUPTS_
	//setup uart IRQ
	pic_init(CPU0_INST_PICTIMER_START_ADDR);
	uart_core_uart.intrLevel = UART0_INST_IRQ;
	uart_core_uart.intrAvail = true;
	//pic_isr_register(UART0_INST_IRQ, uart_isr, (void *)&uart_core_uart);
#endif

	//initialize UART
	uart_init(&uart_core_uart, UART_INST_BASE_ADDR, UART_INST_SYS_CLK * 1000000, UART_INST_BAUD_RATE, 1, 8);
#elif (defined LOCAL_UART_INST_BASE_ADDR)
    local_uart_init(&local_uart_core, LOCAL_UART_INST_BASE_ADDR, CPU0_INST_SYS_CLOCK_FREQ * 1000000, CPU0_INST_BAUD_RATE, 1, 8);
#endif
	iob_init(lscc_uart_putc, lscc_uart_getc, lscc_uart_flush);
	trap_init();

	//###################################
	//#####   I2C Controller Initilization and Configuration
	//###################################
	i2c_controller_inst.instance_name = I2C_C0_INST_NAME;
	i2c_master_init(&i2c_controller_inst, I2C_C0_INST_BASE_ADDR);
	i2c_master_config(&i2c_controller_inst, I2C_9548_ADDR_MODE, I2C_C0_INST_INTERRUPT_EN, I2C_C0_INST_PRESCALER);
}


int main(void) {
	bsp_init();

	printf("Started!\nHello RISC-V world!\n"); 

	//Buffers
	uint8_t rx_buffer; //rx buffer
	uint8_t tx_buffer; //tx buffer
	uint8_t tx_buffer_16;

	//###################################
	//#####   TCA9548
	//###################################

	tx_buffer = 0x08; // TCA9548 -> CH03
	i2c_master_write(&i2c_controller_inst, 0x70, 1, &tx_buffer);
	printf("SELECTING CH3 (0x08) of TCA9548 MUX IC (0x70)\n\n", rx_buffer);

	//###################################
	//#####   TCA9555
	//###################################
	tx_buffer = 0x02; // Control Register -> Output Port 0
	for(int i = 0; i < 3; i++) {
		i2c_master_repeated_start(&i2c_controller_inst, 0x20, 1, &tx_buffer, 1, &rx_buffer);
		printf("READ Output Port 0 TCA9555 MUX IC (0x20): %2p - READ %d\n", rx_buffer, i);
	}

	printf("\n");

	//Note: Example, given data size 2 and data in buffer is 0xF706,
	//it will transfer 0x06 followed by 0xF7.
	//Max width of a given memory address is 1Byte,
	//so 2Byte variable automatically reserves 2 memory address (pointer addr and + 1).

	tx_buffer_16 = 0xF706; // Control Register -> Configuration Port 0 -> Set QSFP_LPMODE pin to output mode.
	i2c_master_write(&i2c_controller_inst, 0x20, 2, &tx_buffer_16);

	tx_buffer_16 = 0xF702; // Output Port 0 -> Set QSFP_LPMODE pin to drive '0'
	i2c_master_write(&i2c_controller_inst, 0x20, 2, &tx_buffer_16);

	tx_buffer = 0x02; // Control Register -> Output Port 0
	for(int i = 0; i < 3; i++) {
		i2c_master_repeated_start(&i2c_controller_inst, 0x20, 1, &tx_buffer, 1, &rx_buffer);
		printf("READ Output Port 0 TCA9555 MUX IC (0x20): %2p - READ %d\n", rx_buffer, i);
	}

	printf("Program ended\n\n");

	return 0;
}

