/*****************************************************************************
*
* AVRPROG compatible boot-loader
* Version  : 0.85 (Dec. 2008)
* Compiler : avr-gcc 4.1.2 / avr-libc 1.4.6
* size     : depends on features and startup ( minmal features < 512 words)
* by       : Martin Thomas, Kaiserslautern, Germany
*            eversmith@heizung-thomas.de
*            Additional code and improvements contributed by:
*           - Uwe Bonnes
*           - Bjoern Riemer
*           - Olaf Rempel
*
* License  : Copyright (c) 2006-2008 M. Thomas, U. Bonnes, O. Rempel
*            Free to use. You have to mention the copyright
*            owners in source-code and documentation of derived
*            work. No warranty! (Yes, you can insert the BSD
*            license here)
*
* Tested with ATmega8, ATmega16, ATmega162, ATmega32, ATmega324P,
*             ATmega644, ATmega644P, ATmega128, AT90CAN128
*
* - Initial versions have been based on the Butterfly bootloader-code
*   by Atmel Corporation (Authors: BBrandal, PKastnes, ARodland, LHM)
*
****************************************************************************
*
*  See the makefile and readme.txt for information on how to adapt 
*  the linker-settings to the selected Boot Size (BOOTSIZE=xxxx) and 
*  the MCU-type. Other configurations futher down in this file.
*
*  With BOOT_SIMPLE, minimal features and discarded int-vectors
*  this bootloader has should fit into a a 512 word (1024, 0x400 bytes) 
*  bootloader-section. 
*
****************************************************************************/

/* Частота контроллера (кварца) */
#ifndef F_CPU
// #define F_CPU 7372800
//#define F_CPU (7372800/2)
#define F_CPU 8000000
#endif

#include <stdint.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/boot.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "chipdef.h"
#include "FAT32.c"
#include "SPI_routines.c"
#include "SD_routines.c"

#if defined(BOOTLOADERHASNOVECTORS)
	#warning "This Bootloader does not link interrupt vectors - see makefile"
	/* make the linker happy - it wants to see __vector_default */
	// void __vector_default(void) { ; }
	void __vector_default(void) { ; }
#endif


#define cPathSIze 32 // размер пути для загрузки файлов
#define STOPPOINT(x) eeprom_write_byte(0,x) // для отладки, находить точки останова







static void (*app_start)(void) = 0x0000;


static void upload(char *fileName, unsigned char memtype)
{
	struct dir_Structure *dir;
	unsigned long cluster, byteCounter = 0, fileSize, firstSector;
	unsigned char filesector, error, p;
	uint16_t  i, j, adr, *lpword;
	error = convertFileName (fileName); //convert fileName into FAT format
	if(error) return;
	dir = findFiles (fileName); //get the file location
	if(dir == 0) return;
	cluster = (((unsigned long) dir->firstClusterHI) << 16) | dir->firstClusterLO;
	fileSize = dir->fileSize;
	firstSector = getFirstSector (cluster);
		switch (memtype) // Какую память будем программировать
		{
		case 0:
			// программируем FLASH
			for(filesector=0; filesector < FL_SECTOR_FOR_READ; filesector++)
			{
   			SD_readSingleBlock(firstSector + filesector);
			lpword = (uint16_t*) buffer;
				for (i=0; i<(512 / SPM_PAGESIZE); i++)
				{
					adr = (filesector * 512) + i * SPM_PAGESIZE;
					boot_page_erase(adr);
					while (boot_rww_busy()) boot_rww_enable();
					for (j=0; j<SPM_PAGESIZE; j+=2) boot_page_fill(adr + j, *lpword++);
					boot_page_write(adr);
					while (boot_rww_busy())	boot_rww_enable();
				};
		  	cluster = getSetNextCluster (cluster, GET, 0);
			}; 
	 	break;
		default:
			// программируем EEPROM
			adr=0;
			for (filesector = 0; filesector < EE_SECTOR_FOR_READ; filesector++)
			{
   				SD_readSingleBlock(firstSector + filesector);
				for(j=0;j<512;j++)
				{
					eeprom_busy_wait();
					eeprom_write_byte(adr, buffer[j]);
					adr++;
				}
		  	cluster = getSetNextCluster (cluster, GET, 0);
			};
	    break;
		}		
}





static unsigned char uploadfilename(char *fileName, char *load)
{
	struct dir_Structure *dir;
	unsigned long cluster, byteCounter = 0, fileSize, firstSector;
	unsigned char  error, p;
	uint16_t  i, j, adr, *lpword;
	error = convertFileName (fileName); //convert fileName into FAT format
	if(error) return;
	dir = findFiles (fileName); //get the file location
	if(dir == 0) return;
	cluster = (((unsigned long) dir->firstClusterHI) << 16) | dir->firstClusterLO;
	fileSize = dir->fileSize;
	firstSector = getFirstSector (cluster);
   	SD_readSingleBlock(firstSector);
	for(j=0;j<cPathSIze;j++)
		{
		if (buffer[j]<33) return 0;
		load[j]=buffer[j];
	//	eeprom_write_byte(j+1, buffer[j]);
		}
	return 0;
}





static void loadboot()
{

	char f[]="boot.fl";     // имя файла FLASH
	char f1[]="boot.ee";     // имя файла EEPROM

/*  старая версия программы. на 64 меге давала переполнение памяти
	char filename[]="boot";     // имя файла, который будет загружатся если 
	char f[cPathSIze];
	char f1[cPathSIze];
	char ee=".ee";
	char fl=".fl";
	memset(f,0,sizeof(f));
	memset(f1,0,sizeof(f1));
	memcpy(f,filename,strlen(filename));
	strcat(f,fl);
	memcpy(f1,filename,strlen(filename));
	strcat(f1,ee);
*/

	upload(f,0); 				// загружаем FLASH
	upload(f1,1); 				// загружаем EEPROM

}


static void loadfile()
{
	char fn[]="upload.bat";     	// имя файла, который содержит файл для загрузки
	char filename[cPathSIze];				// имя загружаемого файла
	char f[cPathSIze];
	char f1[cPathSIze];
	char ee=".ee";
	char fl=".fl";
	memset(filename,0,sizeof(filename));					
	if (uploadfilename(fn,filename)!=0) return; // если файл отсутствует
//	for(unsigned char u=0;u<sizeof(filename);u++) {eeprom_write_byte(u+32, filename[u]);}
	memset(f,0,sizeof(f));
	memset(f1,0,sizeof(f1));
	memcpy(f,filename,strlen(filename));
	strcat(f,fl);
	memcpy(f1,filename,strlen(filename));
	strcat(f1,ee);
	upload(f,0); 				// загружаем FLASH
	upload(f1,1); 				// загружаем EEPROM
}




int main(void)
{
	unsigned char error;
	unsigned char i;
	// запрет прерываний, запрет собачего таймера
	cli();
	wdt_reset();
	wdt_disable();
	// настройка портов клавиатуры
 	PORTC = 0xFF; 	//pullup for keys
 	DDRC  = 0x00;	// x x x START ROTATE LEFT RIGHT DOWN

	// настройка портов
	PORTB = 0xFF;

	// для ATmega32
	#if defined(__AVR_ATmega32__)
		DDRB  = 0xBF; //MISO на вход, остальные на выход
	#endif

	// для ATmega64
	#if defined(__AVR_ATmega64__)
		DDRB  = 0xF7; //MISO на вход, остальные на выход
	#endif

	// настройка SPI init
	SPCR = (1<<MSTR)|(1<<SPE); // SPI config
	SPSR = (1<<SPI2X); // double speed


SPI_transmit(55);


	// проверка работоспособности бутлодера. Моргалка на ногах PF
 	// PORTF = 0xFF;DDRF  = 0xFF; while (1) {PORTF=0; _delay_ms(300); PORTF=255; _delay_ms(300);}


	// попытка инициализировать карту
	cardType = 0;
	for (i=0; i<10; i++) {error = SD_init();if(!error) break;}
	if(error) app_start(); // ошибка - стартуем приложение
	_delay_ms(10);   //some delay
	error = getBootSectorData (); //read boot sector and keep necessary data in global variables
	if(error) app_start(); // ошибка - стартуем приложение


	if(PINC!=255) 				// условие сработки bootloader-а (нажата кнопка VK1)
    {
		loadboot();
	}
	else
	{
		loadfile();				// иначе загружать из файла
	}
	app_start();				// запуск приложения

}
