
\ Ledcomm-Stellaris
\   Connect LED with Anode (over optional 100 Ohms resistor) to PB0 and with Cathode directly to PB1.

compiletoflash

$400053FC constant PORTB_DATA ( Ein- und Ausgaberegister )  
$40005400 constant PORTB_DIR  ( Soll der Pin Eingang oder Ausgang sein ? )
$40005500 constant PORTB_DR2R ( 2 mA Treiber )
$40005504 constant PORTB_DR4R ( 4 mA )
$40005508 constant PORTB_DR8R ( 8 mA )
$4000550C constant PORTB_ODR  ( Open Drain )
$40005510 constant PORTB_PUR  ( Pullup Resistor )
$40005514 constant PORTB_PDR  ( Pulldown Resistor )
$40005518 constant PORTB_SLR  ( Slew Rate )
$4000551C constant PORTB_DEN  ( Digital Enable )

decimal

: Sendedatenholen ( -- Daten true | false ) key? if key dup emit true else false then ;
: Datenempfangen  ( Daten -- ) emit ;
: Verbindungsanfang ( -- ) ."  (Up) "      ; \ Verbindungsanzeige nach Bedarf anpassen
: Verbindungsende   ( -- ) ."  (Down) " cr ;

1 constant Anode
2 constant Kathode

: Strahle ( -- )
  Anode Kathode or portb_dir  bis!
  Anode            portb_data bis!
  Kathode          portb_data bic!
;

: Lauschen-Vorbereitung ( -- )
  Anode Kathode or portb_dir  bis!   
  Anode            portb_data bic! \ Sperrschichtkapazität
  Kathode          portb_data bis! \ durch Verpolung laden

  \ Warten, bis die Kathode geladen ist - das geht im ARM nicht durch Einlesen des Pins
  10 0 do loop

  Kathode portb_dir bic!
;

: Lauschen-Nachbearbeitung ( -- Flag )
  Kathode portb_data bit@ not \ Ist die Kathode entladen, ist es hell
;


34 constant Synchrondauer

8 variable Strahlzaehler
0 variable Verbindungsdauer
0 variable Lauschzaehler
0 variable Lichtmuster
0 variable Sendedaten
0 variable Datenregister

true variable Zustand ( Hell oder Dunkel ? )
 244 variable Basiszeit ( in Mikrosekunden )

: msb? ( x -- x Flag ) dup 0< ;

: HolePuls ( -- )
  8 Strahlzaehler ! \ Null-Puls, wird auch im Ruhezustand gesendet.

  \ Verbindungsdauer prüfen, beginne erst zu Senden, wenn die Verbindung auch sicher besteht.
  \ Belasse es im Falle einer gerade laufenden Synchronisation dabei, Ruhezustandspulse abzugeben.

  Verbindungsdauer @ Synchrondauer <> if exit then

  Sendedaten @ ?dup if  \ An bestehender Übertragung weiterarbeiten
                      msb? if 4 Strahlzaehler ! then \ Eins-Puls erforderlich ?
                      shl 
                      dup 0= if 12 Strahlzaehler ! then \ Wurde gerade die Merk-Eins herausrotiert ? Übertragungspuls !
                      Sendedaten !
                    else  \ Neue Daten holen und vorbereiten                     
                      Sendedatenholen
                      if 
                        ?dup if  ( Daten-zum-Senden )
                               4 Strahlzaehler ! \ Bei neuen Daten ungleich Null wird die führende Eins gesendet
                               
                               msb? if \ Ist das MSB schon die führende Eins ?
                                      shl 1 or \ Eine Merk-Eins reinrotieren, die nicht übertragen wird
                                    else
                                      shl 1 or \ Eine Merk-Eins reinrotieren, die nicht übertragen wird
                                      begin
                                        msb?   \ So lange schieben, bis die führende Eins herauspurzelt
                                        swap shl swap
                                      until
                                    then
                                                              
                               Sendedaten ! \ Fertig geschobene Datenbits zum weiteren Senden bereitlegen
                             else 12 Strahlzaehler ! \ Für eine Null genügt ein Übertragungspuls
                             then
                      then
                    then
;

: Bitmustererkennung ( -- )
  Verbindungsdauer @ Synchrondauer <>
  if \ Verbindung besteht erst nach 18 mal Zublinkern stabil.
    1 Verbindungsdauer +!
    Verbindungsdauer @ Synchrondauer = if Verbindungsanfang then    
  then

  Lichtmuster @
      %1111111111100 and    \ Übertragungspuls wird mit 11 bis 14 Basiszeiten erkannt
  dup %1111111111100 = if drop Datenregister @ Datenempfangen 
                             0 Datenregister ! \ Datenregister muss gelöscht werden,
                       else                    \  da die Daten aus mit variabler Länge übertragen werden

          %111111100 and    \ Null-Puls wird mit 7-10 Basiszeiten erkannt
          %111111100 = if   Datenregister @ shl      Datenregister ! 
                       else Datenregister @ shl 1 or Datenregister ! 
                       then \ Eins-Puls wird mit 3-6 Basiszeiten erkannt.
                       
                       then
; 

: Taktlauscher-init ( -- )
  0 Sendedaten !     \ Keine Daten zum Herausrotieren und Abstrahlen ! Wichtig !
  Verbindungsdauer @ Synchrondauer = if Verbindungsende then
  0 Verbindungsdauer !

  Zustand @ if
    \ Für einen hellen Taktlauscher
    HolePuls
    Strahle
  else
    \ Für einen dunkelen Taktlauscher  
    0 Strahlzaehler !
    1 Lauschzaehler !
    Lauschen-Vorbereitung
  then
;

: Taktlauscher ( -- )
  Strahlzaehler @ ?dup 
  if \ Strahlzähler ist nicht Null
    -1 Strahlzaehler +! 
    1- if 
         Strahle
       else \ Gerade Null geworden
         32 Lauschzaehler !
         0 Lichtmuster !
         Lauschen-Vorbereitung
       then
  else
    Lauschen-Nachbearbeitung
    1 and Lichtmuster @ shl or
    dup Lichtmuster ! ( Neues-Lichtmuster )
    %11111 and
    %11100 = if 
               Bitmustererkennung 
               HolePuls
               Strahle
             else
               -1 Lauschzaehler +!
               Lauschzaehler @ if Lauschen-Vorbereitung 
                               else Taktlauscher-init then
             then
  then
;

: ledcomm ( -- )

  anode kathode or  portb_den  ! \ Ausgänge für die Ledcomm-LED
  anode kathode or  portb_dr8r !
  anode kathode or  portb_dir  !
  0                 portb_data !

  Taktlauscher-init

  ['] Taktlauscher irq-systick !  \ (8 / 32768) s = 244 us
  Basiszeit @ 16 * $E000E014 !    \ 244 us * 16 MHz = 3904 Takte
  7 $E000E010 !                   \ Enable the systick interrupt.

  eint begin again
;

: bright ( -- ) true zustand ! ;
: dark   ( -- ) false zustand ! ;

compiletoram
