%Copyright Larry Tyree, N6TR, 2011,2012,2013,2014,2015.

%This file is part of TR log for linux.

%TR log for linux 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 2 of the
%License, or (at your option) any later version.

%TR log for linux 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 TR log for linux.  If not, see
%<http://www.gnu.org/licenses/>.

\documentclass[12pt]{article}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{url}
\usepackage[margin=.9in]{geometry}
\begin{document}
\title{Notes on porting TR log to linux}
\author{
Kevin E. Schmidt, W9CF\\
6510 S. Roosevelt St.\\
Tempe, AZ 85283 USA\\
}
\date{}
\maketitle
\section{Original program structure}
TR was written for DOS on 286 and later 386 class machines. This
had major consequences that deeply affected the way I have
implemented the linux port.
\begin{itemize}
\item
DOS was limited to 640 Kbytes of memory. Later extended/expanded
memory was available, but is was more difficult to use, and DOS TR
did not use it.
\item
In DOS only a single program ran at a time. Since no other process
can interrupt you, the timing is not a problem.
\item
DOS didn't have the concept of different users having different
permissions or any security.
All DOS programs can directly manipulate any and all hardware on the
computer.
\end{itemize}

With the very limited
memory available 
information needed by more than one routine in the code was almost
always stored in global public variables in the Pascal units. Many, units
are included by most other units, which essentially makes all of these
variables global to the entire program.  The major consequence of this
is that these variables cannot be manipulated or changed without a
more or less global understanding of the entire program. Without
this understanding, it is very
easy to make a local change that inadvertently breaks another part of the
code.

Changing to linux where essentially any system will have at
a Gigabyte of real memory or more (i.e. at least 2000 times more than the
machines TR was written for),
and much more virtual memory, memory use becomes a nonissue. It is
then possible to encapsulate different parts of the code to make modification
easier. This however, needs to be done in a way that doesn't break the
code. That means it will be done slowly.

\section{DOS timer interrupt}
With DOS being a single process operating system, a second consequence is
that TR under DOS could have completely well defined timing. TR under DOS
took over the timer interrupt, and used this to send CW, communicate with
the rigs, packet, etc. While there are real time kernels for linux,
these are not used in the main linux distributions. However, the
standard kernels do have many of the soft real-time timers etc., so that
while not guaranteed, timing is good enough that on a reasonably
lightly loaded machine, things like sending CW from a serial or parallel
port sounds fine. Further since TR was the only thing running on the DOS
machine, whenever TR needed to wait for input, or anything else, it would
busy wait. Under linux this code would cause TR to use nearly 100 percent
of the CPU cycles.

The natural way (at least to me) to implement the various timing requirements
would be to run a multithreaded version on linux. The initial port does
not do this. It does run a second thread for the sound card output, but
the use of a large number of global variables in the original code makes
it extremely difficult to write thread-safe code where only one thread
at a time can manipulate the values of variables. I tried several different
ways of emulating the original DOS timer. Most interacted badly with
the display. In the end, I resorted to
\begin{itemize}
\item
Replacing every busy wait, with calls to a routine that sleeps for
1 millisecond.
\item
The routine that sleeps for 1 millisecond, checks every 500 microseonds
if the time for the DOS interrupt has occured, and if so, it calls
the timer routine.
\end{itemize}
In this way, the timer code is called at more or less the same
time that it would have been called under DOS, and it is called in the
same thread as the rest of TR, so there are no thread safety issues.

The timer routines have been encapsulated in a new timer unit. It has
three procedures
\begin{itemize}
\item
timerinitialize -- this must be called to start the calls to the
timer routines.
\item
millisleep -- this needs to be called whenever the code is waiting for
something like keyboard input. Before timerinitialize is called, it
simply sleeps for 1 millisecond. After timerinitialize is
called it calls the timer routines on
average every 1680 microseconds with a granularity of about 500 microseconds,
\item
addtimer -- this takes as an argument the a procedure from a class, of the
form ``procedure timer(caughtup: boolean)'' -- which will be called
every 1680 microseconds. As many of these routines as desired can be added.
They are called in turn. They are called with argument caughtup set to true
if the timer occurs at the correct time. If the timer has been delayed
because the computer has been busy doing other things, caughtup will be
false. This allows each timer procedure to only process critical items
in an attempt to get better real time performance.
\end{itemize}

More work needs to be done on the timer routine to be able to remove
timers, etc. Right now only the original timer routine is added with addtimer.
All other timer routines are called by it. That should be changed.

Eventually, the timers should be replaced with threads.

\section{Serial and parallel ports}
The original DOS code communicated with the serial and parallel ports
directly. It is possible to write linux code that has special
superuser privileges that communicates directly with these legacy devices.
However,
in order to write a well-behaved multiuser code, and to be able to use
USB serial devices, communicating through the standard linux devices
and libraries is needed. This is accomplished in the unit
communication.pas which defines a set of classes which read and write
from serial and parallel ports. These also implement pseudottys that
can be used for communication.

The packet shell device, and the multinetwork ncat devices fork new processes
which the program communicates with through pseudottys. As far as the
original TR code is concerned, these are just serial ports.

\end{document}
