'##############################################################################
'
' HangingMan.BAS                                               Stand 09.07.2014
' --------------                                               (C) Markus Fulde
'
' Gesamtsoftware Steuerprogramm für das Geocaching-Spiel Hanging Man
'
' Das Projekt verfüg über die folgenden Funktions- und Teilkomponenten:
' - Spannungsversorgung via 9V Batterie und 5V über Festspannungsregler
' - Mikrocontroller ATmega8L (inkl. ISP, RS232 und Reset)
' - LCD-Display 2x16 EA DOG-M 162 von Electronic Assembly
' - Die Helligkeit des Display soll über PWM einstellbar sein
' - Bei Innaktivität soll das Display abgeschaltet werden können
' - Hauptschalter für Spannungsversorgung
' - Drück-Dreh-Geber (inkrementeller Drehgeber mit Tasterfunktion)
' - LED-Anzeigen für Betriebsanzeige und Low-Power Batterie-Überwachung
' - Gehäuse mit Batteriefach und Displayfenster
' - Akustisches Feedback über Piezo Schallwandler
'
'##############################################################################

'------------------------------------------------------------------------------
' Allgemeines zum Spiel:
'------------------------------------------------------------------------------
' Galgenmännchen, Galgenraten, Galgenbaum oder auch Galgenmann, Hängemann,
' Hängemännchen oder ein-fach auch Galgen (englisch auch hangman) ist ein
' einfaches Buchstabenspiel.
'
' Spielverlauf
' Der Spieler spielt alleine mit Hilfe der Elektronik. Am Ende bei erfolgreichem
' Spiel wird eine Geokoordinaten für das Finale ausgegeben.
' Der Computer überlegt sich nun ein Wort 13 Buchstaben. Alle Buchstaben des
' ausgedachten Wortes werden durch Striche markiert. Der Geocacher hat nun die
' Aufgabe, die Buchstaben zu erraten. Hierzu wählt er in beliebiger Reihenfolge
' nacheinander einzelne Buchstaben des Alphabets mit dem DDS aus. Der Computer
' prüft die Eingabe und zeigt an, wie oft und an welcher Stelle des Lösungswortes
' der Buchstabe vorkommt. So ergibt sich nach und nach das gesuchte Wort.
' Kommt ein genannter Buchstabe darin jedoch nicht vor beginnt der Computer damit,
' einen Galgen mit einem Gehängten zu zeichnen. Dies geschieht in 5 Etappen
' (bei jeder Fehlfrage kommt ein Teilstrich dazu), so dass der Geocacher 5
' Versuche hat das Wort zu erraten. Hat er dann das Wort noch nicht herausgefunden,
' so hat er verloren und hängt symbolisch am Galgen.
'
' Umlaute werden ae, oe oder ue geschrieben.
' Der Anfangsbuchstabe muss ebenfalls geraten werden.
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
' Anmerkungen zum Programm:
'------------------------------------------------------------------------------

' [1] Zufallszahlengenerator in BASCOM
' Die Rnd() Funktion Arbeitet Nicht Wirklich Zufällig. Hierzu Sagt Mcv Folgendes:
' The Rnd() Function Returns An Integer / Word And Needs An Internal Storage Of 2 Bytes.
' (___rseed). Each New Call To Rnd() Will Give A New Positive Random Number.
' notice Notice that it is a software based generated number.
' And each time you will restart your program the same sequence will be created.
'
' You can use a different SEED value by dimensioning and assigning ___RSEED yourself:
' Dim ___rseed as word : ___rseed = 10234
' Dim I as word : I = rnd(10)
'
' When your application uses a timer you can assign ___RSEED with the timer value.
' This will give a better random number.
'
' Aus diesem Grund wird hier in der Software beim Auslesen der Batteriespannung
' die SEED-Variable des Zufallszahlengenerators neu gesetzt um mehr
' Zufälligkeit zu erzeugen.
'
' [2] Bypassmodus
' Um das Spiel nicht spielen zu müssen wird quasi als Hintertür ein Bypassmodus
' implementiert der wie folgt erreicht werden kann:
'    - Spiel ausschalten
'    - DDS Drücken / gedrückt halten und Spiel einschalten
'    - DDS loslassen
'    - DDS 5x links drehen
'    - DDS 5x rechts drehen
'    - DDS erneut kurz betätigen
' Danach wird direkt die finale Geokoordinate an der sich der Cache befindet
' angezeigt. Abweichungen zur beschriebenen Bedienung führen zum sofortigen
' Abbruch der Bypasssequenz und es muss normal gespielt werden.
' Zur Kontrolle ob ein Cacher den Bypassmode findet und dies weiterkommuniziert
' wird ein Bypasscounter geführt der im EEPROM abgelegt wird. Dieser Couner
' wird kurz vor dem Anzeigen der finalen Koordinaten angezeigt. Somit hat man
' die Kontrolle darüber ob jemand dieses Hintertürchen gefunden hat.
' Das Hintertürchen ist als Telefonjoker für Cacher gedacht die erfolglos
' versucht haben das Spiel zu spielen und den Owner kontaktieren.

'------------------------------------------------------------------------------
' Compilerinstruktionen und Compilerdirektiven
'------------------------------------------------------------------------------
$regfile = "m8def.dat"                                      ' Definitionsdatei für ATmega128 laden
$crystal = 8000000                                          ' Quarzfrequenz für 16 MHz festlegen

$hwstack = 128                                              ' HW-Stack auf 128 Bytes erweitern
$swstack = 64                                               ' SW-Stack auf 64 Bytes erweitern
$framesize = 80                                             ' Framesize auf 80 Byte festlegen

$baud = 19200                                               ' Baudrate für RS232 Traceausgabe definieren

'------------------------------------------------------------------------------
' Allgemeine Zusatzinformatonen zu Programmbeginn
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
' Definition von Ressourcen
'------------------------------------------------------------------------------

' ----- LED's -----
Alive_pin Alias PinB.0                                      ' GPIO für Alive-LED (für DDR oder Input)
Alive Alias PortB.0                                         ' GPIO für Alive-LED (für Output oder Pullup)

Pwrled_pin Alias PINB.1                                     ' GPIO für Power-LED (für DDR oder Input)
Pwrled Alias PORTB.1                                        ' GPIO für Power-LED (für Output oder Pullup)

' ----- LCD-Display -----
' LCD-Display
Db4_pin Alias PortC.2                                       ' GPIO für LCD Pin4
Db5_pin Alias PortC.3                                       ' GPIO für LCD Pin5
Db6_pin Alias PortC.4                                       ' GPIO für LCD Pin6
Db7_pin Alias PortC.5                                       ' GPIO für LCD Pin7
E_pin Alias PortD.6                                         ' GPIO für LCD E
Rs_pin Alias PortD.7                                        ' GPIO für LCD RS

' ----- SOUND -----
Piezosound_pin Alias Pinb.2                                 ' GPIO für Soundausgabesteuerung (Transistorstufe)
Piezosound Alias Portb.2                                    ' GPIO für Sound (für Output oder Pullup)

' ----- DDS -----
A_signal_pin Alias Pind.2                                   ' GPIO für DDS Signal A (für DDR oder Input)
A_signal Alias Portd.2                                      ' GPIO für DDS Signal A (für Output oder Pullup)

B_signal_pin Alias Pind.4                                   ' GPIO für DDS Signal B (für DDR oder Input)
B_signal Alias Portd.4                                      ' GPIO für DDS Signal B (für Output oder Pullup)

Push_signal_pin Alias Pind.3                                ' GPIO für DDS Push (für DDR oder Input)
Push_signal Alias Portd.3                                   ' GPIO für DDS Push (für Output oder Pullup)

'------------------------------------------------------------------------------
' Definition von Konstaten
'------------------------------------------------------------------------------

' ----- Für Testumgebung bzw. Traceausgaben -----
Const Main_testmodus = 0                                    ' Flag für Testmodus Allgemeinsystem
Const Lcd_testmodus = 0                                     ' Flag für Testmodus rund um das LCD-Display
Const Game_testmodus = 0                                    ' Flag für Testmodus der Spielsteuerung
Const Dds_testmodus = 0                                     ' Flag für Testmodus des Drückdrehstellers
Const Bypass_testmodus = 0                                  ' Flag für Testmodus des Bypass-Modes
Const Eeprom_testmodus = 0                                  ' Flag für Testmodus der Eeprom-Daten

' ----- Allgemeine Systemkonstanten -----

' Tatsächliches Allgemeines
Const Led_aus = 0
Const Led_ein = 1

' Const Led_aus = 1                                           ' Achtung !! bei STK500 ist Logik gedreht!!
' Const Led_ein = 0                                           ' Achtung !! bei STK500 ist Logik gedreht!!

Const False = 0
Const True = 1

Const Pullup_aus = 0
Const Pullup_ein = 1

' Zeitvorgabe für Sekunden-Timer
Const Timervorgabe = 34286                                  ' Timer von 1 Sekunden (SekundenTick)

' ----- LCD -----

' Anmerkung: Wert von 35 ist der beste Wert welcher durch Versuche ermittelt wurde!!
Const Lcd_kontrast_default = 35                             ' LCD-Default-Kontrast

' Anmerkung: Wert von 70 ist der beste Wert welcher durch Versuche ermittelt wurde!!
Const Lcd_helligkeit_default = 70                           ' LCD-Default-Helligkeit

Const Lcd_helligkeit_aus = 0                                ' Wert für Display aus
Const Lcd_abschaltzeit = 20                                 ' Defaultwert auf 10 Sekunden festgelegt

Const Lcd_beleuchtung_status_ein = 1                        ' Statuswert für LCD Beleuchtung ein
Const Lcd_beleuchtung_status_aus = 0                        ' Statuswert für LCD Beleuchtung aus

' ----- ADC: Batterieüberwachung -----
Const Ubatt_grenzwert = 700                                 ' Grenzwert für Batterieüberwachung

' ----- Sound -----
Const Sound_ein = 1                                         ' Wert für GPIO-Wert um Sound einzuschalten
Const Sound_aus = 0                                         ' Wert für GPIO-Wert um Sound auszuschalten

' ----- DDS -----
Const Dds_none = 0                                          ' Keine Betätigung des DDS
Const Dds_links = 1                                         ' DDS wurde nach links gedreht
Const Dds_rechts = 2                                        ' DDS wurde nach rechts gedreht

' ----- GAME -----
Const Game_anzahl_text = 100                                ' Anzahl der Text im DATA Bereich
Const Game_textmaske = "_____________"

'                                          1         2         3
'                                 12345678901234567890123456789012345678
Const Game_auswahltext_default = "uvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
'                                       12345678901234567890123456
'                                                1         2

Const Game_startposition_default = 1                        ' Startposition für Buchstabenauswahl

Const Game_fuellzeichen = 32                                ' Leerzeichen ist Fuellzeichen
' Const Game_fuellzeichen = 95                                ' Unterstrich ist Fuellzeichen

Const Game_cursorzeichen = &B00101010                       ' Zeichen aus Displayzeichentabelle für Cursorzeichen (Stern)

Const Game_leftcount_max = 5                                ' Anzahl von Linkstix für Bypassmode
Const Game_rightcount_max = 5                               ' Anzahl von Rechtstix für Bypassmode

' ----- EEPROM -----
Const Ee_default_version_value = 1                          ' Version für persistente Daten

'------------------------------------------------------------------------------
' Definition von Variablen und Datentypen
'------------------------------------------------------------------------------

' ----- Temporäre Hilfsvariablen -----
Dim Temp_byte_1 As Byte                                     ' Temporäre Byte Variable 1
Dim Temp_byte_2 As Byte                                     ' Temporäre Byte Variable 2

Dim Temp_word_1 As Word                                     ' Temporäre Word Variable 1
Dim Temp_word_2 As Word                                     ' Temporäre Word Variable 2

' ----- System -----
Dim ___rseed As Word                                        ' Manipulation des Zufallszahlengenerators
Dim Sectick_counter As Word                                 ' Globaler Sekundenzähler

' ----- Arbeitsvariablen für Spieleablauf -----
Dim Game_hangman_status As Byte                             ' Arbeitsvariable für Hangman-Status
Dim Game_ablaufstatus As Byte                               ' Arbeitsvariable für System-Status

Dim Game_suchtext As String * 13                            ' Stringvariable für den Suchtext
Dim Game_suchtext_zeichen(14) As Byte At Game_suchtext Overlay

Dim Game_scrolltext As String * 13                          ' Stringvariable für Scrolltext in Zeile 1
Dim Game_scrolltext_zeichen(14) As Byte At Game_scrolltext Overlay       ' Zeichenweise Zugriff auf Scrolltext

Dim Game_raetseltext As String * 13                         ' Stringvariable für zu suchenden Text in Zeile 2
Dim Game_raetseltext_zeichen(14) As Byte At Game_raetseltext Overlay       ' Zeichenweise Zugriff auf Raetseltext

Dim Game_auswahltext As String * 38                         ' Stringvariable für scrollbaren Auswahltext
Dim Game_auswahltext_zeichen(39) As Byte At Game_auswahltext Overlay       ' Zeichenweise Zugriff auf Auswahltext

Dim Game_buchstaben_index As Byte                           ' Arbeitsvariable für aktuelle Buchstabenauswahl

Dim Game_bypassmode_flag As Byte                            ' Arbeitsvariable für Einstieg in Bypassmodus
Dim Game_bypassmode_leftcounter As Byte                     ' Arbeitsvariable für Bypass Linkscounts
Dim Game_bypassmode_rightcounter As Byte                    ' Arbeitsvariable für Rechtscount

' ----- Variablen für LCD-Display -----
Dim Lcd_kontrastwert As Byte                                ' Arbeitsvariable für Kontrastwert
Dim Lcd_helligkeit As Byte                                  ' Arbeitsvariable für Displayhelligkeit
Dim Lcd_abschaltcounter As Word                             ' Variable für Abschaltzeitpunkt
Dim Lcd_beleuchtung_status As Byte                          ' Arbeitsvariable für Zustand der Hintergrundbeleuchtugn

' ----- ADC: Batteriespannungsueberwachung -----
Dim Adc_channel As Byte                                     ' Arbeitsvariable für ADC-Kanalauswahl

' ----- DDS -----
Dim Dds_flag As Byte                                        ' Arbeitsvariable zur Behandlung des DDS
Dim Push_flag As Byte                                       ' Arbeitsvariable zur Behandlung des Tasters

' ----- EEPROM -----
Dim Ee_data_version_value As Eram Byte At &H0000            ' EEPROM Datenstruktur internes EEPROM - Init-Index / Version
Dim Ee_data_bypass_counter As Eram Word At &H0001           ' EEPROM Datenstruktur internes EEPROM - Counter
Dim Ee_version_value As Byte                                ' BYTE Arbeitsvariable für Daten-Version
Dim Ee_bypass_counter As Word                               ' WORD Arbeitsvariable für Bypasscounter

'------------------------------------------------------------------------------
' Prototyping
'------------------------------------------------------------------------------

' ----- LCD und Print -----
Declare Sub Lcd_print_hangingman(byval Value As Byte)       ' Funktion zum schrittweisen Aufbau des Hanging Man

'------------------------------------------------------------------------------
' Konfiguration und Basiseinstellungen (Projekt und Testumgebung)
'------------------------------------------------------------------------------

' --------------------------------- CONFIG ------------------------------------

' ----- Timer -----

' Konfiguration eines Timers für 1 Sekunden Timer-Tick (Scheduler und Alive)
Config Timer1 = Timer , Prescale = 256                      ' Timer 1 verwenden
On Timer1 Sekunden_tick                                     ' Interrupt Routine
Timer1 = Timervorgabe
Enable Timer1                                               ' Interrupt für Sekunden-Tack freigeben

' Konfiguration Timer 2 für Hardware-PWM an OC2 (D.7)
Config Timer2 = Pwm , Prescale = 128 , Compare Pwm = Clear Up       ' Timer 2 verwenden
Enable Timer2                                               ' Interrupt für PWM Timer 2 freigeben

' ----- LCD Display -----

' Konfiguration LCD Display
Config Lcdpin = Pin , Db4 = Db4_pin , Db5 = Db5_pin , Db6 = Db6_pin , Db7 = Db7_pin , E = E_pin , Rs = Rs_pin
Config Lcd = 16 * 2 , Chipset = Dogm162v5                   ' DOG-M Treiber laden
Config Lcdbus = 4                                           ' LCD arbeitet über 4-Bit
Initlcd                                                     ' LCD initialisieren
Waitms 100                                                  ' 100ms nach Init warten
Cursor Off Noblink                                          ' Blinkenden Cursor abschalten

' Definition benutzerdefinierter Zeichen
Deflcdchar 0 , 16 , 16 , 16 , 16 , 16 , 16 , 30 , 30        ' LCD-Zeichen linker Sockel des Galgens
Deflcdchar 1 , 15 , 9 , 10 , 12 , 8 , 8 , 8 , 8             ' LCD-Zeichen linke obere Ecke des Galgens
Deflcdchar 2 , 28 , 4 , 32 , 32 , 32 , 32 , 32 , 32         ' LCD-Zeichen rechter Galgen ohne Männchen
Deflcdchar 3 , 28 , 4 , 4 , 14 , 17 , 17 , 14 , 4           ' LCD-Zeichen rechter Galgen mit Kopf
Deflcdchar 4 , 4 , 4 , 4 , 4 , 32 , 32 , 32 , 32            ' LCD-Zeichen Bauch
Deflcdchar 5 , 4 , 4 , 4 , 4 , 8 , 16 , 16 , 32             ' LCD-Zeichen Bauch mit linkem Beine
Deflcdchar 6 , 4 , 4 , 4 , 4 , 10 , 17 , 17 , 32            ' LCD-Zeichen Bauch mit beiden Beinen
Deflcdchar 7 , 14 , 21 , 21 , 4 , 10 , 17 , 17 , 32         ' LCD-Zeichen kompletter Männchen-Körper

Cls                                                         ' Clear Screen
' Anmerkung: CLS muss gemäß Datenblatt sein um selbstdefinierte Zeichen in den Controller zu übernehmen ......

' ----- ADC: Batterieueberwachung -----
' Konfiguration ADC Single-Mode und automatische Prescaler Setting
' Der Single-Mode wir bei BASCOM in Verbindung mit der Funktion GETADC() verwendet
' Der Prescaler teilt den internen Tackt durch 2, 4, 8,16,32,64 or 128 da der ADC
' einen Takt zwischen 50-200 kHz benötigt.
' Das AUTO Feature von BASCOM, setzt automatisch die höchste mögliche Taktrate
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc

' ------------------------------- Port's und Pin's ----------------------------

' ----- LED-Konfigurationen -----
Config Alive_pin = Output                                   ' GPIO für Alive-LED ist Output
Config Pwrled_pin = Output                                  ' GPIO für Power-LED ist Output

' ----- Sound ------
Config Piezosound_pin = Output                              ' GPIO für Sound ist Output

' ----- DDS ------
Config A_signal_pin = Input                                 ' GPIO für DDS-A ist Input, PullUp wird später geschaltet
Config B_signal_pin = Input                                 ' GPIO für DDS-B ist Input, PullUp wird später geschaltet
Config Push_signal_pin = Input                              ' GPIO für Taster ist Input, PullUp wird später geschaltet

' ----- DDS -----

' Int 0 für Signal A so konfigurieren dass Interrupt bei fallender Flanke angesprungen wird
Config Int0 = Falling                                       ' Schalter zieht PullUp-Spannung auf GND
On Int0 Dds_interrupt                                       ' Interrupt-Routine
Enable Int0                                                 ' Interrupt freigeben

' Int 1 für den Taster so konfigurieren, dass Interrupt bei fallender Flanke angesprungen wird
' Via Default ist Interrupt aber deaktiviert. Er wird nur zur Abfrage des Tasters bei der Anzeige
' der Geokoordinaten aktiviert.
Config Int1 = Falling                                        ' Schalter zieht PullUp-Spannung auf GND
On Int1 Push_interrupt                                       ' Interrupt-Routine
Disable Int1                                                 ' Interrupt freigeben

' ------------------------------ Variablen und Werte --------------------------

' ----- System -----
Sectick_counter = 0                                         ' Globaler Sekundenzähler initialisieren

' ----- LED-Konfigurationen -----
Alive = Led_aus                                             ' Alive-LED aus
Pwrled = Led_aus                                            ' LED für Spannungsüberwachung

' ----- Sound -----
Piezosound = Sound_aus                                      ' Sound ausschalten

' ----- LCD-Display -----
Lcd_kontrastwert = Lcd_kontrast_default                     ' Kontrastwert
Lcd_helligkeit = Lcd_helligkeit_default                     ' Displayhelligkleit

' ----- Spielesteuerung -----
Game_hangman_status = 0                                     ' Statusvariable für gezeichneten HangingMan
Game_ablaufstatus = 0                                       ' Steuervariable für Spielablaufsteuerung

Game_bypassmode_leftcounter = 0                             ' Linkscounter initialisieren
Game_bypassmode_rightcounter = 0                            ' Rechtscounter initialisieren

' ----- ADC_ Batteriespannungsueberwachung -----
Adc_channel = 0                                             ' Spannungsteiler zur Batterispannungsmessung hängt an ADC0

' ----- DDS - Konfiguration -----

' Interne Pull-Ups für die Schalter aktivieren
A_signal = Pullup_ein
B_signal = Pullup_ein
Push_signal = Pullup_ein

' ----- Bypassmodus -----

' An dieser Stelle wird sofort der Status für den Bypassmodus abgefragt.
' Der Bypassmodus kann erreicht werden indem PTT direkt beim Einschalten betätigt wird
' Danach muss man 5x links drehen, 5x rechts drehen und erneut PTT betätigen

' Ggf Trace schreiben
#if Bypass_testmodus
   Print "Pin-Pegel = " ; Push_signal_pin
#endif

' Wurde bei Systemstart PTT als Triggersignal für den Einstieg in den Bypassmode erkannt?
If Push_signal_pin = True Then

   ' PTT nicht betätigt -> Bypassmodus nicht schalten
   Game_bypassmode_flag = False

   ' Ggf Trace schreiben
   #if Bypass_testmodus
      Print "Bypassmode False"
   #endif

Else                                                        ' Wurde Bypassmode getriggert?

   ' PTT betätigt -> Bypassmodus schalten
   Game_bypassmode_flag = True

   ' Ggf Trace schreiben
   #if Bypass_testmodus
      Print "Bypassmode True"
   #endif

End If                                                      ' Wurde Bypassmode getriggert?

' Arbeitsvariable vorinitialisieren
Dds_flag = Dds_none                                         ' ... steuert DDS-Drehung erkannt
Push_flag = False                                           ' ... steuert Push-Taster erkannt

'------------------------------------------------------------------------------
' Und los gehts, hier noch die Restarbeiten
'------------------------------------------------------------------------------

' ----- Freigabe aller Interrupts ----
Enable Interrupts                                           ' Damit auch Empfang von Daten über Buffer

' ---------------------------------- Gosub's ----------------------------------

Gosub Lcd_kontrast_set                                      ' LCD Kontrast einstellen

Gosub Lcd_helligkeit_set                                    ' Displayhelligkeit einstellen
Lcd_beleuchtung_status = Lcd_beleuchtung_status_ein         ' Hintergrundbeleuchtung ist EIN

Gosub Adc_check_batterie                                    ' Batteriespannung überprüfen

Gosub Ee_init                                               ' Persistente Daten aus EEPROM auslesen

' #############################################################################
'
'                             Hauptprogramm ConvCtrl
'
' #############################################################################

' In Abhängigkeit der Konstante Traceausgabe schreiben
#if Main_testmodus
   Print "** OK, let's GO **"
#endif

' Begrüßungstext 1 ausgeben
'                   1234567890123456
Locate 1 , 1 : Lcd " Willkommen zum"                        ' Text Zeile 1
Locate 2 , 1 : Lcd "Geocaching Spiel"                       ' Text Zeile 2

Gosub Sound_piep_400ms                                      ' 400 ms Piepton ausgeben

Wait 3                                                      ' Wartezeit bis nächste Anzeige
Cls                                                         ' Bildschirm löschen

'                   1234567890123456
Locate 1 , 1 : Lcd " Galgenm" ; Chr(132) ; "nnchen"         ' Text Zeile 1
Locate 2 , 1 : Lcd "     GC585BM    "                       ' Text Zeile 2

Gosub Sound_piep_400ms                                      ' 400 ms Piepton ausgeben

Wait 3                                                      ' Wartezeit bis nächste Anzeige

' Logik für Abschaltung Hintergrundbeleuchtung "aufziehen"
Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

' ----------------------------------------------
' ----- Hier ist die Programmhauptschleife -----
' ----------------------------------------------

' Erklärung Spielstati - Game_ablaufstatus:
' 0 = Lösche Bildschirm, zeichne Basisgalgen, erzeuge Zufallstext, lade Auswahltext,
'     lade Textinhalte in Arbeitsstring und zeige diese auf dem Display an
' 1 = Normales Spiels
' 2 = Verloren-Behandlung, Verlorentexte ausgeben, Spielstati zurücksetzen
' 3 = Jippi, gewonnen, Geokoordinate ausgeben
'
' Achtung: Status 1 ist normaler Status der im Wesentlichen den DDS auswertet
'          Hier läuft die Do-While-Schleife die meiste Zeit!!
'

Do                                                          ' Hauptschleife

   ' ------------------------------ Systemaufgaben ----------------------------

   ' Prüfen ob Sekundencounter für Hintergrundbeleuchtung abgelaufen ist
   If Lcd_abschaltcounter = Sectick_counter Then

      ' JA -> Hintergrundbeleuchtung abschalten und Strom sparen
      Gosub Lcd_beleuchtung_aus
      Lcd_beleuchtung_status = Lcd_beleuchtung_status_aus   ' Hintergrundbeleuchtung ist AUS

      ' Durch Verringerung des Counters wird verhindert dass Funktion mehrfach angesprungen wird.
      Decr Lcd_abschaltcounter

   End If                                                   ' LCD Abschaltzeitpunkt erreicht

   ' Prüfen ob der Bildschirm abgeschaltet ist und der DDS betätigt wurden
   If Lcd_beleuchtung_status = Lcd_beleuchtung_status_aus Then

      ' JA -> wurde Drehung erkannt?
      If Dds_flag > Dds_none Then

         'JA -> Beleuchtung einschalten und DDS ignorieren
         Gosub Lcd_beleuchtung_ein                          ' Hintergrundbeleuchtung einschalten
         Lcd_beleuchtung_status = Lcd_beleuchtung_status_ein       ' Hintergrundbeleuchtung ist EIN
         Dds_flag = Dds_none                                ' Flag korrigieren

        ' Logik für Abschaltung Hintergrundbeleuchtung erneut "aufziehen"
        Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

      End If                                                ' DDS betätigt

   End If                                                   ' Hintergrundbeleuchtung abgeschaltet

   ' --------------------------- Spielsteuerung -------------------------------

   ' ==== Spiel Vorbereitung ====

   ' Prüfen ob Spiel neu gestartet werden muss und Anzeige neu aufsetzt
   If Game_ablaufstatus = 0 Then
      ' JA -> Bildschirm löschen und Hanginman neu aufsetzen
      Cls
      Call Lcd_print_hangingman(game_hangman_status )       ' Maennchen gemaess Status zeichnen

      ' Zufallstext ermitteln
      Gosub Game_suchtext_select

      ' Auswahltext in Arbeitsvariable laden (gesamter Zeichenvorrat für Zeile 1)
      Game_auswahltext = Game_auswahltext_default

      ' Ratseltext zurücksetzen und Text auf Display anzeigen (Zeile 2)
      Game_raetseltext = Game_textmaske
      Gosub Lcd_print_raetseltext

      ' Scrollzeile für Buchstaben vorbereiten (Zeile 1)
      Game_buchstaben_index = Game_startposition_default
      Gosub Game_update_scrolltext
      Gosub Lcd_print_scrolltext

      ' Spielstatus weiterschalten
      Game_ablaufstatus = 1

   End If                                                   ' Spiel Vorbereitung

   ' ==== normales Spiel => Auswertung des DDS ====

   If Game_ablaufstatus = 1 Then

      ' ----- DDS auswerten -----
      Select Case Dds_flag

         Case Dds_links : Gosub Dds_links_verarbeiten
         Case Dds_rechts : Gosub Dds_rechts_verarbeiten

      End Select

   End If                                                   ' normales Spiel

   ' ==== Leider verloren ====

   If Game_ablaufstatus = 2 Then

      ' ----- Fehlerszenario -----

      Wait 1

      Gosub Sound_piep_1s
      Waitms 500
      Gosub Sound_piep_1s
      Waitms 500
      Gosub Sound_piep_1s
      Waitms 500

      '                   1234567890123456
      Locate 1 , 1 : Lcd "!!!  Schade  !!!"
      Locate 2 , 1 : Lcd "Leider  verloren"

      Wait 3

      '                   1234567890123456
      Locate 1 , 1 : Lcd "Probiere es doch"
      Locate 2 , 1 : Lcd "einfach nochmals"

      Wait 3

      Game_ablaufstatus = 0                                 ' Gameablaufsteuerung zurücksetzen
      Game_hangman_status = 0                               ' Hangmanstatus zurücksetzen

      ' Logik für Abschaltung Hintergrundbeleuchtung erneut "aufziehen"
      Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

   End If                                                   ' Leider verloren

   ' ==== Jippi gewonnen ====

   If Game_ablaufstatus = 3 Then

      Wait 1

      Gosub Sound_piep_1s
      Waitms 500
      Gosub Sound_piep_1s
      Waitms 500
      Gosub Sound_piep_1s
      Waitms 500

      '                   1234567890123456
      Locate 1 , 1 : Lcd "!! Herzlichen !!"
      '                  "   Glückwunsch
      Locate 2 , 1 : Lcd "!  Gl" ; Chr(129) ; "ckwunsch !"

      Wait 3

      '                   1234567890123456
      Locate 1 , 1 : Lcd "Du hast gewonnen"
      Locate 2 , 1 : Lcd "und findest den "

      Wait 3

      '                   1234567890123456
      Locate 1 , 1 : Lcd "Cache bei fol-  "
      Locate 2 , 1 : Lcd "genden Koords.. "

      Temp_byte_1 = True                                    ' Arbeitsvaraible für Schleifenabbruchkriterium Hinweistexte

      Wait 3

      ' Ab hier auch Interrupt 1 für Taster zulassen.
      ' Interrupt wird wieder in der ISR disabled
      Push_flag = False                                     ' Flag für Taster zurücksetzen
      Gifr.intf1 = 1                                        ' Anstehender Interrupt löschen
      Enable Int1                                           ' Interrupts freigeben

      Do

         '                   1234567890123456
         Locate 1 , 1 : Lcd "N48" ; Chr(223) ; " 31.235     "
         Locate 2 , 1 : Lcd "E009" ; Chr(223) ; " 54.899    "

         Wait 3

         '                   1234567890123456
         Locate 1 , 1 : Lcd "Rohr unter Stein"
         Locate 2 , 1 : Lcd "und Weg von oben"
         Wait 3

         ' Prüfe ob Schleife für Hinweistext verlassen werden kann
         If Dds_flag <> Dds_none Or Push_flag = True Then

            ' JA, alle Flags zurücksetzen

            Dds_flag = Dds_none
            Push_flag = False
            Temp_byte_1 = False

         End If                                             ' Abbruchbedingung für Hinweistext

      Loop Until Temp_byte_1 = False

      ' Spielstatus weiterschalten, Hagmanstatus zurückschalten und nochmals kurz Piepsen
      Game_hangman_status = 0
      Game_ablaufstatus = 4
      Gosub Sound_piep_400ms                                ' 400 ms Piepton ausgeben

      ' Logik für Abschaltung Hintergrundbeleuchtung erneut "aufziehen"
      Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

   End If                                                   ' gewonnen

   ' ==== OK, Du magst nochmals spielen ====

   If Game_ablaufstatus = 4 Then

      '                   1234567890123456
      Locate 1 , 1 : Lcd "Ok Du magst also"
      Locate 2 , 1 : Lcd "nochmal spielen!"

      Gosub Sound_piep_400ms

      Waitms 2600

      '                   1234567890123456
      Locate 1 , 1 : Lcd "Na dann los und "
      Locate 2 , 1 : Lcd "viel Gl" ; Chr(129) ; "ck!!!!!!"

      Wait 3

      ' Spielstatus zurückschalten
      Game_ablaufstatus = 0

      ' Logik für Abschaltung Hintergrundbeleuchtung erneut "aufziehen"
      Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

   End If                                                   ' OK nochmals

   ' PTT-Taste des DDS auswerten
   Debounce Push_signal_pin , 0 , Dds_taste_erkannt , Sub

Loop                                                        ' Hauptschleife

'## End Hauptprogramm #########################################################

End

'******************************************************************************
' Interruptroutinen
'******************************************************************************

'------------------------------------------------------------------------------
' Interrupt-Service-Routine (Timer1): Sekunden_tick
'
' Routine zur Auswertung des Timer Interrupts
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Sectick_counter = Variable für den Sekundencounter
'------------------------------------------------------------------------------
Sekunden_tick:

   ' ----- Programmcode -----

   Timer1 = Timervorgabe                                    ' Timer neu laden
   Toggle Alive                                             ' Alive-LED toggeln lassen

   ' Timervariable erhöhen
   Incr Sectick_counter

Return
'-- End Sekunden_tick  --------------------------------------------------------

'------------------------------------------------------------------------------
' Interrupt-Service-Routine (External Interrupt 0): Dds_interrupt
'
' Routine zur Auswertung des INT0 Interrupts für DDS-Bewegung
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Dds_flag = Variable für den Zustand (Drehrichtung) des DDS
'------------------------------------------------------------------------------
Dds_interrupt:

   ' ----- Programmcode -----

   ' Erkennung der Drehrichtung
   If A_signal_pin = B_signal_pin Then

      ' Links herum
      Dds_flag = Dds_links

   Else                                                     ' Erkennung der Drehrichtung

      ' Rechts herum
      Dds_flag = Dds_rechts

   End If                                                   ' Erkennung der Drehrichtung

Return
'-- End Dds_interrupt ---------------------------------------------------------

'------------------------------------------------------------------------------
' Interrupt-Service-Routine (External Interrupt 1): Push_interrupt
' Routine zur Auswertung des INT0 Interrupts für DDS-Bewegung
'------------------------------------------------------------------------------
Push_interrupt:

   ' ----- Programmcode -----

   Push_flag = True
   Disable Int1

Return
'-- End Push_interrupt ---------------------------------------------------------

'******************************************************************************
' Subroutinen
'******************************************************************************

' ***************
' * LCD-Display *
' ***************

'------------------------------------------------------------------------------
' LCD - Subroutine: Lcd_print_hangingman
'
' Subroutine schreibt je nach uebergebenem Status den Zustand des Hanging Man
' auf das Display
'    Status 0: Galgen ohne Maennchen
'    Status 1: Galgen mit Kopf
'    Status 2: Galgen mit Kopf und Rumpf
'    Status 3: Galgen mit Kopf, Rumpf und linken Bein
'    Status 4: Galgen mit Kopf, Rumpf, linken und rechten Bein
'    Status 5: Galgen mit kompletten Körper
'
' Parameter:    Value = Step n des Hanging-Man
' Rückgabewert: keine
'
' Globale Variable:
' --
'------------------------------------------------------------------------------
Sub Lcd_print_hangingman(byval Value As Byte)

   ' ----- Programmcode -----

   ' Galgen zeichnen
   Locate 1 , 1 : Lcd Chr(1)
   Locate 2 , 1 : Lcd Chr(0)

   Select Case Value
      Case 0 :
         Locate 1 , 2 : Lcd Chr(2)
      Case 1 :
         Locate 1 , 2 : Lcd Chr(3)
      Case 2 :
         Locate 1 , 2 : Lcd Chr(3)
         Locate 2 , 2 : Lcd Chr(4)
      Case 3 :
         Locate 1 , 2 : Lcd Chr(3)
         Locate 2 , 2 : Lcd Chr(5)
      Case 4 :
         Locate 1 , 2 : Lcd Chr(3)
         Locate 2 , 2 : Lcd Chr(6)
      Case 5 :
         Locate 1 , 2 : Lcd Chr(3)
         Locate 2 , 2 : Lcd Chr(7)
   End Select                                               ' Case Value

End Sub
'-- End Lcd_Print_hanginman ---------------------------------------------------

'******************************************************************************
' GOSubroutinen
'******************************************************************************

' ***************
' * LCD-Dsiplay *
' ***************

'------------------------------------------------------------------------------
' LCD - Gosub-Routine: Lcd_contrast_set
'
' Routine berechnen neue Kontrastwerte und steuert direkt den
' Kontroller des Display an.
' Aufgrund von 6 Bit sind nur Kontrastwerte zwischen 0 und 63 möglich!
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Lcd_kontrastwert = Kontrastwert für Display
'------------------------------------------------------------------------------
Lcd_kontrast_set:                                           ' Kontrasteinstellung Display

   ' ----- Programmcode -----

   ' Verarbeitung des Kontrastwertes für High-Byte und Low-Byte
   Temp_byte_1 = Lcd_kontrastwert And &B00001111
   Temp_byte_1 = Temp_byte_1 + &B01110000

   Temp_byte_2 = Lcd_kontrastwert
   Shift Temp_byte_2 , Right , 4
   Temp_byte_2 = Temp_byte_2 And &B00000011
   Temp_byte_2 = Temp_byte_2 + &B01010100

   ' Instruction Table 1 einstellen [0,1]
   _temp1 = &B00101001
   !rCall _Lcd_control

   ' Tempvar_1 = &B0111xxxx für Kontrast Set Instruction Table 1 - Low Byte
   _temp1 = Temp_byte_1
   !rCall _Lcd_control

   ' Temovar_2 = &B010101xx für Kontrast Set Instruction Table 1 - High Byte
   _temp1 = Temp_byte_2
   !rCall _Lcd_control

   ' Zurückschalten auf Instruction Table 0 [0,0]
   _temp1 = &B00101000
   !rCall _Lcd_control

Return
'-- End Lcd_kontrast_set ------------------------------------------------------

'------------------------------------------------------------------------------
' LCD - Gosub-Routine: Lcd_helligkeit_set
'
' Routine setzt den Helligkeitswert aus der globalen Variable Lcd_helligkeit in
' das Controllregister
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Lcd_helligkeit = Helligkeitswert für PWM
'------------------------------------------------------------------------------
Lcd_helligkeit_set:

   ' ----- Programmcode -----

   ' Variable in Timer-Count-Register laden
   Ocr2 = Lcd_helligkeit

Return
'-- End Ir_set_helligkeit -----------------------------------------------------

'------------------------------------------------------------------------------
' LCD - Gosub-Routine: Lcd_beleuchtung_aus
'
' Routine schaltet die LCD-Hintergrundbeleuchtung aus
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' --
'------------------------------------------------------------------------------
Lcd_beleuchtung_aus:

   ' ----- Programmcode -----

   Lcd_helligkeit = Lcd_helligkeit_aus
   Gosub Lcd_helligkeit_set

   #if Lcd_testmodus
      Print "Beleuchtung aus"
   #endif

Return
'-- End Lcd_beleuchtung_aus ---------------------------------------------------

'------------------------------------------------------------------------------
' LCD - Gosub-Routine: Lcd_beleuchtung_ein
'
' Routine schaltet die LCD-Hintergrundbeleuchtung ein
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' --
'------------------------------------------------------------------------------
Lcd_beleuchtung_ein:

   ' ----- Programmcode -----

   Lcd_helligkeit = Lcd_helligkeit_default
   Gosub Lcd_helligkeit_set

   #if Lcd_testmodus
      Print "Beleuchtung ein"
   #endif

   ' Kurzes Piep ausgeben
   Gosub Sound_piep_100ms

Return
'-- End Lcd_beleuchtung_ein ---------------------------------------------------

'------------------------------------------------------------------------------
' LCD - Gosub-Routine: Lcd_print_raetseltext
'
' Routine gibt den bereits enträtselten Text in Zeile 2 mit 13 Zeichen aus
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Game_raetseltext = Textstring für Raetseltext
'------------------------------------------------------------------------------
Lcd_print_raetseltext:

   ' ----- Programmcode -----

   ' 1234567890123456
   '    xxxxxxxxxxxxx
   Locate 2 , 4 : Lcd Game_raetseltext

Return
'-- End Lcd_print_raetseltext -------------------------------------------------

'------------------------------------------------------------------------------
' LCD - Gosub-Routine: Lcd_print_scrolltext
'
' Routine gibt den Scroll-Text der Buchstaben in Zeile 1 mit 13 Zeichen aus
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Game_scrolltext  = Textstring gescrollte Buchstaben
'------------------------------------------------------------------------------
Lcd_print_scrolltext:

   ' ----- Programmcode -----

   ' 1234567890123456
   '    xxxxxxxxxxxxx
   Locate 1 , 4 : Lcd Game_scrolltext

Return
'-- End Lcd_print_raetseltext -------------------------------------------------

' **********************
' * ADC-Batteriestatus *
' **********************

'------------------------------------------------------------------------------
' ADC - Gosub-Routine: Adc_check_batterie
'
' Routine liest den Spannungswert aus dem AD-Wandler, prüft gegen eine
' voreingestellte Grenze und schaltet ggf. die Power-LED als Warnsignal ein.
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Temp_word_1     = temporäre WORD Arbeitsvariable
' adc_channel     = Variable beinhaltet Kanalnummer des ADC
' Ubatt_grenzwert = Konstante für Grenzwert
'------------------------------------------------------------------------------
Adc_check_batterie:

   ' ----- Programmcode -----

   ' ADC-Wert lesen
   Temp_word_1 = Getadc(adc_channel)

   ' Prüfen auf Unterspannung
   If Temp_word_1 < Ubatt_grenzwert Then

      ' Wenn Unterspannung erkannt dann LED dauerhaft einschalten
      Pwrled = Led_ein

   End If                                                   ' Unterspannung?

   ' Zufallszahlengenerator "verdrehen" :-) Erklärung siehe ganz oben in der Einleitung!!
   ___rseed = Temp_word_1

Return
'-- End Adc_check_batterie ----------------------------------------------------

' ***********************
' DDS: Drückdrehsteller *
' ***********************

'------------------------------------------------------------------------------
' DDS - Gosub-Routine: Dds_links_verarbeiten
'
' Routine verarbeitet das Drehen des DDS nach links
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Viele ... (zu viele um hier einzeln beschrieben zu erden!)
'------------------------------------------------------------------------------
Dds_links_verarbeiten:

   ' ----- Programmcode -----

   ' Bearbeitungsflag zurücksetzen
   Dds_flag = Dds_none

   ' Buchstabenzeiger verringern und Grenzwerte überprüfen
   Decr Game_buchstaben_index
   If Game_buchstaben_index = 0 Then

      Game_buchstaben_index = 26

   End If                                                   ' Grenzwert erreicht

   ' Scrollbaren Buchstabenasuwahltext auf LCD-Display aktualisieren
   Gosub Game_update_scrolltext
   Gosub Lcd_print_scrolltext

   ' Logik für Abschaltung Hintergrundbeleuchtung erneut "aufziehen"
   Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

   ' Ggf. Debugausgaben schreiben
   #if Dds_testmodus
      Print "DDS links - Index = " ; Game_buchstaben_index
   #endif

   ' Prüfung ob bypass aktiv, wenn ja verarbeiten
   If Game_bypassmode_flag = True Then

      ' JA, Bypassmode aktiv
      Incr Game_bypassmode_leftcounter

      ' Prüfen ob Linkscounter zu hoch, wenn ja Bypassmodus deaktivieren
      If Game_bypassmode_leftcounter > Game_leftcount_max Then

         ' Ja, Bypassmodus verlassen
         Game_bypassmode_leftcounter = 0
         Game_bypassmode_flag = False

         ' ggf. Trace ausgeben
         #if Bypass_testmodus
            Print "Bypass zuruecksetzen"
         #endif

      End If                                                ' Prüfung Linkscounter

      ' ggf. Trace ausgeben
      #if Bypass_testmodus
         Print "Linkscounter = " ; Game_bypassmode_leftcounter
      #endif

   End If                                                   ' Behandlung Bypassmode

Return
'-- End Dds_links_verarbeiten -------------------------------------------------

'------------------------------------------------------------------------------
' DDS - Gosub-Routine: Dds_Dds_rechts_verarbeiten
'
' Routine verarbeitet das Drehen des DDS nach links
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Viele ... (zu viele um hier einzeln beschrieben zu erden!)
'------------------------------------------------------------------------------
Dds_rechts_verarbeiten:

   ' ----- Programmcode -----

   ' Bearbeitungsflag zurücksetzen
   Dds_flag = Dds_none

   ' Buchstabenzeiger erhöhen und Grenzwerte überprüfen
   Incr Game_buchstaben_index
   If Game_buchstaben_index = 27 Then

      Game_buchstaben_index = 1

   End If                                                   ' Grenzwert erreicht?

   ' Scrollbaren Buchstabenasuwahltext auf LCD-Display aktualisieren
   Gosub Game_update_scrolltext
   Gosub Lcd_print_scrolltext

   ' Logik für Abschaltung Hintergrundbeleuchtung erneut "aufziehen"
   Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

   ' Ggf. Debugausgaben schreiben
   #if Dds_testmodus
      Print "DDS rechts - Index = " ; Game_buchstaben_index
   #endif

   ' Prüfung ob bypass aktiv UND Linkscounter auf Max-Value, wenn ja verarbeiten
   If Game_bypassmode_flag = True And Game_bypassmode_leftcounter = Game_leftcount_max Then

      ' JA, Bypassmode aktiv
      Incr Game_bypassmode_rightcounter

      ' Prüfen ob Rightcounter zu hoch, wenn ja Bypassmodus deaktivieren
      If Game_bypassmode_rightcounter > Game_rightcount_max Then

         ' Ja, Bypassmodus verlassen
         Game_bypassmode_rightcounter = 0
         Game_bypassmode_flag = False

         ' ggf. Trace ausgeben
         #if Bypass_testmodus
            Print "Bypass zuruecksetzen"
         #endif

      End If                                                ' Prüfung Linkscounter

      ' ggf. Trace ausgeben
      #if Bypass_testmodus
         Print "Rechtscounter = " ; Game_bypassmode_rightcounter
      #endif

   Else                                                     ' Behandlung Bypassmode

      ' Bypassmodus verlassen
      Game_bypassmode_rightcounter = 0
      Game_bypassmode_flag = False

      ' ggf. Trace ausgeben
      #if Bypass_testmodus
         Print "Bypass zuruecksetzen"
      #endif

   End If                                                   ' Behandlung Bypassmode

Return
'-- End Dds_rechts_verarbeiten ------------------------------------------------

'------------------------------------------------------------------------------
' DDS - Gosub-Routine: Dds_Taste_erkannt
'
' Routine gibt nur Traceausgabe aus, dass Taste erkannt wurde
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Viele ... (zu viele um hier einzeln beschrieben zu erden!)
'------------------------------------------------------------------------------
Dds_taste_erkannt:

   ' ----- Programmcode -----

   ' Ggf. Debugausgaben schreiben
   #if Dds_testmodus
      Print "DDS gedueckt"
   #endif

   ' Prüfen ob der Bildschirm abgeschaltet ist und der DDS betätigt wurden
   If Lcd_beleuchtung_status = Lcd_beleuchtung_status_aus Then

      'JA -> Beleuchtung einschalten und DDS ignorieren
      Gosub Lcd_beleuchtung_ein                          ' Hintergrundbeleuchtung einschalten
      Lcd_beleuchtung_status = Lcd_beleuchtung_status_ein       ' Hintergrundbeleuchtung ist EIN

   Else                                                     ' Bildschirm abgeschaltet?

      ' Prüfen ob Bypassmodus aktiv und Triggerbedingungen erfüllt
      If Game_bypassmode_flag = True Then

         ' Prüfen ob Bypassbedingungen erfüllt sind
         If Game_bypassmode_leftcounter = Game_leftcount_max And Game_bypassmode_rightcounter = Game_rightcount_max Then

            ' JA, Bedingungen erfüllt, nun können Koordinaten auch ohne Spiel angezeigt werden

            ' ggf. Trace ausgeben
            #if Bypass_testmodus
               Print "Bypass ausloesen, Koordinaten anzeigen"
            #endif

            ' Gamestatus setzen und fertig
            Game_ablaufstatus = 3

            ' Counter für Bypassmode erhöhen und in EEPROM speichern
            Incr Ee_bypass_counter
            Ee_data_bypass_counter = Ee_bypass_counter

            ' Aktuelle Counter Value auf Display ausgeben
            '                   1234567890123456
            Cls
            Locate 1 , 1 : Lcd "Bypasscounter:"
            Locate 2 , 1 : Lcd Ee_bypass_counter

         End If                                             ' Bypassbedingungen erfüllt?

         ' In jedem Fall Counter und Flags wieder zurücksetzen
         Game_bypassmode_flag = False
         Game_bypassmode_leftcounter = 0
         Game_bypassmode_rightcounter = 0

         ' ggf. Trace ausgeben
         #if Bypass_testmodus
            Print "Bypassflags und Counter zuruecksetzen"
         #endif

      Else                                                  ' Bypassmode?

         ' NEIN -> Normale PTT Verarbeitung und Auswertung der Eingabe

         ' Ggf. Trace schreiben
         #if Game_testmodus
            Print "Auswertung PTT"
         #endif

         ' Prüfen ob Zeichen schon ausgewählt wurde und Buchstabe mit Unterstrich ausge-x-t
         ' If Game_scrolltext_zeichen(7) <> Game_fuellzeichen Then
         If Game_scrolltext_zeichen(7) <> Game_cursorzeichen Then

            ' JA -> Zeichen ist gültig

            #if Game_testmodus
               Print "Zeichen ist gueltig : " ; Chr(game_scrolltext_zeichen(7) )
               Print "Game_suchtext   : " ; Game_suchtext
               Print "Game_scrolltext : " ; Game_scrolltext
            #endif

            ' Nun im Rätseltext nach dem Buchstaben suchen und ggf. Buchstaben in Suchtext eintragen

            Temp_byte_2 = False

            For Temp_byte_1 = 1 To 13 Step 1

               If Game_suchtext_zeichen(temp_byte_1) = Game_scrolltext_zeichen(7) Then

                  ' Zeichen gefunden
                  Temp_byte_2 = True
                  Game_raetseltext_zeichen(temp_byte_1 ) = Game_scrolltext_zeichen(7)

               End If                                       ' Suchtextzeichen = Scrolltextzeichen?

            Next                                            ' Schleife über alle Zeichen

            ' Nun prüfen ob passende Zeichen gefunden wurden

            If Temp_byte_2 = True Then

               ' JA

               Gosub Lcd_print_raetseltext

               ' Kurzes Piep ausgeben
               Gosub Sound_piep_100ms
               Waitms 100
               Gosub Sound_piep_100ms

            Else                                               ' Zeichen gefunden

               ' nein

               Incr Game_hangman_status
               #if Game_testmodus
                  Print "Fehler Hangman status : " ; Game_hangman_status
               #endif

               Call Lcd_print_hangingman(game_hangman_status ) ' Maennchen gemaess Status zeichnen

               ' Prüfen ob Spiel schon zuende

               If Game_hangman_status = 5 Then

                  ' Spielstatus weiterschalten
                  Game_ablaufstatus = 2

                  ' Rätseltext übernehmen und anzeigen da Spiel eh zuende
                  Game_raetseltext = Game_suchtext
                  Gosub Lcd_print_raetseltext

               End If                                          ' Spiel zuende

               ' Piepston ausgeben und warten
               Gosub Sound_piep_1s
               ' Wait 1

            End If                                             ' Fehler gemacht

            ' Gesamten Auswahltext nach dem ausgewählten Zeichen durchsuchen und mit Füllzeichen besetzen
            ' ==> Zeichen kann nicht mehr ausgewählt werden.

            ' Gesuchtes Zeichen ist kleingeschrieben, daher muss scrolltext_zeichen angepasst werden
            Temp_byte_2 = Game_scrolltext_zeichen(7) + 32

            ' Ggf. Debugausgaben schreiben
            #if Dds_testmodus
               Print "Rücksetzzeichen = " ; Chr(temp_byte_2)
            #endif

            For Temp_byte_1 = 1 To 38 Step 1

               If Game_auswahltext_zeichen(temp_byte_1 ) = Temp_byte_2 Then

                  ' Zeichen gefunden
                  Game_auswahltext_zeichen(temp_byte_1 ) = Game_fuellzeichen

                  ' Ggf. Debugausgaben schreiben
                  #if Dds_testmodus
                     Print "Zeichen gefunden"
                  #endif

               End If                                       ' Textposition entspricht Füllzeichen

            Next                                            ' Schleife über alle Zeichen

            ' Scrolltext updaten !!! nicht vergessen
            Gosub Game_update_scrolltext
            Gosub Lcd_print_scrolltext

            #if Game_testmodus
               Print "Game_raetseltext : " ; Game_raetseltext
            #endif

            ' Nun prüfen ob bisheriger Text dem gesuchen Wort entspricht

            If Game_raetseltext = Game_suchtext And Game_hangman_status < 5 Then

               ' JA

               #if Game_testmodus
                  Print "Jippi gewonnen"
               #endif

               ' Spielstatus weiterschalten
               Game_ablaufstatus = 3

            End If                                          ' Rätseltext=Suchtext & Status<5

         End If                                             ' Ungültiges Zeichen

      End If                                                ' Bypassmode?

      ' Logik für Abschaltung Hintergrundbeleuchtung erneut "aufziehen"
      Lcd_abschaltcounter = Sectick_counter + Lcd_abschaltzeit

   End If                                                   ' Bypassmode=True & leftcounter=leftcount_max

   Return
'-- End Dds_Taste_erkannt -----------------------------------------------------

' ********
' * GAME *
' ********

'------------------------------------------------------------------------------
' GAME - Gosub-Routine: Game_suchtext_select
'
' Routine ermittelt via Zufallszahl den im Spiel zu suchenden Text aus dem
' DATA Bereich.
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Game_suchtext = Arbeitsvariable in dem Suchtext zur Verfügung gestellt wird.
'------------------------------------------------------------------------------
Game_suchtext_select:

   ' ----- Programmcode -----

   ' Zufallszahl ermitteln
   Temp_byte_1 = Rnd(game_anzahl_text )                     ' Random bei z.B. 40 = 0-39

   ' Suchtext auslesen
   Game_suchtext = Lookupstr(temp_byte_1 , Worte_data)

   ' Falls Flag für Debuging gesetzt debugausgaben ausgeben
   #if Game_testmodus
      Print "Index : " ; Temp_byte_1
      Print "Text  : " ; Game_suchtext
   #endif

Return
'-- End Game_suchtext_select --------------------------------------------------

'------------------------------------------------------------------------------
' GAME - Gosub-Routine: Game_update_scrolltext
'
' Routine überträgt aus dem Gesamtstring game_auswahltext den für die Ausgabe
' auf dem Display relevanten Teil in die globale Variable game_scrolltext.
' Dabei der der mittlerste Buchstabe welche ausgewählt werden kann ggf.
' als Großbuchstabe dargestellt.
' Wurde der Buchstabe bereits ausgewählt und ist er als Leerzeichen gekenn-
' zeichnet wird der Buchstabe ignoriert.
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' Game_scrolltext       = Teilstring für die Ausgabe auf dem Display
' Game_auswahltext      = Gesamtstring auf dem gearbeitet wird
' Game_buchstaben_index = Index auf aktuelle A-Z Buchstabenposition
'------------------------------------------------------------------------------
Game_update_scrolltext:

   ' ----- Programmcode -----

   '          1         2         3
   ' 12345678901234567890123456789012345678
   ' uvwxyzabcdefghijklmnopqrstuvwxyzabcdef
   '       abcdefghijklmnopqrstuvwxyz
   '       12345678901234567890123456
   '                1         2
   ' Zeile 1 ist Scrolltext
   ' Zeile 2 ist Raetseltext

   Game_scrolltext = Mid(game_auswahltext , Game_buchstaben_index , 13 )

   ' Überprüfen ob Zeichen ein NULL-gesetztes Zeichen ist, also dass der Buchstabe
   ' schon mal ausgewählt wurde. Wenn NEIN Buchstaben GROSS setzen
   If Game_scrolltext_zeichen(7) <> Game_fuellzeichen Then

      ' NEIN -> Buchstaben GROSS schreiben
      Game_scrolltext_zeichen(7) = Game_scrolltext_zeichen(7) - 32

   Else                                                     ' Null gesetztes Zeichen ?

      ' JA -> An nicht mehr gültiger Cursorstelle ein Cursorzeichen ausgeben
      Game_scrolltext_zeichen(7) = Game_cursorzeichen

   End If                                                   ' Null gesetztes Zeichen ?

Return
'-- End Game_update_scrolltext ------------------------------------------------

' *********
' * SOUND *
' *********

'------------------------------------------------------------------------------
' SOUND - Gosub-Routine: Sound_piep_100ms
'
' Routine piepst für 100 ms
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' --
'------------------------------------------------------------------------------
Sound_piep_100ms:

   ' ----- Programmcode -----

   Piezosound = Sound_ein
   Waitms 100
   Piezosound = Sound_aus

Return
'-- End Sound_piep_100ms ------------------------------------------------------

'------------------------------------------------------------------------------
' SOUND - Gosub-Routine: Sound_piep_400ms
'
' Routine piepst für 400 ms
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' --
'------------------------------------------------------------------------------
Sound_piep_400ms:

   ' ----- Programmcode -----

   Piezosound = Sound_ein
   Waitms 400
   Piezosound = Sound_aus

Return
'-- End Sound_piep_400ms ------------------------------------------------------

'------------------------------------------------------------------------------
' SOUND - Gosub-Routine: Sound_piep_1s
'
' Routine piepst für 1s
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
' --
'------------------------------------------------------------------------------
Sound_piep_1s:

   ' ----- Programmcode -----

   Piezosound = Sound_ein
   Wait 1
   Piezosound = Sound_aus

Return
'-- End Sound_piep_1s ---------------------------------------------------------

' **********
' * EEPROM *
' **********

'------------------------------------------------------------------------------
' EEPROM - Gosub-Routine: EE_init
'
' Routine prüft ob EEPROM schon initialisiert ist / war, holt ggf. dieses nach
' und liest aktuellen Bytepasscounter aus.
'
' Parameter: keine
' Rückgabe:  keine
'
' Globale Variablen:
'    Ee_bypass_counter      = Arbeitsvariable für Bypasscounter
'    Ee_data_bypass_counter = Flash-variable für Bypasscounter
'    Ee_data_version_value  = Flash-Variable für Version
'    Ee_version_value       = Arbeitsvariable für Version
'------------------------------------------------------------------------------
Ee_init:

   ' ----- Programmcode -----

   ' Anmerkung:
   ' Es wird davon ausgegangen dass nicht initialisierte / neue EEPROMS
   ' bzw. gelöschte EEPROMS den Wert 0xFF enthalten.

   ' Version aus Speicher auslesen
   Ee_version_value = Ee_data_version_value

   ' Prüfen ob Eeprom schon initialisiert ist, wenn NEIN tue dies
   If Ee_version_value <> Ee_default_version_value Then

      ' NEIN, noch nicht initialisiert

      ' Arbeitsvariablen vorbelegen
      Ee_version_value = Ee_default_version_value
      Ee_bypass_counter = 0

      ' Arbeitsvariablen in EEPROM schreiben
      Ee_data_bypass_counter = Ee_bypass_counter
      Ee_data_version_value = Ee_version_value

      ' Ggf. Trace ausgeben
      #if Eeprom_testmodus
         Print "EEPROM und Arbeitsvariablen wurden neu initialisiert"
      #endif

   Else                                                     ' Eeprom schon Initialisiert

      ' JA, Speicher ist initialisiert

      ' Counter in Arbeitsvariable auslesen
      Ee_bypass_counter = Ee_data_bypass_counter

      ' Ggf. Trace ausgeben
      #if Eeprom_testmodus
         Print "EEPROM ist gueltig. Bypasscounter = " ; Ee_bypass_counter
      #endif

   End If                                                   ' Eeprom schon Initialisiert

Return
'-- End Ee_init ---------------------------------------------------------------

'------------------------------------------------------------------------------
' Devices schließend und ggf. "Terminate Programm execution"
'------------------------------------------------------------------------------

' System halt
End                                                         'end program

'------------------------------------------------------------------------------
' Definition von globalen Konstantenfeldern
'------------------------------------------------------------------------------

Worte_data:
Data "WELTRAUMFAHRT"                                        ' 1
Data "ABENTEUERLICH"                                        ' 2
Data "ABENTEUERLUST"                                        ' 3
Data "ANLAGEOBJEKTE"                                        ' 4
Data "ASTROGEOLOGIE"                                        ' 5
Data "ASTROBIOLOGIE"                                        ' 6
Data "BERGKRISTALLE"                                        ' 7
Data "BERGSTATIONEN"                                        ' 8
Data "BERGSTEIGEREI"                                        ' 9
Data "BERGWANDERUNG"                                        ' 10
Data "MYSTERYCACHES"                                        ' 11
Data "HAUSAPOTHEKEN"                                        ' 12
Data "HAUSVERWALTER"                                        ' 13
Data "HAUSHALTSWARE"                                        ' 14
Data "FESTSPIELHAUS"                                        ' 15
Data "FALSCHAUSSAGE"                                        ' 16
Data "WOCHENENDHAUS"                                        ' 17
Data "HAUSBESETZUNG"                                        ' 18
Data "WACKELKONTAKT"                                        ' 19
Data "WACHTELSCHLAG"                                        ' 20
Data "FAHRRADFAHREN"                                        ' 21
Data "DURCHGELAUFEN"                                        ' 22
Data "ASPHALTCOWBOY"                                        ' 23
Data "ARBEITSZIMMER"                                        ' 24
Data "FEUERWEHRAUTO"                                        ' 25
Data "ABSCHIEDSKUSS"                                        ' 26
Data "BUNDESKANZLER"                                        ' 27
Data "ZWIEBELSCHALE"                                        ' 28
Data "BANKGEHEIMNIS"                                        ' 29
Data "ANSICHTSKARTE"                                        ' 30
Data "ASTROPHYSIKER"                                        ' 31
Data "FEUERWEHRMANN"                                        ' 32
Data "KALENDERMONAT"                                        ' 33
Data "HAFENARBEITER"                                        ' 34
Data "COMPUTERFIRMA"                                        ' 35
Data "KNOBLAUCHZEHE"                                        ' 36
Data "LEUCHTREKLAME"                                        ' 37
Data "MINUTENZEIGER"                                        ' 38
Data "VERSTECKSPIEL"                                        ' 39
Data "AMEISENHAUFEN"                                        ' 40
Data "KAPITALANLAGE"                                        ' 41
Data "GANGSCHALTUNG"                                        ' 42
Data "MUTTERSPRACHE"                                        ' 43
Data "BERUFSBERATER"                                        ' 44
Data "NEBELSCHWADEN"                                        ' 45
Data "OBERINSPEKTOR"                                        ' 46
Data "WASCHMASCHINE"                                        ' 47
Data "BLUMENSCHMUCK"                                        ' 48
Data "ORIENTTEPPICH"                                        ' 49
Data "DAMPFMASCHINE"                                        ' 50
Data "PERSONENWAGEN"                                        ' 51
Data "POLIZEISCHUTZ"                                        ' 52
Data "FAMILIENNAMEN"                                        ' 53
Data "RASIERAPPARAT"                                        ' 54
Data "SATTELTASCHEN"                                        ' 55
Data "ZAPPELPHILIPP"                                        ' 56
Data "TASCHENMESSER"                                        ' 57
Data "IDEENREICHTUM"                                        ' 58
Data "TODESKANDIDAT"                                        ' 59
Data "KANONENFUTTER"                                        ' 60
Data "GEISTERSTUNDE"                                        ' 61
Data "UMSTANDSKLEID"                                        ' 62
Data "INNENMINISTER"                                        ' 63
Data "RAUMFORSCHUNG"                                        ' 64
Data "UNTEROFFIZIER"                                        ' 65
Data "COMPUTERSPIEL"                                        ' 66
Data "VANILLESCHOTE"                                        ' 67
Data "POLTERGEISTER"                                        ' 68
Data "VERSUCHSREIHE"                                        ' 69
Data "ELEKTROMAGNET"                                        ' 70
Data "WALNUSSKUCHEN"                                        ' 71
Data "SCHATTENBOXEN"                                        ' 72
Data "HAUPTSCHALTER"                                        ' 73
Data "ZIMMERANTENNE"                                        ' 74
Data "WASSERLEITUNG"                                        ' 75
Data "ERDUMLAUFBAHN"                                        ' 76
Data "ZUGVERBINDUNG"                                        ' 77
Data "EINTRITTSGELD"                                        ' 78
Data "WARTESCHLANGE"                                        ' 79
Data "ZUCKERMELONEN"                                        ' 80
Data "ENERGIEQUELLE"                                        ' 81
Data "WASSERSPIEGEL"                                        ' 82
Data "VERKEHRSCHAOS"                                        ' 83
Data "ENERGIEBEDARF"                                        ' 84
Data "SCHMERZMITTEL"                                        ' 85
Data "VERBOTSSCHILD"                                        ' 86
Data "NIEDRIGWASSER"                                        ' 87
Data "FAHRRADREIFEN"                                        ' 88
Data "TROMMELBREMSE"                                        ' 89
Data "SCHAUKELSTUHL"                                        ' 90
Data "INFRASTRUKTUR"                                        ' 91
Data "RECHENAUFGABE"                                        ' 92
Data "POLIZEIWACHEN"                                        ' 93
Data "ZAHLENSCHLOSS"                                        ' 94
Data "MODEINDUSTRIE"                                        ' 95
Data "LICHTSCHALTER"                                        ' 96
Data "BRIEFUMSCHLAG"                                        ' 97
Data "KLASSENZIMMER"                                        ' 98
Data "HAUTAUSSCHLAG"                                        ' 99
Data "INSEKTENPLAGE"                                        ' 100

' ----------------------------------------------------------------------------

'###################################### END ###################################

'################################### Historie #################################
'
' 30.05.2014 : Version x.x
'              Beginn der Implementierungen für Hanging Man.
'              Fertigstellung Inbetriebnahme LCD-Display und wichtigster
'              Funktionen.
' -----------------------------------------------------------------------------
' 09.06.2014 : B_SIGNAL und PUSH_SIGNAL wegen Erfassung über Interrupt 1
'              getauscht.
' -----------------------------------------------------------------------------
' 02.07.2014 : Restarbeiten und Begriffe auf 100 Stück ergänzt.
' -----------------------------------------------------------------------------
' 04.07.2014 : Spiel-Bypass eingebaut um Koordinaten ohne Spiel anzeigen
'              zu können :-)
' -----------------------------------------------------------------------------
' 09.07.2014 : Bypasscounter implementiert und Ablage Counter in EEPROM
' -----------------------------------------------------------------------------
' 09.07.2014 : Versions 1.0 - Fertigstellung erste Produktivversion
'
'##############################################################################