📄 voip8kisr.asm
字号:
JZ .exit ; Radio buffer empty, nothing to do
MOV X, A ; X = length to load
; ------------------------------
CMP A, MAX_CTL_SZ+1
JC .ctl ; Small "control" frame
; ------------------------------
CMP A, VOIP_PKT_LEN
JNZ .trash ; Discard: not Control or ADPCM
; ------------------------------
; ADPCM Frame
; ------------------------------
.voip:
CMP [rxPktStat], RXPKT_TRASH ; If already loaded ADPCM frame,
JZ .trash ; then discard buffer
MOV [rxVoipSet], [RadioWipPtr]
CALL isrRadioFileReadWip ; Unload ADPCM data from Radio
JMP .exit
; ------------------------------
; Control Frame
; ------------------------------
.ctl: MOV [_bufRxCtl+0], X ; Length of buffer
MOV [RadioWipPtr], _bufRxCtl+1
CALL isrRadioFileReadWip ; Unload Control frame from Radio
JMP .exit
; --------------------------------------------------------------------
; Discard frame (corrupt or duplicate frames)
; --------------------------------------------------------------------
.trash: CALL isrRadioFileReadWipTrash ; Unload data from Radio and discard
; --------------------------------------------------------------------
; If Tx Go was skipped, force radio to RX mode
; --------------------------------------------------------------------
MOV A, [txGoSkipped]
JZ .exit
MOV X, (FRC_END_STATE + END_STATE_RX)
MOV A, XACT_CFG_ADR + bSPI_WRITE
CALL isrRadioWrite
; Don't wait for FRC_END_STATE to complete, just delay
; by waiting for next ISR to issue more SPI commands
; fallthru JMP .exit
; --------------------------------------------------------------------
; If Slot 4A, then publish result of ADPCM Radio load
;
; rxVoipSet = 0 if failed to load ADPCM from radio
; = bufRxVoip0 or bufRxVoip1
; --------------------------------------------------------------------
.exit:
CMP [_slotCt], 4+12 ;
JNZ isrRadX ; Not Tx_4b slot, so not 3 mS epoch
; --------------------------------------------------------------------
; Update Rx Voip Fast Packet Average (assume missed packet)
; --------------------------------------------------------------------
MOV A, [_rxPktAve_Q3] ; Ant A/B packet average
ASR A ;
ASR A ;
ASR A ;
AND A, 0x1F ;
SUB [_rxPktAve_Q3], A ; Default missed-packet
; --------------------------------------------------------------------
; Update Rx Voip Slow Packet Average (assume missed packet)
; --------------------------------------------------------------------
MOV A, [_rxPktAve_Q8+MSB] ; Ant A/B packet average
SUB [_rxPktAve_Q8+LSB], A ; Default missed-packet
SBB [_rxPktAve_Q8+MSB], 0 ;
; -------------------------------
XOR [bufRxVoipTog], 1 ; Alternate RAM buffers for Rx packets
MOV A, [rxVoipSet] ; Load and Test for ZERO
MOV [rxVoipSet], 0 ; Haven't loaded *new* VOIP frame yet
MOV [bufRxVoipPtr], A
JZ .noRx ; <<<< No RF frame, bufRxVoipPtr=0 >>>
; --------------------------------------------------------------------
; Publish results of valid received 3 mS voice packet.
; --------------------------------------------------------------------
ADD [_rxPktAve_Q3], 15 ; Update Fast Rx Packet Average
ADD [_rxPktAve_Q8+LSB], 127 ; Update Slow Rx Packet Average
ADC [_rxPktAve_Q8+MSB], 0 ;
ADD [bufRxVoipPtr], 3 ; Ptr to ADPCM samples
IF LOOPBACK_ADPCM ;#############################################
; Let ADPCM predict and step free-run ;#####
ELSE ; NOT LOOPBACK_ADPCM ;#############################################
MOV X, A ; rxVoipSet[0]
MOV A, [X+MSB]
AND A, 0x0F ; prediction is only 12-bits
MOV [_iDecPredict+MSB], A ; MSByte
MOV A, [X+LSB]
; --------------------------------------------------------------------
; Convert 12-bit Prediction from RF to 15-bit prediction for local use
; --------------------------------------------------------------------
ASL A ; (MSB,LSB) <<= 3
RLC [_iDecPredict+MSB]
ASL A ; LSByte
RLC [_iDecPredict+MSB]
ASL A ; LSByte
RLC [_iDecPredict+MSB]
MOV [_iDecPredict+LSB], A ; LSByte
MOV A, [X+2]
MOV [_bDecStepSizePtr], A
ENDIF ; LOOPBACK_ADPCM ;#############################################
JMP isrRadX
.noRx:
INC_16 _mibMissRx_2
JMP isrRadX
; ----------------------------------------------------------------------------
doFrameTx_6a:
UART_BIT
JMP isrRadX
; ----------------------------------------------------------------------------
; ----------------------------------------------------------------------------
;
; doFrameRx_1 -
;
; ----------------------------------------------------------------------------
doFrameRx_1:
MOV A, [_reqChWrite] ; If new voice channel pending
JNZ doChChg1 ; then begin changing channel
; Else proceed with normal receive
; ---------- RX_GO
MOV X, (RX_GO + SOFDET_IRQ + RXC_IRQ)
MOV A, RX_CTRL_ADR + bSPI_WRITE
CALL isrRadioWrite
; ---------- WORKAROUND: FALSE SOP IMMEDIATELY AFTER RX_GO
MOV A, RX_IRQ_STATUS_ADR ; Clear any false SOP bit from RX_GO
CALL isrRadioRead ; When radio isn't IDLE, if this
MOV [rxGoOn], 1 ; occurs, it *just* occurred.
MOV [rxIrqStatus], 0
; ---------- goto Tx mode if frame received
MOV X, END_STATE_TXSYNTH
MOV A, XACT_CFG_ADR + bSPI_WRITE
CALL isrRadioWrite
JMP isrRadX
; ----------------------------------------------------------------------------
;
; doFrameRx_2a - Decide whether SOP is arriving where it should
; doFrameRx_2b - Decide whether SOP is arriving where it should
;
; ----------------------------------------------------------------------------
doFrameRx_2a:
UART_BIT
doFrameRx_2b:
MOV [rxPktStat], RXPKT_VOIP ; Default to Found SOP for VOIP frame
; --------------------------------------------------------------------
; ADJUST SLOT TIMING TO TRACK ARRIVING FRAMES
;
; Align SOP at this point (about 30 uS from ISR)
; --------------------------------------------------------------------
TEST_LED_LO ; =======================
TEST_LED_HI ; =======================
IS_IRQ_ON
jnz .early
; --------------------------------------------------------------------
; If SOP doesn't arrive in 20 uS, then begin Rx Abort process
; --------------------------------------------------------------------
.sopWait:
MOV A, (20 * CPU_MHZ/23) ; Wait max 20uS
.wait: IS_IRQ_ON ; 9
JNZ .late ; 5 GOOD: SOP arrived
DEC A ; 4
JNZ .wait ; 5
.sopFail:
; --------------------------------------------------------------------
; SOP FAILED - Start Rx ABORT process via CDT4056 WORKAROUND
; --------------------------------------------------------------------
MOV X, ABORT_EN
MOV A, RX_ABORT_ADR + bSPI_WRITE
CALL isrRadioWrite
MOV [rxPktStat], RXPKT_NOSOP ; Mark bad Rx slot
INC_16 _mibMissRx_1 ; ++ error count
JMP isrRadX
; --------------------------------------------------------------------
.early: MOV [isrPeriod], ISR_VAL_NEG1 ; Early SOP = Faster Counter
jmp .exit
.late: MOV [isrPeriod], ISR_VAL_POS1 ; Late SOP = Slower Counter
.exit: MOV A, RX_IRQ_STATUS_ADR ;
CALL isrRadioRead ; Expose RXC/RXE IRQ
MOV [rxIrqStatus], A ; and remember any self-clearing flags
JMP isrRadX
; ----------------------------------------------------------------------------
;
; doFrameRx_3 -
;
; ----------------------------------------------------------------------------
doFrameRx_3a:
UART_BIT
doFrameRx_3b:
MOV [isrPeriod], ISR_VAL_NOM ; Clr possible adj from doFrameRx_2
CMP [rxPktStat], RXPKT_NOSOP ; If SOP was present
JNZ isrRadX ; then don't abort the Rx
; --------------------------------------------------------------------
; No Rx Frame arrived in designated Slot, therefore Rx is
; manually being aborted by using digital loopback.
; --------------------------------------------------------------------
; although RadioAbort() uses SOP bit in RSSI register, this isn't any
; better than using SOP_IRQ. I've seen SOP_IRQ be falsely set, then
; cleared by this firmware, and subsequently SOP_RSSI is seen here.
; So... forget RadioAbort() and just use SOP_IRQ
; --------------------------------------------------------------------
IS_IRQ_ON
JZ frcEnd ; No SOP, Force End State is OK now
MOV A, RX_IRQ_STATUS_ADR ;
call isrRadioRead ; Expose RXC/RXE IRQ
OR [rxIrqStatus], A ; and remember any self-clearing flags
JMP digLbOff
; --------------------------------------------------------------------
; No SOP yet (and we're not going to get one because digital loopback)
; So Force End State is safe.
; --------------------------------------------------------------------
frcEnd:
MOV X, (FRC_END_STATE + END_STATE_TXSYNTH)
MOV A, XACT_CFG_ADR + bSPI_WRITE
CALL isrRadioWrite
.Loop: MOV A, XACT_CFG_ADR ; Wait for the FRC_END_STATE
CALL isrRadioRead ; bit in the XACT_CFG register
AND A, FRC_END_STATE ; to clear indicating the force has
JNZ .Loop ; completed.
MOV [rxGoOn], 0 ; Rx Go is finally finished
digLbOff:
MOV X, 0x00 ; Disble digital loopback (normal mode)
MOV A, RX_ABORT_ADR + bSPI_WRITE
CALL isrRadioWrite
JMP isrRadX
; ----------------------------------------------------------------------------
; ----------------------------------------------------------------------------
;
; doFrameRx_5a -
; doFrameRx_5b -
;
; ----------------------------------------------------------------------------
doFrameRx_5b:
; --------------------------------------------------------------------
; Prep to load Load VOIP Tx Slot A: Always a new VOIP frame
; --------------------------------------------------------------------
MOV [txPktLen], VOIP_PKT_LEN
MOV [RadioWipPtr], bufTxVoip
MOV X, TX_CLR ; ---------- Clear Tx Buffer
MOV A, TX_CTRL_ADR + bSPI_WRITE
CALL isrRadioWrite
INC_16 _voipCt
JMP isrRadX
; ----------------------------------------------------------------------------
; Load VOIP Tx Slot B: Usually retransmit VOIP_A frame, or new control frame
; ----------------------------------------------------------------------------
doFrameRx_5a:
UART_BIT
MOV A, [bufTxCtl]
JZ isrRadX ; Just retransmit VOIP_A frame
MOV [txPktLen], A ; Control frame Length
MOV X, TX_CLR ; ---------- Clear Tx Buffer
MOV A, TX_CTRL_ADR + bSPI_WRITE
CALL isrRadioWrite
JMP isrRadX
; ----------------------------------------------------------------------------
;
; doFrameRx_6a -
;
; FINAL SLOT BEFORE REPEAT
; doFrameRx_6b - Should have (nearly) finished receiving frame
;
; ----------------------------------------------------------------------------
doFrameRx_6b:
MOV [_slotCt], 0 ; wraparound slot counter [1-24]
; --------------------------------------------------------------------
;
; ---------- Copy VOIP frame to Radio Tx buf
;
; --------------------------------------------------------------------
MOV A, TX_BUFFER_ADR + bSPI_WRITE
CALL isrRadioFileWriteWip ; Burst the data in
; --------------------------------------------------------------------
; Reset local ADPCM Encode buffer
;
; Snapshot of ADPCM Encoder state
; --------------------------------------------------------------------
MOV [bufTxVoipPtr], bufTxVoip+3 ; New ADPCM samples go here
MOV [bufTxVoip+2], [_bEncStepSizePtr] ; Enc StepSize
MOV [bufTxVoip+LSB], [_iEncPredict+LSB]
MOV A, [_iEncPredict+MSB] ; Enc Predict (15-bit)
RRC A ; (MSB,LSB) >>= 3
RRC [bufTxVoip+LSB]
RRC A ; (MSB,LSB) >>= 3
RRC [bufTxVoip+LSB]
RRC A ; (MSB,LSB) >>= 3
RRC [bufTxVoip+LSB]
AND A, 0x0F
MOV [bufTxVoip+MSB], A ; Enc Predict (12-bit)
; ------------------------------
JMP isrRadX
doFrameRx_6a:
CMP [txPktLen], VOIP_PKT_LEN
JZ isrRadX ; Resend prior VOIP frame
; --------------------------------------------------------------------
; ---------- Copy Control frame to Radio Tx buf
; --------------------------------------------------------------------
MOV [RadioWipPtr], bufTxCtl + 1 ; ptr to Control frame data
MOV [bufTxCtl], 0 ; Indicate control buf has been sent
MOV A, TX_BUFFER_ADR + bSPI_WRITE
CALL isrRadioFileWriteWip ; Burst the data in
JMP isrRadX
isrRadX:
; --------------------------------------------------------------------
;
; ADPCM PROCESSING
;
; Get 15-bit unipolar big-endian word from USB OUT page buffer
;
; Also do USB to Codec rate-matching here (sample insert/delete),
; based on
; If bit 15 is SET in [[usbOutOt]], then either INSERT or DELETE sample
; insert [insertVal], clearing [15] in [usbOutOt] for next time
; delete skip by simply ++usbOutOt.
; extern char nulInsDel = Pending: {0=none, 1=insert, 2=delete}
; extern WORD insertVal = 15-bit unipolar
; ---------------------------------------------------------------------
MOV A, [_usbOutOt+LSB]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -