
.include "msp430x2xx.inc"

RAM equ 0x0200
SD_COMMAND equ 0x0200
DS18B20_DATA equ 0x0210
DS18B20_CMD equ 0x0220
DS18B20_CMD_LEN equ 0x0221
DS18B20_BIT equ 0x0222
DEBUG_STATE equ 0x0223
CLOCK_DATA equ 0x0230
OLD_SPI_CKCTL equ 0x254
MENU_COUNT equ 0x0250
ALARM_SET equ 0x0252       ; 0x20
FAHR_FLAG equ 0x0253       ; 0x21
HOURLY_CHIME equ 0x0254    ; 0x22
SPI_DATA_OUT equ 0x0255
SPI_DATA_IN equ 0x0256
SPI_DATA_COUNT equ 0x0257
MENU_DIRTY equ 0x0258
CMD0 equ 0x40
CMD1 equ 0x41
;CMD17 equ (0x40|17)
CMD17 equ 0x51
SOUND_RATE equ 2000

;  r4 =
;  r5 =
;  r6 =
;  r7 =
;  r8 = current offset in flash block (div by 4)
;  r9 = Sound data, temp for clock
; r10 = temp for main routine
; r11 = signal from interrupt to main code for DS18B20
; r12 = DS18B20 bit flag
; r13 = interupt jump routine
; r14 = temp in functions (interrupt)
; r15 = temp in functions (interrupt)

  .org 0xe000
start:
  ;; Turn off watchdog
  mov.w #(WDTPW|WDTHOLD), &WDTCTL

  mov.w #0x3fff, &0x0250 ; FUCK

  ;; Please don't interrupt me
  dint

  ;; r13 points to which interrupt routine should be called
  mov.w #null_interrupt, r13

  ;; Set up stack pointer
  ;; FIXME - Warning, this is for msp430g2452
  mov.w #0x0300, SP

  ;; Set MCLK to 16 MHz with DCO 
  mov.b #DCO_7, &DCOCTL
  mov.b #RSEL_14, &BCSCTL1
  ;mov.b #DCO_3, &DCOCTL
  ;mov.b #RSEL_15, &BCSCTL1
  mov.b #0, &BCSCTL2

.if 0
  ;; Set MCLK to 16 MHz external crystal
  bic.w #OSCOFF, SR
  bis.b #XTS, &BCSCTL1
  mov.b #LFXT1S_3, &BCSCTL3
test_osc:
  bic.b #OFIFG, &IFG1
  mov.w #0x00ff, r15
dec_again:
  dec r15
  jnz dec_again
  bit.b #(OFIFG), &IFG1
  jnz test_osc
  mov.b #(SELM_3|SELS), &BCSCTL2
.endif

  ;; Set up output pins
  ;; P1.0 = Data Out for DS18B20
  ;; P1.1 =  CE for RTC
  ;; P1.2 = /CS for DAC
  ;; P1.3 = /CS for SD
  ;; P2.0 = SCK for RTC  OUT
  ;; P2.1 = RTC INT0     IN
  ;; P2.2 = RTC INT1     IN
  ;; P2.3 = MENU BUTTON  IN
  ;; P2.4 = SEL BUTTON   IN
  ;; P2.5 = SDO for RTC  OUT
  ;; P2.6 = GREEN LIGHT  OUT
  ;; P2.7 = RED LIGHT    OUT
  ;; P1.4 = SDI for RTC  IN
  mov.b #0x0f, &P1DIR        ; P1.0, P1.1, P1.2, P1.3
  mov.b #(8|4|1), &P1OUT

  mov.b #0x00, &P2SEL
  mov.b #0xe1, &P2DIR
  mov.b #0x5e, &P2OUT
  mov.b #0x1e, &P2REN

  ;; Set up SPI
  mov.b #(USIPE7|USIPE6|USIPE5|USIMST|USIOE|USISWRST), &USICTL0
  mov.b #USICKPH, &USICTL1
  mov.b #(USIDIV_7|USISSEL_2), &USICKCTL ; div 128, SMCLK
  bic.b #USISWRST, &USICTL0      ; clear reset

  ;; Set up Timer
  mov.w #SOUND_RATE, &TACCR0
  mov.w #(TASSEL_2|MC_1), &TACTL ; SMCLK, DIV1, COUNT to TACCR0
  mov.w #CCIE, &TACCTL0
  mov.w #0, &TACCTL1

  ;; FIXME - Remove this I think
  ;mov.b #0, &USISRL
  ;mov.b #8, &USICNT

  call #send_sd_init
  call #rtc_init

  ;; Setup to read SD block
  mov.w #0x0000, r8
  mov.b #CMD17, &SD_COMMAND+0

  ;; Okay, I can be interrupted now
  eint

say_time_and_temp:
  ;; read temp and time
  call #read_time
  call #read_temp
  call #say_time
  mov.b #121, r10
  call #say
  call #say_temp

  ;call #alarm_ding_ding

setup_blink:
  mov.w #40000, &TACCR0
  mov.w #0, r9
  mov.w #blink_interrupt, r13

main:
  bit.b #0x08, &P2IN  ; MENU BUTTON
  jz main_menu
  cmp.b #1, &ALARM_SET
  jz skip_alarm_0
  bit.b #0x02, &P2IN  ; ALARM 0
  jz alarm0_zomg
skip_alarm_0:
  cmp.b #1, &HOURLY_CHIME
  jz skip_alarm_1
  bit.b #0x04, &P2IN  ; ALARM 1
  jz alarm1_zomg
skip_alarm_1:
  bit.b #0x10, &P2IN  ; SELECT BUTTON
  jnz main
  jmp say_time_and_temp

alarm0_zomg:
  call #alarm_ding_ding
  jmp main

alarm1_zomg:
  call #read_time
  ;mov.b #0x0b, r9   ; reset alarm1
  ;call #read_rtc
  jmp say_time_and_temp

main_menu:
  mov.w #115, r10 ; "Main menu"
  call #say

  mov.w #111, r10 ; "Reset second"
  call #say
  mov.w #0, &MENU_COUNT
reset_second:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN ; MENU BUTTON
  jz exit_reset_second
  bit.b #0x10, &P2IN ; SELECT BUTTON
  jnz reset_second
  mov.b #0, r10
  call #say
  mov.b #0x80, r9
  mov.b #0x00, r10
  call #write_rtc
exit_reset_second:

  mov.b #0, &MENU_DIRTY
  mov.w #104, r10 ; "Set minute"
  call #say
  mov.b &CLOCK_DATA+1, r7
  call #bcd_to_dec
set_minute:
  mov.b r7, r10
  call #say
  mov.w #0, &MENU_COUNT
wait_minute:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN
  jz save_minute
  bit.b #0x10, &P2IN
  jnz wait_minute
  mov.b #1, &MENU_DIRTY
  inc.b r7
  cmp.b #60, r7
  jne set_minute
  mov.b #0, r7
  jmp set_minute
save_minute:
  cmp.b #0, &MENU_DIRTY
  jeq dont_set_minute
  call #dec_to_bcd60
  mov.b #0x81, r9
  mov.b r7, r10
  call #write_rtc
dont_set_minute:

  mov.b #0, &MENU_DIRTY
  mov.w #103, r10 ; "Set hour"
  call #say
  mov.b &CLOCK_DATA+2, r7
  mov.b r7, r4
  and.b #0x1f, r7
  and.b #0x20, r4
  call #bcd_to_dec
set_hour:
  mov.b r7, r10
  call #say
  cmp.b #0, r4
  jeq set_hour_say_am
  mov.b #107, r10 ; "pm"
  call #say
  mov.w #0, &MENU_COUNT
  jmp wait_hour
set_hour_say_am:
  mov.b #108, r10 ; "am"
  call #say
  mov.w #0, &MENU_COUNT
wait_hour:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN
  jz save_hour
  bit.b #0x10, &P2IN
  jnz wait_hour
  mov.b #1, &MENU_DIRTY
  inc.b r7
  cmp.b #12, r7
  jne dont_flip_am_pm
  xor.b #0x20, r4
dont_flip_am_pm:
  cmp.b #13, r7
  jne set_hour
  mov.b #1, r7
  jmp set_hour
save_hour:
  cmp.b #0, &MENU_DIRTY
  jeq dont_set_hour
  push r4
  call #dec_to_bcd60
  pop r4
  bis.b r4, r7
  bis.b #0x40, r7
  mov.b #0x82, r9
  mov.b r7, r10
  call #write_rtc
dont_set_hour:

  mov.w #122, r10 ; "Set alarm minute"
  call #say
  mov.b &CLOCK_DATA+8, r7
  call #bcd_to_dec
set_alarm_minute:
  mov.b r7, r10
  call #say
  mov.w #0, &MENU_COUNT
wait_alarm_minute:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN
  jz save_alarm_minute
  bit.b #0x10, &P2IN
  jnz wait_alarm_minute
  inc.b r7
  cmp.b #60, r7
  jne set_alarm_minute
  mov.b #0, r7
  jmp set_alarm_minute
save_alarm_minute:
  call #dec_to_bcd60
  mov.b #0x88, r9
  mov.b r7, r10
  call #write_rtc
  mov.b #0x87, r9
  mov.b #0, r10
  call #write_rtc

  mov.w #103, r10 ; "Set alarm hour"
  call #say
  mov.b &CLOCK_DATA+9, r7
  mov.b r7, r4
  and.b #0x1f, r7
  and.b #0x20, r4
  call #bcd_to_dec
set_alarm_hour:
  mov.b r7, r10
  call #say
  cmp.b #0, r4
  jeq set_alarm_hour_say_am
  mov.b #107, r10 ; "pm"
  call #say
  mov.w #0, &MENU_COUNT
  jmp wait_alarm_hour
set_alarm_hour_say_am:
  mov.b #108, r10 ; "am"
  call #say
  mov.w #0, &MENU_COUNT
wait_alarm_hour:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN
  jz save_alarm_hour
  bit.b #0x10, &P2IN
  jnz wait_alarm_hour
  inc.b r7
  cmp.b #13, r7
  jne set_alarm_hour
  mov.b #1, r7
  xor.b #0x20, r4
  jmp set_alarm_hour
save_alarm_hour:
  push r4
  call #dec_to_bcd60
  pop r4
  bis.b r4, r7
  bis.b #0x40, r7
  mov.b #0x89, r9
  mov.b r7, r10
  call #write_rtc

  mov.b &ALARM_SET, r7
set_alarm:
  bit.b #1, r7
  jeq alarm_off
  mov.w #117, r10 ; "alarm is on"
  call #say
  mov.w #0, &MENU_COUNT
  jmp wait_set_alarm
alarm_off:
  mov.w #118, r10 ; "alarm is off"
  call #say
  mov.w #0, &MENU_COUNT
wait_set_alarm:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN
  jz save_set_alarm
  bit.b #0x10, &P2IN
  jnz wait_set_alarm
  xor.b #1, r7
  jmp set_alarm
save_set_alarm:
  and.b #0x01, r7       ; don't ask
  mov.b r7, &ALARM_SET
  mov.b #0xa0, r9
  mov.b r7, r10
  call #write_rtc
  cmp.b #1, &ALARM_SET
  jne alarm_led_off
  bis.b #0x80, &P2OUT
  jmp alarm_led_exit
alarm_led_off:
  bic.b #0x80, &P2OUT
alarm_led_exit:


  mov.b &HOURLY_CHIME, r7
set_hourly_chime:
  bit.b #1, r7
  jeq hourly_chime_off
  mov.w #123, r10 ; "hourly chime is on"
  call #say
  mov.w #0, &MENU_COUNT
  jmp wait_set_hourly_chime
hourly_chime_off:
  mov.w #124, r10 ; "hourly chime is off"
  call #say
  mov.w #0, &MENU_COUNT
wait_set_hourly_chime:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN
  jz save_set_hourly_chime
  bit.b #0x10, &P2IN
  jnz wait_set_hourly_chime
  xor.b #1, r7
  jmp set_hourly_chime
save_set_hourly_chime:
  and.b #0x01, r7       ; don't ask
  mov.b r7, &HOURLY_CHIME
  mov.b #0xa2, r9
  mov.b r7, r10
  call #write_rtc

  mov.b &FAHR_FLAG, r7
set_fahr:
  bit.b #1, r7
  jeq use_celcius
  mov.w #114, r10 ; "degrees fahrenheit"
  call #say
  mov.w #0, &MENU_COUNT
  jmp wait_set_fahr
use_celcius:
  mov.w #109, r10 ; "degrees celcius"
  call #say
  mov.w #0, &MENU_COUNT
wait_set_fahr:
  cmp.w #65535, &MENU_COUNT
  jeq exit_menu
  bit.b #0x08, &P2IN
  jz save_set_fahr
  bit.b #0x10, &P2IN
  jnz wait_set_fahr
  xor.b #1, r7
  jmp set_fahr
save_set_fahr:
  and.b #0x01, r7       ; don't ask
  mov.b r7, &FAHR_FLAG
  mov.b #0xa1, r9
  mov.b r7, r10
  call #write_rtc

exit_menu:
  mov.w #120, r10 ; "Exit menu"
  call #say
  jmp setup_blink

dec_to_bcd60:
  mov.b #0, r4
dec_to_bcd60_repeat:
  cmp.b #10, r7
  jl dec_to_bcd60_done
  sub.b #10, r7
  inc.b r4
  jmp dec_to_bcd60_repeat
dec_to_bcd60_done:
  rla.b r4
  rla.b r4
  rla.b r4
  rla.b r4
  bis.b r4, r7
  ;mov.b r7, &MENU_COUNT+2 ;; DEBUG
  ret

bcd_to_dec:
  push.w r4
  mov.b r7, r4
  and.b #0x0f, r7
  rra.b r4
  rra.b r4
  rra.b r4
  rra.b r4
  and.b #7, r4
repeat_bcd_to_dec:
  cmp.b #0, r4
  jeq exit_bcd_to_dec
  add.b #10, r7
  dec.b r4
  jmp repeat_bcd_to_dec
exit_bcd_to_dec:
  pop.w r4
  ret

alarm_ding_ding:
  call #read_time                ; turn off alarms
  mov.w #0x3fff, r9
  mov.w #0, r5

repeat_ding_ding:
  bic.b #0x04, &P1OUT            ; DAC /CS = 0 (enable)
  mov.w r9, &USISR
  mov.b #(USI16B|16), &USICNT    ; Read in 16 bits
wait_spi_ding:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_ding
  bis.b #0x04, &P1OUT            ; DAC /CS = 1 (disable)

  mov.w #3000, r4
check_buttons:
  bit.b #0x08, &P2IN  ; MENU BUTTON
  jz ding_ding_stop
  bit.b #0x10, &P2IN  ; SELECT BUTTON
  jz ding_ding_stop
  dec.w r4
  jnz check_buttons

  inc.w r5
  cmp.w #200, r5
  jne not_200_yet
  mov.w #0, r5
not_200_yet:
  cmp.w #100, r5
  jge repeat_ding_ding
  xor.w #0x0fff, r9
  jmp repeat_ding_ding

ding_ding_stop:

  ;; turn off sound
  bic.b #0x04, &P1OUT            ; DAC /CS = 0 (enable)
  mov.w #1000, &USISR
  mov.b #(USI16B|16), &USICNT    ; Read in 16 bits
wait_spi_ding2:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_ding2
  bis.b #0x04, &P1OUT            ; DAC /CS = 1 (disable)

debounce_buttons:
  bit.b #0x08, &P2IN  ; MENU BUTTON
  jz debounce_buttons
  bit.b #0x10, &P2IN  ; SELECT BUTTON
  jz debounce_buttons
  mov.w #1000, r9
debounce_buttons_fin:
  dec.w r9
  jnz debounce_buttons_fin
  ret

say_time:
  mov.b #106, r10 ; "The time is"
  call #say
  mov.b &CLOCK_DATA+2, r10
  and.b #0x0f, r10
  bit.b #0x10, &CLOCK_DATA+2
  jz not_past_9
  add #10, r10
not_past_9:
  call #say
  mov.b &CLOCK_DATA+1, r10
  cmp.b #0, r10
  jeq dont_say_minute
  and.b #0xf0, r10
  rra.b r10
  rra.b r10
  rra.b r10
  mov.b #0, r4
  add.b r10, r4
  add.b r10, r4
  add.b r10, r4
  add.b r10, r4
  add.b r10, r4
  cmp.b #0, r4
  jne say_minute
  mov.w #110, r10 ; "OH"
  call #say
say_minute:
  mov.b &CLOCK_DATA+1, r10
  and.b #0x0f, r10
  add.b r4, r10
  call #say
dont_say_minute:
  bit.b #0x20, &CLOCK_DATA+2
  jz say_am
  mov.w #107, r10 ; "PM"
  call #say
  jmp said_pm
say_am:
  mov.w #108, r10 ; "AM"
  call #say
said_pm:
  ret

say_temp:
  mov.w &DS18B20_DATA, r4
  rra r4
  rra r4
  rra r4
  rra r4

  bit.b #1, &FAHR_FLAG
  jz say_celcius
  mov.w #fahr_table, r5
  and.w #0xff, r4
  add.w r4, r5
  mov.b @r5, r4

  bit.b #0x08, &DS18B20_DATA     ; Check if celcius is +0.05 and add 1 if so
  jz say_celcius
  bit.b #0x80, &DS18B20_DATA+1   ; is this negative?
  jnz c2f_neg
  inc.b r4
  jz say_celcius
c2f_neg:
  dec.b r4

say_celcius:
  mov.w #105, r10 ; "The temperature is"
  call #say

  bit.w #128, r4
  jeq not_neg
  mov.w #0, r10 ; "minus"
  inv.w r4
  inc.w r4
not_neg:
  mov.w #0, r5
factor:
  cmp.w #10, r4
  jl no_more_factors
  add.w #10, r5
  sub.w #10, r4
  jmp factor
no_more_factors: 
  cmp.w #0, r4
  jeq temp_no_zero
  mov.w r5, r10
  call #say
temp_no_zero:
  mov.w r4, r10
  call #say

  bit.b #1, &FAHR_FLAG
  jz say_degrees_celcius

  mov.w #114, r10 ; "degrees fahrenheit"
  call #say
  ret
say_degrees_celcius:
  mov.w #109, r10 ; "degrees celcius"
  call #say
  ret

say:
  ;; Read block 1 or 2 using index to find address of sound
  mov.w #SOUND_RATE, &TACCR0
  mov.b #0, &SD_COMMAND+1
  mov.b #0, &SD_COMMAND+2
  mov.b #0, &SD_COMMAND+3
  mov.b #0, &SD_COMMAND+4
  rla.w r10
  rla.w r10
  cmp.w #512, r10
  jl not_second_block
  sub.w #512, r10
  add.b #2, &SD_COMMAND+3
not_second_block:
  bic.b #0x08, &P1OUT            ; SD /CS = 0 (enable)
  call #spi_get_char
  call #spi_get_char
  call #send_sd_command

  ;mov.w #0xfefe, r6

  ;; Read data token
not_fe_yet_say:
  call #spi_get_char
  cmp.b #0xfe, r15
  jne not_fe_yet_say

  ;mov.w #0x6969, r6

  mov.w r10, r11
pre_flush_indexes:
  call #spi_get_char
  dec.w r11
  jne pre_flush_indexes

  mov.w #SD_COMMAND+1, r11
read_sound_address:
  call #spi_get_char
  mov.b r15, 0(r11)
  inc.w r11
  cmp.w #SD_COMMAND+5, r11
  jne read_sound_address

  mov.w #512, r11
  sub.w r10, r11
  sub.w #2, r11     ; 512-address+4-2 (4 bytes for address and 2 for CRC)

  ;; Flush CRC
pre_flush_end:
  call #spi_get_char
  dec.w r11
  jne pre_flush_end

  bis.b #0x08, &P1OUT            ; SD /CS = 1 (disable)

  mov.w #0, r11                  ; flag
  mov.w #0, r8                   ; sound byte count
  mov.w #0x3801, r9              ; sound byte
  mov.w #0, TAR
  mov.w #sound_player_interrupt, r13

keep_playing_sound:
  cmp.w #0, r11
  jeq keep_playing_sound
  ret

read_time:
  mov.w #CLOCK_DATA, r4

  bis.b #2, &P1OUT            ; RTC CE = 1 (enabled)
  mov.b #0x00, &SPI_DATA_OUT
  call #send_soft_spi
again:
  mov.b #0xff, &SPI_DATA_OUT
  call #send_soft_spi
  mov.b &SPI_DATA_IN, 0(r4)

  inc.w r4
  cmp.w #CLOCK_DATA+17, r4
  jne again

  bic.b #2, &P1OUT            ; RTC CE = 0 (disabled)
  ret

read_rtc:
  bis.b #2, &P1OUT            ; RTC CE = 1 (enabled)
  mov.b r9, &SPI_DATA_OUT
  call #send_soft_spi
  mov.b #0xff, &SPI_DATA_OUT
  call #send_soft_spi
  mov.b &SPI_DATA_IN, r7
  bic.b #2, &P1OUT            ; RTC CE = 0 (disabled)
  ret

write_rtc:
  bis.b #2, &P1OUT            ; RTC CE = 1 (enabled)
  mov.b r9, &SPI_DATA_OUT
  call #send_soft_spi
  mov.b r10, &SPI_DATA_OUT
  call #send_soft_spi
  bic.b #2, &P1OUT            ; RTC CE = 0 (disabled)
  ret

;; SPI_DATA_IN = send_sound_data(SPI_DATA_OUT)   (software SPI)
;; P1.1 = CE    0x02
;; P2.0 = SCK   0x01
;; P2.5 = SDO   0x20
;; P1.4 = SDI   0x10
send_soft_spi:
  mov.b #8, &SPI_DATA_COUNT
bit_loop:
  bis.b #1, &P2OUT        ; TICK

  ;; Shift out a bit and set output
  rla.b &SPI_DATA_OUT
  jc set_one_a
  bic.b #0x20, &P2OUT
  jmp sdo_ready_a
set_one_a:
  bis.b #0x20, &P2OUT
sdo_ready_a:

  ;; Shift in a bit
  rla.b &SPI_DATA_IN
  bit.b #0x10, &P1IN
  jne get_one_a
  bic.b #1, &SPI_DATA_IN
  nop
  nop
  jmp sdi_ready_a
get_one_a:
  bis.b #1, &SPI_DATA_IN
  nop
  nop
sdi_ready_a:

  bic.b #1, &P2OUT        ; TOCK
  dec.b &SPI_DATA_COUNT
  jnz bit_loop
  ret

read_temp:
  mov.w #ds18b20_signal_interrupt, r13
  ;; First do a convert
  call #init_ds18b20
  mov.b #0xcc, &DS18B20_CMD
  call #send_ds18b20_cmd
  mov.b #0x44, &DS18B20_CMD
  call #send_ds18b20_cmd
  ;;mov.w #0, r4  ;; DEBUG
  call #wait_ds18b20_convert

  ;; Second fetch the scratch-pad
  call #init_ds18b20
  mov.b #0xcc, &DS18B20_CMD
  call #send_ds18b20_cmd
  mov.b #0xbe, &DS18B20_CMD
  call #send_ds18b20_cmd
  call #fetch_ds18b20_scratch_pad

  mov.w #null_interrupt, r13
  ret

;; init DS18B20
init_ds18b20:
  ;mov.w #0, r4
  ;mov.w #0, r5
  bic.b #1, P1OUT
  mov.w #7680, &TACCR0   ; 480us
  mov.w #0, TAR
  mov.w #0, r11
master_reset_pulse:
  cmp.w #1, r11
  jne master_reset_pulse
  bis.b #1, P1OUT
  bic.b #1, P1DIR
wait_slave_low:
  ;inc r4
  bit.b #1, P1IN
  jnz wait_slave_low
wait_slave_hi:
  ;inc r5
  bit.b #1, P1IN
  jz wait_slave_hi
  bis.b #1, P1DIR
  mov.w #960, &TACCR0   ; 60us
  ret

;; send_ds18b20_cmd
send_ds18b20_cmd:
  mov.b #8, &DS18B20_CMD_LEN
send_next_bit:
  bit.b #1, &DS18B20_CMD
  jz cmd_bit_0
  call #write_ds18b20_1
  jmp cmd_bit_done
cmd_bit_0:
  call #write_ds18b20_0
cmd_bit_done:
  mov.w #6, r10
cmd_wait_1us:
  dec r10
  jnz cmd_wait_1us
  rra.b &DS18B20_CMD
  dec.b &DS18B20_CMD_LEN
  jnz send_next_bit
  ret

;; wait_ds18b20_convert
wait_ds18b20_convert:
  mov.w #6, r10
convert_wait_1us:
  dec r10
  jnz convert_wait_1us
  call #read_ds18b20
  cmp.w #0, r10
  jeq wait_ds18b20_convert
  ret

;; fetch_ds18b20_scratch_pad
fetch_ds18b20_scratch_pad:
  mov.w #DS18B20_DATA, r14
fetch_next_byte:
  mov.w #8, &DS18B20_BIT

fetch_next_bit:
  mov.w #6, r10
scratch_wait_1us:
  dec r10
  jnz scratch_wait_1us

  call #read_ds18b20
  rra.b 0(r14)
  cmp.w #0, r10
  jeq fetched_0
  bis.b #128, 0(r14)
  jmp done_set_fetch
fetched_0:
  bic.b #128, 0(r14)
done_set_fetch:
  dec &DS18B20_BIT
  jnz fetch_next_bit

  inc r14
  cmp.w #DS18B20_DATA+9, r14
  jne fetch_next_byte
  ret

;; write 1 to DS18B20
write_ds18b20_1:
  bic.b #1, P1OUT
  mov.w #0, TAR
  mov.w #0, r11
  mov.w #6, r10
wait_at_least_1us_write_1:
  dec r10
  jnz wait_at_least_1us_write_1
  bis.b #1, P1OUT
master_write_1:
  cmp.w #1, r11
  jne master_write_1
  ret

;; write 0 to DS18B20
write_ds18b20_0:
  bic.b #1, P1OUT
  mov.w #0, TAR
  mov.w #0, r11
master_write_0:
  cmp.w #1, r11
  jne master_write_0
  bis.b #1, P1OUT
  ret

;; read from DS18B20 (returns 0 in r10 for a 0, return 1 for a 1)
read_ds18b20:
  bic.b #1, P1OUT
  mov.w #6, r10
wait_at_least_1us_read:
  dec r10
  jnz wait_at_least_1us_read
  bis.b #1, P1OUT
  bic.b #1, P1DIR
  mov.w #0, TAR
  mov.w #0, r11
wait_read_bit:
  bit.w #1, P1IN
  jnz read_bit_not_zero
  inc r10
read_bit_not_zero:
  cmp.w #1, r11
  jne wait_read_bit
  bis.b #1, P1DIR

  cmp.w #0, r10
  jeq return_1
  mov.w #0, r10
  ret
return_1:
  mov.w #1, r10
  ret

;; send_sound_data(r15)   (software SPI)
;; P.0 = /CS
;; P.1 = SCK
;; P.2 = SDO
.if 0
send_sound_data:
  bic.b #0x04, &P1OUT     ; /CS = 0 (enable)
  mov.b #16, r14
bit_loop:
  rla r15
  jc set_one_a
  bic.b #4, &P1OUT
  jmp clock_it_a
set_one_a:
  bis.b #4, &P1OUT
clock_it_a:
  bis.b #2, &P1OUT        ; TICK
  bic.b #2, &P1OUT        ; TOCK
  dec r14
  jnz bit_loop
  bis.b #0x04, &P1OUT     ; DAC /CS = 1 (disable)
  ret
.endif

delay_min_1ms:
  mov.w #16000, r15       ; Wait at least 1ms (this is much longer)
wait_1ms:
  dec r15
  jnz wait_1ms
  ret

rtc_init:
  ;; Set up clock
  mov.b #0x8f, r9
  mov.b #0x00, r10
  call #write_rtc
  call #write_rtc  ;; Just in case.
  call #read_time
  bit.b #0x40, &CLOCK_DATA+2
  jnz already_12_hour
  mov.b #0x81, r9
  mov.b #0x00, r10
  call #write_rtc
  mov.b #0x82, r9
  mov.b #0x46, r10
  call #write_rtc
already_12_hour:
  bis.b #2, &P1OUT            ; RTC CE = 1 (enabled)
  mov.b #0x8b, &SPI_DATA_OUT
  call #send_soft_spi
  mov.b #0x00, &SPI_DATA_OUT  ; set alarm1 seconds
  call #send_soft_spi
  mov.b #0x00, &SPI_DATA_OUT  ; set alarm1 minutes
  call #send_soft_spi
  mov.b #0x80, &SPI_DATA_OUT  ; set alarm1 hours (MASKED OUT)
  call #send_soft_spi
  mov.b #0x80, &SPI_DATA_OUT  ; set alarm1 days (MASKED OUT)
  call #send_soft_spi
  bic.b #2, &P1OUT            ; RTC CE = 0 (disabled)

  bis.b #2, &P1OUT            ; RTC CE = 1 (enabled)
  mov.b #0x8a, &SPI_DATA_OUT
  call #send_soft_spi
  mov.b #0x80, &SPI_DATA_OUT  ; set alarm0 days (MASKED OUT)
  call #send_soft_spi
  bic.b #2, &P1OUT            ; RTC CE = 0 (disabled)

  bis.b #2, &P1OUT            ; RTC CE = 1 (enabled)
  mov.b #0x87, &SPI_DATA_OUT
  call #send_soft_spi
  mov.b #0x00, &SPI_DATA_OUT  ; set alarm0 seconds to 0
  call #send_soft_spi
  bic.b #2, &P1OUT            ; RTC CE = 0 (disabled)

  mov.b #0x8f, r9    ; turn on alarm interrupts
  mov.b #0x07, r10
  call #write_rtc

  ;; read ALARM_SET
  mov.b #0x20, r9
  call #read_rtc
  mov.b r7, &ALARM_SET
  cmp.b #1, r7
  jne alarm_led_off_a
  bis.b #0x80, &P2OUT
  jmp alarm_led_exit_a
alarm_led_off_a:
  bic.b #0x80, &P2OUT
alarm_led_exit_a:

  ;; read FAHR_FLAG
  mov.b #0x21, r9
  call #read_rtc
  mov.b r7, &FAHR_FLAG
  ;; read HOURLY_CHIME
  mov.b #0x22, r9
  call #read_rtc
  mov.b r7, &HOURLY_CHIME
  ret

;; send_sd_init()
;; Trashes r15

send_sd_init:
  bis.b #0x08, &P1OUT            ; SD /CS = 1 (disable on purpose)
  call #delay_min_1ms

  ;; send 80 bits of 1's out of SPI
  mov.w #5, r15
send_80_1s:
  mov.w #0xffff, &USISR
  mov.b #(USI16B|16), &USICNT    ; Flush out 16 bits
wait_spi_0:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_0
  dec r15
  jnz send_80_1s

  mov.b #CMD0, &SD_COMMAND+0     ; Reset SD card
  mov.b #0, &SD_COMMAND+1
  mov.b #0, &SD_COMMAND+2
  mov.b #0, &SD_COMMAND+3
  mov.b #0, &SD_COMMAND+4
  mov.b #0x95, &SD_COMMAND+5     ; CRC 0x95
  mov.b #0xff, &SD_COMMAND+6
  mov.b #0xff, &SD_COMMAND+7

retry_reset:
  call #delay_min_1ms

  bic.b #0x08, &P1OUT            ; SD /CS = 0 (enable)
  call #send_sd_command
  bis.b #0x08, &P1OUT            ; SD /CS = 1 (disable)
  cmp.b #1, r15
  jne retry_reset

  mov.b #CMD1, &SD_COMMAND+0     ; Init SD card
  mov.b #0x00, &SD_COMMAND+5     ; CRC 0
retry_init:
  ;; BEGIN WTF
  mov.b #0xff, r15
  call #spi_send_char
  ;; END WTF


  bic.b #0x08, &P1OUT            ; SD /CS = 0 (enable)
  call #send_sd_command
  bis.b #0x08, &P1OUT            ; SD /CS = 1 (disable)
  cmp.b #0, r15
  jne retry_init

done_init:
  bis.b #8, &P1OUT               ; SD /CS = 1 (disable)
  bis.b #USISWRST, &USICTL0      ; reset SPI
  mov.b #(USIDIV_0|USISSEL_2), &USICKCTL ; div 1, SMCLK full speed now
  bic.b #USISWRST, &USICTL0      ; enable SPI
  ret

;; send_sd_command()
;; Trashes r15, r14
send_sd_command:
  mov.w #SD_COMMAND, r14
sd_next_byte:
  mov.b @r14+, &USISRH
  mov.b @r14+, &USISRL
  mov.b #(USI16B|16), &USICNT    ; Read in 16 bits
wait_spi_cmd:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_cmd
  cmp.w #SD_COMMAND+8, r14
  jne sd_next_byte
  mov.b &USISRL, r15
  ret

; spi_send_char(r15)
spi_send_char:
  mov.b r15, &USISRL
  mov.b #8, &USICNT
wait_spi_read_write:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_read_write
  mov.b &USISRL, r15
  ret

; spi_get_char()
spi_get_char:
  mov.b #0xff, &USISRL
  mov.b #8, &USICNT
wait_spi_get_char:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_get_char
  mov.b &USISRL, r15
  ret

timer_interrupt:
  br r13

null_interrupt:
  inc.w &MENU_COUNT
  reti

blink_interrupt:
  inc.w r9
  cmp.w #200, r9
  jne dont_turn_off
  bis.b #0x40, &P2OUT
dont_turn_off:
  cmp.w #400, r9
  jne dont_turn_on
  bic.b #0x40, &P2OUT
  mov.w #0, r9
dont_turn_on:
  reti

ds18b20_signal_interrupt:
  mov.w #1, r11
  reti

sound_player_interrupt:
  ;cmp.w #0xffff, r9
  ;jeq flush_sound_toilet
  bit.w #0x8000, r9
  jne flush_sound_toilet

  bic.b #0x04, &P1OUT            ; DAC /CS = 0 (enable)
  mov.w r9, &USISR
  mov.b #(USI16B|16), &USICNT    ; Read in 16 bits
wait_spi_4:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_4
  bis.b #0x04, &P1OUT            ; DAC /CS = 1 (disable)

  cmp.w #0, r8
  jne read_word

  ;; flush CRC
  bic.b #0x08, &P1OUT            ; SD /CS = 0 (enable)
  mov.w #0xffff, &USISR
  mov.b #(USI16B|16), &USICNT    ; Read in 16 bits
wait_spi_flush:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_flush
  ;bis.b #0x08, &P1OUT            ; SD /CS = 1 (disable)

  add.b #2, &SD_COMMAND+3
  jnc ready_send
  inc.b &SD_COMMAND+2
  jnc ready_send
  inc.b &SD_COMMAND+1
ready_send:
  ;bic.b #0x08, &P1OUT            ; SD /CS = 0 (enable)
  call #send_sd_command

  ;; Read data token
not_fe_yet:
  mov.b #0xff, &USISRL
  mov.b #8, &USICNT    ; Read in 8 bits
wait_spi_fe:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_fe
  cmp.b #0xfe, &USISRL
  jne not_fe_yet

  mov.w #128, r8
read_word:
  dec r8

  bic.b #0x08, &P1OUT            ; SD /CS = 0 (enable)
  mov.w #0xffff, &USISR
  mov.b #(USI16B|16), &USICNT    ; Read in 16 bits
wait_spi_3:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_3
  mov.w &USISR, r9
  bis.b #0x08, &P1OUT            ; SD /CS = 1 (disable)

  reti

flush_sound_toilet:
  ;mov.w #1, r6
  mov.w #1, r11
  bic.b #0x08, &P1OUT            ; SD /CS = 0 (enable)
  mov.w #null_interrupt, r13
  add.w r8, r8
  add.w #1, r8    ; flush CRC too
flush_more_poop:
  mov.w #0xffff, &USISR
  mov.b #(USI16B|16), &USICNT    ; Read in 16 bits
wait_spi_flush_poop:
  bit.b #USIIFG, &USICTL1
  jz wait_spi_flush_poop
  dec r8
  jnz flush_more_poop
  bis.b #0x08, &P1OUT            ; SD /CS = 1 (disable)
  reti

spi_interrupt:
  ;; shouldn't happen
  reti

.include "fahr_table.inc"

  org 0xffe8
vectors:
  dw spi_interrupt
  dw 0
  dw 0
  dw 0
  dw 0
  dw timer_interrupt       ; Timer_A2 TACCR0, CCIFG
  dw 0
  dw 0
  dw 0
  dw 0
  dw 0
  dw start                 ; Reset



