/*********************************************

Передатчик для радиоуправления машинкой
Среда разработки: Version: Neon.1 Release (4.6.1) Build id: 20160913-0900, WinAVR 20100110
ОСОБЕНОСТИ:
1. отладка всегда выдается в USART на скорости 9600
2. засыпает через 5 минут отсутствия команд
3. Отправляет в эфир команду, только если были измtнения по нажатым кнопкам
4. Не удалось полностью усыпить NRF, жрет 3.12ма во сне.

Device: atmega8L

Program:    5330 bytes (65.1% Full)
(.text + .data + .bootloader)

Data:         41 bytes (4.0% Full)
(.data + .bss + .noinit)

EEPROM:        9 bytes (1.8% Full)
(.eeprom)


Finished building: sizedummy

Linker argument: -Wl,-gc-sections
Compiller argument: -ffunction-sections

1. в нормальном состоянии INT - выход с нулем
2. в нормальном состоянии порты кнопок - входы с подтяжкой
3. в нормальном состоянии нажатие кнопок отслеживается поллингом порта кнопок - нажатые будут в 0, ненажатые - в 1
4. перед тем, как уснуть, производится перенастройка портов в следующей последовательности
5. INT делается входом с подтяжкой, порты кнопок делаются выходами с нулями
6. настраивается прерывание по переходу в 0,
7. усыпление.
8. после пробуждения (прерывание не надо обрабатывать) восстанавливается нормальное состояние - п.1

 *********************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include "avr_helper.h"
#include <util/delay.h>
#include "protocol.h"
#include "led.h"
#include "timer.h"
#include <stdio.h>
#include "adc.h"
#include "buttons.h"
#include <avr/sleep.h>
#include <avr/wdt.h>
#include "mirf.h"
#include "nRF24L01.h"
#include "com_io.h"
#include "config.h"


//static uint8_t cmd_buf[32];			// буфер для принятой команды

/** Усыпляем МК, оставляя пробуждение от низкого уровня на INT0.
 */
void go_sleep(void){
#if defined(DDRA)
	uint8_t porta, ddra;
#endif
	uint8_t ddrb, ddrc, ddrd;
	uint8_t portb, portc, portd;

	// запоминаем состояние периферийных регистров
#if defined(DDRA)
	ddra = DDRA;
#endif
	ddrb = DDRB;
	ddrc = DDRC;
	ddrd = DDRD;
#if defined(PORTA)
	porta = PORTA;
#endif
	portb = PORTB;
	portc = PORTC;
	portd = PORTD;

	// гасим перефирию
	mirf_power_down();							// усыпляем NRF
	nrf_print_config();
	_delay_ms(100);
	adc_powerdown();							// переводим ацп в powerdown для сокращения расхода энергии
	//_delay_ms(10);
	// устанавливаем состояния пинов, при котором наименьшие утечки по ним
#if defined (PORTA)
	PORTA= 0;
#endif
	PORTB = 0;
	PORTC = 0;
	PORTD = 0;
#if defined(DDRA)
	DDRA = 0xFF;
#endif
	DDRB = 0xFF;
	DDRC = 0xFF;
	DDRD = 0xFF;
	// гасим турбо-режим
	//OSCCAL = 0;

	// настраиваем порты для пробуждение по любой кнопке
	// INT делается входом с подтяжкой, порты кнопок делаются выходами с нулями
	DDR(INT_PORT)&= ~ _BV(INT_PIN); 			// INT0 port configure as input
	PORT(INT_PORT)|= _BV(INT_PIN);				// and pullup

	DDR(KEY_PORT) |= KEY_ANY;					// output
	PORT(KEY_PORT) &= ~ KEY_ANY;				// not pullup
	DDR(KEY_FORWARD_PORT) |= KEY_FORWARD;		// output
	PORT(KEY_FORWARD_PORT) &= ~ KEY_FORWARD;	// not pullup

	// level interrupt INT0 (low level)
	MCUCR &= ~((1 << ISC01) | (1 << ISC00));
	// enable external interrupt
	GICR |= (1 << INT0);
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);							// задаем сон = Powerdown
	sleep_enable();													// уходим в сон
	sleep_cpu();
	sleep_disable();
	// просыпаемся по нажатию кнопки на INT0
	// disable external interrupt here, in case the external low pulse is too long
	GICR &= ~(1 << INT0);

	// активируем турбо-режим
	//OSCCAL = 0xFF;
	_delay_ms(10);
	// восстанавливаем состояния портов
#if defined(PORTA)
	PORTA = porta;
#endif
	PORTB = portb;
	PORTC = portc;
	PORTD = portd;
#if defined(DDRA)
	DDRA = ddra;
#endif
	DDRB = ddrb;
	DDRC = ddrc;
	DDRD = ddrd;
	// будим переферию
	mirf_power_up();												// пробуждаем NRF
}

SIGNAL(INT0_vect)
{
   // ISR might be empty, but is necessary nonetheless
	//led2_on();
    // disable external interrupt here, in case the external low pulse is too long
    //GICR &= ~(1 << INT0);
	asm("nop");
}


static buttons_t cur_state_port,last_state_port;
char tmp;
//param_receipt_t send_package;

int main(void){

    	key_init();
    	led_init();
    	timer1_init();								// запускаем таймер для ухода в powerdown
    	adc_init();									// конфигурим ацп

        printf_P(PSTR("START\r"));
        load_config(&config);						// загружаем настройки девайса
        //config.debug_on=ON;

		mirf_init();									// инициализируем перефирию для работы с NRF (выводы, spi)
		_delay_ms(50);									// технологическая задержка
		printf_P(PSTR("NRF config"));
		tmp=mirf_config();
		if (tmp==1){							// конфигурим сам NRF (канал, адреса, подтверждение и т.д.)
			led2_on();
			printf_P(PSTR(" OK\r"));
			led2_off();
		}else{
			led1_on();
			printf_P(PSTR(" ERROR=%d\r"),tmp);
			led1_off();
		}
		_delay_ms(500);

		led1_on();
		led2_on();
		buzzer_on();
		_delay_ms(100);
		led1_off();
		led2_off();
		buzzer_off();


		nrf_print_status();
		nrf_print_config();
		nrf_print_setup();
		nrf_print_future();
		nrf_print_fifostatus();
		nrf_print_cd();
		nrf_print_chanel();
		nrf_print_payload();
		nrf_print_tx_addr();
		nrf_print_rx_addr_p0();
		nrf_print_rx_addr_p1();

		sei(); // interrupt on, clock starts ticking now

        while(1){

        if (time_is_over(DELAY_POWERDONW)){
       		// уходим в powerdown
        	printf_P(PSTR("sleeping\r"));
        	go_sleep();
        	printf_P(PSTR("wakeup\r"));
        	reset_timer(DELAY_POWERDONW);
       	}

        if (time_is_over(DELAY_REPEAT)){
        	printf_P(PSTR("battery measurement\r"));
        	printf_P(PSTR("battery voltage=%04d\r"),get_battery_adc());
			if (get_battery_low()){
				//printf_P(PSTR("battery voltage=%04d\r"),get_battery_adc());
				buzzer_on();
				_delay_ms(100);
				buzzer_off();
				_delay_ms(100);
				buzzer_on();
				_delay_ms(100);
				buzzer_off();
			}
        	reset_timer(DELAY_REPEAT);
       	}

		// читаем в переменную состояниz кнопок в структуре отправки в приемник
		cur_state_port.byte = get_key();
		if (cur_state_port.byte && config.debug_on){
			led2_on();
		}else {
			led2_off();
		}

		// Проверяем, изменилось ли чего в состоянии кнопок
		if (cur_state_port.byte != last_state_port.byte){
			printf_P(PSTR("KEY= %02d\r"), cur_state_port.byte);
			 // Отправялем изменения в эфир
			tmp=mirf_write((void*)&cur_state_port,sizeof(cur_state_port));
			printf_P(PSTR("SEND TO RADIO code=%d\r"),tmp);

			 // Отладка по кнопкам
			 printf_P(PSTR("KEY\t\t = %02d BACKRWARD=%x LEFT=%x RIGHT=%x BOOZ=%x BLINK=%x LAMP=%x FORWARD=%x\r"),
					  cur_state_port.byte,
					  cur_state_port.k_back,
					  cur_state_port.k_left,
					  cur_state_port.k_right,
					  cur_state_port.k_booz,
					  cur_state_port.k_blink,
					  cur_state_port.k_lamp,
					  cur_state_port.k_fwd
					  );

			// сохраняем состояние кнопок для дальнейшего сравнения
			last_state_port.byte = cur_state_port.byte;
			reset_timer(DELAY_POWERDONW);	// сбрасывает таймер ухода в сон
		 }
}
}
