/*
 * Time_WS2812b_84LED_2Led_1Seg.c
 *
 * Created: 27.08.2017 12:36:00
 * Author : w666m
 */ 

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include "I2C.h"
#define value 255//40
#define strip 30	//длина ленты
#define menu_but (PINC&(1<<2))
#define up_but (PINC&(1<<0))
#define dn_but (PINC&(1<<1))
#define int_time (PINC&(1<<3))
//green/red/blue//
unsigned char color_level EEMEM;
unsigned char led_off[3]={0,0,0};
unsigned char cifra[4]={0,7,16,23};
unsigned char flag_zamena[6]={1,1,1,1,1,1};
unsigned char times[6] = {0,0,0,0,0,0};
unsigned char date[6] = {0,0,0,0,0,0};
unsigned char erace_cifra_home[5] = {0,16,0,16,0};
unsigned char erace_cifra_end[5] = {0,30,14,30,14};
unsigned char times_history[6] = {0,0,0,0,0,0};
unsigned char temperature[6];
unsigned char light[3] = {0,0,0};
unsigned char mas_color[7][3] =
{
	{0,0,value},	//синий
	{0,value,value},	//фиолетовый
	{value,0,value},	//голубой
	{value,value,value},	//белый
	{value,0,0},	//зеленый
	{value,value,0},	//желтый
	{0,value,0}	//красный
};
unsigned const char digit[12][7] =
{      //c d e f a b g
	{1,1,1,1,1,1,0},	//0 c d e f a b g
	{1,0,0,0,0,1,0},	//1
	{0,1,1,0,1,1,1},	//2
	{1,1,0,0,1,1,1},	//3
	{1,0,0,1,0,1,1},	//4
	{1,1,0,1,1,0,1},	//5
	{1,1,1,1,1,0,1},	//6
	{1,0,0,0,1,1,0},	//7
	{1,1,1,1,1,1,1},	//8
	{1,1,0,1,1,1,1},	//9
	{0,0,0,1,1,1,1},	//o
	{0,1,1,1,1,0,0}		//C
};
unsigned const char effect_1_zifr[10][7] =
{
	{4,3,2,1,0,5,20},		//0
	{5,0,20,20,20,20,20},	//1
	{4,5,6,2,1,20,20},		//2
	{4,5,6,0,1,20,20},		//3
	{3,6,5,0,20,20,20},	//4
	{3,6,0,1,4,20,20},		//5
	{4,3,2,1,0,6,20},		//6
	{4,5,0,20,20,20,20},	//7
	{5,4,3,6,0,1,2},		//8
	{4,3,6,5,0,1,20}		//9
};
volatile unsigned char temp[strip];  //массив для вывода на ленту
unsigned char colors, k, z, count, flag_temperature=0;
void button(void);
void SPI_MasterInit(void);
void SPI_Write(void);
void off_strip(void);
void timer1_init(void);
void timer1_deinit(void);
void cifry(unsigned char s0, unsigned char s1, unsigned char m0, unsigned char m1, unsigned char ch0, unsigned char ch1, unsigned char tipes);
void write_temperature(void);
void write_date(void);
void update_time(void);
void start_ADC(void);
void init_ADC(void);
unsigned char hour, minute, minute_temp, second, temp_time,  flag, temperature_MSB, temperature_LSB, updat, update_start;
unsigned char year, month, day;
unsigned char menu=0, ADC_value;
unsigned char sec_0_his, sec_1_his, min_0_his, min_1_his, hour_0_his, hour_1_his;

void start_ADC(void)
{ uint8_t i;
	ADCSRA |= (1<<ADSC);
	while ((ADCSRA&(1<<ADSC))!=0){;}
	ADC_value = (255 - ADCH)/3;
	if (ADC_value<3)
	{
		ADC_value = 3;
	}
	for (i=0; i<3; i++)
	{
		if (mas_color[colors][i]!=0)
		{
			light[i] = ADC_value;
		   light[i]=255;
		}
		else
		{
			light[i] = 0;
		}
	}
}

void init_ADC(void)
{
	ADMUX |= (1<<REFS0)|(1<<MUX1)|(1<<MUX0)|(1<<MUX2)|(1<<ADLAR);				//10bit 6ch
	ADCSRA |= (1<<ADEN)|(1<<ADPS1)|(1<<ADPS2)|(1<<ADPS0);	//prescal 128
}
/*инициализация SPI*/
void SPI_MasterInit(void)
{
	//DDRB|=(1<<3)|(1<<5)|(1<<4)|(1<<1)|(1<<2);
	DDRB|=(1<<3)|(1<<5)|(0<<4)|(1<<1)|(1<<2);
	PORTB|=(1<<0)|(1<<1)|(1<<2);
	PORTC|=(1<<0)|(1<<1)|(1<<2)|(1<<3);
	SPCR |= (1<<SPE)|(1<<MSTR)|(1<<CPHA);//fosc/2 16MHz/2
	SPSR |=(1<<SPI2X);
}

/*вывод временного массива на ленту*/
void SPI_Write(void)
{
	unsigned char j,i,n,a;
	for (n=0; n<strip; n++)			//strip=60 диодов длина ленты
	{
		if (temp[n] != 0)
		{
		for (j=0; j<3; j++)			//первым выставляется G (Hi->Low), потом R и B
			{
				a = 0x80;				//сравниваем каждый бит
				for (i=0;i<8;i++)			//передача 8 бит цвета из подготовленного массива temp
				{
					//if ((mas_color[colors][j]&a)==0)
					if ((light[j]&a)==0)
					{
						SPDR = 224;//0xE0 0.37us 0	//ноль
						//SPDR = 0xe0;//0xE0 0.37us 0	//ноль
					}
					else
					{
						SPDR = 252;//0xFC 0.75us 1 //единица
						//SPDR = 0xfc;//0xFC 0.75us 1 //единица
					}
					while(!(SPSR & (1<<SPIF)));
					a=a>>1;
				}
			}	
		} 
		else
		{
			for (i=0;i<24;i++)			//передача 24 бит цвета
			{
				SPDR = 224;//0xE0 0.37us 0	//ноль
				while(!(SPSR & (1<<SPIF)));
			}
		}
		
	}
	//_delay_us(50);
	//start_ADC();
}

void cifry(unsigned char s0, unsigned char s1, unsigned char m0, unsigned char m1, unsigned char ch0, unsigned char ch1, unsigned char tipes)//
{
	switch (tipes)
	{
	case 0:
		if (s1 == 0)
		{
			s1 = 10;
			temp[15] = 0;
		}
		if (m1 == 0)
		{
			m1 = 10;
		}
		if (ch1 == 0)
		{
			ch1 = 10;
		}
	break;
	case 1:
		if (ch1 == 0)
		{
			ch1 = 10;
		}
	break;
	case 2:
	if (m1 == 0)
	{
		m1 = 10;
	}
	break;
	}
  
	//sec_edinicy
	for (count=cifra[0]; count<cifra[1]; count++)
	{
		temp[count] = digit[s0][count];
	}
	//sec_des
	for (count=cifra[1]; count<(cifra[2]-2); count++)
	{
		temp[count] = digit[s1][count-cifra[1]];
	}
	//min_edinicy
	for (count=cifra[2]; count<cifra[3]; count++)
	{
		temp[count] = digit[m0][count-cifra[2]];
	}
	//min_des
	//for (count=cifra[3]; count<(cifra[4]-2); count++)
	for (count=cifra[3]; count<strip; count++)   
	{
		temp[count] = digit[m1][count-cifra[3]];
	}
	//chas_edinicy
/*	for (count=cifra[4]; count<cifra[5]; count++)
	{
		temp[count] = digit[ch0][count-cifra[4]];
	}
	//chas_des
	for (count=cifra[5]; count<strip; count++)
	{
		temp[count] = digit[ch1][count-cifra[5]];
	} */
	SPI_Write();
}

/*потушить ленту*/
void off_strip(void)
{
	for (count=0; count<strip; count++)
	{
		temp[count]=0;//задвигаем led_off во временный массив
	}
	SPI_Write();//отправляем что собрали на ленту
}

void timer1_init(void)
{
	TCCR1B |= (0<<ICNC1)|(0<<ICES1)|(0<<WGM13)|(0<<WGM12)|(1<<CS12)|(0<<CS11)|(1<<CS10);
	//TIMSK1 |= (1<<OCIE1B);
	TIMSK |= (1<<OCIE1B);
	OCR1B=900;
	sei();
}

void timer1_deinit(void)
{
	TCCR1B &=~((1<<CS12)|(1<<CS10));
	//TIMSK1 &=~(1<<OCIE1B);
	TIMSK &=~(1<<OCIE1B);
	cli();
	start_ADC();
}

ISR (TIMER1_COMPB_vect)
{
		//for (z=0; z<6; z++)
		for (z=0; z<4; z++)   
		{
			if ((effect_1_zifr[times[z]][k] < 20)&&(flag_zamena[z] != 0))
			{
				temp[effect_1_zifr[times[z]][k] + cifra[z]] = 1;
			}
		}
		SPI_Write();
		k++;
		//if (k>13)
		if (k>6)   
		{
			k=0;
			timer1_deinit();
			//for (z=0; z<6; z++)
			for (z=0; z<4; z++)   
			{
				flag_zamena[z] = 0;
			}
		}
	TCNT1 = 0;
}

void button(void)
{
	if(menu_but==0) // Если нажата кнопка
	{
		while(menu_but==0){} // Ждем отпускания кнопки
		menu++; // Увеличиваем menu на 1
		flag=0;
		if(menu > 6)
		{
			menu = 0;
			off_strip();
			for (z=0; z<6; z++)
			{
				flag_zamena[z] = 1;
			}
		}
	}
	
	switch(menu)
	{
		case 0:
		if (flag==0)
		{
			flag=1;
		}
		if(up_but==0) // Если нажата кнопка
		{
			while(up_but==0){} // Ждем отпускания кнопки
			colors++;
			if (colors > 6)
			{
				colors = 0;
			}
			eeprom_update_byte(&color_level, colors);
		}

		if(dn_but==0) // Если нажата кнопка
		{
			while(dn_but==0){} // Ждем отпускания кнопки
			colors--;
			if (colors > 9)
			{
				colors = 6;
			}
			eeprom_update_byte(&color_level, colors);
		}
		break;
		case 1:
		if (flag==0)
		{
			flag=1;
		}
		if(up_but==0) // Если нажата кнопка
		{
			while(up_but==0){} // Ждем отпускания кнопки
			hour++; // Увеличиваем часы на 1
			if(hour > 23) hour = 0;
			temp_time = ((hour/10) << 4)|(hour%10);
			DS3231SN_write(0x02, temp_time);
			cifry(times[0],times[1],times[2],times[3],hour%10,hour/10,1);
		}
		if(dn_but==0) // Если нажата кнопка
		{
			while(dn_but==0){} // Ждем отпускания кнопки
			hour--; // Увеличиваем минуты на 1
			if(hour > 23) hour = 23;
			temp_time = ((hour/10) << 4)|(hour%10);
			DS3231SN_write(0x02, temp_time);
			cifry(times[0],times[1],times[2],times[3],hour%10,hour/10,1);
		}
		break;
		case 2:
		if (flag==0)
		{
			flag=1;
		}
		if(up_but==0) // Если нажата кнопка
		{
			while(up_but==0){} // Ждем отпускания кнопки
			minute++; // Увеличиваем часы на 1
			if(minute > 59) minute = 0;
			temp_time = ((minute/10) << 4)|(minute%10);
			DS3231SN_write(0x01, temp_time);
			cifry(times[0],times[1],minute%10,minute/10,times[4],times[5],1);
		}
		if(dn_but==0) // Если нажата кнопка
		{
			while(dn_but==0){} // Ждем отпускания кнопки
			minute--; // Увеличиваем минуты на 1
			if(minute > 59) minute = 59;
			temp_time = ((minute/10) << 4)|(minute%10);
			DS3231SN_write(0x01, temp_time);
			cifry(times[0],times[1],minute%10,minute/10,times[4],times[5],1);
		}
		break;
		case 3:
		if (flag==0)
		{
			flag=1;
		}
		if(up_but==0) // Если нажата кнопка
		{
			while(up_but==0){} // Ждем отпускания кнопки
			second = 0;
			temp_time = ((second/10) << 4)|(second%10);
			DS3231SN_write(0x00, temp_time);
			cifry(second%10,second/10,times[2],times[3],times[4],times[5],1);
		}
		if(dn_but==0) // Если нажата кнопка
		{
			while(dn_but==0){} // Ждем отпускания кнопки
			second = 0;
			temp_time = ((second/10) << 4)|(second%10);
			DS3231SN_write(0x00, temp_time);
			cifry(second%10,second/10,times[2],times[3],times[4],times[5],1);
		}
		break;
		case 4:
		if (flag==0)
		{
			flag=1;
		}
		if(up_but==0) // Если нажата кнопка
		{
			while(up_but==0){} // Ждем отпускания кнопки
			day++; // Увеличиваем день на 1
			if(day > 31) day = 1;
			temp_time = ((day/10) << 4)|(day%10);
			DS3231SN_write(0x04, temp_time);
			cifry(date[0],date[1],date[2],date[3],day%10,day/10,3);
		}
		if(dn_but==0) // Если нажата кнопка
		{
			while(dn_but==0){} // Ждем отпускания кнопки
			day--; // Уменьшаем день на 1
			if(day == 0) day = 31;
			temp_time = ((day/10) << 4)|(day%10);
			DS3231SN_write(0x04, temp_time);
			cifry(date[0],date[1],date[2],date[3],day%10,day/10,3);
		}
		break;
		case 5:
		if (flag==0)
		{
			flag=1;
		}
		if(up_but==0) // Если нажата кнопка
		{
			while(up_but==0){} // Ждем отпускания кнопки
			month++; // Увеличиваем месяц на 1
			if(month > 12) month = 1;
			temp_time = ((month/10) << 4)|(month%10);
			//temp_time|=(1<<7);
			DS3231SN_write(0x05, temp_time);
			cifry(date[0],date[1],month%10,month/10,date[4],date[5],3);
		}
		if(dn_but==0) // Если нажата кнопка
		{
			while(dn_but==0){} // Ждем отпускания кнопки
			month--; // Уменьшаем месяц на 1
			if(month == 0) month = 12;
			temp_time = ((month/10) << 4)|(month%10);
			//temp_time|=(1<<7);
			DS3231SN_write(0x05, temp_time);
			cifry(date[0],date[1],month%10,month/10,date[4],date[5],3);
		}
		break;
		case 6:
		if (flag==0)
		{
			flag=1;
		}
		if(up_but==0) // Если нажата кнопка
		{
			while(up_but==0){} // Ждем отпускания кнопки
			year++; // Увеличиваем год на 1
			if(year > 99) year = 17;
			temp_time = ((year/10) << 4)|(year%10);
			DS3231SN_write(0x06, temp_time);
			cifry(year%10,year/10,date[2],date[3],date[4],date[5],3);
		}
		if(dn_but==0) // Если нажата кнопка
		{
			while(dn_but==0){} // Ждем отпускания кнопки
			year--; // Уменьшаем год на 1
			if(year == 16) year = 17;
			temp_time = ((year/10) << 4)|(year%10);
			DS3231SN_write(0x06, temp_time);
			cifry(year%10,year/10,date[2],date[3],date[4],date[5],3);
		}
		break;
	}
}

void write_temperature(void)
{
	//temp[29] = 0;
	//temp[28] = 0;
	//temp[58] = 0;
	//temp[59] = 1;
	 temp[15] = 1;
	cifry(11,10,temperature_LSB%10,temperature_LSB/10,temperature_MSB%10,temperature_MSB/10,0);
}
void write_date(void)
{
	//temp[28] = 0;
	//temp[58] = 0;
	//temp[59] = 1;
	//temp[29] = 1;
	 temp[15] = 1;
	cifry(date[0],date[1],date[2],date[3],date[4],date[5],1);
}

void update_time(void)
{ uint8_t i;
	if ((int_time == 0)&&(updat == 0))
	{
		updat = 1;
		update_start = 1;
		if (menu != 0)
		{
			switch (menu)
			{
			case 1:
			temp[28] = 1;
			temp[58] = 1;
			cifry(times[0],times[1],times[2],times[3],hour%10,hour/10,1);
			break;
			case 2:
			temp[28] = 1;
			temp[58] = 1;
			cifry(times[0],times[1],minute%10,minute/10,times[4],times[5],1);
			break;
			case 3:
			temp[28] = 1;
			temp[58] = 1;
			cifry(second%10,second/10,times[2],times[3],times[4],times[5],1);
			break;
			case 4:
			temp[29] = 1;
			temp[59] = 1;
			cifry(date[0],date[1],date[2],date[3],day%10,day/10,3);
			break;
			case 5:
			temp[29] = 1;
			temp[59] = 1;
			cifry(date[0],date[1],month%10,month/10,date[4],date[5],3);
			break;
			case 6:
			temp[29] = 1;
			temp[59] = 1;
			cifry(year%10,year/10,date[2],date[3],date[4],date[5],3);
			break;
			}
		}
		else
		{
			//temp[28] = 1;
			//temp[58] = 1;
			temp[14] = 1;
			temp[15] = 1;
		}
	}
	if ((int_time != 0)&&(updat !=0))
	{
		updat = 0;		
		//temp[28] = 0;
		//temp[58] = 0;
		//temp[29] = 0;
		//temp[59] = 0;
		  temp[14] = 0;
		  temp[15] = 0;
		if (menu != 0)
		{
			for (i=erace_cifra_home[menu]; i<erace_cifra_end[menu]; i++)
			{
				temp[i] = 0;
			}
			SPI_Write();
		}
	}
	
	if (update_start == 1)
	{
		update_start = 0;

		DS3231SN_read(0x00, &temp_time); // Чтение регистра секунд
		times[0] = temp_time & 0x0F;
		times[1] = (temp_time & 0xf0) >> 4;
		second = times[1]*10 + times[0];

		DS3231SN_read(0x01, &temp_time); // Чтение регистра минут
		times[2] = temp_time & 0x0F;
		times[3] = (temp_time & 0xF0) >> 4;
		minute = times[3]*10 + times[2];

		DS3231SN_read(0x02, &temp_time); // Чтение регистра часов
		times[4] = temp_time & 0x0F;
		times[5] = (temp_time & 0x30) >> 4;
		hour = times[5]*10 + times[4];
		/////////////////////////////////////////////////////

if (menu == 0)
{
		//for (i=0; i<6; i++)
		for (i=0; i<4; i++)   
		{
			if (times[i] != times_history[i])
			{
				times_history[i] = times[i];
				flag_zamena[i] = 1;
				//for (count=cifra[i]; count<cifra[i]+14; count++)
				for (count=cifra[i]; count<cifra[i]+7; count++)   
				{
					temp[count]=0;//задвигаем led_off во временный массив
				}
			}
		}
		if ((second > 30)&&(second < 38)&&(flag_temperature!=0))
		{
			if (second < 34)
			{
				write_temperature();
			}
			else
			{
				write_date();
			}
		} 
		else
		{
			if ((second==38)&&(flag_temperature!=0))
			{
				off_strip();
				//for (z=0; z<6; z++)
				for (z=0; z<4; z++)   
				{
					flag_zamena[z] = 1;
				}
				
				//temp[28] = 1;
				//temp[58] = 1;
				temp[14] = 1;
				temp[15] = 1;
			}
				timer1_init();
		}
	}
		//////////////////////////////////////////////
		
		minute_temp++;
		if (minute_temp > 70)
		{
			flag_temperature = 1;
			minute_temp = 0;
			DS3231SN_read(0x11, &temp_time); // Чтение регистра температуры
			temperature_MSB = temp_time;
			
			DS3231SN_read(0x12, &temp_time); // Чтение регистра температуры
			temperature_LSB = 25*(temp_time >> 6);
			
			DS3231SN_read(0x06, &temp_time);	//Чтение регистра год
			date[0] = temp_time & 0x0F;
			date[1] = (temp_time & 0xf0) >> 4;
			year = date[1]*10 + date[0];
			DS3231SN_read(0x05, &temp_time);	//Чтение регистра месяц
			date[2] = temp_time & 0x0F;
			date[3] = (temp_time & 0x10) >> 4;
			month = date[3]*10 + date[2];
			DS3231SN_read(0x04, &temp_time);	//Чтение регистра день
			date[4] = temp_time & 0x0F;
			date[5] = (temp_time & 0x30) >> 4;
			day = date[5]*10 + date[4];
		}
	}
}

int main(void)
{
	DDRC = 0x00;
	PORTC = 0xFF;
	i2c_init(); // Инициализация шины I2C
	DS3231SN_init();
	SPI_MasterInit();
	init_ADC();
	off_strip();
	colors = eeprom_read_byte(&color_level);	//выбор цвета ленты
	colors = 3;
	DS3231SN_read(0x11, &temp_time); // Чтение регистра температуры
	temperature_MSB = temp_time;
	
	DS3231SN_read(0x12, &temp_time); // Чтение регистра температуры
	temperature_LSB = 25*(temp_time >> 6);
	
	DS3231SN_read(0x06, &temp_time);	//Чтение регистра год
	date[0] = temp_time & 0x0F;
	date[1] = (temp_time & 0xf0) >> 4;
	year = date[1]*10 + date[0];
	DS3231SN_read(0x05, &temp_time);	//Чтение регистра месяц
	date[2] = temp_time & 0x0F;
	date[3] = (temp_time & 0x10) >> 4;
	month = date[3]*10 + date[2];
	DS3231SN_read(0x04, &temp_time);	//Чтение регистра день
	date[4] = temp_time & 0x0F;
	date[5] = (temp_time & 0x30) >> 4;
	day = date[5]*10 + date[4];
	while(1)
	{
		button();
		update_time();
	}
   return 0;
 }