-- Title: T0comInIsr.jal Interupt routine included by tstRF12main.jal

-- Author H.v.Broekhuyzen (henk@henkzelf.nl)
-- Compiler: >=2.4m
--
-- This file is part of jallib  (http://jallib.googlecode.com)
-- Released under the BSD license (http://www.opensource.org/licenses/bsd-license.php)
--
-- Description: This files forms, together with tstRF12main.jal, tstRFcom.jal
--              and  tstRFsub.jal the test- and experiment- framework for
--              the files: spi_rf12b.jal and spi_sw_master.jal
--              For Hardware etc. see: tstRF12B.doc
--

-- Function : Contains a timer T0 interrupt routine and a routine  timers_init
-- that must be called by the main program to activate the interrupt hardware
-- and to initialise the variables used and maintained by the interruptroutine.
-- The T0 hardware is controlled so that it activates the interrupt 5000 times
-- per second.
-- Generally, the interruptroutine supplies the mainprogram with 2 tools:
-- a) Two timers to measure elapsed time and realise delay
-- b) Reading commands that arrive via the RS232 (hardware) interface.

--**********************************************************************
-- WARNING: Mark that some libraries (like for software RS232 interface)
-- disable interupts what might slowdown the timers.
-- Avoid the use of this libraries !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
--**********************************************************************
--
-- ************************************ Measuring of elapsed time.
-- In various situations the main program has to 'wait' a certain time, e.g.
-- for reaction of an external device.
-- In simple microcontroller programs this is implemented by couting in a loop
-- until a number of times the instructions in this loop are executed.
-- This methode is not always optimal because of the following reasons:
-- 1) The interrupt routine steels (a variable number of) instructions of
--    the mainprogram).
-- 2) The mainprogram may have a beter use for the waiting time (e.g. do
--    calculations or check inputsignals for errorconditions.
-- This software module provides two word variabled named  TMR_nr1 and TMR_nr2
-- Only if TMR_nr* != 0 the interupt routine decrements it by 1.
-- So the main program can set TMR_nr* to the number of Ticks to wait
-- and the interuptroutine takes care that TMR_nr*.
-- represents the wait time left.
--
-- Note: Adapting this software to support more timers is not difficult.
--
-- *********************************** Command input
-- PIC-programs that  to use these ISR are designed to share an RS232 link to
-- a mastercontroller (e.g. another PIC or a PC with terminal-emulator.
-- All PIC's receive what is send by the mastercontroller (= Commands).
-- The format of a command is such, that each slave-PIC can filter-out the
-- commands that are aimend for that particular slave-PIC.
-- This filtering is executed by this ISR, so the main program is not aware
-- or disturbed by commands sent to other PICs.
-- Note: 'Because of a diode in the RS232-out line of all slave PIC's and
--       1 resistor at the RS232-in of the master, all mainprograms of
--       the slave PICs can send characters to the master, BUT NOT AT THE
--       SAME TIME.
-- There are 2 formats for commands:
-- a) Commands adderres to all slaves. These consists at only one character.
--    This version of the ISR implements only "H" meaning "Halt" e.g. for
--    emergency-stop.
-- b) Two (non- numeric) ASCII-charracters, optionally followed by a typed
--    value (sword) follower by a \r (= enterkey)
-- The first one of the two (non- numeric) ASCII-charracters identifies the
-- slave (who). The main program has to define a constant with the label:
-- CFG_ControllerID to allow the ISR to filter the commands for that PIC.
-- The second charracter defines the wanted action (what) (== Command).
-- The optional value-part (default == 0) parameterises the command (how much)
-- Only when the \r (enter-key) the command character and the value are
-- past to the main program. It has to define the variables:
-- var byte  CommandIn ,  var sword ComValIn  and var byte  ComFlag
-- Where Comflag is set to 1 when the ISR has stored new values.
-- The main program can poll this flag and reset it to 0 when processed.
-- When you type commands you (like me) might make mistakes and want to make
-- corrections before hitting the Enter-key. For this: you hit the ESC-key
-- and start all over. All <control> characters but <esc> and \r
--
-- ADVERISING REMARK: This way of command input enables that a control-loop
-- runs until a new command is completely entered. It even enables that
-- parameters used in this loop are changed by commands while this loop keeps
-- running. For this there must be checked for the arrival of parameter-change-
-- commands at an adequate place in the control-loop.

-- ----------------------------------------------------------------------------

; Global data
; For timer T0
const word TMR_ticks_per_sec = 5000  ; if not 5000, change times in RC5 code.

var word TMR_nr1     ; if != 0 counts (each clock tick) to 0 (use for delay)
var word TMR_nr2     ; if != 0 counts (each clock tick) to 0 (use for delay)
; -------------- for use during command input

var byte TMR_CommandIn
var sword TMR_ComValIn  ; -1 * abs (typed number)
var bit  TMR_NegFlag   ; minus sign received at right place
var byte TMR_inputStatus
var byte TMR_charIn

const byte ESC = 27


---------------------------- Exported subroutines ------------------------

;------------------------------- Initialisatie  -------------------------------
procedure TMRs_init() is
 pragma inline
 INTCON_GIE = 0  ; disable all interrupts  (enabled at end of this routine)
 ; Initialise variables
 TMR_nr1            = 0
 TMR_nr2            = 0
 ; Now start timer
 option_reg = 0b_0000_0010  ; enable timer 0 interrupt
              ; clock source: int instruction cycle
              ; preccaler used for timer 0 and on 8,
              ; 20 MHz x-tal --> instruction cycle = 5MHz
              ; --> tmr0 counts at 625 kHz
 tmr0 = 131   ; (256 - 131 = 125) so overflow 625 kHz / 125 = 5 kHz

 INTCON_TMR0IE = 1  ; enable timer0 interrupt
 INTCON_GIE    = 1  ; enable all interrupts
end procedure

-----------------------------------------------------------------------------
---------  The interrupt routine --------------------------------------------
procedure TMRs_int() is
  pragma interrupt
--*************************************************************************
--                  T0 ( timers, command input)                          --
--*************************************************************************
  if (INTCON_TMR0IF != 0) & (INTCON_TMR0IE != 0) then ; if level 1
    -- Maintain hardware timer (T0) data ---------------------------
    tmr0 =  131 + tmr0 ; so overflow after 125 --> 5 kHZ
    ; done with add, because tmr0 > 0 when we reach this point
    INTCON_TMR0IF = 0 ; clear interrupt flag to enable next interrupt
    -- Maintain software timer(s) -----------------------------------
    if TMR_nr1 != 0 then
       TMR_nr1 = TMR_nr1 - 1
    end if
    if TMR_nr2 != 0 then
       TMR_nr2 = TMR_nr2 - 1
    end if
    -- Command Input -------------------------------------------------
    if Serial_HW_Read(TMR_charIn) then
      if TMR_charIn <= " " & TMR_charIn != "\r" then
        if TMR_charIn == ESC  then
          TMR_inputStatus = 0
        ; else it is a control character that is ignoired
        end if
      else
       case TMR_inputStatus of
         0 : block
               case  TMR_charIn of
                 CFG_ControllerID : TMR_inputStatus = 1 ; commond for this PIC
                 "H"            : block         ; Halt for all
                                   CommandIn = "H"   ComFlag  = 1
                                end block
                 otherwise  TMR_inputStatus = 4   ; not for this PIC
               end case
             end block
         1 : block
               if TMR_charIn == "\r" then
                TMR_inputStatus = 0
               else
                 TMR_CommandIn = TMR_charIn
                 TMR_ComValIn  = 0
                 TMR_NegFlag = 0
                 TMR_inputStatus = 2
               end if
             end block
         2 : block
               if TMR_charIn == "\r" then ; command known
                 CommandIn = TMR_CommandIn
                 if  TMR_NegFlag then
                   ComValIn  = TMR_ComValIn
                 else
                   ComValIn  =  - TMR_ComValIn
                 end if
                 ComFlag   = 1
                 TMR_inputStatus = 0
               else
                 if TMR_charIn == "-" & TMR_ComValIn  == 0 then
                   TMR_NegFlag = 1
                 else
                   if TMR_charIn >= "0" & TMR_charIn <= "9"  then
                     TMR_ComValIn = TMR_ComValIn * 10
                     TMR_charIn = TMR_charIn - "0"
                     TMR_ComValIn = TMR_ComValIn - TMR_charIn
                      ; pos numbers also calc neg, because of range (-32768)
                   else
                     CommandIn  = "?"
                     ComFlag   = 1
                     TMR_inputStatus = 5
                   end if  ; if cyfer
                 end if    ; if "-"
               end if      ; if "\r"
             end block
         4 : block
               if TMR_charIn == "\r"  then
                  TMR_inputStatus = 0
               end if
             end block
         5 : block
                CommandIn  = "?"
                ComFlag   = 1
             end block
        end case
      end if
    end if
    -- End Command Input
  end if ; (T0if)
end procedure


