/* Project: 3x3x3 Mono LED Cube (r3).
 * File: DisplayFrame.cpp
 * Description: Functions for updating the LED cube.
 *
 * Copyright (C) 2014 Marc Symonds
 * All rights reserved.
 *
 * This software may be used and redistributed, with or without
 * modification, as long as it is understood that this software
 * is provided as-is without any explicit or implied warranties
 * of merchantablity or fitness of purpose.
 */

#include "Arduino.h"
#include "DisplayFrame.h"
#include "DirectIO.h"
#include "ShiftReg_7495.h"
#include "Counter_4017.h"

const byte brightnessSubFrames[] = {B00000000, B00000001, B01001001, B01010101, B01011101, B01110111, B11110111, B11111111};

boolean dfpa_fadeOut(int *, byte);

byte displayFrame[27];

Point points[8]; // An array of points that animations can use.

volatile DisplayParameters dispParams;

ShiftReg_7495 DisplayZ(4, 10, 11, 12); // Parallel mode: Clock on pin 4, A on pin 10, B on pin 11 and C on pin 12. NOT ACTUALLY USING PIN 4 - PINS 10, 11 and 12 WILL DRIVE THE DISPLAY DIECTLY.
Counter_4017 DisplayXY(7, 6); // Clock pin 7, last element detect pin 6.

// Used for timing metrics in the updateDisplay function.

volatile boolean gotupt = false;
volatile unsigned int upt = 0;
volatile unsigned int upc = 0;

void df_init()
{
  df_clear();
  attachInterrupt(0, updateDisplay, RISING); // Interrupt 0 is on pin 2 (DISPLAYCLOCKPIN).
}

// Called by interrupt 0.
// Displays a 3 LED segment on each interrupt.

void updateDisplay()
{
  byte b, c, d;
  unsigned long st = 0, et = 0;

  // Timing metrics.
  
  if (gotupt == false)
  {
    st = micros(); // micros() still works in an interrupt - apparently.
  }
  
  DisplayZ.clear();    // Clear data lines.
  DisplayXY.clock();   // Trigger 4017 - move to the next row to display on.

  // Move to next row to display.
  
  dispParams.x += 3;
  if (dispParams.x > 26)
  {
    dispParams.x = 0;
  
    // Subframe for dimming LED.
    
    if (++dispParams.subFrame > MAXBRIGHTNESSLEVEL)
    {
      dispParams.subFrame = 0;
      dispParams.subFrameBit = 1;
    }
    else
      dispParams.subFrameBit <<= 2;
  }
  
  // Set bits to be displayed.
  
  c = dispParams.x;
  for (b = 0 ; b < 3 ; b++)
  {
    DisplayZ.setBit(b, (brightnessSubFrames[displayFrame[c]] & dispParams.subFrameBit) != 0);
    ++c;
  }
  
  /*
    This loop is a delay to allow the triggering of the 4017 (DisplayXY) to propagate.
    The 4017 can take up to 530ns from tigger to output at 5V, according to data sheet.

    Without this delay, we will see the new data being applied to the current data lines
    before the 4017 has acted. So you get a ghost of the next set of data on the current
    leds.
  */
  
  for (d = 0 ; d < 9 ; d++)
    digitalRead(0);

  // Display the bits (LEDs).
  
  DisplayZ.send();

  // Timing metrics.
  
  if (gotupt == false && st > 0)
  {
    et = micros();
    upt = et - st;
    st = 0;
    gotupt = true;
  }
  
  ++upc;
}

void df_allOn()
{
  for (byte i = 0 ; i < 27 ; i++)
    displayFrame[i] = MAXBRIGHTNESSLEVEL;
}

void df_clear()
{
  for (byte i = 0 ; i < 27 ; i++)
    displayFrame[i] = 0;
}

boolean df_fadeOut(int delayTime)
{
  boolean faded = false;
  int changed = 0;

  while (!faded)
  {  
    changed = 0;
    
    df_processAll(dfpa_fadeOut, &changed);
    faded = (changed == 0);
    delay(delayTime);    
  }
  
  return faded;
}

boolean dfpa_fadeOut(int *data, byte cell)
{
  if (displayFrame[cell] > 0)
  {
    displayFrame[cell] -= 1;
    *data += 1;
  }
  
  return true;
}

boolean df_processAll(df_processAllFunc func, int *data)
{
  byte x;
  boolean success = true;
  
  for (x = 0 ; x < 27 ; x++)
  {
    if (!func(data, x))
    {
      success = false;
      continue;
    }
  }
  
  return success;
}

POSTransFPtr GetPOSTrans(byte t)
{
  switch(t)
  {
    case 1:
      return POSTrans1;
      break;
    
    case 2:
      return POSTrans2;
      break;
      
    case 3:
      return POSTrans3;
      break;
    
    case 4:
      return POSTrans4;
      break;
      
    case 5:
      return POSTrans5;
      break;
      
    case 6:
      return POSTrans6;
      break;
    
    case 7:
      return POSTrans7;
      break;
      
    default:
      return POSTrans0;
      break;
  }
}

byte POSTrans0(byte x, byte y, byte z)
{
  return(POS(x, y, z));
}

byte POSTrans1(byte x, byte y, byte z)
{
  return(POS(2-x, y, z));
}

byte POSTrans2(byte x, byte y, byte z)
{
  return(POS(x, 2-y, z));
}

byte POSTrans3(byte x, byte y, byte z)
{
  return(POS(2-x, 2-y, z));
}

byte POSTrans4(byte x, byte y, byte z)
{
  return(POS(x, y, 2-z));
}

byte POSTrans5(byte x, byte y, byte z)
{
  return(POS(2-x, y, 2-z));
}

byte POSTrans6(byte x, byte y, byte z)
{
  return(POS(x, 2-y, 2-z));
}

byte POSTrans7(byte x, byte y, byte z)
{
  return(POS(2-x, 2-y, 2-z));
}

// Each bit in "box" represents an LED in the display; 0=Off, 1 = On.

void df_DisplayMonoFrame(POSTransFPtr trans, unsigned long box)
{
  register byte x = 0, y = 0, z = 0;
  
  for (int i = 0 ; i < 27 ; i++)
  {
    displayFrame[trans(x, y, z)] = (box & 1) == 1 ? MAXBRIGHTNESSLEVEL : 0;
    box >>= 1;
    if (++x > 2)
    {
      x = 0;
      if (++y > 2)
      {
        y = 0;
        ++z;
      }
    }
  }
}

Leave a Reply

Your e-mail address will not be published. Required fields are marked *

Comments Protected by WP-SpamShield Spam Blocker