
;; Remote Control - Copyright 2009 by Michael Kohn
;; Email: mike at mikekohn.net
;;   Web: http://www.mikekohn.net/
;;
;; Control a tv with an attiny13
;; Tested on Samsung LN-S3251D TV

;.include "tn13def.inc"
.device ATtiny13

;  cycles  sample rate   @4.8 MHz:
;    61   39.2kHz * 2

; start: 4.5ms on / 4.5ms off
;           21600 / 21600         21600 / 61 = 354
;
;     0: 0.56ms on/ 0.56ms off     2688 / 61 = 44
;     1: 0.56ms on/ 1.69ms off     2688 / 61 = 44
;                                  8112 / 61 = 133
;  stop: 0.56ms on/ 0.56ms off

; r0  = 0
; r1  = 1
; r15 = 255
; r14 = temp
; r17 = temp
; r20 = current bit (2 phase: 01 = 1, 10 = 0)
; r21 = current carrier freq toggle bit
; r22 = carrier freq count bit (64 waves at 36kHz for 1.778ms)
; r23 = current actual toggle bit
; r30 = command low byte ptr
; r31 = command high byte ptr
;

; note: CLKSEL 10

.cseg

.equ PART_BIT = 61
.equ SHORT = 44
.equ LONG = 133

.org 0x000
  rjmp start
.org 0x003
  reti
.org 0x006
  rjmp service_interrupt
  ;ijmp         ; might as well ijmp, IJMP!

;; FIXME - erase this padding.. it's dumb
.org 0x020

start:
  ;; I'm busy.  Don't interrupt me!
  cli

  ;; 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

  ldi r30, (power_off*2)&0xff
  ldi r31, (power_off*2)>>8

  ldi r20, 0x87             ; no command
  mov r21, r1               ; set the pin to 1 with no toggle
  ldi r22, PART_BIT         ; 64 waves of 36kHz
  eor r23, r23              ; start with nothing banged out

  ;; Set up PORTB
  out DDRB, r1              ; entire port B is output
  out PORTB, r15            ; turn off all of port B for fun

  ;; Set up TIMER1
  ;lds r17, PRR
  ;andi r17, 255 ^ (1<<PRTIM1)
  ;sts PRR, r17                   ; turn of power management bit on TIM1

  ldi r17,  61                    ; set carrier freq
  out OCR0A, r17

  ldi r17, (1<<OCIE0A)
  out TIMSK0, r17                ; enable interrupt compare A 
  ldi r17, (1<<WGM01)
  out TCCR0A, r17                ; normal counting (0xffff is top, count up)
  ldi r17, (1<<CS00)             ; CTC OCR0A  Clear Timer on Compare
  out TCCR0B, r17                ; prescale = 1 from clock source

  ; Fine, I can be interrupted now
  sei

main:
  rjmp main               ; main() { while(1); }

;; The Great Interrupt Routine!
service_interrupt:
  eor r21, r23
  out PORTB, r21

  dec r22
  breq bang_half_bit
  reti

bang_half_bit:
  ser r21
  lpm r22, Z+
  lpm r23, Z+
  cpi r22, 0xff
  brne exit_interrupt

  ;; loop around
  ldi r30, (power_off*2)&0xff
  ldi r31, (power_off*2)>>8
  ;ldi r20, 0x80

exit_interrupt:
  reti

signature:
.db "Remote Control - Copyright 2009 - Michael Kohn - Version 0.04",0

;; START BIT
;; PRE: E0E0 1 1 1 0  0 0 0 0  1 1 1 0  0 0 0 0 
;; COM: 40BF 0 1 0 0  0 0 0 0  1 0 1 1  1 1 1 1
;; END BIT

power_off:
.db 177, 1, 177, 1, 177, 0, 177, 0
;; E
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, SHORT, 0

;; 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; E
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, SHORT, 0

;; 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; 4
.db SHORT, 1, SHORT, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; B
.db SHORT, 1, LONG, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0

;; F
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0

;; STOP
.db SHORT, 1, SHORT, 0
.db 254, 0, 254, 0, 254, 0, 254, 0
.db 254, 0, 254, 0, 254, 0, 254, 0
.db 254, 0, 254, 0, 254, 0, 254, 0
.db 254, 0, 254, 0, 150, 0
.db 0xff, 0x00

;; START BIT
;; PRE: E0E0 1 1 1 0  0 0 0 0  1 1 1 0  0 0 0 0 
;; COM: F00F 1 1 1 1  0 0 0 0  0 0 0 0  1 1 1 1
;; END BIT

mute_tv:
.db 177, 1, 177, 1, 177, 0, 177, 0
;; E
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, SHORT, 0

;; 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; E
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, SHORT, 0

;; 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; F
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0

;; 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0
.db SHORT, 1, SHORT, 0

;; F
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0
.db SHORT, 1, LONG, 0

;; STOP
.db SHORT, 1, SHORT, 0
.db 254, 0, 254, 0, 254, 0, 254, 0
.db 254, 0, 254, 0, 254, 0, 254, 0
.db 254, 0, 254, 0, 254, 0, 254, 0
.db 254, 0, 254, 0, 150, 0
.db 0xff, 0x00



