Program listing for the Big-O-Trak project.

' This is the program for the Big-O-Trak.
' It programs an OOPic to duplicate the 
' original program that was in the Big Trak.
' http://www.oopic.com

' You can find the Big-O-Trak project at:
' http://www.robotprojects.com

' Create the Objects to drive the motors
Dim MotorRightForward As New oDio1
Dim MotorRightReverse As New oDio1
Dim MotorLeftForward As New oDio1
Dim MotorLeftReverse As New oDio1

' Create the Objects to count how far the Big Trak moved.
Dim MotorEncoderIRrcv As New oDio1
Dim MotorEncoderIRled As New oDio1
Dim MotorEncoderControl As New oDio1
Dim MotorEncoderCounter As New oCounter
Dim MotorEncoderCount As New oByte

' Create the Objects for a 4x6 keypad
Dim KeyColumns As New oDio4
Dim KeyRow1 As New oDio1
Dim KeyRow2 As New oDio1
Dim KeyRow3 As New oDio1
Dim KeyRow4 As New oDio1
Dim KeyRow5 As New oDio1
Dim KeyRow6 As New oDio1

' Create the Objects for the Laser Light
Dim LaserLight As New oDio1

' Create the Objects to make a sound generator
Dim ToneTimer As New oTimer
Dim ToneFrequency As New oWord
Dim ToneCompare As New oMath
Dim ToneDriver As New oCounter
Dim ToneGate As New oGate
Dim ToneZero As New oMath
Dim ToneSpeaker As New oDio1

' Create the Objects to do the time-out function
Dim TimeOut As New oByte
Dim TimeOutCounter As New oCounter

' Create the Objects to store the movement sequence.
Dim BOTPrg As New oEEProm
Dim Keypress As New oByte
Dim CommandState As New oNibble

' Create some work variables
Dim X As New oByte
Dim RepeatFlag As New oBit

'---------------------------------------------------------------

' Define some constant values.
Const Btn0 = 0
Const Btn1 = 1
Const Btn2 = 2
Const Btn3 = 3
Const Btn4 = 4
Const Btn5 = 5
Const Btn6 = 6
Const Btn7 = 7
Const Btn8 = 8
Const Btn9 = 9

Const BtnGo = 10
Const BtnCk = 11
Const BtnCls = 12
Const BtnClr = 13

Const BtnUp = 14
Const BtnDown = 15
Const BtnLeft = 16
Const BtnRight = 17
Const BtnFire = 18
Const BtnHold = 19
Const BtnRpt = 20

Const BtnIn = 21
Const BtnOut = 22
Const BtnTest = 23

Const BtnNone = 128

'------------------------------------------------------

Sub Main()
' This routine continuously checks the keypad
' to determine what the program should do.
  Call SetUp
  Do
    Keypress = Inkey
    If Keypress = BtnNone Then
      ToneDriver.Operate = cvFalse
      If TimeOut > 35 Then
        Call ComplainBeep
        TimeOut = 0
      End If
    Else
      Select Case Keypress
        Case BtnGo To BtnClr: Call CommandKey
        Case BtnUp To BtnRpt: Call FunctionKey
        Case Btn0 To Btn9: Call NumberKey
      End Select
      TimeOut = 0
    End If
  Loop
End Sub

Sub CommandKey()
' This routine is called when a command key is pressed.
' It determines what to do in response to the command.
  Call PlayToneUntilKeyReleased
  Select Case Keypress
    Case BtnGo: Call RunProgram
    Case BtnCk: Call CheckCommand
    Case BtnClr: Call ClearPrgPos: BOTPrg = 0
    Case BtnCls: Call ClearLastFunction
  End Select
End Sub

Sub FunctionKey()
' This routine is called when a function key is pressed.
' It stores the function in the EEPROM
  If (CommandState = 0) Or (CommandState = 2) Then
    Call PlayToneUntilKeyReleased
    BOTPrg = Keypress
    BOTPrg = 0
    CommandState = 1
  End If
End Sub

Sub NumberKey()
' This routine is called when a number key is pressed.
' It stores the number in the EEPROM.  However, if the
' last key was also a number, then it multiplies the last
' number by 10, then adds the new number, then stores it.
  If (CommandState = 1) Or (CommandState = 2) Then
    Call PlayToneUntilKeyReleased
    BOTPrg.Location = BOTPrg.Location - 3
    If CommandState = 1 Then
      BOTPrg = Keypress
      CommandState = 2
    Else
      Keypress = Keypress + (BOTPrg * 10)
      BOTPrg.Location = BOTPrg.Location - 1
      BOTPrg = Keypress
      CommandState = 0
    End If
    BOTPrg.Location = BOTPrg.Location + 2
  End If
End Sub

Sub PlayToneUntilKeyReleased()
' This routine is called after a legal key is pressed.
' It turns on the Tone Generator, which was set to a
' certain frequency by the routine that called it.
  ToneDriver.Operate = cvTrue
  Do Until Inkey = BtnNone: Loop
  ToneDriver.Operate = cvFalse
End Sub

Sub ClearLastFunction()
' This routine is called when the last stored function
' needs to be erased out of the EEPROM
    BOTPrg.Location = BOTPrg.Location - 3
    BOTPrg = 0
End Sub

Sub CheckCommand()
' This routine positions the EEPROM to one function back
' and then calls the RunCommands routine.
  If (CommandState = 0) Or (CommandState = 2) Then
    BOTPrg.Location = BOTPrg.Location - 3
    Call RunCommands
  End If
End Sub

Sub RunProgram()
' This routine positions the EEPROM at the beginning
' and then calls the RunCommands routine.
  Call ClearPrgPos
  Call RunCommands
End Sub

Sub RunCommands()
' This routine runs the functions stored in the EEPROM
' from the current EEPROM position
  Call StartBeep
  RepeatFlag = 0
  X = BOTPrg
  Do Until X = 0
    Select Case BOTPrg
      Case BtnUp:    Call Forward
      Case BtnDown:  Call Backward
      Case BtnRight: Call TurnRight
      Case BtnLeft:  Call TurnLeft
      Case BtnFire:  Call Laser
      Case BtnHold:  Call Hold
      Case BtnRpt:   Call Repeat
    End Select
    X = BOTPrg
  Loop
  Call EndBeep
End Sub

Sub Repeat()
' This routine repeats a specified number of functions
  If RepeatFlag = 0 Then
    BOTPrg.Location = BOTPrg.Location - (2 * (X + 1))
  End If
  RepeatFlag = 1
End Sub

Sub Hold()
' This routine delays a specified amount of time.
  Do Until X = 0
    OOPic.delay = 10
    X = X - 1
  Loop
End Sub

Sub Laser()
' This routine "shoots" the laser a specified
' number of times.
  ToneDriver.Operate = cvTrue
  ToneFrequency = 5208
  OOPic.delay = 17
  Do Until X = 0
    LaserLight = 1
    For ToneFrequency = 1488 To 2964 Step 110
    Next ToneFrequency
    LaserLight = 0
    For ToneFrequency = 2988 To 4464 Step 80
    Next ToneFrequency
    X = X - 1
  Loop
  ToneFrequency = 0
  ToneDriver.Operate = cvFalse
End Sub

Sub Forward()
' This routine makes the Big Trak go forward a
' specified distance.
  MotorRightForward = cvOn
  MotorLeftForward = cvOn
  Call GoUnits
End Sub

Sub Backward()
' This routine makes the Big Trak go backwards 
' a specified distance.
  MotorRightReverse = cvOn
  MotorLeftReverse = cvOn
  Call GoUnits
End Sub

Sub TurnRight()
' This routine makes the Big Trak turn right a
' specified distance.
  MotorRightReverse = cvOn
  MotorLeftForward = cvOn
  Call GoUnits
End Sub

Sub TurnLeft()
' This routine makes the Big Trak turn left a 
' specified distance.
  MotorRightForward = cvOn
  MotorLeftReverse = cvOn
  Call GoUnits
End Sub

Sub GoUnits()
' This routine shuts the Big Traks motor off 
' after a specified distance.
  ToneDriver.Operate = cvTrue
  ToneFrequency = 7812
  MotorEncoderControl = 0
  MotorEncoderIRled = cvOn
  Do Until X = 0
    MotorEncoderCount = 0
    Do Until MotorEncoderCount > 42: Loop
    X = X - 1
  Loop
  ToneFrequency = 0
  MotorRightForward = cvOff
  MotorLeftForward = cvOff
  MotorRightReverse = cvOff
  MotorLeftReverse = cvOff
  MotorEncoderIRled = cvOff
  MotorEncoderControl = 1
  ToneDriver.Operate = cvFalse
End Sub

Sub ComplainBeep()
' This routine beeps 4 times
  ToneDriver.Operate = cvTrue
  ToneFrequency = 6250
  OOPic.delay = 10
  ToneFrequency = 0
  OOPic.delay = 10
  ToneFrequency = 6250
  OOPic.delay = 10
  ToneFrequency = 0
  OOPic.delay = 10
  ToneFrequency = 6250
  OOPic.delay = 10
  ToneFrequency = 0
  OOPic.delay = 10
  ToneFrequency = 6250
  OOPic.delay = 10
  ToneDriver.Operate = cvFalse
End Sub

Sub StartBeep()
' This routine makes the beep before the program runs.
  ToneDriver.Operate = cvTrue
  Call AnnounceBeep
  ToneDriver.Operate = cvFalse
End Sub

Sub EndBeep()
' This routine makes the beep after the program runs.
  ToneDriver.Operate = cvTrue
  Call AnnounceBeep
  ToneFrequency = 0
  OOPic.delay = 8
  ToneFrequency = 6250
  OOPic.delay = 8
  ToneDriver.Operate = cvFalse
End Sub

Sub AnnounceBeep()
' This routine makes the Big Trak beep.
  ToneFrequency = 625
  OOPic.delay = 8
  ToneFrequency = 0
  OOPic.delay = 8
  ToneFrequency = 6250
  OOPic.delay = 8
  ToneFrequency = 0
  OOPic.delay = 8
  ToneFrequency = 2083
  OOPic.delay = 8
  ToneFrequency = 0
  OOPic.delay = 8
  ToneFrequency = 7812
  OOPic.delay = 8
  ToneFrequency = 0
  OOPic.delay = 8
  ToneFrequency = 1042
  OOPic.delay = 8
  ToneFrequency = 0
End Sub

Function Inkey() As oByte
' This function is used to read the 4x6 Keypad.
  Inkey = BtnNone
  KeyRow1.Direction = cvOutput
  KeyRow1.Clear
  If KeyColumns < 15 Then
    ToneFrequency = 1042
    Select Case KeyColumns
      Case 7: Inkey = BtnIn
      Case 11: Inkey = Btn0
      Case 13: Inkey = BtnOut
      Case 14: Inkey = BtnGo
    End Select
  End If
  KeyRow1.Direction = cvInput
  KeyRow2.Direction = cvOutput
  KeyRow2.Clear
  If KeyColumns < 15 Then
    ToneFrequency = 1250
    Select Case KeyColumns
      Case 7: Inkey = Btn1
      Case 11: Inkey = Btn2
      Case 13: Inkey = Btn3
      Case 14: Inkey = BtnCk
    End Select
  End If
  KeyRow2.Direction = cvInput
  KeyRow3.Direction = cvOutput
  KeyRow3.Clear
  If KeyColumns < 15 Then
    ToneFrequency = 1562
    Select Case KeyColumns
      Case 7: Inkey = Btn4
      Case 11: Inkey = Btn5
      Case 13: Inkey = Btn6
      Case 14: Inkey = BtnTest
    End Select
  End If
  KeyRow3.Direction = cvInput
  KeyRow4.Direction = cvOutput
  KeyRow4.Clear
  If KeyColumns < 15 Then
    ToneFrequency = 2083
    Select Case KeyColumns
      Case 7: Inkey = Btn7
      Case 11: Inkey = Btn8
      Case 13: Inkey = Btn9
      Case 14: Inkey = BtnRpt
    End Select
  End If
  KeyRow4.Direction = cvInput
  KeyRow5.Direction = cvOutput
  KeyRow5.Clear
  If KeyColumns < 15 Then
    ToneFrequency = 3125
    Select Case KeyColumns
      Case 7: Inkey = BtnLeft
      Case 11: Inkey = BtnDown
      Case 13: Inkey = BtnRight
      Case 14: Inkey = BtnCls
    End Select
  End If
  KeyRow5.Direction = cvInput
  KeyRow6.Direction = cvOutput
  KeyRow6.Clear
  If KeyColumns < 15 Then
    ToneFrequency = 6250
    Select Case KeyColumns
      Case 7: Inkey = BtnHold
      Case 11: Inkey = BtnUp
      Case 13: Inkey = BtnFire
      Case 14: Inkey = BtnClr
    End Select
  End If
  KeyRow6.Direction = cvInput
End Function

Sub SetUp()
  
  ' Set up I/O for the motor drivers
  MotorRightForward.IOLine = 15
  MotorRightForward.Direction = cvOutput
  MotorRightForward.Value = 0
  MotorRightReverse.IOLine = 30
  MotorRightReverse.Direction = cvOutput
  MotorRightReverse.Value = 0
  MotorLeftForward.IOLine = 29
  MotorLeftForward.Direction = cvOutput
  MotorLeftForward.Value = 0
  MotorLeftReverse.IOLine = 28
  MotorLeftReverse.Direction = cvOutput
  MotorLeftReverse.Value = 0
  
  ' Set up I/O for the motor encoders
  MotorEncoderIRled.IOLine = 7
  MotorEncoderIRled.Direction = cvOutput
  MotorEncoderIRled.Value = 0
  MotorEncoderControl.IOLine = 12
  MotorEncoderControl.Direction = cvOutput
  MotorEncoderControl.Value = 1
  MotorEncoderIRrcv.IOLine = 8
  
  ' Set up I/O for the 4x6 keypad
  KeyRow1.IOLine = 6
  KeyRow2.IOLine = 5
  KeyRow3.IOLine = 24
  KeyRow4.IOLine = 25
  KeyRow5.IOLine = 26
  KeyRow6.IOLine = 27
  KeyColumns.IOgroup = 1
  KeyColumns.Nibble = 0
  OOPic.Pullup = 1
  
  ' Set up I/O for the Laser Light
  LaserLight.IOLine = 14
  LaserLight.Direction = cvOutput
  LaserLight.Value = 0
  
  ' Set up I/O for the Speaker
  ToneSpeaker.IOLine = 13
  ToneSpeaker.Direction = cvOutput
  ToneSpeaker.Value = 0
  
  ' Create the Tone Generator Vitual Circuit.
  ToneTimer.Prescale = 3
  ToneTimer.Operate = cvTrue
  ToneCompare.Input1.Link (ToneTimer)
  ToneCompare.Input2.Link (ToneFrequency)
  ToneCompare.Mode = cvSubtract
  ToneCompare.Operate = cvTrue
  ToneDriver.ClockIn1.Link (ToneCompare.negative)
  ToneDriver.Output.Link (ToneSpeaker)
  ToneDriver.Operate = cvTrue
  ToneGate.Input1.Link (ToneCompare.negative)
  ToneGate.Output.Link (ToneZero.Operate)
  ToneGate.Invertout = cvTrue
  ToneGate.Operate = cvTrue
  ToneZero.Output.Link (ToneTimer)

  ' Create the Time-Out Vitual Circuit.
  TimeOutCounter.ClockIn1.Link (OOPic.hz1)
  TimeOutCounter.Output.Link (TimeOut)
  TimeOutCounter.Operate = cvTrue

  ' Create the Distance Counter Vitual Circuit.
  MotorEncoderCounter.ClockIn1.Link (MotorEncoderIRrcv)
  MotorEncoderCounter.Output.Link (MotorEncoderCount)
  MotorEncoderCounter.Operate = 1

End Sub

Sub ClearPrgPos()
' This routine sets BOTPrg.location to the place where 
' the compiler put the data.
  BOTPrg.Data(1,BtnUp,3,BtnFire,0,0)
  ' Notes: 
  ' To compile this routine, you will need to
  '   download version 3.02 or later of the OOPic compiler
  ' The Big Trak program is stored in this way:
  '   Units,Function,Units,Function,Units,Function,etc....
  ' When the Units value is 0, the Big Trak stops.
  ' The number of functions that can be stored is based on
  '   the size of the EEPROM in the OOPic.
  ' This needs to be the last routine in the program, so that
  '   the Big Trak's stored functions do not overwrite anything 
  '   else that may be placed behind it in the EEPROM.
End Sub