//#include <stdint.h>
//#include <inttypes.h>
//#include <stdio.h>
//#include <stdlib.h>
#include <avr/io.h>
#include "topology.h"

#include "COM.h"
#include <avr/boot.h>
#include <avr/pgmspace.h>

//#include <avr/interrupt.h>

#include <util/delay_basic.h>

#undef IS_VECTOR_NODE

//activate this define to show transfer errors. recommendation: do not activate this feature in a big network
//#define SHOW_TRANSFER_ERRORS 1


//#define nop() __asm volatile ("nop")

void boot_program_page (uint32_t page, uint8_t *buf);


//see boot.h
    void boot_program_page (uint32_t page, uint8_t *buf)
    {
        uint16_t i;
        //uint8_t sreg;
        

        // Disable interrupts.

        //sreg = SREG;
        //cli();
    
        eeprom_busy_wait ();

        boot_page_erase (page);
        boot_spm_busy_wait ();      // Wait until the memory is erased.

        for (i=0; i<SPM_PAGESIZE; i+=2)
        {
            // Set up little-endian word.

            uint16_t w = *buf++;
            w += (*buf++) << 8;
                    
            boot_page_fill (page + i, w);
        }

        boot_page_write (page);     // Store buffer in flash page.
        boot_spm_busy_wait();       // Wait until the memory is written.

        // Reenable RWW-section again. We need this if we want to jump back
        // to the application after bootloading.

        //boot_rww_enable ();

        // Re-enable interrupts (if they were ever enabled).
	
        //SREG = sreg;
    }


int main(void)
{
	volatile uint16_t z;
	volatile uint8_t b1;
	//volatile uint8_t destination;
	
	uint8_t b2;	
	uint8_t pagenumber;
	uint8_t myPage[SPM_PAGESIZE];
	uint8_t bytecounter;
	uint8_t c;
	uint8_t d;
	//uint8_t e;
	uint8_t started;	
	uint8_t retransmitAllowed;
	
	uint8_t connections;//bit7..0: SNEWSNEW - first nibble says: vector present, second says: normal neighbour present
	
	uint8_t r;
	uint16_t totalbytes;
	volatile uint8_t loading;
	//uint8_t oldSREG;
	uint8_t* address = (uint8_t*) EEPROM_VECTOR_ADDRESS;
	
	void (*ptr_putc) (uint8_t data);
	uint8_t (*ptr_getc) (void);
	
	
	//uint8_t calibrationValue;//the calibration value for the RC calibration from the eeprom
	//calibrationValue = eeprom_read_byte(0x01ff); /* the AVR053 application note stores the calibration value at this address */
	/*
	calibrationValue = eeprom_read_byte(0); // calibration value is stored in first byte of eeprom
    if(calibrationValue != 0xff){
        OSCCAL = calibrationValue;
    }
	*/
	
	//oldSREG = SREG;
	cli();
	
	connections = eeprom_read_byte((uint8_t) address);//programm space code should have stored the connections here
	if(connections == 0xFF)//no connections found
	{
		topology_scan(&connections);//only terminates if no vector is found
	}
	eeprom_write_byte((uint8_t) address, 0xFF);//clear the eeprom byte because this is bootspace
			
	
	DDRA = 0xFF;
	
	COM_init();
	
	for(r=0; r<SPM_PAGESIZE; r++)
	{
		myPage[r] = 0xFF;
	}


///////////BOOTLOADER	
	RED_ON;
	if(connections >= 16)
	{
		//direction of vector node...
		if( (connections & (16 << WEST)))		
		{
			ptr_putc = LEFT_putc;
			ptr_getc = LEFT_getc;
		}
		else if( (connections & (16 << NORTH)))		
		{
			ptr_putc = UP_putc;
			ptr_getc = UP_getc;
		}
		else if( (connections & (16 << SOUTH)))		
		{
			ptr_putc = DOWN_putc;
			ptr_getc = DOWN_getc;
		}
		else if( (connections & (16 << EAST)))		
		{
			ptr_putc = RIGHT_putc;
			ptr_getc = RIGHT_getc;
		}
		
		pagenumber = 0;
		bytecounter = 0;
		totalbytes = 0;
		loading = 1;
		started = 0;
		retransmitAllowed=1;
		
		while(loading)
		{
			c  = ptr_getc();
		
			if(c == START)//START
			{
				RED_OFF;//DEBUG
				GREEN_OFF;//DEBUG
				BLUE_OFF;//DEBUG
				pagenumber = 0;
				bytecounter = 0;
				totalbytes = 0;
				started = 1;
				retransmitAllowed=1;
			}
			else if(c == END)//END
			{
				if(started)
				{
					if(bytecounter > 0)
					{
						boot_program_page (pagenumber*64, myPage);
					}
					loading = 0;
				}
			}
			else if( (c == DATA) || (c == RETRANSMISSION)  )//DATA
			{
				d = ptr_getc();
				if(c == RETRANSMISSION)
				{
					if(retransmitAllowed)
					{
#ifdef SHOW_TRANSFER_ERRORS
						BLUE_ON;//DEBUG
#endif
						if(bytecounter > 0)
						{
							bytecounter--;
						}
					}
				}
				else
				{
#ifdef SHOW_TRANSFER_ERRORS
					RED_OFF;//DEBUG
					GREEN_OFF;//DEBUG
					BLUE_OFF;//DEBUG
#endif
					totalbytes++;
					retransmitAllowed=1;
					
					if(bytecounter == SPM_PAGESIZE)
					{
						boot_program_page (pagenumber*64, myPage);	
	
						bytecounter = 0;
						pagenumber++;
						
						for(r=0; r<SPM_PAGESIZE; r++)
						{
							myPage[r] = 0xFF;
						}
						
						if(pagenumber >= MAX_PAGENUMBER)//do not override bootloader!
						{
							RED_ON;//DEBUG
							while(1)
							{
								asm volatile("nop");
							}
						}
					}
				}
				myPage[bytecounter] = d;
				bytecounter = bytecounter +1;
				
				_delay_loop_2(800);
				ptr_putc(d);//ACK --> sender sends next byte
			}
			else
			{
#ifdef SHOW_TRANSFER_ERRORS
				RED_ON;//DEBUG
#endif
				//ERROR
				if(started)
				{
					//SEND WRONG ACK BECAUSE THERE WAS A TRANSMISSION ERROR
					d = ptr_getc();
					_delay_loop_2(200);
					ptr_putc(d+3);//SEND WRONG ACK
					retransmitAllowed=0;
				}
				else
				{
					//IGNORE BYTE
				}
			}
		}
	}
////////////////////////////////////////////////////////////////////////


_delay_loop_2(62510); // 250ms
_delay_loop_2(62510); // 250ms

	
	
//////BOOTSENDER	
RED_OFF;
GREEN_OFF;
BLUE_ON;
_delay_loop_2(60000);

	for(uint8_t volatile direction=0;direction<4;direction++)
	{
		if(direction==EAST)
		{
			ptr_putc = RIGHT_putc;
			ptr_getc = RIGHT_getc;
		}
		else if(direction==WEST)
		{
			ptr_putc = LEFT_putc;
			ptr_getc = LEFT_getc;
		}
		else if(direction==NORTH)
		{
			ptr_putc = UP_putc;
			ptr_getc = UP_getc;
		}
		else if(direction==SOUTH)
		{
			ptr_putc = DOWN_putc;
			ptr_getc = DOWN_getc;
		}
			
		if( (connections & (1 << direction)) && (!(connections & (16 << direction))) )
		{
			//////send block
			ptr_putc(START);
			_delay_loop_2(50); // 1ms
			
			z = 0;
			for(z=PAYLOAD_FLASH_ADDRESS;z<(PAYLOAD_FLASH_ADDRESS+totalbytes); z++)
			{
			
				b1 = pgm_read_byte_near(z);				
				//_delay_loop_2(5); // 1ms
				
				ptr_putc(DATA);
				//_delay_loop_2(5); // 1ms
				
				ptr_putc(b1);
				
				b2 = ptr_getc();
				
				
				while(b2 != b1)//byte invalid -> retransmission (error correction)
				{
					_delay_loop_2(50); // 1ms
					ptr_putc(RETRANSMISSION);
					
					_delay_loop_2(50); // 1ms
					
					ptr_putc(b1);
					b2 = ptr_getc();
					
				}
				//_delay_loop_2(5); // 1ms
				
				
				}
			_delay_loop_2(250); // 1ms
			ptr_putc(END);
			
			_delay_loop_2(250); // 1ms
			//////send block
		}
	}
		
	RED_OFF;
	GREEN_OFF;
	BLUE_OFF;
	
	//SREG = oldSREG;
	
	
//////////////////////////////////////////////////////////////////////////////////////////
//now the node blinks, indicating that the process has finished for this node. 
//When every  node blinks (blue or green) the user can restart the nodes
//blue (blinking) nodes must be removed from the luminet, because those are vector nodes
//red blinking indicates that there was an error
//no blinking indicates that there was an error
	while(1)
	{
	
		if(connections >= 16)//everything was ok, I received code from a vector path
		{
			GREEN_ON;
					}
		else//I did not receive or send anything
		{
			RED_ON;
		}
	
	}
}



