\documentclass[11pt,a4paper]{article}

% 2006-07-07 EW Adventures-1.tex
% 2006-07-22 EW Adventures-2.tex
% 2006-08-14 EW Adventures-2a.tex
% 2007-01-10 EW Adventures-3.tex
% 2007-01-13 EW Adventures-4.tex
% 2008-11-14 EW Adventures-5.tex
%
% Aufgebessert nachdem ich 'ne Reihe Optimierungen gemacht hatte
% Und dann nochmal komplett umgeräumt!
%

% language support
\usepackage[german]{babel}
%\usepackage{german}
%\usepackage[latin1]{inputenc} % can use Umlauts now "u instead of "u
%\usepackage{lmodern} % better fonts
%\usepackage{pslatex} % use native PostScript fonts
\usepackage{cm-super}

\usepackage{url} % \url{} \path{} with correct "hyphenation"
%\usepackage{fancyvrb} % for code examples

% \voffset-10mm
% \pagestyle{empty}
% \pagestyle{plain}
% \pagestyle{headings}
% \renewcommand{\baselinestretch}{1.08}
%\usepackage{xspace}
\parindent=0pt
%\newcommand{\Forth}{\textsc{forth}\xspace}
\begin{document}

\title{Adventures in Forth 5}

\author{Erich W"alde}

\maketitle

\begin{multicols}{2}




% ====================================================================
  \section{Umstieg auf \texttt{amforth}}
  \label{sec:amforth}

Am Ende meiner kleinen Artikelserie mit Code f"ur den  
Renesas--\texttt{r8c}--Kontroller war ich ein wenig traurig: der Datenspeicher, in dem mein
Programm aufbewahrt wird, war leider fast voll. Und dabei wollte ich jetzt
erst richtig loslegen. Zun"achst habe ich ein wenig mit \texttt{ByteForth}
von Willem Ouwerkerk [\ref{willem}] herumexperimentiert. Allerdings ben"otigt
man zum Arbeiten ein DOS. In meiner GNU/Linux--Welt l"asst sich das mit
\texttt{dosemu} zwar halbwegs komfortabel handhaben, aber eben nur halbwegs.

Dann bekam ich Wind von einem gewissen Matthias Trute und \texttt{amforth}
[\ref{amforth}]. Ein nagelneues Forth f"ur die \texttt{atmega}--Familie von
Atmel, angelehnt an die Artikelserie von Ron Minke [\ref{ron}]. Einen
arbeitslosen atmega32--Kontroller hatte ich noch herumliegen. Also flugs an
die Arbeit.

Es stellte sich heraus, dass ich an meinem Code f"ur den \texttt{r8c} nur
wenig "Anderungen vornehmen musste. Der Umstieg war leicht.

\begin{itemize}
\item \texttt{amforth} ist in kleinen Buchstaben programmiert: \texttt{IF}
  ist schlecht, \texttt{if} ist gut.
\item Etliche Worte sind erst durch Eintragen in \texttt{dict\_appl.inc}
  verf"ugbar.
\item statt bit--bang i2c Code ein simples \texttt{include lib/twi.frt}
\item \texttt{,} (comma) schreibt ins Flash, das muss man mit \texttt{i@}
  lesen.
\item Nur \texttt{allot} reserviert RAM, das kann man dann mit \texttt{@}
  lesen und mit \texttt{!} beschreiben.
\item \texttt{bset}, \texttt{bclr}, \texttt{btst} fehlen.
\item Das Thema mit den \texttt{include}--Dateien habe ich anders gel"ost.
  Ich expandiere meine Forth--Dateien zuerst mit einem \texttt{perl}--Filter
  und "ubertrage dann den kompletten (um Kommentare erleichterten)
  Quelltext auf den Kontroller. Es gibt ein nettes python--Programm
  \texttt{amforth-upload.py}, welches das genauso gut erledigt.
\item Ich habe zuerst die \texttt{timeup}--Uhr mit den "Uberl"aufen von
  \texttt{timer2} gef"uttert und damit meine Zeitverwaltung realisiert. Das
  ist in [\ref{Adv2}] beschrieben und mit sehr geringen "Anderungen auch
  auf \texttt{amforth} lauff"ahig.
\end{itemize}



\section{Bit Flags}

Inspiriert durch den Artikel \emph{Named Bits} von M.~Kalus, M.~Trute [\ref{namedbits}] habe ich Bit--Variablen
realisiert.


Die Definition von \texttt{flag:} ist verbl"uffend einfach

\begin{verbatim}
: flag: create ( addr bit -- )
  1 swap lshift , ,
does>          ( -- bitmask addr )
  dup i@ swap 1+ i@
;
\end{verbatim}

Die Bitnummer wird in eine Maske umgewandelt (\texttt{1 swap lshift}) und
gespeichert. Die Adresse der Variablen, die die Bits speichert, wird
ebenfalls in Flash geschrieben. Zur Laufzeit wird die Adresse der Variablen
und die Bitmaske auf den Stapel gelegt. Premiere: das war meine erste
eigene Verwendung von \texttt{create ... does>}.

Zur Verwendung erzeugt man zun"achst eine Variable, in der 16 Bits
gespeichert werden k"onnen, dann definiert man eine Bitvariable, etwa so:

\begin{verbatim}
variable FLAGS
FLAGS 4 flag: Fdebug
\end{verbatim}


Au"serdem definiert man Worte, die die auf den Stapel gelegten Werte
\texttt{bitmask} und \texttt{addr} benutzen, z.B.\ \texttt{fset}:

\begin{verbatim}
: fset ( bitmask addr -- )
  dup @         ( -- mask addr value )
  rot           ( -- addr value mask )
  or            ( -- addr new-value )
  swap !        ( -- )
;
\end{verbatim}
Die Variable \texttt{FLAGS} wird in einer Lesen--"Andern--Schreiben--Sequenz
bearbeitet, so dass die anderen Bits unver"andert bleiben.

Die folgenden Worte habe ich definiert:
\begin{itemize}
\item \texttt{fset} --- Bit setzen
\item \texttt{fclr} --- Bit l"oschen
\item \texttt{fset?} --- wahr, wenn Bit gesetzt ist
\item \texttt{fclr?} --- wahr, wenn Bit gel"oscht ist
\item \texttt{ftgl} --- das Bit setzen, wenn es gel"oscht ist, und umgekehrt
\end{itemize}

Das l"asst sich dann auch gleich ausprobieren:

\begin{verbatim}
> variable FLAGS
 ok
> 0 FLAGS !
 ok
> FLAGS @ .
 0  ok
> FLAGS 2 flag: F_debug
 ok
> F_debug fset? .
 0  ok
> F_debug fset
 ok
> FLAGS @ .
 4  ok
> F_debug fset? .
 -1  ok
> F_debug ftgl
 ok
> F_debug fset? .
 0  ok
> FLAGS @ .
 0  ok
\end{verbatim}

\section{So 'ne Art Objekt: \texttt{sensor:}}

Mein derzeitiges Kontrollerprogramm liest alle 10 Sekunden zweierlei
Temperatursensoren aus, LM75-- und LM92--Sensoren. Der Datentransfer ist bei
beiden exakt identisch, nur die Anzahl der signifikanten Bits in der
Antwort ist verschieden. Es gibt ein Wort \texttt{lm.get}, welches 2 Byte
von der angegebenen Adresse liest:

\begin{verbatim}
: lm.get ( i2c_addr -- xh xl ok | err )
  dup twi.ping? if
      >r
  0 1 r@ >i2c
    2 r> <i2c
    0          \ ok
  else
    drop \ addr
    -1         \ err
  then
;
\end{verbatim}
Wenn der Sensor erreichbar war, wird zus"atzlich eine \texttt{0} auf den
Stapel gelegt, sonst nur eine \texttt{-1}. Die beiden Funktionen
\texttt{>i2c} und \texttt{<i2c} schreiben bzw.\ lesen $N$ Bytes von einer
i2c-Adresse (s.\ Listings und [\ref{Adv1}]): 

\begin{verbatim}
: >i2c ( x1 .. xN.msB N addr -- ) ... ;
: <i2c ( N addr -- xN.msB .. x1 ) ... ;
\end{verbatim}


Die beiden von \texttt{lm.get} gelesenen Bytes werden dann dekodiert und in
Centigrad Celsius umgerechnet:

\begin{verbatim}
: lm75.decode ( xh xl -- T*100 [C] )
  [ hex ]
  80 and swap 8 lshift +
  [ decimal ]
  100 256 */
;
\end{verbatim}

Die gleiche Funktion f"ur den LM92 unterscheidet sich nur an zwei Stellen:
\begin{verbatim}
: lm92.decode ( xh xl -- T*100 )
  [ hex ]
  f8 and swap 8 lshift +
  [ decimal ]
  100 128 */
;
\end{verbatim}
\texttt{f8} statt \texttt{80} und \texttt{128} statt \texttt{256}. Die
k"onnte man zwar glatt als Argumente "ubergeben, aber das ist sehr
h"asslich. 

Wenn man die Sensoren ausliest, muss man also immer wissen, welche Sorte man
gerade ausliest:

\begin{verbatim}
...
addr_lm75 lm.get 0= if lm75.decode . then
addr_lm92 lm.get 0= if lm92.decode . then
...
\end{verbatim}

Das fand ich doof. Also habe ich ein \textit{Objekt} definiert, welches
Zeiger auf die richtigen Funktionen speichert. Wird das Objekt zur Laufzeit
aufgerufen, dann holt es die Werte vom Sensor, dekodiert und korrigiert
diese und legt das Ergebnis auf den Stapel. Dann braucht's nur noch eine
passende Anzeigefunktion. 

\begin{verbatim}
: sensor:
  create ( id i2c-addr 'get 'decode a_0 -- )
    \ keep order of arguments in (flash) memory
    >r >r >r >r , r> , r> , r> , r> ,
  does>  ( -- id skalierterWert ok | id err )
    >r             ( -- )
      r@    i@     ( -- id )
    1 r@ +  i@     ( -- id i2c-addr )

    2 r@ +  i@     ( -- id i2c-addr 'get )
    execute        ( -- id xN..x1 ok | id err )
    0= if          ( -- id xN..x1 )
      3 r@ +  i@   ( -- id xN..x1 'decode )
      execute      ( -- id T*100 )
      4 r@ +  i@ + ( -- id T*100+a_0 )  
      0            ( -- id T*100+a_0 ok )
    else           ( -- id )
      -1           ( -- id error )
    then
    r> drop
;
\end{verbatim}

Beim Definieren eines \texttt{sensor:}--Objekts werden eine ID, die Adresse
des Sensors, je ein Zeiger auf eine Funktion zum Lesen des Sensors, sowie
zum Dekodieren der gelesenen Daten, und schlie"slich eine Korrektur
(Offset) abgespeichert. Die Verwendung wird jetzt einfacher:

\begin{verbatim}
: .T ( id value ok | id err -- )
  0= if
    swap .id 2 +.f
  else
    .id ." *"
  then
;
...
01 a_th1 ' lm.get ' lm75.decode -150 sensor: T1
02 a_th2 ' lm.get ' lm92.decode  122 sensor: T2
...
T1 .T   T2 .T
...
\end{verbatim}


Das ist jetzt so eine Art Objekt mit privaten Konstanten, ohne private
Variablen und mit nur einer Methode (\texttt{does>}). Nachteilig ist, dass
man hier nicht verschiedene Methoden basteln kann. Immerhin kann man
mehrere Instanzen anlegen, die sich in ihrem Innenleben verschieden
verhalten. Diese Verschiedenheit wird "uber Funktionszeiger transportiert.
Die Instanzen lassen sich daher auch f"ur andere Sensoren verwenden, die
komplett anders anzusprechen sind und/oder eine andere Art und/oder Anzahl
von Ergebnissen produzieren. Diese m"ussen nur korrekt weiterverarbeitet
werden (z.B.\ Anzeigefunktion)



\section{So 'ne Art Objekt: \texttt{filter\_mean:}}

Ich wollte die Messwerte "uber 10 Minuten mitteln und am Ende der 10 Minuten
nur als Liste von Werten $N$, $x_{min}$, $x_{mean}$, $x_{max}$ ausgeben.
Beim Mittelwert ist es einfach, ich muss nicht alle Werte aufheben, sondern
nur die Summe und die Anzahl der Messwerte. $x_{mean} = x_{sum}/N$,
$x_{min}$ und $x_{max}$ k"onnen fortlaufend bestimmt werden.

Also brauche ich 4 Variablen im RAM: $N$, $x_{min}$, $x_{sum}$, $x_{max}$.
Davon $x_{sum}$ besser mit doppelter L"ange. \texttt{filter\_mean:} bekommt
eine ID und einen Zeiger auf den reservierten RAM--Bereich.


\begin{verbatim}
: filter_mean:
  create ( id -- )
    ,      \ store id in dictionary entry
    heap , \ store next RAM addr
    5 cells allot \ create RAM space
  does>  ( -- id ram_addr )
    dup i@
    swap 1+ i@
;
\end{verbatim}


\texttt{filter\_mean:} speichert beim Anlegen eines Filters zuerst eine ID.
Dann wird die Adresse der n"achsten freien RAM--Zelle gespeichert, und
anschlie"send im RAM die n"otige Anzahl von Zellen reserviert. Zur Laufzeit
werden lediglich die ID und die RAM--Adresse auf den Stapel gelegt.

Die Belegung im RAM--Speicher soll mit Konstanten lesbarer gemacht werden.
Dazu kommen Worte, die das Offset zu einer gegebenen Adresse addieren.

\begin{verbatim}
\ offsets into ram_addr
0 constant mean_sum
2 constant mean_N
3 constant mean_min
4 constant mean_max
: mean_sum+ ( mean_sum cells + ) noop ;
: mean_N+     mean_N   cells + ;
: mean_min+   mean_min cells + ;
: mean_max+   mean_max cells + ;
\end{verbatim}


Drei Methoden habe ich definiert, um mit dem RAM--Bereich zu arbeiten:
\begin{itemize}
\item \texttt{reset ( id ram\_addr -- )}\\
  die Werte im Speicher auf Null setzen
\item \texttt{addup ( x id ram\_addr -- )}\\
  einen neuen Messwert in die Daten einf"ugen, Dabei $x_{min}$ und
  $x_{max}$ "uberpr"ufen und ggf.\ aktualisieren.
\item \texttt{eval ( id ram\_addr -- id max d.sum min N>0 | id 0 )}\\
  die vorhandenen Daten auswerten
\end{itemize}
Neu war f"ur mich an dieser Stelle nur die korrekte Bearbeitung von
$x_{sum}$ als doppelt lange Variable. Daf"ur gibt es die Helferlein
\texttt{2@}, \texttt{2!}, \texttt{s>d}, \texttt{d+} und \texttt{m*/}, die
sich in der Datei \texttt{lib/ans94/2x.frt} befinden.

\begin{verbatim}
: mean_eval
( id ram_addr -- id max d.sum min N>0 | id 0 )
  >r
  r@ mean_N+ @  0=  if
    0 \ N=0, no data
  else
    r@ mean_max+  @ \ mean_max
    r@           2@ \ mean_sum
    1
    r@ mean_N+    @ \ mean_N
    m*/             \ mean_sum*1/mean_N
    r@ mean_min+  @ \ mean_min
    r@ mean_N+    @ \ mean_N
  then
  r> drop \ ram_addr
;
\end{verbatim}

\begin{verbatim}
> decimal ok
> 10 filter_mean: F10 ok
> F10 mean_reset ok
> : .F10 cr . . d. . . ; ok
> 1000 F10 mean_addup ok
> 2000 F10 mean_addup ok
> 3000 F10 mean_addup ok
> 4000 F10 mean_addup ok
> F10 mean_eval .F10
 4  1000  2500  4000  10  ok
\end{verbatim}

Im Unterschied zu \texttt{sensor:} enth"alt \texttt{filter\_mean:} private
Variablen und drei Methoden, die auf den Variablen operieren.
Wahrscheinlich sind das keine \textit{Objekte nach der reinen Lehre}, aber
als Beispiel erhellend. Die Methoden sind hier f"ur alle Instanzen gleich.


%\section{Ausblick}

%Ein paar Dinge k"onnte man jetzt noch tun:


\section{Referenzen}

\begin{enumerate}
\item \label{Adv1} E. W"alde, Adventures in Forth, Die 4. Dimension 3/2006, Jahrgang 22
\item \label{Adv2} E. W"alde, Adventures in Forth 2, Die 4. Dimension 4/2006, Jahrgang 22
%\item \label{Adv3} E. W"alde, Adventures in Forth 3, Die 4. Dimension 1/2007, Jahrgang 23
%\item \label{Adv4} E. W"alde, Adventures in Forth 4, Die 4. Dimension 1/2007, Jahrgang 23
%\item \label{r8c-ds} Renesas R8C/13 datasheet auf \url{www.renesas.com}
%\item \label{Koenig} A.\ K"onig und M.\ K"onig, Das PICmicro Profi Buch, Franzis
%  Verlag 1999, ISBN 3-7723-4284-1
%\item \label{SPelc} Stephen Pelc, Programming Forth, \\ \url{http://www.mpeforth.com/arena/ProgramForth.pdf}
%\item \label{Deliano} \url{http://www.embeddedforth.de/emb3.pdf} S.\ 9
%\item \label{dcf} \url{http://de.wikipedia.org/wiki/DCF77} und Verweise darin
\item \label{willem} ByteForth von Willem Ouwerkerk,\\  \url{http://www.forth.hccnet.nl/byteforth.htm}
\item \label{amforth} \url{http://amforth.sourceforge.net/}
\item \label{ron} Ron Minke, Forth von der Pike auf  Die 4. Dimension 3+4/2005 \ldots 4/2006, sowie Sonderheft AVR und  3+4/2007
\item \label{namedbits} M. Kalus, M. Trute, Named Bits, Die 4. Dimension 2/2007, Jahrgang 23
\end{enumerate}
\end{multicols}

\newpage
\section{Listings}
\begin{quote}
\begin{small}
\begin{multicols}{2}
\listinginput[1]{1}{2008-04/flags.fs}
\listinginput[1]{1}{2008-04/i2c_lmXX.fs}
\listinginput[1]{1}{2008-04/i2c.fs}
\listinginput[1]{1}{2008-04/sensor.fs}
\listinginput[1]{1}{2008-04/filter_mean.fs}
\end{multicols}
\end{small}
\end{quote}


\end{document}
