/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */ 

#include <avr/io.h>
#define F_CPU 1000000
#include <util/delay.h>

#define PORT_ROW PORTD
#define DDR_ROW  DDRD

#define PORT_COL1 PORTC
#define DDR_COL1  DDRC
#define PORT_COL2 PORTB
#define DDR_COL2  DDRB
#define PORT_COL3 PORTD
#define DDR_COL3  DDRD

//  ABCDEF...
//const uint8_t displayText[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, 200};

// VISIT WWW.STUDENT-IM-URLAUB.DE
//const uint8_t displayText[] = { 0,0,22,9,19,9,20,0,0,23,23,23,29,19,20,21,4,5,14,20,31,9,13,31,21,18,12,1,21,2,29,4,5,0,0, 200}; 

const uint8_t displayText[] = { 
  0,0,6,18,15,8,5, // FROHE
  0,23,5,9,8,14,1,3,8,20,5,14, // WEIHNACHTEN
  0,21,14,4, // UND
  0,7,21,20,5,14, // GUTEN
  0,18,21,20,19,3,8, // RUTSCH
  0,9,14,19, // INS
  0,14,5,21,5, // NEUE
  0,10,1,8,18, // JAHR
  0,200 }; // 200 markiert das Ende

const uint8_t charTable[] = {
  0, 0, 0, 0,     // Leerzeichen
  126,9,9,126,    // A
  127,73,73,54,   // B
  62,65,65,65,    // C
  127,65,65,62,   // D
  127,73,73,73,   // E
  127,9,9,1,      // F
  62,65,81,50,    // G
  127,8,8,127,    // H
  0,127,127,0,    // I
  49,65,65,63,    // J
  127,24,38,67,   // K
  127,64,64,64,   // L
  127,6,2,127,    // M
  127,14,48,127,  // N
  127,65,65,127,  // O
  127,9,9,6,      // P
  63,33,49,127,   // Q
  127,25,41,70,   // R
  70,73,73,49,    // S
  1,1,127,1,      // T
  63,64,64,63,    // U
  15,120,48,15,   // V
  127,32,48,127,  // W
  67,44,18,97,    // X
  71,72,72,63,    // Y
  97,89,69,67,    // Z
  0,111,111,0,    // !
  2,97,105,6,     // ?
  96,96,0,0,      // .
  64,32,0,0,      // ,
  12,12,12,12     // -
};

uint8_t currentColumn=0;
uint8_t columnBuffer[10];
uint8_t	charPosition=0;
uint8_t	stringPosition=0;

// Spalte aktivieren. colNr ist dabei die Spaltennr 0 bis 9
inline void setActiveCol(const uint8_t colNr)
{
  int8_t maskLo;
  int8_t maskHi;
  if (colNr < 10)
  {
    maskLo = (1 << colNr) & 255;
    maskHi = 0;
    if (colNr > 7)
      maskHi = (1 << (colNr-8)) & 255;
  }else{
	maskLo = 0;
	maskHi = 0;
  }

  PORT_COL1 = maskLo & 63;
  PORT_COL2 = ((maskLo >> 6) &3) | ((maskHi & 1) << 2);
  PORT_COL3 &= ~(1<<7);
  PORT_COL3 |= (maskHi & 2) << 6;
}

inline void initPorts()
{
  // LED-Port auf OUT
  DDR_ROW = 255;
  PORT_ROW = 0;

  DDR_COL1 = 255;
  DDR_COL2 = 255;
  DDR_COL3 = 255;

  PORT_COL1 = 255;
  PORT_COL2 = 255;
  PORT_COL3 |= (1<<7);

	
  // Puffer leeren, damit nicht zunächst
  // wirre Zeichen angezeigt werden.
  columnBuffer[0] = 0;
  columnBuffer[1] = 0;
  columnBuffer[2] = 0;
  columnBuffer[3] = 0;
  columnBuffer[4] = 0;
  columnBuffer[5] = 0;
  columnBuffer[6] = 0;
  columnBuffer[7] = 0;
  columnBuffer[8] = 0;
  columnBuffer[9] = 0;
}

int main()
{
  uint8_t n=0;

  initPorts();

  // Endlosschleife
  while (1)
  {
	// Die Bildaufbaugeschwindigkeit ist einfach faul
	// durch diesen Sleep für 1ms zwischen den Frames
	_delay_ms(1);

    setActiveCol(10);
	PORT_ROW &= ~127;
	PORT_ROW |= ~(columnBuffer[currentColumn]) & 127;
    setActiveCol(currentColumn);
    if (++currentColumn > 9)
    {
      currentColumn=0;
      if(++n>13) // Nach jedem 13. Bildaufbau wird das Bild selbst weitergeschoben
      {
		// Spaltenweise weiterkopieren  
    	for(n=9; n>0; --n)
    	  columnBuffer[n] = columnBuffer[n-1];

        if (4 == charPosition) // Eine Spalte Zwischenraum zwischen den Buchstaben
        {
    	    columnBuffer[0] = 0;
        } else {
			// Bitmuster des entsprechenden Buchstabenteils einsetzen
    	    columnBuffer[0] = charTable[displayText[stringPosition]*4 +charPosition];
        }
	    if (++charPosition > 4)
        {  // Es wurde ein ganzer Buchstabe angezeigt --> es folgt der nächste!
          charPosition=0;
          ++stringPosition;
          if (200 == displayText[stringPosition])
            stringPosition=0;
        }
    	  n=0;
      }
    }
  }
}

