
;; Garage Door Opener - Copyright 2009 by Michael Kohn
;; Email: mike to mikekohn.net
;;   Web: http://www.mikekohn.net/
;;
;; Keypad control for a garage door

;.include "tn2313def.inc"
.device ATtiny2313

; CKSEL: 0110 - Run on internal 128 kHz clock

;  cycles  sample rate   @128 kHz:
;    65536 = 1/2 second 

; PDO = UART RX (Currently set for 128kHz and 300 baud.. and problematic)
; PD1 = UART TX (Currently set for 128kHz and 300 baud.. and problematic)
; PD3 = Input-: Program Mode
; PD4 = Output: Garage Door Output
; PD5 = Output: DEBUG LED or Buzzer: turn on when button pushed until let go
; PB1 = Input-: from keypad
; PB2 = Output: to keypad
; PB3 = Input-: from keypad
; PB4 = Output: to keypad
; PB5 = Input-: from keypad
; PB6 = Output: to keypad
; PB7 = Output: to keypad

; Keypad
; 1: 2+3
; 2: 2+1
; 3: 2+5
; 4: 7+3
; 5: 7+1
; 6: 7+5
; 7: 6+3
; 8: 6+1
; 9: 6+5
; *: 4+3
; 0: 4+1
; #: 4+5

; r0  = 0
; r1  = 1
; r15 = 255
; r14 = temp
; r17 = temp
; r26 = X(lsb)
; r27 = X(msb) pointer to ring buffer in SRAM

; Not sure why this pause is needed between polling...
.macro PAUSE
  nop
  nop
  nop
  nop
  nop
  nop
  nop
  nop
  nop
  nop
  nop
  nop
  nop
.endm

.cseg

.org 0x0000

start:
  ;; Set up stack ptr
  ;ldi r17, RAMEND>>8
  ;out SPH, r17
  ldi r17, RAMEND&255
  out SPL, r17

  ;; r0 = 0, r1 = 1, r15 = 255
  eor r0, r0
  eor r1, r1
  inc r1
  ;ldi r17, 0xff
  ;mov r15, r17
  eor r15, r15
  dec r15

  ; X (r27:r26) = start of ring buffer
  ldi r27, (SRAM_START>>8)
  ldi r26, (SRAM_START&0xff)

  ;; Set up PORTB
  ldi r17, (1<<PB7)|(1<<PB6)|(1<<PB4)|(1<<PB2)
  out DDRB, r17             ; 1,3,5 are input
  out PORTB, r15            ; Turn pullups on
  ldi r17, (1<<PD5)|(1<<PD4)
  out DDRD, r17             ; PORTD is output on pin 5
  ldi r17, (1<<PD3)
  out PORTD, r17            ; turn on input pullup on PD3

  ;; Set up rs232 baud rate
  ;ldi r17, (416>>8)
  ;out UBRRH, r17
  ;ldi r17, (416&0xff)
  ;out UBRRL, r17            ; 416 @ 8MHz = 1200 baud

  out UBRRH, r0
  ldi r17, 24
  out UBRRL, r17            ; 24 @ 128kHz = 300 baud

  ;; Set up rs232 options
  ldi r17, (1<<UCSZ0)|(1<<UCSZ1)      ; sets up data as 8N1
  out UCSRC, r17
  ldi r17, (1<<TXEN)|(1<<RXEN)        ; enables send/receive
  out UCSRB, r17
  out UCSRA, r0

main:
  rcall poll_keypad       ; See if user pushed a button
  tst r16
  breq main               ; r16 == 0: no button pushed

  mov r18, r16            ; Save r16 since we'll trash it soon
  mov r24, r16            ; output on rs232 for debug
  rcall send_char

  sbi PORTD, PD5          ; Turn on debug LED
wait_for_release:
  rcall delay             ; debounce
  rcall poll_keypad
  tst r16
  brne wait_for_release   ; loop until r16 == 0 (button released)

  cbi PORTD, PD5          ; Turn off debug LED

  cpi r18, '#'            ; if (r18 == '#') { check ring buffer }
  brne not_tic_pushed
  rcall check_ring
  rcall clear_ring
  rjmp main

not_tic_pushed:
  cpi r18, '*'            ; if (r18 == '*') { program_eeprom  }
  brne not_star_pushed
  rcall program_eeprom
  rcall clear_ring
  rjmp main

not_star_pushed:          ; else { put_in_ring_buffer }
  st X+, r18
  cpi r26, SRAM_START+4
  brne dont_ring_around
  ldi r26, (SRAM_START&0xff)
dont_ring_around:
  rjmp main

delay:
  mov r14, r15
  ldi r17, 5
delay_l1:
  dec r14
  brne delay_l1
  dec r17
  brne delay_l1
  ret

clear_ring:
  ldi r24, 'C'       ;; ZOMG DEBUG
  rcall send_char
  sts SRAM_START, r0
  sts SRAM_START+1, r0
  sts SRAM_START+2, r0
  sts SRAM_START+3, r0
  ret

; void send_char(r24)  : r14 trashed
send_char:
  in r14, UCSRA      ; check to see if it's okay to send a char
  sbrs r14, UDRE
  rjmp send_char      ; if it's not okay, loop around :)
  out UDR, r24        ; output a char over rs232
  ret

; int pollkeypad();   Returns r16, Trashes (nothing)
poll_keypad:
  clr r16
  out PORTB, r15
  cbi PORTB, PB2
  PAUSE

  ; 1: 2+3
  sbic PINB, PB3
  rjmp not_1
  ldi r16, '1' 
  ret
not_1:

  ; 2: 2+1
  sbic PINB, PB1
  rjmp not_2
  ldi r16, '2' 
  ret
not_2:

  ; 3: 2+5
  sbic PINB, PB5
  rjmp not_3
  ldi r16, '3'
  ret
not_3:

  ;;;;; Next Row ;;;;
  sbi PORTB, PB2
  cbi PORTB, PB7
  PAUSE

  ; 4: 7+3
  sbic PINB, PB3
  rjmp not_4
  ldi r16, '4'
  ret
not_4:

  ; 5: 7+1
  sbic PINB, PB1
  rjmp not_5
  ldi r16, '5'
  ret
not_5:

  ; 6: 7+5
  sbic PINB, PB5
  rjmp not_6
  ldi r16, '6'
  ret
not_6:

  ;;;;; Next Row ;;;;
  sbi PORTB, PB7
  cbi PORTB, PB6
  PAUSE

  ; 7: 6+3
  sbic PINB, PB3
  rjmp not_7
  ldi r16, '7'
  ret
not_7:

  ; 8: 6+1
  sbic PINB, PB1
  rjmp not_8
  ldi r16, '8'
  ret
not_8:

  ; 9: 6+5
  sbic PINB, PB5
  rjmp not_9
  ldi r16, '9'
  ret
not_9:

  ;;;;; Next Row ;;;;
  sbi PORTB, PB6
  cbi PORTB, PB4
  PAUSE

  ; *: 4+3
  sbic PINB, PB3
  rjmp not_star
  ldi r16, '*'
  ret
not_star:

  ; 0: 4+1
  sbic PINB, PB1
  rjmp not_0
  ldi r16, '0'
  ret
not_0:

  ; #: 4+5
  sbic PINB, PB5
  rjmp not_tic_tac_toe
  ldi r16, '#'
  ret
not_tic_tac_toe:
  ret

check_ring:
  ldi r24, 'R' ;;; ZOMG DEBUG
  rcall send_char
  ldi r17, 0
read_loop:                    ; while (r17 < 4)
  ld r14, X+                  ; read next char from ring
  cpi r26, SRAM_START+4
  brne wait_eeprom_rd
  ldi r26, (SRAM_START&0xff)
wait_eeprom_rd:
  sbic eecr, eepe
  rjmp wait_eeprom_rd
  out eear, r17
  sbi eecr, eere
  in r18, eedr
  cp r18, r14
  brne bad_code
  inc r17
  cpi r17, 4
  brne read_loop

  sbi PORTD, PD4
  rcall delay_long
  cbi PORTD, PD4
  ret

bad_code:
  ldi r24, 'B' ;;; ZOMG DEBUG
  rcall send_char
  ret

program_eeprom:
  sbic PIND, PD3             ; make sure the program pin is cleared
  ret
  ldi r24, 'W' ;;; ZOMG DEBUG
  rcall send_char
  ldi r17, 0
program_loop:                 ; while (r17 < 4)
  ld r14, X+                  ; read next char from ring
  cpi r26, SRAM_START+4
  brne wait_eeprom_wr
  ldi r26, (SRAM_START&0xff)
wait_eeprom_wr:
  sbic eecr, eepe
  rjmp wait_eeprom_wr
  out eear, r17
  out eedr, r14
  sbi eecr, eempe
  sbi eecr, eepe
  inc r17
  cpi r17, 4                  ; see if r17 == 4
  brne program_loop
  ret

delay_long:
  mov r14, r15
  ldi r17, 128
delay_long_l1:
  dec r14
  brne delay_long_l1
  dec r17
  brne delay_long_l1
  ret

signature:
.db "Garage Door Opener - Copyright 2009 - Michael Kohn - Version 0.04",0

