; gps baud changer
; (c) 2009 by DH6MBM
; This code is freeware, and can be modified, redistributed and whatever
; you like.

.include "def/tn13def.inc"
;.define RS232		; use RS232 level, which is inverted

.equ PRELOAD = 256 - 71	; baud constant for timer
.equ OUTPORT = PORTB
.equ OUTCTL = DDRB
.equ OUTPIN = PB4

.def zero = r2
.def one = r1
.def temp = r16
.def char = r3
.def pre = r18
.def counter = r19

.cseg
	rjmp	main
	reti
	reti
	rjmp	SIG_OVERFLOW0
	reti
	reti
	reti
	reti
	reti
	reti

SIG_OVERFLOW0:
	out TCNT0, pre			; set next timer cycles
.ifdef RS232
	sbrc char, 0			; inverted
.else
	sbrs char, 0	
.endif
	rjmp ov1
	sbi OUTPORT, OUTPIN
	reti
ov1:	cbi OUTPORT, OUTPIN
	reti

main:

	ldi temp, RAMEND		; stack init
	out SPL, temp

	clr zero
	clr one
	inc one

	ldi temp, 1<<CLKPCE		; set clk prescaler to 1
	out CLKPR, temp
	out CLKPR, zero

	ldi ZL, low(command<<1)		; init command pointer
	ldi ZH, high(command<<1)

	sbi OUTCTL, OUTPIN		; set pin for output

	ldi temp, 1<<TOIE0		; enable timer interrupt
	out TIMSK0, temp	

	ldi temp, (1<<SE)		; enable sleep mode
	out MCUCR, temp

	sei				; enable global interrupts

	out TCCR0A, zero		; set normal operation
	out TCNT0, zero			; wait as long as possible
					;  for the first time
	mov char, one			; set level to 1
	clr pre				; set preload for timer to max
	ldi temp, (1<<CS02) | (1<<CS00)	; start timer,
	out TCCR0B, temp		;  select prescaler 1024

	ldi temp, 100			; power up wait
wait:	sleep
	dec temp
	brne wait

	ldi pre, PRELOAD		; set preload for timer
	ldi temp, 1<<CS00		
	out TCCR0B, temp		; select prescaler 1 (full CLK)

byteloop:
	lpm r0, Z+			; get next byte
	tst r0
	breq down			; end?

	clr char			; set start bit
	sleep				; wait for interrupt

	mov char, r0
	ldi counter, 8

bitloop:
	sleep				; wait for interrupt
	lsr char			; shift next bit
	dec counter
	brne bitloop

	mov char, one			; set stop bit
	sleep				; wait for interrupt

	out TCNT0, one			; wait for next char
					; much time to load the next char
	rjmp byteloop

down:
	cbi OUTCTL, OUTPIN		; set pin for Tri-state input again, so
	cbi OUTPORT, OUTPIN		; the normal RXD line can be used anyway
	ldi temp, (1<<SE)|(1<<SM1)	; power down
	out MCUCR, temp
	sleep

stop:	rjmp stop

command:	.db 13,10,"@CB 9600",13,10,0
