/********************************************************************* * @fn zbSocTransportWrite * * @brief Write to the the serial port to the CC253x. * * @param fd - file descriptor of the UART device * * @return status */ void zbSocTransportWrite( uint8_t* buf, uint8_t len ) { if (len > SPI_MAX_DAT_LEN) { len = SPI_MAX_DAT_LEN; } spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; spiClockData(spiTxPkt, SPI_PKT_LEN(spiTxPkt)); return; }
/************************************************************************************************** * @fn HalUARTWriteSPI * * @brief Transmit data bytes as a SPI packet. * * input parameters * * @param buf - pointer to the memory of the data bytes to send. * @param len - the length of the data bytes to send. * * output parameters * * None. * * @return Zero for any error; otherwise, 'len'. */ static spiLen_t HalUARTWriteSPI(uint8 *buf, spiLen_t len) { // Already in Tx or Rx transaction #ifdef RBA_UART_TO_SPI // The RBA Bridge is not written to handle re-writes so we must // just let it write if (spiTxLen != 0) #else //!RBA_UART_TO_SPI if (spiTxLen != 0 || SPI_RDY_OUT()) #endif { return 0; } if (len > SPI_MAX_DAT_LEN) { len = SPI_MAX_DAT_LEN; } spiTxLen = len; writeActive = 1; #if defined HAL_SPI_MASTER spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt)); /* DMA TX might need padding */ /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_RX ); spiRxIdx = 0; (void)memset(spiRxBuf, (DMA_PAD ^ 0xFF), SPI_MAX_PKT_LEN * sizeof(uint16)); HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_TX ); HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_CSn_OUT(); while((!SPI_RDY_IN()) && (!spiRdyIsr) ); HAL_DMA_MAN_TRIGGER(HAL_SPI_CH_TX); #elif !defined HAL_SPI_MASTER #ifdef POWER_SAVING /* Disable POWER SAVING when transmission is initiated */ CLEAR_SLEEP_MODE(); #endif HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt) + 1); /* slave DMA TX might drop the last byte */ HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_RDY_OUT(); #endif return len; }
/************************************************************************************************** * @fn spiClockData * * @brief Clock Rx bytes on the SPI bus. * * input parameters * * @param pBuf - pointer to the memory of the data bytes to send; NULL to send dummy zeroes. * @param len - the length of the data bytes to send. * * output parameters * * None. * * @return The FCS calculated. */ static void spiClockData(uint8_t *pBuf, uint8_t len) { struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)pBuf, .rx_buf = (unsigned long)spiRxTmp, .len = len, .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; if (pBuf == NULL) // If just requesting to send dummy zero bytes. { (void)memset(spiRxTmp, 0, len); tr.tx_buf = (unsigned long)spiRxTmp; } pthread_mutex_lock(&spiMutex1); int rtrn = ioctl(spiDevFd, SPI_IOC_MESSAGE(1), &tr); pthread_mutex_unlock(&spiMutex1); if (rtrn < 0) { //printf("spiClockData: Full duplex transfer failed\n"); } else { pBuf = spiRxTmp; // Now that the SPI bus Mutex has been released, copy the Rx data from this temporary linear // buffer into the circular buffer accessed by the background parsing algorithm. while (len--) { //printf("spiClockData[%x]: %x\n", spiRxTail, *pBuf); spiRxBuf[spiRxTail++] = *pBuf++; } } } /************************************************************************************************** * @fn spiParseRx * * @brief Parse all available bytes from the spiRxBuf[] into the spiRxPkt[]. * Note: Only call if (spiRxRdy == 0). * * input parameters * * None. * * output parameters * * None. * * @return None. */ static void spiParseRx(void) { //printf("spiParseRx++\n"); while (1) { if (spiRxHead == spiRxTail) { //If we have FCS/Sync errors consider giving zbSoC longer to change SRDY //usleep(50); if (spiSrdyCheck(1)) { spiClockData(NULL, 1); continue; } break; } uint8_t ch = spiRxBuf[spiRxHead]; SPI_LEN_T_INCR(spiRxHead); switch (spiRxSte) { case spiRxSteSOF: if (ch == SPI_SOF) { spiRxSte = spiRxSteLen; // At this point, the master has effected the protocol for ensuring that the SPI slave is // awake, so set the spiRxLen to non-zero to prevent the slave from re-entering sleep until // the entire packet is received - even if the master interrupts the sending of the packet // by de-asserting/re-asserting MRDY one or more times. spiRxLen = 1; } break; case spiRxSteLen: spiRxPkt[SPI_LEN_IDX] = ch; if ((ch == 0) || (ch > SPI_MAX_DAT_LEN)) { spiRxSte = spiRxSteSOF; spiRxLen = 0; } else { spiRxLen = ch; spiRxCnt = 0; spiRxSte = spiRxSteData; spiClockData(NULL, (ch+1)); // Clock out the SPI Frame Data bytes and FCS. } break; case spiRxSteData: spiRxPkt[SPI_DAT_IDX + spiRxCnt++] = ch; if (spiRxCnt == spiRxLen) { spiRxSte = spiRxSteFcs; } break; case spiRxSteFcs: spiRxSte = spiRxSteSOF; if (ch == spiCalcFcs(spiRxPkt)) { spiRxRdy = spiRxLen; // Zero spiRxLen now to re-enable sleep within SPI_PM_DLY time. Before sleep is entered, // both the Application will be notified of spiRxRdy via uartCB(), and the spiRxBuf will be // polled again for another SOF (which would block the return to sleep). spiRxLen = 0; // Zero spiRxCnt now to re-use it for counting the data bytes incrementally read with // HalUARTReadSPI() for Applications that do not read all at once. spiRxCnt = 0; return; } else { printf("spiParseRx: FCS failed for len %x, Calc:%x Read:%x\n", spiRxPkt[SPI_LEN_IDX], spiCalcFcs(spiRxPkt), ch); } spiRxCnt = 0; break; default: spiRxSte = spiRxSteSOF; break; } } } /********************************************************************* * API FUNCTIONS */ /********************************************************************* * @fn zbSocTransportOpen * * @brief opens the serial port to the CC253x. * * @param devicePath - path to the UART device * * @return status */ int32_t zbSocTransportOpen( char *devicePath ) { //printf("zbSocTransportOpen++: %s\n",devicePath); /* open the device */ spiDevFd = open(devicePath, O_RDWR ); if (spiDevFd <0) { perror(devicePath); printf("%s open failed\n",devicePath); exit(-1); } /* * spi mode */ ioctl(spiDevFd, SPI_IOC_WR_MODE, &mode); ioctl(spiDevFd, SPI_IOC_RD_MODE, &mode); /* * bits per word */ ioctl(spiDevFd, SPI_IOC_WR_BITS_PER_WORD, &bits);; ioctl(spiDevFd, SPI_IOC_RD_BITS_PER_WORD, &bits); /* * max speed hz */ ioctl(spiDevFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); ioctl(spiDevFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); return spiSrdyInit(); }
/************************************************************************************************** * @fn HalUARTWriteSPI * * @brief Transmit data bytes as a SPI packet. * * input parameters * * @param buf - pointer to the memory of the data bytes to send. * @param len - the length of the data bytes to send. * * output parameters * * None. * * @return Zero for any error; otherwise, 'len'. */ static spiLen_t HalUARTWriteSPI(uint8 *buf, spiLen_t len) { if (spiTxLen != 0) { return 0; } if (len > SPI_MAX_DAT_LEN) { len = SPI_MAX_DAT_LEN; } spiTxLen = len; #if defined HAL_SPI_MASTER spiRdyIsr = 0; spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt)); /* DMA TX might need padding */ /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_RX ); spiRxIdx = 0; (void)memset(spiRxBuf, (DMA_PAD ^ 0xFF), SPI_MAX_PKT_LEN * sizeof(uint16)); HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_TX ); HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_CSn_OUT(); while((!SPI_RDY_IN()) && (!spiRdyIsr) ); HAL_DMA_MAN_TRIGGER(HAL_SPI_CH_TX); #elif !defined HAL_SPI_MASTER #ifdef POWER_SAVING /* Disable POWER SAVING when transmission is initiated */ CLEAR_SLEEP_MODE(); #endif SPI_CLR_RDY_OUT(); HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); if ( SPI_RDY_IN() ) { SPI_SET_RDY_OUT(); } spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt) + 1); /* slave DMA TX might drop the last byte */ HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_RDY_OUT(); #endif return len; }