#define byte unsigned char

//*************************************
//***      code value checking      ***
//*************************************

//***********************************//
//******CHANGE THIS SECTION**********//
//Fill in the secret code here!
//example:
//volatile byte code[] = {1,2,3,4,5};
volatile byte code[] = {1,2,3,4,5};
//Fill in the length of the secret code
//example:
//#define CODELENGTH 5
#define CODELENGTH 5
//***********************************//
//***********************************//

volatile byte acceptedDiceValueQueue[CODELENGTH];
volatile byte acceptedDiceValueQueuePtr;
volatile byte previousAcceptedDiceValue;

// returns true if the entire code was entered correctly, false otherwise.
byte CheckNewDiceValue(byte newValue)
{
	byte i, j, ok = 0;
	if (newValue != previousAcceptedDiceValue)
        {
               Beep();
		acceptedDiceValueQueue[acceptedDiceValueQueuePtr] = newValue;
		++acceptedDiceValueQueuePtr;
		if (acceptedDiceValueQueuePtr >= CODELENGTH)
			acceptedDiceValueQueuePtr = 0;
		
		// check code
		ok = 1;
		for(i=0; i<CODELENGTH && ok; ++i)
		{
			j = i + acceptedDiceValueQueuePtr;
			if (j >= CODELENGTH)
				j -= CODELENGTH;
			ok = (code[i] == acceptedDiceValueQueue[j]);
		}
		previousAcceptedDiceValue = newValue;
       }
	return ok;
}



//*************************************
//***     dice value filtering      ***
//*************************************
#define DICEVALUEFILTERLENGTH 32 // must be power of 2 (for '&' operation)
#define HISTOGRAMTHRESHOLDVALUE 30 // minimum value in the histogram for the value to be accepted
volatile byte queue[DICEVALUEFILTERLENGTH]; 
volatile byte queuePtr;
volatile byte histogram[8]; //invariant: sum(queue[0]...queue[7]) == DICEVALUEFILTERLENGTH
	// note: histogram could in principle be one byte shorter (the undefined one can be left out), 
	// but on the other hand it would require two extra ifs in the function below, + the invariant would be less obvious.

byte MeasureFilteredDiceValue(void)
{
	byte i, m, v = ReadDiceSensor();
	
	--histogram[queue[queuePtr]];
	queue[queuePtr] = v;
	++histogram[v];
    // assert(histogram[0] + histogram[1] + histogram[2] + histogram[3] + histogram[4] + histogram[5] + histogram[6] + histogram[7] == DICEVALUEFILTERLENGTH);
	
	queuePtr = (queuePtr+1) & (DICEVALUEFILTERLENGTH-1);

	// find max in the histogram
	m = HISTOGRAMTHRESHOLDVALUE; // m keeps track of the max value in the histogram till now.
		// as trick, I initialize it to a threshold, so that lower histogram value are always ignored.
	v = 7; // if no value above the lower threshold is found we will just retunr 7 = undefined.
	for (i = 0; i < 7; ++i)
	{
		if (histogram[i] > m)
		{
			m = histogram[i];
			v = i;
		}
	}

	return v;
}



//*************************************
//***    sensor reader interrupt    ***
//*************************************
#define	SAMEDICEVALUECOUNTERSTART 5

volatile byte previousFilteredDiceValue;
volatile byte sameDiceValueCounter;

void ProcessSensorValues(void)
{
	byte newValue = MeasureFilteredDiceValue();
	if (newValue < 7 && newValue == previousFilteredDiceValue)
	{
		--sameDiceValueCounter;
		if (sameDiceValueCounter == 0)
		{
			// same filtered value occured for a longer time, so pass it on the code checker.
			if (CheckNewDiceValue(newValue))
				Open();
			sameDiceValueCounter = SAMEDICEVALUECOUNTERSTART; // need to reset this counter for case the (joker) value stays the same
		}
	}
	else
	{
		// new value occured.	
		sameDiceValueCounter = SAMEDICEVALUECOUNTERSTART-1;
		previousFilteredDiceValue = newValue;
	}
}


//*************************************
//***        initialization         ***
//*************************************
void Initialize(void)
{
	byte i;

	// init dice code checker
	previousAcceptedDiceValue = 7;
	acceptedDiceValueQueuePtr = 0;
	for (i = 0; i < CODELENGTH; ++i)
	{
		acceptedDiceValueQueue[i] = 7;
	}

	// initialize the filter
	for (i = 0; i < DICEVALUEFILTERLENGTH; ++i)
	{
		queue[i] = 7; // invalid value
	}
	for (i = 0; i < 7; ++i)
	{
		histogram[i] = 0; // invalid value
	}
	histogram[7] = DICEVALUEFILTERLENGTH;
	queuePtr = 0;

	// init sensor reader interrupt
	previousFilteredDiceValue = 0;
	sameDiceValueCounter = SAMEDICEVALUECOUNTERSTART;
}






