/*
 * $Id: main.c,v 1.3 2007/08/02 01:33:13 bsd Exp $
 *
 */

/*
 * Simple I2C Bus Scanner - reports the I2C addresses of any devices
 * found.  Results are reported on UART0, 9600 baud, N81.
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/twi.h>

#include <stdio.h>

#include "i2c.h"
#include "led.h"

//#define CPU_FREQ 16000000L  /* set to clock frequency in Hz */
#define   CPU_FREQ 14745600L  /* set to clock frequency in Hz */

#define BAUD 9600

#if CPU_FREQ == 16000000L
#define OCR_1MS 125
#elif CPU_FREQ == 14745600L
#define OCR_1MS 115
#endif

#define BAUD_RR(f,b) ((f % (16L*b) >= (16L*b)/2) ? (f / (16L*b)) : (f / (16L*b)) - 1)

volatile uint16_t ms_count;


/*
 * ms_sleep() - delay for specified number of milliseconds
 */
void ms_sleep(uint16_t ms)
{
  TCNT0  = 0;
  ms_count = 0;
  while (ms_count != ms)
    ;
}


/* 
 * millisecond counter interrupt vector 
 */
SIGNAL(SIG_OUTPUT_COMPARE0)
{
  ms_count++;
}


/*
 * Initialize timer0 to use the main crystal clock and the output
 * compare interrupt feature to generate an interrupt approximately
 * once per millisecond to use as a general purpose time base.
 */
void init_timer0(void)
{
  TCCR0 = 0;
  TIFR  |= _BV(OCIE0)|_BV(TOIE0);
  TIMSK |= _BV(TOIE0)|_BV(OCIE0);         /* enable output compare interrupt */
  TCCR0  = _BV(WGM01)|_BV(CS02)|_BV(CS00); /* CTC, prescale = 128 */
  TCNT0  = 0;
  OCR0   = OCR_1MS;                     /* match in aprox 1 ms */
}




int def_putc(char ch, FILE * f)
{
  /* output character to UART0 */
  while ((UCSR0A & _BV(UDRE)) == 0)
    ;
  UDR0 = ch;
  return 0;
}


uint8_t i2cscan(void)
{
  uint8_t i;
  uint8_t n;

  n = 0;
  
  for (i=1; i<127; i++) {
    led_on();
    ms_sleep(10);
    /* start condition */
    if (i2c_start(0x08, 1)) {
      break;
    }
    
    /* address slave device, write */
    if (!i2c_sla_rw(i, 0, TW_MT_SLA_ACK, 0)) {
      printf("found device at address 0x%02x\n", i);
      n++;
    }
    
    i2c_stop();
    led_off();
    ms_sleep(10);
  }

  return n;
}


int main(void)
{
  uint16_t br;
  uint8_t n;

  init_timer0();
  led_init();

  /* compute baud rate register value */
  br = BAUD_RR(CPU_FREQ, BAUD);
  
  /* enable UART0 */
  UBRR0H = (br >> 8) & 0xff;
  UBRR0L = br & 0xff;
  UCSR0B = _BV(TXEN); /* enable transmitter only */

  /* enable interrupts */
  sei();

  /* initialize stdio */
  fdevopen(def_putc, NULL);

  /* set the I2C bit rate generator to 100 kb/s */
  TWSR &= ~0x03;
  TWBR  = 28;
  TWCR |= _BV(TWEN);

  printf("\n\nI2C bus scanner starting ...\n\n");
  n = i2cscan();
  printf("\n%u devices found\n", n);
  printf("scan complete\n");

  while (1)
    ;
}

