#include <IIC_ultimate.h>


void DoNothing(void);

u8 i2c_Do;								// Переменная состояния передатчика IIC

u8 i2c_Buffer[i2c_MaxBuffer];			// Буфер для данных работы в режиме Master
u8 i2c_index;							// Индекс этого буфера
u8 i2c_ByteCount;						// Число байт передаваемых

u8 i2c_SlaveAddress;						// Адрес подчиненного

u8 i2c_PageAddress[i2c_MaxPageAddrLgth];	// Буфер адреса страниц (для режима с sawsarp)
u8 i2c_PageAddrIndex;						// Индекс буфера адреса страниц
u8 i2c_PageAddrCount;						// Число байт в адресе страницы для текущего Slave

											// Указатели выхода из автомата:
IIC_F MasterOutFunc = &DoNothing;			//  в Master режиме
IIC_F ErrorOutFunc = &DoNothing;			//  в результате ошибки в режиме Master
u8 END;

/*
u8 	WorkLog[30];						// Лог пишем сюда
u8     WorkIndex=0;						// Индекс лога
*/

interrupt[TWI]	 void twi(void){							// Прерывание TWI Тут наше все.

/*
// Отладочный кусок. Вывод лога работы конечного автомата в буфер памяти, а потом. По окончании работы через UART на волю
if (WorkIndex <99)							// Если лог не переполнен
{
	if (TWSR)								// Статус нулевой?
		{
		WorkLog[WorkIndex]= TWSR & 0xF8;			// Пишем статус в лог
		WorkIndex++;						
		}
	else
		{
		WorkLog[WorkIndex]= 0x20;			// Если статус нулевой то вписываем FF
		WorkIndex++;
		}
}
*/
switch(TWSR & 0xF8)						// Отсекаем биты прескалера
	{
	case 0x00:	// Bus Fail (автобус сломался)
			{
			i2c_Do |= i2c_ERR_BF;
			TWCR = 0<<TWSTA|1<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;  	// Go!
			MACRO_i2c_WhatDo_ErrorOut
			break;
			}

	case 0x08:	// Старт был, а затем мы:
			{
			if( (i2c_Do & i2c_type_msk)== i2c_sarp)							// В зависимости от режима
				{
				i2c_SlaveAddress |= 0x01;									// Шлем Addr+R
				}
			else															// Или 
				{
				i2c_SlaveAddress &= 0xFE;									// Шлем Addr+W
				}
			
			TWDR = i2c_SlaveAddress;													// Адрес слейва
			TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;  	// Go!
			break;
			}
				
	case 0x10:	// Повторный старт был, а затем мы
			{
			if( (i2c_Do & i2c_type_msk) == i2c_sawsarp)						// В зависимости от режима
				{
				i2c_SlaveAddress |= 0x01;									// Шлем Addr+R
				}
			else
				{
				i2c_SlaveAddress &= 0xFE;									// Шлем Addr+W
				}

			// To Do: Добавить сюда обработку ошибок 

			TWDR = i2c_SlaveAddress;													// Адрес слейва
			TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;  	// Go!
			break;
			}

	case 0x18:	// Был послан SLA+W получили ACK, а затем:
			{
			if( (i2c_Do & i2c_type_msk) == i2c_sawp)						// В зависимости от режима
				{
				TWDR = i2c_Buffer[i2c_index];								// Шлем байт данных
				i2c_index++;												// Увеличиваем указатель буфера
				TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;  // Go! 

				}

			if( (i2c_Do & i2c_type_msk) == i2c_sawsarp)
				{
				TWDR = i2c_PageAddress[i2c_PageAddrIndex];					// Или шлем адрес странцы (по сути тоже байт данных)
				i2c_PageAddrIndex++;										// Увеличиваем указатель буфера страницы
				TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;	// Go!
				}	 
			}
			break;

	case 0x20:	// Был послан SLA+W получили NACK - слейв либо занят, либо его нет дома.
			{
			i2c_Do |= i2c_ERR_NA;															// Код ошибки
			TWCR = 0<<TWSTA|1<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;			// Шлем шине Stop

			MACRO_i2c_WhatDo_ErrorOut 														// Обрабатываем событие ошибки;
			break;
			}

	case 0x28: 	// Байт данных послали, получили ACK!  (если sawp - это был байт данных. если sawsarp - байт адреса страницы)
			{	// А дальше: 
			if( (i2c_Do & i2c_type_msk) == i2c_sawp)							// В зависимости от режима
				{
				if (i2c_index == i2c_ByteCount)												// Если был байт данных последний
					{																		
					TWCR = 0<<TWSTA|1<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;	// Шлем Stop

					MACRO_i2c_WhatDo_MasterOut												// И выходим в обработку стопа

					}
				else
					{
					TWDR = i2c_Buffer[i2c_index];												// Либо шлем еще один байт
					i2c_index++;
					TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;  	// Go!
					}
				}

			if( (i2c_Do & i2c_type_msk) == i2c_sawsarp)						// В другом режиме мы
				{
				if(i2c_PageAddrIndex == i2c_PageAddrCount)					// Если последний байт адреса страницы
					{
					TWCR = 1<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;		// Запускаем Повторный старт!
					}
				else
					{														// Иначе 
					TWDR = i2c_PageAddress[i2c_PageAddrIndex];				// шлем еще один адрес страницы
					i2c_PageAddrIndex++;									// Увеличиваем индекс счетчика адреса страниц
					TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;		// Go!
					}
				}	 
			}
			break;

	case 0x30:	//Байт ушел, но получили NACK причин две. 1я передача оборвана слейвом и так надо. 2я слейв сглючил.
			{
			i2c_Do |= i2c_ERR_NK;				// Запишем статус ошибки. Хотя это не факт, что ошибка. 

			TWCR = 0<<TWSTA|1<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;		// Шлем Stop

			MACRO_i2c_WhatDo_MasterOut													// Отрабатываем событие выхода

			break;
			}

	case 0x38:	//  Коллизия на шине. Нашелся кто то поглавней
			{
			i2c_Do |= i2c_ERR_LP;			// Ставим ошибку потери приоритета

			// Настраиваем индексы заново. 
			i2c_index = 0;
			i2c_PageAddrIndex = 0;

			TWCR = 1<<TWSTA|0<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;		// Как только шина будет свободна 
			break;																		// попробуем передать снова.
			}

	case 0x40: // Послали SLA+R получили АСК. А теперь будем получать байты
			{
			if(i2c_index+1 == i2c_ByteCount)								// Если буфер кончится на этом байте, то 
				{
				TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|0<<TWEA|1<<TWEN|1<<TWIE;	// Требуем байт, а в ответ потом пошлем NACK(Disconnect)
				}															// Что даст понять слейву, что мол хватит гнать. И он отпустит шину
			else
				{
				TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|1<<TWEA|1<<TWEN|1<<TWIE;	// Или просто примем байт и скажем потом ACK
				}

			break;
			}

	case 0x48: // Послали SLA+R, но получили NACK. Видать slave занят или его нет дома. 
			{
			i2c_Do |= i2c_ERR_NA;															// Код ошибки No Answer
			TWCR = 0<<TWSTA|1<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;			// Шлем Stop

			MACRO_i2c_WhatDo_ErrorOut														// Отрабатываем выходную ситуацию ошибки
			break;
			}

	case 0x50: // Приняли байт.
			{ 
			i2c_Buffer[i2c_index] = TWDR;			// Забрали его из буфера
			i2c_index++;

			// To Do: Добавить проверку переполнения буфера. А то мало ли что юзер затребует

			if (i2c_index+1 == i2c_ByteCount)		// Если остался еще один байт из тех, что мы хотели считать
				{
				TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|0<<TWEA|1<<TWEN|1<<TWIE;		// Затребываем его и потом пошлем NACK (Disconnect)
				}
			else
				{
				TWCR = 0<<TWSTA|0<<TWSTO|1<<TWINT|1<<TWEA|1<<TWEN|1<<TWIE;		// Если нет, то затребываем следующий байт, а в ответ скажем АСК
				}
			break;
			}

	case 0x58:	// Вот мы взяли последний байт, сказали NACK слейв обиделся и отпал. 
			{
			i2c_Buffer[i2c_index] = TWDR;													// Взяли байт в буфер
			TWCR = 0<<TWSTA|1<<TWSTO|1<<TWINT|i2c_i_am_slave<<TWEA|1<<TWEN|1<<TWIE;			// Передали Stop

			MACRO_i2c_WhatDo_MasterOut														// Отработали точку выхода

			break;
			}


	}
}

void DoNothing(void)																// Функция пустышка, затыкать несуществующие ссылки
{
 END = 0;
}

void Init_i2c(void)							// Настройка режима мастера
{
i2c_PORT |= 1<<i2c_SCL|1<<i2c_SDA;			// Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился
i2c_DDR &=~(1<<i2c_SCL|1<<i2c_SDA);
TWBR = 0x0C;                                         // Настроим битрей       						
TWSR = 0x00;
}

