/************************************************************************************************** * @fn HalUARTReadSPI * * @brief Read data bytes from a received SPI packet. * * input parameters * * @param buf - pointer to the memory to where to copy the received SPI data bytes. * @param len - the length to copy (for now, must be the exact length of the received data). * * output parameters * * None. * * @return The number of bytes read from a received SPI packet. */ static spiLen_t HalUARTReadSPI(uint8 *buf, spiLen_t len) { for (spiLen_t cnt = 0; cnt < len; cnt++) { if (spiRxHead == spiRxTail) { len = cnt; break; } *buf++ = spiRxDat[spiRxHead]; SPI_LEN_T_INCR(spiRxHead); } return len; }
/************************************************************************************************** * @fn spiParseRx * * @brief Parse all available bytes from the spiRxBuf[]; parse Rx data into the spiRxDat[]. * * input parameters * * None. * * output parameters * * None. * * @return None. */ static void spiParseRx(void) { uint8 done = 0; halIntState_t cs; #ifdef HAL_SPI_MASTER uint8 numNotSOF = 0; uint8 count = 0; SPI_SET_CSn_OUT(); #endif //HAL_SPI_MASTER while (!done) { if (!SPI_NEW_RX_BYTE(spiRxIdx)) { #if defined HAL_SPI_MASTER // Clock a byte from slave SPI_CLOCK_RX(1); #else break; #endif } uint8 ch = SPI_GET_RX_BYTE(spiRxIdx); SPI_CLR_RX_BYTE(spiRxIdx); SPI_LEN_T_INCR(spiRxIdx); #ifdef HAL_SPI_MASTER // If searching for a SOF byte limit the number of bytes searched // to SPI_FRM_LEN if ( spiRxPktState == SPIRX_STATE_SOF ) { count++; numNotSOF = ( ch == SPI_SOF ) ? numNotSOF : numNotSOF + 1; // Haven't recieved an SOF. Assume not a packet but only break if there is // no new bytes in the RX buffer to read if ( numNotSOF > SPI_FRM_LEN && numNotSOF == count ) { // Clear all Rx'ed NULL bytes while(SPI_NEW_RX_BYTE(spiRxIdx)) { SPI_CLR_RX_BYTE(spiRxIdx); SPI_LEN_T_INCR(spiRxIdx); } break; } } #endif //HAL_SPI_MASTER switch (spiRxPktState) { case SPIRX_STATE_SOF: if (ch == SPI_SOF) { spiRxPktState = SPIRX_STATE_LEN; /* 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 SPIRX_STATE_LEN: if ((ch == 0) || (ch > SPI_MAX_DAT_LEN)) { spiRxPktState = SPIRX_STATE_SOF; spiRxLen = 0; } else { spiRxFcs = spiRxLen = ch; spiRxTemp = spiRxTail; spiRxCnt = 0; spiRxPktState = SPIRX_STATE_DATA; #if defined HAL_SPI_MASTER if (!SPI_NEW_RX_BYTE(spiRxIdx)) /* Fix for simultaneous TX/RX to avoid extra clock pulses to SPI Slave */ { halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); SPI_CLOCK_RX(ch + 1); /* Clock out the SPI Frame Data bytes and FCS */ HAL_EXIT_CRITICAL_SECTION(intState); } #endif } break; case SPIRX_STATE_DATA: spiRxFcs ^= ch; spiRxDat[spiRxTemp] = ch; SPI_LEN_T_INCR(spiRxTemp); if (++spiRxCnt == spiRxLen) { spiRxPktState = SPIRX_STATE_FCS; } break; case SPIRX_STATE_FCS: spiRxPktState = SPIRX_STATE_SOF; #ifdef POWER_SAVING pktFound = TRUE; #endif if (ch == spiRxFcs) { spiRxTail = spiRxTemp; } else { dbgFcsByte = ch; #ifdef RBA_UART_TO_SPI badFcsPktCount++; #endif } spiRxCnt = spiRxLen = 0; #ifdef HAL_SPI_MASTER // Clear any trailing empty Rx'ed bytes // Should only receive one frame per MRDY assertion while(SPI_NEW_RX_BYTE(spiRxIdx)) { SPI_CLR_RX_BYTE(spiRxIdx); SPI_LEN_T_INCR(spiRxIdx); } done = 1; #endif //HAL_SPI_MASTER break; default: HAL_ASSERT(0); break; } } spiTxLen = 0; HAL_ENTER_CRITICAL_SECTION(cs); spiRdyIsr = 0; HAL_EXIT_CRITICAL_SECTION(cs); #ifdef HAL_SPI_MASTER SPI_CLR_CSn_OUT(); #ifdef RBA_UART_TO_SPI // Must wait until slave has ended transaction because // the RBA implementation cannot delay writes so this is a // forced delay.... while(SPI_RDY_IN()); #endif #else SPI_CLR_RDY_OUT(); #endif //HAL_SPI_MASTER }
/************************************************************************************************** * @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 spiParseRx * * @brief Parse all available bytes from the spiRxBuf[]; parse Rx data into the spiRxDat[]. * * input parameters * * None. * * output parameters * * None. * * @return None. */ static void spiParseRx(void) { while (1) { if (!SPI_NEW_RX_BYTE(spiRxIdx)) { #if defined HAL_SPI_MASTER if (SPI_RDY_IN() && (spiTxLen == 0)) { SPI_CLOCK_RX(1); continue; } #endif break; } uint8 ch = SPI_GET_RX_BYTE(spiRxIdx); SPI_CLR_RX_BYTE(spiRxIdx); SPI_LEN_T_INCR(spiRxIdx); switch (spiRxPktState) { case SPIRX_STATE_SOF: if (ch == SPI_SOF) { spiRxPktState = SPIRX_STATE_LEN; /* 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 SPIRX_STATE_LEN: if ((ch == 0) || (ch > SPI_MAX_DAT_LEN)) { spiRxPktState = SPIRX_STATE_SOF; spiRxLen = 0; } else { spiRxFcs = spiRxLen = ch; spiRxTemp = spiRxTail; spiRxCnt = 0; spiRxPktState = SPIRX_STATE_DATA; #if defined HAL_SPI_MASTER if (!SPI_NEW_RX_BYTE(spiRxIdx)) /* Fix for simultaneous TX/RX to avoid extra clock pulses to SPI Slave */ { halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); SPI_CLOCK_RX(ch + 1); /* Clock out the SPI Frame Data bytes and FCS */ HAL_EXIT_CRITICAL_SECTION(intState); } #endif } break; case SPIRX_STATE_DATA: spiRxFcs ^= ch; spiRxDat[spiRxTemp] = ch; SPI_LEN_T_INCR(spiRxTemp); if (++spiRxCnt == spiRxLen) { spiRxPktState = SPIRX_STATE_FCS; } break; case SPIRX_STATE_FCS: spiRxPktState = SPIRX_STATE_SOF; #ifdef POWER_SAVING pktFound = TRUE; #endif SPI_CLR_RDY_OUT(); /* SPI_RDYOut = 1 */ if (ch == spiRxFcs) { spiRxTail = spiRxTemp; } else { dbgFcsByte = ch; #ifdef RBA_UART_TO_SPI badFcsPktCount++; #endif } spiRxCnt = spiRxLen = 0; break; default: HAL_ASSERT(0); break; } } }