//*********************************************************************
//
//    FAT16 MMC/SD ЗАГРУЗЧИК версия 1.10.
// 
// 1. Добавляем makefile.mak в проект. Идем 
//    Project ->Configuration options. 
//    На вкладке General устанавливаем галку Use external makefile. 
//    Нажмаем "…" находим makefile.mak.
//
// 2. В makefile.mak настраиваем параметры компиляции загрузчика: 
//    MCU - модель процессора
//    F_CPU - рабочая частота процессора
//    BOOTLDRSIZE - размер загрузчика 
//    BOOTLOADERSTARTADR - стартовый адрес загрузчика
//    TARGET - имя *.hex файла, получаемого при компиляции
//    OBJDIR - директория, в которую происходит компиляция загрузчика
//
// 3. В mmc.h в секции, соответствующей модели процессора 
//    (см. makefile.mak, параметр MCU) настраиваем ноги, на которые 
//    вешается SD карта. Ноги SPI_DI, SPI_DO, SPI_Clock должны быть 
//    стандартными для интерфейса SPI т.к. программная реализация SPI 
//    отсутствует. Ноги MMC_Chip_Select и SPI_SS настраиваются в 
//    соответствии со схемной реализацией. 
//    Для SD карты MMC_Chip_Select  = SPI_SS.
//
// 4. В megavar.h, если модель процессора отсутствует, настраиваем
//    размеры EEPROM и FLASH памяти в секторах для программирования: 
//    EE_SECTOR_FOR_READ и FL_SECTOR_FOR_READ для EEPROM и FLASH памяти
//    соответственно. 
// 
// 5. В main.с в процедуре int main(void) настраиваем условие сработки 
//    bootloader-a (например низкий сигнал на PINC). Имя файла для 
//    загрузки по этому событию "boot" (задается в loadboot()).
// 
// 6. SD карта должна быть отформатирована в системе FAT16. 
//	  Размер кластера 512 байт.
//    На карточке должны размещаться bin-файлы EEPROM и FLASH. 
//    Например "boot.ee" и "boot.fl" Расширение файла EEPROM - "ee", 
//    расширение FLASH - "fl". Файл EEPROM может отсутствовать. 
//    Файл FLASH должен быть всегда. Размеры файлов - постоянная 
//    величина равная EE_SECTOR_FOR_READ*512 и FL_SECTOR_FOR_READ*512 
//    для EEPROM и FLASH соответственно.
// 
// 7. Для программирования чипа используйте 
//    progeeprom32.bat (программирование загрузчика) и 
//    progHfuse32.bat (программирование фьюзов). 
//    Для программатора отличного usbasp 
//    скорректировать указанные файлы.
//
// 8. Со всеми вопросами обращаетесь на адрес matrex@rambler.ru.
// 
// 9. При написании программы использовались следующие материалы:
//    http://www.mikrocontroller.net/articles/MMC/SD_Bootloader_f%C3%BCr_AT_Mega
//    http://www.ulrichradig.de/home/index.php/avr/mmc-sd
//    http://www.dharmanitech.com/2009/01/sd-card-interfacing-with-atmega8-fat32.html
//
//
//    ИСТОРИЯ ИЗМЕНЕНИЙ:
//
//    01.10.2011 v. 1.01.
//    Устранена ошибка в размере EEPROM памяти для ATMEGA32. 
//    Приведено в соответствие со спецификацией наименование типов 
//    памяти. Добавлена работа с EEPROM памятью.
//
//    08.12.2011 v. 1.10.
//    Изменена логика работы программы:
//		- если сработало условие сработки бутлодера (нажата клавиша)
//		  загружаем файлы "boot.fl" "boot.ee"
//		- иначе чтитаем содержимое файла "upload.bat" и загружаем тот
//		  файл, который записан в upload, Обязательное условие - 
//		  имя файла должно заканчиваться "непечатным символом", например
//		  zagrus(#0D)(#0A)
//
//*********************************************************************



#include <util/delay.h>

#include <avr/boot.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "mmc.h"
#include "fat.h"
#include "megavar.h"

#define cPathSIze 32 // размер пути для загрузки файлов
void (*app_start)(void) = 0x0000;






void upload(char *filename, unsigned char memtype)
{
	unsigned int tmp;
	unsigned int Clustervar=0;
	unsigned char Dir_Attrib = 0;
	unsigned long Size = 0;
	unsigned char Buffer[512];
	uint16_t filesector, j, ii, adr, *lpword;
	uint8_t i;
	if (fat_search_file(filename,&Clustervar,&Size,&Dir_Attrib,Buffer) != 1) return; // файл отсутствует
	switch (memtype) // Какую память будем программировать
	{
	case 0:
		// программируем FLASH
		for (filesector = 0; filesector < FL_SECTOR_FOR_READ ; filesector++)
		{
		lpword = (uint16_t*) Buffer;
		fat_read_file (Clustervar,Buffer,filesector);
		for (i=0; i<(512 / SPM_PAGESIZE); i++)
			{
			adr = (filesector * 512) + i * SPM_PAGESIZE;
//			if (adr>=Size) break;
			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();
			}; 
		 };
		 break;


	default:
		// программируем EEPROM
		adr=0;
		for (filesector = 0; filesector < EE_SECTOR_FOR_READ; filesector++)
		{
		fat_read_file (Clustervar,Buffer,filesector);
			for(ii=0;ii<512;ii++)
			{
//				if (adr==Size) break;	
				eeprom_busy_wait();
				eeprom_write_byte(adr, Buffer[ii]);
				adr++;
			}
		};
	    break;
	}
}





unsigned char uploadfilename(char *filename, char *load)
{
	unsigned int Clustervar=0;
	unsigned char Dir_Attrib = 0;
	unsigned long Size = 0;
	unsigned char Buffer[512], ii;
	if (fat_search_file(filename,&Clustervar,&Size,&Dir_Attrib,Buffer) != 1) return 1; // файл отсутствует
	fat_read_file (Clustervar,Buffer,0);
			for(ii=0;ii<cPathSIze;ii++)
			{
				if (Buffer[ii]<33) return 0;
				load[ii]=Buffer[ii];
			//	eeprom_write_byte(ii, Buffer[ii]);
			}
	return 0;
}




void loadboot()
{
char filename[]="boot";     // имя файла, который будет загружатся если 
char f[cPathSIze];
char f1[cPathSIze];
char ee=".ee";
char fl=".fl";
cli();						// запрет прерываний
if (mmc_init() !=0) return; // не смогли инициализировать карту
fat_init();
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
}



void loadfile()
{
char fn[]="upload.bat";     	// имя файла, который содержит файл для загрузки
char filename[cPathSIze];				// имя загружаемого файла
char f[cPathSIze];
char f1[cPathSIze];

char ee=".ee";
char fl=".fl";


cli();						// запрет прерываний
if (mmc_init() !=0) return; // не смогли инициализировать карту
fat_init();					// инициализируем FAT16
memset(filename,0,sizeof(filename));					
if (uploadfilename(fn,filename)!=0) return; // если файл отсутствует
//for(unsigned char u=0;u<sizeof(nn);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)
{
 _delay_ms(10);
 PORTC = 0xFF; 	//pullup for keys
 DDRC  = 0x00;	// x x x START ROTATE LEFT RIGHT DOWN
  _delay_ms(10);
if(PINC!=255) 				// условие сработки bootloader-а (нажата кнопка VK1)
    {
	loadboot();   			// загружаем память
	}
	else
	{
	loadfile();					// иначе загружать из файла
	}
app_start();				// запуск приложения
}




