; PBX Software (MCS51 Assembly program) - Project
;   
;  General Info
;     Course : Final Project (BS degree)
;     Prgrmr : Sayed Behdad Hosseini, #781413112
;     Instr  : Mr. Etemadi
;     Date   : Feb,Mar,Apr 2003
;     Place  : University of Isfahan, Isfahan
;  
;  Project Info
;     Name   : PBX
;     Lang   : 8051 Assembly
;     Source : pbx.asm
;     Object : pbx.obj
;     Hex&Lst: pbx.hex - pbx.lst
;     Method : Procedure Oriented (structured)
;     Program: Machine (Binary) Code
;     Editor : Ms Visual Studio 2000
;     Assmblr: 8051 Cross Assembler
;     EpPrgmr: Kahroma Tarashe EEProm programmer
;   
;  Description Info
;     Work   : 
;        This program in 8051 (MCS51) asm lang.
;     is for controlling a pbx ckt. It 
;     communicates with ports and processes the
;     signals and then controlling the whole
;     system with outputing to ports (like an
;     open-loop control system). The boards
;     (hardware) makes a private branch exchange
;     (pbx) i.e the switching center for
;     some phones and also some external lines.
;     In this project the no of phones is 4 
;     (lines) and the no of external connections
;     (trunks) is 1. For more information see the
;     schematics (pbx.dsn or schematics.pdf) and
;     the thesis (thesis.pdf).
;
;        The software is responsilbe for 
;     detecting user inputs (scan the phones and
;     trunk) and respond to the requests like 
;     establishing the connections and sending 
;     informative tones to the phones ...
;
;        The software implements a low degree of
;     concurrency with use of states and events.
;     States are internal situations a procedure
;     can have and at a specified time is in one
;     of those states. Events are data messages
;     between procedures and are exported 
;     whenever an event has been occured in the 
;     system. The concurrent routines is invoked
;     repeatedly with the aid of time interrupt
;     and exposes the time sharing method. The
;     software first initializes the variables &
;     afterwards does an infinite loop and lets
;     the time interrupt do the rest.
;
;        Two used features of 8052: timer2 and
;     upper 128 data bytes of ram. So the program
;     must be executed on an 8X52 instead of its
;     familiar sibling (8X51).
;        
;        The program can be divided into 3 parts:
;     Constants, Variable declarations & Routines
;
;      Hardware Considrations : 
;        As said before the software assumes that 
;     uC is 8X52 and works with 12.0 Mhz clock 
;     (needed for timing routines). The port 
;     assignments can be found in schematics and 
;     also in Constants section of the program. 
;     All input ports must be TTL compatible.
;
;        Note that there are 3 leds just for
;     debuging purposes and can be removed for
;     the final version of the implementaion.



; 8051 Cross assembler controls
$MOD52
$NOPAGING

USING 0 ; Register bank 0 is used



;************************************************
;**             Contants Section               **

; ----- For debuging -----
DebugMode      equ   0
; DebugModes :
; 0: normal mode. Only if th's err led2 will be 1
; 1: shows a 3 bit increasing no (delay:1ms)
; 2: line 0 rings
; 3: all lines ring
; 4: shows line interface states of line 1
; 5: shows events got by LineControl 4 line 1
; 6: connects line 0&1 to CC0 and show on leds
; 7: shows free state of CCs (l0->CC0 l1->CC1)
; 8: shows l1 is con. to which CC (l1->CC1)
; 9: GetAFreeConv. output (l0->CC0 l2->CC2)
; 10: (l0->CC0:No l1->CC1:Dial l2->CC2:Busy)
; 11: (l0->CC0:Invalid l1->CC1:Ringback)
; 12: (l0,l1: EvConvReq&EvToneReq(Dial) l0:rel)
; 13: shows line control states of line 1
; 14: shows line3 connections to all CCs
; 15: shows TrunkControl states of t0

; ----- Ports -----
; line ports :
;  Rng: command to ring a phone
;  Dtct: dc-loop detect singnal (low active)
;  Intr: make internal connection
L0_Rng         equ   P0.0
L0_Dtct        equ   P0.1
L0_Intr        equ   P0.2
L1_Rng         equ   P1.0
L1_Dtct        equ   P1.1
L1_Intr        equ   P1.2
L2_Rng         equ   P2.0
L2_Dtct        equ   P2.1
L2_Intr        equ   P2.2
L3_Rng         equ   P3.0
L3_Dtct        equ   P3.1
L3_Intr        equ   P3.2

; switch ports:
;  Sx: The x-th line switch command
;  Tone: tone generating command (to conv signal)
C0_S0          equ   P0.3
C0_S1          equ   P0.4
C0_S2          equ   P0.5
C0_S3          equ   P0.6
C0_Tone        equ   P0.7
C1_S0          equ   P1.3
C1_S1          equ   P1.4
C1_S2          equ   P1.5
C1_S3          equ   P1.6
C1_Tone        equ   P1.7
C2_S0          equ   P2.3
C2_S1          equ   P2.4
C2_S2          equ   P2.5
C2_S3          equ   P2.6
C2_Tone        equ   P2.7

; trunk ports:
;  Cnct: connect (to conversation) command
;  Rdtct: ring detect singal
T0_Cnct        equ   P3.3
T0_RDtct       equ   P3.4

; led ports:
Led0           equ   P3.5
Led1           equ   P3.6
Led2           equ   P3.7

; ----- Tones -----
TnNo           equ   0  ; silence
TnDial         equ   1
TnBusy         equ   2
TnInvalid      equ   3
TnRingback     equ   4
TnDefault      equ   TnNo

; ----- LineInterface states -----
StDown         equ   0  ; on-hook
StUp           equ   1  ; off-hook
StLow1         equ   2  ; open loop for 1 state
StLow2         equ   3  ; open loop for 2 state
StLow3         equ   4  ; open loop for 3 state
StLow4         equ   5  ; open loop for 4 state
StHigh1        equ   6  ; close loop for 1 state
StHigh2        equ   7  ; close loop for 2 state
StHigh3        equ   8  ; close loop for 3 state
StHigh4        equ   9  ; close loop for 4 state
LIDefaultN     equ   0
LIDefaultState equ   StDown

; ----- LineControl & TrunkControl states -----
StIdle         equ   0  ; no request (on-hook)
StDialTone     equ   1  ; wait for dialing
StInvalidTone  equ   2  ; invalid tone is sent
StBusyTone     equ   3  ; busy tone is sent
StRingbackTone equ   4  ; ringback tone is sent
StTrunk        equ   5  ; conv with trunk
StRing         equ   6  ; ringing
StTalk         equ   7  ; conv is established
StDialing      equ   8  ; in dialing
LCDefaultState equ   StIdle
TCDefaultState equ   StIdle

; ----- CentralControl defaults -----
LineWantDefault   equ   -1
TrunkWantDefault  equ   -1

; ----- Events -----
EvPickup       equ   0  ; phone pick up
EvPutdown      equ   1  ; phone put down
EvSOD          equ   2  ; start of dialing
EvEOD          equ   3  ; end of dialing
EvConvReq      equ   4  ; a conver. is requested
EvAllRel       equ   5  ; release all resources
EvToneReq      equ   6  ; a tone request
EvTalkAccept   equ   7  ; conversation is OK
EvTalkCancel   equ   8  ; request is canceled
EvDigitDialed  equ   9  ; a digit is dialed
EvSOR          equ   10 ; start of ring
EvEOR          equ   11 ; end of ring
EvNoInvalid    equ   12 ; dialed no is invalid
EvNoLineBusy   equ   13 ; dialed no is busy line
EvNoTrunkBusy  equ   14 ; dialed no is busy trunk
EvNoTrunkOK    equ   15 ; dialed no is trunk & OK
EvNoLineRB     equ   16 ; dialed no is ring line
EvOK           equ   17 ; OK response
EvConnect      equ   18 ; a connect command
EvTalkReq      equ   19 ; talk request from line
EvTrunkRel     equ   20 ; release trunk
EvRdtctSample  equ   21 ; a Rdtct is sampled
EvTTalkReq     equ   22 ; talk request from trunk
EvTTalkCancel  equ   23 ; request is canceled

; ----- Auxiliary Registers -----
; some assignment for read(writ)ibility
; ARs are absolute (direct) addressings in ram
n              equ   R0
nAR            equ   AR0
d              equ   R1
dAR            equ   AR1
e              equ   R2
eAR            equ   AR2
t              equ   R3
tAR            equ   AR3
state          equ   R7
stateAR        equ   AR7



;************************************************
;**           Variable declarations            **

; ----- Byte Allocation (at direct segment) -----
dseg at 30H

; these two bytes are used for debuging purposes
debug1:        ds    1
debug2:        ds    1

; vars for timings
count4:        ds    1
count20:       ds    1
count250:      ds    1

; Tones that is to apply at conversations
c0ToneState:   ds    1
c1ToneState:   ds    1
c2ToneState:   ds    1

; LineInterface state & n variables
lIstate0:      ds    1
lIstate1:      ds    1
lIstate2:      ds    1
lIstate3:      ds    1
lIn0:          ds    1
lIn1:          ds    1
lIn2:          ds    1
lIn3:          ds    1

; LineControl state variables
lCstate0:      ds    1
lCstate1:      ds    1
lCstate2:      ds    1
lCstate3:      ds    1

; CentralControl variables
; these are used to save each line/trunk request
lineWant0:     ds    1
lineWant1:     ds    1
lineWant2:     ds    1
lineWant3:     ds    1
trunkWant:     ds    1

; TrunkControl variables
tCstate:       ds    1  ; its state
countTC:       ds    1  ; its aux var for timing


; ----- Bit Allocation (at bit segment) -----
bseg

; the main 500Hz wave for use in tones
mainWave:      dbit  1

; varying-with-time variables for making tones
noTone:        dbit  1
dialTone:      dbit  1
busyTone:      dbit  1
invalidTone:   dbit  1
ringbackTone:  dbit  1
ringWave       equ   ringbackTone ; 4 readability

; ring variables indicating which line is ringing
l0RingState:   dbit  1
l1RingState:   dbit  1
l2RingState:   dbit  1
l3RingState:   dbit  1

; two general purposes flags, for temp works
gf0:           dbit  1
gf1:           dbit  1



;************************************************
;**                 Routines                   **
cseg

org 0000H
   jmp Start


;/**
; * Timer 2 ISR: This piece of code is executed 
; * whenever timer 2 interrupts the uC.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
org 002BH

T2Isr:
   clr tf2   ; OK, the int is seen
   call Int1ms
   reti


;/**
; * The first executable code after each restart.
; * It first calls initialize routine then waits 
; * in a loop forever. The interrupt system 
; * continues handling the software.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
org 0038H

Start:
   mov sp, #7FH   ; stack
   call Init
   
   ; These are just for debug and don't assemble
   ; during final version
   IF (DebugMode = 2)
      push acc
      push psw
      clr a
      setb c
      call SetLineRingState
      pop psw
      pop acc
   ENDIF

   IF (DebugMode = 3)
      push acc
      push psw
      clr a
      setb c
      DM3L0:
         call SetLineRingState
      inc a
      cjne a, #4, DM3L0
      pop psw
      pop acc
   ENDIF

   IF (DebugMode = 6)
      push acc
      push dAR
      push psw
      
      setb c
      mov d, #0
      mov a, #0
      call SetSwitch
      call GetSwitch
      mov led0, c

      setb c
      mov a, #1
      call SetSwitch
      call GetSwitch
      mov led1, c

      mov a, #2
      call GetSwitch
      mov led2, c

      pop psw
      pop dAR
      pop acc
   ENDIF

   IF (DebugMode = 7)
      push acc
      push dAR
      push psw
      
      setb c
      mov d, #0
      mov a, #0
      call SetSwitch
      call IsConversationFree
      mov led0, c

      setb c
      mov d, #1
      mov a, #1
      call SetSwitch
      call IsConversationFree
      mov led1, c

      mov d, #2
      call IsConversationFree
      mov led2, c

      pop psw
      pop dAR
      pop acc
   ENDIF

   IF (DebugMode = 8)
      push acc
      push dAR
      push psw
      push nAR
      
      setb c
      mov d, #1
      mov a, #1
      call SetSwitch

      mov d, #0
      call GetLineConversation
      mov n, dAR
      call ShowOnLeds
      mov led2, c

      pop nAR
      pop psw
      pop dAR
      pop acc
   ENDIF

   IF (DebugMode = 9)
      push acc
      push dAR
      push psw
      push nAR
      
      setb c
      mov d, #0
      mov a, #0
      call SetSwitch
      mov d, #2
      mov a, #2
      call SetSwitch

      call GetAFreeConversation
      mov n, dAR
      call ShowOnLeds
      mov led2, c

      pop nAR
      pop psw
      pop dAR
      pop acc
   ENDIF

   IF (DebugMode = 10)
      push acc
      push dAR
      push psw
      push b
      
      setb c
      mov d, #0
      mov a, #0
      call SetSwitch
      mov b, #TnNo
      call SetConversationToneState

      mov d, #1
      mov a, #1
      call SetSwitch
      mov b, #TnDial
      call SetConversationToneState

      mov d, #2
      mov a, #2
      call SetSwitch
      mov b, #TnBusy
      call SetConversationToneState

      pop b
      pop psw
      pop dAR
      pop acc
   ENDIF

   IF (DebugMode = 11)
      push acc
      push dAR
      push psw
      push b
      
      setb c
      mov d, #0
      mov a, #0
      call SetSwitch
      mov b, #TnInvalid
      call SetConversationToneState

      mov d, #1
      mov a, #1
      call SetSwitch
      mov b, #TnRingback
      call SetConversationToneState

      pop b
      pop psw
      pop dAR
      pop acc
   ENDIF

   IF (DebugMode = 12)
      push acc
      push nAR
      push psw
      push b
      
      mov a, #0
      mov e, #EvConvReq
      call SwitchControl
      mov led0, c
      call SetSwitch

      mov a,#1
      call SwitchControl
      mov led1, c

      mov e, #EvToneReq
      mov n, #TnDial
      call SwitchControl

      mov a, #0
      mov e, #EvAllRel
      call SwitchControl
      mov led2, c

      pop b
      pop psw
      pop nAR
      pop acc
   ENDIF

   Loop:
      jmp Loop      ; infine loop


;/**
; * This routine initializes everything that is 
; * concerned to be correct at the beginnig of 
; * the program.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
Init:
   ; it can also be done using the set routines

   ; initialize ports
   clr L0_Rng
   setb L0_Intr
   clr C0_S0
   clr C0_S1
   clr C0_S2
   clr C0_S3

   clr L1_Rng
   setb L1_Intr
   clr C1_S0
   clr C1_S1
   clr C1_S2
   clr C1_S3

   clr L2_Rng
   setb L2_Intr
   clr C2_S0
   clr C2_S1
   clr C2_S2
   clr C2_S3
   
   clr L3_Rng
   setb L3_Intr
   
   clr T0_Cnct

   clr Led0
   clr Led1
   clr Led2
   
   ; initialize variables
   mov count20, #20
   mov count250, #250
   mov count4, #4

   setb dialTone
   clr noTone
   clr l0RingState
   clr l1RingState
   clr l2RingState
   clr l3RingState
   
   mov lIState0, #LIDefaultState
   mov lIState1, #LIDefaultState
   mov lIState2, #LIDefaultState
   mov lIState3, #LIDefaultState

   mov lIn0, #LIDefaultN
   mov lIn1, #LIDefaultN
   mov lIn2, #LIDefaultN
   mov lIn3, #LIDefaultN

   mov lCState0, #LCDefaultState
   mov lCState1, #LCDefaultState
   mov lCState2, #LCDefaultState
   mov lCState3, #LCDefaultState

   mov c0ToneState, #TnDefault
   mov c1ToneState, #TnDefault
   mov c2ToneState, #TnDefault

   mov lineWant0, #LineWantDefault
   mov lineWant1, #LineWantDefault
   mov lineWant2, #LineWantDefault
   mov lineWant3, #LineWantDefault
   mov trunkWant, #TrunkWantDefault

   mov tCstate, #TCDefaultState

   ; initialize timer2 (for 1000us == 1ms)
   mov rcap2h, #HIGH(-1000)
   mov rcap2l, #LOW(-1000)
   mov t2con, #00H
   mov ie, #10100000B   ; enable interrupt

   ; wait some miliseconds(500) for stability
   mov d, #5
   WLOOP:
   mov b, #200
   mov a, #250
   djnz acc, $
   djnz b, $-5
   djnz d, WLOOP

   ; Everything is ready. FIRE!
   setb tr2

   ret


;/**
; * This routine is used for showing a number (4 
; * test) between 0 and 7 on 3 leds that is 
; * connected to the uC.
; * @param n the number (the least 3 bit is used)
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
ShowOnLeds:
   push acc
   push psw
   mov a, n

   rrc a
   mov Led0, c

   rrc a   
   mov Led1, c
   
   rrc a   
   mov Led2, c

   pop psw
   pop acc
   ret


;/**
; * This routine is invoked whenever a routine
; * determines an unpredicted error. In this
; * implementaion it just turns led2 on.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
Error:
   setb Led2
   ret


;/**
; * It sets a tone to a conversation ckt.
; * @param d conversation number
; * @param b the desired tone
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetConversationToneState:
   push psw

   ; a switch() on d
   SCTS0:
      cjne d, #0, SCTS1
      mov c0ToneState, b
      jmp SCTSEnd

   SCTS1:
      cjne d, #1, SCTS2
      mov c1ToneState, b
      jmp SCTSEnd
      
   SCTS2:
      cjne d, #2, SCTS3
      mov c2ToneState, b
      jmp SCTSEnd

   SCTS3:

   SCTSEnd:
      pop psw
      ret


;/**
; * It outputs the tone assigned to a conv. ckt.
; * @param d conversation number
; * @return b the assigned tone
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetConversationToneState:
   push psw

   ; a switch() on d
   GCTS0:
      cjne d, #0, GCTS1
      mov b, c0ToneState
      jmp GCTSEnd

   GCTS1:
      cjne d, #1, GCTS2
      mov b, c1ToneState
      jmp GCTSEnd
      
   GCTS2:
      cjne d, #2, GCTS3
      mov b, c2ToneState
      jmp GCTSEnd

   GCTS3:

   GCTSEnd:
      pop psw
      ret


;/**
; * This routine starts/stops a line to ring.
; * @param a line number
; * @param c determines start(1) or stop(0)
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetLineRingState:
   push psw

   ; a switch() on a
   SLRS0:
      cjne a, #0, SLRS1
      pop psw
      mov l0RingState, c
      jmp SLRSEnd

   SLRS1:
      cjne a, #1, SLRS2
      pop psw
      mov l1RingState, c
      jmp SLRSEnd
      
   SLRS2:
      cjne a, #2, SLRS3
      pop psw
      mov l2RingState, c
      jmp SLRSEnd

   SLRS3:
      cjne a, #3, SLRS4
      pop psw
      mov l3RingState, c
      jmp SLRSEnd

   SLRS4:
      pop psw

   SLRSEnd:
      ret


;/**
; * This routine outputs a line ring state.
; * @param a line number
; * @return c determines ringing(1) or not(0)
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetLineRingState:

   ; a switch() on a
   GLRS0:
      cjne a, #0, GLRS1
      mov c, l0RingState
      jmp GLRSEnd

   GLRS1:
      cjne a, #1, GLRS2
      mov c, l1RingState
      jmp GLRSEnd
      
   GLRS2:
      cjne a, #2, GLRS3
      mov c, l2RingState
      jmp GLRSEnd

   GLRS3:
      cjne a, #3, GLRS4
      mov c, l3RingState
      jmp GLRSEnd

   GLRS4:

   GLRSEnd:
      ret


;/**
; * This routine sets a line contact in a 
; * conversation ckt to c (1:connect 0:open)
; * @param a line number
; * @param d conversation number
; * @param c hardware signal to the port
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetSwitch:
   push psw

   ; first a switch() on d then on a
   SSChk0:
      cjne d, #0, SSChk1

      SSChk0_0:
         cjne a, #0, SSChk0_1
         pop psw
         mov C0_S0, c
         jmp SSEnd

      SSChk0_1:
         cjne a, #1, SSChk0_2
         pop psw
         mov C0_S1, c
         jmp SSEnd

      SSChk0_2:
         cjne a, #2, SSChk0_3
         pop psw
         mov C0_S2, c
         jmp SSEnd

      SSChk0_3:
         cjne a, #3, SSError
         pop psw
         mov C0_S3, c
         jmp SSEnd

   SSChk1:
      cjne d, #1, SSChk2

      SSChk1_0:
         cjne a, #0, SSChk1_1
         pop psw
         mov C1_S0, c
         jmp SSEnd

      SSChk1_1:
         cjne a, #1, SSChk1_2
         pop psw
         mov C1_S1, c
         jmp SSEnd

      SSChk1_2:
         cjne a, #2, SSChk1_3
         pop psw
         mov C1_S2, c
         jmp SSEnd

      SSChk1_3:
         cjne a, #3, SSError
         pop psw
         mov C1_S3, c
         jmp SSEnd

   SSChk2:
      cjne d, #2, SSError

      SSChk2_0:
         cjne a, #0, SSChk2_1
         pop psw
         mov C2_S0, c
         jmp SSEnd

      SSChk2_1:
         cjne a, #1, SSChk2_2
         pop psw
         mov C2_S1, c
         jmp SSEnd

      SSChk2_2:
         cjne a, #2, SSChk2_3
         pop psw
         mov C2_S2, c
         jmp SSEnd

      SSChk2_3:
         cjne a, #3, SSError
         pop psw
         mov C2_S3, c
         jmp SSEnd

   SSError:
      ; invalid d or a
      pop psw
      IF (DebugMode = 0)
         call Error
      ENDIF
      jmp SSEnd

   SSEnd:
      ret
         

;/**
; * This routine gets a line contact in a 
; * conversation ckt into c (1:connect 0:open)
; * @param a line number
; * @param d conversation number
; * @return c hardware signal from the port
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetSwitch:

   ; first a switch() on d then on a
   GSChk0:
      cjne d, #0, GSChk1

      GSChk0_0:
         cjne a, #0, GSChk0_1
         mov c, C0_S0
         jmp GSEnd

      GSChk0_1:
         cjne a, #1, GSChk0_2
         mov c, C0_S1
         jmp GSEnd

      GSChk0_2:
         cjne a, #2, GSChk0_3
         mov c, C0_S2
         jmp GSEnd

      GSChk0_3:
         cjne a, #3, GSError
         mov c, C0_S3
         jmp GSEnd

   GSChk1:
      cjne d, #1, GSChk2

      GSChk1_0:
         cjne a, #0, GSChk1_1
         mov c, C1_S0
         jmp GSEnd

      GSChk1_1:
         cjne a, #1, GSChk1_2
         mov c, C1_S1
         jmp GSEnd

      GSChk1_2:
         cjne a, #2, GSChk1_3
         mov c, C1_S2
         jmp GSEnd

      GSChk1_3:
         cjne a, #3, GSError
         mov c, C1_S3
         jmp GSEnd

   GSChk2:
      cjne d, #2, GSError

      GSChk2_0:
         cjne a, #0, GSChk2_1
         mov c, C2_S0
         jmp GSEnd

      GSChk2_1:
         cjne a, #1, GSChk2_2
         mov c, C2_S1
         jmp GSEnd

      GSChk2_2:
         cjne a, #2, GSChk2_3
         mov c, C2_S2
         jmp GSEnd

      GSChk2_3:
         cjne a, #3, GSError
         mov c, C2_S3
         jmp GSEnd

   GSError:
      ; invlid d or a
      IF (DebugMode = 0)
         call Error
      ENDIF
      jmp GSEnd

   GSEnd:
      ret
         

;/**
; * It determines a specified conversation ckt
; * is free to use (c:1) or not(c:0)
; * @param d conversation ckt number
; * @return c free(1) or not(0)
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
IsConversationFree:
   push acc
   clr a
   
   ; loop on a
   ISFNext:
      call GetSwitch
      jc ISFEnd   ; found
      inc a
      cjne a, #4, ISFNext

   ISFEnd:
      cpl c

      pop acc
      ret


;/**
; * It outputs a line is connected to whitch
; * conversation ckt.
; * @param a line number
; * @return c it is connected at all or not
; * @return d conversation ckt number
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetLineConversation:
   mov d, #0

   ; loop on d
   GLCNext:
      call GetSwitch
      jc GLCEnd
      inc d
      cjne d, #3, GLCNext

   clr c      ; not found

   GLCEnd:
      ret


;/**
; * It outputs first free conversation ckt found.
; * @return c is there a free(1) or not(0)
; * @return d conversation ckt number
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetAFreeConversation:
   mov d, #0

   ; loop on d
   GAFCNext:
      call IsConversationFree
      jc GAFCEnd   ; found
      inc d
      cjne d, #3, GAFCNext

   clr c

   GAFCEnd:
      ret


;/**
; * This routine controls the switch unit: 2 int.
; * + 1 ext. conversation ckt. It recieves events
; * from other units and makes necessary changes
; * to the switch unit.
; * @param a line number
; * @param e event
; * @param n another parameter if e determines
; * @return c it's executed properly(1) or not(0)
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SwitchControl:
   push acc
   push dAR
   push b

   ; a switch() on e
   SC0:
      cjne e, #EvConvReq, SC1
      call GetLineConversation
      jc SC0Error
      call GetAFreeConversation
      jnc SC0Error
      cjne d, #2, SC0OK

      SC0Error:
         clr c
         jmp SCEnd

      SC0OK:
         setb c
         call SetSwitch
         setb c
         jmp SCEnd

   SC1:
      cjne e, #EvAllRel, SC2
      call GetLineConversation
      jnc SCEnd
      clr c
      call SetSwitch
      
      call IsConversationFree
      jnc SC1Con
      mov b, #TnDefault
      call SetConversationToneState
      cjne d, #2, SC1Con
      mov t, #0
      mov e, #EvTrunkRel
      call TrunkControl

      SC1Con:
         setb c
         jmp SCEnd

   SC2:
      cjne e, #EvToneReq, SC3
      call GetLineConversation
      jnc SCEnd
      mov b, n
      call SetConversationToneState
      setb c
      jmp SCEnd

   SC3:
      cjne e, #EvConnect, SC4
      call GetLineConversation
      jnc SCEnd
      mov a, n
      setb c
      call SetSwitch
      jmp SCEnd

   SC4:

   SCEnd:
      pop b
      pop dAR
      pop acc
      ret


;/**
; * Outputs lineWant (the connection a line has
; * been requested) of each line.
; * @param a line number
; * @return n lineWant
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetLineWant:
   push psw

   ; a switch() on a
   GLW0:
      cjne a, #0, GLW1
      mov n, lineWant0
      jmp GLWEnd

   GLW1:
      cjne a, #1, GLW2
      mov n, lineWant1
      jmp GLWEnd
      
   GLW2:
      cjne a, #2, GLW3
      mov n, lineWant2
      jmp GLWEnd

   GLW3:
      cjne a, #3, GLW4
      mov n, lineWant3
      jmp GLWEnd

   GLW4:

   GLWEnd:
      pop psw
      ret


;/**
; * Sets lineWant (the connection a line has been
; * requested) of each line into memory.
; * @param a line number
; * @param n lineWant
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetLineWant:
   push psw

   ; a switch() on a
   SLW0:
      cjne a, #0, SLW1
      mov lineWant0, n
      jmp SLWEnd

   SLW1:
      cjne a, #1, SLW2
      mov lineWant1, n
      jmp SLWEnd
      
   SLW2:
      cjne a, #2, SLW3
      mov lineWant2, n
      jmp SLWEnd

   SLW3:
      cjne a, #3, SLW4
      mov lineWant3, n
      jmp SLWEnd

   SLW4:

   SLWEnd:
      pop psw
      ret


;/**
; * The routine controls interconnection (switch)
; * between lines & trunks. It acccept requests
; * (in form of events) from line controls and
; * trunk controls.
; * @param e event
; * @param a line number
; * @param n if the event needs passing a param
; * @return e in some events for pass the result
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
CentralControl:
   push psw
   push b
   push nAR
   push acc
   push eAR

   ; a switch() on e
   CC0:
      cjne e, #EvDigitDialed, CC1_near
      jmp CC0_0

      CC0LineBusy:
         pop eAR
         mov e, #EvNoLineBusy
         push eAR
         jmp CCEnd

      CC0TrunkBusy:
         pop eAR
         mov e, #EvNoTrunkBusy
         push eAR
         jmp CCEnd

      CC0LineRB:
         call SetLineWant
         pop eAR
         mov e, #EvNoLineRB
         push eAR
         jmp CCEnd

      CC1_near:   ; CC1 exeeds jmp valid range
         jmp CC1

      CC0_0:
         cjne n, #1, CC0_1
         push acc
         mov a, #0
         mov n, acc
         mov e, #EvSOR
         call LineControl
         pop acc
         cjne e, #EvOK, CC0LineBusy
         jmp CC0LineRB
         
      CC0_1:
         cjne n, #2, CC0_2
         push acc
         mov a, #1
         mov n, acc
         mov e, #EvSOR
         call LineControl
         pop acc
         cjne e, #EvOK, CC0LineBusy
         jmp CC0LineRB
         
      CC0_2:
         cjne n, #3, CC0_3
         push acc
         mov a, #2
         mov n, acc
         mov e, #EvSOR
         call LineControl
         pop acc
         cjne e, #EvOK, CC0LineBusy
         jmp CC0LineRB
         
      CC0_3:
         cjne n, #4, CC0_4
         push acc
         mov a, #3
         mov n, acc
         mov e, #EvSOR
         call LineControl
         pop acc
         cjne e, #EvOK, CC0LineBusy
         jmp CC0LineRB

      CC0_4:
         cjne n, #0, CC0_5
         mov t, #0
         mov e, #EvTalkReq
         call TrunkControl
         cjne e, #EvOK, CC0TrunkBusy
         pop eAR
         mov e, #EvNoTrunkOK
         push eAR
         jmp CCEnd

      CC0_5:
         pop eAR
         mov e, #EvNoInvalid
         push eAR
         jmp CCEnd
         
   CC1:
      cjne e, #EvTalkAccept, CC2
      mov b ,a
      mov a, #0

      CC1Next:
         call GetLineWant
         push acc
         mov a, n
         cjne a, b, CC1Inc
         pop acc
         jmp CC1OK
         CC1Inc:
            pop acc
            inc a
            cjne a, #4, CC1Next

      mov a, b
      cjne a, trunkWant, CC1Error
      mov t, #0
      mov e, #EvTalkAccept
      call TrunkControl
      mov trunkWant, #TrunkWantDefault
      mov d, #2
      setb c
      call SetSwitch
      jmp CCEnd

      CC1Error:
         IF (DebugMode = 0)
            ; Serious Error
            call Error
         EndIF
         jmp CCEnd

      CC1OK:
         mov e, #EvTalkAccept
         call LineControl

         mov n, #LineWantDefault
         call SetLineWant

         mov n, b
         mov e, #EvConnect
         call SwitchControl

         jmp CCEnd

   CC2:
      cjne e, #EvTalkCancel, CC3
      call GetLineWant

      push acc
      mov a, n
      mov e, #EvEOR
      call LineControl
      pop acc

      mov n, #LineWantDefault
      call SetLineWant
      jmp CCEnd


   CC3:
      cjne e, #EvTrunkRel, CC4
      mov t, #0
      call TrunkControl
      jmp CCEnd

   CC4:
      cjne e, #EvTTalkReq, CC5
      mov a, #0

      CC4Next:
         mov e, #EvSOR
         call LineControl
         cjne e, #EvOK, CC4Inc
         mov trunkWant, a
         jmp CCEnd
         CC4Inc:
            inc a
            cjne a, #4, CC4Next

      jmp CCEnd

   CC5:
      cjne e, #EvTTalkCancel, CC6
      mov a, trunkWant
      cjne a, #TrunkWantDefault, CC5Cancel
      jmp CCEnd

      CC5Cancel:
         mov e, #EvEOR
         call LineControl
         mov trunkWant, #TrunkWantDefault
         jmp CCEnd

   CC6:

   CCEnd:
      pop eAR
      pop acc
      pop nAR
      pop b
      pop psw
      ret


;/**
; * This routine controls a trunk. It means it 
; * monitors ring signal and recieves events from
; * higher levels and does the control tasks.
; * @param e event
; * @param t trunk number
; * @return e in some events for pass the result
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
TrunkControl:
   push psw
   push stateAR
   push eAR
   push psw

   mov state, tCstate

   ; a switch() first on state then on e
   TC0:
      cjne state, #StIdle, TC1
      
      TC0_0:
         cjne e, #EvTalkReq, TC0_1
         pop psw
         pop eAR
         mov e, #EvOK
         push eAR
         setb c
         call SetTrunkCnct
         mov state, #StTalk
         jmp TCEnd

      TC0_1:
         cjne e, #EvRdtctSample, TC0_2
         pop psw
         jnc TCEnd
         mov state, #StRing
         mov e, #EvTTalkReq
         call CentralControl
         jmp TCEnd

      TC0_2:
         pop psw
         jmp TCEnd

   TC1:
      cjne state, #StTalk, TC2

      TC1_0:
         cjne e, #EvTrunkRel, TC1_1
         pop psw
         mov state, #StIdle
         clr c
         call SetTrunkCnct
         jmp TCEnd

      TC1_1:
         pop psw
         jmp TCEnd

   TC2:
      cjne state, #StRing, TC3

      TC2_0:
         cjne e, #EvRdtctSample, TC2_1
         pop psw
         jnc TC2_0Chk
         mov countTC, #210
         jmp TCEnd

         TC2_0Chk:
            djnz countTC, TCEnd
            mov state, #StIdle
            mov e, #EvTTalkCancel
            call CentralControl
            jmp TCEnd

      TC2_1:
         cjne e, #EvTalkAccept, TC2_2
         pop psw
         mov state, #StTalk
         setb c
         call SetTrunkCnct
         jmp TCEnd

      TC2_2:
         pop psw
         jmp TCEnd

   TC3:
      ; invalid state
      pop psw
      IF (DebugMode = 0)
         call Error
      ENDIF
      mov state, #TCDefaultState
      jmp TCEnd

   TCEnd:
      mov tCstate, state

      IF (DebugMode = 15)
         push psw
         push nAR
         cjne t, #0, DB15L0
         mov n, stateAR
         call ShowOnLeds
         
         DB15L0:
         pop nAR
         pop psw
      ENDIF
      
      pop eAR
      pop stateAR
      pop psw
      ret


;/**
; * Outputs state of each LineControl.
; * @param a line number
; * @return state current state of LineControl
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetLineControlData:
   push psw

   ; a switch() on a
   GLCD0:
      cjne a, #0, GLCD1
      mov state, lCstate0
      jmp GLCDEnd

   GLCD1:
      cjne a, #1, GLCD2
      mov state, lCstate1
      jmp GLCDEnd
      
   GLCD2:
      cjne a, #2, GLCD3
      mov state, lCstate2
      jmp GLCDEnd

   GLCD3:
      cjne a, #3, GLCD4
      mov state, lCstate3
      jmp GLCDEnd

   GLCD4:

   GLCDEnd:
      pop psw
      ret


;/**
; * Sets the state of each LineControl into the 
; * memory.
; * @param a line number
; * @param state updated state of the LineControl
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetLineControlData:
   push psw

   ; a switch() on a
   SLCD0:
      cjne a, #0, SLCD1
      mov lCstate0, state
      jmp SLCDEnd

   SLCD1:
      cjne a, #1, SLCD2
      mov lCstate1, state
      jmp SLCDEnd
      
   SLCD2:
      cjne a, #2, SLCD3
      mov lCstate2, state
      jmp SLCDEnd

   SLCD3:
      cjne a, #3, SLCD4
      mov lCstate3, state
      jmp SLCDEnd

   SLCD4:

   SLCDEnd:
      pop psw
      ret


;/**
; * This routine controls and commands everything
; * that is related to a line. It recieves events
; * from lower or higher levels and decides what 
; * to do with a line.
; * @param a line number
; * @param e event
; * @param n if e==EOD contains the dialed no
; * @return e in some events for show correctness
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
LineControl:

   IF (DebugMode = 5)
      push psw
      push nAR
      cjne a, #1, DB5L0
      mov n, eAR
      call ShowOnLeds
      
      DB5L0:
      pop nAR
      pop psw
   ENDIF

   push psw
   push stateAR
   push nAR
   push eAR

   call GetLineControlData

   ; a switch() on state then on e
   LC0:
      cjne state, #StIdle, LC1

      LC0_0:
         cjne e, #EvPickUp, LC0_1
         mov state, #StDialTone
         mov e, #EvConvReq
         call SwitchControl
         jc LC0_0OK
         mov state, #StInvalidTone
         jmp LCEnd

         LC0_0OK:
            mov e, #EvToneReq
            mov n, #TnDial
            call SwitchControl
            jmp LCEnd

      LC0_1:
         cjne e, #EvSOR, LC0_2
         mov state, #StRing
         pop eAR
         mov e, #EvOK
         push eAR
         setb c
         call SetLineRingState
         jmp LCEnd

      LC0_2:
         jmp LCEnd

   LC1:
      cjne state, #StRing, LC2

      LC1_0:
         cjne e, #EvEOR, LC1_1
         clr c
         call SetLineRingState
         mov state, #StIdle
         jmp LCEnd

      LC1_1:
         cjne e, #EvPickup, LC1_2
         clr c
         call SetLineRingState
         mov state, #StTalk
         mov e, #EvTalkAccept
         call CentralControl
         jmp LCEnd

      LC1_2:
         jmp LCEnd

   LC2:
      cjne state, #StTalk, LC3

      LC2_0:
         cjne e, #EvPutdown, LC2_1
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         jmp LCEnd

      LC2_1:
         jmp LCEnd

   LC3:
      cjne state, #StDialTone, LC4

      LC3_0:
         cjne e, #EvSOD, LC3_1
         mov state, #StDialing
         mov e, #EvToneReq
         mov n, #TnNo
         call SwitchControl
         jmp LCEnd

      LC3_1:
         cjne e, #EvPutdown, LC3_2
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         jmp LCEnd
      
      LC3_2:
         jmp LCEnd

   LC4:
      cjne state, #StDialing, LC5

      LC4_0:
         cjne e, #EvPutdown, LC4_1
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         jmp LCEnd

      LC4_1:
         cjne e, #EvEOD, LC4_2
         mov e, #EvDigitDialed
         call CentralControl

         LCNo0:
            cjne e, #EvNoInvalid, LCNo1
            mov state, #StInvalidTone
            mov e, #EvToneReq
            mov n, #TnInvalid
            call SwitchControl
            jmp LCEnd

         LCNo1:
            cjne e, #EvNoLineBusy, LCNo2
            mov state, #StBusyTone
            mov e, #EvToneReq
            mov n, #TnBusy
            call SwitchControl
            jmp LCEnd

         LCNo2:
            cjne e, #EvNoTrunkBusy, LCNo3
            mov state, #StBusyTone
            mov e, #EvToneReq
            mov n, #TnBusy
            call SwitchControl
            jmp LCEnd

         LCNo3:
            cjne e, #EvNoLineRB, LCNo4
            mov state, #StRingbackTone
            mov e, #EvToneReq
            mov n, #TnRingback
            call SwitchControl
            jmp LCEnd

         LCNo4:
            cjne e, #EvNoTrunkOK, LCNo5
            mov state, #StTrunk
            mov e, #EvAllRel
            call SwitchControl
            ;clr c
            ;call SetLineIntr
            mov d, #2
            setb c
            call SetSwitch
            jmp LCEnd

         LCNo5:
            jmp LCEnd

      LC4_2:
         jmp LCEnd

   LC5:
      cjne state, #StBusyTone, LC6

      LC5_0:
         cjne e, #EvPutdown, LC5_1
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         jmp LCEnd

      LC5_1:
         jmp LCEnd

   LC6:
      cjne state, #StInvalidTone, LC7

      LC6_0:
         cjne e, #EvPutdown, LC6_1
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         jmp LCEnd

      LC6_1:
         jmp LCEnd

   LC7:
      cjne state, #StTrunk, LC8

      LC7_0:
         cjne e, #EvPutdown, LC7_1
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         ;setb c
         ;call SetLineIntr
         mov e, #EvTrunkRel
         call CentralControl
         jmp LCEnd

      LC7_1:
         jmp LCEnd

   LC8:
      cjne state, #StTalk, LC9

      LC8_0:
         cjne e, #EvPutdown, LC8_1
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         jmp LCEnd

      LC8_1:
         jmp LCEnd

   LC9: 
      cjne state, #StRingbackTone, LC10

      LC9_0:
         cjne e, #EvPutdown, LC9_1
         mov state, #StIdle
         mov e, #EvAllRel
         call SwitchControl
         mov e, #EvTalkCancel
         call CentralControl
         jmp LCEnd

      LC9_1:
         cjne e, #EvTalkAccept, LC9_2
         mov state, #StTalk
         mov e, #EvToneReq
         mov n, #TnNo
         call SwitchControl
         jmp LCEnd

      LC9_2:
         jmp LCEnd

   LC10:
      ; invalid state
      IF (DebugMode = 0)
         call Error
      ENDIF
      mov state, #LCDefaultState
      jmp LCEnd

   LCEnd:
      call SetLineControlData

      IF (DebugMode = 13)
         push psw
         push nAR
         cjne a, #1, DB13L0
         mov n, stateAR
         call ShowOnLeds
         
         DB13L0:
         pop nAR
         pop psw
      ENDIF

      pop eAR
      pop nAR
      pop stateAR
      pop psw
      ret


;/**
; * Outputs state & no (dialed) of each line of
; * LineInterface.
; * @param a line number
; * @return state previous state of the LineInte.
; * @return n number that is counted until now
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetLineInterfaceData:
   push psw

   ; a switch() on a
   GLID0:
      cjne a, #0, GLID1
      mov state, lIstate0
      mov n, lIn0
      jmp GLIDEnd

   GLID1:
      cjne a, #1, GLID2
      mov state, lIstate1
      mov n, lIn1
      jmp GLIDEnd
      
   GLID2:
      cjne a, #2, GLID3
      mov state, lIstate2
      mov n, lIn2
      jmp GLIDEnd

   GLID3:
      cjne a, #3, GLID4
      mov state, lIstate3
      mov n, lIn3
      jmp GLIDEnd

   GLID4:

   GLIDEnd:
      pop psw
      ret


;/**
; * Sets the state & no of each LineInterface
; * into the memory.
; * @param a line number
; * @param state updated state of the LineInter.
; * @param n number that is counted until now
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetLineInterfaceData:
   push psw

   ; a switch() on a
   SLID0:
      cjne a, #0, SLID1
      mov lIstate0, state
      mov lIn0, n
      jmp SLIDEnd

   SLID1:
      cjne a, #1, SLID2
      mov lIstate1, state
      mov lIn1, n
      jmp SLIDEnd
      
   SLID2:
      cjne a, #2, SLID3
      mov lIstate2, state
      mov lIn2, n
      jmp SLIDEnd

   SLID3:
      cjne a, #3, SLID4
      mov lIstate3, state
      mov lIn3, n
      jmp SLIDEnd

   SLID4:

   SLIDEnd:
      pop psw
      ret


;/**
; * This routine interfaces the dtct line signal 
; * to meaningful events and if necessary send it 
; * to higher levels.
; * @param a line number
; * @param c debounced dtct signal
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
LineInterface:
   push stateAR
   push nAR
   push eAR
   push psw

   call GetLineInterfaceData
   ; a switch() on state
   jmp LIChk0

   LIEnd:
      call SetLineInterfaceData

      IF (DebugMode = 4)
         push psw
         push nAR
         cjne a, #1, DB4L0
         mov n, stateAR
         call ShowOnLeds
         
         DB4L0:
         pop nAR
         pop psw
      ENDIF

      pop eAR
      pop nAR
      pop stateAR
      ret

   GotoHigh:
      mov state, #StHigh1
      cjne n, #0, IncNo
      mov e, #EvSOD
      call LineControl
      
      IncNo:
         inc n
         jmp LIEnd

   GotoLow:
      mov state, #StLow1
      jmp LIEnd

   LIChk0:
      cjne state, #StDown, LIChk1
      pop psw
      jnc LIEnd
      mov state, #StUp
      mov e, #EvPickup
      call LineControl
      jmp LIEnd

   LIChk1:
      cjne state, #StUp, LIChk2
      pop psw
      jc LIEnd
      mov state, #StLow1
      jmp LIEnd

   LIChk2:
      cjne state, #StLow1, LIChk3
      pop psw
      jc GotoHigh
      mov state, #StLow2
      jmp LIEnd

   LIChk3:
      cjne state, #StLow2, LIChk4
      pop psw
      jc GotoHigh
      mov state, #StLow3
      jmp LIEnd

   LIChk4:
      cjne state, #StLow3, LIChk5
      pop psw
      jc GotoHigh
      mov state, #StLow4
      jmp LIEnd

   LIChk5:
      cjne state, #StLow4, LIChk6
      pop psw
      jc GotoHigh
      mov state, #StDown
      mov e, #EvPutdown
      call LineControl
      jmp LIEnd


   LIChk6:
      cjne state, #StHigh1, LIChk7
      pop psw
      jnc GotoLow
      mov state, #StHigh2
      jmp LIEnd

   LIChk7:
      cjne state, #StHigh2, LIChk8
      pop psw
      jnc GotoLow
      mov state, #StHigh3
      jmp LIEnd
   
   LIChk8:
      cjne state, #StHigh3, LIChk9
      pop psw
      jnc GotoLow
      mov state, #StHigh4
      jmp LIEnd
   
   LIChk9:
      cjne state, #StHigh4, LIChk10
      pop psw
      jnc GotoLow

      ; Digit correction (10->0)
      cjne n, #10, LIChkDOK
      mov n, #0

      LIChkDOK:
         mov e, #EvEOD
         call LineControl
      
         mov n, #0
         mov state, #StUp
         jmp LIEnd

   LIChk10:
      ; invalid state
      pop psw
      IF (DebugMode = 0)
         call Error
      ENDIF
      mov state, #LIDefaultState
      jmp LIEnd


;/**
; * This routine is executed every 1ms and is
; * responsible for updating the conv. tone 
; * signals based on the known tone states.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
ApplyConversationTones:
   push psw
   push dAR
   push b
   push acc   

   ; a for() on d
   mov d, #0
   ACTNext:
      call GetConversationToneState
      mov a, b

      ; a switch on a      
      ACTChk0:
         cjne a, #TnNo, ACTChk1
         mov c, mainWave
         anl c, noTone
         call SetConversationTone
         jmp ACTInc

      ACTChk1:
         cjne a, #TnDial, ACTChk2
         mov c, mainWave
         anl c, dialTone
         call SetConversationTone
         jmp ACTInc
         
      ACTChk2:
         cjne a, #TnBusy, ACTChk3
         mov c, mainWave
         anl c, busyTone
         call SetConversationTone
         jmp ACTInc

      ACTChk3:
         cjne a, #TnInvalid, ACTChk4
         mov c, mainWave
         anl c, invalidTone
         call SetConversationTone
         jmp ACTInc

      ACTChk4:
         cjne a, #TnRingback, ACTChk5
         mov c, mainWave
         anl c, ringbackTone
         call SetConversationTone
         jmp ACTInc

      ACTChk5:
         jmp ACTInc

   ACTInc:
      inc d
      cjne d, #3, ACTNext

   pop acc
   pop dAR
   pop b
   pop psw
   ret


;/**
; * This routine is executed every 1ms and is 
; * responsible for making another timings.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
Int1ms:
   cpl mainWave

   ; make 20ms
   Chk20:
      djnz count20, Chk250
      mov count20, #20
      call Int20ms
   
   ; make 250ms
   Chk250:
      djnz count250, I1End
      mov count250, #250
      call Int250ms
      
   I1End:
      call ApplyConversationTones
      ret


;/**
; * This routine is executed every 20ms. Its main 
; * purpose is sampling input signals and send it
; * to higher levels of software.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
Int20ms:
   push acc
   push psw

   clr a
   DBounce:
      call GetLineDtct
      mov gf0, c
      nop
      call GetLineDtct
      mov gf1, c
      orl c, /gf0
      jnc DBounce
      mov c, gf0
      orl c, /gf1
      jnc DBounce
      
      ;OK (xor of two sequential samples == 0)
      mov c, gf0
      call LineInterface

   IF (DebugMode = 2)
      mov c, l0RingState
      mov led0, c
   ENDIF

   ; apply ring state for each line
   call GetLineRingState
   anl c, ringWave
   call SetLineRng

   NextLine:
      inc a
      cjne a, #4, DBounce

   mov t, #0
   NextTrunk:
      call GetTrunkRdtct
      mov e, #EvRdtctSample
      call TrunkControl
      inc t
      cjne t, #1, NextTrunk


   IF (DebugMode = 14)
      push dAR
      push acc
      push psw

      mov a, #3
      mov d, #0
      call GetSwitch
      mov led0, c
      mov d, #1
      call GetSwitch
      mov led1, c
      mov d, #2
      call GetSwitch
      mov led2, c

      pop psw
      pop acc
      pop dAR
   ENDIF

   pop psw
   pop acc
   ret


;/**
; * This routine is executed every 250ms. It 
; * makes the necessary waves especially for tone
; * generator unit.
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
Int250ms:
   cpl invalidTone
   jb   invalidTone, I250End

   cpl busyTone
   jb  busyTone, I250End

   IF (DebugMode = 1)
      inc debug1
      push nAR
      mov n, debug1
      call ShowOnLeds
      pop nAR
   ENDIF

   clr ringbackTone
   djnz count4, I250End
   setb ringbackTone
   mov count4, #4

   I250End:
      ret


;/**
; * This routine changes the line ring signal.
; * @param a line number
; * @param c the signal to the port
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetLineRng:
   push psw

   ; first check that phone is on-hook
   mov gf0, c
   call GetLineDtct
   cpl c
   anl c,gf0
   push psw

   ; a switch() on a
   SLRng0:
      cjne a, #0, SLRng1
      pop psw
      mov l0_Rng, c
      jmp SLRngEnd

   SLRng1:
      cjne a, #1, SLRng2
      pop psw
      mov l1_Rng, c
      jmp SLRngEnd
      
   SLRng2:
      cjne a, #2, SLRng3
      pop psw
      mov l2_Rng, c
      jmp SLRngEnd

   SLRng3:
      cjne a, #3, SLRng4
      pop psw
      mov l3_Rng, c
      jmp SLRngEnd

   SLRng4:
      pop psw

   SLRngEnd:
      pop psw
      ret


;/**
; * This routine changes line internal signals.
; * @param a line number
; * @param c the signal to the port
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetLineIntr:
   push psw
   ; Maybe here, some check is necessary

   ; a switch() on a
   SLIntr0:
      cjne a, #0, SLIntr1
      pop psw
      mov l0_Intr, c
      jmp SLIntrEnd

   SLIntr1:
      cjne a, #1, SLIntr2
      pop psw
      mov l1_Intr, c
      jmp SLIntrEnd
      
   SLIntr2:
      cjne a, #2, SLIntr3
      pop psw
      mov l2_Intr, c
      jmp SLIntrEnd

   SLIntr3:
      cjne a, #3, SLIntr4
      pop psw
      mov l3_Intr, c
      jmp SLIntrEnd

   SLIntr4:
      pop psw

   SLIntrEnd:
      ret


;/**
; * This routine changes trunk connect signals.
; * @param t trunk number
; * @param c the signal to the port
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetTrunkCnct:
   push psw

   STCnct0:
      cjne t, #0, STCnct1
      pop psw
      mov T0_Cnct, c
      jmp STCnctEnd

   STCnct1:
      pop psw

   STCnctEnd:
      ret


;/**
; * This routine changes the conv. tone signal.
; * @param d conversation number
; * @param c the signal to the port
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
SetConversationTone:
   push psw

   ; a switch() on d
   SCTone0:
      cjne d, #0, SCTone1
      pop psw
      mov C0_Tone, c
      jmp SCToneEnd

   SCTone1:
      cjne d, #1, SCTone2
      pop psw
      mov C1_Tone, c
      jmp SCToneEnd
      
   SCTone2:
      cjne d, #2, SCTone3
      pop psw
      mov C2_Tone, c
      jmp SCToneEnd

   SCTone3:
      pop psw

   SCToneEnd:
      ret


;/**
; * This routine outputs the line detect signal.
; * @param a line number
; * @return c the signal from the port
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetLineDtct:

   ; a switch() on a
   GLDtct0:
      cjne a, #0, GLDtct1
      mov c, l0_Dtct
      jmp GLDtctEnd

   GLDtct1:
      cjne a, #1, GLDtct2
      mov c, l1_Dtct
      jmp GLDtctEnd
      
   GLDtct2:
      cjne a, #2, GLDtct3
      mov c, l2_Dtct
      jmp GLDtctEnd

   GLDtct3:
      cjne a, #3, GLDtct4
      mov c, l3_Dtct
      jmp GLDtctEnd

   GLDtct4:

   GLDtctEnd:
      cpl c ; change low active to high active
      ret


;/**
; * This routine outputs the trunk ring detect 
; * signal.
; * @param t trunk number
; * @return c the signal from the port (trunk)
; * @author Behdad Hosseini, #781413112
; * @version 1.0, Apr 2003
; */
GetTrunkRdtct:
   GTRdtct0:
      cjne t, #0, GTRdtct1
      mov c, T0_Rdtct
      jmp GTRdtctEnd

   GTRdtct1:

   GTRdtctEnd:
      cpl c ; change low active to high active
      ret


end

