Rievo Lie detector
Around 1997 I imported the software which was published by Rolf Hilchner from (somewhere near) Neuss in
Germany. They sold the PTS brand and a lot of gimmicks. Party gear, to get things going. Now, germans are not
known for their sense of humor or their easy going mind. Yet, this is all bullshit. If there is one people in
the world that knows how to party, it's the germans. Many have a dedicated Party Keller (Party cellar) and not
for offering guests a place to sleep. There may be a bed involved, but not for closed eye activities. :0)
One of the party gimmicks was the Rievo lie detector. You see the box in which it was shipped, in the picture above. The lines on the box translate to something like:
The general idea was: hook up someone, ask him/her some naughty questions and then let the situation get our of control. I envy the germans for their parties. I'd love to loose all my sense of humor, only to have their party culture...
Convert to an oscilloscope
On the right you see the circuit drawing for the original "Rievo Luegendetektor" as it was sold by Rievo. The
design was ingeniously simple. A cheap yet more than enough accurate serial low-power 10 bit Analog to Digital
Convertor (ADC) was always enabled and was read out continuously by the software.
It was connected to the COM (= serial) port. It also took its power from the COM port. The subject to be tested was hooked up across the C2 capacitor (far right).
By just clipping out the 100 k resistor and the C2 capacitor, you get a simple oscilloscope or data logger. Whatever you choose. The sample is taken from pin J2c. For more information, consult fruttenboel/asm/lda.html
Create a data logger or DSO
With some clever software I created a slow sampling DSO or a fast enough sampling data logger. Below is the source code:
MODULE Sample; FROM barith IMPORT nand, or, test, xor, MulDiv; FROM Display IMPORT ClrEOS, ClrEOL, SetCursorPosition; FROM InOut IMPORT Write, WriteLine, WriteLn, WriteCard, WriteHex, WriteString, RedirectOutput, CloseOutput; FROM Keyboard IMPORT GetKey, KeyPressed; FROM LowLevel IMPORT IOsize, InPort, OutPort; FROM SYSTEM IMPORT ASSEMBLER; FROM System IMPORT GetArg, Terminate; FROM Strings IMPORT Assign, CompareStr; FROM Storage IMPORT Available, ALLOCATE, DEALLOCATE; FROM Timer IMPORT OpenTimer, CloseTimer, ReadTimer, Wait; FROM NumberConversion IMPORT StringToCard; CONST TxDbit = 40H; (* bit 6 *) ClkBit = 2H; (* bit 1 *) DataBit = 20H; (* bit 5 *) Tab = 11C; Esc = 33C; AdcAccuracy = 10; (* for TLC 1549 *) TYPE PowerState = (On, Off); (* ADC power states *) ClockState = (Low, High, Strobe); (* Three options for ADC clocking *) SampleMode = (DMM, Timed, FreeRunning); VAR ComBase, Value, seconds, BufferSize, MaxRate, Speed, SamplePeriod : CARDINAL; Filename : ARRAY [0..49] OF CHAR; DataPtr : POINTER TO ARRAY [0..32000] OF CARDINAL; EscapePressed : BOOLEAN; Sampling : SampleMode; PROCEDURE UserMessage (Number : CARDINAL); BEGIN WriteLn; CASE Number OF 1 : WriteLine ("CopyLeft Jan Verhoeven 1999. This is GNU GPL style FREE software."); WriteLine ("Please find yourself a copy of the GPL. It might be useful..."); | 2 : WriteLine ("The commandline for using SAMPLE is as follows:"); WriteLn; Write (Tab); WriteLine ("SAMPLE COMx mode rate secs filename.ext"); WriteLn; WriteString ("Where:"); Write (Tab); WriteLine (" - COMx is the COM port to which the ADC is connected,"); Write (Tab); WriteLine (" - mode is the sampling mode (DMM, Free, Test, Timed),"); Write (Tab); WriteLine (" - rate is the number of samples per second (0..100),"); Write (Tab); WriteLine (" - secs is the nr of seconds to record,"); Write (Tab); WriteLine (" - 'filename.ext' is the device to send the data to."); WriteLn; WriteLine ("The commandline is CASE SENSITIVE! Perform a Test-run before a Free run."); WriteLn; WriteLine ("mode = DMM or Test => no parameters are needed."); WriteLine ("mode = Free => only the sample-time is needed."); UserMessage (1); | 3 : WriteLine ("Error 3: In number-entry, please use only decimal digits (0..9)."); WriteLine ("Thank you for your cooperation."); UserMessage (1); | 4 : WriteLine ("Error 4: The samplerate may not exceed 100 samples per second."); UserMessage (1); | 5 : WriteLine ("Error 1: Please specify the COM port the LD-ADC is connected to."); | 6 : WriteLine ("Error 2: Not enough memory available to run this application."); UserMessage (1); | 7 : WriteLine ("Error 5: No sample time specified!"); WriteLine (" Please input how many seconds you want to record."); UserMessage (1); | 8 : WriteLine ("Error 6: Too many datapoints. Make sure rate * seconds does not exceed 32000."); UserMessage (1); END; WriteLn; END UserMessage; PROCEDURE AdcPower (State : PowerState); VAR al, port : CARDINAL; BEGIN port := ComBase + 3; al := InPort (port, Byte); CASE State OF On : al := or (al, TxDbit); | Off : al := nand (al, TxDbit); END; OutPort (port, al, Byte); Wait (5); (* Wait 5 ms to stabilise ADC *) END AdcPower; PROCEDURE Clock (State : ClockState); VAR al, port : CARDINAL; BEGIN port := ComBase + 4; al := InPort (port, Byte); CASE State OF Low : al := nand (al, ClkBit); | High : al := or (al, ClkBit); | Strobe : al := xor (al, ClkBit); OutPort (port, al, Byte); al := xor (al, ClkBit); END; OutPort (port, al, Byte); END Clock; PROCEDURE ReadWord (VAR value : CARDINAL); VAR al, index, port : CARDINAL; BEGIN port := ComBase + 6; value := 0; FOR index := 1 TO AdcAccuracy DO value := value * 2; al := InPort (port, Byte); IF test (al, DataBit) THEN INC (value) END; Clock (Strobe); END; END ReadWord; PROCEDURE CalibrateTime (Iterations : CARDINAL) : CARDINAL; VAR i, j, first, last, zero, time : CARDINAL; BEGIN WriteLn; OpenTimer; first := ReadTimer (); FOR i := 1 TO Iterations DO (* Nothing *) END; last := ReadTimer (); zero := first - last; (* determine looping overhead *) first := ReadTimer (); FOR i := 1 TO Iterations DO ReadWord (j); END; last := ReadTimer (); (* determine total looping time *) time := first - last - zero; RETURN (time); CloseTimer; END CalibrateTime; PROCEDURE FindAddress (Port : CARDINAL) : CARDINAL; VAR Result : CARDINAL; BEGIN ASM MOV AX, 0 MOV ES, AX MOV BX, 0400H (* Start address of COM port addresses *) MOV AX, Port SHL AX, 1 ADD BX, AX MOV AX, ES:[BX] MOV Result, AX END; RETURN Result; END FindAddress; PROCEDURE CheckArguments; VAR Option : ARRAY [0..49] OF CHAR; count, ComPort, rate, index : CARDINAL; char : CHAR; done : BOOLEAN; MaxSex : REAL; BEGIN GetArg (Option, count); (* Get first argument from command line *) IF count # 4 THEN (* IF invalid tail, get out *) UserMessage (5); UserMessage (2); Terminate (5); (* Inform the moron of it *) END; char := Option ; ComPort := ORD (char) - ORD('0'); ComBase := FindAddress (ComPort - 1); WriteString ("Specified COM-port: "); WriteCard (ComPort, 1); Write (Tab); WriteString (" base address: "); WriteHex (ComBase, 4); WriteLine ("h."); GetArg (Option, count); (* Retrieve sample-rate *) IF count = 0 THEN UserMessage (2); (* if no samplerate, tell the man *) Terminate (2); END; IF CompareStr (Option, "DMM") = 0 THEN Sampling := DMM; RETURN; ELSIF CompareStr (Option, "Test") = 0 THEN WriteString ("This system is capable of taking "); WriteCard (MaxRate, 6); WriteLine (" samples per second."); WriteLine ("Press ENTER to continue."); WaitTrigger (15C); Terminate (255); ELSIF CompareStr (Option, "Free") = 0 THEN Sampling := FreeRunning; rate := MaxRate; ELSIF CompareStr (Option, "Timed") = 0 THEN Sampling := Timed; GetArg (Option, count); StringToCard (Option, rate, done); IF NOT done THEN UserMessage (3); (* error converting ASCII to number *) Terminate (3); (* report it to the user *) END; SamplePeriod := 1000 DIV rate; WriteString ("The sample rate is "); WriteCard (rate, 1); WriteString (" samples per second, or "); WriteCard (SamplePeriod, 1); WriteLine (" ms between samples."); END; GetArg (Option, count); IF count = 0 THEN UserMessage (7); (* if no sampletime, tell the man *) Terminate (7); END; StringToCard (Option, seconds, done); IF NOT done THEN UserMessage (3); (* error converting ASCII to number *) Terminate (3); (* report it to the user *) END; MaxSex := FLOAT (seconds) * FLOAT (rate); IF MaxSex > 32000.0 THEN UserMessage (8); Terminate (8); END; BufferSize := seconds * rate; GetArg (Option, count); (* Get device where to store data *) IF count = 0 THEN Option := "Sample.Adc" (* Generate default file *) END; Assign (Option, Filename); WriteString ("The data will be stored on device "); WriteString (Filename); WriteLine ("."); WriteLn END CheckArguments; PROCEDURE WaitTrigger (trigger : CHAR); VAR k : CHAR; BEGIN LOOP REPEAT (* Do nothing *) UNTIL KeyPressed (); GetKey (k); IF k = trigger THEN EXIT ELSIF k = Esc THEN EscapePressed := TRUE; EXIT; END END END WaitTrigger; PROCEDURE LongWait (time : CARDINAL); (* Wait increments of 1 ms *) VAR i : CARDINAL; BEGIN FOR i := 1 TO time DO Wait (1); END END LongWait; PROCEDURE ShowVolt; VAR value, x, y : CARDINAL; k : CHAR; BEGIN WriteLine ("Press SPACE to start/stop measuring."); WaitTrigger (" "); IF EscapePressed THEN RETURN END; SetCursorPosition (0, 0); ClrEOS; LOOP ReadWord (value); SetCursorPosition (2, 4); WriteCard (value, 5); Wait (500); IF KeyPressed () THEN GetKey (k); IF k = " " THEN EXIT END END END END ShowVolt; PROCEDURE TakeSamples (mode : SampleMode); VAR i, val, max : CARDINAL; k : CHAR; BEGIN WriteLine ("Press SPACE to start measuring."); WriteLine ("SAMPLE will take samples, store them in memory and afterwards save them."); WaitTrigger (" "); max := BufferSize - 1; CASE mode OF FreeRunning : FOR i := 0 TO max DO ReadWord (val); DataPtr^[i] := val; (* store the value in memory *) END; | Timed : FOR i := 0 TO max DO ReadWord (val); DataPtr^[i] := val; (* store the value in memory *) LongWait (SamplePeriod); END END; WriteLine ("Sampling done. Writing data to specified device."); RedirectOutput (Filename); (* send screen-output to file *) FOR i := 0 TO max DO WriteCard (i, 5); Write (","); Write (Tab); WriteCard (DataPtr^[i], 5); WriteLn; END; CloseOutput; (* restore output to screen *) WriteLine ("Data written to file. File closed."); END TakeSamples; PROCEDURE Initialize; (* Various initialization steps *) BEGIN EscapePressed := FALSE; Speed := CalibrateTime (10) DIV 10; MaxRate := MulDiv (1000, 1193, Speed); CheckArguments; IF Available (BufferSize * 2) THEN ALLOCATE (DataPtr, BufferSize * 2); ELSE UserMessage (6); Terminate (6); END; END Initialize; BEGIN Initialize; AdcPower (On); ReadWord (Value); (* Get rid of first value after PowerUp *) IF Sampling = DMM THEN ShowVolt; ELSE TakeSamples (Sampling); END; WriteLn; WriteLine ("Shutting down ADC and clearing buffers."); AdcPower (Off); DEALLOCATE (DataPtr, BufferSize * 2); UserMessage (1); END Sample.
Page created September 13, 2012 and