;-------------------------------------------------------------------------------
;MMInterrupt
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
;Interrupt B0 instellingen
;-------------------------------------------------------------------------------
OPTION_REG_INTEDG = high
INTCON_INTE = high

;-------------------------------------------------------------------------------
;INT variabelen
;-------------------------------------------------------------------------------
const byte WAIT = 5
var volatile byte WaitLoop = WAIT
var volatile byte*3 dwMMData = 0
var volatile byte MMData[3]  at dwMMData
var volatile byte MMDataLow  at MMData[0]
var volatile byte MMDataMid  at MMData[1]
var volatile byte MMDataHigh at MMData[2]
var volatile byte*3 dwOldMMData = 0
var volatile byte OldMMData[3]  at dwOldMMData
var volatile byte OldMMDataLow  at OldMMData[0]
var volatile byte OldMMDataMid  at OldMMData[1]
var volatile byte OldMMDataHigh at OldMMData[2]
var volatile byte*3 dwMMPassData = 0
var volatile byte MMPassData[3]  at dwMMPassData
var volatile byte MMPassDataLow  at MMPassData[0]
var volatile byte MMPassDataMid  at MMPassData[1]
var volatile byte MMPassDataHigh at MMPassData[2]

const byte BITCOUNT = 18
var volatile byte BitCounter = BITCOUNT
var volatile byte ITemp
var volatile byte CommandStatus
const byte COMMANDSTATUS_NONE     = 0x00
const byte COMMANDSTATUS_PAUSE    = 0x01
const byte COMMANDSTATUS_DATABUSY = 0x11
const byte COMMANDSTATUS_COMPLETE = 0x80
const byte DATA_NONE    = 0x00
const byte DATA_LOCO    = 0x01
const byte DATA_TURNOUT = 0x02
var volatile byte DataStatus = DATA_NONE

const byte TIME_TURNOUT = 60
var volatile byte DataTime
var volatile byte T0Passed = 0
const byte BLINKTIME = 250
var byte BlinkTimer = BLINKTIME


;-------------------------------------------------------------------------------
;INTERRUPT PROCEDURE
;-------------------------------------------------------------------------------
procedure Interrupt is
  pragma interrupt
    ;tot hiertoe zij 12 instructies verlopen vanaf het moment dat de interrupt
    ;actief werd.  12 * 1/(8000000 / 4) = 6µs
    ;Bij een logische nul blijft het signaal 13µs hoog bij een seindecoder
    ;of 26µs voor een locdecoder.
    ;Na 27µs bekijken we het signaal: is dit nog hoog hebben we een logische
    ;één, is det laag hebben we een logische nul.
    ;pin_B5 = on
  if(INTCON_INTF)then
    INTCON_INTF = low
    ;sla de verstreken tijd op
    DataTime = TMR0
    ;reset Timer0
    TMR0 = 0
    INTCON_TMR0IF = low
    ;14 instructies = 7µs
    if(CommandStatus < COMMANDSTATUS_COMPLETE)then
      ;data moet nog beginnen of is reeds bezig
      CommandStatus = COMMANDSTATUS_DATABUSY
      ;terug 3µs
      ;De loop duurt 2,5µs - 5 keer deze loop + voorgaande en één sprong
      ;geeft 5 * 2.5µs = 12.5µs
      ;+ 6µs + 7µs + 3µs + 1µs = 29.5µs
      while(Waitloop != 0)loop
        WaitLoop = WaitLoop - 1
      end loop
      ;verwerk de data - kijk nu naar het signaal
      ;schuif het ganse datapakket 1 bit naar links
      ;Een nul wordt automatisch bijgevoegd; een één moeten we controleren
      dwMMData = dwMMData << 1
      if(Motorola)then
        MMDataLow = MMDataLow | 1
      end if

      BitCounter = BitCounter - 1
      if(BitCounter == 0)then
        ;alle 18 bits zijn binnen
        CommandStatus = COMMANDSTATUS_COMPLETE
        DataStatus = DATA_NONE
        ;Data gelijk?
        if(dwMMData == dwOldMMData)then
          ;data is identiek aan de vorige, we hebben een geldig commando
          dwOldMMData = 0
          ;afhankelijk van de polariteit van het signaal kan het
          ;nog zijn dat de volledige data geïnverteerd moet worden
          if(OPTION_REG_INTEDG == low)then
            ;negatief signaal: inverteren
            MMData[0] = !MMData[0]
            MMData[1] = !MMData[1]
            MMData[2] = !MMData[2]
          end if
          ;enkele 'addertjes onder het gras'...
          ;de data 0x3FFFF komt overeen met een DCC idle signaal
          ;en mag niet verwerkt worden
          if(dwMMData != 0x3FFFF)then
            ;De IB stuurt ook 'onmogelijke' data 0x02A800 als
            ;idle-signaal.  Ook filteren
            if(dwMMData != 0x02A800)then
              ;data doorgeven
              dwMMPassData = dwMMData
              if(DataTime > TIME_TURNOUT)then
                DataStatus = DATA_LOCO
              else
                ;Nog een eigenaardigheid van de IB: een lok-commando in oud-motorola
                ;formaat wordt na het aanduiden van de lok éénmalig als seindata
                ;verzonden.  De vijfde trit die normaal bij seindata altijd nul is,
                ;wordt als onderscheid dan als één verzonden. - filteren!
                if((MMDataMid & 0x03) == 0)then
                  DataStatus = DATA_TURNOUT
                end if
              end if
            end if
          end if
        else
          ;data verschillend, fout is eerste keer dat commando verzonden wordt
          dwOldMMData = dwMMData
        end if
        dwMMData = 0
        BitCounter = BITCOUNT
      end if
    end if
    WaitLoop = WAIT
  end if

  if(INTCON_TMR0IF)then
    ;Positief of negatief signaal?
    if(Motorola)then
      ;pause is hoog, int op lage flank
      OPTION_REG_INTEDG = low
    else
      ;pause is laag, int op hoge flank
      OPTION_REG_INTEDG = high
    end if
    ;zaten we al in een pauze?
    if(CommandStatus != COMMANDSTATUS_PAUSE)then
      ;was er nog niet complete data? - Afbreken!
      dwMMData = 0
      BitCounter = BITCOUNT
      CommandStatus = COMMANDSTATUS_PAUSE
    end if
    ;meldt dat T0 is afgegaan
    T0Passed = 1
    INTCON_TMR0IF = low
    TMR0          = 0
  end if
end procedure
;-------------------------------------------------------------------------------