// 易占回路 for ATtiny2313 (AVR GCC)
// (C)2007-2008 by Takumi Funada, Musashinodenpa

#define F_CPU 1000000

#include <util/delay.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>

#define Button1_Down ((PINA & 0b00000001) == 0)
#define Button2_Down ((PINA & 0b00000010) == 0)
#define EEPROM_Log (0x10)  // 得卦を保存するEEPROMアドレス
#define BLANK (255)
#define LED_Delay (127)

// ビットマップ

unsigned char matrix[7] = {0,0,0,0,0,0,0};
unsigned char matrix_num[7] = {0,0,0,0,0,0,0};
unsigned char matrix_kou[7] = {0,0,0,0,0,0,0};

unsigned char left_prompt[2][7] = {  // プロンプト(2フレーム)
	{0, 0, 0, 0, 20, 8, 0},
	{0, 0, 0, 0, 0, 20, 8}
};
const prog_uint8_t Number_Font[11][3] PROGMEM = {
	{31, 17, 31},
	{0, 31, 0},
	{29, 21, 23},
	{21, 21, 31},
	{7, 4, 31},
	{23, 21, 29},
	{31, 21, 29},
	{1, 1, 31},
	{31, 21, 31},
	{23, 21, 31},
	{0, 0, 0} // Space
};

// 変換テーブル(ビットパターン→易経での順番)
const prog_uint8_t Ka_Table[64] PROGMEM = {
	2, 46, 7, 19, 15, 36, 46, 11,
	16, 51, 40, 54, 62, 55, 32, 34,
	8, 3, 29, 60, 39, 63, 48, 5,
	45, 17, 47, 58, 31, 49, 28, 43,
	23, 27, 4, 41, 52, 22, 18, 26,
	35, 21, 64, 38, 56, 30, 50, 14,
	20, 42, 59, 61, 53, 37, 57, 9,
	12, 25, 6, 10, 33, 13, 44, 1
};

// ビットマップの単純コピー
void cp(unsigned char a[7], unsigned char b[7])
{
	unsigned char i;
	for(i = 0; i < 7; i++) {
		b[i] = a[i];
	}
}

// 2桁の数字を生成
void draw_number(unsigned char d10, unsigned char d1, unsigned char b[7])
{
	b[0] = pgm_read_byte(Number_Font[d10]);
	b[1] = pgm_read_byte(Number_Font[d10]+1);
	b[2] = pgm_read_byte(Number_Font[d10]+2);
	b[3] = 0;
	b[4] = pgm_read_byte(Number_Font[d1]);
	b[5] = pgm_read_byte(Number_Font[d1]+1);
	b[6] = pgm_read_byte(Number_Font[d1]+2);
}	

// LEDをリフレッシュ
void bitblt(unsigned char p[7])
{
	unsigned char i;
	for(i = 0; i < 7; i++) {
		PORTD = 0b01111111 & ~(1<<i); // activate a cathode
		PORTB = 0b00010000 & p[i]; // activate an anode
		_delay_us(LED_Delay);
		PORTB = 0b00001000 & p[i];
		_delay_us(LED_Delay);
		PORTB = 0b00000100 & p[i];
		_delay_us(LED_Delay);
		PORTB = 0b00000010 & p[i];
		_delay_us(LED_Delay);
		PORTB = 0b00000001 & p[i];
		_delay_us(LED_Delay);
		PORTB = 0;
	}
}

// 易のサインを描く
void render(unsigned char ka, unsigned char kou)
{
	unsigned char i;

	// 64卦
	for(i = 0; i < 6; i++) {
		matrix[i] = 0b00011011 + (((ka>>(5-i)) & 0b00000001)<<2);
	}
	matrix[6] = 0;

	// 卦の番号(1-64)を得る
	ka = pgm_read_byte(Ka_Table + ka);
	draw_number((ka/10)%10, ka%10, matrix_num);

	// 爻の位置のドットを反転し別のビットマップとして保存
	cp(matrix, matrix_kou);
	matrix_kou[kou] ^= 0b00000100;
}

int main()
{
	unsigned char pattern = 0, count = 0;
	unsigned char count_ka = 0, count_kou = 0;
	unsigned char ka = BLANK, kou = BLANK;

	DDRA = 0b00000000; // PA0-1 = buttons
	PORTA= 0b00000011; // PA0-1 = pull up

	DDRB = 0b11111111; // PB0-4 = anode1-5 (PB5-7 = NC)
	PORTB= 0b00000000;

	DDRD = 0b01111111; // PD0-6 = cathodeA-G
	PORTD= 0b01111111;

	// button1を押した状態で起動すると、前回の得卦の表示
	if(Button1_Down) {
		ka = eeprom_read_byte((void *)EEPROM_Log);
		kou = eeprom_read_byte((void *)EEPROM_Log + 1);
		render(ka, kou);
	}

	// 乱数を得るためcount_ka、count_kouを加算しながらループ
	for(;;) {

		if(ka == BLANK && count++ > 100) {
			cp(left_prompt[pattern++ % 2], matrix);
			count = 0;
		}

		bitblt(matrix);
		++count_ka;
		if(++count_kou == 252) count_kou = 0; // 6の剰余が偏らないように

		if(Button1_Down && ka == BLANK) {
			_delay_ms(32);
			while(Button1_Down) { // button upを待つ
				++count_ka;
				++count_kou;
			}

			ka = count_ka % 64; // 卦を生成
			eeprom_write_byte((void *)EEPROM_Log, ka);
			render(ka, 0);

		} else if(Button1_Down && ka != BLANK) {
			while(Button1_Down) {
				bitblt(matrix_num);
			}

		} else if(Button2_Down && ka != BLANK) {
			if(kou == BLANK) {
				kou = count_kou % 6; // 爻を生成
				eeprom_write_byte((void *)EEPROM_Log + 1, kou);
				render(ka, kou);
			}
			while(Button2_Down) {
				bitblt(matrix_kou);
			}
		} else {
			// ボタンは押されていなかった
		}
	}
}
