;
; i0.test.bridge.asm
; bridge bytes between I0 and RS-232
; Modified by Ken Avery and then Tom Owens on 12/17/05 for MAS863
;
; Neil Gershenfeld  CBA  MIT  9/8/05
; (c) Massachusetts Institute of Technology 2005
; Permission granted for experimental and personal use;
; license for commercial use available from MIT
;

.include "tn13def.inc"
;.equ rxpin = PB0; receive pin
.equ txpin = PB4; transmit pin
.equ clickin = PB3 ; I0 input pin
.equ buttonbit = 2; pushbutton bit
.equ buttonpin = PB2; pushbutton pin
.equ ledpin2 = PB1 ; I0 output pin

.def txbyte =  R24
.def bitcount = R16; bit counter
.def byte = R17; tx/rx byte
.def clickdelay2 = R18; click spacing
.def tripledelay = R19; triple click spacing
.def count = R20; loop counter
.def doublecount = R21; double loop count
.def temp = R22; temporary storage
.def temp1 = R23; temporary storage

.cseg
.org 0
rjmp reset

;
; getchar
; input a serial byte following first transition
;
;getchar:
 ;  ldi bitcount, 9 ; 8 data bit + 1 stop bit
 ;  rcall bitdelay ; 0.5 bit delay
  ; getcharloop:
   ;   rcall bitdelay ; 1 bit delay
    ;  rcall bitdelay ;
    ;  clc ; clear carry
     ; sbis PINB, rxpin ; if RX pin high skip
     ;    sec ; otherwise set carry
      ;dec bitcount
  ;    breq getcharend ; return if all bytes read
  ;    ror byte ; otherwise shift bit into receive byte
  ;    rjmp getcharloop ; get next bit
  ; getcharend:
   ;   ret
;
; putchar
; output a serial byte
;
putchar:
   .equ sb = 1 ; number of stop bits
   ldi bitcount, 9+sb; 1+8+sb
   com byte ; invert everything
   sec ; set start bit
   putchar0:
      brcc putchar1 ; if carry set
      sbi PORTB, txpin ; send a '0'
      rjmp putchar2 ; else
   putchar1:
      cbi PORTB, txpin ; send a '1'
      nop ; even out timing
   putchar2:
      rcall bitdelay ; one bit delay
      rcall bitdelay
      lsr byte ; get next bit
      dec bitcount ; if not all bits sent
      brne putchar0 ; send next bit
   ret
;
; getclick
; input an I0 byte following first click
;
getclick:
   clr clickdelay2
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   sbi ACSR, ACI ; reset comparator
   ;
   ; find click delay from arrival of second start click
   ;
   start2:
      inc clickdelay2
      breq getclicktimeout ; time-out if count overflows
      sbis ACSR, ACI
      rjmp start2
   ;mov byte, clickdelay2
   ;rcall putchar
   mov tripledelay, clickdelay2
   add tripledelay, clickdelay2
   add tripledelay, clickdelay2
   ;
   ; decode data clicks
   ;
   clr byte
   ldi bitcount, 8
   bitloop:
      ;
      ; time arrival of next click
      ;
      clr count
 	  nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      nop
      ;nop
      ;nop
      ;nop
      ;nop
      ;nop
      ;nop
      ;nop
      ;nop
      sbi ACSR, ACI ; reset comparator
      bitclickloop:
         inc count
         breq getclicktimeout ; time-out if count overflows
         sbis ACSR, ACI
         rjmp bitclickloop
      ;
      ; determine bit delay
      ;
      mov doublecount, count
      add doublecount, count
      cp doublecount, tripledelay
      brsh zero
         ;
         ; one bit
         ;
         sec ; set carry
         ror byte ; shift in carry
         ;
         ; even out timing with click delay
         ;
         mov count, clickdelay2
         onedelay:
            nop ; time for breq
            nop ; time for sbis
nop
nop
            dec count
            brne onedelay
         dec bitcount
      	 brne bitloop ; output if byte received
   	     rjmp getclickend
      zero:
         ;
         ; zero bit
         ; 
         clc ; clear carry
	 ror byte ; shift in carry
         dec bitcount
         brne bitloop ; output if byte received
      getclickend:
         ret
      getclicktimeout:
         mov byte, clickdelay2
	 ret
;
;
; packet_delay
; delay between packets
;
packet_delay:
   ldi temp, 255
   packet_delayloop:
      ldi temp1, 255
      packet_delayloop1:
         dec temp1
         brne packet_delayloop1
      dec temp
      brne packet_delayloop
   ret

; putclick
; output an I0 byte
;
putclick:
   ldi bitcount, 8
   sec; set start bit
   ;
   ; send start clicks
   ;
   cbi PORTB, ledpin2
   sbi PORTB, ledpin2
   rcall clickdelay
   cbi PORTB, ledpin2
   rcall clickdelay
   sbi PORTB, ledpin2
   rcall clickdelay
   cbi PORTB, ledpin2
   cbi PORTB, ledpin2
   rcall clickdelay
   ;
   ; send data clicks
   ;
   putclick0:
      lsr txbyte; get next bit
      brcc putclick1; if carry set, send a 1 click
      cbi PORTB, ledpin2
      sbi PORTB, ledpin2
      rcall clickdelay
      cbi PORTB, ledpin2
	  rcall clickdelay
      cbi PORTB, ledpin2
      rcall clickdelay
	  cbi PORTB, ledpin2
      cbi PORTB, ledpin2
      rcall clickdelay
      rjmp putclick2; otherwise ...
   putclick1:
      cbi PORTB, ledpin2; ... send a 0 click
      cbi PORTB, ledpin2
      rcall clickdelay
      cbi PORTB, ledpin2
	  rcall clickdelay
      sbi PORTB, ledpin2
      rcall clickdelay
      cbi PORTB, ledpin2
      cbi PORTB, ledpin2
      rcall clickdelay
   putclick2:
      dec bitcount; if not all bits sent
      brne putclick0; send next bit
   ;
   ; send stop clicks
   ;
   cbi PORTB, ledpin2
   sbi PORTB, ledpin2
   rcall clickdelay
   cbi PORTB, ledpin2
   rcall clickdelay
   sbi PORTB, ledpin2
   rcall clickdelay
   cbi PORTB, ledpin2
   cbi PORTB, ledpin2
   rcall clickdelay
   ;
   ; return
   ;
   ret
;
; bitdelay
; serial bit delay
;
.equ b = 17
bitdelay:
   ldi temp, b
   bitdelayloop:
      dec temp
      brne bitdelayloop
   ret
;
; clickdelay
; delay between clicks
;
clickdelay:
   ldi temp, 200
   clickdelayloop:
      ;ldi temp1, 200
      ;clickdelayloop2:
      ;   dec temp1
         ;brne clickdelayloop2
      dec temp
      brne clickdelayloop
   ret
;
pulsedelay:
   ldi temp, 3
   pulsedelayloop:
      dec temp
      brne pulsedelayloop
   ret
;
;
; main program
;
reset:
   ldi temp, low(RAMEND) ; set stack pointer to top of RAM
   out SPL, temp ;
   cbi PORTB, txpin; init comm pin for output
   sbi DDRB, txpin
   sbi PORTB, buttonpin ; init pushbutton pin for input with pull-up
   cbi DDRB, buttonpin ;
   sbi PORTB, ledpin2 ; init irled control pin for output
   sbi DDRB, ledpin2 
   cbi ACSR, ACIS1 ; setup comparator to output on state change
   cbi ACSR, ACIS0 ;
   sbi ADCSRB, ACME ; setup comparator to use ADC multiplexer
   cbi ADCSRA, ADEN ;
   sbi ADMUX, MUX1 ; set channel to ADC3
   sbi ADMUX, MUX0 ;
   loop:
      ;
      ; wait for a click or a bit
      ;
      sbi ACSR, ACI ; reset comparator
      waitloop:
         sbic ACSR, ACI ; check for click
            rjmp click
         sbic PINB, buttonbit ; check for button
            rjmp waitloop
      button:
         ;
         ; send the string and blink the LED
         ;
         cbi PORTB, ledpin2
		 ;sbi PORTB, ledpin2
         ;ldi txbyte, END ; SLIP start
         ;rcall putclick
         ;rcall chardelay
         ;ldi txbyte, 254
		 rcall packet_delay
         sbi PORTB, ledpin2
         ;cbi PORTB, ledpin2
         rjmp loop
      click:
         ;
         ; blink the LED
         ;
		 rcall getclick
         ;cbi PORTB, ledpin2
			 ;ldi byte, 4
		 rcall putchar
         ;rcall packet_delay
         ;sbi PORTB, ledpin2
		 rjmp loop
