.include "tn28def.inc"

.DEF inport_save =R3;
.DEF loop1_store =R4;
.DEF loop2_store =R5;
.DEF loop3_store =R6;
.DEF clk_delay   =R16; specifies the delay of each duty cycle
.DEF rat         =R17; register active time
.DEF rit         =R18; register inactive time.
.DEF rgen1       =R19; general register 1
.DEF rgen2       =R20; general register 2
.DEF loop1	 =r21; loop delay counters
.DEF loop2       =r22	
.DEF loop3       =r23
.DEF width       =R24;  width is the five bit input from motor controller
.DEF active_time =R26;
.DEF inact_time  =R28;

;
; Constants
;
.EQU ActivePin =DDA0; Desired output pin
.EQU LoopLen   =4; Magic num for the length loops are multiplied

;
; Code segment start
;
.CSEG

	rjmp Start; 
	
;
; Subroutines

;
; Get cycle
;
; Read the input and use first three bits to set the delay length. Use the
;   last five bits to calculate the width of active and inactive times
;   of the pulse. Calculate counter value for active time
; It may be wise to do some error checking, and maybe even create minimun 
;   and maximum limits to the lengths of times.
getcycle:
    in  inport_save, PIND
    mov width, inport_save
    ; push the last five bits over three
    lsr width
    lsr width
    lsr width ; the max that width can be is 32
    lsl width ; I'm told this doubles the value, and the laser's max is 65
    brne wasnt_zero
    ldi width, 1; It was zero, and width has >= 1
wasnt_zero:	
	mov rat,width; rat will contain the active time
    ; rit will contain inactive time. which is almost there after its subtracted from 100
    mov rit,width
    ldi rgen1,100
    sub rgen1,rit
    mov rit,rgen1	
    ret
	
set_delays:
    ; this is going to be the multiplier that sets the length of the duty cycle
    ldi rgen1,1
    mov loop1_store,rgen1
    mov loop2_store,rgen1
    mov loop3_store,rgen1
    mov clk_delay, inport_save
    cbr clk_delay,0b11111000

    ldi rgen1,LoopLen
    bst clk_delay,2 ; load third bit into t-register
    brtc j3 ; do some tests to see what will be stored in the loop registers...
    mov loop3_store,rgen1 
j3:	bst clk_delay,1
    brtc j2
    mov loop2_store,rgen1
j2: bst clk_delay,0
    brtc j1
    mov loop1_store,rgen1
j1:	
    ret

;
; Delay
;
; A triple nested loop that chows cycles depending on what
;   is loaded into the loop registers. This is set based on 
;   what came in from the first three bits of InPort
delay:
 	mov loop3,loop3_store
loop3:	mov loop2,loop2_store
loop2:	  mov loop1,loop1_store
loop1:       dec loop1
             brne loop1
          dec loop2
          brne loop2
        dec loop3
        brne loop3
        ret
	
;
; Start of program
;
Start:

;
; Initiate Ports
;
    sbi PACR,ActivePin   ; set portA to output signal
    ldi rgen1,0b00000000 ; set portd as input
    out DDRD,rgen1
    out PORTD,rgen1

;	
; Init cycle times
;	
    rcall getcycle; get new cycle time
    mov active_time,rat; active_time, gets the active time
    mov inact_time,rit; and inact_time gets the inactive time. 
    rcall set_delays
;
; Loop starts, continues indefinitely.
;
ctloop:
    sbi PORTA,ActivePin

ActLoop:
    rcall delay
    subi active_time,1; 0.5 µs
    brne ActLoop; 0.5 µs
    cbi PORTA,ActivePin

InactLoop:
    rcall delay
    subi inact_time,1; 0.5 µs
    brne InactLoop; 0.5 µs
    ; there is a value at PIND, go get it. 
    in  rgen1, PIND
    ; how does it compare to what was saved earlier?
    cpse rgen1,inport_save; if rgen1 and input_save are different...
    rcall getcycle;           get new cycle time
    mov active_time,rat; get the active time
    mov inact_time,rit; get the inactive time. 
    rjmp ctloop; start a new cycle