'MICROPROFILER AND O2 CELL DATA LOGGING PROGRAM
'BY ROBERT GLATTS 4-15-93

'THIS PROGRAM RUNS A MOCKUP OF THE MICROPROFILER AND LOGS DATA FROM A BANK
'OF SAYLES OXYGEN CELLS.  THE MICROPROFILER SECTION HAS A SUBROUTINE FOR MANUAL
'POSITIONING OF THE RACK.  ONCE THE RACK IS POSITIONED, YOU CAN START
'A DATA LOGGING CYCLE WHERE THE RACK WILL MOVE DOWN 1/4mm AND THEN RECORD
'THE OXYGEN CELL OUTPUT CURRENTS. THE SAYLES OXYGEN CELL LOGGING SECTION IS
'INTENDED TO RUN SOMEWHAT IN THE BACKGROUND AND CAN BE STARTED AND STOPPED
'WHENEVER THE MICROPROFILER IS NOT IN A DATA AQUISITION CYCLE.

'THE NEXT LINE SETS UP THE BASE ADDRESS OF THE ADA520.
'THE ADDRESS IN VARIABLE "BA" MUST MATCH THE SWITCH SETTINGS(S1) ON THE BOARD.

   DIM CV(16) 'Channel Voltage array
   BA = 768   'BASE ADDRESS
  
'THIS SECTION OF THE PROGRAM SETS UP THE COMPUTER SCREEN

   CLS                                       'CLEAR SCREEN
  

'THE NEXT SECTION SETS UP THE ADDRESSES FOR THE ADA520 REGISTERS.

        PA = BA + 0                               'ADDRESS FOR 8255 PORT A
        PB = BA + 1                               'ADDRESS FOR 8255 PORT B
        PC = BA + 2                               'ADDRESS FOR 8255 PORT C
        CW = BA + 3                               'ADDRESS FOR 8255 CONTROL WORD
        DIR = BA + 4                              'DIRECTION REGISTER FOR DIGITAL I/O LINES
        IOA = BA + 5                              'DIGITAL I/O PORT A
        IOB = BA + 6                              'DIGITAL I/O PORT B
        IOC = BA + 7                              'DIGITAL I/O PORT C
        TA = BA + 8                               'ADDRESS FOR 8254 TIMER A
        TB = BA + 9                               'ADDRESS FOR 8254 TIMER B
        TC = BA + 10                              'ADDRESS FOR 8254 TIMER C
        TCW = BA + 11                             'ADDRESS FOR 8254 CONTROL WORD
        DA1LSB = BA + 12                          'ADDRESS FOR D/A 1 LSB
        DA1MSB = BA + 13                          'ADDRESS FOR D/A 1 MSB
        DA2LSB = BA + 14                          'ADDRESS FOR D/A 2 LSB
        DA2MSB = BA + 15                          'ADDRESS FOR D/A 2 MSB
        UPDATE = BA + 12                          'ADDRESS TO UPDATE DAC OUTPUTS
        STAT = BA + 13                            'ADDRESS TO READ STATUS BYTE

'THE NEXT LINE PROGRAMS THE BOARD FOR PORT A OUTPUT, PORT B INPUT, PORT C INPUT,
'PPI PORT B OUTPUT

'THIS SECTION INITIALIZES THE BOARD FOR OPERATION


   OUT DIR, 1                  'PORT A OUT, PORT B IN, PORT C IN
   OUT CW, &H92                'PPI PORT A IN, POT B OUT, PORT C OUT
   OUT PC, 0                   'SELECT CHANNEL 1, GAIN = 1

'THE NEXT SECTION IS THE BIT VALUES FOR EACH MICROPROFILER CONTROL FUNCTION

        MOTSTOP = 0
        MOTUPFAST = 3
        MOTUPSLOW = 7
        MOTDOWNFAST = 1
        MOTDOWNSLOW = 5

'********************************************************************  
' BEGINNING OF MAIN PROGRAM
'********************************************************************

MAIN:
        TIMER ON
        KEY(2) ON
        ON KEY(2) GOSUB MPSTOP
        KEY(3) ON
        ON KEY(3) GOSUB O2STOP
        ON TIMER(1) GOSUB CLOCKTICK  'Update various timers once a second
        MPFLAG = 0
        O2FLAG = 0
       
'Print the main menu

MAINMENU:       
        CLS
        LOCATE 1, 1
        PRINT "        MICROPROFILER/O2 LOGGING PROGRAM"
        PRINT
        PRINT "1    -- POSITION MICROPROFILER RACK"
        PRINT "2/F2 -- START/STOP MICROPROFILER DATA CYCLE"
        PRINT "3/F3 -- START/STOP O2 ELECTRODE DATA CYCLE"
        PRINT "9    -- QUIT"
       
'The program spends most of its time in this loop waiting for something    
'to happen. A keypress puts the program into various modes while the
'clock counters in CLOCKTICK initiate the data logging for both the
'microprofiler and O2 cell logging.
        
MAINLOOP:
        KEYPRESSED$ = INKEY$
        IF KEYPRESSED$ = "1" THEN
          GOSUB MPPOSITION
          GOSUB MAINMENU
          ELSEIF KEYPRESSED$ = "2" THEN
            GOSUB MPSTART
            GOSUB MAINMENU
          ELSEIF KEYPRESSED$ = "3" THEN
            GOSUB O2START
            GOSUB MAINMENU
          ELSEIF KEYPRESSED$ = "9" THEN
            GOSUB QUIT
        END IF
       
        IF MPSETCLOCK <= 0 AND MPFLAG = 1 THEN  'Counter to start Microprofiling cycle
          MPSETCLOCK = SETINTERVAL
          GOSUB MPDATACYCLE   'Start of a Microprofiling cycle
        END IF
        GOTO MAINLOOP:

'This subroutine updates a set of counters once a second.  The counters
'

CLOCKTICK:
        O2CLOCK = O2CLOCK - 1
        IF O2CLOCK <= 0 AND O2FLAG = 1 THEN
          O2CLOCK = O2INTERVAL
          GOSUB READO2DATA
        END IF
        MPSTEPCLOCK = MPSTEPCLOCK - 1
        MPSETCLOCK = MPSETCLOCK - 1
        DELAYCLOCK = DELAYCLOCK - 1
        RETURN

'This section is used to preposition the microprofiler frame.  The up and
'down arrow keys are used to move the rack up and down. 

MPPOSITION:
        CLS
        LOCATE 1, 1
        PRINT "PRESS UP ARROW MOMENTARILY TO MOVE UP 1/4mm"
        PRINT "PRESS UP ARROW AND SHIFT TO MOVE UP FAST"
        PRINT
        PRINT "PRESS DOWN ARROW MOMENTARILY TO MOVE DOWN 1/4mm"
        PRINT "PRESS DOWN ARROW AND SHIFT TO MOVE DOWN FAST"
        PRINT
        PRINT "PRESS ESC TO RETURN TO MAIN MENU"
       
MPPOSLOOP:
        MPFLAG = 0      'STOP DATA AQUISITION
        KEYPRESSED$ = INKEY$
        IF KEYPRESSED$ = CHR$(0) + CHR$(72) THEN   'UP ARROW KEY
          OUT IOA, MOTUPSLOW
            FOR DELAY = 1 TO 1000     'LET MICROSWITCH OPEN
            NEXT DELAY
          WHILE INP(IOC) = 255        'LOOK FOR MICROSWITCH CLOSURE
          WEND
          OUT IOA, MOTSTOP
        ELSEIF KEYPRESSED$ = "8" THEN  'SHIFTED ARROW KEY
          OUT IOA, MOTUPFAST
        ELSEIF KEYPRESSED$ = CHR$(0) + CHR$(80) THEN   'DOWN ARROW KEY
          OUT IOA, MOTDOWNSLOW
            FOR DELAY = 1 TO 1000
            NEXT DELAY
          WHILE INP(IOC) = 255
          WEND
          OUT IOA, MOTSTOP
        ELSEIF KEYPRESSED$ = "2" THEN      'SHIFTED DOWN ARROW KEY
          OUT IOA, MOTDOWNFAST
        ELSEIF KEYPRESSED$ = "" THEN       'STOP MOTOR IF NO KEY PRESSED
          OUT IOA, MOTSTOP
        ELSEIF KEYPRESSED$ = CHR$(27) THEN    'ESC KEY EXITS MENU SELECTION
          RETURN
        END IF
        FOR DELAY = 1 TO 1000      'DELAY KEEPS MOTOR ON UNTIL KEYBOARD
        NEXT DELAY                 'BUFFER FILLS
        GOTO MPPOSLOOP

'This section sets up the microprofiler data logging cycle.  Once started, the
'Microprofiler rack will move down in 1/4mm increments until the maximum
'specified depth is reached.  When the rack moves down each increment, the
'program waits a few seconds before taking an oxygen reading to allow the
'cell to settle.
        
MPSTART:
        IF MPFLAG = 1 THEN RETURN
        CLS
        INPUT "ENTER SECONDS BETWEEN SAMPLE STEPS: ", STEPINTERVAL
        INPUT "ENTER MINUTES BETWEEN SAMPLE SETS: ", SETINTERVAL
        SETINTERVAL = SETINTERVAL * 60
        INPUT "ENTER MAXIMUM PROBE DEPTH IN mm: ", MAXPROBEDEPTH
        INPUT "ENTER OUTPUT FILENAME PREFIX: ", MPFILE$
        GOSUB OPENMPFILE
        DEPTHCOUNT = 0
        MPSTEPCLOCK = 0
        MPSETCLOCK = 0
        MPFLAG = 1
        RETURN

MPSTOP:
        LOCATE 7, 1
        INPUT "DO YOU WANT TO STOP THE MICROPROFILER Y/N?", YESNO$
        IF YESNO$ = "Y" OR YESNO$ = "y" THEN
          MPFLAG = 0
          CLOSE #2
          LOCATE 7, 1
          PRINT "                                                  "
          RETURN
          ELSE
          LOCATE 7, 1
          PRINT "                                                 "
          RETURN
        END IF
        RETURN

MPDATACYCLE:
        IF DEPTHCOUNT >= (MAXPROBEDEPTH * 4) AND MPFLAG = 1 THEN
            GOSUB RETRACTPROBE
            RETURN
          ELSEIF MPSTEPCLOCK <= 0 AND MPFLAG = 1 THEN
            MPSTEPCLOCK = STEPINTERVAL   'RESET STEPINTERVAL CLOCK
            GOSUB MPSAMPLESTEP
            LOCATE 23, 1
            PRINT "                                                  "
            LOCATE 23, 1
            PRINT "LAST UPDATE:", TIME$, DATE$, MPOUTPUTFILE$
          ELSE RETURN
        END IF
        GOTO MPDATACYCLE:
        

MPSAMPLESTEP:
        LASTO2FLAG = O2FLAG   'Momentarily stop logging O2 data
        O2FLAG = 0
        OUT IOA, MOTDOWNSLOW
          FOR DELAY = 1 TO 1000     'Let microswitch close
          NEXT DELAY
        WHILE INP(IOC) = 255        'Wait for microswitch to open
        WEND
        OUT IOA, MOTSTOP
        O2FLAG = LASTO2FLAG         'Resume logging O2 data

        IF MPFLAG = 1 THEN
          DEPTHCOUNT = DEPTHCOUNT + 1  'INCREMENT PROBEDEPTH IN 1/4mm STEPS
          LOCATE 10, 1
          PRINT USING "PROBE DEPTH:   ###.## mm"; DEPTHCOUNT / 4
          DELAYCLOCK = 5
          WHILE DELAYCLOCK > 0      'Wait for microprofiler O2 cell to settle
          WEND
          GOSUB READMPDATA          'Get some data
          RETURN
          ELSE RETURN
          END IF

'This subroutine retracts the Microprofiler probe by raising the rack
'to the previous zero depth position.

RETRACTPROBE:
        DO UNTIL DEPTHCOUNT = 0
          OUT IOA, MOTUPSLOW       'Start motor turning up slow
          FOR DELAY = 1 TO 1000    'Let microswitch close
          NEXT DELAY
          WHILE INP(IOC) = 255     'Wait for microswitch to open
          WEND
          OUT IOA, MOTSTOP         'Stop motor
          DEPTHCOUNT = DEPTHCOUNT - 1   'Update depth
          LOCATE 10, 1
          PRINT USING "PROBE DEPTH: ###.##"; DEPTHCOUNT / 4
        LOOP
        RETURN

READMPDATA:
        GOSUB SCANCHANNELS          'Get some data
        GOSUB PRINTMPDAT
        GOSUB STOREMPDAT             'Now store the data collected previously
        RETURN
           

PRINTMPDAT:
'THIS SECTION PRINTS THE A/D DATA ON THE COMPUTER SCREEN.

        LOCATE 11, 1
        PRINT USING "CHANNEL 13: ######.### VOLTS"; CV(12)
        PRINT USING "CHANNEL 14: ######.### VOLTS"; CV(13)
        RETURN


OPENMPFILE:
        MPOUTPUTFILE$ = MPFILE$ + ".MP"
        OPEN MPOUTPUTFILE$ FOR OUTPUT AS #2
        RETURN

STOREMPDAT:
        IF MPFLAG = 1 THEN
          SAMPLEHOUR = VAL(MID$(SAMPLETIME$, 1, 2))  'Parse the sample time
          SAMPLEMIN = VAL(MID$(SAMPLETIME$, 4, 2))
          SAMPLESEC = VAL(MID$(SAMPLETIME$, 7, 2))
          WRITE #2, SAMPLEHOUR, SAMPLEMIN, SAMPLESEC, CV(12), CV(13)
          RETURN
          ELSE RETURN
        END IF

'********************************************************************
' O2 DATA ACQUISITION SECTION
'********************************************************************

       
O2START:
        IF O2FLAG = 1 THEN RETURN
        CLS
        INPUT "ENTER OUTPUT FILENAME PREFIX: "; O2FILE$  'Record data in this file
        DAY% = 1
        LASTDAY$ = DATE$     'Keep track of day so we can open a new file each day
        GOSUB OPENO2FILE
        INPUT "ENTER MINUTES BETWEEN SAMPLE SETS: "; O2INTERVAL
        O2INTERVAL = O2INTERVAL * 60     'Change minutes to seconds
        O2FLAG = 1      'Enable O2 logging
        RETURN

O2STOP:
        LOCATE 7, 1
        INPUT "DO YOU WANT TO STOP LOGGING O2 DATA Y/N? ", YESNO$
        IF YESNO$ = "Y" OR YESNO$ = "y" THEN
          O2FLAG = 0                          'Disable logging
          CLOSE #1                            'Close O2 log file
          LOCATE 7, 1
          PRINT "                                                     "
          RETURN
          ELSE
            LOCATE 7, 1
            PRINT "                                                    "
            RETURN  'GO BACK TO LOGGING O2
        END IF

READO2DATA:
        IF O2FLAG = 1 THEN
          GOSUB SCANCHANNELS          'Get some data
          THISDAY$ = DATE$            'What day is it?
          IF LASTDAY$ <> THISDAY$ THEN   'Is it a new day?
             CLOSE #1                    'If so, close the old file and open a new one
             DAY% = DAY% + 1
             GOSUB OPENO2FILE
             LASTDAY$ = THISDAY$
             END IF
          GOSUB PRINTO2DAT
          GOSUB STOREO2DAT             'Now store the data collected previously
          LOCATE 23, 1
          PRINT "                                                  "
          LOCATE 23, 1
          PRINT "LAST UPDATE:"; TIME$, DATE$, O2OUTPUTFILE$
          RETURN
            ELSE RETURN
          END IF


PRINTO2DAT:
'THIS SECTION PRINTS THE A/D DATA ON THE COMPUTER SCREEN.

        LOCATE 14, 1
        PRINT USING "CHANNEL 1: ######.### VOLTS"; CV(0)
        PRINT USING "CHANNEL 2: ######.### VOLTS"; CV(1)
        PRINT USING "CHANNEL 3: ######.### VOLTS"; CV(2)
        PRINT USING "CHANNEL 4: ######.### VOLTS"; CV(3)
        PRINT USING "CHANNEL 5: ######.### VOLTS"; CV(4)
        PRINT USING "CHANNEL 6: ######.### VOLTS"; CV(5)
        PRINT USING "CHANNEL 7: ######.### VOLTS"; CV(6)
        PRINT USING "CHANNEL 8: ######.### VOLTS"; CV(7)
        RETURN


OPENO2FILE:
        O2OUTPUTFILE$ = O2FILE$ + "." + LTRIM$(STR$(DAY%))
        OPEN O2OUTPUTFILE$ FOR OUTPUT AS #1
        RETURN

STOREO2DAT:
        IF O2FLAG = 1 THEN
          SAMPLEHOUR = VAL(MID$(SAMPLETIME$, 1, 2))
          SAMPLEMIN = VAL(MID$(SAMPLETIME$, 4, 2))
          SAMPLESEC = VAL(MID$(SAMPLETIME$, 7, 2))
          WRITE #1, SAMPLEHOUR, SAMPLEMIN, SAMPLESEC, CV(0), CV(1), CV(2), CV(3), CV(4), CV(5), CV(6), CV(7)
          RETURN
          ELSE RETURN
          END IF

'****************************************************************************
'  COMMON SUBROUTINES
'****************************************************************************

SCANCHANNELS:
        SAMPLETIME$ = TIME$             'STORE SAMPLE TIME
        FOR CHANNEL = 0 TO 15             'CHANNELS TO SCAN (1 TO 16)
        OUT PC, CHANNEL                   'SELECT CHANNEL
        FOR D = 1 TO 10: NEXT D           'OPTIONAL DELAY FOR INPUT SETTLING TIME (DEPENDENT ON CPU SPEED)
        OUT CW, 13                        'START CONVERSION (SET PC6 = 1)
        GOSUB EOCHI                       'WAIT TILL STATUS = 1
        OUT CW, 12                        'STOP CONVERSION (SET PC6 = 0)
        GOSUB EOCLO                       'WAIT TILL STATUS = 0
        GOSUB READDAT                     'READ A/D DATA
        VOLT = RESULT * (5 / 4096)
        CV(CHANNEL) = VOLT                'Store the voltage readings in an array
        NEXT CHANNEL
        RETURN



EOCHI:
        DONE = INP(STAT) AND 1            'CHECK TO SEE IF STATUS = 1
        IF DONE <> 1 GOTO EOCHI             'WAIT TILL STATUS = 1
        RETURN

EOCLO:
        DONE = INP(STAT) AND 1            'CHECK TO SEE IF STATUS = 0
        IF DONE <> 0 GOTO EOCLO           'WAIT TILL STATUS = 0
        RETURN


READDAT:
        OUT CW, 14                        'POINT TO MSB (PC7 = 0)
        MSB = INP(PA)                     'READ MSB
        POL = MSB AND 128                 'CHECK POLARITY BIT
        MSB = MSB AND 15                  'MASK OFF TOP 4 BITS
        MSB = MSB * 256                   'SCALE MSB
        OUT CW, 15                        'POINT TO LSB (PC7 = 1)
        LSB = INP(PA)                     'READ LSB
        RESULT = MSB + LSB                'COMBINE LSB AND MSB
        IF POL < 128 THEN RESULT = RESULT * -1  'ADJUST FINAL RESULT FOR POLARITY
        RETURN

QUIT:
        LOCATE 7, 1
        INPUT "ARE YOU SURE YOU WANT TO QUIT ENTIRE PROGRAM"; YESNO$
        IF YESNO$ = "Y" OR YESNO$ = "y" THEN
          CLOSE #1
          CLOSE #2
          TIMER OFF
          ELSE
          LOCATE 7, 1
          PRINT "                                                "
          RETURN
        END IF
        END



