/*
 * Project_Garage_Attiny26.c
 *
 * Created: 2013.03.10. 13:52:17
 *  Author: Orova Vince
 */ 

#define MotorPin PINB3
#define RemoteBtnPin PINB6

#define SetBtnPin PINA0
#define StopSwitchClosedPin PINA1
#define StopSwitchOpenedPin PINA2
#define LedPin PINA3
#define RelayOpenPin PINA4
#define RelayClosePin PINA5

#define _ClosedSwitchState !(PINA & _BV(StopSwitchClosedPin))
#define _OpenedSwitchState !(PINA & _BV(StopSwitchOpenedPin))
#define _RemoteButtonState !(PINB & _BV(RemoteBtnPin))
#define _SetButtonState !(PINA & _BV(SetBtnPin))
#define _OpenRelayOn PORTA |= _BV(RelayOpenPin)
#define _OpenRelayOff PORTA &= ~_BV(RelayOpenPin)
#define _CloseRelayOn PORTA |= _BV(RelayClosePin)
#define _CloseRelayOff PORTA &= ~_BV(RelayClosePin)
#define _LedOn PORTA |= _BV(LedPin);
#define _LedOff PORTA &= ~_BV(LedPin);

 

#include <avr/io.h>
#include <avr/eeprom.h>

#define F_CPU 8000000UL  // Specifies a system clock of 8MHz
#include<util/delay.h>

uint8_t iRemoteOldState = 0;	// távirányító gomb előző állapota
uint8_t iSetOldState = 0;		// set gomb előző állapota
uint16_t iDelayCounter = 0;		// késleltetéseket számolja
uint8_t iMotorMoving = 0;		// 0: a motor áll,  1: a motor nyit,  2: a motor zár
uint16_t iStoredDelay = 0;		// ennyi ezredmásodperc múlva lassít a motor3
uint8_t iWorking = 0;			// várunk a távirányítóra vagy csinálunk valamit
uint16_t iERDelay = 0;			// vészüzemben használt számláló

void analogWriteMotor(uint8_t val) {
	if (val == 255) {
		// Switch off pwm and disconnect pin from timer
		TCCR1A = 0;
		TCCR1B = 0;
		// Switch motor 100%
		PORTB |= _BV(MotorPin);
	} else
	if (val == 0) {
		// Switch off pwm and disconnect pin from timer
		TCCR1A = 0;
		TCCR1B = 0;
		// Switch off motor
		PORTB &= ~_BV(MotorPin);
	} else {
	    if (!(TCCR1A & _BV(PWM1B)) || !(TCCR1A & _BV(COM1B0))) {
			TCCR1B |= _BV(CS12); // set prescaler to 8
			OCR1C = 199;
			// switch on PWM and connect Motor pin
			TCCR1A |= _BV(PWM1B) | _BV(COM1B0);
		}		
		// set PWM for duty cycle
		OCR1B = val;
	}
}
uint8_t CheckRemoteButton() {
	uint8_t bBtnActualState = _RemoteButtonState;
	_delay_ms(5);
	if ((bBtnActualState) == _RemoteButtonState) {
		if ((bBtnActualState) && (!iRemoteOldState)) { // most nyomta meg a gombot
			iRemoteOldState = bBtnActualState;
			return 1;
		} else {
			iRemoteOldState = bBtnActualState;
		}
	}
	return 0; // prellezünk
};

uint8_t CheckSetButton() {
	uint8_t bBtnActualState = _SetButtonState;
	_delay_ms(5);
	if ((bBtnActualState) == _SetButtonState) {
		if ((bBtnActualState) && (!iSetOldState)) { // most nyomta meg a gombot
			iSetOldState = bBtnActualState;
			return 1;
		} else {
			iSetOldState = bBtnActualState;
		}
	}
	return 0; // prellezünk
};

void CDelay(uint16_t val) {
	uint16_t i;
	for (i = 1; i <= val; i+=5)
	{
		_delay_ms(5);
	}
	iDelayCounter += val;
}

void SetMotor(uint8_t irany, uint8_t sebesseg){
	// motor off
	if ((irany == 0) || (sebesseg == 0)) {
		_OpenRelayOff;
		_CloseRelayOff;
		analogWriteMotor(0);
	} else
	// motor nyit
	if ((irany == 1) && (sebesseg > 0)) {
		_CloseRelayOff;
		_OpenRelayOn;
		analogWriteMotor(sebesseg);
	} else
	// motor zar
	if ((irany == 2) && (sebesseg > 0)) {
		_OpenRelayOff;
		_CloseRelayOn;
		analogWriteMotor(sebesseg);
	};
	iMotorMoving = irany;
}

void StoreDelayCounter(uint16_t val) {
	iStoredDelay = val;
	eeprom_busy_wait();
	eeprom_write_word((uint16_t*)1, val);
}

uint16_t ReadDelayCounter() {
	eeprom_busy_wait();
	return eeprom_read_word((uint16_t*)1);
}

void GoToSleep() {
	SetMotor(0, 0);
	iWorking = 0;
	iDelayCounter = 0;	
};

int main(void)
{
	// Set pins as output
	DDRB = _BV(MotorPin);
	DDRA = _BV(LedPin) | _BV(RelayOpenPin) | _BV(RelayClosePin);
	// switch off pull-up on analog comparator
	PORTA &= ~_BV(PIN6);
	PORTA &= ~_BV(PIN7);

	// init
	GoToSleep();

	// Read Eprom
	iStoredDelay = ReadDelayCounter();

	// Set Analog Comparator
	PORTA &= ~_BV(PINA6);
	PORTA &= ~_BV(PINA7);
	ACSR |= _BV(ACIE);	// enable interrupt
	ACSR |= _BV(ACIS0) || _BV(ACIS1);	// rising edge
	ACSR |= _BV(ACI);	// enable trigger

	while(1)
	{
		if(!iWorking) {
			// másodpercenként megnézzük a távirányitót
			_LedOn;
			_delay_ms(25);
			_LedOff;
			_delay_ms(975);
			iWorking = CheckRemoteButton();
			if (!iWorking) {
				iWorking = CheckSetButton();
				if (iWorking) {
					StoreDelayCounter(0);
				}
			}
		} else {
			if (!iMotorMoving) {  // nem megy a motor, bekapcsoljuk
				if (_OpenedSwitchState) {  
					SetMotor(2, 255);	// teljesen nyitott (végállás), zárunk
				} else {
					SetMotor(1, 255); // nincs nyitva (zárt vagy félúton), nyitunk
				}					
			}
			
			// Kinyílt
			if ((iMotorMoving == 1) && (_OpenedSwitchState)) { 
				CDelay(25);
				GoToSleep();
			}
			
			// Bezárt
			if ((iMotorMoving == 2) && (_ClosedSwitchState)) { 
				CDelay(25);
				GoToSleep();
			}

			// Túlterhelés 
			if (ACSR & _BV(ACO)) {
				SetMotor(iMotorMoving, 0);
				_LedOn;
				iERDelay = 0;
				while ((!_RemoteButtonState) && (iERDelay < 500)) {
					_delay_ms(50);
					iERDelay += 50;
				}
				if (iERDelay >= 500) {  // nem nyomták a gombot
					ACSR |= _BV(ACI);	// enable trigger
					if (iMotorMoving == 1) {		//ellenkező irány
						iMotorMoving = 2;
					} else if (iMotorMoving == 2) {
						iMotorMoving = 1;
					}
					iERDelay = 0;
					SetMotor(iMotorMoving, 255);
					while ((!_RemoteButtonState) && (iERDelay < 1500) && !(ACSR & _BV(ACO))) {
						_delay_ms(25);
						iERDelay += 25;
					}
				}
				GoToSleep();
				_delay_ms(1000);
				_LedOff;
				ACSR |= _BV(ACI);	// enable trigger
			}
			
			if (CheckSetButton()) {
				StoreDelayCounter(iDelayCounter);				
			} 
			iDelayCounter += 5;
			
			if ((iStoredDelay > 0) && (iDelayCounter > iStoredDelay) && (iMotorMoving)) {
				SetMotor(iMotorMoving, 100);
			}
			
			// ha már 20 másodperce jár a motor, akkor leállunk
			if (iDelayCounter > 20000) {
				GoToSleep();
			}
			
			// megnyomtuk a gombot (ER STOP)
			if (CheckRemoteButton()) {
				GoToSleep();
			}
			iDelayCounter += 5;

			if ((iDelayCounter & 128) || (iDelayCounter & 512)) {
				_LedOff;
			} else {
				_LedOn;
			}
			CDelay(25);
		}
	}
}