#include "digirule1.h"

uint16 ticks;

void main( void )
{
	enum
	{
		StateStart,
		StateLampTest,
		StateModeSelect,
		StateStandard,
		StateSparkle,
		StateShiftReg,
		StateLEDTest,
		StatePOV,
		StateDice,
		StateGame,
		StateLogic,
	} state;
	uint8 timer, timer2;
	
	OSCCONbits.IRCF = 0b110;	// Fosc to 8 MHz
	
	// initialize ports
	ANSEL	= 0b00000000;		// all analog-capable pins to digital
	ANSELH	= 0b00000000;
	
	LATA	= 0b00000000;
	TRISA	= 0b00000011;		// RA1..0 to inputs, all others to outputs
	
	LATB	= 0b00000000;
	TRISB	= 0b11111110;		// RB7..1 to inputs, all others to outputs

	LATC	= 0b00000000;
	TRISC	= 0b00000000;		// all to outputs
	
	LATD	= 0b00000000;
	TRISD	= 0b00000000;		// all to outputs
	
	LATE	= 0b00000000;
	TRISE	= 0b00000000;		// all to outputs

	// initialize timer 2 (periodic) to 8 MHz (Fosc) / 4 (Fcyc) / 1 (prescale) / 200 (PR2 + 1) / 10 (postscale) = 1000 Hz (1 mS)
	PR2		= 199;
	T2CON	= 0b01001100;		// timer on, 1:1 prescale, 1:10 postscale
	
	state = StateStart;
	
	// main loop
	for( ;; )
	{
		TEST_POINT = 0;
		
		for( TMR2IF = 0; TMR2IF == 0; )		// wait for next tick
			;
		
		TEST_POINT = 1;
		ticks++;
		buttons_process();

		if( button.b.held2 && button.a.state && state >= StateStandard )	// if restart request
			state = StateStart;

		switch( state )
		{
			case StateStart:
				A_LED = NOT_LED = AND_LED = NOR_LED = XNOR_LED = SJTD_LED = RK_LED = JK_LED = D_LED = QNOT_LED = CTR4_LED = CTR1_LED = 1;
				B_LED = OR_LED = XOR_LED = NAND_LED = X_LED = CLK_LED = SR_LED = T_LED = Q_LED = CTR8_LED = CTR2_LED = 0;
				timer = timer2 = 0;
				state = StateLampTest;
				break;

			case StateLampTest:
				if( ++timer == 75 )
				{
					if( ++timer2 == 16 )
					{
						all_leds_set( 0 );

						if( button.a.state )	// if mode select request
						{
							ctr_leds_set( 1 );
							state = StateModeSelect;
						}
						else
						{
							mode_standard_init( CounterModeBinary );
							state = StateStandard;
						}
					}
					else
					{
						all_leds_set( 2 );		// invert
						timer = 0;
					}
				}

				break;

			case StateModeSelect:
				if( button.down.pressed )		// previous mode
				{
					static const uint8 lut[] = { 0, 9, 1, 2, 3, 4, 5, 6, 7, 8 };
					ctr_leds_set( lut[ctr_leds_get()] );
				}
				else if( button.up.pressed )	// next mode
				{
					static const uint8 lut[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 };
					ctr_leds_set( lut[ctr_leds_get()] );
				}
				else if( button.b.pressed )		// enter
				{
					switch( ctr_leds_get() )
					{
						case 1:
							mode_standard_init( CounterModeBinary );
							state = StateStandard;
							break;

						case 2:
							mode_standard_init( CounterModeGray );
							state = StateStandard;
							break;

						case 3:
							mode_sparkle_init();
							state = StateSparkle;
							break;

						case 4:
							mode_shift_reg_init();
							state = StateShiftReg;
							break;

						case 5:
							mode_led_test_init();
							state = StateLEDTest;
							break;

						case 6:
							mode_pov_init();
							state = StatePOV;
							break;

						case 7:
							mode_dice_init();
							state = StateDice;
							break;

						case 8:
							mode_game_init();
							state = StateGame;
							break;

						case 9:
							mode_logic_init();
							state = StateLogic;
							break;
					}
				}
				else
					B_LED = (ticks & 0x200) == 0;		// blink "enter" button LED

				break;

			case StateStandard:		// mode 1 or 2
				mode_standard_process();
				break;

			case StateSparkle:		// mode 3
				mode_sparkle_process();
				break;

			case StateShiftReg:		// mode 4
				mode_shift_reg_process();
				break;

			case StateLEDTest:		// mode 5
				mode_led_test_process();
				break;

			case StatePOV:			// mode 6
				mode_pov_process();
				break;

			case StateDice:			// mode 7
				mode_dice_process();
				break;

			case StateGame:			// mode 8
				mode_game_process();
				break;

			case StateLogic:		// mode 9
				mode_logic_process();
				break;
		}
	}
}
