How to create a digital recorder/scope

In 1997, Hilchner in germany marketed the Rievo Lie-detector Since I am a playful kid, I saw some market potential for these things in my country.
OK, I was proven wrong. These boring dutch didn't understand the nature of the thing. It was a FUN article, to be used in a half drunk state in a party-cellar to get the right atmosphere. And the only questions I got were if I would give a test-certificate.

Since I had a truckload of lie detectors (yes, this is a lie; in fact I had only 20) lying around I needed some other purpose for these fun-items. So I used my engineering wits to please my fellow dutch: I would make a TOOL out of a TOY.

I succeeded in converting the toy into a tool. But then the dutch began to bark that the 10 euro toy was worse than a 1000 euro LeCroy. Talk about a sense for humor.
In the download section you can find the full LDA package. It contains instructions how to change a fun article into a toy-tool. The DVM created from the toy is Really Good. It DOES measure at 10 bits accuracy and with a Vref of 5 Volts, the accuracy is 5 mV. And that's not bad for such a cheap product.

Below you see the program that I developed for running the Rievo LD as and ADC (hence the name LDA) at breakneck speeds. And since I am a real engineer I added things only engineers can think of.

In this source I first used my (then new) grahical user interface routines that I published about in APJ issue 6 and which were later ported to Modula-2 in the VGAlib3 project.


The circuit drawings..

Rievo Lie detector Here you see the circuit drawing for the original "Rievo Luegendetektor" as it was sold by Rievo. The design was ingeniously simple.


Run a converted Rievo liedetector as a scope

LD scope circuit To the left, you see the circuit drawing for the converted "Rievo Luegen detektor". I mainly removed the capacitor and the 100k resistor. And wrote some software, of course.


The new LDA software.

The first part is easy: we set up data, constants and the rest. Also we have the version history in the header. As you see, this is an old program and I should have published it many moons ago.

This program is GNU GPL, so don't complain it it works in another way than you expected. You have the source, so if it doesn't do what you wanted, just change it such that it will meet your requirements.

Please keep in mind that all rights for the hardware remain property of Rievo.

name     LDA04d
title    Lie Detector as Adc
page     80, 120

;  LDA01 : first version, create user interface                 OK : 31-03-1998
;  LDA02 : add mouse interface                                  OK : 16-04-1998
;  LDA03 : make it measure                                      OK : 17-04-1998
;        : improved bargraph plotting to <50 s avg (386DX-40)  OK : 17-04-1998
;        : let it show digits                                   OK : 20-04-1998
;        : optimize for speed                                   OK : 24-04-1998
;  LDA04 : incorporate timing functions                         OK : 24-04-1998
;        : use JMP $+2 before OUT  DX, AL                       OK : 26-04-1998
;        : get it to sample and stop automatically              OK : 10-09-1998
;        : let it plot data                                     OK : 10-09-1998
;        : Bug fixed, on exit FindClick jumped to AFTER 
;          restoration of the 01C vector...                     OK : 11-09-1998
;        : make it nicer to the eye                             OK : 12-09-1998
;        : use INT 070 for the sampler interrupt                OK : 28-09-1998
;        : make it sample at 8192 Sps                           OK : 29-09-1998
;        : fix IRQ-0 glitches                                   OK : 29-09-1998
;        : make it sample at selectable sample rates            OK : 

lf        = 10
cr        = 13

CHR_WID   = 9           ; number of pixels per character
BarLines  = 14          ; height of bargraph

LftButton = bit 0       ; Mouse button codes
RgtButton = bit 1
MidButton = bit 2

PowerFlag = bit 0       ; ADC has power?
FastMode  = bit 1       ; too fast to update screen?
PackWord  = bit 2       ; store 3 (10-bit) results in 4 bytes
TimeOut   = bit 3       ; one sample has been taken, please process
TrigWait  = bit 4       ; if set, wait on trigger
StopNow   = bit 5       ; if set, stop sampling
Running   = bit 6       ; if set, IRQ may sample
RefrshBar = bit 7
RefrshDig = bit 8
ForceDigs = bit 11      ; Enforce a refresh of digits
Upd8Digs  = bit 12      ; Update digital readout
RefrPara  = bit 13      ; Parameter window needs refreshing
RfrshBar  = bit 14      ; Refresh scale of bargraph?
JustUpd8  = bit 15      ; after a LOAD CONFIG, update only?

ClkBit    = bit 1       ; bitnumbers in COM port registers
TxDBit    = bit 6

MaxGroup  =   64        ; maximum nr of sample per group
MaxShift  =    6        ; LN (MaxGroup) / LN (2)
MaxCount  = 1024        ; Maximum ADC count + 1

xxx  STRUC
Now      dw    ?        ; current value
Prev     dw    ?        ; previous value
     ENDS

Infoblk1 STRUC
Win_X    dw    ?        ; top-left window position, X and ...
Win_Y    dw    ?        ;     ... Y
Win_wid  dw    ?        ; window width and ...
Win_hgt  dw    ?        ;     ... height
CurrX    dw    ?        ; within window, current X-coordinate, ...
CurrY    dw    ?        ;     ... and Y
DeltaX   dw    ?
DeltaY   dw    ?
Indent   dw    ?        ; Indentation for characters in PIXELS!
Multiply dw    ?        ; screenwidth handler
Watte01  dw    ?        ; 
BoxCol   db    ?        ;     border colour
TxtCol   db    ?        ;       text colour
BckCol   db    ?        ; background colour
MenuCol  db    ?        ;  menu text colour
         ENDS

clr MACRO               ; make the #1 parameter ZERO
    xor  #1, #1
    #EM

ShowMouse MACRO         ; Make the mouse visible
    mov  ax, 1
    int  033
    #EM

HideMouse MACRO         ; Make the mouse invisible
    mov  ax, 2
    int  033
    #EM

Piep MACRO              ; BEEEEEEEEEEEEP
    mov  ah, 2
    mov  dl, 07
    int  021
    #EM

Store MACRO             ; store one value in buffer at [di]
    mov  al, #1
    stosb
    #EM

Topic MACRO             ; start of printing message
    dw   #1, #2
    db   #3, #4
    #EM

TopicEnd MACRO          ; topics stop here
    dw   0F000
    #EM
   

Some data declarations.

What follows are some variables needed to run this program. I used lots of comments so it should be not too hard to find out what it's all about.

  DATA segment

FirstByte equ $
dummy    db    ?        ; cosmetic variable, just to please D86!

E_mask   db    ?          ; First-byte mask
L_mask   db    ?          ; Last-byte mask
C_val    db    ?          ; char mask allignment
clk_bit  db    ?          ; last value of clkbit port
ToPlot   db    ?          ; Plotting mask for pixels
hdc      db    6 dup (?)  ; Hex/Dec Conversion buffer
DigBuff  db    8 dup (?)  ; Digits from digital display (new/old)
VidMode  db    ?          ; original video mode

      even
ZeroSeg  dw    ?        ; fast way to load SegReg with Zero
BufSeg   dw    ?        ; segment of ADC buffer data
DataSeg  dw    ?        ; segment of variables (same as CodeSeg)
CodeSeg  dw    ?        ; segment of instructions (same as DataSeg)
Flags    dw    ?        ; several status bits
ComNr    dw    ?        ; current COM port number
ComBase  dw    ?        ; base address of current COM port
ClkPort  dw    ?        ; ComBase + 4

                        ; Item number in options list of parameter:
StartIt  dw    ?        ; Start Item Ĵ>>
StopIt   dw    ?        ; Stop Item     [Mem, Man, +, -, Val, Up, Down]
UnitIt   dw    ?        ; Unit Item     [V, A, F, ]
ModeIt   dw    ?        ; Mode Item     [DMM, Plot, Hist, Stat]
StatIt   dw    ?        ; Status Item   [Idle, Sampl, Wait, Ready, Single]

Vref     dw    ?        ; reference voltage of ADC [mV]
Scale    dw    ?        ; actual scaling factor  [x100]
GroupS   dw    ?        ; actual groupsize
ShiftIt  dw    ?        ; shiftbits for this groupsize
SmpRate  dw    ?        ; actual sample rate
FSval    dw    ?        ; Full-Scale value      [mV]
MathRate dw    ?        ; nr of groups per second
RefrCnt  dw    ?        ; refresh counter
TrigMode dw    ?        ; triggermode

BarVal   dw    ?, ?     ; value to use in bargraph display [mV]
AvgVal   dw    ?, ?     ; Most recent value  [0..1023]
AvgVolt  dw    ?        ; Scaled and ready to print value
ThisVal  dw    ?, ?     ; Scaled and ready to print value
AdcCount dw    ?        ; current sample number
AdcValue dw    ?        ; current sample value
RunTotal dw    ?        ; running total for averaging
Counter  dw    ?        ; incremented by NewIRQ0 for screen updates
Sigma    dw    ?        ; Most recent sigma
Segments dw    ?, ?     ; Segments to plot in bargraph

SubDiv   dw    ?        ; subdivisons for axis printer
TotalDiv dw    ?        ; total nr of divisons

T_val    dw    ?        ; total nr of bits to plot
E_val    dw    ?        ; nr of bits in first byte
L_val    dw    ?        ; nr of bits in last byte
K_val    dw    ?        ; nr of BYTES to fill in between
P_mask   dw    ?        ; mask for printing characters

MouseX   dw    ?        ; mouse X coordinate
MouseY   dw    ?        ; mouse Y coordinate
MouseB   dw    ?        ; mouse button status
Clicker  dw    ?        ; mouse clickfield counter
Handle   dw    ?        ; filehandle storage
VidPoint dw    ?        ; videoRAM pointer

ShouldBe dw    ?        ; target for timing function           [s]
TrialRun dw    ?        ; Indirect call for DoW8 function
Delay    dw    ?        ; actual value for delay loop      [counts]
OneShot  dw    ?        ; time it takes to take ONE sample     [s]
MaxRate  dw    ?, ?     ; maximum sample rate                 [Sps]
SampTime dw    ?        ; maximum recording time at this rate   [s]

         even 4
OldIRQ0  dd    ?        ; pointer to old timer routine
OldClock dd    ?        ; pointer to old RTC routine

time     dw    020 dup (?)      ; space for timing values
RawBuff  dw    MaxGroup dup (?) ; space for averaging
ADCbuff  dw    4096 dup (?)

         dw    01FF dup (?)
stacktop dw    ?

LastByte equ $
;-------------------------------
   

Window definitions and timer operation.

We start with the multiply-by-80 routine. It's needed by the graphic engine and it is used in the BOX-parameter lists.

Next come the 16 window definitions. Each definition is of type InfoBlk1 (see above) and describes a full window.

Next come some routines to control the microsecond timer in the hardware (CMOS) clock.

  CODE segment

         jmp   main

mul_80:  push  bx               ; calculate pixel address in 640 x 480 mode
         shl   ax, 4
         mov   bx, ax           ; bx = 16 x SCR_Y
         shl   ax, 2            ; ax = 64 x SCR_Y
         add   ax, bx           ; ax = 80 x SCR_Y
         pop   bx
         ret
;-------------------------------

         even
fullscrn dw     0,  0,640,480, 0, 0, 0, 0, 4, mul_80, 0      ; main screen window
         db    12, 14,  3, 15 
ParWin2  dw     5, 30,630,150, 8, 9, 0, 0, 4, mul_80, 0      ; Parameter window
         db    10, 11,  3, 11
PlotWin  dw     5,195,630,260, 0, 0, 0, 0, 4, mul_80, 0      ; Virtual plotting window
         db     9, 15,  3,  7
PlotWin2 dw     6,196,628,256, 0, 0, 0, 0, 4, mul_80, 0      ; Actual plotting window
         db     9, 15,  3,  7

ParWin   dw     5, 30,630,150, 4, 9, 0, 0, 4, mul_80, 0      ; parameter window
         db    10, 11,  3, 11
EditWin  dw     5, 30,630,150, 4, 9, 0, 0, 4, mul_80, 0      ; Data entry window
         db     5,  6, 15, 14
TopBar   dw     5,  5,630, 20, 6, 0, 0, 0, 4, mul_80, 0      ; menu bar
         db     4,  5,  1, 0E
BotBar   dw     5,460,630, 18,15, 0, 0, 0, 4, mul_80, 0      ; copyrights
         db     3,  6,  2, 0F
VrefBar  dw    15,120,540, 50, 0, 0, 0, 0, 0, mul_80, 0      ; mouse scroll-bar Vref
         db    10, 15,  4, 14
ScaleBar dw    15,120,540, 50, 0, 0, 0, 0, 0, mul_80, 0      ; mouse scroll-bar Scale
         db    11, 14,  3, 12
DisplBar dw    10,150,500, 20, 0, 0, 0, 0, 0, mul_80, 0      ; Bargraph display
         db     8, 10, 14,  4
DigSpac1 dw    16, 90, 40, 50, 0, 0, 0, 0, 0, mul_80, 0      ; Digital display, digit 1, MSD
         db     9, 11, 14,  3
DigSpac2 dw    56, 90, 40, 50, 0, 0, 0, 0, 0, mul_80, 0      ; Digital display, digit 2
         db     9, 11, 14,  3
DigSpac3 dw    96, 90, 40, 50, 0, 0, 0, 0, 0, mul_80, 0      ; Digital display. digit 3
         db     9, 11, 12,  3
DigSpac4 dw   136, 90, 40, 50, 0, 0, 0, 0, 0, mul_80, 0      ; Digital display, digit 4, LSD  
         db     9, 11, 12,  3

MX_box   dw   592, 38, 50, 60, 0, 0, 0, 0, 4, mul_80, 0      ; Mouse plotters
         db    3,  6,  2, 0F

VGA_base dw    0A000            ; for ease of loading segment registers
;-------------------------------

DoZip:   ret                    ; do absolutely NOTHING!
;-------------------------------

open_2:  push  ax       ; open timer chip in mode 2
         mov   al, 034
         out   043, al
         xor   al, al
         out   040, al
         out   040, al
         pop   ax
         ret
;-------------------------------

close_2: push  ax       ; close mode 2 of timer chip
         mov   al, 036
         out   043, al
         xor   al, al
         out   040, al
         out   040, al
         pop   ax
         ret
;-------------------------------

rd_time: mov   al, 6    ; read timer
         out   043, al
         in    al, 040
         mov   ah, al
         in    al, 040
         xchg  al, ah
         stosw
         ret
;-------------------------------
   

Some mouse related functions.

Since this program was written to be fully mouse-operated (ditch that keybored!), the mouse must be initialised and such.
The first routine is an alternate mouse-interrupt server. The second routine installs this server and the third routine releases it from memory again.

AltMous: push  ds               ; let the mouse tell when to stop
      cs mov   ds, [DataSeg]    ; set Data segment correctly
         test  bx, bit 4                ; right button released?
         IF  Z or [Flags], StopNow      ; if so, set ABORT flag
         pop   ds
         retf                   ; and exit
;-------------------------------

SetAltMous:                     ; install AltMous interrupt routine
         push  ax, cx, dx, es
         mov   dx, offset AltMous
         mov   es, [CodeSeg]
         mov   cx, bit 4        ; routine triggers on RELEASED right button
         mov   ax, 0C
         int   033
         pop   es, dx, cx, ax
         ret
;-------------------------------

ClrAltMous:                     ; uninstall AltMous interrupt routine
         push  ax, cx
         clr   cx
         mov   ax, 0C           ; clear mask => driver disabled
         int   033
         pop   cx, ax
         ret
;-------------------------------

Key:     mov   ax, 0C07         ; wait for keypress
         int   021
         ret
;-------------------------------
   
The latter routine ('key') is used to wait for a keypress. This rouitne is only used for debugging purposes since the finalised program is FULLY mouse-controlled.

Windowing the graphics way.

What follows is the core (kernel?) of the VGAlib library. It controls the VGA card and controls how pixels are manipulated. When you do things on your own in the VGA card, you have to set colours and also define how to place pixels.

The 'H_Line' function draws horizontal ines. This can be done by plotting each pixel on it's own but that would mean that you would access most bytes in VGA memory space eight times: once for each pixel.
That can be done smarter so H_Line determines how many pixels fall in the first and last bytes of a line. Hence the rest is in adjacent bytes and we don't need to isolate the bits there.
H_Line then plots the first and last isolated pixels and next fills in the 'in-between-pixels' byte-wise.

SetMask: push  dx               ; ah = mask
         mov   dx, 03CE
         mov   al, 8
         out   dx, ax           ; set bit mask to "all on"
         pop   dx
         ret
;-------------------------------

SetColr: push  dx               ; ah = colour
         mov   dx, 03C4
         mov   al, 2
         out   dx, ax           ; select page register and colour
         pop   dx
         ret
;-------------------------------

VGaddr:  mov   es, [VGA_base]   ; calculate address in VGA memory
         mov   ax, [di.CurrY]
         add   ax, [di.Win_Y]
         call  [di.Multiply]
         mov   bx, [di.CurrX]
         add   bx, [di.Win_X]
         shr   bx, 3
         add   bx, ax           ; bx = index address
         ret
;-------------------------------

VgaPlot: mov   al, [es:bx]      ;  Do the actual plotting
         mov   al, [ToPlot]
         mov   [es:bx], al
         ret
;-------------------------------

PlotPix: push  ax, bx, cx, es   ; plot a point on screen
         call  VGaddr
         mov   cx, [di.CurrX]   ; calculate plottingmask
         add   cx, [di.Win_X]
         and   cx, 0111xB
         mov   ah, 080
         shr   ah, cl
         call  SetMask
         call  VgaPlot
         pop   es, cx, bx, ax
         ret
;-------------------------------

comment ^
           First             1  ...        ...  K           Last          : byte in video memory
       |                |               |               |                |
       |             # #|# # # # # # # #|# # # # # # # #|# # #           |
       +----------------+---------------+---------------+----------------+
                E = 2        K = 2                       L = 3                  T = 21

   E-val = 8 - ((CurrX + Win_X) AND 7)          E-mask = 0FF shr ((8 - E-val) AND 7)   
   L-val = (T - E-val) AND 7                    L-mask = 080 sar L-val
   K-val = (T - E-val - L-val)/8        ^

L0:      mov   cx, [di.DeltaX]         ; do a short line
L1:      call  PlotPix
         inc   [di.CurrX]
         loop  L1
         pop   es, cx, bx, ax
         ret

H_Line:  push  ax, bx, cx, es   ; optimized horizontal line drawing
         cmp   [di.DeltaX], 17  ; too few pixels for a bulk draw?
         jb    L0
         mov   cx, [di.CurrX]   ; do a long line
         add   cx, [di.Win_X]
         and   cx, 0111xB
         mov   bx, 8
         sub   bx, cx
         mov   [E_val], bx      ; number of pixels to plot in leftmost byte
         mov   al, 0FF
         shr   al, cl
         mov   [E_mask], al     ; set up mask for plotting leftmost pixels
         mov   cx, [di.DeltaX]
         sub   cx, [E_val]
         mov   ax, cx
         and   ax, 0111xB
         mov   [L_val], ax      ; number of pixels to plot in rightmost byte
         sub   cx, ax
         shr   cx, 3
         mov   [K_val], cx      ; number of "full" bytes to plot
         clr   al
         mov   cx, [L_val]
         cmp   cx, 0
         IF ne mov  al, bit 7
         dec   cx
         sar   al, cl
         mov   [L_mask], al     ; determine mask for last pixels
         call  VGaddr
         mov   ah, [E_mask]
         call  SetMask
         call  VgaPlot          ; plot leftmost part
         inc   bx
         mov   cx, [K_val]
         jcxz  >L4
         mov   ah, 0FF
         call  SetMask
L3:      call  VgaPlot          ; plot middle part
         inc   bx
         loop  L3
L4:      mov   ah, [L_mask]
         call  SetMask
         call  VgaPlot          ; plot remaining pixels
         mov   ax, [di.DeltaX]
         add   [di.CurrX], ax
         pop   es, cx, bx, ax
         ret
;-------------------------------

VertLin: push  cx               ; draw a vertical line
         mov   cx, [di.DeltaY]
L0:      call  PlotPix
         inc   [di.CurrY]
         loop  L0
         pop   cx
         ret
;-------------------------------

MakeWin: push  ax, cx           ; make window
         mov   ah, [di.BckCol]
         call  SetColr          ; define colour
         mov   cx, [di.Win_hgt]
         clr   ax
         mov   [di.CurrY], ax
L0:      clr   ax
         mov   [di.CurrX], ax
         mov   ax, [di.Win_wid]
         mov   [di.DeltaX], ax
         call  H_Line
         inc   [di.CurrY]
         loop  L0
         pop   cx, ax
         ret
;-------------------------------

DelWin:  push  ax, cx           ; delete window
         mov   [ToPlot], 0
         mov   ah, 0FF
         call  SetColr
         mov   cx, [di.Win_hgt]
         clr   ax
         mov   [di.CurrY], ax
L0:      clr   ax
         mov   [di.CurrX], ax
         mov   ax, [di.Win_wid]
         mov   [di.DeltaX], ax
         call  H_Line
         inc   [di.CurrY]
         loop  L0
         mov   [ToPlot], 0FF
         pop   cx, ax
         ret
;-------------------------------

MakeBox: push  ax, [di.CurrX], [di.CurrY], [di.DeltaX], [di.DeltaY]   ; make a box 
         mov   ah, [di.BoxCol]
         call  SetColr
         mov   ax, [di.Win_wid]
         mov   [di.DeltaX], ax
         mov   ax, [di.Win_hgt]
         mov   [di.DeltaY], ax
         clr   ax
         mov   [di.CurrX], ax
         mov   [di.CurrY], ax
         call  H_Line
         dec   [di.CurrX]
         call  VertLin
         mov   [di.CurrX], ax
         mov   [di.CurrY], ax
         call  VertLin
         dec   [di.CurrY]
         call  H_Line
         pop   [di.DeltaY], [di.DeltaX], [di.CurrY], [di.CurrX], ax
         ret
;-------------------------------
   

Important routines: put text on-sceen.

Now that we can place boxes on the screen, we also need to fill these boxes with characters. These characters are defined in a big array which is included into the source in the botoom line of this source. The bitmap file is called bitmap.a86.
Take a look at bitmap.a86 and try to understand it. Control this file and you control your own characterset.

The problem with plotting text is that not all letters are plot on whole byte boundaries. So an 8 pixel character can be smeared out over two bytes. I could have defined that all tokens were to be printed on whole-byte boundaries but that would have taken away just about all the chamrs of this library.

L0:      add   [di.CurrY], 16   ; process 'LF'
L1:      pop   es, si, cx, bx
         ret

L2:      mov   bx, [di.Indent]
         mov   [di.CurrX], bx   ; process 'CR'
         jmp   L1

putchar: push  bx, cx, si, es   ; print char in al at (x,y)
         cmp   al, lf
         je    L0
         cmp   al, cr
         je    L2

         mov   bx, [di.CurrX]
         add   bx, CHR_WID
         cmp   bx, [di.Win_wid]
         jbe   >L3
         mov   bx, [di.Indent]
         mov   [di.CurrX], bx   ; mimick 'CR'
         add   [di.CurrY], 16   ; mimick 'LF'

L3:      mov   cx, [di.CurrX]
         add   cx, [di.Win_X]
         and   cx, 0111xB
         mov   [C_val], cl      ; store shiftcount for masks
         mov   bx, 0FF00
         shr   bx, cl           ; setup plotting mask and ...
         mov   [P_mask], bx     ;     ... store it
         clr   ah
         mov   si, ax           ; make address of pixels in bitmap
         shl   si, 4
         add   si, offset bitmap
         call  VGaddr           ; bx = -> in video memory
         mov   ax, [P_mask]
         call  SetMask
         mov   cx, 16
L4:      push  cx
         mov   ah, [si]
         clr   al
         mov   cl, [C_val]
         shr   ax, cl
         mov   cl, [es:bx]
         mov   [es:bx], ah
         add   bx, 80
         inc   si
         pop   cx
         loop  L4
         sub   bx, 16 * 80 - 1
         mov   ax, [P_mask]
         cmp   al, 0            ; if nothing to do, ...
         je    >L6              ;    ... skip this chapter
         mov   ah, al
         call  SetMask
         mov   cx, 16
         sub   si, cx
L5:      push  cx
         mov   ah, [si]
         clr   al
         mov   cl, [C_val]
         shr   ax, cl
         mov   cl, [es:bx]
         mov   [es:bx], al
         add   bx, 80
         inc   si
         pop   cx
         loop  L5
L6:      add   [di.CurrX], CHR_WID
         jmp   L1
;-------------------------------

print:   mov   ah, [di.TxtCol]  ; print a table of text
         call  SetColr
L0:      lodsw
         cmp   ax, 0F000        ; end of table?
         je    ret
         mov   [di.CurrX], ax
         lodsw
         mov   [di.CurrY], ax
L1:      lodsb
         cmp   al, 0
         je    L0
         call  putchar
         jmp   L1
;-------------------------------

Center:  push  ax, bx, cx, dx, si       ; put a menubar on screen
         mov   ah, [di.MenuCol]         ; si = -> menu-text (ASCIIZ)
         call  SetColr
         clr   cx
         clr   bx
D0:      lodsb 
         cmp   al, 0
         je    >D2             ; zero found => end of string
         cmp   al, ' '
         jne   >D1
         inc   cx              ; increment space-counter
         jmp   D0
D1:      add   bx, CHR_WID     ; increment character count (in pixels!)
         jmp   D0

D2:      pop   si
         mov   ax, [di.Win_wid]
         sub   ax, [di.Indent]
         sub   ax, [di.Indent]
         sub   ax, [di.CurrX]
         sub   ax, bx           ; ax = # of spaces in line
         clr   dx
         div   cx
         mov   bx, ax           ; bx = empty pixels between items
D3:      lodsb
         cmp   al, ' '
         jne   >D4
         add   [di.CurrX], bx
         jmp   D3
D4:      cmp   al, 0
         je    >D5
         cmp   al, '_'
         IF  E mov  al, ' '
         call  putchar
         jmp   D3
D5:      pop   dx, cx, bx, ax
         ret
;-------------------------------

prax:    push  cx, si, ds, ax   ; print AX on (scr_x, scr_y)
         mov   ah, [di.TxtCol]
         call  SetColr
         pop   ax, es
         call  hexdec
         mov   cx, 3
         add   si, 3
         cld
L1:      lodsb
         call  putchar
         loop  L1
         pop   si, cx
         ret
;-------------------------------
   

Some additional routines.

Below are some routines used by other functions.

Show_Mouse:                     ; display mouse coordinates in special window
         push  ax, di
         mov   di, offset MX_box
         mov   [di.CurrX], 4
         mov   [di.CurrY], 2
         mov   ax, [MouseX]
         call  prax
         mov   [di.CurrX], 4
         mov   [di.CurrY], 20
         mov   ax, [MouseY]
         call  prax
         pop   di, ax
         ret
;-------------------------------

GetMous: push  ax, bx, cx, dx
         mov   ax, 3
         int   033              ; call Mouse and:
         mov   [MouseB], bx     ; store buttons, ...
         mov   [MouseX], cx     ;   ... horizontal and ...
         mov   [MouseY], dx     ;   ... vertical position.
         call  Show_Mouse
         pop   dx, cx, bx, ax
         ret
;-------------------------------

hexdec:  push  cx, dx, di       ; make hex number printable
         mov   di, offset hdc   ; ax = number in hex
         push  di, ax
         mov   cx, 6
         mov   al, ' '
         cld
         rep   stosb            ; clear ASCII buffer
         dec   di               ; point to LSB position
         mov   b [di], '0'      ; init LSB
         pop   ax
         mov   cx, 10
L0:      clr   dx
         div   cx
         add   dl, '0'
         mov   [di], dl
         dec   di
         or    ax, ax
         jnz   L0
         pop   si, di, dx, cx
         ret
;-------------------------------

L1:      add   bx, 8
         inc   [Clicker]
         jmp   >L2

L0:      pop   bx, ax
         ret

FindClick:                      ; Was this a valid click of the mouse?
         push  ax, bx           ; bx = -> klikken-tabel
         mov   bx, offset clix1
         mov   [Clicker], 0
L2:      mov   ax, [bx]
         cmp   ax, 0F0F0
         je    L0
         cmp   [MouseX], ax
         jb    L1               ; next entry
         mov   ax, [bx+2]
         cmp   [MouseY], ax
         jb    L1
         mov   ax, [bx+4]
         cmp   [MouseX], ax
         ja    L1
         mov   ax, [bx+6]
         cmp   [MouseY], ax
         ja    L1
         cmp   [MouseB], 0
         je    L0
         Piep
L3:      mov   bx, [Clicker]
         test  [Flags], PowerFlag
         jz    >L4
         cmp   bx, 7
         ja    L0
L4:      shl   bx, 1
         call  ParaMous[bx]
         jmp   L0
;-------------------------------
   

Routines to control the hardware.

The Rievo used a TLC 1549 serial Analog to Digital converter. These have a very low pincount (8 pins in total) but the data need to be clocked out one by one.
This is not difficult, but strict timing procedures must be met. Therefore these routines must be designed with great care.

The routines are PowerUp for supplying power to the ADC chip, PowDown for turning off the power, ClkLo for making the clockline LOW and Clock for generating a HIGH followed by a LOW on the clockline.
RdWord and RdFast are functions to get a result word from the ADC. RdFast may only be used when RdWord has preceeded it.

PowerUp: push  ax, dx           ; supply power to ADC
         mov   dx, [ComBase]
         add   dx, 3
         in    al, dx
         or    al, TxDBit
         jmp   $+2
         out   dx, al
         pop   dx, ax
         mov   b [ParaPowr][0], 'O'
         mov   b [ParaPowr][1], 'N'
         mov   b [ParaPowr][2], ' '
         mov   [StatIt], 1
         or    [Flags], PowerFlag + RefrPara
         ret
;-------------------------------

PowDown: push  ax, dx           ; remove power from ADC
         mov   dx, [ComBase]
         add   dx, 3
         in    al, dx
         and   al, not TxDBit
         jmp   $+2
         out   dx, al
         pop   dx, ax
         mov   b [ParaPowr][0], 'O'
         mov   b [ParaPowr][1], 'F'
         mov   b [ParaPowr][2], 'F'
         mov   [StatIt], 0
         and   [Flags], not PowerFlag
         or    [Flags], RefrPara
         ret
;-------------------------------

ClkLo:   push  ax, dx           ; Set ADC clock Low
         mov   dx, [ComBase]
         add   dx, 4
         in    al, dx
         and   al, not ClkBit
         jmp   $+2
         out   dx, al
         mov   [clk_bit], al
         pop   dx, ax
         ret
;-------------------------------

clock:   mov   ah, al
         sub   dx, 2
         mov   al, [clk_bit]
         xor   al, ClkBit
         out   dx, al
         xor   al, ClkBit
         jmp   $+2
         out   dx, al
         add   dx, 2
         mov   al, ah
         ret
;-------------------------------

RdWord:  cli
         push  cx, dx
         mov   dx, [ComBase]    ; read in one 10-bit word from ADC
         add   dx, 6
         mov   cx, bit 6        ; set end-point
L0:      in    al, dx           ; get bit, ...
         call  clock
         shl   al, 3            ; ... isolate it, ...
         rcl   cx, 1            ; ... rotate it into buffer, ...
         jnc   L0               ; ... until done.
         mov   ax, cx
         pop   dx, cx
         sti
         ret                    ; with result in ax
;-------------------------------

RdFast:  mov   bx, bit 6        ; set end-point
L0:      in    al, dx           ; get bit, ...
         call  clock
         shl   al, 3            ; ... isolate it, ...
         rcl   bx, 1            ; ... rotate it into buffer, ...
         jnc   L0               ; ... until done.
         mov   ax, bx
         stosw                  ; and store it
         ret                    ; with result in ax
;-------------------------------
   

Some more 'glue' routines.

FindPort:                       ; find ComBase for ComNr
         push  bx, es
         mov   bx, [ComNr]
         shl   bx, 1
         add   bx, 0400
         mov   es, [ZeroSeg]
      es mov   ax, [bx]
         pop   es, bx
         ret
;-------------------------------

RelButt: call  GetMous           ; wait until Mouse Button released
         cmp   [MouseB], 0
         jne   RelButt
         ret
;-------------------------------

L0:      call  RelButt
         pop   dx, cx, bx, ax
         ret

DoSave:  push  ax, bx, cx, dx           ; save settings to CFG file
         mov   dx, offset CFG_file
         clr   cx
         mov   ah, 03C
         int   021              ; create CFG file
         jc    L0
         mov   [Handle], ax
         mov   dx, offset Flags
         mov   cx, offset FSval + 2
         sub   cx, dx
         mov   bx, [Handle]
         mov   ah, 040
         int   021              ; save important data to file
         mov   bx, [Handle]
         mov   ah, 03E
         int   021              ; close CFG file
         jmp   L0
;-------------------------------
comment ^

L0:      pop   dx, cx, bx, ax
         ret

SaveDef: push  ax, bx, cx, dx           ; save settings to DEF file
         mov   dx, offset DEF_file
         clr   cx
         mov   ah, 03C
         int   021              ; create CFG file
         jc    L0
         mov   [Handle], ax
         mov   dx, offset Flags
         mov   cx, offset FSval + 2
         sub   cx, dx
         mov   bx, [Handle]
         mov   ah, 040
         int   021              ; save important data to file
         mov   bx, [Handle]
         mov   ah, 03E
         int   021              ; close CFG file
         jmp   L0
;-------------------------------

L0:      pop   dx, cx, bx, ax
         ret

LoadDef: push  ax, bx, cx, dx
         mov   dx, offset DEF_file
         mov   ax, 03D00
         int   021              ; open CFG file
         jc    L0
         mov   [Handle], ax
         mov   dx, offset Flags
         mov   cx, offset RefrCnt
         sub   cx, dx
         mov   bx, [Handle]
         mov   ah, 03F
         int   021              ; read in critical data
         mov   bx, [Handle]
         mov   ah, 03E
         int   021              ; close CFG file
         call  UpDate
         jmp   L0
;-------------------------------        ^

L2:      pop   dx, cx, bx, ax
         ret

DoLoad:  push  ax, bx, cx, dx
         mov   dx, offset CFG_file
         mov   ax, 03D00
         int   021              ; open CFG file
         jc    L2
         mov   [Handle], ax
         mov   dx, offset Flags
         mov   cx, offset RefrCnt
         sub   cx, dx
         mov   bx, [Handle]
         mov   ah, 03F
         int   021              ; read in critical data
         mov   bx, [Handle]
         mov   ah, 03E
         int   021              ; close CFG file
         call  UpDate
         call  RelButt
         jmp   L0
;-------------------------------
   

Controlling the user interface options.

SetStat: push  cx, si, di               ; update "Status" field
         mov   si, [StatIt]
         shl   si, 3
         add   si, offset SamStat
         mov   di, offset ParaStat
         mov   cx, 8
         rep   movsb
         pop   di, si, cx
         ret
;-------------------------------

L0:      call  RelButt
         or    [Flags], RefrPara
L1:      call  ParRfsh
         pop   di, si, cx
         ret

SetStrt: push  cx, si, di
         mov   ax, [StartIt]
         test  [Flags], JustUpd8          ; just refreshing?
         jnz   >L2
         test  [MouseB], LftButton + RgtButton
         IF  Z jmp  L1
         test  [MouseB], LftButton
         IF NZ inc  ax
         test  [MouseB], RgtButton
         IF NZ dec  ax
         cmp   ax, 6
         IF E  clr  ax
         cmp   ax, 0FFFF
         IF E  mov  ax, 5
         mov   [StartIt], ax
L2:      shl   ax, 3
         mov   si, offset TrigStrt
         add   si, ax
         mov   di, offset ParaStrt
         mov   cx, 8
         mov   es, ds
         rep   movsb
         jmp   L0
;-------------------------------

UpDate:  push  ax, bx, cx, si, di
         or    [Flags], JustUpd8        ; SIGNAL: update only
         test  [Flags], PowerFlag
         jnz   >L0
         mov   b [ParaPowr][1], 'F'
         mov   b [ParaPowr][2], 'F'
         jmp   >L1
L0:      mov   b [ParaPowr][1], 'N'
         mov   b [ParaPowr][2], ' '
L1:      mov   ax, [ComNr]
         add   al, '1'
         mov   [ParaCom], al
         call  ShowFS
         mov   ax, [Vref]
         mov   di, offset ParaVref
         call  hexdec           ; update after reloading settings
         add   si, 2
         movsb
         Store ','
         movsb
         movsb
         movsb
         mov   ax, [Scale]
         mov   di, offset ParaScal
         call  hexdec           ; update after reloading settings
         add   si, 3
         movsb
         Store ','
         movsb
         movsb
         mov   ax, [SmpRate]
         mov   di, offset ParaRate
         call  hexdec
         inc   si
         mov   cx, 5
         rep   movsb
         Store ' '
         Store 'S'
         Store 'p'
         Store 's'
         mov   ax, [GroupS]
         call  hexdec
         add   si, 4
         mov   di, offset ParaGrup
         mov   cx, 2
         rep   movsb
         call  SetStrt
         call  SetStop
         call  SetSpd
         call  SetUnit
         call  SetMode
         or    [Flags], RefrPara
         call  ParRfsh
         and   [Flags], not JustUpd8      ; end of update
         pop   di, si, cx, bx, ax
         ret
;-------------------------------

Trigger: ret                            ; wait for trigger event to happen
;-------------------------------

L0:      call  RelButt
         ret

WinClr:  test  [MouseB], LftButton + RgtButton
         jz    L0
         push  di
         mov   di, offset PlotWin2
         call  DelWin
         pop   di
         jmp   L0
;-------------------------------

PlotDot: push  di                       ; plot dot on screen, value in AX
         mov   di, offset PlotWin2
         shr   ax, 2
         neg   ax
         add   ax, [di.Win_hgt]
         mov   [di.CurrY], ax
         mov   ah, [di.TxtCol]
         call  SetColr
         call  PlotPix
         inc   [di.CurrX]
         cmp   [di.CurrX], 512 + 50
         IF NB or  [Flags], StopNow
         pop   di
         ret
;-------------------------------

L2:      and   [Flags], not Running     ; disable sampling during INT 1C
         call  ClrAltMous               ; disable mouse interrupt
         call  PowDown                  ; ADC off
         ret

L0:      call  RelButt
         ret

DoRun:   test  [MouseB], LftButton
         jz    L0
         call  PowerUp          ; switch ADC on
         call  RdWord           ; retrieve bogovalue
         call  RelButt          ; make sure no mouse button depressed anymore
         clr   ax
         mov   [AdcCount], ax
         mov   [RunTotal], ax
         mov   [Counter], ax
         mov   [PlotWin2.CurrX], 50
         test  [Flags], TrigWait        ; wait for trigger?
         IF NZ call  Trigger
         and   [Flags], not StopNow     ; clear StopNow flag 
         call  SetAltMous               ; install mouse interruptor AND GO
         or    [Flags], Running
L1:      test  [Flags], StopNow         ; mouse button pressed?
         jnz   L2                       ;   if so, stop sampling
         test  [Flags], TimeOut         ; time to take a sample?
         jz    L1                       ;   if not, wait for it
         and   [Flags], not TimeOut     ; reset TimeOut flag
         call  RdWord                   ; get value from ADC
         mov   [BarVal.Now], ax         ; use this value for the bargraph
         inc   [AdcCount]
         add   ax, [RunTotal]           ; summ it up
         mov   [RunTotal], ax           ; store it
         mov   cx, [AdcCount]           ; group filled up yet?
         cmp   cx, [GroupS]
         jb    L1                       ; if not, loop back
         mov   cx, [ShiftIt]            ; else prepare to ...
         cmp   cx, 0
         IF NZ shr  ax, cl              ; ... average it
         mov   [AvgVal], ax             ; store average for plotting and digital readout
         call  PlotDot                  ; and plot it in the Plotting Window
         clr   ax
         mov   [RunTotal], ax           ; reset running total ...
         mov   [AdcCount], ax           ; ... and current count
         test  [Flags], RefrshBar
         IF NZ call  ShowBar
         test  [Flags], RefrshDig
         IF NZ call  ShowDig
         and   [Flags], not (RefrshDig + RefrshBar)
         jmp   L1                       ; and do some more waiting
;-------------------------------

L0:      call  RelButt          ; wait
;         call  SaveDef          ; save current settings
         pop   ax               ; adjust stack
         jmp   exit             ; and exit

DoQuit:  test  [MouseB], RgtButton      ; exit to DOS
         jnz   L0                       ; right button pressed?
         call  RelButt                  ; if not, wait
         ret                            ; and return
;-------------------------------

SetFile: ret
;-------------------------------

L0:      mov   [ComBase], ax
         mov   ax, [ComNr]
         add   al, '1'
         mov   [ParaCom], al
         or    [Flags], RefrPara
L2:      call  RelButt          ; wait until button is released
         call  ParRfsh          ; refresh screen
         ret                    ; and exit

SetComm: test  [Flags], JustUpd8          ; just refreshing?
         jnz   >L1
         test  [MouseB], LftButton
         jz    L2
         inc   [ComNr]
L1:      call  FindPort
         cmp   ax, 0
         jne   L0
         mov   [ComNr], ax
         jmp   L1
;-------------------------------

L0:      call  PowDown
L1:      call  ParRfsh
L2:      call  RelButt
         ret

SetPowr: test  [MouseB], LftButton
         jz    L2
         test  [Flags], PowerFlag       ; is it "ON "?
         jnz   L0
         call  PowerUp
         jmp   L1
;-------------------------------

L0:      call  RelButt
         or    [Flags], RefrPara
L1:      call  ParRfsh
         pop   di, si, cx
         ret

SetStop: push  cx, si, di
         mov   ax, [StopIt]
         test  [Flags], JustUpd8          ; just refreshing?
         jnz   >L2
         test  [MouseB], LftButton + RgtButton
         IF  Z jmp  L1
         test  [MouseB], LftButton
         IF NZ inc  ax
         test  [MouseB], RgtButton
         IF NZ dec  ax
         cmp   ax, 7
         IF E  clr  ax
         cmp   ax, 0FFFF
         IF E  mov  ax, 6
         mov   [StopIt], ax
L2:      shl   ax, 3
         mov   si, offset TrigStop
         add   si, ax
         mov   di, offset ParaStop
         mov   cx, 8
         mov   es, ds
         rep   movsb
         jmp   L0
;-------------------------------

SetSpd:  push  ax, cx, si, di
         mov   ax, [SmpRate]    ; ax = nr of samples per second
         mov   cx, [GroupS]     ; cx = nr of samples per group
         cmp   ax, cx
         IF  B xchg  ax, cx     ; swap params if necessary
         clr   dx
         div   cx
         mov   [MathRate], ax    ; store MATHEMATICAL samplerate
         call  hexdec
         inc   si
         mov   di, offset ParaSpd
         mov   cx, 5
         rep   movsb
         mov   al, '/'
         mov   cx, [SmpRate]
         cmp   cx, [GroupS]
         IF  B mov  al, ' '
         stosb
         or    [Flags], RefrPara
         pop   di, si, cx, ax
         ret
;-------------------------------
   

Build the four '7 segment digits' and the bargraph.

DoDigit: push  bx, cx, si, es           ; display digit in al to screen.
         mov   [DigBuff+4][bx], al      ; store new value for later
         push  ax
         mov   ah, [di.BckCol]
         call  SetColr
         mov   ah, 0FF
         call  Setmask
         mov   es, [VGA_base]   ; calculate address in VGA memory
         mov   ax, [di.Win_Y]
         call  [di.Multiply]
         mov   bx, [di.Win_X]
         shr   bx, 3
         add   bx, ax           ; es:bx = index address
         mov   [VidPoint], bx   ; store bx pointer
         pop   ax
         sub   al, '0'
         IF  C mov  al, 10      ; if SPACE, use "rub out pattern"
         clr   ah
         mov   cx, 10
         mul   cx
         mov   si, ax
         add   si, offset DigMap
L0:      push  cx
         mov   cx, 4
         lodsb                  ; get bitpattern
L1:      push  cx
         clr   ah
         shl   ax, 2
         push  ax               ; save for later
         xchg  ah, al
         mov   bx, offset BitTable
         xlat                   ; al = bit pattern
         mov   bx, [VidPoint]
         mov   cx, 4
L2:      mov   ah, [es:bx]
         mov   [es:bx], al
         add   bx, 80
         loop  L2               ; 4 fractions plotted
         sub   bx, 320 - 1      ; point to next V-ram address
         mov   [VidPoint], bx
         pop   ax, cx
         loop  L1
         add   bx, 320 - 4
         mov   [VidPoint], bx
         pop   cx
         loop  L0
         pop   es, si, cx, bx
         ret
;-------------------------------

DelDig:  push  ax, bx, cx, es   ; delete digit, optimized for speed
         mov   ah, 0FF
         call  SetColr          ; erase all bitplanes
         mov   ah, 0FF
         call  SetMask          ; use eight bits per byte
         mov   es, [VGA_base]   ; calculate address in VGA memory
         mov   ax, [di.Win_Y]
         call  [di.Multiply]
         mov   bx, [di.Win_X]
         shr   bx, 3
         add   bx, ax           ; bx = index address
         mov   cx, 40
         clr   al
L0:      push  cx
         mov   cx, 4
L1:      mov   ah, [es:bx]
         mov   [es:bx], al
         inc   bx
         loop  L1
         add   bx, 80 - 4
         pop   cx
         loop  L0
         pop   es, cx, bx, ax
         ret
;-------------------------------

L0: ;     and   [Flags], not Upd8Digs
         pop   di, si, cx, bx, ax
         ret

ShowDig: test  [Flags], Upd8Digs         ; Put actual value on screen
         jz    ret
         push  ax, bx, cx, si, di
;         mov   ax, [AvgVal.Now]
;         cmp   ax, [AvgVal.Prev]        ; same as before?
;         je    L0                       ; if so, quit
;         mov   [AvgVal.Prev], ax        ; else update .Prev
;         mov   ax, [AvgVal]     ; get avg Count [0..1023]
         mov   ax, [BarVal.Now]
         mul   [Vref]           ; make mV's     [0..5.250.000]
         shl   dx, 6 
         shr   ax, 10
         or    ax, dx           ; = divide by 1024  [0..5.100]
         mul   [Scale]
         mov   si, 100
         div   si               ; correct for hardware [0..25.000]

         mov   [ThisVal.Now], ax    ; store result
         call  hexdec               ; convert Ax value
         inc   si
         mov   di, offset DigSpac2
         mov   [di.BckCol], 14
         cmp   [ThisVal.Now], 9999  ; 4 or 5 digit value?
         ja    >L1
         inc   si                   ; if 4 digits, skip over leading space
         cmp   [ThisVal.Prev], 9999
         IF  A call  DelDig         ; if necessary, erase old colour
         mov   [di.BckCol], 12
L1:      mov   di, offset DigBuff   ; store results
         mov   cx, 4
L2:      lodsb
         cmp   al, ' '
         IF  E mov  al, '0'             ; cvt all spaces to zero's
         stosb
         loop  L2
         mov   ax, [ThisVal.Now]
         mov   [ThisVal.Prev], ax
         clr   bx                       ; set up index pointer
         mov   di, offset DigSpac1
         mov   al, [DigBuff][bx]
         cmp   al, [DigBuff+4][bx]      ; same as current digit?
         IF NE call DoDigit
         inc   bx
         mov   di, offset DigSpac2
         mov   al, [DigBuff][bx]
         cmp   al, [DigBuff+4][bx]      ; same as current digit?
         IF NE call DoDigit
         inc   bx
         mov   di, offset DigSpac3
         mov   al, [DigBuff][bx]
         cmp   al, [DigBuff+4][bx]      ; same as current digit?
         IF NE call DoDigit
         inc   bx
         mov   di, offset DigSpac4
         mov   al, [DigBuff][bx]
         cmp   al, [DigBuff+4][bx]      ; same as current digit?
         IF NE call DoDigit
         jmp   L0
;-------------------------------

PlotSeg: push  ax, bx, cx, es   ; plot one segment of the BarGraph
         mov   cx, [di.CurrX]   ; calculate plottingmask
         add   cx, [di.Win_X]
         mov   bx, cx           ; save copy for later
         and   cx, 0111xB
         mov   ah, 080
         shr   ah, cl           ; determine bit to plot
         call  SetMask          ; set mask
         mov   es, [VGA_base]   ; calculate address in VGA memory
         mov   ax, [di.CurrY]
         add   ax, [di.Win_Y]
         call  [di.Multiply]
         shr   bx, 3            ; bx = CurrX + Win_X / 8
         add   bx, ax           ; bx = index address in VGA memory
         mov   cx, BarLines
         mov   al, [ToPlot]
L1:      mov   ah, [es:bx]      ;  Do the actual plotting
         mov   [es:bx], al
         add   bx, 80
         loop  L1
         add   [di.CurrX], 2
         pop   es, cx, bx, ax
         ret
;-------------------------------

L0:      pop   di, cx, bx, ax
         ret

ShowBar: push  ax, bx, cx, di           ; Put bargraph display on screen
         mov   ax, [BarVal.Now]         ; get ADC-count [0..1023]
         cmp   ax, [BarVal.Prev]
         je    L0                       ; current value same as previous value?
         mov   [BarVal.Prev], ax        ; store new value of "Previous"
         shr   ax, 2                    ; cvt ADC-count to [0..255]
         mov   [Segments.Now], ax       ; ... store value
         cmp   ax, [Segments.Prev]
         je    L0                       ; if same Bar-length, exit
         mov   di, offset DisplBar      ; else, ... 
         mov   ah, [di.BckCol]
         call  SetColr                  ; ... set colour, and ...
         mov   ax, [Segments.Now]       ; restore current value
         cmp   ax, [Segments.Prev]      ; is new val above/below previous one?
         ja    >L2                      ; if ax > Segments, fill up bar
         mov   cx, [Segments.Prev]      ; else erase superfluous segments
         sub   cx, ax                   ; calculate count
         shl   ax, 1                    ; correct for bar-type
         mov   [di.CurrX], ax           ; store coordinates
         mov   [di.CurrY], 0
         mov   [ToPlot], 0              ; determine plot/ERASE
L1:      call  PlotSeg                  ; plot the bar-line
         loop  L1
         mov   [ToPlot], 0FF            ; determine PLOT/erase
         jmp   >L4

L2:      mov   cx, ax
         mov   bx, [Segments.Prev]
         sub   cx, bx                   ; determine COUNT
         shl   bx, 1
         mov   [di.CurrX], bx           ; store coordinates
         mov   [di.CurrY], 0
L3:      call  PlotSeg
         loop  L3

L4:      mov   ax, [Segments.Now]
         mov   [Segments.Prev], ax      ; remember current bar-length
         test  [Flags], RfrshBar        ; time to refresh the bar-markers?
         jz    L0                       ; if not, exit
         mov   cx, 4
         mov   [di.CurrY], BarLines
L5:      push  cx
         mov   [di.CurrX], 0
         mov   cx, 6
L6:      call  PlotPix
         inc   [di.CurrX]
         call  PlotPix
         add   [di.CurrX], 101
         loop  L6
         inc   [di.CurrY]
         pop   cx
         loop  L5
         and   [Flags], not RfrshBar
         jmp   L0
;-------------------------------

BrScale: push  ax, cx, di             ; make a scale on the Bar Graph
         mov   di, offset DisplBar
         mov   ah, [di.BckCol]
         call  SetColr
         mov   cx, 4
         mov   [di.CurrY], BarLines
L5:      push  cx
         mov   [di.CurrX], 0
         mov   cx, 6
L6:      call  PlotPix
         inc   [di.CurrX]
         call  PlotPix
         add   [di.CurrX], 101
         loop  L6
         inc   [di.CurrY]
         pop   cx
         loop  L5
         and   [Flags], not RfrshBar
         pop   di, cx, ax
         ret
;-------------------------------
   

Enable the user to set Vref/Scale by means of sliders.

ShowVref:                       ; Show actual value of V-ref pointer
         push  cx, dx, si, di
         call  GetMous
         mov   ax, [MouseX]
         sub   ax, [di.Win_X]
         add   ax, 4750 - 20    ; make millivolts
         mov   dx, ax
         call  hexdec           ; si = -> ASCII buffer
         add   si, 2
         mov   cx, si           ; store si for later
         mov   di, offset VrefIs
         movsb                  ; store results in Vref window
         Store ','
         movsb
         movsb
         movsb
         pop   di                   ; restore colour info
         mov   si, offset VrefSet
         call  print                ; print in SetVref window
         test  [MouseB], LftButton  ; if right button pressed, exit
         jz    >L0
         push  di
         mov   si, cx               ; get old SI
         mov   di, offset ParaVref
         movsb                      ; store results in Parameters window
         Store ','
         movsb
         movsb
         movsb
         mov   [Vref], dx
         pop   di
         or    [Flags], RefrPara
L0:      pop   si, dx, cx
         ret
;-------------------------------

ParRfsh: test  [Flags], RefrPara + JustUpd8
         jz    ret
         push  si, di
         call  SetStat
         mov   di, offset ParWin      ; refresh parameter screen
         mov   si, offset params
         call  print
         call  ShowBar
         and   [Flags], not RefrPara
         pop   di, si
         ret
;-------------------------------

ShowScale:                      ; Show actual value of Scale-pointer
         push  cx, dx, si, di
         call  GetMous
         mov   ax, [MouseX]
         sub   ax, [di.Win_X]
         sub   ax, 20           ; make scalefactor
         mov   dx, ax
         call  hexdec           ; si = -> ASCII buffer
         add   si, 3
         mov   cx, si           ; store si for later
         mov   di, offset ScaleIs
         lodsb
         cmp   al, ' '
         IF  E mov  al, '0'
         stosb
         Store ','
         lodsb
         cmp   al, ' '
         IF  E mov  al, '0'
         stosb
         movsb
         pop   di                   ; restore colour info
         mov   si, offset ScalSet
         call  print                ; print in SetVref window
         test  [MouseB], LftButton  ; if right button pressed, exit
         jz    >L0
         push  di
         mov   si, cx               ; get old SI
         mov   di, offset ParaScal
         lodsb                      ; store results in Parameters window
         cmp   al, ' '
         IF  E mov  al, '0'
         stosb
         Store ','
         lodsb
         cmp   al, ' '
         IF  E mov  al, '0'
         stosb
         movsb
         mov   [Scale], dx
         pop   di
         or    [Flags], RefrPara
L0:      pop   si, dx, cx
         ret
;-------------------------------

MakeAxis:                       ; make nice dented horizontal axis
         push  ax, cx, dx
         mov   dx, [di.CurrY]
         mov   [di.DeltaY], 8
         mov   ax, [TotalDiv]
         div   b [SubDiv]
         mov   cx, ax
L0:      push  cx
         call  VertLin
         mov   cx, [SubDiv]
         shr   cx, 1
L1:      call  PlotPix
         add   [di.CurrX], 2
         loop  L1
         mov   [di.CurrY], dx
         pop   cx
         loop  L0
         mov   [di.CurrY], dx
         call  VertLin
         pop   dx, cx, ax
         ret
;-------------------------------

ShowFS:  push  ax, bx, dx, si, di  ; show Full Scale on screen
         pushf
         mov   ax, [Scale]
         mul   [Vref]
         mov   bx, 100
         div   bx                  ; ax = Full Scale voltage
         mov   [FSval], ax
         call  hexdec
         add   si, 4
         mov   di, offset ParaFull + 4
         std
         movsb
         movsb
         Store ','
         lodsb
         cmp   al, ' '
         IF  E mov  al, '0'
         stosb
         movsb
         or    [Flags], RefrPara
         popf
         pop   di, si, dx, bx, ax
         ret
;-------------------------------

SetVref: test  [MouseB], LftButton      ; set V-reference
         jz    ret                      ; if nothing to do, get out
         push  ax, cx, dx, si, di
         or    [Flags], RfrshBar        ; signal: REFRESH needed
         mov   [Segments.Prev], 0
         mov   [BarVal.Prev], 0
         call  RelButt                  ; wait for button release
         mov   di, offset VrefBar
         HideMouse
         call  DelWin           ; erase old contents
         call  MakeWin          ; make new background
         call  MakeBox          ; fancy lines
         push  [MouseX], [MouseY]
         mov   cx, [di.Win_X]
         mov   dx, cx
         add   cx, 20
         add   dx, [di.Win_wid]
         sub   dx, 20
         mov   ax, 7
         int   033              ; set horizontal boundaries
         mov   cx, [di.Win_Y]
         add   cx, 33
         mov   dx, cx
         mov   ax, 8
         int   033              ; set vertical boundaries
         mov   cx, [di.Win_X]
         add   cx, [Vref]
         sub   cx, 4750 - 20
         mov   dx, [di.Win_Y]
         add   dx, 33
         mov   ax, 4
         int   033              ; set mouse cursor
         mov   si, offset VrefSet
         call  print
         mov   [di.CurrX], 20
         mov   [di.CurrY], 25
         mov   [SubDiv], 50
         mov   [TotalDiv], 500
         call  MakeAxis
         ShowMouse
L0:      call  ShowVref
         test  [MouseB], LftButton + RgtButton
         jz    L0
         call  RelButt
         HideMouse              ; to prevent odd blocks popping up
         mov   cx, 0
         mov   dx, 639
         mov   ax, 7
         int   033              ; mouse boundaries back ...
         mov   cx, 0
         mov   dx, 479
         mov   ax, 8
         int   033              ;     ... to normal
         pop   dx, cx
         mov   ax, 4
         int   033
         call  DelWin
         or    [Flags], Upd8Digs
         mov   w [DigBuff][4], '  '
         mov   w [DigBuff][6], '  '     ; clear out DigBuff.Prev
         call  ShowFS
         call  ParRfsh
         ShowMouse              ; show the mouse again
         pop   di, si, dx, cx, ax
         ret
;-------------------------------

SetScal: test  [MouseB], LftButton      ; set scale factor
         jz    ret                      ; if nothing to do, get out
         push  ax, cx, dx, si, di
         or    [Flags], RfrshBar
         mov   [Segments.Prev], 0
         mov   [BarVal.Prev], 0
         call  RelButt                  ; wait for button release
         mov   di, offset ScaleBar
         HideMouse
         call  DelWin           ; erase old contents
         call  MakeWin          ; make new background
         call  MakeBox          ; fancy lines
         push  [MouseX], [MouseY]
         mov   cx, [di.Win_X]
         mov   dx, cx
         add   cx, 20 + 18
         add   dx, [di.Win_wid]
         sub   dx, 20
         mov   ax, 7
         int   033              ; set horizontal boundaries
         mov   cx, [di.Win_Y]
         add   cx, 33
         mov   dx, cx
         mov   ax, 8
         int   033              ; set vertical boundaries
         mov   cx, [di.Win_X]
         add   cx, [Scale]
         add   cx, 20
         mov   dx, [di.Win_Y]
         add   dx, 33
         mov   ax, 4
         int   033              ; set mouse cursor
         mov   si, offset ScalSet
         call  print
         mov   [di.CurrX], 20
         mov   [di.CurrY], 25
         mov   [SubDiv], 100
         mov   [TotalDiv], 500
         call  MakeAxis
         ShowMouse
L0:      call  ShowScale
         test  [MouseB], LftButton + RgtButton
         jz    L0
         call  RelButt
         HideMouse              ; to prevent odd blocks popping up
         mov   cx, 0
         mov   dx, 639
         mov   ax, 7
         int   033              ; mouse boundaries back ...
         mov   cx, 0
         mov   dx, 479
         mov   ax, 8
         int   033              ;     ... to normal
         pop   dx, cx
         mov   ax, 4
         int   033
         call  DelWin
         call  ShowFS
         or    [Flags], Upd8Digs
         mov   w [DigBuff][4], '  '
         mov   w [DigBuff][6], '  '     ; clear out DigBuff.Prev
         call  ParRfsh
         ShowMouse              ; show the mouse again
         pop   di, si, dx, cx, ax
         ret
;-------------------------------
   

Control some more options on screen and update screen.

L1:      mov   [SmpRate], ax
         call  hexdec
         inc   si
         mov   di, offset ParaRate
         mov   cx, 5
         rep   movsb
         mov   ax, 'S '
         stosw
         mov   ax, 'sp'
         stosw
         or    [Flags], RefrPara
         call  SetSpd
         call  ParRfsh
L2:      call  RelButt
         pop   di, si, cx
         ret

SetRate: push  cx, si, di
         test  [MouseB], LftButton + RgtButton
         jz    L2
         mov   ax, [SmpRate]
         test  [MouseB], LftButton      ; if LEFT button, ...
         jz    >L5
         shl   ax, 1                    ;    ... double the rate
         jmp   >L6
L5:      shr   ax, 1                    ; if RIGHT button, ...
L6:      cmp   ax, 0                    ; if too low, ...
         jne   >L3
         mov   ax, 1                    ;    ... fill with lowest value
         jmp   L1

L3:      cmp   ax, [MaxRate.Prev]       ; if MaxRate, ...
         jna   >L4
         mov   ax, [MaxRate]            ;    ... fill it in
         jmp   L1

L4:      mov   si, [MaxRate]            ; if below MaxRate,
         shr   si, 1
         cmp   ax, si
         IF E  mov  ax, [MaxRate.Prev]  ; switch to multiples of 2
         jmp   L1
;-------------------------------

L0:      mov   [GroupS], ax
         call  hexdec
         add   si, 4
         mov   di, offset ParaGrup
         mov   cx, 2
         rep   movsb
         or    [Flags], RefrPara
         call  SetSpd
         call  ParRfsh

L1:      call  RelButt
         pop   di, si, cx
         ret

L2:      shr   ax, 1            ; so it is the right button!
         dec   [ShiftIt]
         cmp   ax, 0
         ja    L0
         mov   ax, 1
         mov   [ShiftIt], 0
         jmp   L0

SetGrup: push  cx, si, di
         test  [MouseB], LftButton + RgtButton
         jz    L1
         mov   ax, [GroupS]
         test  [MouseB], LftButton
         jz    L2
         shl   ax, 1
         inc   [ShiftIt]
         cmp   ax, MaxGroup
         jbe   L0
         mov   ax, MaxGroup
         mov   [ShiftIt], MaxShift
         jmp   L0
;-------------------------------

L0:      call  RelButt
         pop   si, cx
         ret

SetUnit: push  cx, si
         test  [Flags], JustUpd8
         jnz   >L1
         test  [MouseB], LftButton + RgtButton
         jz    L0
L1:      mov   ax, [UnitIt]
         test  [MouseB], LftButton
         IF NZ inc  ax
         test  [MouseB], RgtButton
         IF NZ dec  ax
         and   ax, 011xB
         mov   [UnitIt], ax
         mov   si, offset Unitsss
         add   si, ax
         mov   al, [si]
         mov   [ParaUnit], al
         or    [Flags], RefrPara
         call  ParRfsh
         jmp   L0
;-------------------------------

L0:      call  RelButt          ; wait till buttons released
         pop   di, si, cx       ; and get out
         ret

SetMode: push  cx, si, di
         test  [Flags], JustUpd8                ; just updating?
         jnz   >L1                              ; if so, skip the buttons part
         test  [MouseB], LftButton + RgtButton  ; Button pressed?
         jz    L0                               ; if not, exit
L1:      mov   ax, [ModeIt]             ; get current value
         test  [MouseB], LftButton      ; how to change?
         IF NZ inc  ax
         test  [MouseB], RgtButton
         IF NZ dec  ax
         cmp   ax, 4                    ; out of bounds?
         IF  E clr  ax
         cmp   ax, 0FFFF
         IF  E mov  ax, 3
         mov   [ModeIt], ax
         mov   cx, ax
         shl   ax, 3
         add   ax, cx           ; multiply by 9
         mov   si, offset DispMode
         add   si, ax
         mov   di, offset ParaMode
         mov   cx, 9
         rep   movsb
         or    [Flags], RefrPara
         call  ParRfsh
         jmp   L0
;-------------------------------

FillScreen:
         mov   di, offset fullscrn
         call  MakeBox                  ; compose main frame
         mov   di, offset PlotWin
         call  MakeBox                  ; make parameters windows
         mov   di, offset ParWin2
         call  MakeBox                  ; make plotting window
         mov   di, offset BotBar
         mov   si, offset copyleft
         call  Center                   ; print copyrights
         mov   di, offset TopBar
         mov   si, offset MenuBar
         call  Center                   ; print menu bar
         call  ShowFS
         call  ParRfsh
         ret
;-------------------------------
   

Timing part I: slow signals.

Tune_W8: push  ax, bx, cx, dx, si, di   ; calibrate the wait-loop 
         mov   [Delay], 419
         mov   di, offset time
         mov   si, di
         mov   [TrialRun], offset DoZip
         call  open_2           ; open hi res timer.
         mov   cx, 16           ; repeat 16 times
L0:      call  rd_time          ; read timer, ...
         call  DoW8             ; ... wait specified time, and ...
         call  rd_time          ; ... read timer again
         loop  L0               ; until 16 done
         call  close_2          ; close hi res timer
         mov   cx, 16
         xor   bx, bx           ; bx = total
L1:      lodsw                  ; get "start" count,
         mov   dx, ax           ; store it
         lodsw                  ; get "end" count, 
         sub   dx, ax           ; determine "time spent"
         add   bx, dx           ; sum it all up
         loop  L1               ; until done
         add   bx, 8
         shr   bx, 4
         mov   ax, 500          ; get current value
         mul   [ShouldBe]
         div   bx               ; compose better value
         cmp   ax, 0
         IF  E inc  ax          ; compensate for very  S  L  O  W  machines....
         mov   [Delay], ax      ; store new value
         pop   di, si, dx, cx, bx, ax
         ret
;------------------------

DoW8:    push  cx               ; timing routine
         mov   cx, [Delay]
L0:      call  [TrialRun]
         loop  L0
         pop   cx
         ret
;-------------------------------

ChkTime: push  si, di
         mov   [Delay], 250     ; initialize at 250 loop count
         mov   di, offset time
         mov   si, di
         call  open_2
         mov   dx, [ComBase]    ; read in one 10-bit word from ADC
         add   dx, 6
         mov   [TrialRun], RdFast
         call  rd_time          ; store (a) value
         push  di
         call  DoW8
         pop   di
         call  rd_time          ; store (b) value
         mov   [TrialRun], DoZip
         call  rd_time          ; store (c) value
         push  di
         call  DoW8
         pop   di
         call  rd_time          ; store (d) value
         call  close_2
ddd:     lodsw                  ; get startvalue (a)
         mov   bx, ax           ; store it
         lodsw
         sub   bx, ax           ; subtract long-done value (b)
         lodsw
         sub   ax, [si]
         sub   bx, ax           ; bx = time until completion (a-b)-(c-d)
         clr   dx
         mov   ax, bx           ; store it in DX:AX
         mov   bx, 298          ; divisor for time-in-s
         div   bx               ; ax = time in s to complete ONE RdWord
         mov   [OneShot], ax    ; store it
         pop   di, si
         ret
;-------------------------------
   

Timing part II: sample speed and sample time.

MaxSpS:  push  ax, bx, dx       ; determine maximum sample speed
         mov   dx, 15
         mov   ax, 16960        ; DX:AX = 1.000.000 [s/s]
         mov   bx, [OneShot]
         div   bx               ; AX = maximum sample rate
         mov   [MaxRate], ax
         clr   cl
L0:      inc   cl               ; increment shiftcount
         shr   ax, 1            ; shift right
         jnz   L0               ; until AX empty
         dec   cl
         mov   ax, 1
         shl   ax, cl           ; AX = 2nd highest sample rate
         mov   [MaxRate.Prev], ax
         pop   dx, bx, ax
         ret
;-------------------------------

L0:      mov   bx, ax
         shr   bx, 1
         add   ax, bx
L1:      mov   [SampTime], ax
         pop   dx, bx, ax
         ret

MaxTime: push  ax, bx, dx       ; determine maximum sample time
         clr   dx
         mov   ax, 08000
         mov   bx, [SmpRate]
         div   bx                       ; ax = nr of seconds to record
         test  [Flags], PackWord        ; store 3 ADC-words in 4 bytes?
         jz    L1
         jmp   L0
;-------------------------------

SetSps:  ret
;-------------------------------
   

New interrupt vectors.

L0:      pop   ds
         jmp   [cs:OldIRQ0]

NewIRQ0: push  ds
      cs mov   ds, [DataSeg]
         test  [Flags], Running
         jz    L0
         inc   [Counter]
         or    [Flags], RefrshBar
         test  [Counter], 07
         IF  Z or  [Flags], RefrshDig
         jmp   L0
;-------------------------------

NewIRQ8: push  ax
         mov   al, 0C
         out   070, al
         in    al, 071                  ; clear interrupt flags
         test  [cs:Flags], Running      ; are we running?
         IF NZ or  [cs:Flags], TimeOut  ; if so, set TimeOut flag
         mov   al, 020
         out   020, al
         out   0A0, al
         pop   ax
         iret
;-------------------------------

EnableNewIRQ8:
         push  ax
         mov   al, 0C
         out   070, al
         in    al, 071          ; check register C first
         mov   al, 0A
         out   070, al
         mov   al, 00100011xB   ; select 1 kSps
         out   071, al          ; and set it in register A
         mov   al, 0B
         out   070, al
         mov   al, 01000010xB
         out   071, al          ; and store it
         in    al, 0A1          ; get IRQ mask word
         and   al, not bit 0
         out   0A1, al          ; enable IRQ 8
         pop   ax
         ret
;-------------------------------

ResetNewIRQ8:
         push  ax
         mov   al, 0A
         out   070, al          ; select register A
         mov   al, 00100110xB
         out   071, al          ; and set it back to PC default
         mov   al, 0B
         out   070, al
         mov   al, 00000010xB
         out   071, al
         in    al, 0A1          ; get IRQ mask word
         or    al, bit 0
         out   0A1, al          ; disable IRQ 8
         pop   ax
         ret
;-------------------------------
   

Some initialisations.

SetVars: mov   [ComBase], 03F8  ; init ComBase 
         mov   [ShouldBe], 20   ; target value for timing = 20 s
         mov   [SmpRate], 0400  ; init sample rate
         mov   [GroupS], 010    ; init group size
         mov   [ShiftIt], 4     ; and related shift count for averaging
         mov   [StopIt], 1      ; set to "Manual"
         mov   [ToPlot], 0FF
         mov   [FSval], 5100
         mov   [Scale], 100     ; Scale factor = 1,00
         mov   [Vref], 5100     ; prime V-ref with most probable value
         ret
;-------------------------------

init:    call  SetVars          ; init most import variables
         call  PowDown          ; make sure ADC is OFF
         call  ClkLo            ; prepare ADC for power-up
         call  ChkTime          ; measure minimum sample time
         call  MaxSps           ; determine maximum sample speed

         mov   ah, 0F
         int   010              ; determine existing video mode
         mov   [VidMode], al    ; store it
         mov   ax, 012
         int   010              ; set 640 x 480 graphics
         push  es
         mov   ax, 0351C        ; get old timervector
         int   021
         mov   w [OldIRQ0], bx
         mov   w [OldIRQ0+2], es
         mov   dx, offset NewIRQ0
         mov   ax, 0251C
         int   021              ; install new TIMER routine
         mov   ax, 03570
         int   021
         mov   w [OldClock], bx
         mov   w [OldClock+2], es
         mov   dx, offset NewIRQ8
         mov   ax, 02570
         int   021              ; install NewIRQ8 routine
         call  EnableNewIRQ8    ; and get it to work
         pop   es
         mov   ax, 0
         int   033              ; init mouse
         ShowMouse

         call  FillScreen
         or    [Flags], RfrshBar + RefrPara + Upd8Digs
         call  ShowDig
         call  BrScale
         call  Update
         ret
;-------------------------------
   

The main routine for LDA.

main:    mov   cx, LastByte
         mov   di, FirstByte
         sub   cx, di
         cld
         rep   stosb            ; init all vars
         mov   ax, cs
         mov   [DataSeg], ax            ; only for PROGRAM STRUCTURE
         mov   [CodeSeg], ax            ;
         add   ax, (LastByte/16) + 1
         mov   [BufSeg], ax
         mov   sp, offset stacktop
         call  init

L0:      test  [Flags], PowerFlag
         jz    >L1
         call  RdWord
         mov   [BarVal], ax
         call  ShowBar
         or    [Flags], Upd8Digs
         call  ShowDig
L1:      call  GetMous          ; get mouse status
         call  FindClick
         mov   ah, 0B
         int   021
         cmp   al, 0FF
         jne   L0
   

Exit from the LDA program and return to DOS.

exit:    call  PowDown
         call  ResetNewIRQ8
         push  ds
         lds   dx, [OldIRQ0]
         mov   ax, 0251C
         int   021              ; restore timer vector
         pop   ds
         push  ds
         lds   dx, [OldClock]
         mov   ax, 02570
         int   021              ; restore realtime clock vector
         pop   ds

         mov   ah, 0
         mov   al, [VidMode]
         int   010              ; back to previous screenmode
         mov   ax, 0
         int   033              ; reset mouse and -driver
         mov   ax, 04C00
         int   021
;-------------------------------
   

Definitions to fill windows.

params:  Topic  27, 9, 'COM : '
ParaCom  db    '1', 0

         Topic 180, 9, 'Start : '
ParaStrt db    'Manual   ', 0

         Topic 369, 9, 'File : '
ParaFile db    'filename.ext   ', 0

         Topic  9, 28, 'Power : '
ParaPowr db    'OFF', 0

         Topic 189, 28, 'Stop : '
ParaStop db    'Mem.Full', 0

         Topic 351, 95, 'Status : '
ParaStat db    'Idle    ', 0

         Topic 189, 55, 'Rate : '
ParaRate db    ' 1024 Sps ', 0

         Topic 360, 55, 'Group : '
ParaGrup db    '16 ', 0

         Topic 483, 55, 'Speed : '
ParaSpd  db    '   64/s', 0

         Topic 492, 72, 'Vref : '
ParaVref db    '5,100 V', 0

         Topic 189, 72, 'Unit : '
ParaUnit db    'V ', 0

         Topic 360, 72, 'Scale : '
ParaScal db    '1,00 x', 0

         Topic 189, 95, 'Mode : '
ParaMode db    'DMM       ', 0

         Topic 520, 120, '% FS '
ParaFull db    '..... ', 0
         TopicEnd

VrefSet: Topic   4, 2, '4,75', 0
         Topic 500, 2, '5,25', 0

         dw    250, 2
VrefIs   db    '5,000', 0
         TopicEnd

ScalSet: Topic  16, 2, '0', 0
         Topic 116, 2, '1', 0
         Topic 216, 2, '2', 0
         Topic 316, 2, '3', 0
         Topic 416, 2, '4', 0
         Topic 516, 2, '5', 0

         dw    250, 2
ScaleIs  db    ' 1,0', 0
         TopicEnd

SamStat  db    'Idle    '       ; Status
         db    'Sampling'
         db    'Waiting '
         db    'Ready   '
         db    'Single  '
DispMode db    'Voltmeter'      ; Display method
         db    'Recorder '
         db    'Histogram'
         db    'Statistix'
TrigStop db    'Mem.Full'
TrigStrt db    'Manual  '
         db    'Delta + '
         db    'Delta - '
         db    'Value   '
         db    'Up      '
         db    'Down    '
Unitsss  db    'VAF',0

copyleft db    'A-klasse (C)_1998 NL-5012_GH__272 [aklasse@tip.nl]', 0
MenuBar  db    'LD-ADC: Save Load _Cls Run Quit', 0

BitTable db    000, 00F, 0F0, 0FF       ; translation table for ShowDig

         even
clix1    dw    148,   6, 183,  16       ; Save 
         dw    262,   6, 296,  16       ; Load 
         dw    373,   6, 407,  16       ; Cls   Menu bar
         dw    485,   6, 511,  16       ; Run  
         dw    588,   6, 622,  16       ; Quit 

         dw     13,  59,  55,  70       ; Power
         dw    364, 103, 407, 114       ; Scale
         dw    495, 103, 530, 114       ; V-ref
         dw     32,  40,  56,  50       ; COM
         dw    184,  40, 228,  50       ; Start
         dw    193,  59, 226,  70       ; Stop
         dw    193,  86, 228,  98       ; Rate
         dw    364,  86, 407,  98       ; Group
         dw    193, 103, 228, 114       ; Unit
         dw    193, 126, 228, 138       ; Mode
         dw    373,  40, 410,  50       ; File
         dw    0F0F0                    ; end of table

ParaMous dw     DoSave,  DoLoad,  WinClr,   DoRun,  DoQuit
         dw    SetPowr, SetScal, SetVref, SetComm, SetStrt
         dw    SetStop, SetRate, SetGrup, SetUnit, SetMode
         dw    SetFile

DigMap:  db   03C,   8 dup (042), 03C                            ; '0'
         db   018, 038, 008, 008, 008, 008, 008, 008, 008, 03E   ; '1'
         db   03C, 002, 002, 002, 03C, 040, 040, 040, 040, 03C   ; '2'
         db   03C, 002, 002, 002, 01C, 002, 002, 002, 002, 03C   ; '3'
         db   000, 042, 042, 042, 042, 03C, 002, 002, 002, 002   ; '4'
         db   03C, 040, 040, 040, 03C, 002, 002, 002, 002, 03C   ; '5'
         db   03C, 040, 040, 040, 03C, 042, 042, 042, 042, 03C   ; '6'
         db   07C, 002, 002, 004, 008, 010, 010, 010, 010, 010   ; '7'
         db   03C, 042, 042, 042, 03C, 042, 042, 042, 042, 03C   ; '8'
         db   03C, 042, 042, 042, 03C, 002, 002, 002, 002, 03C   ; '9'
         db   10 dup (000)                                       ; ' '

CFG_file db    'LDA0$#$#.CFG', 0
DEF_file db    'LDA0$#$#.DEF', 0

INCLUDE bitmap.a86
   

Epilog.

Go get yourself an old Rievo 'Luegendetector' on Ebay or build one for yourself based on the SOAP drawings in the Soap section of fruttenboel. The SOAP project was influenced by the Rievo detector. Soap is superior since it's faster and completely isolated.

Project designed around 1998 and