;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; measurer.asm
; the operating system for the HTMAA (How to Measure Almost Anything) tool
;
; (c) a whole lot of people taking class 863 at the MIT Media Lab in 2005
; see credits at bottom, or in indvidual sections
;
;
.include "tn13def.inc"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Pin Definitions Section
;
.equ txpin = PB1; transmit pin
.equ rxpin = PB0; receive pin
.equ micpin = PB2; mic data in pin

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variable Declarations
;
.def bitcnt = R16; bit counter
.def temp = R17; temporary storage
.def temp1 = R18; temporary storage
.def txbyte = R19; transmit byte
.def rxbyte = R20; receive byte
.def which_mode = R21; stores which mode we are currently in


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Interrupt Handlers
;
.cseg


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Program memory:
;
.org 0
rjmp init ; let's start by running init


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Utility functions
; these can be used by any code

;
; putchar
; assumes no line driver (doesn't invert bits)
;
.equ sb = 1; number of stop bits
putchar:
    ldi bitcnt, 9+sb; 1+8+sb
    com txbyte; 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 txbyte; get next bit
         dec bitcnt; if not all bits sent
         brne putchar0; send next bit
    ret;
;
; getchar
; assumes no line driver (doesn't invert bits)
;
getchar:
    ldi bitcnt,9 ; 8 data bit + 1 stop bit
    getchar1:
        sbis PINB, rxpin ; wait for start bit
        rjmp getchar1
    rcall bitdelay ; 0.5 bit delay
    getchar2:
        rcall bitdelay ; 1 bit delay
        rcall bitdelay ;
        clc ; clear carry
        sbis PINB, rxpin ; if RX pin high skip
            sec ; otherwise set carry
        dec bitcnt
        breq getchar3 ; return if all bits read
        ror rxbyte ; otherwise shift bit into receive byte
        rjmp getchar2 ; go get next bit
    getchar3:
        ret
        
;
; print
; prints a null-terminated string
;
print:
    print_loop:
        lpm
        mov txbyte,R0
        cpi txbyte,0
        breq return
        rcall putchar
        inc zl
        rjmp print_loop
    return:
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Mode-specific functions
;

; Digitize input from microphone
;
mic_mode:
	; main mic program
	;
   	; initiate communication
   	;
   	sbi PORTB, txpin ; set initial value
   	sbi DDRB, txpin ; set for output
   	;
   	; initiate the A/D converter
   	;
   	cbi ADMUX, REFS0  ; set Vcc as the reference voltage
   	cbi ADMUX, ADLAR  ; right-adjust result (make sure left-adj is off)
   	sbi ADCSRA, ADEN  ; enable A/D
   	cbi ADCSRA, ADATE ; set for single-shot measurement (turn off auto trigger)
   	cbi ADCSRA, ADIE  ; disable A/D interrupt
   	cbi ADCSRA, ADPS2 ; set prescaler for input clock=tinyclock/2
   	cbi ADCSRA, ADPS1 ; " 
   	cbi ADCSRA, ADPS0 ; " (these settings make the A/D input clock as fast as possible)
   	cbi ADMUX, MUX1   ; input on ADC1
   	sbi ADMUX, MUX0   ; "
   	;
   	; infinite main mic loop
   	;
   	mic_loop:
      	;
      	; read first response
      	;
      	sbi ADCSRA, ADSC ; start conversion
      	adloopa:
      	   sbic ADCSRA, ADSC ; loop until A/D conversion is complete
      	   rjmp adloop1a
      	;
	;read next response
	mic_loopb:

            sbi ADCSRA, ADSC ; start conversion
      	    ; send last conversion and wait for current conversion to end
      	    ;
      	    in txbyte, ADCL ; send low byte from previous conversion
      	    rcall putchar
      	    in txbyte,ADCH ; send high byte from previous conversion
      	    rcall putchar
	    ;
	    adloopb:
      	        sbic ADCSRA, ADSC ; loop until conversion is complete
      	        rjmp adloop2b
	    ;      	    
	    rjmp mic_loop ; continue to get and send conversions forever.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Operating System functions
; these functions are only to be used by the operating system microcode
; if you need to use them, please let seth know, and he will make an accessor
;

;
; bit delay
.equ b = 17 ; 9600 bps 5V
bitdelay:
    ldi temp, b
    bitloop:
        dec temp
        brne bitloop
    ret
    
;
; print_delay
; delay between printed lines
;
.equ delay = 200
print_delay:
    ldi temp1, delay
    charloop1:
        ldi temp, delay
        charloop0:
            dec temp
            brne charloop0
        dec temp1
        brne charloop1
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; init: main entry point for the program
; pick a mode to work in, and go do it.
;
init:
    ldi temp, low(RAMEND) ; set stack pointer to top of RAM
    out SPL, temp
    rjmp mic_mode


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CREDITS:
;    Stacy DeRuiter
;    microcode (Seth)
