;/***************************************************************************
; *   Copyright (C) 2009, Crawlerz                                          *
; *                                                                         *
; *   Description:                                                          *
; *        - Juno RF Module Blocking Transmit & Receive API                 *
; *   Version:                                                              *
; *     2009.45.6                                                           *
; *                                                                         *
; *   This program is free software; you can redistribute it and/or modify  *
; *   it under the terms of the GNU General Public License as published by  *
; *   the Free Software Foundation; either version 2 of the License, or     *
; *   (at your option) any later version.                                   *
; *                                                                         *
; *   This program is distributed in the hope that it will be useful,       *
; *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
; *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
; *   GNU General Public License for more details.                          *
; *                                                                         *
; *   You should have received a copy of the GNU General Public License     *
; *   along with this program; if not, write to the                         *
; *   Free Software Foundation, Inc.,                                       *
; *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
; ***************************************************************************/
include "m8c.inc"
include "psocgpioint.inc"
include "memory.inc"
include "juno.inc"

export _JunoStart
export  JunoStart
export _JunoDelay
export  JunoDelay
export _JunoWrite
export  JunoWrite
export _JunoRead
export  JunoRead
export _JunoSleep
export  JunoSleep
export _JunoWake
export  JunoWake
export _JunoGetMID
export  JunoGetMID
export _JunoTransmit
export  JunoTransmit
export _JunoReceive
export  JunoReceive
export _JunoStop
export  JunoStop
export bRadioMID
export bRadioRxStat
export bRadioRxData
export bRadioRxLen
export bRadioRSSI

area InterruptRAM(ram) ; variables on ram page 0
;PortShadow:    blk 1
bRadioMID:      blk 4
bRadioTemp:
bRadioRxStat:   blk 1
bRadioRxData:   blk 16
;bRadioTxData:  blk 16
bRadioWipPtr:   blk 1
bRadioRxLen:    blk 1
bRadioRSSI:     blk 1

area UserModules (ROM, REL)

.section
;-----------------------------------------------------------------------------
; JunoWrite:      Start the Juno RF Module.
;
; 'C' Call:        void JunoStart(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: lost
;                  X: lost
 JunoStart:
_JunoStart:
    mov reg[VREGCR], VREGCR_ENABLE                                              ; Enable 3.3V VREG to JUNO
;   call MSTIMER_Start                                                          ;
;   call JUNO_SPIM_Start
;   mov A, SPIM_MOSI_P15                                                        ;MOSI=P1_5                      [4 cycles]
;   call JUNO_SPIM_SetMOSI
;   mov A, SPIM_MISO_P16                                                        ;MISO=P1_6                      [4 cycles]
;   call JUNO_SPIM_SetMISO
    and reg[JUNO_nRST_Data_ADDR],~JUNO_nRST_MASK                                ; Assert nRST
    and reg[JUNO_nPD_Data_ADDR],~JUNO_nPD_MASK                                  ; Assert nPD
    mov A, tVREG_SETTLE + tPWR_RST
    call JunoDelay                                                              ; ...Delay 'til VREG pin voltage > VIH & Delay(tPWR_RST), 1300usec min.
    or  reg[JUNO_nPD_Data_ADDR], JUNO_nPD_MASK                                  ; Release nPD
    mov A, tPDN_X13
    call JunoDelay                                                              ; ...Delay(tPDN_X13), 2000usec typ.
    or  reg[JUNO_nRST_Data_ADDR], JUNO_nRST_MASK                                ; Release nRST
    mov A, tXTAL_STARTUP
    call JunoDelay                                                              ; ...Delay(tSPI_RDY), 1usec min & Delay(CRYSTAL_STARTUP), 2100usec typ.
    or  reg[JUNO_nSS_Data_ADDR], JUNO_nSS_MASK                                  ; Release Slave Select

    mov [bRadioTemp], (EndRadioStartTable - RadioStartTable)                    ; RadioStartTable is loaded bottom to top
.RadioStartLoop:
    dec [bRadioTemp]                                                            ;                               [7 cycles]
    mov A, [bRadioTemp]                                                         ;                               [5 cycles]
    index RadioStartTable                                                       ;                               [13 cycles]
    mov x, A                                                                    ;                               [4 cycles]
    dec [bRadioTemp]                                                            ;                               [7 cycles]
    mov A, [bRadioTemp]                                                         ;                               [5 cycles]
    index RadioStartTable                                                       ;                               [13 cycles]
    call  JunoWrite                                                             ;                               [11 cycles]
    cmp [bRadioTemp], 0                                                         ;                               [8 cycles]
    jnz .RadioStartLoop                                                         ;                               [5 cycles]
    ret                                                                         ;                               [8 cycles]
.endsection

.literal
RadioStartTable:
    db 18h, B2h                                                                 ;REG_PN_CODE, B
    db 17h, BBh                                                                 ;REG_PN_CODE, B
    db 16h, 09h                                                                 ;REG_PN_CODE, B
    db 15h, 2Bh                                                                 ;REG_PN_CODE, B
    db 14h, B8h                                                                 ;REG_PN_CODE, A
    db 13h, 6Bh                                                                 ;REG_PN_CODE, A
    db 12h, C0h                                                                 ;REG_PN_CODE, A
    db 11h, DCh                                                                 ;REG_PN_CODE, A overwrite default w/ PN Code Index 1 (64kbps table)
    db 1Ah, 1Dh                                                                 ;REG_THRESHOLD_H - TH32=3
    db 19h, 03h                                                                 ;REG_THRESHOLD_L - TH32=3
    db 07h, 03h                                                                 ;REG_RX_INT_EN - enable EOFA and FULLA flags on IRQ pin
    db 04h, 07h                                                                 ;REG_DATA_RATE - 64kbps, CODELEN=32, DATAMODE=DDR, 12x Oversampling
    db 21h, 02h                                                                 ;REG_CHANNEL = 2402MHz
    db 23h, 03h                                                                 ;REG_PA - PA=3
    db 10h, FFh                                                                 ;REG_TX_VALID
    db 06h, 08h                                                                 ;REG_SERDES_CTL, EOF=0 event will occur at the first invalid bit after a valid reception.
    db 24h, 40h                                                                 ;REG_CRYSTAL_ADJ - comment out this line to measure X13OUT (juno's sole testpoint)
    db 32h, 41h                                                                 ;REG_CLOCK_MANUAL
    db 33h, 41h                                                                 ;REG_CLOCK_ENABLE
    db 26h, C0h                                                                 ;REG_VCO_CAL
    db 2Eh, 80h                                                                 ;REG_PWR_CTL
    db 20h, 44h                                                                 ;REG_ANALOG_CTL
    db 20h, 45h                                                                 ;REG_ANALOG_CTL
EndRadioStartTable:
.endliteral

;.literal
;Radio64kbpsTable:
;   db 18h, B2h                                                                 ;REG_PN_CODE, B
;   db 17h, BBh                                                                 ;REG_PN_CODE, B
;   db 16h, 09h                                                                 ;REG_PN_CODE, B
;   db 15h, 2Bh                                                                 ;REG_PN_CODE, B
;   db 14h, B8h                                                                 ;REG_PN_CODE, A
;   db 13h, 6Bh                                                                 ;REG_PN_CODE, A
;   db 12h, C0h                                                                 ;REG_PN_CODE, A
;   db 11h, DCh                                                                 ;REG_PN_CODE, A overwrite default w/ PN Code Index 1 (64kbps table)
;   db 1Ah, 1Dh                                                                 ;REG_THRESHOLD_H - TH32=3
;   db 19h, 03h                                                                 ;REG_THRESHOLD_L - TH32=3
;   db 04h, 06h                                                                 ;REG_DATA_RATE - 64kbps, CODELEN=32, DATAMODE=DDR
;EndRadio64kbpsTable:
;.endliteral
;
;.literal
;Radio16kbpsTable:
;   db 18h, C9h                                                                 ;REG_PN_CODE, A
;   db 17h, 7Ah                                                                 ;REG_PN_CODE, A
;   db 16h, 48h                                                                 ;REG_PN_CODE, A
;   db 15h, 71h                                                                 ;REG_PN_CODE, A
;   db 14h, AAh                                                                 ;REG_PN_CODE, A
;   db 13h, 4Eh                                                                 ;REG_PN_CODE, A
;   db 12h, 2Ch                                                                 ;REG_PN_CODE, A
;   db 11h, 3Fh                                                                 ;REG_PN_CODE, A overwrite default w/ PN Code Index 1 (16kbps table)
;   db 1Ah, 38h                                                                 ;REG_THRESHOLD_H - TH32=8
;   db 19h, 08h                                                                 ;REG_THRESHOLD_L - TH32=8
;   db 04h, 00h                                                                 ;REG_DATA_RATE - 16kbps, CODELEN=64, DATAMODE=SDR
;EndRadio16kbpsTable:
;.endliteral

.section
;-----------------------------------------------------------------------------
; JunoDelay:      Delay Xmsec, where 1>x<256
;
; 'C' Call:        void JunoDelay(void);
;
; Assembly Call:   A: #msec to delay
;                  X: don't care
;
; Assembly Return: A: zero
;                  X: contents of OSC_CR0
 JunoDelay:
_JunoDelay:
    M8C_SetBank1
    mov X, [OSC_CR0]                                                            ; Temporarily store contents of OSC_CR0 (CPU Speed, Sleep Interval, etc)
    mov [OSC_CR0], 6                                                            ; set CPU Speed to Clock In/128 (187.5kHz/Internal)
    M8C_SetBank0
    or  F,0x1                                                                   ;M8C_EnableGInt                 [4 cycles]
    call MSTIMER_EnableInt                                                      ; Enable MSTIMER interrupt
    mov [MSTIMER_Fired], 0
d1:
    tst [MSTIMER_Fired], 1                                                      ; 5.33usec/instruction cycle    [9 cycles]
    jz  d1                                                                      ;                               [5 cycles]
    mov [MSTIMER_Fired], 0
    dec A
    jnz d1
    M8C_SetBank1
    mov [OSC_CR0], X                                                            ; Restore contents of OSC_CR0
    M8C_SetBank0
    ret                                                                         ;                               [8 cycles]
.endsection

.section
;-----------------------------------------------------------------------------
; JunoWrite:      Write a single byte to an Radio register.
;
; 'C' Call:        void JunoWrite(BYTE regAddr, BYTE value);
;
; Assembly Call:   A: Register number to write, high 2 bits MUST be ZERO !
;                  X: Value to write to the selected register.
;
; Assembly Return: A: lost
;                  X: lost
 JunoWrite:
_JunoWrite:
    or  A, bSPI_WRITE                                                           ; Set the write bit.            [6 cycles]
;-----------------------------------------------------------------------------
;
; JunoRead:       Read a single byte from an Radio register.
;
; 'C' Call:        BYTE JunoRead(BYTE regAddr);
;
; Assembly Call:   A: The register number to read
;                  X: READ=unused, fallthru from WRITE=Data
;
;                  (For both the 'C' and assembly call the top two bits of
;                   the register number MUST be clear.)
;
; Assembly Return: A: Value from register
;                  X: lost
;-----------------------------------------------------------------------------
 JunoRead::
_JunoRead::
    and F,0xFE                                                                  ;M8C_DisableGInt                [4 cycles]
    and reg[JUNO_nSS_Data_ADDR],~JUNO_nSS_MASK                                  ; Assert Slave Select           [9 cycles]
    and reg[INT_CLR0],~(INT_MSK0_SPI_TX | INT_MSK0_SPI_RX)                      ; Clear the TX and RX flag      [9 cycles]
    mov reg[SPIDATA], A                                                         ; Write the address             [5 cycles]
.w1:                                                                            ; Wait for the address write to complete
    tst reg[INT_CLR0],INT_MSK0_SPI_RX                                           ; Address transfer complete?
    jz  .w1                                                                     ; Wait some more
    mov A, X                                                                    ; Load the data to be written
    and reg[INT_CLR0],~(INT_MSK0_SPI_TX | INT_MSK0_SPI_RX)                      ; Clear the TX and RX flag
    mov reg[SPIDATA], A                                                         ; Write the data
.w2:                                                                            ; Wait for the data write to complete
    tst reg[INT_CLR0],INT_MSK0_SPI_RX                                           ; Data transfer complete?
    jz  .w2                                                                     ; Wait some more
    mov A, reg[SPIDATA]                                                         ; Return the sampled data
    or  reg[JUNO_nSS_Data_ADDR], JUNO_nSS_MASK                                  ; Release Slave Select          [9 cycles]
    or  F,0x1                                                                   ;M8C_EnableGInt                 [4 cycles]
    ret                                                                         ;                               [8 cycles]
.endsection

.section
;-----------------------------------------------------------------------------
; JunoSleep:      Sleep the Juno RF Module.
;
; 'C' Call:        void JunoSleep(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: lost
;                  X: lost
 JunoSleep:
_JunoSleep:
    mov A, REG_CONTROL                                                          ;
    mov X, 0                                                                    ;
    call JunoWrite                                                              ; REG_CONTROL - force idle
    mov A, REG_WAKE_EN
    mov X, 1
    call JunoWrite                                                              ; REG_WAKE_EN - event is triggered when the nPD pin is deasserted and once the IC is ready to receive SPI communications.
    mov A, REG_WAKE_STAT
    call JunoRead                                                               ; REG_WAKE_STAT - clear wake status
    and reg[JUNO_nPD_Data_ADDR],~JUNO_nPD_MASK                                  ; Assert nPD - force sleep (typically takes ~50usec from the time nPD is asserted to low power mode)
    and reg[JUNO_nSS_Data_ADDR],~JUNO_nSS_MASK                                  ; Assert Slave Select
    and reg[JUNO_SPIM_MISO_Data_ADDR],~JUNO_SPIM_MISO_MASK                      ; Drive MISO low
    mov reg[P16CR], 01h                                                         ; Make P16 an output
    mov A, 1
    call JunoDelay                                                              ; delay for >10usec
;   mov reg[VREGCR], VREGCR_KEEP_ALIVE                                          ; Put VREG_3V in low-power mode, WARNING!!! w/R3=1ohm ~3.89V measured !!!
    ret                                                                         ;                               [8 cycles]
.endsection

.section
;-----------------------------------------------------------------------------
; JunoWake:      Wake the Juno RF Module.
;
; 'C' Call:        void JunoWake(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: lost
;                  X: lost
 JunoWake:
_JunoWake:
;    mov reg[VREGCR], VREGCR_ENABLE                                             ; Enable 3.3V VREG to JUNO
;    mov A, 1
;    call JunoDelay                                                             ; delay for >1msec
     or reg[JUNO_nPD_Data_ADDR], JUNO_nPD_MASK                                  ; Release nPD - force idle
;    mov A, tXTAL_STARTUP
;    call JunoDelay                                                             ; delay for >3msec
wakeup:
    tst reg[JUNO_IRQ_Data_ADDR], JUNO_IRQ_MASK                                  ; Has the interrupt asserted?
    jz wakeup                                                                   ; wait 'til crystal has stabilized to within 10ppm, ~100usec later ready for synth
    or  reg[JUNO_nSS_Data_ADDR], JUNO_nSS_MASK                                  ; Release Slave Select          [9 cycles]
    mov reg[P16CR], 94h                                                         ; Restore P16 as SPI MISO
    mov A, REG_WAKE_STAT
    call JunoRead                                                               ; REG_WAKE_STAT - clear wake status
;   mov A, 1
;   call JunoDelay                                                              ; delay for >100usec
    ret                                                                         ;                               [8 cycles]
.endsection

.section
;-----------------------------------------------------------------------------
; JunoGetMID:      Retrieve/Store Juno's manufacturing ID in enCoRe II's ram, bRadioMID[]
;
; 'C' Call:        void JunoGetMID(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: lost
;                  X: lost
 JunoGetMID:
_JunoGetMID:
    mov X, 64h
    mov A, REG_ANALOG_CTL                                                       ; REG_ANALOG_CTL - enable reads from MID
    call JunoWrite
    mov A, REG_MFG_ID+0                                                         ;                               [4 cycles]
    call JunoRead                                                               ;                               [11 cycles]
    mov [bRadioMID+0], A                                                        ;                               [5 cycles]
    mov A, REG_MFG_ID+1
    call JunoRead
    mov [bRadioMID+1], A
    mov A, REG_MFG_ID+2
    call JunoRead
    mov [bRadioMID+2], A
    mov A, REG_MFG_ID+3
    call JunoRead
    mov [bRadioMID+3], A
    mov X, 44h
    mov A, REG_ANALOG_CTL                                                       ; REG_ANALOG_CTL - disable reads from MID
    call JunoWrite
    ret
.endsection

.section
;-----------------------------------------------------------------------------
; JunoTransmit:    Transmit data (blocking)
;
; 'C' Call:        void JunoTransmit(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: lost
;                  X: lost
 JunoTransmit:
_JunoTransmit:
;   mov A, REG_TX_INT_STAT
;   call JunoRead                                                               ; REG_TX_INT_STAT - clear transmit status
    mov A, REG_TX_INT_EN
    mov X, 1
    call JunoWrite                                                              ; REG_TX_INT_EN - enable empty flag on IRQ pin
    mov A, REG_CONTROL
    mov X, 50h
    call JunoWrite                                                              ; REG_CONTROL - enable tx
    ; todo: delay synth settle
    ; todo: delay preamble
    mov A, REG_TX_DATA
    mov X, FFh
    call JunoWrite                                                              ; REG_TX_DATA - send data
txE1:
    tst reg[JUNO_IRQ_Data_ADDR], JUNO_IRQ_MASK                                  ; Has the interrupt asserted?
    jz txE1                                                                     ; wait 'til REG_TX_DATA empty
    mov A, REG_TX_DATA
    mov X, 55h
    call JunoWrite                                                              ; REG_TX_DATA - send data (REG_TX_DATA is double buffered)
txE2:
    tst reg[JUNO_IRQ_Data_ADDR], JUNO_IRQ_MASK                                  ; Has the interrupt asserted?
    jz txE2                                                                     ; wait 'til REG_TX_DATA empty
    mov A, REG_TX_DATA
    mov X, AAh
    call JunoWrite                                                              ; REG_TX_DATA - send data
txE3:
    tst reg[JUNO_IRQ_Data_ADDR], JUNO_IRQ_MASK                                  ; Has the interrupt asserted?
    jz txE3                                                                     ; wait 'til REG_TX_DATA empty
    mov A, REG_TX_DATA
    mov X, 00h
    call JunoWrite                                                              ; REG_TX_DATA - send data

    mov A, REG_TX_INT_EN
    mov X, 2
    call JunoWrite                                                              ; REG_TX_INT_EN - enable done flag on IRQ pin
txD:
    tst reg[JUNO_IRQ_Data_ADDR], JUNO_IRQ_MASK                                  ; Has the interrupt asserted?
    jz txD                                                                      ; wait 'til REG_TX_DATA done
    mov A, REG_CONTROL
    mov X, 0
    call JunoWrite                                                              ; REG_CONTROL - return to idle
    mov A, REG_TX_INT_STAT
    call JunoRead                                                               ; REG_TX_INT_STAT - clear transmit status
    ret
.endsection

.section
;-----------------------------------------------------------------------------
; JunoReceive:    Receive data (blocking)
;
; 'C' Call:        void JunoReceive(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: bRadioRxLen
;                  X: lost
 JunoReceive:
_JunoReceive:
    mov [bRadioRxLen], 0
    mov [bRadioWipPtr], bRadioRxData
    mov A, REG_RX_INT_STAT
    call JunoRead                                                               ; REG_RX_INT_STAT - clear receive status
    mov A, REG_CONTROL
    mov X, 90h
    call JunoWrite                                                              ; REG_CONTROL - enable rx
    ; todo: delay synth settle
    ; todo: delay receiver ready
rxP:
    tst reg[JUNO_IRQ_Data_ADDR], JUNO_IRQ_MASK                                  ; Has the interrupt asserted?
    jz rxP                                                                      ; wait 'til either EOFA or FULLA receive flag fires
    mov A, REG_RX_INT_STAT
    call JunoRead                                                               ; REG_RX_INT_STAT - check receive status
    mov [bRadioRxStat], A
    tst [bRadioRxStat], 1                                                       ; check to see if the receive SERDES register has data
    jz checkRxEOF
    mov A, REG_RX_DATA_A
    call JunoRead                                                               ; store REG_RX_DATA_A and
    mvi [bRadioWipPtr], A
;   mov A, REG_RX_VALID_A
;   call JunoRead                                                               ; store REG_RX_VALID_A
;   mvi [bRadioWipPtr], A
    tst [bRadioRxStat], 8                                                       ; check to see if all of the bits in the Receive SERDES Data A Register are valid.
    jz checkRxEOF
    inc [bRadioRxLen]
checkRxEOF:
    tst [bRadioRxStat], 2                                                       ; check to see if an EOF event has occurred
    jnz rxDone
    jmp rxP
rxDone:
    mov A, REG_CONTROL
    mov X, 0
    call JunoWrite                                                              ; REG_CONTROL - return to idle
    mov A, REG_RSSI
    call JunoRead                                                               ; REG_RSSI - fetch RSSI for this receive packet
    mov [bRadioRSSI], A
    mov A, [bRadioRxLen]
    ret
.endsection

.section
;-----------------------------------------------------------------------------
; JunoStop:      Stop the Juno RF Module.
;
; 'C' Call:        void JunoStop(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: lost
;                  X: lost
 JunoStop:
_JunoStop:
    call JunoSleep
    and reg[JUNO_nRST_Data_ADDR],~JUNO_nRST_MASK                                ; Assert nRST
;   mov reg[VREGCR], VREGCR_DISABLE                                             ; Disable 3.3V VREG to JUNO
    ret                                                                         ;                               [8 cycles]
.endsection
