;/***************************************************************************
; *   Copyright (C) 2009, Crawlerz                                          *
; *                                                                         *
; *   Description:                                                          *
; *        - Juno RF Module Non-Blocking Transmit & Receive API             *
; *   Version:                                                              *
; *     2009.48.2                                                           *
; *                                                                         *
; *   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 JunoDelay
export JunoWrite
export JunoRead
export JunoSleep
export JunoWake
export JunoGetMID
export JunoStartTransmit
export JunoStartReceive
export JunoInterrupt
export JunoStop
export bRadioMID
export bRadioRxStat
export bRadioRxData
export bRadioTxData
export bRadioWipPtr
export bRadioPayloadLen
export bRadioRSSI
export bRadioState

area InterruptRAM(ram)                                                          ; variables on ram page 0
bRadioMID:
bRadioRxData:
bRadioTxData:       blk 16
bRadioWipPtr:       blk 1
bRadioPayloadLen:   blk 1
bRadioTemp:
bRadioRxStat:       blk 1
bRadioRSSI:         blk 1
bRadioState:        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::
    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 [bRadioState], RADIO_IDLE

    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 04h, 07h                                                                  ;REG_DATA_RATE - 64kbps, CODELEN=32, DATAMODE=DDR, 12x Oversampling
   db 21h, 02h                                                                  ;REG_CHANNEL = 2402MHz
   db 23h, 00h                                                                  ;REG_PA - PA=0
   db 07h, 03h                                                                  ;REG_RX_INT_EN - enable EOFA and FULLA flags on IRQ pin   
   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, 07h                                                                 ;REG_DATA_RATE - 64kbps, CODELEN=32, DATAMODE=DDR, 12x Oversampling
;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 0>x<256
;
; 'C' Call:        void JunoDelay(void);
;
; Assembly Call:   A: #msec to delay
;                  X: don't care
;
; Assembly Return: A: contents of OSC_CR0
;                  X: contents of OSC_CR0
JunoDelay::
;    push A
;    M8C_SetBank1
;    mov A, reg[OSC_CR0]                                                         ; Temporarily store contents of OSC_CR0 (CPU Speed, Sleep Interval, etc)
;    mov X, A
;    mov reg[OSC_CR0], 6                                                         ; set CPU Speed to Clock In/128 (187.5kHz/Internal)
;    M8C_SetBank0
;    pop A
    or  F,0x1                                                                   ;M8C_EnableGInt                 [4 cycles]
    call MSTIMER_EnableInt                                                      ; Enable MSTIMER interrupt
    mov [MSTIMER_Fired], 0
waitForIsrToFire:
    tst [MSTIMER_Fired], 1                                                      ; 5.33usec/instruction cycle    [9 cycles]
    jz  waitForIsrToFire                                                        ;                               [5 cycles]
    mov [MSTIMER_Fired], 0
    dec A
    jnz waitForIsrToFire
;    M8C_SetBank1
;    mov A, X
;    mov reg[OSC_CR0], A                                                         ; Restore contents of OSC_CR0
;    M8C_SetBank0
    call MSTIMER_DisableInt
    ret                                                                         ;                               [8 cycles]
.endsection

.section
;-----------------------------------------------------------------------------
; JunoWrite:      Write a single byte to a radio register.
;
; 'C' Call:        void JunoWrite(BYTE address, 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::
    or  A, bSPI_WRITE                                                           ; Set the write bit.            [6 cycles]
;-----------------------------------------------------------------------------
; JunoRead:       Read a single byte from a radio register.
;
; 'C' Call:        BYTE JunoRead(BYTE address);
;
; Assembly Call:   A: The register number to read
;                  X: READ=unused, fallthru from WRITE=Data
;
; Assembly Return: A: Value from register
;                  X: lost
;-----------------------------------------------------------------------------
JunoRead::
;   and F,0xFE                                                                  ;M8C_DisableGInt                [4 cycles]
    and reg[JUNO_nSS_Data_ADDR],~JUNO_nSS_MASK                                  ; Assert Slave Select           [9 cycles]
    mov reg[SPIDATA], A                                                         ; Write the address             [5 cycles]
    and reg[INT_CLR0],~(INT_MSK0_SPI_TX | INT_MSK0_SPI_RX)                      ; Clear the TX and RX flag      [9 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
    index radioStartTable                                                       ; 6 index x 13 cycles/index = 78 cycles ~3.25usec
    index radioStartTable
    index radioStartTable
    index radioStartTable
    index radioStartTable
    index radioStartTable
    mov A, X                                                                    ; Load the data to be written
    mov reg[SPIDATA], A                                                         ; Write the data
    and reg[INT_CLR0],~(INT_MSK0_SPI_TX | INT_MSK0_SPI_RX)                      ; Clear the TX and RX flag
;w2:                                                                            ; Wait for the data write to complete
;   tst reg[INT_CLR0],INT_MSK0_SPI_RX                                           ; Data transfer complete?
;   jz w2                                                                       ; Wait some more
    index radioStartTable                                                       ; 7 index x 13 cycles/index = 91 cycles ~3.79usec
    index radioStartTable
    index radioStartTable
    index radioStartTable
    index radioStartTable
    index radioStartTable
    index radioStartTable    
    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::
    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 [bRadioState], RADIO_SLEEP
;   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::
;   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
waitForCrystalStable:
    tst reg[JUNO_IRQ_Data_ADDR], JUNO_IRQ_MASK                                  ; Has the interrupt asserted?
    jz waitForCrystalStable                                                     ; 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
    mov [bRadioState], RADIO_IDLE
    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::
    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
;-----------------------------------------------------------------------------
; JunoStartTransmit:    Transmit bRadioTxData data, bRadioPayloadLen times
;
; 'C' Call:        void JunoStartTransmit(void);
;
; Assembly Call:   A: don't care, !!!WARNING!!! dont' forget to set bRadioPayloadLen
;                  X: don't care, !!!WARNING!!! don't forget to fill bRadioTxData
;
; Assembly Return: A: lost
;                  X: lost
JunoStartTransmit::
    M8C_DisableIntMask INT_MSK0, INT_MSK0_GPIO_INT0 
    cmp [bRadioPayloadLen], 0
    jz  startTransmitEnd2
    mov A, REG_CONTROL
    mov X, 50h
    call JunoWrite                                                              ; REG_CONTROL - enable tx
    mov [bRadioState], RADIO_TX                                                 ; [8 cycles]    
    mov X, 2                                                                    ; [4 cycles]
    M8C_SetBank1                                                                ; [4 cycles]
    mov A, reg[OSC_CR0]                                                         ; [6 cycles] Temporarily store contents of OSC_CR0 (CPU Speed, Sleep Interval, etc)
    mov reg[OSC_CR0], 6                                                         ; [8 cycles] set CPU Speed to Clock In/128 (187.5kHz/Internal)
    M8C_SetBank0                                                                ; [4 cycles] 5.33usec/instruction cycle
delaySynthPreamble:
    cmp A, [bRadioState]                                                        ; [7 cycles]
    dec X                                                                       ; [4 cycles]
    jnz delaySynthPreamble                                                      ; [5 cycles]
    M8C_SetBank1                                                                ; [4 cycles]
    mov reg[OSC_CR0], A                                                         ; [5 cycles] Restore contents of OSC_CR0
    M8C_SetBank0                                                                ; [4 cycles]
    mov [bRadioWipPtr], bRadioTxData     
    mvi A, [bRadioWipPtr]                                                       ; get data 
    mov X, A
    mov A, REG_TX_DATA
    call JunoWrite                                                              ; REG_TX_DATA - send data
    mov A, REG_TX_INT_EN
    mov X, 1
    call JunoWrite                                                              ; REG_TX_INT_EN - enable empty flag on IRQ pin
    dec [bRadioPayloadLen]
    jnz  startTransmitEnd    
    mov A, REG_TX_INT_EN
    mov X, 2
    call JunoWrite                                                              ; REG_TX_INT_EN - enable done flag on IRQ pin    
startTransmitEnd:       
;    M8C_ClearIntFlag  INT_MSK0, INT_MSK0_GPIO_INT0
    M8C_EnableIntMask INT_MSK0, INT_MSK0_GPIO_INT0
    M8C_EnableGInt
startTransmitEnd2:    
    ret
.endsection

.section
;-----------------------------------------------------------------------------
; JunoStartReceive:    Start the receive process
;
; 'C' Call:        void JunoStartReceive(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: bRadioPayloadLen
;                  X: lost
JunoStartReceive::
    mov [bRadioPayloadLen], 0
    mov [bRadioWipPtr], bRadioRxData
    mov A, REG_CONTROL
    mov X, 90h
    call JunoWrite                                                              ; REG_CONTROL - enable rx
    mov [bRadioState], RADIO_RX
    M8C_EnableGInt
    M8C_ClearIntFlag  INT_MSK0, INT_MSK0_GPIO_INT0
    M8C_EnableIntMask INT_MSK0, INT_MSK0_GPIO_INT0
    ret
.endsection

.section
;-----------------------------------------------------------------------------
; JunoInterrupt:    Process the data phase
;
; 'C' Call:        void JunoInterrupt(void);
;
; Assembly Call:   A: don't care
;                  X: don't care
;
; Assembly Return: A: bRadioPayloadLen
;                  X: lost
JunoInterrupt::
    cmp [bRadioState], RADIO_RX
    jnz checkTx
    mov A, REG_RX_INT_STAT                                                      ; either EOFA or FULLA receive flag fired
    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
;   mov A, REG_RSSI
;   call JunoRead                                                               ; REG_RSSI - fetch RSSI for this receive packet
;   mov [bRadioRSSI], A
    tst [bRadioRxStat], 2                                                       ; check to see if an EOFA event has occurred
    jnz transactionDone
    tst [bRadioRxStat], 8                                                       ; check to see if all of the bits in the Receive SERDES Data A Register are valid.
    jz checkRxEOF
    inc [bRadioPayloadLen]
checkRxEOF:
    mov A, REG_RX_INT_STAT                                                      ; debounce EOFA - event fires faster than can be serviced via interrupts
    call JunoRead                                                               ; REG_RX_INT_STAT - check receive status
    mov [bRadioRxStat], A
    tst [bRadioRxStat], 2                                                       ; check to see if an EOFA event has occurred
    jnz transactionDone
    reti
checkTx:
    cmp [bRadioState], RADIO_TX
    jnz interruptEnd
    cmp [bRadioPayloadLen], 0
    jz  transactionDone
moveTxData:
    mvi A, [bRadioWipPtr]                                                       ; get data
    mov X, A
    mov A, REG_TX_DATA
    call JunoWrite                                                              ; REG_TX_DATA - send data
    cmp [bRadioPayloadLen], 1
    jnz nextTxData 
    mov A, REG_TX_INT_EN
    mov X, 2
    call JunoWrite                                                              ; REG_TX_INT_EN - enable done flag on IRQ pin
nextTxData:
    dec [bRadioPayloadLen]
    reti
transactionDone:    
    mov A, REG_CONTROL
    mov X, 0
    call JunoWrite                                                              ; REG_CONTROL - return to idle
    mov [bRadioState], RADIO_IDLE
    M8C_DisableIntMask INT_MSK0, INT_MSK0_GPIO_INT0
interruptEnd:
    reti
.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::
    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