//----------------------------------------------------------------------------- // See cul.h for a description of this function. //----------------------------------------------------------------------------- void sppReceive(SPP_STRUCT* pReceiveData){ sppRxStatus = RX_WAIT; DMA_ABORT_CHANNEL(dmaNumberRx); // Setting the address to where the received data are to be written. // Setting max number of bytes to receive SET_DMA_DEST(dmaRx,pReceiveData); SET_DMA_LENGTH(dmaRx,255); // Arming the DMA channel. The receiver will initate the transfer when a packet is received. DMA_ARM_CHANNEL(dmaNumberRx); // Debug: SIDLE(); RFIF &= ~IRQ_SFD; RFIM |= IRQ_SFD; // Turning on the receiver SRX(); return; }
// ************************************************************************************************* // Test RF reception // ************************************************************************************************* void test_rf(void) { u16 time1, time2, packet1, packet2, div; s16 ref, delta; u8 i; s16 freqest; u8 freqest1; s16 freqest0; u8 continue_test = YES; // Config radio for RX rftest_init(); // Set timeout in 1.5 seconds reset_timer1(); set_timer1(32768*1.5); T1CCTL0 = 0x44; T1CTL = 0x02; // Clear RF interrupts S1CON &= ~(BIT1 | BIT0); // Clear MCU interrupt flag RFIF &= ~BIT4; // Clear "receive/transmit done" interrupt RFIM |= BIT4; // Enable "receive/transmit done" interrupt // Enable IRQ INT_ENABLE(INUM_RFTXRX, INT_ON); INT_ENABLE(INUM_RF, INT_ON); INT_ENABLE(INUM_T1, INT_ON); // Clear test result variable test_result = 0; // Continue to receive packets until timeout while ((rftest_count < RFTEST_PACKET_COUNT) && (!sTimer1.iflag)) { // Start new RX if radio is IDLE if (MARCSTATE == 0x01) SRX(); } SIDLE(); // Analyze received packets if (sTimer1.iflag || rftest_count < RFTEST_PACKET_COUNT/2) { // Timeout - no or not enough packets received test_result = 0x8000; continue_test = NO; } else { // Store last and first packet for (i=0; i<RFTEST_PACKET_COUNT; i++) { if (rftest[i].valid) { time1 = rftest[i].time; packet1 = rftest[i].packet_nb; break; } } for (i=RFTEST_PACKET_COUNT-1; i>0; i--) { if (rftest[i].valid) { time2 = rftest[i].time; packet2 = rftest[i].packet_nb; break; } } // Calculate mean freqest freqest = 0; div = 0; for (i=0; i<RFTEST_PACKET_COUNT; i++) { if (rftest[i].valid) { // Sign extend negative numbers if ((rftest[i].freqoffset & BIT7) == BIT7) { freqest += (s16)(0xFF00 | rftest[i].freqoffset); } else { freqest += (s16)(rftest[i].freqoffset); } div++; } } // FREQEST range check freqest0 = freqest/(s16)div; if ((freqest0 < RFTEST_FREQEST_MIN) || (freqest0 > RFTEST_FREQEST_MAX)) { test_result = 0x2000 | (u8)freqest0; continue_test = NO; } else { // FREQEST range ok // Calculate distance between 1 and 2 // TX sends packet each 3276 ACLK ticks (= 1145 T1CLK ticks) ref = (packet2 - packet1)*3276; delta = time2 - time1; if ((ref - delta) < RFTEST_ACLK_DEVIATION_MAX) { // Store ACLK deviation in test result test_result = ((ref - delta)&0x0F) << 8; // Store average FREQEST if (freqest < 0) { freqest1 = (u8)((freqest*(-1))/div); freqest1 = ~freqest1 + 1; test_result |= freqest1; } else { test_result |= (u8)(freqest/div); } } else if ((delta - ref) < RFTEST_ACLK_DEVIATION_MAX) { // Store ACLK deviation in test result test_result = ((delta - ref)&0x0F) << 8; // Store average FREQEST if (freqest < 0) { freqest1 = (u8)((freqest*(-1))/div); freqest1 = ~freqest1 + 1; test_result |= freqest1; } else { test_result |= (u8)(freqest/div); } } else { // Too high ACLK deviation test_result = 0x4000; continue_test = NO; } } } // 2nd test stage - use RF offset to catch another few packets if (continue_test == YES) { rftest_count = 0; // Clear RX variables for (i=0; i<RFTEST_PACKET_COUNT; i++) { rftest[i].valid = 0; rftest[i].time = 0; rftest[i].packet_nb = 0; rftest[i].freqoffset = 0; } // Set frequency offset FSCTRL0 = freqest0; // Set timeout in 0.5 seconds reset_timer1(); set_timer1(32768*0.5); // Try to receive just 1 packet while ((rftest_count < 1) && (!sTimer1.iflag)) { // Start new RX if radio is IDLE if (MARCSTATE == 0x01) SRX(); } SIDLE(); // Analyze received packets frequency offset - should be close to 0 if (rftest_count > 0) { if (!((rftest[0].freqoffset >= 0xFE) || (rftest[0].freqoffset <= 0x02))) { test_result = 0x1000; } } else { test_result = 0x1000; } } // Disable IRQ INT_ENABLE(INUM_RFTXRX, INT_OFF); INT_ENABLE(INUM_RF, INT_OFF); INT_ENABLE(INUM_T1, INT_OFF); // Stop Timer1 T1CTL = 0x00; T1CNTL = 0x55; reset_timer1(); }
//----------------------------------------------------------------------------- // See cul.h for a description of this function. //----------------------------------------------------------------------------- BYTE sppSend(SPP_STRUCT* pPacketPointer){ BYTE res = TRUE; // Checking that length is not too long if (pPacketPointer->payloadLength > SPP_MAX_PAYLOAD_LENGTH) { res = TOO_LONG; sppTxStatus = TX_IDLE; } // Flipping the sequence bit, writing total packet length and address if the transfer is not a retransmission. // If it is a retransmission, the fields are correct if(!(pPacketPointer->flags & RETRANSMISSION)) { pPacketPointer->flags ^= SEQUENCE_BIT; pPacketPointer->payloadLength += SPP_HEADER_AND_FOOTER_LENGTH; pPacketPointer->srcAddress = myAddress; } // Setting up the DMA DMA_ABORT_CHANNEL(dmaNumberTx); SET_DMA_SOURCE(dmaTx,pPacketPointer); // Proceed if the packet length is OK. if (res == TRUE) { // Clearing RF interrupt flags and enabling RF interrupts. RFIF &= ~IRQ_DONE; RFIM &= ~IRQ_SFD; INT_SETFLAG(INUM_RF, INT_CLR); #ifdef CCA_ENABLE if(!CCA) { SRX(); // Turning on Rx and waiting to make the RSSI value become valid. halWait(1); } if(CCA) #endif { // Setting up radio DMA_ABORT_CHANNEL(dmaNumberRx); SIDLE(); RFTXRXIF = 0; INT_GLOBAL_ENABLE(FALSE); DMA_ARM_CHANNEL(dmaNumberTx); STX(); INT_GLOBAL_ENABLE(TRUE); sppTxStatus = TX_IN_PROGRESS; if(pPacketPointer->flags & DO_ACK) { pAckData = pPacketPointer; waitForAck(); } else { pAckData = NULL; } RFIM |= IRQ_DONE; } #ifdef CCA_ENABLE // The "air" is busy else { res = CHANNEL_BUSY; RFIM &= ~IRQ_DONE; // De-flipping the sequence bit. if(!(pPacketPointer->flags & RETRANSMISSION)) { pPacketPointer->flags ^= SEQUENCE_BIT; } } #endif } return res; } // ends sppSend
//----------------------------------------------------------------------------- // See cul.h for a description of this function. //----------------------------------------------------------------------------- BOOL sppInit(UINT32 frequency, BYTE address){ BYTE res = 0; BOOL status = TRUE; sppSetAddress(address); // Clearing the states of the spp. sppTxStatus = TX_IDLE; sppRxStatus = RX_IDLE; retransmissionCounter = 0; ackTimerNumber = 0; pAckData = 0; // Clearing the RF interrupt flags and enable mask and enabling RF interrupts RFIF = 0; RFIM = 0; INT_SETFLAG(INUM_RF,INT_CLR); INT_ENABLE(INUM_RF,INT_ON); // Setting the frequency and initialising the radio res = halRfConfig(FREQUENCY_4_CC1110); if(res == FALSE){ status = FALSE; } // Always in RX unless sending. //debug: MCSM1 = 0x2F; // MCSM1 = 0x3F; SRX(); // Using the timer 4 administrator to generate interrupt to check if a message is unacked... culTimer4AdmInit(); // Initialising the DMA administrator culDmaInit(); // Requesting a DMA channel for transmit data. No callback function is used. Instead the TX_DONE // interrupt is used to determine when a transfer is finished. Configuring the DMA channel for // transmit. The data address and length will be set prior to each specific transmission. dmaTx = culDmaAllocChannel(&dmaNumberTx, 0); if((dmaNumberTx == 0) || (dmaNumberTx > 4)){ status = FALSE; } culDmaToRadio(dmaTx, SPP_MAX_PAYLOAD_LENGTH + SPP_HEADER_AND_FOOTER_LENGTH, 0, FALSE); // Requesting a DMA channel for receiving data. Giving the address of the callback function. // Configuring the DMA channel for receive. The data address will be set prior to each specific // reception. dmaRx = culDmaAllocChannel(&dmaNumberRx, &rxCallBack); if((dmaNumberRx == 0) || (dmaNumberRx > 4)){ status = FALSE; } culDmaFromRadio(dmaRx, 0, TRUE); // Making sure that none of the channels are armed. DMA_ABORT_CHANNEL(dmaNumberRx); DMA_ABORT_CHANNEL(dmaNumberTx); INT_ENABLE(INUM_DMA, INT_ON); return status; } // ends sppInit