' ****************************************************************************
' MRB_IR_Control.txt (v1)
'
' Make-it-with-Micromite (Part 19)
'
' PE Magazine (August 2020)
'

' This code will allow you to control the MRB by using a 44pin IR control
' (as used with the Micromite MoodLight).

' In fact, any IR transmitter can be used but you will need to alter the 
' KEYCODE values in the SUB myIR_Int (in the SELECT CASE KEYCODE section)

' DO NOT PANIC IF YOU DO NOT FOLLOW ALL OF THE CODE!!
' (it is rather complex to follow the logic without a detailed explaination.)

' IR Buttons used (on the 44-button remote) include:
' FLASH: to blink eyes
' Red UP Arrow:  Turn to LEFT (large step)
' Green UP Arrow: Forwards (at the current speed setting)
' Blue UP Arrow: Turn to RIGHT (large step)
' Red DOWN Arrow: Turn to LEFT (small step)
' Green DOWN Arrow: Backwards (at the current speed setting)
' Blue DOWN Arrow: Turn to RIGHT (small step)
' DIY1,2,3: STOP moving
' QUICK: INCREASE speed setting value
' SLOW: DECREASE speed setting value

' NOTE: Remove JP8 jumper to keep the MRB powered up while in the EDITor
'

' ****************************************************************************

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

' SET-UP
' ======

Option AUTORUN ON              ' set program to automically RUN on power-up
CPU 48

IR DevCode,KeyCode,myIR_Int    ' enable IR detection - see SUB myIR_Int which
                               ' is located at the very end of this code!


CS=21               ' define I/O pin connected to the LED MATRIX module CS-pin
Pin(CS)=1                  ' default to high (any SPI data is ignored for now)
SetPin(CS),dout            ' set up the I/O pin as defined in above 2 lines

Dim Leye(8)                 ' an array that holds the 8x7 solid-eyeball pattern
Dim Reye(8)
Dim LeyeTemp(8) As INTEGER ' array used during calculation of LEFT eye data
Dim ReyeTemp(8) As INTEGER ' likewise for RIGHT eye
Dim Lpupil(2)
Dim Rpupil(2)

LED_Init                   ' SUB to initially set up both LED matrix modules

Leye(1)=&b00111100          ' define 8x7 (rugby ball shape) LED eyeball pattern
Leye(2)=&b01111110            ' This is used as a 'background' and loaded into..
Leye(3)=&b11111111            ' L(R)eyeTemp array each time the eyes are drawn.
Leye(4)=&b11111111            ' The pupil is then drawn at the correct position
Leye(5)=&b11111111            ' and finally the eye drawn either in Up or Down
Leye(6)=&b01111110            ' position (ie on first row (Up), or second
Leye(7)=&b00111100            ' row (Down)) - see DrawEye SUB below!
Leye(8)=&b00000000

Reye(1)=&b00111100          ' define 8x7 (rugby ball shape) LED eyeball pattern
Reye(2)=&b01111110            ' This is used as a 'background' and loaded into..
Reye(3)=&b11111111            ' L(R)eyeTemp array each time the eyes are drawn.
Reye(4)=&b11111111            ' The pupil is then drawn at the correct position
Reye(5)=&b11111111            ' and finally the eye drawn either in Up or Down
Reye(6)=&b01111110            ' position (ie on first row (Up), or second
Reye(7)=&b00111100            ' row (Down)) - see DrawEye SUB below!
Reye(8)=&b00000000



' Ly (-1 to 9) = which row where the Left-PUPIL is drawn
' Ry (-1 to 9) = as above but for Right-PUPIL (pupil=2x2 block with LEDs OFF)

' Lx (-1 to 9) = column position for the Left-PUPIL (9=no pupil)
' Rx (-1 to 9) = as above but for Right-PUPIL (0 or 8 = half a pupil!)

Randomize Timer            ' ensures different animation effects each time

d=50                       ' variable used to hold 'delay' between animations
                             ' hence speed of animation. Decrease to speed up.


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

' MAIN PROGRAM
' ============

Lpupil(1)=&b01
LPupil(2)=&b11

Rpupil(1)=&b10
RPupil(2)=&b11

Lx=4:Ly=4
Rx=4:Ry=4

LBlink=&b00000000
RBlink=&b00000000

LShiftX=0
LShiftY=0

RShiftX=0
RShiftY=0


'draweye

'End
Look_Straight
PWM 1,stop
SetPin(9),dout
SetPin(10),dout
MRB_Speed=90

Do
  If MRB_MOVE=1 Then
    If MRB_DIR<0 Then
      PWM 1,1000,100-MRB_Speed,100-MRB_Speed
      Pin(9)=1
      Pin(10)=1
    Else
      PWM 1,1000,MRB_Speed,MRB_Speed
      Pin(9)=0
      Pin(10)=0
    End If
  Else
    If MRB_Turn=0 Then
      Pin(9)=0
      Pin(10)=0
      PWM 1,stop
'      If Int(Rnd()*1000)<5 Then EyeBlink
    Else
      Pause MRB_TurnDuration
      MRB_Turn=0
    End If
  End If


'  Look_Left
'    d=500:If Int(Rnd()*5)=1 Then EyeBlink:d=100
'    Pause d
'  Look_Straight
'    d=500:If Int(Rnd()*5)=1 Then EyeBlink:d=100
'    Pause d
'  Look_Right
'    d=500:If Int(Rnd()*5)=1 Then EyeBlink:d=100
'    Pause d
'  Look_Straight
'    d=500:If Int(Rnd()*5)=1 Then EyeBlink:d=100
'    Pause d
Pin(cs)=1
Text 120,160,Time$,cm,1,3,RGB(White),RGB(Blue)
Text 120,50,Str$(MRB_Speed),cm,1,4
'Pause 100
Loop


Sub Look_Left
    LShiftX=-1
    RShiftX=-1
    DrawEye
End Sub

Sub Look_Straight
    LShiftX=0
    RShiftX=0
    Lpupil(1)=&b11
    LPupil(2)=&b11
    Rpupil(1)=&b11
    RPupil(2)=&b11
    DrawEye
End Sub

Sub Look_Right
    LShiftX=1
    RShiftX=1
    DrawEye
End Sub

Sub EyeBlink
  For ppp=1 To 9
    Select Case ppp
      Case 1
        LBlink=&b00000000
        RBlink=&b00000000
      Case 2
        LBlink=&b10000001
        RBlink=&b10000001
      Case 3
        LBlink=&b11000011
        RBlink=&b11000011
      Case 4
        LBlink=&b11100111
        RBlink=&b11100111
      Case 5
        LBlink=&b11111111
        RBlink=&b11111111
      Case 6
        Pause 100
        LBlink=&b11100111
        RBlink=&b11100111
      Case 7
        LBlink=&b11000011
        RBlink=&b11000011
      Case 8
        LBlink=&b10000001
        RBlink=&b10000001
      Case 9
        LBlink=&b00000000
        RBlink=&b00000000
      End Select
      draweye
      Pause 10
    Next ppp
End Sub



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

' SUBROUTINES
' ===========


Sub DrawEye                        ' DO NOT PANIC IF YOU DON'T FOLLOW THIS SUB!

  'draw both pupils in correct place
  Lpupil(1)=Lpupil(1) And 3 'ensure only two ls bits
  Lpupil(2)=Lpupil(2) And 3 'ensure only two ls bits
  Rpupil(1)=Rpupil(1) And 3 'ensure only two ls bits
  Rpupil(2)=Rpupil(2) And 3 'ensure only two ls bits
  For i=1 To 8
    LeyeTemp(i)=Leye(i)
    ReyeTemp(i)=Reye(i)
    If i=Ly Then
      If (Lpupil(1) And 2) Then LeyeTemp(i)=LeyeTemp(i) And (255-2^(8-Lx)) 'switch off relevant bit
      If (Lpupil(1) And 1) Then LeyeTemp(i)=LeyeTemp(i) And (255-2^(7-Lx)) 'switch of relevant bit
    End If
    If i=Ly+1 Then
      If (Lpupil(2) And 2) Then LeyeTemp(i)=LeyeTemp(i) And (255-2^(8-Lx)) 'switch off relevant bit
      If (Lpupil(2) And 1) Then LeyeTemp(i)=LeyeTemp(i) And (255-2^(7-Lx)) 'switch of relevant bit
    End If

    If i=Ry Then
      If (Rpupil(1) And 2) Then ReyeTemp(i)=ReyeTemp(i) And (255-2^(8-Rx)) 'switch off relevant bit
      If (Rpupil(1) And 1) Then ReyeTemp(i)=ReyeTemp(i) And (255-2^(7-Rx)) 'switch of relevant bit
    End If
    If i=Ry+1 Then
      If (Rpupil(2) And 2) Then ReyeTemp(i)=ReyeTemp(i) And (255-2^(8-Rx)) 'switch off relevant bit
      If (Rpupil(2) And 1) Then ReyeTemp(i)=ReyeTemp(i) And (255-2^(7-Rx)) 'switch of relevant bit
    End If

  Next i

  'draw blink patterns &bxabcdefg where bit x = top row of 8x8 eye, and bit g = bootm row of eye
  For i = 1 To 8
    If (LBlink And (2^(8-i))) Then LeyeTemp(i)=&H0
    If (RBlink And (2^(8-i))) Then ReyeTemp(i)=&H0
  Next i

  'draw eyes into correct HORIZONTAL position
  For i = 1 To 8
    Select Case LShiftX
      Case <0
        LeyeTemp(i)=(255 And (LeyeTemp(i)<<Abs(LShiftX)))
      Case >0
        LeyeTemp(i)=(255 And LeyeTemp(i)>>LShiftX)
    End Select
    Select Case RShiftX
      Case <0
        ReyeTemp(i)=(255 And (ReyeTemp(i)<<Abs(RShiftX)))
      Case >0
        ReyeTemp(i)=(255 And ReyeTemp(i)>>RShiftX)
    End Select
  Next i

  'draw eyes VERTICAL position
  Select Case LShiftY
    Case <0
      If LShiftY<-8 Then LShiftY=-8 ' ensure value not less than -8
      For i = 1 To 8
        If Abs(LShiftY)<(9-i) Then
          LeyeTemp(i)=LeyeTemp(i+Abs(LShiftY))
        Else
          LeyeTemp(i)=0
        End If
      Next i
    Case >0
      If LShiftY>8 Then LShiftY=8 ' ensure value not more than 8
      For i = 8 To 1 Step -1
        If LShiftY<i Then
          LeyeTemp(i)=LeyeTemp(i-LShiftY)
        Else
          LeyeTemp(i)=0
        End If
      Next i
    End Select
    Select Case RShiftY
      Case<0
        If RShiftY<-8 Then RShiftY=-8 ' ensure value not greater than 8
        For i = 1 To 8
          If Abs(RShiftY)<=(8-i) Then
            ReyeTemp(i)=ReyeTemp(i+Abs(RShiftY))
          Else
            ReyeTemp(i)=0
          End If
        Next i
      Case >0
        If RShiftY>8 Then RShiftY=8 ' ensure value not more than 8
        For i = 8 To 1 Step -1
          If RShiftY<i Then
            ReyeTemp(i)=ReyeTemp(i-RShiftY)
          Else
            ReyeTemp(i)=0
          End If
        Next i
    End Select

    ' DRAW EYE
  SPI OPEN 10000000,0,32           ' configure SPI port for communication to 8x8's
    For i = 1 To 8
      Pin(cs)=0
      aa=SPI( (((i*256)+ReyeTemp(i))*(2^16)) Or ((i*256) Or LeyeTemp(i)))
      Pin(cs)=1
      'Pulse cs,.1
    Next i
  'Pause 1
  SPI CLOSE
End Sub

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


Sub LED_Init                      ' initialise the MAX7219 display modules
  SPI OPEN 3000000,0,32           ' configure SPI port for communication to 8x8's
  Pin(cs)=0:AA=SPI(&H0C000C00):Pin(cs)=1 'Pulse cs,1
  Pin(cs)=0:AA=SPI(&H09000900):Pin(cs)=1 'Pulse cs,0.1
  Pin(cs)=0:AA=SPI(&H0A050A05):Pin(cs)=1 'Pulse cs,0.1
  Pin(cs)=0:AA=SPI(&H0B070B07):Pin(cs)=1 'Pulse cs,0.1
  Pin(cs)=0:AA=SPI(&H0F000F00):Pin(cs)=1 'Pulse cs,0.1
  Pin(cs)=0:AA=SPI(&H0C010C01):Pin(cs)=1 'Pulse cs,0.1
  SPI CLOSE
End Sub

'------------------------------------------------------------------------------
Sub LookRightUp
    LShiftY=0
    RShiftY=0
    Lpupil(1)=&b11
    LPupil(2)=&b01
    Rpupil(1)=&b11
    RPupil(2)=&b01
    Lx=5:Ly=3
    Rx=5:Ry=3
    Look_Right
End Sub

Sub LookRightDown
    LShiftY=1
    RShiftY=1
    Lpupil(1)=&b01
    LPupil(2)=&b11
    Rpupil(1)=&b01
    RPupil(2)=&b11
    Lx=5:Ly=4
    Rx=5:Ry=4
    Look_Right
End Sub

Sub LookLeftUp
    LShiftY=0
    RShiftY=0
    Lpupil(1)=&b11
    LPupil(2)=&b10
    Rpupil(1)=&b11
    RPupil(2)=&b10
    Lx=3:Ly=3
    Rx=3:Ry=3
    Look_Left
End Sub

Sub LookLeftDown
    LShiftY=1
    RShiftY=1
    Lpupil(1)=&b10
    LPupil(2)=&b11
    Rpupil(1)=&b10
    RPupil(2)=&b11
    Lx=3:Ly=4
    Rx=3:Ry=4
    Look_Left
End Sub

Sub LookStraightUp
    LShiftY=0
    RShiftY=0
    Lx=4:Ly=3
    Rx=4:Ry=3
    Look_Straight
End Sub

Sub LookStraightDown
    LShiftY=1
    RShiftY=1
    Lx=4:Ly=4
    Rx=4:Ry=4
    Look_Straight
End Sub



Sub myIR_Int
  Print "IR detected: Device Code="+Str$(DevCode) + ", Key Code="+Str$(KeyCode)
Select Case KeyCode
  Case 40          ' right-up
    LookRightUp
    MRB_Move=0
    MRB_Turn=1
    Pin(9)=1
    Pin(10)=0
    PWM 1,1000,20,80
    MRB_TurnDuration=300
  Case 8           ' right-down
    LookRightDown
    MRB_Move=0
    MRB_Turn=1
    Pin(9)=1
    Pin(10)=0
    PWM 1,1000,20,80
    MRB_TurnDuration=50
  Case 104         ' left-up
    LookLeftUp
    MRB_Move=0
    MRB_Turn=-1
    Pin(9)=0
    Pin(10)=1
    PWM 1,1000,80,20
    MRB_TurnDuration=300
  Case 72          ' left-down
    LookLeftDown
    MRB_MOVe=0
    MRB_TURN=-1
    Pin(9)=0
    Pin(10)=1
    PWM 1,1000,80,20
    MRB_TurnDuration=50
  Case 168         ' straight-up
    LookStraightDown
    MRB_DIR=1
    MRB_Move=1
  Case 136         ' straight-down
    LookStraightUp
    MRB_DIR=-1
    MRB_Move=1
  Case 208         ' Flash
    EyeBlink
  Case 48,176,112   'DIY1/2/3
    MRB_Move=0
  Case 232         ' Quick
    MRB_Speed=MRB_Speed+5
    If MRB_Speed>100 Then MRB_Speed=100
  Case 200         ' Slow
    MRB_Speed=MRB_Speed-5
    If MRB_Speed<60 Then MRB_Speed=60
End Select
End Sub