/*
 ===============================================================================
 Name        : main.c
 Author      : $(author)
 Version     :
 Copyright   : $(copyright)
 Description : main definition
 ===============================================================================
 */

#include <cr_section_macros.h>

#include <stdio.h>

#include <string.h>

#include "board.h"

#include "scheduler.h"

#include "gram_usb_cdc_api.h"

#include "gram_pwm_adc_sampling.h"

#include "gram_beep.h"

#include "gram_buffer.h"

#include "gram_aux.h"

#include "gram_fft.h"

#include "gram_motor_control.h"

#include "tictoc.h"


#include "lwip/init.h"
#include "lwip/opt.h"

#include "lwipopts.h"

#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/tcpip.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/timers.h"
#include "netif/etharp.h"


#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif

#include "lpc_phy.h"
#include "arch/lpc17xx_40xx_emac.h"
#include "arch/lpc_arch.h"
#include "echo.h"

#define TICKRATE_HZ			(1000)		// systick interrupt frequency

/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/

uint8_t buf_str[128];				// Buffer used for string operations

/* NETIF data */
static struct netif lpc_netif;

/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/

/*****************************************************************************
 * Private functions
 ****************************************************************************/

/*****************************************************************************
 * Public functions
 ****************************************************************************/

uint16_t timer_btn_a;
uint16_t timer_btn_b;

void EINT3_IRQHandler(void)
{
	if ( Chip_GPIOINT_GetStatusFalling(LPC_GPIOINT, GPIOINT_PORT2) & (1UL << BTN_A_GPIO_BIT_NUM) ){
		Chip_GPIOINT_ClearIntStatus(LPC_GPIOINT, GPIOINT_PORT2, 1UL << BTN_A_GPIO_BIT_NUM);
		LPC_GPIOINT->IO2.ENR &= ~(1UL << BTN_A_GPIO_BIT_NUM);	// Disable this interrupt
		ResetDelay(&timer_btn_a);	// Start timer to enable interrupt
		Board_LED_Toggle(LEDS_LED_B);
	}
	if ( Chip_GPIOINT_GetStatusFalling(LPC_GPIOINT, GPIOINT_PORT2) & (1UL << BTN_B_GPIO_BIT_NUM) ){
		Chip_GPIOINT_ClearIntStatus(LPC_GPIOINT, GPIOINT_PORT2, 1UL << BTN_B_GPIO_BIT_NUM);
		LPC_GPIOINT->IO2.ENR &= ~(1UL << BTN_B_GPIO_BIT_NUM);	// Disable this interrupt
		ResetDelay(&timer_btn_b);	// Start timer to enable interrupt
		Board_LED_Toggle(LEDS_LED_B);
	}

	//Board_LED_Toggle(0);
}

/*void SysTick_Handler(void) {
	TickCounter++;
}*/

void task_1s(void) {

}

int main(void) {

	uint32_t physts;
	ip_addr_t ipaddr, netmask, gw;
	static int prt_ip = 0;

	// Read clock settings and update SystemCoreClock variable
	SystemCoreClockUpdate();
	// Initialize GPIO, Buttons, LEDs...
	Board_Init();

	SysTick_Enable(1);

	// Initizlize USB stack

	usb_init();

	// Initialize USB Simple Packet Protocol

	USB_SPP_Init();

	// Initialize stopwatch module
	TicTocInit(LPC_TIMER3);
	// Initialize systick
	//SysTick_Config(SystemCoreClock / TICKRATE_HZ);


	// Enable GPIO interrupts on BTN1 and BTN2
	Chip_GPIOINT_SetIntFalling(LPC_GPIOINT, GPIOINT_PORT2, 1 << BTN_A_GPIO_BIT_NUM);
	Chip_GPIOINT_SetIntFalling(LPC_GPIOINT, GPIOINT_PORT2, 1 << BTN_B_GPIO_BIT_NUM);
	NVIC_ClearPendingIRQ(EINT3_IRQn);
	NVIC_EnableIRQ(EINT3_IRQn);	// EINT3 is shared with GPIO interrupts


	// Initialize LWIP
	lwip_init();

	// Static IP assignment
#if LWIP_DHCP
	IP4_ADDR(&gw, 0, 0, 0, 0);
	IP4_ADDR(&ipaddr, 0, 0, 0, 0);
	IP4_ADDR(&netmask, 0, 0, 0, 0);
#else
	IP4_ADDR(&gw, 10, 1, 10, 1);
	IP4_ADDR(&ipaddr, 10, 1, 10, 234);
	IP4_ADDR(&netmask, 255, 255, 255, 0);
	//APP_PRINT_IP(&ipaddr);
#endif

	// Add netif interface for lpc17xx_8x
	netif_add(&lpc_netif, &ipaddr, &netmask, &gw, NULL, lpc_enetif_init,
			  ethernet_input);
	netif_set_default(&lpc_netif);
	netif_set_up(&lpc_netif);

#if LWIP_DHCP
	dhcp_start(&lpc_netif);
#endif

	// Initialize and start application
	echo_init();

	// Scheduler counters
	uint16_t timer_led_a;
	ResetDelay(&timer_led_a);
	uint16_t timer_1s_task;
	ResetDelay(&timer_1s_task);

	Chip_GPIO_SetPinDIR(LPC_GPIO, 0, 0, 1);
	Chip_GPIO_SetPinDIR(LPC_GPIO, 0, 1, 1);
	Chip_GPIO_SetPinDIR(LPC_GPIO, 1, 19, 1);
	Chip_GPIO_SetPinDIR(LPC_GPIO, 1, 20, 1);
	// set direction of motor rotation
	Chip_GPIO_SetPinState(LPC_GPIO, 1, 19, 0);
	Chip_GPIO_SetPinState(LPC_GPIO, 1, 20, 1);


	while (1) {
		// LED blinky task
		if (HasDelayElapsed(500, &timer_led_a, true))
			Board_LED_Toggle(LEDS_LED_A);
		// 1s periodic task for whatever
		if (HasDelayElapsed(1000, &timer_1s_task, true))
			task_1s();
		if ( !(Chip_GPIOINT_GetIntFalling(LPC_GPIOINT, GPIOINT_PORT2) & 1<<BTN_A_GPIO_BIT_NUM) && HasDelayElapsed(50, &timer_btn_a, false) )
			Chip_GPIOINT_SetIntFalling(LPC_GPIOINT, GPIOINT_PORT2, 1 << BTN_A_GPIO_BIT_NUM);
		if ( !(Chip_GPIOINT_GetIntFalling(LPC_GPIOINT, GPIOINT_PORT2) & 1<<BTN_B_GPIO_BIT_NUM) && HasDelayElapsed(50, &timer_btn_b, false) )
			Chip_GPIOINT_SetIntFalling(LPC_GPIOINT, GPIOINT_PORT2, 1 << BTN_B_GPIO_BIT_NUM);
		USB_SPP_task();










		/* Handle packets as part of this loop, not in the IRQ handler */
		lpc_enetif_input(&lpc_netif);

		/* lpc_rx_queue will re-qeueu receive buffers. This normally occurs
		   automatically, but in systems were memory is constrained, pbufs
		   may not always be able to get allocated, so this function can be
		   optionally enabled to re-queue receive buffers. */
#if 0
		while (lpc_rx_queue(&lpc_netif)) {}
#endif

		/* Free TX buffers that are done sending */
		lpc_tx_reclaim(&lpc_netif);

		/* LWIP timers - ARP, DHCP, TCP, etc. */
		sys_check_timeouts();

		/* Call the PHY status update state machine once in a while
		   to keep the link status up-to-date */
		physts = lpcPHYStsPoll();

		/* Only check for connection state when the PHY status has changed */
		if (physts & PHY_LINK_CHANGED) {
			if (physts & PHY_LINK_CONNECTED) {
				Board_LED_Set(LEDS_LED_B, true);
				prt_ip = 0;

				/* Set interface speed and duplex */
				if (physts & PHY_LINK_SPEED100) {
					Chip_ENET_Set100Mbps(LPC_ETHERNET);
					NETIF_INIT_SNMP(&lpc_netif, snmp_ifType_ethernet_csmacd, 100000000);
				}
				else {
					Chip_ENET_Set10Mbps(LPC_ETHERNET);
					NETIF_INIT_SNMP(&lpc_netif, snmp_ifType_ethernet_csmacd, 10000000);
				}
				if (physts & PHY_LINK_FULLDUPLX) {
					Chip_ENET_SetFullDuplex(LPC_ETHERNET);
				}
				else {
					Chip_ENET_SetHalfDuplex(LPC_ETHERNET);
				}

				netif_set_link_up(&lpc_netif);
			}
			else {
				Board_LED_Set(LEDS_LED_B, false);
				netif_set_link_down(&lpc_netif);
			}

			//DEBUGOUT("Link connect status: %d\r\n", ((physts & PHY_LINK_CONNECTED) != 0));
			sprintf((char *) buf_str, (char *) "Link connect status: %d\r\n",	((physts & PHY_LINK_CONNECTED) != 0));
			usb_printstr(buf_str);
		}

		/* Print IP address info */
		if (!prt_ip) {
			if (lpc_netif.ip_addr.addr) {
				static char tmp_buff[16];
				/*DEBUGOUT("IP_ADDR    : %s\r\n", ipaddr_ntoa_r((const ip_addr_t *) &lpc_netif.ip_addr, tmp_buff, 16));
				DEBUGOUT("NET_MASK   : %s\r\n", ipaddr_ntoa_r((const ip_addr_t *) &lpc_netif.netmask, tmp_buff, 16));
				DEBUGOUT("GATEWAY_IP : %s\r\n", ipaddr_ntoa_r((const ip_addr_t *) &lpc_netif.gw, tmp_buff, 16));*/
				sprintf((char *) buf_str, (char *) "IP_ADDR    : %s\r\n",	ipaddr_ntoa_r((const ip_addr_t *) &lpc_netif.ip_addr, tmp_buff, 16) );
				usb_printstr(buf_str);
				sprintf((char *) buf_str, (char *) "NET_MASK   : %s\r\n",	ipaddr_ntoa_r((const ip_addr_t *) &lpc_netif.netmask, tmp_buff, 16) );
				usb_printstr(buf_str);
				sprintf((char *) buf_str, (char *) "GATEWAY_IP : %s\r\n",	ipaddr_ntoa_r((const ip_addr_t *) &lpc_netif.gw, tmp_buff, 16));
				usb_printstr(buf_str);
				prt_ip = 1;
			}
		}


	}
	return 0;
}

 // 5,31 - piezo
 // 6,30 - current
 // 7,32 - FFT piezo
