/*
 * render.cpp
 *
 *  Created on: Oct 24, 2014
 *      Author: parallels
 */


#include <BeagleRT.h>
#include <Utilities.h>

#define NUM_PINS 12

// Breadboard wiring layout:
// 11 10 12 9  8  7
// [ LED DISP ]
// 1  2  3  6  4  5

// Organised by display segments:
// e d . X c g b X X X f a
const int kPins[NUM_PINS] = {P8_07, P8_08, P8_09, P8_10, P8_11, P8_12,
							 P8_15, P8_16, P8_27, P8_28, P8_29, P8_30};

// Indices into the above array: pins 12, 9, 8, 6
const int kDigits[4] = {9, 8, 7, 3};

int gCurrentlyDisplayingDigit = 0;
int gDigitDisplayTime = 0;
const int kDigitMaxDisplayTime = 44;

int gState = 0;
int gStateCounter = 0;
const int kMaxState = 25;

// . g f e d c b a
//const unsigned char kBELA[4] = {0x7C, 0x79, 0x38, 0x77};
const unsigned char kBELA[4] = {0x7C, 0x7B, 0x38, 0x5F};
const unsigned char kPerimeter[6] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20};

int gCharacterToDisplay[4] = {0, 0, 0, 0};
	
// setup() is called once before the audio rendering starts.
// Use it to perform any initialisation and allocation which is dependent
// on the period size or sample rate.
//
// userData holds an opaque pointer to a data structure that was passed
// in from the call to initAudio().
//
// Return true on success; returning false halts the program.

bool setup(BeagleRTContext *context, void *userData)
{	
	// This project makes the assumption that the audio and digital
	// sample rates are the same. But check it to be sure!
	if(context->audioFrames != context->digitalFrames) {
		rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n");
		return false;
	}
	
	for(int i = 0; i < NUM_PINS; i++) {
		pinModeFrame(context, 0, kPins[i], OUTPUT);
	}

	return true;
}

// render() is called regularly at the highest priority by the audio engine.
// Input and output are given from the audio hardware and the other
// ADCs and DACs (if available). If only audio is available, numMatrixFrames
// will be 0.

void render(BeagleRTContext *context, void *userData)
{
	for(unsigned int n = 0; n < context->audioFrames; n++) {
		// Check for rotation between digits
		if(--gDigitDisplayTime <= 0) {
			gCurrentlyDisplayingDigit = (gCurrentlyDisplayingDigit + 1) % 4;
			gDigitDisplayTime = kDigitMaxDisplayTime;
		}
	
		// Write the currently displaying digit low and the rest high
		for(int i = 0; i < 4; i++)
				digitalWriteFrameOnce(context, n, kPins[kDigits[i]], HIGH);
		digitalWriteFrameOnce(context, n, kPins[kDigits[gCurrentlyDisplayingDigit]], LOW);
		
		// Write the digit to the other outputs
		digitalWriteFrameOnce(context, n, kPins[11],
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x01);	// a
		digitalWriteFrameOnce(context, n, kPins[6], 
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x02);	// b
		digitalWriteFrameOnce(context, n, kPins[4], 
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x04);	// c
		digitalWriteFrameOnce(context, n, kPins[1],
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x08);	// d
		digitalWriteFrameOnce(context, n, kPins[0],
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x10);	// e
		digitalWriteFrameOnce(context, n, kPins[10],
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x20);	// f
		digitalWriteFrameOnce(context, n, kPins[5],
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x40);	// g
		digitalWriteFrameOnce(context, n, kPins[2],
			gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x80);	// .
			
		// Check for changing state
		if(--gStateCounter <= 0) {
			gState = (gState + 1) % kMaxState;
			if(gState != (kMaxState - 1)) {
				for(int i = 0; i < 4; i++)
					gCharacterToDisplay[i] = 1 << (gState % 6);
				gStateCounter = 2000;
			}
			else {
				for(int i = 0; i < 4; i++)
					gCharacterToDisplay[i] = kBELA[i];
				gStateCounter = 50000;
			}
		}
	}
}

// cleanup() is called once at the end, after the audio has stopped.
// Release any resources that were allocated in setup().

void cleanup(BeagleRTContext *context, void *userData)
{
	
}
