pn532_error_t pn532_bus_Wakeup(void)
{
  pn532_error_t error = PN532_ERROR_NONE;
  byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };

  pn532_pcb_t *pn532 = pn532GetPCB();

  #ifdef PN532_DEBUGMODE
  PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
  #endif
  error = pn532_bus_i2c_WriteData(abtWakeUp,sizeof(abtWakeUp));
  if (error)
  {
    #ifdef PN532_DEBUGMODE
      PN532_DEBUG("Wakeup Failed (Error: %d)%s", error, CFG_PRINTF_NEWLINE);
    #endif
    return error;
  }

  systickDelay(100);

  // Wait for the IRQ/Ready flag to indicate a response is ready
  if (!(pn532_bus_i2c_WaitForReady(PN532_I2C_TIMEOUT)))
  {
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE);
    #endif
    error = PN532_ERROR_READYSTATUSTIMEOUT;
  }

  // Read and discard the ACK frame
  I2CWriteLength = 0;
  I2CReadLength = 7;  // ACK + Ready bit = 7
  I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
  i2cEngine();
  systickDelay(1);

  // Wait for the IRQ/Ready flag to indicate a response is ready
  if (!(pn532_bus_i2c_WaitForReady(PN532_I2C_TIMEOUT)))
  {
    error = PN532_ERROR_READYSTATUSTIMEOUT;
  }
  #ifdef PN532_DEBUGMODE
  PN532_DEBUG("Wakeup Complete%s", CFG_PRINTF_NEWLINE);
  #endif

  pn532->state = PN532_STATE_READY;
  return error;
}
pn532_error_t pn532_bus_Wakeup(void)
{
  size_t szLen;
  byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };

  pn532_pcb_t *pn532 = pn532GetPCB();

  #ifdef PN532_DEBUGMODE
  PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
  #endif
  uartSend(abtWakeUp,sizeof(abtWakeUp));
  delay(100);

  byte_t response[32];
  pn532_bus_ReadResponse(response, &szLen);

  // Todo: Check for error ... currently throws a checksum error
  // that isn't really an error

  pn532->state = PN532_STATE_READY;
  return PN532_ERROR_NONE;
}
pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
{
  uint8_t i;
  pn532_pcb_t *pn532 = pn532GetPCB();

  // Check if we're busy
  if (pn532->state == PN532_STATE_BUSY)
  {
    return PN532_ERROR_BUSY;
  }

  // Flag the stack as busy
  pn532->state = PN532_STATE_BUSY;

  // Reset the app error flag
  pn532->appError = PN532_APPERROR_NONE;

  for ( i = 0; i < I2C_BUFSIZE; i++ )
  {
    I2CMasterBuffer[i] = 0x00;
  }
  I2CWriteLength = 0;
  I2CReadLength = I2C_BUFSIZE;
  I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
  i2cEngine();

  // Use the full I2C buffer size for now (until we're sure we have a good frame)
  *pszRxLen = I2C_BUFSIZE - 1;

  // Display the raw response data for debugging if requested
  #ifdef PN532_DEBUGMODE
  PN532_DEBUG("Received (%02d): ", I2C_BUFSIZE-1);
  pn532PrintHex(I2CSlaveBuffer+1, I2C_BUFSIZE-1);
  #endif

  // Check the frame type
  if ((0x01 == I2CSlaveBuffer[4]) && (0xff == I2CSlaveBuffer[5]))
  {
    // Error frame
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG("Application level error (0x%02x)%s", I2CSlaveBuffer[6], CFG_PRINTF_NEWLINE);
    #endif
    // Set application error message ID
    pn532->appError = I2CSlaveBuffer[6];
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_APPLEVELERROR;
  }
  else if ((0xff == I2CSlaveBuffer[4]) && (0xff == I2CSlaveBuffer[5]))
  {
    // Extended frame
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
    #endif
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_EXTENDEDFRAME;
  }
  else
  {
    // Normal frame
    if (256 != ((I2CSlaveBuffer[4]) + (I2CSlaveBuffer[5])))
    {
      // TODO: Retry
      #ifdef PN532_DEBUGMODE
      PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
      #endif
      pn532->state = PN532_STATE_READY;
      return PN532_ERROR_LENCHECKSUMMISMATCH;
    }
  }

  // Figure out how large the response really is
  // Response Frame Len = pbtResponse[4] + 7 (00 00 FF LEN LCS TFI [DATA] DCS)
  *pszRxLen = (I2CSlaveBuffer[4]) + 7;

  // TODO: Find a solution for this horribly ugly Mifare Classic block write hack!
  // Some responses to command 0x40 report the incorrect len, and don't take into
  // account the 16 byte payload when working with Mifare Classic sectors.
  // The response frame indicates len 10 (0x0A) in I2CSlaveBuffer[4] but it should be
  // 10+16 = 26 (0x1A)
  if ((*pszRxLen == 10) && (I2CSlaveBuffer[7] == 0x41) && (I2CSlaveBuffer[26] != 0x00))
  {
    // For some reason, the PN532 reports len 10 for responses to
    // command 0x40 which includes the command data but does not
    // take into account the response/payload data in the len byte
    *pszRxLen+=16;
  }

  // Fill the response buffer
  // memcpy(pbtResponse, I2CSlaveBuffer+1, *pszRxLen);
  for ( i = 0; i < *pszRxLen; i++ )
  {
    pbtResponse[i] = I2CSlaveBuffer[i+1];
  }

  pn532->state = PN532_STATE_READY;
  return PN532_ERROR_NONE;
}
pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData)
{
  pn532_error_t error = PN532_ERROR_NONE;
  byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
  size_t szFrame = 0;
  pn532_pcb_t *pn532 = pn532GetPCB();
  uint32_t i;

  // Check if we're busy
  if (pn532->state == PN532_STATE_BUSY)
  {
    return PN532_ERROR_BUSY;
  }

  // Flag the stack as busy
  pn532->state = PN532_STATE_BUSY;

  // --------------------------------------------------------------------
  // Send the command frame
  // --------------------------------------------------------------------
  // Build the frame
  pn532_bus_i2c_BuildFrame (abtFrame, &szFrame, pbtData, szData);

  // Keep track of the last command that was sent
  pn532->lastCommand = pbtData[0];

  // Output the frame data for debugging if requested
  #ifdef PN532_DEBUGMODE
  PN532_DEBUG("Sending  (%02d): ", szFrame);
  pn532PrintHex(abtFrame, szFrame);
  #endif

  // Send data to the PN532
  error = pn532_bus_i2c_WriteData(abtFrame, szFrame);

  if (error == PN532_ERROR_I2C_NACK)
  {
    // Most likely error is PN532_ERROR_I2C_NACK
    // meaning no I2C ACK received from the PN532
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG ("No ACK received on I2C bus%s", CFG_PRINTF_NEWLINE);
    #endif
    pn532->state = PN532_STATE_READY;
    return error;
  }

  // --------------------------------------------------------------------
  // Wait for the IRQ/Ready flag
  // --------------------------------------------------------------------
  if (!(pn532_bus_i2c_WaitForReady(PN532_I2C_TIMEOUT)))
  {
    pn532->state = PN532_STATE_READY;
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE);
    #endif
    return PN532_ERROR_READYSTATUSTIMEOUT;
  }

  // --------------------------------------------------------------------
  // Read the ACK frame
  // --------------------------------------------------------------------
  I2CWriteLength = 0;
  I2CReadLength = 7;  // ACK + Ready bit = 7
  I2CMasterBuffer[0] = PN532_I2C_ADDRESS | PN532_I2C_READBIT;
  i2cEngine();

  // Make sure the received ACK matches the prototype
  do
  {
    const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
    byte_t abtRxBuf[6];
    // memcpy(abtRxBuf, I2CSlaveBuffer+1, 6);
    for ( i = 0; i < 6; i++ )
    {
      abtRxBuf[i] = I2CSlaveBuffer[i+1];
    }
    if (0 != (memcmp (abtRxBuf, abtAck, 6)))
    {
      #ifdef PN532_DEBUGMODE
      PN532_DEBUG ("Invalid ACK: ");
      pn532PrintHex(abtRxBuf, 6);
      PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
      #endif
      pn532->state = PN532_STATE_READY;
      return PN532_ERROR_INVALIDACK;
    }

    // --------------------------------------------------------------------
    // Wait for the post-ACK IRQ/Ready flag
    // --------------------------------------------------------------------
    if (!(pn532_bus_i2c_WaitForReady(PN532_I2C_TIMEOUT)))
    {
      pn532->state = PN532_STATE_READY;
      #ifdef PN532_DEBUGMODE
      PN532_DEBUG ("Timed out waiting for IRQ/Ready%s", CFG_PRINTF_NEWLINE);
      #endif
      return PN532_ERROR_READYSTATUSTIMEOUT;
    }
  } while(0);

  pn532->state = PN532_STATE_READY;
  return PN532_ERROR_NONE;
}
pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
{
  pn532_pcb_t *pn532 = pn532GetPCB();

  // Check if we're busy
  if (pn532->state == PN532_STATE_BUSY)
  {
    return PN532_ERROR_BUSY;
  }

  // Flag the stack as busy
  pn532->state = PN532_STATE_BUSY;

  // Reset the app error flag
  pn532->appError = PN532_APPERROR_NONE;

  // Read response from uart
  if (!uartRxBufferReadArray(pbtResponse, pszRxLen))
  {
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_RESPONSEBUFFEREMPTY;
  }

  // Display the raw response data for debugging if requested
  #ifdef PN532_DEBUGMODE
  PN532_DEBUG("Received (%02d): ", *pszRxLen);
  pn532PrintHex(pbtResponse, *pszRxLen);
  #endif

  // Check preamble
  const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
  if (0 != (memcmp (pbtResponse, pn53x_preamble, 3)))
  {
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE);
    #endif
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_PREAMBLEMISMATCH;
  }

  // Check the frame type
  if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
  {
    // Error frame
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
    #endif
    // Set application error message ID
    pn532->appError = pbtResponse[5];
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_APPLEVELERROR;
  }
  else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
  {
    // Extended frame
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
    #endif
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_EXTENDEDFRAME;
  }
  else
  {
    // Normal frame
    if (256 != (pbtResponse[3] + pbtResponse[4]))
    {
      // TODO: Retry
      #ifdef PN532_DEBUGMODE
      PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
      #endif
      pn532->state = PN532_STATE_READY;
      return PN532_ERROR_LENCHECKSUMMISMATCH;
    }
    // size_t szPayloadLen = abtRx[3] - 2;
  }

  pn532->state = PN532_STATE_READY;
  return PN532_ERROR_NONE;
}
pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData)
{
  pn532_pcb_t *pn532 = pn532GetPCB();

  // Check if we're busy
  if (pn532->state == PN532_STATE_BUSY)
  {
    return PN532_ERROR_BUSY;
  }

  // Flag the stack as busy
  pn532->state = PN532_STATE_BUSY;

  // Every packet must start with "00 00 ff"
  byte_t  abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
  size_t szFrame = 0;

  // Build the frame
  pn532_bus_BuildFrame (abtFrame, &szFrame, pbtData, szData);

  // Keep track of the last command that was sent
  pn532->lastCommand = pbtData[0];

  // Output the frame data for debugging if requested
  #ifdef PN532_DEBUGMODE
  PN532_DEBUG("Sending  (%02d): ", szFrame);
  pn532PrintHex(abtFrame, szFrame);
  #endif

  // Send data to the PN532
  uartSend (abtFrame, szFrame);

  // Wait for ACK
  byte_t abtRxBuf[6];
  uart_pcb_t *uart = uartGetPCB();
  delay(10);   // FIXME: How long should we wait for ACK?
  if (uart->rxfifo.len < 6)
  {
    // Unable to read ACK
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG ("Unable to read ACK%s", CFG_PRINTF_NEWLINE);
    #endif
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_NOACK;
  }

  // Read ACK ... this will also remove it from the buffer
  const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
  abtRxBuf[0] = uartRxBufferRead();
  abtRxBuf[1] = uartRxBufferRead();
  abtRxBuf[2] = uartRxBufferRead();
  abtRxBuf[3] = uartRxBufferRead();
  abtRxBuf[4] = uartRxBufferRead();
  abtRxBuf[5] = uartRxBufferRead();

  // Make sure the received ACK matches the prototype
  if (0 != (memcmp (abtRxBuf, abtAck, 6)))
  {
    #ifdef PN532_DEBUGMODE
    PN532_DEBUG ("Invalid ACK: ");
    pn532PrintHex(abtRxBuf, 6);
    PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
    #endif
    pn532->state = PN532_STATE_READY;
    return PN532_ERROR_INVALIDACK;
  }

  pn532->state = PN532_STATE_READY;
  return PN532_ERROR_NONE;
}