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

compiletoflash

\ ------------------------------------------------------------------------------
\ Wuseldraht-Chefknoten in Forth.
\ ------------------------------------------------------------------------------

8 constant wuselleitung

%0111 constant wusel1
%0011 constant wusel0
%0001 constant wuselN

244 variable basiszeit
\ 61 für die alten Knoten

\ ------------------------------------------------------------------------------
: oberleitung
\ ------------------------------------------------------------------------------
  wuselleitung p2out cbis! \ High bereitlegen
  wuselleitung p2dir cbis! \ Einschalten
;

\ ------------------------------------------------------------------------------
: entgleisen \ Init für den Knoten, zum Anfang und zum Loslassen der Leitung 
             \ für längere Pausen in der Kommunikation
\ ------------------------------------------------------------------------------
  wuselleitung p2dir cbic! \ Ausschalten
  wuselleitung p2out cbis! \ High bereitlegen
;

\ ------------------------------------------------------------------------------
: wmw ( Muster -- Muster* ) \ warten, messen, warten. Speziell für den Wuseldraht.
\ ------------------------------------------------------------------------------
  basiszeit @ us
  shl
  wuselleitung p2in cbit@
  1 and or
  basiszeit @ us
;

\ ------------------------------------------------------------------------------
: wuseldraht ( Muster hinaus -- Muster hinein )
             \ Synchronisierende Kommunikationsroutine
\ ------------------------------------------------------------------------------
  \ Flanke zur Synchronisation suchen
  begin wuselleitung p2in cbit@ until \ Warte auf High
  wuselleitung p2dir cbic! \ Loslassen
  begin wuselleitung p2in cbit@ not until \ Warte auf Low

  case
    wusel1 of 0 wmw wuselleitung p2dir cbis! wmw wmw wmw endof
    wusel0 of 0 wmw wmw wuselleitung p2dir cbis! wmw wmw endof
    wuselN of 0 wmw wmw wmw wuselleitung p2dir cbis! wmw endof
  endcase

  \ ...0ZN1 wenn alles gutgeht !
;

\ ------------------------------------------------------------------------------
\ Ganz einfache Chef-Definitionen zum Suchen und Ansprechen !
\ ------------------------------------------------------------------------------

: null wusel0 wuseldraht drop ;
: eins wusel1 wuseldraht drop ;
: n    wuseln wuseldraht drop ;

: adressiere-alle ( -- ? )
  begin wuselN wuseldraht wuselN = until

  eins
  eins

  wuselN wuseldraht wusel1 =
;

: wuselbit-senden ( ? -- )
  if eins else null then
;

: wuselbit-lesen ( -- ? )
  wusel0 wuseldraht wusel1 =
;

: adressiere-knoten ( Adresslänge Adresse -- ? )
  begin wuselN wuseldraht wuselN = until

  null

  \ Schiebe die Adresse passend:
  over 16 swap - ( Adresslänge Adresse Schiebeweite )
  lshift ( Adresslänge Adresse* )

  swap ( Adresse* Adresslänge )

  0 do
    dup $8000 and wuselbit-senden
    shl
  loop

  drop

  wuselN wuseldraht wusel1 =
;

: sendeword ( x -- x* )
  0 swap ( 0 x )

  16 0 do
    ( rein raus )
    dup 1 i lshift and wuselbit-senden
    swap wuselbit-lesen 1 i lshift and or swap
  loop

  drop
;

\ ------------------------------------------------------------------------------
\ Die Knotensuche. Prüfe sie noch genau !
\ ------------------------------------------------------------------------------

: neuanfang ( Adresslänge Adresse -- )
  ." Neuanfang " .s
  \ N wurde schon beim Erkennen des letzten Knotens im Bus erzeugt !
  eins
  null

  \ Schiebe die Adresse passend:
  over 16 swap - ( Adresslänge Adresse Schiebeweite )
  lshift ( Adresslänge Adresse* )

  swap ( Adresse* Adresslänge )

  0 ?do
    n n
    dup $8000 and wuselbit-senden
    shl
  loop

  drop
  n n
;

: weitersuchen ( Adresslänge Adresse -- )
  ." Weitersuchen " .s
  wuselN wuseldraht \ 1. Antwort
  case
    wusel0 of
             wuselN wuseldraht \ 2. Antwort
             case
               wusel0 of
                        ." Ein Knoten antwortet falsch." cr
                      endof
               wusel1 of \ Es gibt nur Nullen
                        null \ Nimm die Null !
                        2dup shl swap 1+ swap recurse \ Weitersuchen
                      endof
               ." Elektrische Störung" cr
             endcase
           endof \ wusel0

    wusel1 of
             wuselN wuseldraht \ 2. Antwort
             case
               wusel0 of \ Es gibt nur Einsen
                        eins \ Nimm die Eins !
                        2dup shl 1+ swap 1+ swap recurse \ Weitersuchen
                      endof

               wusel1 of \ Es gibt Einsen und Nullen                       
                        null \ Nimm die Null !
                        2dup shl swap 1+ swap recurse \ Weitersuchen
                        2dup neuanfang \ Adresse muss neu gesendet werden !
                        eins \ Nimm die Eins !
                        2dup shl 1+ swap 1+ swap recurse \ Weitersuchen
                      endof
               wuselN of
                        ." Knoten gefunden: "
                        2dup ." Adresse: " u. ." Länge: " u. cr
                      endof
               ." Elektrische Störung" cr
             endcase
           endof \ wusel1

    wuselN of
             wuselN wuseldraht drop \ 2. Antwort, hier unwichtig
             ." Ein Knoten ist während der Suche weggefallen !" cr
           endof
    ." Elektrische Störung" cr
  endcase

  2drop
;

: suche
  begin wuselN wuseldraht wuselN = until
  eins null \ Adressuche beginnt !
  0 0 weitersuchen
; 

\ ------------------------------------------------------------------------------

: init init oberleitung ;

\ Vorher den passenden Knoten - oder alle - adressieren, sonst passiert nichts !

\ 3 %101 adressiere-knoten .
\ adressiere-alle .

: tc! ( Daten Adresse -- ) 2 sendeword drop swap sendeword drop sendeword drop ;
: t!  ( Daten Adresse -- ) 3 sendeword drop swap sendeword drop sendeword drop ;
: tc@ ( Adresse - Daten )  4 sendeword drop sendeword drop -1 sendeword ;
: t@  ( Adresse - Daten )  5 sendeword drop sendeword drop -1 sendeword ;

: led-aus ( -- ) 0 sendeword drop ;
: led-an  ( -- ) 1 sendeword drop ;

\ Beispiele: LED an P2.6/P2.7 - Oszillatoranschluss:

: xtalled+ ( -- )
  0 p2sel tc!
  64 p2out tc!
  64 128 or p2dir tc!
;
  
: xtalled- ( -- )
  0 p2sel tc!
  128 p2out tc!
  64 128 or p2dir tc!  
;
