; W8DIZ Iambic-Mode-B Keyer used with the Universal 1Watter Transceiver.
; http://kitsandparts.com/1watter-u.php
; August 27, 2015
; using ATmel ATtiny45 or ATtiny85

.nolist
.include "tn45def.inc"
;.include "tn85def.inc"
.list

; set up the working directory for avra13 ==> cd ~/Desktop/www/kitsandparts.com/keyer/
; Assembple the code ==> ./avra13 1W-U-keyer.asm

; upload the code using avrdude - make sure to select the correct avrdude commands based on AVR chip

; avrdude -P usb -p t45 -c avrispv2 -U flash:w:1W-U-keyer.hex
; avrdude -P usb -p t45 -c avrispv2 -U flash:w:1W-U-keyer.hex:i -D - DO NOT USE the "D" option
; avrdude -P usb -p t45 -c avrispv2 -U lfuse:w:0xE2:m ; Clock divided by 8 turned off; 0x62 is default
; avrdude -P usb -p t45 -c avrispv2 -U hfuse:w:0xDC:m ; Brownout; 0xDF is default

; avrdude -P usb -p t85 -c avrispv2 -U 1W-U-keyer.hex
; avrdude -P usb -p t85 -c avrispv2 -U lfuse:w:0xE2:m ; Clock divided by 8 turned off; 0x62 is default
; avrdude -P usb -p t85 -c avrispv2 -U hfuse:w:0xDC:m ; Brownout; 0xDF is default

.equ DIT_MASK  = 0
.equ DAH_MASK  = 1
.equ CMD = 2
.equ XMIT = 4 ; .equ XMIT = 4 on production rig
.equ TONE = 3 ; .equ TONE = 3 on production rig
.equ DIT = 2 ; 1 on bit and 1 off bit
.equ DAH = 4 ; 3 on bits and 1 off bit

;--Rst--------Vcc--
;--PB3--------PB2--
;--PB4--------PB1--
;--Gnd--------PB0--

.equ NUM_0 = 0b00111111
.equ NUM_1 = 0b00101111
.equ NUM_2 = 0b00100111
.equ NUM_3 = 0b00100011
.equ NUM_4 = 0b00100001
.equ NUM_5 = 0b00100000
.equ NUM_6 = 0b00110000
.equ NUM_7 = 0b00111000
.equ NUM_8 = 0b00111100
.equ NUM_9 = 0b00111110
.equ LET_A = 0b00000101
.equ LET_B = 0b00011000
.equ LET_C = 0b00011010
.equ LET_D = 0b00001100
.equ LET_E = 0b00000010
.equ LET_F = 0b00010010
.equ LET_G = 0b00001110
.equ LET_H = 0b00010000
.equ LET_I = 0b00000100
.equ LET_J = 0b00010111
.equ LET_K = 0b00001101
.equ LET_L = 0b00010100
.equ LET_M = 0b00000111
.equ LET_N = 0b00000110
.equ LET_O = 0b00001111
.equ LET_P = 0b00010110
.equ LET_Q = 0b00011101
.equ LET_R = 0b00001010
.equ LET_S = 0b00001000
.equ LET_T = 0b00000011
.equ LET_U = 0b00001001
.equ LET_V = 0b00010001
.equ LET_W = 0b00001011
.equ LET_X = 0b00011001
.equ LET_Y = 0b00011011
.equ LET_Z = 0b00011100
.equ CHR_ERROR  = 0b01001100
.equ CHR_COMMA  = 0b01110011
.equ CHR_PERIOD = 0b01010101
.equ CHR_SLASH  = 0b00110010
.equ COPYRIGHT = 0b11010010

;R0 and R1 reserved for hardware multiply
.DEF rd1l = R3 ; LSB 16-bit-number to be divided
.DEF rd1h = R4 ; MSB 16-bit-number to be divided
.DEF rd1u = R5 ; interim register
.DEF rd2 = R6 ; 8-bit-number to divide with
.def sidetone = r7
.def tone_delay = r8 ; load and count down to zero for action

.def deadman = r10
.def sidetone_flag = r11 ; sidetone flag
.def straight_key = r12 ; straight key flag
.def paddles = r13 ; reverse paddles flag
.def wpm_lo = r14 ; load and count down to zero for action
.def wpm_hi = r15 ; load and count down to zero for action
.def temp1 = r16
.def temp2 = r17
.def temp3 = r18
.def key_down = r19
.def transmit_enabled = r20
.def character = r21
.def dit_period = r22 ; 4 for dah & 2 for dit 
.def delay = r23 ; 100 mS per bit general delay
.def delay_100_lo = r24 ; load and count down to zero for action
.def delay_100_hi = r25 ; load and count down to zero for action
.def delay_wpm_lo = r26 ; load and count down to zero for action
.def delay_wpm_hi = r27 ; load and count down to zero for action
.def capture_dit = r28
.def capture_dah = r29
;R30/ZL and R31/ZH used for data pointer

.dseg

.org SRAM_START

.cseg

.org 0
 rjmp RESET

.org INT0addr
 reti ; External Interrupt 0
.org PCI0addr
 reti ; ; Pin change Interrupt Request 0
.org OC1Aaddr
 reti ; Timer/Counter1 Compare Match 1A
.org OVF1addr
 reti ; Timer/Counter1 Overflow
.org OVF0addr
 rjmp TIM0_OVF_ISR ; Timer/Counter0 Overflow
.org ERDYaddr
 reti ; EEPROM Ready
.org ACIaddr
 reti ; Analog comparator
.org ADCCaddr
 reti ; ADC Conversion ready
.org OC1Baddr
 reti ; Timer/Counter1 Compare Match B
.org OC0Aaddr
 reti ; Timer/Counter0 Compare Match A
.org OC0Baddr
 reti ; Timer/Counter0 Compare Match B
.org WDTaddr
 reti ; Watchdog Time-out
.org USI_STARTaddr
 reti ; USI START
.org USI_OVFaddr
 reti ; USI Overflow

RESET:

 ldi temp1,low(RAMEND)
 out SPL,temp1 ; Set stack pointer to last internal RAM location
 ldi temp1,high(RAMEND)
 out SPH,temp1


 ldi temp1,$07
 out PORTB,temp1 ; pull-ups enabled for DIT, DAH, CMD
 ldi temp1,$18
 out DDRB,temp1 ; set outputs for XMIT and TONE
 cbi PORTB,XMIT ;turn XMIT high
 
;ATtiny45 clock set at 8 MHz with the CKDIV8 fuse turned off = 0.125 uS clock
 ldi temp1,0b00000010 ; set timer0 prescale divisor to 8
 out TCCR0B,temp1 ; using 8 MHz clock = 1 uS timer pulse
;ATtiny45 using 8 MHz clock = 1 uS timer pulse

 ldi temp1,0b00000010
 out TIMSK,temp1 ;enable TIMER0 overflow interrupts

 ldi delay_100_lo,232 ; default 100mS
 ldi delay_100_hi,3 ; default 100mS

RESET2:
 sbis PINB,PB0 ; Skip if DIT paddle open
 rjmp RESET2
 sbis PINB,PB1 ; Skip if DAH paddle open
 rjmp RESET2
 
 sbic PINB,CMD ; Skip if CMD button pressed
 rjmp RESET3
 ldi temp1,0 ; set address for WPM value
 ldi temp2,0
 ldi temp3,15 ; set default WPM value
 rcall EEPROM_WRITE
 ldi temp2,1 ; set address for sidetone value
 ldi temp3,8 ; set default sidetone value
 rcall EEPROM_WRITE
 ldi temp2,2 ; set address for paddles value
 ldi temp3,0 ; set default paddles value
 rcall EEPROM_WRITE
 ldi temp2,3 ; set address for sidetone audio flag
 ldi temp3,0 ; set default sidetone audio flag
 rcall EEPROM_WRITE

; EEPROM ADDRESS TABLE
; 00 00 = WPM VALUE
; 00 01 = SIDETONE AUDIO VALUE
; 00 02 = PADDLES FLAG
; 00 03 = SIDETONE AUDIO FLAG
; 00 04 = reserved
; 00 05 = reserved
; 00 06 = reserved
; 00 07-0F = reserved
; 00 10 = start of 80 character msg1
; 00 60 = start of 80 character msg2
; 00 A0 = start of 80 character msg3

 
RESET3:
 clr temp1 ; set address for WPM value
 clr temp2
 rcall EEPROM_READ
 cpi temp3,$FF
 brne SET_WPM
 ldi temp3,15 ; default WPM
SET_WPM:
 rcall WPM_SET

 clr temp1 ; set address for sidetone value
 ldi temp2,1
 rcall EEPROM_READ
 cpi temp3,$FF
 brne SET_SIDETONE
 ldi temp3,8 ; default sidetone 625 Hz
SET_SIDETONE:
 mov sidetone,temp3
 mov tone_delay,sidetone ; toggle every 800 uS = 625 Hz

 clr temp1 ; set address for paddles value
 ldi temp2,2
 rcall EEPROM_READ
 cpi temp3,$FF
 brne SET_PADDLES
 ldi temp3,0 ; default paddles value
SET_PADDLES:
 mov paddles,temp3

 rcall READ_SIDETONE_AUDIO_FLAG
 
 clr deadman
 clr key_down
 clr capture_dit
 clr capture_dah
 clr transmit_enabled
 clr straight_key
  
 sei ; global all interrupt enable
 
 ldi temp1,NUM_1
 rcall SEND_CHAR ; send a "1"
 
 rcall CHAR_DELAY
 
 ldi temp1,LET_W
 rcall SEND_CHAR ; send a "W"

 ;sbic PINB,CMD ; Skip if CMD button pressed
 ;rjmp LOOP
 ;ldi delay,15
 ;rcall WAIT




 rjmp LOOP

WAIT:
 tst delay
 brne WAIT
 ret

CHAR_DELAY:
 ldi delay,2
 rcall WAIT
 ret
 
MENU:
 cpi character,LET_S ; SET_SPEED ******************************
 brne MENU20
SET_SPEED:
 ldi temp1,LET_E 
 rcall SEND_CHAR ; send an ACK
 rcall GET_CHAR
 cpi character,1
 brne SET_SPEED10
 rjmp ERROR
SET_SPEED10:
 rcall MTON ; convert morse code from character to ascii in temp1
 cpi temp1,$FF
 brne SET_SPEED20
 rjmp ERROR
SET_SPEED20:
 cbr temp1,$30
 mov temp2,temp1 ; multiply by 10
 add temp2,temp1
 lsl temp1
 lsl temp1
 lsl temp1
 add temp2,temp1 ; temp2 holds upper digit for wpm
 ldi temp1,LET_E 
 rcall SEND_CHAR ; send an ACK
 rcall GET_CHAR
 cpi character,1
 brne SET_SPEED30
 rjmp ERROR
SET_SPEED30:
 rcall MTON ; convert morse code from character to ascii in temp1
 cpi temp1,$FF
 brne SET_SPEED40
 rjmp ERROR
SET_SPEED40:
 cbr temp1,$30
 add temp1,temp2
 tst temp1 ; error if zero
 brne SET_SPEED50
 rjmp ERROR
SET_SPEED50:
 cpi temp1,46 ; error if same or higher
 brlo SET_SPEED60
 rjmp ERROR
SET_SPEED60:
 mov temp3,temp1
 clr temp1 ; set up address for WPM
 clr temp2
 rcall EEPROM_WRITE ; save WPM to EEPROM
 rcall WPM_SET
 rjmp OK

MENU20:
 cpi character,LET_F ; SET_TONE Frequency ******************************
 brne MENU30
SET_TONE:
 ldi temp1,LET_E 
 rcall SEND_CHAR ; send an ACK
 rcall GET_CHAR
 cpi character,1
 brne SET_TONE10
 rjmp ERROR
SET_TONE10:
 rcall MTON ; convert morse code from character to binary number in temp1
 cpi temp1,0x3A
 brlo SET_TONE20
 rjmp ERROR
SET_TONE20:
 ldi temp2,43
 sub temp1,temp2
 mov sidetone,temp1
 mov temp3,temp1
 clr temp1 ; set up address for sidetone
 ldi temp2,1
 rcall EEPROM_WRITE ; save sidetone to EEPROM
 rjmp OK
;9/14 = 357 hz
;8/13 = 385 Hz
;7/12 = 417 Hz
;6/11 = 455 Hz
;5/10 = 500 Hz
;4/9 = 555 Hz
;3/8 = 625 Hz
;2/7 = 714 Hz
;1/6 = 833 Hz
;0/5 = 1000 Hz

MENU30:
 cpi character,LET_R ; REVERSE_KEY ******************************
 brne MENU40
REVERSE_KEY:
 tst paddles
 breq REVERSE2
 clr paddles
 ldi temp1,LET_P
 rcall SEND_CHAR
 rjmp REVERSE3
REVERSE2:
 inc paddles
 ldi temp1,LET_X
 rcall SEND_CHAR
REVERSE3:
 clr temp1 ; set up address for REVERSE_PADDLES
 ldi temp2,2
 mov temp3,paddles
 rcall EEPROM_WRITE ; save PADDLES value to EEPROM
 rjmp LOOP

MENU40:
 cpi character,LET_E ; STRAIGHT_KEY ******************************
 breq KEY5
 cpi character,LET_T
 brne MENU50
KEY5:
 inc straight_key
 ldi temp1,LET_S ; send "S" for straight key active
 rcall SEND_CHAR
KEY10:
 sbic PINB,CMD ; Skip if CMD button pressed
 rjmp KEY15
 clr straight_key
 rjmp OK
KEY15:
 sbis PINB,PB0 ; Skip if DIT paddle open
 rjmp KEY20
 sbis PINB,PB1 ; Skip if DAH paddle open
 rjmp KEY20
 clr key_down
 clr transmit_enabled
 rjmp KEY10
KEY20: ; key down
 ser transmit_enabled
 ser key_down
 rjmp KEY10
 
MENU50:
 cpi character,LET_B ; BEACON MODE ******************************
 brne MENU60
GET_MSG:
 ldi temp1,LET_E 
 rcall SEND_CHAR ; send an ACK
 rcall GET_CHAR
 cpi character,1
 brne GET_MSG10
 rjmp ERROR
GET_MSG10:
 rcall MTON ; convert morse code from character to binary number in temp1
 cpi temp1,'1'
 brne GET_MSG20
 ldi temp2,$10
 rjmp GET_MSG50
GET_MSG20:
 cpi temp1,'2'
 brne GET_MSG30
 ldi temp2,$60
 rjmp GET_MSG50
GET_MSG30:
 cpi temp1,'3'
 brne GET_MSG40
 ldi temp2,$B0
 rjmp GET_MSG50
GET_MSG40: 
 rjmp ERROR
GET_MSG50: ; get message(n) characters
 push temp2
 rcall READ_SIDETONE_AUDIO_FLAG
MESSAGE1:
 tst capture_dit
 breq MESSAGE1A
 clr capture_dit
 pop temp2
 rjmp LOOP
MESSAGE1A:
 tst capture_dah
 breq MESSAGE1B
 clr capture_dah
 pop temp2
 rjmp LOOP
MESSAGE1B:
 clr temp1 ; set up address for msg
 rcall EEPROM_READ
 tst temp3
 breq	MSG_COMPLETE
 ser transmit_enabled
 mov temp1,temp3
 rcall NTOM
 rcall SEND_CHAR
 clr transmit_enabled
 rcall CHAR_DELAY
 inc temp2
 rjmp MESSAGE1
MSG_COMPLETE:
 pop temp2
 rjmp GET_MSG50 ; repeat message

MENU60:
 cpi character,LET_V ; VERSION ******************************
 brne MENU65
 ldi temp1,NUM_0 ; version 0
 rcall SEND_CHAR
 rjmp OK2

MENU65:
 cpi character,LET_X ; XMTR TUNE ******************************
 brne MENU70
 ;clr key_down
 ;clr transmit_enabled
 ldi temp1,LET_R ; READY
 rcall SEND_CHAR
XMTRTUNE:
 ser transmit_enabled
 ldi dit_period,DAH
 tst capture_dit
 breq XMTRTUNE1
 rjmp OK2
XMTRTUNE1:
 tst capture_dah
 breq XMTRTUNE
 rjmp OK2

MENU70:
 cpi character,LET_A ; SIDETONE AUDIO ******************************
 brne MENU80
 rcall READ_SIDETONE_AUDIO_FLAG
 tst sidetone_flag
 breq REVERSE4
 clr sidetone_flag
 ldi temp1,LET_Y
 rcall SEND_CHAR
 rjmp REVERSE5
REVERSE4:
  ldi temp1,LET_N
 rcall SEND_CHAR
 inc sidetone_flag
REVERSE5:
 clr temp1 ; set up EEPROM address for sidetone_flag
 ldi temp2,3
 mov temp3,sidetone_flag
 rcall EEPROM_WRITE ; save sidetone_flag to EEPROM
 rjmp LOOP
 
MENU80:
 cpi character,LET_M ; Enter Message Mode ******************************
 brne MENU90
SET_MSG:
 ldi temp1,LET_E 
 rcall SEND_CHAR ; send an ACK
 rcall GET_CHAR
 cpi character,1
 brne SET_MSG10
 rjmp ERROR
SET_MSG10:
 rcall MTON ; convert morse code from character to binary number in temp1
 cpi temp1,'1'
 brne SET_MSG20
 ldi temp2,$10
 rjmp SET_MSG50
SET_MSG20:
 cpi temp1,'2'
 brne SET_MSG30
 ldi temp2,$60
 rjmp SET_MSG50
SET_MSG30:
 cpi temp1,'3'
 brne SET_MSG40
 ldi temp2,$B0
 rjmp SET_MSG50
SET_MSG40: 
 rjmp ERROR
SET_MSG50: ; get message(n) characters
 ldi temp1,LET_E 
 rcall SEND_CHAR ; send an ACK
 rcall GET_CHAR
 cpi character,1
 brne SET_MSG60
 ;rjmp ERROR
 ldi character,1
SET_MSG60:
 rcall MTON ; convert morse code from character to binary number in temp1
 cpi temp1,$FF ; check for valid character
 brne SET_MSG70
 rjmp ERROR
SET_MSG70: ; process valid character
 cpi temp1,'@'
 breq SET_MSG80 ; finished
 mov temp3,temp1
 clr temp1 ; set up address for msg
 rcall EEPROM_WRITE ; save msg to EEPROM
 inc temp2
 rjmp SET_MSG50 ; get next character
SET_MSG80:
 clr temp3 ; end-of-message character = 0
 clr temp1 ; set up address for msg
 rcall EEPROM_WRITE ; save end-of-message to EEPROM
 rjmp OK

MENU90:
 cpi character,COPYRIGHT ; COPYRIGHT ******************************
 brne MENU99
 ldi ZH,high(2*msg1)
 ldi ZL,low(2*msg1)
CR1:
 lpm temp1,Z+
 push ZH
 push ZL
 tst temp1
 breq	CR_COMPLETE
 ldi ZH,high(2*xref1)
 ldi ZL,low(2*xref1)
CR3:
 lpm temp2,Z+
 cp temp1,temp2
 breq CR7
 lpm temp2,Z+ ; dummy to increment pointer only
 rjmp CR3
CR7:
 lpm temp1,Z+
 ;ser transmit_enabled
 clr transmit_enabled
 rcall SEND_CHAR
 rcall CHAR_DELAY
 pop ZL
 pop ZH
 rjmp CR1
CR_COMPLETE:
 pop ZL
 pop ZH
 rjmp LOOP

MENU99:

ERROR:
 ldi temp1,CHR_ERROR
 rcall SEND_CHAR
 rjmp LOOP
OK:
 ldi temp1,LET_R ; ROGER
 rcall SEND_CHAR
OK2:
 clr capture_dit
 clr capture_dah
LOOP:
 ldi temp1,$40
 cp deadman,temp1
 brlo LOOPOK
 ldi temp1,$C0
 cp deadman,temp1
 brsh LOOPOK
LOCK: rjmp lock
LOOPOK: 
 rcall READ_SIDETONE_AUDIO_FLAG
 ser transmit_enabled
 rcall READ_PADDLES
 sbic PINB,CMD ; Skip if CMD button pressed
 rjmp LOOP
 clr key_down
 clr transmit_enabled
 clr sidetone_flag
 ldi temp1,LET_R ; READY
 rcall SEND_CHAR
 rcall GET_CHAR
 cpi character,1
 breq LOOP20
 rjmp MENU ;
LOOP20:
 sbic PINB,CMD ; Skip if CMD button pressed
 rjmp ERROR
 rjmp RESET

READ_PADDLES:
 tst capture_dit
 breq DAH10
 lsl character
 tst paddles
 brne DIT15
 ldi dit_period,DIT
 tst deadman
 brpl DIT12
 clr deadman
DIT12:
 inc deadman
 rjmp DIT20
DIT15:
 inc character
 ldi dit_period,DAH
DIT20:
 tst dit_period
 brne DIT20
 clr capture_dit
DAH10:
 tst capture_dah
 breq NEXT
 lsl character
 tst paddles
 brne DAH15
 ldi dit_period,DAH
 tst deadman
 brmi DAH12
 clr deadman
DAH12:
 dec deadman
 inc character
 rjmp DAH20
DAH15:
 ldi dit_period,DIT
DAH20:
 tst dit_period
 brne DAH20
 clr capture_dah
NEXT:
 ret

WPM_SET:
 rcall DIVIDE16BY8
 mov delay_wpm_lo,temp1
 mov delay_wpm_hi,temp2
 mov wpm_lo,delay_wpm_lo
 mov wpm_hi,delay_wpm_hi
 ret
 
GET_CHAR:
 push temp1
 push temp2
 ldi delay,20 ; 2 sec get char period
 ldi character,1
GET_CHAR10:
 rcall READ_PADDLES
 mov temp2,character
 cpi character,1
 brne GET_CHAR20
 tst delay
 brne GET_CHAR10
 rjmp GET_CHAR_EXIT
GET_CHAR20:
 mov temp1,wpm_hi
 lsl temp1
 ;add temp1,wpm_hi
 mov delay,temp1 ;  set delay to 5 x wpm_hi
GET_CHAR30:
 tst delay
 brne GET_CHAR40
GET_CHAR_EXIT:
 pop temp2
 pop temp1
 ret
GET_CHAR40:
 rcall READ_PADDLES
 cp temp2,character
 breq GET_CHAR30
 mov temp2,character
 rjmp GET_CHAR20
 
SEND_CHAR: ; character is in temp1
 push temp2
 ldi temp2,9
SEND10:
 dec temp2
 lsl temp1
 brcc SEND10
SEND20:
 dec temp2
 breq SEND_CHAR_EXIT
 lsl temp1
 brcc SEND_DIT
SEND_DAH:
 ldi dit_period,DAH
SEND_DAH1:
 tst dit_period
 brne SEND_DAH1
 rjmp SEND20
SEND_DIT:
 ldi dit_period,DIT
SEND_DIT1:
 tst dit_period
 brne SEND_DIT1
 rjmp SEND20
SEND_CHAR_EXIT:
 pop temp2
 ret

TIM0_OVF_ISR:
 push temp1
 in temp1,SREG
 push temp1
 
 ldi temp1,256-100 ; counts up to 100
 out TCNT0,temp1 ; each overflow = 100 uS
 
 sbis PINB,PB0 ; Skip if Bit in I/O Register is set (dit not active)
 ldi capture_dit,1
 sbis PINB,PB1 ; Skip if Bit in I/O Register is set (dah not active)
 ldi capture_dah,1
  
 tst delay ; used for command timing
 breq TIM0_OVF_10

 sbiw delay_100_lo,1 ; decrement delay_100 timer
 brne TIM0_OVF_10
 
 ldi delay_100_lo,232 ; default 100mS
 ldi delay_100_hi,3 ; default 100mS
 dec delay

TIM0_OVF_10:
 tst key_down
 brne TIM0_OVF_30
 tst straight_key
 breq TIM0_OVF_12
 cbi PORTB,XMIT ;turn XMIT low
TIM0_OVF_12: 
 tst dit_period
 breq TIM0_OVF_EXIT
 sbiw delay_wpm_lo,1 ; decrement wpm timer 
 brne TIM0_OVF_20
 mov delay_wpm_lo,wpm_lo
 mov delay_wpm_hi,wpm_hi
 dec dit_period
 breq TIM0_OVF_EXIT
TIM0_OVF_20:
 cpi dit_period,1
 breq TIM0_OVF_50

TIM0_OVF_30:
 dec tone_delay
 brne TIM0_OVF_EXIT
 
;TONE producing routine
 tst transmit_enabled
 breq TONE2
 sbi PORTB,XMIT ;turn XMIT high
TONE2:
 mov tone_delay,sidetone
 tst sidetone_flag
 brne TIM0_OVF_EXIT
 sbi PINB,TONE ; toggle every 800 uS = 625 Hz
 rjmp TIM0_OVF_EXIT
 
TIM0_OVF_50:
 sbi PORTB,TONE ;turn output high
 cbi PORTB,XMIT ;turn XMIT low
 
TIM0_OVF_EXIT:
 pop temp1
 out SREG,temp1
 pop  temp1
 reti

DIVIDE16BY8: ; divide 12000 by temp1, result temp1=LSB temp2=MSB
 	mov rd2,temp3
 	ldi temp1,$E0
 	mov rd1l,temp1
 	ldi temp2,$2E
	mov rd1h,temp2
div8:
	clr rd1u ; clear interim register
	clr temp2 ; clear result (the result registers
	clr temp1 ; are also used to count to 16 for the
	inc temp1 ; division steps, is set to 1 at start)
div8a:
	clc ; clear carry-bit
	rol rd1l ; rotate the next-upper bit of the number
	rol rd1h ; to the interim register (multiply by 2)
	rol rd1u
	brcs div8b ; a one has rolled left, so subtract
	cp rd1u,rd2 ; Division result 1 or 0?
	brcs div8c ; jump over subtraction, if smaller
div8b:
	sub rd1u,rd2; subtract number to divide with
	sec ; set carry-bit, result is a 1
	rjmp div8d ; jump to shift of the result bit
div8c:
	clc ; clear carry-bit, resulting bit is a 0
div8d:
	rol temp1 ; rotate carry-bit into result registers
	rol temp2
	brcc div8a ; as long as zero rotate out of the result
stop:
	ret

MTON: ; convert morse code from character to binary number in temp1
 push temp2
 ldi ZH,high(2*xref1)
 ldi ZL,low(2*xref1)
MTON1:
 lpm temp1,Z+
 lpm temp2,Z+
 tst temp1
 breq MTON8
 cp character,temp2
 brne MTON1
 rjmp MTON9
MTON8:
 ldi temp1,$FF
MTON9:
 pop temp2
 ret

NTOM: ; convert binary number to morse code character in temp1
 push temp2
 push temp3
 mov temp3,temp1
 ldi ZH,high(2*xref1)
 ldi ZL,low(2*xref1)
NTOM1:
 lpm temp2,Z+
 lpm temp1,Z+
 tst temp2
 breq NTOM5
 cp temp2,temp3
 brne NTOM1
 rjmp NTOM9
NTOM5:
 ldi temp1,$FF
NTOM9:
 pop temp3
 pop temp2
 ret

EEPROM_READ:
 sbic EECR,EEPE
 rjmp EEPROM_READ ; Wait for completion of previous write
 out EEARH,temp1 ; Set up address register
 out EEARL,temp2
 sbi EECR,EERE ; Start eeprom read by writing EERE
 in temp3,EEDR ; Read data from data register
 ret

EEPROM_WRITE:
 sbic EECR,EEPE
 rjmp EEPROM_WRITE ; Wait for completion of previous write
 push temp1
 ldi temp1,0 ; Set Programming mode
 out EECR,temp1
 pop temp1
 out EEARH,temp1 ; Set up address register
 out EEARL,temp2
 out EEDR,temp3 ; Write data temp3 to data register
 sbi EECR,EEMPE ; Write logical one to EEMPE
 sbi EECR,EEPE ; Start eeprom write by setting EEPE
 ret

READ_SIDETONE_AUDIO_FLAG:
 push temp3
 push temp2
 push temp1
 clr temp1 ; set address for sidetone audio flag
 ldi temp2,3
 rcall EEPROM_READ
 cpi temp3,$FF
 brne SET_AUDIO
 ldi temp3,0 ; default paddles value
SET_AUDIO:
 mov sidetone_flag,temp3
 pop temp1
 pop temp2
 pop temp3
 ret

msg1:
;    123456789012345678901234567890123456789012345678901234567890
.db "COPYRIGHT 2015 DE W8DIZ K",0

xref1:
.db " ",0b00000001
.db "0",0b00111111
.db "1",0b00101111
.db "2",0b00100111
.db "3",0b00100011
.db "4",0b00100001
.db "5",0b00100000
.db "6",0b00110000
.db "7",0b00111000
.db "8",0b00111100
.db "9",0b00111110
.db "A",0b00000101
.db "B",0b00011000
.db "C",0b00011010
.db "D",0b00001100
.db "E",0b00000010
.db "F",0b00010010
.db "G",0b00001110
.db "H",0b00010000
.db "I",0b00000100
.db "J",0b00010111
.db "K",0b00001101
.db "L",0b00010100
.db "M",0b00000111
.db "N",0b00000110
.db "O",0b00001111
.db "P",0b00010110
.db "Q",0b00011101
.db "R",0b00001010
.db "S",0b00001000
.db "T",0b00000011
.db "U",0b00001001
.db "V",0b00010001
.db "W",0b00001011
.db "X",0b00011001
.db "Y",0b00011011
.db "Z",0b00011100
.db "?",0b01001100
.db ",",0b01110011
.db ".",0b01010101
.db "/",0b00110010
.db "@",0b00101010 ; "AR"
.db "$",0b01000101 ; "SK"
.db 0,0
