/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.5 Standard
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : Telemetrie Empfänger
Version : 
Date    : 30.04.2007
Author  : Wilhelm Krug                    
Company : 92345 Dietfurt, Germany         
Comments: 

Chip type           : ATmega8
Program type        : Application
Clock frequency     : 8,000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/

/****************************************************
Alle Rechte dieses Programmes liegen bei mir.
Dieses Programm besitz den Status einer Open Source für Privatanwender.
Das bedeutet jeder Privatmann kann dieses Programm oder Teile daraus
für seine eigenen Entwicklungen nutzen.
Eine wie auch immer geartete kommerzielle Nutzung schließe ich aber Ausdrücklich aus.
Sollte mir eine Kommerzielle Nutzung dieses Programmcodes bekannt werden,
behalte ich mir strafrechtliche Schritte vor.
****************************************************/

/****************************************************
Dieses Programm liest die Daten eines RFM 01 Funkmoduls
(Empfänger) von Pollin aus und berechnet anhand der mitgelieferten
Checksumme ob das Signal Fehler enthielt.
Fehlerfreie Frames werden an die serielle Schnittstelle im Format
38400,8,N,1 übertragen.
Das Empfangssignal hat das Format:
Ein Startframe lautet 0xAA 0xAA 0xAA 0x2D 0xD4
Dieses Startframe wird vor den eigentlichen Daten gesendet
und vom FiFo Puffer dieses Empfängers ausgeblendet.
Jetzt folgen die eigentlichen Daten:
$x1;x2;x3;...xn;cscs<cr><lf>
Das '$' ist das Startzeichen einer Zeile.
x1... Sind die übertragenen Werte
cs cs ist das High und Low Nibble der Checksumme in ASCII Codierung
Die Checksumme ist das Ergebnis einer EXOR Verknüpfung
aller Bytes von '$' bis letzter Datensatz  
Die Berechnung der Checksumme und die Sendung an die
serielle Schnittstelle wird durch das Zeichen <lf> getriggert.
Nur fehlerfreie Frames werden an die serielle Schnittstelle gesendet

Zuordnung Kanäle - Dip Fix - Frequenz
Dip Fix:Kanal:Frequenz
Dip Kanal	Frequenz
xxx 01	433.075 MHz
00  02	433.100 MHz
xxx 03	433.125 MHz
xxx 04	433.150 MHz
01  05	433.175 MHz
xxx 06	433.200 MHz
xxx 07	433.225 MHz
02  08	433.250 MHz
xxx 09	433.275 MHz
xxx 10	433.300 MHz
03  11	433.325 MHz
xxx 12	433.350 MHz
xxx 13	433.375 MHz
04  14	433.400 MHz
xxx 15	433.425 MHz
xxx 16	433.450 MHz
05  17	433.475 MHz
xxx 18	433.500 MHz
xxx 19	433.525 MHz
06  20	433.550 MHz
xxx 21	433.575 MHz
xxx 22	433.600 MHz
07  23	433.625 MHz
xxx 24	433.650 MHz
xxx 25	433.675 MHz
08  26	433.700 MHz
xxx 27	433.725 MHz
xxx 28	433.750 MHz
09  29	433.775 MHz
xxx 30	433.800 MHz
xxx 31	433.825 MHz
10  32	433.850 MHz
xxx 33	433.875 MHz
xxx 34	433.900 MHz
11  35	433.925 MHz
xxx 36	433.950 MHz
xxx 37	433.975 MHz
12  38	434.000 MHz
xxx 39	434.025 MHz
xxx 40	434.050 MHz
13  41	434.075 MHz
xxx 42	434.100 MHz
xxx 43	434.125 MHz
14  34	434.150 MHz
xxx 45	434.175 MHz
xxx 46	434.200 MHz
15  47	434.225 MHz
xxx 48	434.250 MHz
xxx 49	434.275 MHz
16  50	434.300 MHz
xxx 51	434.325 MHz
xxx 52	434.350 MHz
17  53	434.375 MHz
xxx 54	434.400 MHz
xxx 55	434.425 MHz
18  56	434.450 MHz
xxx 57	434.475 MHz
xxx 58	434.500 MHz
19  59	434.525 MHz
xxx 60	434.550 MHz
xxx 61	434.575 MHz
20  62	434.600 MHz
xxx 63	434.625 MHz
xxx 64	434.650 MHz
21  65	434.675 MHz
xxx 66	434.700 MHz
xxx 67	434.725 MHz
22  68	434.750 MHz
xxx 69	434.775 MHz
Alle DIP FIX mit gültigen Werten versehen !
23  68	434.750 MHz
24  68	434.750 MHz
25  68	434.750 MHz
26  68	434.750 MHz
27  68	434.750 MHz
28  68	434.750 MHz
29  68	434.750 MHz
30  68	434.750 MHz
31  68	434.750 MHz
****************************************************/

#include <mega8.h>
// Standard Input/Output functions
#include <stdio.h>
#include <string.h>
#include <delay.h>
#include <stdlib.h> /* Test */
#asm
.equ portb=0x18
.equ portd=0x12
.equ sdi=0     ;PortB,0
.equ sck=1     ;PortB,1
.equ nsel=2    ;PortB,2
.equ sdo=3     ;PortB,3
.equ nirq=2    ;PortD,2
#endasm

// Declare your global variables here
bit newstring=0; /* Ein neuer gültiger Datenstring wurde empfangen */
flash unsigned int ui_frequ[32]={1240,1270,1300,1330,1360,1390,1420,1450,1480,1510,1540,1570,1600,1630,1660,1690,1720,1750,1780,1810,1840,1870,1900,1900,1900,1900,1900,1900,1900,1900,1900,1900};
volatile unsigned char uc_receivebuffer[127];/* Empfangspuffer */
volatile unsigned char uc_receivebyte=0;/* Zeiger aktuelles Sendebyte */
volatile unsigned char uc_timeout=0;
volatile unsigned char uc_kanal; /* gewählter Kanal */

// Sende ein Byte zum RFM 01
void sendbyte(volatile unsigned char uc_byte)
{   
    #asm
    push r26        ;Register retten
    in r26,sreg
    push r26
    push r27
    ldi r26,8       ;Schleifenzähler mit 8 laden
    ld r27,y        ;uc_Byte vom Ram holen
    
    sendloop:
        tst r26     ;Schleifenzähler eins runterzählen
        breq endsend
        dec r26
        clc
        rol r27     ;High Byte ins Carry schieben
        brcs send1  ;Bei 1 -> High ausgeben
        cbi portb,sdi     ;Bei 0 -> Low ausgeben
        rcall clockpulse
        rjmp sendloop
    
    send1:
        sbi portb,sdi
        rcall clockpulse
        rjmp sendloop
    
    clockpulse:
        nop
        nop
        nop
        sbi portb,sck     ;Clock Port auf 1 setzen
        nop
        nop
        nop
        nop
        nop
        nop
        cbi portb,sck     ;Clock Port auf 0 setzen
        nop
        nop
        nop
        ret         ;Zurück zur aufrufenden Routine
    
    endsend:
        cbi portb,sdi ;SDI Port auf 0 setzen zwecks kosmetik
        pop r27
        pop r26
        out sreg,r26
        pop r26
   #endasm
}

// Checksumme berechnen
unsigned char checksum (void)
{
    volatile unsigned char uc_check[2]={0,0}; /* (Checksummenpuffer)*/
    volatile unsigned char uc_i=0;
    volatile unsigned char uc_stringlengh=0;
    uc_stringlengh=strlen(uc_receivebuffer);
    uc_check[0]=uc_receivebuffer[uc_stringlengh-4]; /* High nibble einlesen */
    uc_check[1]=uc_receivebuffer[uc_stringlengh-3]; /* Low nibble einlesen */
    if (uc_check[0]>0x39)
    {
        uc_check[0]=uc_check[0]-0x37; /*ASCII Code A...F */
    }
    else
    {
        uc_check[0]=uc_check[0]-0x30; /*ASCII Code 0...9 */
    }    
    if (uc_check[1]>0x39)
    {
        uc_check[1]=uc_check[1]-0x37;
    }
    else
    {
        uc_check[1]=uc_check[1]-0x30;
    }    
    uc_check[0]&=0x0F;
    uc_check[1]&=0x0F;
    uc_check[0]=uc_check[0]*16;         /* Checksummen zusammenführen */
    uc_check[0]=uc_check[0]|uc_check[1];
    
    for (uc_i=0;uc_i<(uc_stringlengh-4);uc_i++)
    {
        uc_check[0]^=uc_receivebuffer[uc_i]; /* XOR Verknüpfung */
    };
    return uc_check[0]; /* Rückgabe der Checksumme, sollte wenn richtig 0 sein */
}

//FIFO Puffer initialisieren bei Fehlern und Datensatzende
void reset_fifo (void)    
{
    /* FIFO Command: Enable FIFO, IT level=8, Sync. Patt + VDI, stop FIFO  */
    #asm ("cbi portb,nsel");
    sendbyte(0b11001110);
    sendbyte(0b10001001);
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    /* FIFO Command: Enable FIFO, IT level=8, Sync. Patt + VDI, start FIFO  */
    #asm ("cbi portb,nsel");
    sendbyte(0b11001110);
    sendbyte(0b10001011);
    #asm ("sbi portb,nsel");
    #asm ("nop");
    uc_receivebyte=0;
}

// Einen Taktimpuls erzeugen 
void clockpulse(void)
{
    #asm
        nop
        nop
        nop
        sbi portb,sck     ;Clock Port auf 1 setzen
        nop
        nop
        nop
        nop
        nop
        nop
        cbi portb,sck     ;Clock Port auf 0 setzen
        nop
        nop
        nop
        
    
    #endasm
}

// Empfange Daten vom RFM 01
interrupt [EXT_INT0] void ext_int0_isr(void)
{
    unsigned char uc_i=0;
    unsigned char uc_buffer=0;
    unsigned char uc_check=0;
    
    
    uc_timeout=0; /* Timeout Zähler zurücksetzen */
    
    /* Die ersten 16 Bit des Statuswortes übergehen */
    #asm ("cbi portb,nsel");
    sendbyte(0b00000000);
    sendbyte(0b00000000); 
    
    for(uc_i=0;uc_i<8;uc_i++)/* 8 Bits auslesen */
    {
        
        
        if ((PINB&(1<<3))!=0) /* SDO abfragen = PortB,3 */
        {
            uc_buffer=(uc_buffer<<1)| 0x01;
        }
        else
        {
            uc_buffer=(uc_buffer<<1);     
        }
        clockpulse();
    }
    #asm ("sbi portb,nsel"); /* nSel Leitung abschalten */
    #asm ("nop");
    
    // Hingen noch Reste im Puffer ? oder Puffer Überlauf -> Dann löschen    
    if((uc_buffer=='$')||(uc_receivebyte>125))
    {
        uc_receivebyte=1;
        uc_receivebuffer[0]='$';     /* Das Erste Byte des Empfangspuffers mit $ beschreiben*/
        uc_receivebuffer[1]=0;             /* Ein Stringende anfügen*/
    }
    else
        {
        uc_receivebuffer[uc_receivebyte]=uc_buffer;
        uc_receivebyte++;
        uc_receivebuffer[uc_receivebyte]=0; /* Stringende anfügen */
        };
         
    if (uc_buffer==10) /* Line Feed wurde empfangen*/ 
    {
        reset_fifo();
        uc_check=checksum();
                               
        if (uc_check==0)
        {
            newstring=1;
        };
        uc_receivebyte=0;
    }
}   




#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

// USART Transmitter buffer
#define TX_BUFFER_SIZE 127
char tx_buffer[TX_BUFFER_SIZE];

#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif

// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
if (tx_counter)
   {
   --tx_counter;
   UDR=tx_buffer[tx_rd_index];
   if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
   {
   tx_buffer[tx_wr_index]=c;
   if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
   ++tx_counter;
   }
else
   UDR=c;
#asm("sei")
}
#pragma used-
#endif


//RFM01 initialisieren
void init_rfm01(void)
{
    volatile unsigned char uc_frequ[2]; /* Frequenz tuningword */
    /* Frequenzwortermittlung aus der Kanalangabe */
    uc_frequ[1]=ui_frequ[uc_kanal]/256;
    uc_frequ[1]|=0b10100000;
    uc_frequ[0]=ui_frequ[uc_kanal]%256;
    
    /* Configuration Setting: 433MHz, CLK on, 11,5pf Kapaz., 67kHz */
    #asm ("cbi portb,nsel");
    sendbyte(0b10001001);
    sendbyte(0b01101100); 
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    /* Low Batt Clock Divider Command: clock 5MHz */
    #asm ("cbi portb,nsel");
    sendbyte(0b11000010);
    sendbyte(0b11000000); 
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    /* Frequency Setting: 434MHz (je nach Kanal) */
    #asm ("cbi portb,nsel");
    sendbyte(uc_frequ[1]);
    sendbyte(uc_frequ[0]); 
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    /* Receiver Setting Command: VDI= Digital RSSI Out, -103dB, receiver disabled */
    #asm ("cbi portb,nsel");
    sendbyte(0b11000000);
    sendbyte(0b10000000);
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    /* Receiver Setting Command: VDI= Digital RSSI Out, -103dB receiver enabled */
    #asm ("cbi portb,nsel");
    sendbyte(0b11000000);
    sendbyte(0b10000001);
    #asm ("sbi portb,nsel");
    #asm ("nop");
       
    /* FIFO Command: Enable FIFO, IT level=8, Sync. Patt + VDI, stop FIFO  */
    #asm ("cbi portb,nsel");
    sendbyte(0b11001110);
    sendbyte(0b10001001);
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    /* FIFO Command: Enable FIFO, IT level=8, Sync. Patt + VDI, start FIFO  */
    #asm ("cbi portb,nsel");
    sendbyte(0b11001110);
    sendbyte(0b10001011);
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    
    /* Data Filter Command:  */
    #asm ("cbi portb,nsel");
    sendbyte(0b11000100);
    sendbyte(0b10101100); 
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    
    /* Data Rate Command: 2400 bit/s */
    #asm ("cbi portb,nsel");
    sendbyte(0b11001000);
    sendbyte(0b10010001);
    #asm ("sbi portb,nsel");
    #asm ("nop");
    
    
    /* AFC Command: Enable AFC, +3/-4, offset at VDI high */
    #asm ("cbi portb,nsel");
    sendbyte(0b11000110);
    sendbyte(0b10111111); 
    #asm ("sbi portb,nsel");
    #asm ("nop");
       
}

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
/* 1 Sekunde */
uc_timeout++;

if (uc_timeout>3)/* Wenn 3 Sekunden kein Bit mehr Empfangen wurde wird der FiFo resetet */
{
    init_rfm01();
    reset_fifo();
    uc_timeout=0;
}
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here
unsigned char uc_i=0;
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=Out 
// State7=T State6=T State5=T State4=T State3=T State2=0 State1=0 State0=0 
PORTB=0x00;
DDRB=0x07;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State6=T State5=P State4=P State3=P State2=P State1=P State0=P 
PORTC=0x3F;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 31,250 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
// CTC Mode : On
TCCR1A=0x00;
TCCR1B=0x0C;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x7A; /* Comparematch Register mit 31250 laden = 1 Sekunde */
OCR1AL=0x11;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: Off
GICR|=0x40;
MCUCR=0x02;
GIFR=0x40;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 38400
UCSRA=0x00;
UCSRB=0x48;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x0C;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// Kanalauswahl
uc_kanal=(PINC&0b00011111);

// RFM 01 initialisieren
#asm ("sbi portb,nsel");
delay_ms(1);
init_rfm01();
reset_fifo();


// Global enable interrupts
#asm("sei")


while (1)
      {
      /*newstring=1;*/ /* zu Testzwecken */
      
      /* strcpyf(uc_receivebuffer,"$3;1;680;525;526;0;0;0;0;0;0;0;0;20¶?");
      uc_receivebyte=37;
      uc_i=checksum();*/
      if (newstring==1)
      {
        for (uc_i=0;uc_i<strlen(uc_receivebuffer);uc_i++)
        {
        putchar (uc_receivebuffer[uc_i]);
        }
        newstring=0;
      }  
      };
}
