Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed

/*****************************************************************************
Project : Video Overlay for RC Planes
Date    : 1/14/2007
Author  : Gunter Logemann (C) ALL RIGHTS RESERVED                  

Comments:
This project is optimized to work with the Mikrocopter (www.mikrokopter.de)
Many Thanks to Gary Dion who created the first basic implementation
Data communication decoder and encoder functions are taken from the
mikrokopter (www.mikrokopter.de) project.

Redistributions of this source code (with or without modifications) or parts
of this sourcode must retain the above copyright notice, this list of
conditions and the following disclaimer.
* Neither the name of the copyright holders nor the names of contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.
* The use of this source code permittet for non-commercial use (directly
  or indirectly) only.
* Commercial use Is only permitted with our written permission by
  Gunter Logemann (gunter@pccon.de)
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

Chip type           : ATmega88
Program type        : Application
Clock frequency     : 20,000000 MHz
*****************************************************************************/


#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/io.h>
#include "Main.h"

#define CPUSPEED_20
//#define CPUSPEED_16
//#define CPUSPEED_11059

// Macros
#define WatchdogReset() asm("wdr")     
#define Wait() while(!(SPSR & (1<<SPIF)))

// Define CPU speed dependant constants:
#ifdef CPUSPEED_20
#define LINESTART 200
#define COPYRIGHTSTART 0
#define HEADINGSTART 200
#endif

#ifdef CPUSPEED_16
#define LINESTART 150
#define COPYRIGHTSTART 0
#define HEADINGSTART 200
#endif

#ifdef CPUSPEED_11059
#define LINESTART 130
#define COPYRIGHTSTART 0
#endif

// Static functions and variables
unsigned int line;                              // current line to be drawed
unsigned char lowbat = 0;
unsigned char showmessage1 = 0;
unsigned char framecounter = 0;
unsigned char showgraphic = 1;
unsigned char showgraphicb = 1;  

static unsigned char head[17]           = {'C','@','G','U','N','T','E','R','@','L','O','G','E','M','A','N','N'};
static unsigned char Message_LowBat[15] = {'@','@','L','O','W','@','B','A','T','T','E','R','Y','@','@'};
unsigned char rxtx[ 9]          = {'T','X','D',0x01,'@','R','X','D',0x01};
unsigned char heading[5]        = { 0x02, '0', '0', '0',0x03};
unsigned char bat[8]            = { 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08};
unsigned char ubat[8]           = {  'U', ':', '@', '0', '0', '.', '0', 'V'};
unsigned char rx[8]             = { 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08};
unsigned char urx[8]            = {  'R', 'X', ':', '@', '1', '0', '0', '/'};
unsigned char altv[6]           = {  '+','0', '0', '0', '0', '0'};
unsigned char bar0 = 0x00;
unsigned char bar1 = 0xfe;

int old_alt;
unsigned int alt_delta = 0;
char alt_inc = 0;
char alt_dec = 0;

// define Graphic Area (56x40 pixel)
#define GR_MaxGraph             280
#define GR_BytePerLine          7
#define GR_Lines            40
 
unsigned char dmem[280] = {     0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                                                                0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                                                                0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                                                                0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                                                               
                                                                0x00,0x55,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                               
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                               
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                                0x00,0xff,0x00,0xff,0x00,0xff,0x00,
                                                               
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                               
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                               
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                               
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,

                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xff,

                                                                0xff,0x00,0xff,0x00,0xff,0x00,0x55,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xAA,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0x55,
                                                                0xff,0x00,0xff,0x00,0xff,0x00,0xAA,
 };

//                                                                      ' ' A   B   C   D   E   F   G   H   I   J   K   L   M   N   O   P   Q   R   S   T   U   V   W   X   Y   Z

static unsigned char ltrs[189] = {       0, 24,124, 60,120,126,126, 60, 66,124,126, 66, 64,130,130, 60,124, 60,124, 60,124, 66, 66,130,130,130,254,
                                                                     0, 36, 66, 66, 68, 64, 64, 66, 66, 16,  8, 68, 64,198,194, 66, 66, 66, 66, 66, 16, 66, 66,130, 68, 68,  4,
                                                                         0, 66, 66, 64, 66, 64, 64, 64, 66, 16,  8, 72, 64,170,162, 66, 66, 66, 66, 64, 16, 66, 66,146, 40, 40,  8,
                                                                         0, 66,124, 64, 66,124,124, 78,126, 16,  8,112, 64,146,146, 66,124, 66,124, 60, 16, 66, 36,146, 16, 16, 16,
                                                                         0,126, 66, 64, 66, 64, 64, 66, 66, 16,  8, 72, 64,130,138, 66, 64, 76, 72,  2, 16, 66, 36,146, 40, 16, 32,
                                                                         0, 66, 66, 66, 68, 64, 64, 66, 66, 16, 72, 68,126,130,134, 66, 64, 70, 68, 66, 16, 66, 36,108, 68, 16, 64,
                                                                         0, 66,124, 60,120,126, 64, 60, 66,124, 48, 66,126,130,130, 60, 64, 50, 66, 60, 16, 60, 24,108,130, 16,254};

//                                                                      +   ,   -   .   /   0   1   2   3   4   5   6   7   8   9   :
static unsigned char nums[112] = {       0,  0,  0,  0, 48,124, 16,124,124, 28,254,124,254,124,124,  0,
                                                                        16,  0,  0,  0, 68,130, 48,130,130, 36,128,128,  2,130,130, 16,  
                                                                        16,  0,  0,  0, 68,130, 16,  2,  2, 68,128,128,  4,130,130,  0,
                                                                   124,  0,124,  0, 48,130, 16, 12, 28,132,124,252,  8,124,126,  0,
                                                                        16, 24,  0,  0,  0,130, 16, 48,  2,254,  2,130, 16,130,  4,  0,
                                                                        16, 24,  0, 24,  0,130, 16, 64,130,  4,130,130, 16,130,  8, 16,
                                                                         0,  0,  0, 24,  0,124, 56,254,124,  4,124,124, 16,124, 48,  0};
                                                                       

static unsigned char infos[63]  = {     0xfe,0xfe,0x18,0x30,0x00,0x80,0xa0,0xa8,0xaa,
                                                                        0xfe,0x82,0x38,0x38,0x00,0x80,0xa0,0xa8,0xaa,
                                                                        0xfe,0x82,0x78,0x3c,0x00,0x80,0xa0,0xa8,0xaa,
                                                                        0xfe,0x82,0xfe,0xfe,0x00,0x80,0xa0,0xa8,0xaa,
                                                                        0xfe,0x82,0x7e,0x3c,0x00,0x80,0xa0,0xa8,0xaa,
                                                                        0xfe,0x82,0x38,0x38,0x00,0x80,0xa0,0xa8,0xaa,
                                                                        0xfe,0xfe,0x18,0x30,0x00,0x80,0xa0,0xa8,0xaa};



unsigned char display_line1[10];
unsigned char templine[5];

unsigned char mode = 0;  

#define MAX_RX_BUF 100
unsigned volatile char SioTmp = 0;
unsigned volatile char RxdBuffer[MAX_RX_BUF];
unsigned volatile char NeuerDatensatzEmpfangen = 0;
unsigned volatile char CntCrcError = 0;
unsigned volatile char AnzahlEmpfangsBytes = 0;

struct str_DebugOut    DebugOut;


static unsigned char grlevel[21] = {    0x00,0x00,0x00,0x18,0x00,0x00,0x00,
                                                                                0xff,0xff,0xff,0x24,0xff,0xff,0xff,
                                                                                0x00,0x00,0x00,0x18,0x00,0x00,0x00};
static unsigned char grlevel0[7] = {    0xAA,0xAA,0xAA,0xFF,0x55,0x55,0x55};


//-----------------------------------------------------------------------------
// copy bitmap
//-----------------------------------------------------------------------------
extern void GR_Copy(unsigned char* source,int start,int max)
{
        int i;
        for(i=0;i<max;i++)
        {
          dmem[start+i]=*source;
          source++;
        }
}

//-----------------------------------------------------------------------------
// Clear Graphic Area
//-----------------------------------------------------------------------------
extern void GR_Clear()
{
        int i;
        for(i=0;i<GR_MaxGraph;i++)
        {
                dmem[i]=0;
        }
}

//-----------------------------------------------------------------------------
// Show and Hide Graphic area and Background
//-----------------------------------------------------------------------------
#define SHOWGRAPHIC     showgraphic=1
#define HIDEGRAPHIC             showgraphic=0
#define SHOWGRAPHICBACK showgraphicb=1
#define HIDEGRAPHICBACK showgraphicb=0


//-----------------------------------------------------------------------------
// Decode64
//-----------------------------------------------------------------------------
extern void Decode64(unsigned char *ptrOut, unsigned char len, unsigned char ptrIn,unsigned char max)  
{
        unsigned char a,b,c,d;
        unsigned char ptr = 0;
        unsigned char x,y,z;
        while(len)
        {
                a = RxdBuffer[ptrIn++] - '=';
                b = RxdBuffer[ptrIn++] - '=';
                c = RxdBuffer[ptrIn++] - '=';
                d = RxdBuffer[ptrIn++] - '=';
                if(ptrIn > max - 2) break;    

                x = (a << 2) | (b >> 4);
                y = ((b & 0x0f) << 4) | (c >> 2);
                z = ((c & 0x03) << 6) | d;

                if(len--) ptrOut[ptr++] = x; else break;
                if(len--) ptrOut[ptr++] = y; else break;
                if(len--) ptrOut[ptr++] = z; else break;
        }
}

//-----------------------------------------------------------------------------
// process RX Data
//-----------------------------------------------------------------------------
extern void process_rxdata(unsigned char c)
{
        static unsigned int crc;
        static unsigned char crc1,crc2,buf_ptr;
        static unsigned char UartState = 0;
        unsigned char CrcOkay = 0;

        SioTmp=c;

        if(buf_ptr >= MAX_RX_BUF)    
                UartState = 0;
        if(SioTmp == '\r' && UartState == 2)
        {
                UartState = 0;
                crc -= RxdBuffer[buf_ptr-2];
                crc -= RxdBuffer[buf_ptr-1];
                crc %= 4096;
                crc1 = '=' + crc / 64;
                crc2 = '=' + crc % 64;
                CrcOkay = 0;
                if((crc1 == RxdBuffer[buf_ptr-2]) && (crc2 == RxdBuffer[buf_ptr-1]))
                {
                        CrcOkay = 1;
                }
                else
                {
                        CrcOkay = 0;
                        CntCrcError++;
                        display_line1[1]='E';

                }
                if(!NeuerDatensatzEmpfangen && CrcOkay) // Datensatz schon verarbeitet
                {
                        NeuerDatensatzEmpfangen = 1;
                        AnzahlEmpfangsBytes = buf_ptr;
                        RxdBuffer[buf_ptr] = '\r';
                        display_line1[1]='R';
                }                                
        }
        else
        switch(UartState)
        {
                case 0:
          if(SioTmp == '#' && !NeuerDatensatzEmpfangen) UartState = 1;  // Startzeichen und Daten schon verarbeitet
                  buf_ptr = 0;
                  RxdBuffer[buf_ptr++] = SioTmp;
                  crc = SioTmp;
                  display_line1[2]='A';
                  display_line1[1]='X';
          break;
                case 1: // Adresse auswerten
                  UartState++;
                  RxdBuffer[buf_ptr++] = SioTmp;
                  crc += SioTmp;
                  display_line1[2]='B';
                  break;
                case 2: //  Eingangsdaten sammeln
                  RxdBuffer[buf_ptr] = SioTmp;
                  if(buf_ptr < MAX_RX_BUF) buf_ptr++;
                  else UartState = 0;
                  crc += SioTmp;
                  display_line1[2]='C';
                  break;
                default:
          UartState = 0;
                  display_line1[2]='D';
          break;
        }      
       
       
        if(rxtx[8]==0x00)
                rxtx[8]=0x01;
        else
                rxtx[8]=0x00;
}

//-----------------------------------------------------------------------------
// convert_uint16
//-----------------------------------------------------------------------------
extern void convert_uint16(unsigned char * c,int len, unsigned int value)
{
   int tempvalue, i;
   char c1[7];
   
   if(len<1) return;
   for(i=0;i<len;i++) {
     c1[i]='0';
   }
     
   i=len-1;
   while(value>0) {
     tempvalue=value;
         value=value/10;
         c1[i]=(tempvalue-(value*10))+'0';
         i--;
   }
   for(i=0;i<len;i++) {
     *c=c1[i];
         c++;

   }
}


//-----------------------------------------------------------------------------
//main
//main execution loop
//-----------------------------------------------------------------------------
extern int main(void)
{
        unsigned char c;
        unsigned int i;
        int i1;
       
        HIDEGRAPHIC;
        HIDEGRAPHICBACK;
       
        CLKPR=0x80;
        CLKPR=0x00;

        // PORT D - unused right now   
        PORTD = 0x10;                                                  
        DDRD  = 0x00;                                                  

        // USART initialization
        // Communication Parameters: 8 Data, 1 Stop, No Parity
        // USART Receiver: On
        // USART Transmitter: On
        // USART Mode: Asynchronous
        // USART Baud rate: 57600      
        UCSR0A=0x00;
        UCSR0B=0x18;
        UCSR0C=0x86;
#ifdef CPUSPEED_20      //20.000MHz
        UBRR0H=0x00;
        UBRR0L=0x15;   
#endif

#ifdef CPUSPEED_16      //16.000MHz
        UBRR0H=0x00;
        UBRR0L=0x10;
#endif
       
#ifdef CPUSPEED_11059 //11.059MHz
        UBRR0H=0x00;
        UBRR0L=0x0B;
#endif

        // Initialize the 8-bit Timer0 to clock at 20/8 MHz */
        TCCR0A=0x00;
        TCCR0B=0x01;

        // Initialize the SPI Interface
        PORTB = 0x00;
        DDRB = 0x3E; //0x3E
        //DDRB = 0x3A;
                                       
        SPCR = (1<<SPE) | (1<<MSTR) | (1<<CPHA);
        SPSR = 1;

        // External Interrupt(s) initialization
        // INT0: On
        // INT0 Mode: Falling Edge
        // INT1: On
        // INT1 Mode: Falling Edge
        // Interrupt on any change on pins PCINT0-7: Off
        // Interrupt on any change on pins PCINT8-14: Off
        // Interrupt on any change on pins PCINT16-23: Off
        EICRA=0x0A;
        EIMSK=0x03;
        EIFR=0x03;
        PCICR=0x00;

        // Enable interrupts
        sei();

        // MAIN lOOP
        display_line1[0]='X';
        display_line1[1]='X';
        display_line1[2]='X';
        display_line1[3]='X';
        display_line1[4]='X';
        display_line1[5]='X';
       
        NeuerDatensatzEmpfangen = 0;
       
        framecounter = 0;
       
        GR_Clear();
        GR_Copy(&grlevel[0],(GR_Lines/2)*7,21);
        SHOWGRAPHIC;
       
        while (1)
        {
               
                if (UCSR0A & (1<<RXC0)) {
                        c=UDR0;
                        UDR0=c;
                        process_rxdata(c);
                }
               
                if (framecounter<25) showmessage1=1; else showmessage1=0;
                if (framecounter>50) framecounter = 0;  
               
                if(NeuerDatensatzEmpfangen) {
                        switch(RxdBuffer[2])
                        {
                                case 'D':
                                        //decode the Messagee  
                                        Decode64((unsigned char *)&DebugOut,sizeof(DebugOut),3,AnzahlEmpfangsBytes);
                                       
                                        // Heading information
                                        convert_uint16((unsigned char *)&heading[1],3,(unsigned int)DebugOut.Analog[8]);
                                       
                                        // Altitute Information
                                        if(DebugOut.Analog[5]>old_alt) {
                                          alt_inc=1;
                                          alt_dec=0;
                                          alt_delta=DebugOut.Analog[5]-old_alt;
                                        }
                                        else {
                                          if(DebugOut.Analog[5]<old_alt) {
                                                alt_inc=0;
                                                alt_dec=1;
                                                alt_delta=old_alt-DebugOut.Analog[5];
                                          }
                                          else {
                                                alt_inc=0;
                                                alt_dec=0;
                                                alt_delta=0;
                                          }
                                        }
                                        if(alt_delta>60) alt_delta=60;
                                        if(alt_delta<0) alt_delta=0;
                                       
                                        old_alt=DebugOut.Analog[5];
                                        if(DebugOut.Analog[5]<0) {
                                          altv[0]='-';
                                          DebugOut.Analog[5]=(0xffff-(unsigned int)DebugOut.Analog[5]);
                                        }
                                        else {
                                          altv[0]='+';
                                        }
                                        convert_uint16((unsigned char *)&altv[1],5,(unsigned int)DebugOut.Analog[5]);
                                       
                                        //Voltage value
                                        convert_uint16((unsigned char *)&templine[0],5,(unsigned int)DebugOut.Analog[9]);
                                        ubat[3]=templine[2];
                                        ubat[4]=templine[3];
                                        ubat[6]=templine[4];
                                       
                                        if(DebugOut.Analog[9]>90) bat[0]=0x08; else bat[0]=0x04;
                                        if(DebugOut.Analog[9]>95) bat[1]=0x08; else bat[1]=0x04;
                                        if(DebugOut.Analog[9]>100) bat[2]=0x08; else bat[2]=0x04;
                                        if(DebugOut.Analog[9]>105) bat[3]=0x08; else bat[3]=0x04;
                                        if(DebugOut.Analog[9]>110) bat[4]=0x08; else bat[4]=0x04;
                                        if(DebugOut.Analog[9]>115) bat[5]=0x08; else bat[5]=0x04;
                                        if(DebugOut.Analog[9]>120) bat[6]=0x08; else bat[6]=0x04;
                                        if(DebugOut.Analog[9]>125) bat[7]=0x08; else bat[7]=0x04;
                                       
                                        if(DebugOut.Analog[9]<94) lowbat=1; else lowbat = 0;
                                       
                                        //RX level
                                        i=((unsigned int)DebugOut.Analog[10]*100)/255;
                                       
                                        convert_uint16((unsigned char *)&templine[0],5,(unsigned int)i);
                                        urx[4]=templine[2];
                                        urx[5]=templine[3];
                                        urx[6]=templine[4];
                                       
                                        if(i>10) rx[0]=0x08; else rx[0]=0x04;
                                        if(i>20) rx[1]=0x08; else rx[1]=0x04;
                                        if(i>30) rx[2]=0x08; else rx[2]=0x04;
                                        if(i>40) rx[3]=0x08; else rx[3]=0x04;
                                        if(i>50) rx[4]=0x08; else rx[4]=0x04;
                                        if(i>60) rx[5]=0x08; else rx[5]=0x04;
                                        if(i>70) rx[6]=0x08; else rx[6]=0x04;
                                        if(i>80) rx[7]=0x08; else rx[7]=0x04;
                                       
                                        // nick
                                        i1=DebugOut.Analog[0]/50;
                                        i1=((GR_Lines/2)-i1);
                                        if(i1<0) i1=0;
                                        if(i1>37) i1=37;
                                        GR_Clear();
                                        GR_Copy(&grlevel[0],i1*7,21);
                                        if(i1!=20) GR_Copy(&grlevel0[0],20*7,7);
                                        break;
                                       

                                       
                                default:
                                        break;
                               
                        }
                        NeuerDatensatzEmpfangen=0;
                }
        }
        return(1);
}       /* main */



//-----------------------------------------------------------------------------
// draw line()
// will be executed in interrupt context and will display the overlay content
//-----------------------------------------------------------------------------*/
extern void draw_line()
{
        unsigned char *ltr_p;
        unsigned char *num_p;
        unsigned char *info_p;
        short ltemp;   
        short ntemp;
        short itemp;
        unsigned int i1;
        unsigned char i=0;
        unsigned char c1;
        unsigned char c2;
        unsigned char c3;
        unsigned char c4;
        unsigned char c5;
        unsigned char c6;
        unsigned char c7;

        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // Bat and Heading output
        if ((line > 35) && (line < 43))
        {
                ltemp = (line - 36) * 27 - 64;
                ntemp = (line - 36) * 16 - 43;
                itemp = (line - 36) * 9;
                ltr_p = ltrs+ltemp;
                num_p = nums+ntemp;
                info_p = infos+itemp;
                // +++ Bat
                while(TCNT0<LINESTART);
                TCNT0=0;
                SPSR=1;
               
                DDRB|=1;                        //sink thru PB0
                SPDR = info_p[bat[0]]; Wait();
                SPDR = info_p[bat[1]]; Wait();
                SPDR = info_p[bat[2]]; Wait();
                SPDR = info_p[bat[3]]; Wait();
                SPDR = info_p[bat[4]]; Wait();
                SPDR = info_p[bat[5]]; Wait();
                SPDR = info_p[bat[6]]; Wait();
                SPDR = info_p[bat[7]]; Wait();
                DDRB&=0xFE;             //PB0 Hi-Z again, and load a blank so spacing is right
               
                // +++ Heading
                TCNT0=0;
                while(TCNT0<80);
                TCNT0=0;
                SPSR=0;
                DDRB|=1;
                SPDR = info_p[heading[0]]; Wait();
                SPDR = num_p[heading[1]]; Wait();
                SPDR = num_p[heading[2]]; Wait();
                SPDR = num_p[heading[3]]; Wait();
                SPDR = info_p[heading[4]]; Wait();
                DDRB&=0xFE;             //PB0 Hi-Z again, and load a blank so spacing is right
               
                // +++ RX Level
                while(TCNT0<250);  
                TCNT0=0;
                while(TCNT0<70);  
                SPSR=1;
                DDRB|=1;
                SPDR = info_p[rx[0]]; Wait();
                SPDR = info_p[rx[1]]; Wait();
                SPDR = info_p[rx[2]]; Wait();
                SPDR = info_p[rx[3]]; Wait();
                SPDR = info_p[rx[4]]; Wait();
                SPDR = info_p[rx[5]]; Wait();
                SPDR = info_p[rx[6]]; Wait();
                SPDR = info_p[rx[7]]; Wait();
                DDRB&=0xFE;    
        }
       
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // UBat
        if ((line > 44) && (line < 52))
        {
                ltemp = (line - 45) * 27 - 64;
                ntemp = (line - 45) * 16 - 43;
                itemp = (line - 45) * 9;
                ltr_p = ltrs+ltemp;
                num_p = nums+ntemp;
                info_p = infos+itemp;
                // +++ UBat
                while(TCNT0<LINESTART);
                TCNT0=0;
                SPSR=1;
                DDRB|=1;
                SPDR = ltr_p[ubat[0]]; Wait();
                SPDR = num_p[ubat[1]]; Wait();
                SPDR = ltr_p[ubat[2]]; Wait();
                SPDR = num_p[ubat[3]]; Wait();
                SPDR = num_p[ubat[4]]; Wait();
                SPDR = num_p[ubat[5]]; Wait();
                SPDR = num_p[ubat[6]]; Wait();
                SPDR = ltr_p[ubat[7]]; Wait();
                DDRB&=0xFE;            
                TCNT0=0;
                while(TCNT0<80);
                TCNT0=0;
                while(TCNT0<250);
                TCNT0=0;
                while(TCNT0<70);
                TCNT0=0;
                SPSR=1;
                DDRB|=1;
                SPDR = ltr_p[urx[0]]; Wait();
                SPDR = ltr_p[urx[1]]; Wait();
                SPDR = num_p[urx[2]]; Wait();
                SPDR = ltr_p[urx[3]]; Wait();
                SPDR = num_p[urx[4]]; Wait();
                SPDR = num_p[urx[5]]; Wait();
                SPDR = num_p[urx[6]]; Wait();
                SPDR = num_p[urx[7]]; Wait();
                DDRB&=0xFE;
       
        }
       
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // Message
        if ((line > 60) && (line < 68) && (showmessage1) && (lowbat))
        {
                ltemp = (line - 61) * 27 - 64;
                ntemp = (line - 61) * 16 - 43;
                itemp = (line - 61) * 9;
                ltr_p = ltrs+ltemp;
                num_p = nums+ntemp;
                info_p = infos+itemp;
                // +++ UBat
                while(TCNT0<LINESTART);
                TCNT0=0;
                while(TCNT0<250);
                SPSR=1;
                SPDR = ltr_p[Message_LowBat[0]]; Wait();
                SPDR = ltr_p[Message_LowBat[1]]; Wait();
                SPDR = ltr_p[Message_LowBat[2]]; Wait();
                SPDR = ltr_p[Message_LowBat[3]]; Wait();
                SPDR = ltr_p[Message_LowBat[4]]; Wait();
                SPDR = ltr_p[Message_LowBat[5]]; Wait();
                SPDR = ltr_p[Message_LowBat[6]]; Wait();
                SPDR = ltr_p[Message_LowBat[7]]; Wait();
                SPDR = ltr_p[Message_LowBat[8]]; Wait();
                SPDR = ltr_p[Message_LowBat[9]]; Wait();
                SPDR = ltr_p[Message_LowBat[10]]; Wait();
                SPDR = ltr_p[Message_LowBat[11]]; Wait();
                SPDR = ltr_p[Message_LowBat[12]]; Wait();
                SPDR = ltr_p[Message_LowBat[13]]; Wait();
                SPDR = ltr_p[Message_LowBat[14]]; Wait();
        }
       
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // alt value
       
        if((line > 80) && (line <250))
        {
                while(TCNT0<LINESTART);
                TCNT0=0;
        }

        if ((line > 170) && (line < 178))
        {
                ltemp = (line - 171) * 27 - 64;
                ntemp = (line - 171) * 16 - 43;
                itemp = (line - 171) * 9;
                ltr_p = ltrs+ltemp;
                num_p = nums+ntemp;
                info_p = infos+itemp;
                while(TCNT0<10);
                SPSR=1;
                DDRB|=1;
                SPDR = num_p[altv[0]]; Wait();
                SPDR = num_p[altv[1]]; Wait();
                SPDR = num_p[altv[2]]; Wait();
                SPDR = num_p[altv[3]]; Wait();
                SPDR = num_p[altv[4]]; Wait();
                SPDR = num_p[altv[5]]; Wait();
                DDRB&=0xFE;    
        }

        if ((line > 179) && (line < (179 + alt_delta)) && alt_dec)
        {
                while(TCNT0<50);
                SPDR = bar1; Wait();
        }

        if ((line > (169 - alt_delta)) && (line < 169) && alt_inc)
        {
                while(TCNT0<50);
                SPDR = bar1; Wait();
        }
    asm("nop");
       
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // grafic array
        if ((line > 90) && (line < 250) && (showgraphic==1))
        {

                while(TCNT0<250);
                TCNT0=0;

                i1=7*((line-90)>>2);
                i=0;
                c1=dmem[i1++];
                c2=dmem[i1++];
                c3=dmem[i1++];
                c4=dmem[i1++];
                c5=dmem[i1++];
                c6=dmem[i1++];
                c7=dmem[i1++];
                while(TCNT0<20);
                if (showgraphicb) DDRB|=1;
                do {
                  PORTB=((c1<<2)&0x04);
                  c1=c1>>1;
                  i++;
                } while(i<8);
                do {
                  PORTB=((c2<<2)&0x04);
                  c2=c2>>1;
                  i++;
                } while(i<16);
                do {
                  PORTB=((c3<<2)&0x04);
                  c3=c3>>1;
                  i++;
                } while(i<24);
                do {
                  PORTB=((c4<<2)&0x04);
                  c4=c4>>1;
                  i++;
                } while(i<32);
                do {
                  PORTB=((c5<<2)&0x04);
                  c5=c5>>1;
                  i++;
                } while(i<40);
                do {
                  PORTB=((c6<<2)&0x04);
                  c6=c6>>1;
                  i++;
                } while(i<48);
                do {
                  PORTB=((c7<<2)&0x04);
                  c7=c7>>1;
                  i++;
                } while(i<56);
                PORTB=0x00;
                DDRB&=0xFE;            
        }


// Debug - remove for release
//      if ((line > 270) && (line < 278))
//      {
//              SPSR=1;
//              ltemp = (line - 271) * 27 - 64;
//              ntemp = (line - 271) * 16 - 43;
//              itemp = (line - 271) * 8;
//              ltr_p = ltrs+ltemp;
//              num_p = nums+ntemp;
//              info_p = infos+itemp;
//              while(TCNT0<LINESTART);
//              DDRB|=1; //sink thru PB0
//              SPDR = ltr_p[rxtx[0]]; Wait();
//              SPDR = ltr_p[rxtx[1]]; Wait();
//              SPDR = ltr_p[rxtx[2]]; Wait();
//              SPDR = info_p[rxtx[3]]; Wait();
//              SPDR = ltr_p[rxtx[4]]; Wait();
//              SPDR = ltr_p[rxtx[5]]; Wait();
//              SPDR = ltr_p[rxtx[6]]; Wait();
//              SPDR = ltr_p[rxtx[7]]; Wait();
//              SPDR = info_p[rxtx[8]]; Wait();
//              TCNT0=0;
//              while(TCNT0<3);         // 3 wait a little bit before turning off dimmer so that the
//                                                      // length of black box on the right matches the one on the left
//              DDRB&=0xFE;             //PB0 Hi-Z again, and load a blank so spacing is right
//      }
       

//      if ((line > 280) && (line < 288))
//      {
//              SPSR=1;
//              ltemp = (line - 281) * 27 - 64;
//              ntemp = (line - 281) * 16 - 43;
//              ltr_p = ltrs+ltemp;     //by calculating this pointer you only have to
//              num_p = nums+ntemp;     //add ltemp/ntemp once per line, instead of for
                                                                //every char. This tightens up printing a bit
                                                                //saves about 3 assembly instructions per char
               
//              SPDR = ltr_p['@']; Wait(); //goofy hack to make SPSR=0 work, write an empty char at SPSR=1 first
//              SPSR=1;
//              while(TCNT0<LINESTART);
//              DDRB|=1; //sink thru PB0
//              //;display_line1[0]='A';
//              SPDR = ltr_p[display_line1[0]]; Wait();
//              SPDR = ltr_p[display_line1[1]]; Wait();
//              SPDR = ltr_p[display_line1[2]]; Wait();
//              SPDR = ltr_p[display_line1[3]]; Wait();
//              SPDR = ltr_p[display_line1[4]]; Wait();
//              SPDR = ltr_p[display_line1[5]]; Wait();
//              TCNT0=0;
//              while(TCNT0<3);         // 3 wait a little bit before turning off dimmer so that the
//                                                      // length of black box on the right matches the one on the left
//              DDRB&=0xFE;             //PB0 Hi-Z again, and load a blank so spacing is right
//      }
       
        if ((line > 300) && (line < 308))
        {
                SPSR=1;
                ltemp = (line - 301) * 27 - 64;
                ntemp = (line - 301) * 16 - 43;
                ltr_p = ltrs+ltemp;    
                num_p = nums+ntemp;    
                while(TCNT0<LINESTART+COPYRIGHTSTART);
                SPDR = ltr_p[head[0]]; Wait();
                SPDR = ltr_p[head[1]]; Wait();
                SPDR = ltr_p[head[2]]; Wait();
                SPDR = ltr_p[head[3]]; Wait();
                SPDR = ltr_p[head[4]]; Wait();
                SPDR = ltr_p[head[5]]; Wait();
                SPDR = ltr_p[head[6]]; Wait();
                SPDR = ltr_p[head[7]]; Wait();
                SPDR = ltr_p[head[8]]; Wait();
                SPDR = ltr_p[head[9]]; Wait();
                SPDR = ltr_p[head[10]]; Wait();
                SPDR = ltr_p[head[11]]; Wait();
                SPDR = ltr_p[head[12]]; Wait();
                SPDR = ltr_p[head[13]]; Wait();
                SPDR = ltr_p[head[14]]; Wait();
                SPDR = ltr_p[head[15]]; Wait();
                SPDR = ltr_p[head[16]]; Wait();
                TCNT0=0;
                while(TCNT0<2);        
        }
} // end draw_line()


//-----------------------------------------------------------------------------
// H-Sync Interrupt
//-----------------------------------------------------------------------------*/
SIGNAL(SIG_INTERRUPT0)
{
        TCNT0=0;                // reset timer
        line++;                 // increment line counter
        draw_line();    // output the line
}      


//-----------------------------------------------------------------------------
// V-Sync Interrupt
//-----------------------------------------------------------------------------*/
SIGNAL(SIG_INTERRUPT1)
{
        line = 0;
        framecounter++;
}