/* 
2010-08-11
Using the 2-wire interface to write a byte to address 0x10
 */

#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 8000000UL/8UL
#include <util/delay.h>

/* commands */
#define DRIVER_SPECIAL 0b00000000
#define DRIVER_DIGIT1 0b01000000
#define DRIVER_DIGIT2 0b10000000
#define DRIVER_DIGIT3 0b11000000
/* driver digit enum */
enum DIGIT{
	DIGIT0 = 0,
	DIGIT1,
	DIGIT2,
	DIGIT3,
	DIGIT4,
	DIGIT5,
	DIGIT6,
	DIGIT7,
	DIGIT8,
	DIGIT9,
	DIGITSPACE,
	DIGITUNDERSCORE,
	DIGITMINUS,
	DIGITA,
	DIGITB,
	DIGITC,
	DIGITD,
	DIGITE,
	DIGITF,
	DIGITG,
	DIGITH,
	DIGITI,
	DIGITJ,
	DIGITK,
	DIGITL,
	DIGITM,
	DIGITN,
	DIGITO,
	DIGITP,
	DIGITQ,
	DIGITR,
	DIGITS,
	DIGITT,
	DIGITU,
	DIGITV,
	DIGITW,
	DIGITX,
	DIGITY,
	DIGITZ,
	DIGITTOP,
};

void wait_ms(int w){
  int i;
  for(i=0; i<w ; ++i) _delay_ms(1);
}

int twi_send(char s){

	/* enable the TWI and attempt to go */
	TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTA);
	while(!(TWCR & _BV(TWINT)));	/* wait for the interrupt */
	if((TWSR & 0xf8) != 0x8) return 0;	/* error condition! */
	/* otherwise, load up the address */
	TWDR = (0x10 << 1) | 0; /* no idea what this should look like D: */
	TWCR = _BV(TWINT) | _BV(TWEN);
	/* wait for reception of ACK */
	while(!(TWCR & _BV(TWINT)));
	if((TWSR & 0xf8) != 0x18) return 0; /* error condition */
	/* received ACK */
	/* load data */
	TWDR = s;
	TWCR = _BV(TWINT) | _BV(TWEN);
	/* wait for ACK again */
	while(!(TWCR & _BV(TWINT)));
	if((TWSR & 0xf8) != 0x28) return 0; /* error condition */
	TWCR = _BV(TWSTO) | _BV(TWINT);

	return 1;
}

int twi_send_bus_check(char s){

	int i = twi_send(s);
	if(i == 0){
		DDRB = 1;
		PORTB = 1;
		//if((TWSR & 0xf8) == 0x00)
			TWCR = _BV(TWSTO) | _BV(TWINT);
	}
	return i;
}

void display_number(unsigned char x){
  /* assuming ports C and D are properly set up */
  /* get the digits */
  unsigned char d0,d1,d2,t1;
  if(x>999) d0 = d1 = d2 = 10;
  else{
    d2 = x / 100;
    t1 = x % 100;
    d1 = t1 / 10;
    d0 = t1 % 10;
  };
  /* build the portout */
	twi_send_bus_check(DRIVER_DIGIT1|d2);
	twi_send_bus_check(DRIVER_DIGIT2|d1);
	twi_send_bus_check(DRIVER_DIGIT3|d0);
}

/* SCROLLING MESSAGE! */
/* hello there people 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ   */
unsigned char msg[] = {
	DIGITSPACE,
	DIGITSPACE,
	DIGITSPACE,
	DIGITH,
	DIGITE,
	DIGITL,
	DIGITL,
	DIGITO,
	DIGITSPACE,
	DIGITT,
	DIGITH,
	DIGITE,
	DIGITR,
	DIGITE,
	DIGITSPACE,
	DIGITP,
	DIGITE,
	DIGITO,
	DIGITP,
	DIGITL,
	DIGITE,
	DIGITSPACE,
	DIGITSPACE,
	DIGITSPACE,
	DIGITSPACE,
	DIGIT0,
	DIGIT1,
	DIGIT2,
	DIGIT3,
	DIGIT4,
	DIGIT5,
	DIGIT6,
	DIGIT7,
	DIGIT8,
	DIGIT9,
	DIGITSPACE,
	DIGITUNDERSCORE,
	DIGITMINUS,
	DIGITA,
	DIGITB,
	DIGITC,
	DIGITD,
	DIGITE,
	DIGITF,
	DIGITG,
	DIGITH,
	DIGITI,
	DIGITJ,
	DIGITK,
	DIGITL,
	DIGITM,
	DIGITN,
	DIGITO,
	DIGITP,
	DIGITQ,
	DIGITR,
	DIGITS,
	DIGITT,
	DIGITU,
	DIGITV,
	DIGITW,
	DIGITX,
	DIGITY,
	DIGITZ,
	DIGITSPACE,
	DIGITSPACE,
	DIGITSPACE,
	DIGITSPACE,
};

int main(void){
	/* Go to 8Mhz/8 */
	CLKPR = _BV(CLKPCE);
	CLKPR = 3;
	/*wait_ms(500);*/
	twi_send_bus_check(10);
	unsigned int i;
	while(1){
		wait_ms(200);
		switch(sizeof(msg) - i){
			case 1:
				twi_send_bus_check(DRIVER_DIGIT1 | msg[i]);
				twi_send_bus_check(DRIVER_DIGIT2 | msg[0]);
				twi_send_bus_check(DRIVER_DIGIT3 | msg[1]);
				break;
			case 2:
				twi_send_bus_check(DRIVER_DIGIT1 | msg[i]);
				twi_send_bus_check(DRIVER_DIGIT2 | msg[i+1]);
				twi_send_bus_check(DRIVER_DIGIT3 | msg[0]);
				break;
			default:
				twi_send_bus_check(DRIVER_DIGIT1 | msg[i]);
				twi_send_bus_check(DRIVER_DIGIT2 | msg[i+1]);
				twi_send_bus_check(DRIVER_DIGIT3 | msg[i+2]);
		}
		++i;
		if(i == sizeof(msg)) i = 0;
	};
	return 0;
}

