/*********************************************************************
 * @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;
}
Example #2
0
/**************************************************************************************************
 * @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;
}