;
; i0.6.thtp.asm
; Modified by Tom Owens 12/17/05 for MAS863 assignment #11
;
; Neil Gershenfeld  CBA  MIT  11/27/05
; (c) Massachusetts Institute of Technology 2005
; Permission granted for experimental and personal use;
; license for commercial use available from MIT
;
; transmit a SLIP UDP HTTP (THTP) packet when the button is pushed
; blink the LED when the button is pushed or a click is received
;

.include "tn13def.inc"

.equ ledpin = PB1; LED pin
.equ buttonbit = 2; pushbutton bit
.equ buttonpin = PB2; pushbutton pin
.equ clickpin = PB3; click input pin
.equ irledpin = PB4; irled output pin

.def bitcnt = R16; bit counter
.def txbyte = R17; bit counter
.def temp = R18; temporary storage
.def temp1 = R19; temporary storage
.def count = R20; loop counter
.def check_lo = R21; lo checksum accumulator
.def check_hi = R22; hi checksum accumulator
.def check_carry = R23; checksum carry accumulator
.def zero = R24; 0

.equ END = 192
.equ ESC = 219
.equ ESC_END = 220
.equ ESC_ESC = 221

.macro putslip
   ;
   ; putslip
   ; outputs char in txbyte, with SLIP mapping
   ;
   ldi temp, END
   cpse txbyte, temp
   rjmp putslipchar
      mov temp, txbyte
      ldi txbyte, ESC
      rcall putclick
      rcall chardelay
      ldi txbyte, ESC_END
      rcall putclick
      rcall chardelay
      mov txbyte, temp
      rjmp endputslip
   ldi temp, ESC
   cpse txbyte, temp
   rjmp putslipchar
      mov temp, txbyte
      ldi txbyte, ESC
      rcall putclick
      rcall chardelay
      ldi txbyte, ESC_ESC
      rcall putclick
      rcall chardelay
      mov txbyte, temp
      rjmp endputslip
   putslipchar:
      rcall putclick
      rcall chardelay
   endputslip:
      .endmacro

.cseg
.org 0
rjmp reset

;
; the packet
;
   .equ ip_header_size = 20
   .equ ip_header_size_before_checksum = 10
   .equ ip_header_size_after_checksum = 8
   .equ udp_header_size = 8
   .equ data_size = 72
   ip:
      .db 0x45, 0
          ; version = 4 (4 bits)
          ; header length = 5 32-bit words (4 bits)
          ; type of service
      .db 0, ip_header_size + udp_header_size + data_size
          ; total length
      .db 0, 0
          ; identification
      .db 0, 0
          ; flag (3 bits)
	  ; fragment offset (13 bits)
      .db 255, 17
          ; time to live
          ; protocol = 17 for UDP
      .db 0, 0
          ; header checksum (to be calculated)
;      .db 192, 168, 1, 101
      .db 192, 168, 1, 102
	  ; source address
      .db 127, 0, 0, 1
	  ; destination address
   udp:
      .db 0, 0
          ; source port = 0
      .db 0x10, 0
          ; destination port = 4096
      .db 0, udp_header_size + data_size
          ; length
      .db 0, 0
          ; packet checksum
   data:
      .db "HTTP/1.1 200 OK",13,10,"Content-Type: text/html",13,10,13,10,"<center><H1>button pushed ",13,10 ; 44 bytes HTTP header + 14 bytes HTML + text string = data_size
;      .db "HTTP/1.1 200 OK",13,10,"Content-Type: text/html",13,10,13,10,"<center><H1>Internet 0    ",13,10 ; 44 bytes HTTP header + 14 bytes HTML + text string = data_size
;
; putclick
; send char in txbyte clicks
;
putclick:
   ldi bitcnt, 8
   sec; set start bit
   ;
   ; send start clicks
   ;
   sbi PORTB, irledpin
   rcall pulsedelay
   cbi PORTB, irledpin
   rcall clickdelay
   sbi PORTB, irledpin
   rcall pulsedelay
   cbi PORTB, irledpin
   rcall clickdelay
   ;
   ; send data clicks
   ;
   putclick0:
      lsr txbyte; get next bit
      brcc putclick1; if carry set, send a 1 click
      sbi PORTB, irledpin
      rcall pulsedelay
	  cbi PORTB, irledpin
      rcall clickdelay
      cbi PORTB, irledpin
      rcall pulsedelay
	  cbi PORTB, irledpin
      rcall clickdelay
      rjmp putclick2; otherwise ...
   putclick1:
      cbi PORTB, irledpin; ... send a 0 click
      rcall pulsedelay
	  cbi PORTB, irledpin
      rcall clickdelay
      sbi PORTB, irledpin
      rcall pulsedelay
	  cbi PORTB, irledpin
      rcall clickdelay
   putclick2:
      dec bitcnt; if not all bits sent
      brne putclick0; send next bit
   ;
   ; send stop clicks
   ;
   sbi PORTB, irledpin
   rcall pulsedelay
   cbi PORTB, irledpin
   rcall clickdelay
   sbi PORTB, irledpin
   rcall pulsedelay
   cbi PORTB, irledpin
   rcall clickdelay
   ret;
;
; clickdelay
; delay between clicks
;
clickdelay:
   ldi temp, 30
   clickdelayloop:
      dec temp
      brne clickdelayloop
   ret
;
; pulsedelay
; delay to lengthen click pulse
;
pulsedelay:
   ldi temp, 5
   pulsedelayloop:
      dec temp
      brne pulsedelayloop
   ret
;
; chardelay
; delay between characters
;
chardelay:
   ldi temp, 100
   chardelayloop:
      ldi temp1, 10
      chardelayloop1:
         dec temp1
         brne chardelayloop1
      dec temp
      brne chardelayloop
   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
;
; print_packet
; send a packet, calculating checksums and doing SLIP encoding
;
print_packet:
   ;
   ; find the header checksum
   ;
   ldi zl, low(ip*2)
   ldi zh, high(ip*2)
   ldi count, ip_header_size
   clr check_lo
   clr check_hi
   clr check_carry
   ip_checksum_loop:
      inc zl
      lpm
      add check_lo, R0
      dec count
      dec zl
      lpm
      adc check_hi, R0
      adc check_carry, zero
      inc zl
      inc zl
      dec count
      brne ip_checksum_loop
   add check_lo, check_carry
   adc check_hi, zero
   com check_lo
   com check_hi
   ;
   ; send the packet
   ;
   ldi txbyte, END ; SLIP start
   rcall putclick
   rcall chardelay
   ldi zl, low(ip*2)
   ldi zh, high(ip*2)
   ldi count, ip_header_size_before_checksum
   print_loop: ; start of IP header
      lpm
      mov txbyte, R0
      putslip
      inc zl
      dec count
      brne print_loop
   mov txbyte, check_hi ; IP header checksum
   putslip
   inc zl
   mov txbyte, check_lo
   putslip
   inc zl
   ldi count, (ip_header_size_after_checksum + udp_header_size + data_size)   
   print_loop1: ; rest of IP header
      lpm
      mov txbyte, R0
      putslip
      inc zl
      dec count
      brne print_loop1
   ldi txbyte, END ; SLIP end
   rcall putclick
   rcall chardelay
   ret
;
; main program
;
reset:
   ldi temp, low(RAMEND) ; set stack pointer to top of RAM
   out SPL, temp ;
   clr zero
   sbi PORTB, ledpin ; init LED pin for output
   sbi DDRB, ledpin ;
   sbi PORTB, buttonpin ; init pushbutton pin for input with pull-up
   cbi DDRB, buttonpin ;
   cbi PORTB, irledpin ; init irled control pin for output
   sbi DDRB, irledpin ; 
   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 the button to be pressed or a click to arrive
      ;
      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, ledpin
         rcall print_packet
         sbi PORTB, ledpin
         rjmp loop
      click:
         ;
         ; blink the LED
         ;
         cbi PORTB, ledpin
         rcall packet_delay
         sbi PORTB, ledpin
         rjmp loop
