#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include "ssd1306_display_driver.h"
#include "i2c.h"
#include "debug.h"
#include "br24t_eeprom_driver.h"

//this is used elsewhere (only one file) besides debug but kind of gross, maybe move to a header or something
#define SSD1306_ADDR      0x3c
#define SSD1306_CMD_REG   0x00
#define SSD1306_DATA_REG  0x40

#define SCREEN_PAGE_CNT   SCREEN_RES_Y / 8 

#define I2C_WRITE   0
#define I2C_READ    1

void debug_crash() {
  for(;;) {
    LED_DEBUG_PORT ^= _BV(LED_DEBUG); 
    _delay_ms(500);
  }
}

void scroll_test() {
  //sets scroll area to whole screen
  i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 3, (uint8_t[]){0xa3, 0x00, 0x20});
  //set up scroll options
  i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 6, (uint8_t[]){0x29, 0x00, 0x00, 0x00, 0x04, 0x00});
  //actually activate scroll
  i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 6, (uint8_t[]){0x2f});
}

void screen_lowlvl_testdraw() {
  unsigned int on_pix;
  unsigned int on_page;

  printf("running screen time tests\r\n");
  printf("generating test image...\r\n");
  for(on_pix = 0; on_pix < sizeof(screen_buffer); on_pix++) 
    screen_buffer[on_pix] = ((uint8_t)0xaa << (on_pix % 8));

  printf("page mode, individual byte per i2c call...\r\n");
  for(on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
    i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
    i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
    i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
    for(on_pix = 0; on_pix < SCREEN_RES_X; on_pix++)
      i2c_write_reg(SSD1306_ADDR, SSD1306_DATA_REG, screen_buffer[(on_page * 8) + on_pix]);
  }
  printf("page mode, 1 page per i2c call...\r\n");
  for(on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
    i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
    i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
    i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
    i2c_write_reg_multi(SSD1306_ADDR, SSD1306_DATA_REG, SCREEN_RES_X, &screen_buffer[on_page * SCREEN_RES_X]);
  }
  printf("screen test draw done!\n");
}


void uart_echo() {
  char buff;
  for(;;) {
    fread(&buff, 1, 1, stdin);
    fwrite(&buff, 1, 1, stdout);
  }
}

void test_clock() {
  printf("The time is %s, waiting 5 mintes...\r\n", "not implimented");
  _delay_ms(300000);
  printf("The time is now %s, hope your RTC clock works\r\n", "not implimented");
}


/*
 * TCNTn: timer/counter
 * TCCRnA/B/C: timer/counter control registers
 */
void timer_init() {
  TCCR1A = 0;         //no waveform generation or something like that
  TCCR1B = _BV(CS00); //no prescaling; use internal clock
  TCCR1C = 0;
}

//makes it easier to print time; is an unsigned int and NOT to be used for more then printing
unsigned int ticks_to_seconds(uint16_t start, uint16_t end) { 
  return ((unsigned int)(end - start) / F_CPU);
}

void test_timer() {
  uint16_t start, end;
  start = TCNT1;
  _delay_ms(1000);
  end = TCNT1;
  printf("1 second is %u ticks\r\n",  end - start);
}

void eeprom_testbyte() {
  uint8_t data_in = 0xdf;
  uint8_t data_out = 0;
  printf("writing 0x%x to eeprom...\r\n", data_in);
  EEPROM_WRITEBYTE(0x0000, data_in);
  _delay_ms(10); //max write cycle time
  data_out = EEPROM_READBYTE(0x0000);
  printf("byte read from eeprom: 0x%x\r\n", data_out);
}
