Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SPITIS_TPM20.cpp
- Committer:
- LordOfDorks
- Date:
- 2015-03-23
- Revision:
- 0:b11c8971edd9
- Child:
- 1:fd0a59e55a85
File content as of revision 0:b11c8971edd9:
/* mbed TCG TIS 1.3 SPI TPM 2.0 Library, * Copyright (c) 2015, Microsoft Coprporation Inc. * by Stefan Thom (LordOfDorks) StefanTh@Microsoft.com, Stefan@ThomsR.Us * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SPITIS_TPM20.h" TISTPM20::TISTPM20( PinName mosi, PinName miso, PinName clk, PinName cs ) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Init: "); #endif m_SPITpmDev = new SPI(mosi, miso, clk); m_SPITpmDev->format(8, 0); m_SPITpmDev->frequency(4000000); m_SPICSTpmDev = new DigitalOut(cs); *m_SPICSTpmDev = 1; m_ExclusiveAccess = false; #ifdef TPM_TIS_DEBUG_OUTPUT printf("OK.\n\r"); #endif } // Release all held resources TISTPM20::~TISTPM20() { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Destroy: "); #endif if(m_SPITpmDev != NULL) { delete m_SPITpmDev; m_SPITpmDev = NULL; } if(m_SPICSTpmDev != NULL) { delete m_SPICSTpmDev; m_SPICSTpmDev = NULL; } #ifdef TPM_TIS_DEBUG_OUTPUT printf("OK.\n\r"); #endif } uint32_t TISTPM20::Execute( uint8_t locality, uint8_t* pbCmd, uint32_t cbCmd, uint8_t* pbRsp, uint32_t cbRsp, uint32_t timeout ) { uint32_t result = 0; Timeout watchdog; #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.ExecuteWaitForAccess."); #endif // Only one caller should be talking to the TPM at any given time while(m_ExclusiveAccess) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("."); #endif wait_us(500); } m_ExclusiveAccess = true; #ifdef TPM_TIS_DEBUG_OUTPUT printf("OK\n\r"); #endif // Set the requested locality for the call m_Locality = locality; #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Locality = %d\n\r", m_Locality); #endif #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.SetupTimeout\n\r"); #endif // Setup TPM timeout m_TimeoutTriggered = false; watchdog.attach(this, &TISTPM20::TimeoutTrigger, 0.0001 * timeout); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Execute: "); for(uint32_t n = 0; n < cbCmd; n++) printf("%02x ", pbCmd[n]); printf("\n\r"); #endif // Execute command on the TPM if((result = ExecuteTIS(pbCmd, cbCmd, pbRsp, cbRsp)) == 0) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Failed\n\r"); #endif goto Cleanup; } #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Response: "); for(uint32_t n = 0; n < result; n++) printf("%02x ", pbRsp[n]); printf("\n\r"); #endif #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.CancelTimeout\n\r"); #endif Cleanup: watchdog.detach(); m_ExclusiveAccess = false; return result; } uint32_t TISTPM20::ParseResponseHeader( uint8_t* pbRsp, uint32_t rspLen, uint16_t* rspTag, uint32_t* rspSize, uint32_t* cursor ) { uint32_t rspResponseCode = 0; // Check that the response header is well formatted if(rspLen < (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t))) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.ResponseHdr.rspLen = 0x%08x\n\r", rspLen); #endif rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } // Read the header components *rspTag = BYTEARRAY_TO_UINT16(pbRsp, *cursor); *cursor += sizeof(uint16_t); *rspSize = BYTEARRAY_TO_UINT32(pbRsp, *cursor); *cursor += sizeof(uint32_t); rspResponseCode = BYTEARRAY_TO_UINT32(pbRsp, *cursor); *cursor += sizeof(uint32_t); // Check the components if(((*rspTag != TPM_ST_NO_SESSIONS) && (*rspTag != TPM_ST_SESSIONS)) || (*rspSize != rspLen)) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.ResponseHdr.rspTag = 0x%04x.rspLen=0x%08x\n\r", *rspTag, rspLen); #endif rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } Cleanup: return rspResponseCode; } uint32_t TISTPM20::TPM2_Startup( uint8_t locality, uint16_t startupType ) { uint32_t rspLen = 0; uint16_t rspTag = 0; uint32_t rspSize = 0; uint32_t rspResponseCode = 0; uint32_t cursor = 0; uint8_t tpmCmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; #ifndef TPM_TIS_DEBUG_OUTPUT uint32_t timeout = 2000; #else uint32_t timeout = 20000; #endif UINT16_TO_BYTEARRAY(startupType, tpmCmd, sizeof(tpmCmd) - 2); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_Startup(0x%04x)\n\r", startupType); #endif if((rspLen = Execute(locality, tpmCmd, sizeof(tpmCmd), tpmCmd, sizeof(tpmCmd), timeout)) == 0) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) { goto Cleanup; } if(rspSize != 0x0000000a) { rspResponseCode = TPM_RC_FAILURE; } Cleanup: #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_Startup.ResponseCode = 0x%08x\n\r", rspResponseCode); #endif return rspResponseCode; } uint32_t TISTPM20::TPM2_Shutdown( uint8_t locality, uint16_t shutdownType ) { uint32_t rspLen = 0; uint16_t rspTag = 0; uint32_t rspSize = 0; uint32_t rspResponseCode = 0; uint32_t cursor = 0; uint8_t tpmCmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x45, 0x00, 0x00}; #ifndef TPM_TIS_DEBUG_OUTPUT uint32_t timeout = 2000; #else uint32_t timeout = 20000; #endif UINT16_TO_BYTEARRAY(shutdownType, tpmCmd, sizeof(tpmCmd) - 2); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_Shutdown(0x%04x)\n\r", shutdownType); #endif if((rspLen = Execute(locality, tpmCmd, sizeof(tpmCmd), tpmCmd, sizeof(tpmCmd), timeout)) == 0) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) { goto Cleanup; } if(rspSize != 0x0000000a) { rspResponseCode = TPM_RC_FAILURE; } Cleanup: #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_Shutdown.ResponseCode = 0x%08x\n\r", rspResponseCode); #endif return rspResponseCode; } uint32_t TISTPM20::TPM2_SelfTest( uint8_t locality, uint8_t fullTest ) { uint32_t rspLen = 0; uint16_t rspTag = 0; uint32_t rspSize = 0; uint32_t rspResponseCode = 0; uint32_t cursor = 0; uint8_t tpmCmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x43, 0x00}; #ifndef TPM_TIS_DEBUG_OUTPUT uint32_t timeout = 2000; #else uint32_t timeout = 20000; #endif tpmCmd[sizeof(tpmCmd) - 1] = fullTest; #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_SelfTest(0x%02x)\n\r", fullTest); #endif if((rspLen = Execute(locality, tpmCmd, sizeof(tpmCmd), tpmCmd, sizeof(tpmCmd), timeout)) == 0) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) { goto Cleanup; } if(rspSize != 0x0000000a) { rspResponseCode = TPM_RC_FAILURE; } Cleanup: #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_SelfTest.ResponseCode = 0x%08x\n\r", rspResponseCode); #endif return rspResponseCode; } uint32_t TISTPM20::TPM2_GetRandom( uint8_t locality, uint16_t bytesRequested, uint8_t* randomBytes ) { uint32_t cursor = 0; uint32_t rspLen = 0; uint16_t rspTag = 0; uint32_t rspSize = 0; uint32_t rspResponseCode = 0; uint32_t tpmMax = sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + bytesRequested; uint8_t* tpmCmd = new uint8_t[tpmMax]; uint16_t bytesReturned = 0; #ifndef TPM_TIS_DEBUG_OUTPUT uint32_t timeout = 2000; #else uint32_t timeout = 20000; #endif if(tpmCmd == NULL) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } // Build command UINT16_TO_BYTEARRAY(TPM_ST_NO_SESSIONS, tpmCmd, cursor); cursor += sizeof(uint16_t) + sizeof(cursor); UINT32_TO_BYTEARRAY(TPM_CC_GetRandom, tpmCmd, cursor); cursor += sizeof(TPM_CC_GetRandom); UINT16_TO_BYTEARRAY(bytesRequested, tpmCmd, cursor); cursor += sizeof(bytesRequested); UINT32_TO_BYTEARRAY(cursor, tpmCmd, sizeof(uint16_t)); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_GetRandom(%d)\n\r", bytesRequested); #endif if((rspLen = Execute(locality, tpmCmd, cursor, tpmCmd, tpmMax, timeout)) == 0) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } cursor = 0; if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) { goto Cleanup; } if(rspSize != tpmMax) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } // Copy the random bytes out bytesReturned = BYTEARRAY_TO_UINT16(tpmCmd, cursor); cursor += sizeof(uint16_t); memcpy(randomBytes, &tpmCmd[cursor], (size_t)min(bytesReturned, bytesRequested)); Cleanup: #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_GetRandom.ResponseCode = 0x%08x\n\r", rspResponseCode); #endif if(tpmCmd != NULL) { delete[] tpmCmd; tpmCmd = NULL; } return rspResponseCode; } uint32_t TISTPM20::TPM2_StirRandom( uint8_t locality, uint16_t inDataLen, uint8_t* inData ) { uint32_t cursor = 0; uint32_t rspLen = 0; uint16_t rspTag = 0; uint32_t rspSize = 0; uint32_t rspResponseCode = 0; uint32_t tpmMax = sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + inDataLen; uint8_t* tpmCmd = new uint8_t[tpmMax]; #ifndef TPM_TIS_DEBUG_OUTPUT uint32_t timeout = 2000; #else uint32_t timeout = 20000; #endif if(tpmCmd == NULL) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } // Build command UINT16_TO_BYTEARRAY(TPM_ST_NO_SESSIONS, tpmCmd, cursor); cursor += sizeof(uint16_t) + sizeof(cursor); UINT32_TO_BYTEARRAY(TPM_CC_StirRandom, tpmCmd, cursor); cursor += sizeof(TPM_CC_GetRandom); UINT16_TO_BYTEARRAY(inDataLen, tpmCmd, cursor); cursor += sizeof(inDataLen); memcpy(&tpmCmd[cursor], inData, inDataLen); cursor += inDataLen; UINT32_TO_BYTEARRAY(cursor, tpmCmd, sizeof(uint16_t)); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_StirRandom(%d)\n\r", inDataLen); #endif if((rspLen = Execute(locality, tpmCmd, cursor, tpmCmd, tpmMax, timeout)) == 0) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } cursor = 0; if((rspResponseCode = ParseResponseHeader(tpmCmd, rspLen, &rspTag, &rspSize, &cursor)) != TPM_RC_SUCCESS) { goto Cleanup; } if(rspSize != 0x0000000a) { rspResponseCode = TPM_RC_FAILURE; goto Cleanup; } Cleanup: #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.TPM2_StirRandom.ResponseCode = 0x%08x\n\r", rspResponseCode); #endif if(tpmCmd != NULL) { delete[] tpmCmd; tpmCmd = NULL; } return rspResponseCode; } void TISTPM20::TimeoutTrigger( void ) { m_TimeoutTriggered = true; } uint32_t TISTPM20::ExecuteTIS( uint8_t* pbCmd, uint32_t cbCmd, uint8_t* pbRsp, uint32_t cbRsp ) { uint32_t result = 0; uint8_t tisStatus = 0xFF; uint32_t index = 0; uint32_t rspSize = 0; uint16_t tisBurstCount = 0; // Lock the requested locality #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.RequestLocality\r\n"); #endif if(!RequestLocality()) { goto Cleanup; } // Check the status before writing the command if(!GetStatus(&tisStatus)) { goto Cleanup; } // Abort anything that may still be stuck in the TPM if((tisStatus & TIS_STS_COMMAND_READY) == 0) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.GetReady\r\n"); #endif uint8_t mask = TIS_STS_COMMAND_READY; if(!Abort() || !WaitForStatus(mask)) { goto Cleanup; } } #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.ReadyForCommand\r\n"); #endif // Send the command to the TPM do { uint16_t cbIteration = 0; // Get the maximum bytes we can send for this iteration if((!GetBurstCount(&tisBurstCount)) || (tisBurstCount == 0)) { goto Cleanup; } #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.GetBurstCount = %d\r\n", tisBurstCount); #endif // Assemble the buffer for transmission cbIteration = min((cbCmd - index), min(tisBurstCount, TIS_MAX_HW_FRAME_SIZE)); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.SendingBurst = %d\r\n", cbIteration); #endif if(!SPIFullDuplex(false, TIS_DATA_FIFO, &pbCmd[index], cbIteration)) { goto Cleanup; } // Update the counts index += cbIteration; #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Remaining = %d\r\n", (cbCmd - index)); #endif } while((cbCmd - index) > 0); // Wait for the TPM to get ready and kick the command off #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.StatusValid\r\n"); #endif if(!WaitForStatus(TIS_STS_VALID) || !Go()) { goto Cleanup; } #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Go\r\n"); #endif // Wait for the TPM to finish the command execution do { wait_us(1000); tisStatus = 0xFF; if(!GetStatus(&tisStatus) || ((tisStatus & TIS_STS_VALID) == 0)) { goto Cleanup; } } while(((tisStatus & TIS_STS_DATA_AVAIL) == 0) && (!m_TimeoutTriggered)); if(m_TimeoutTriggered) { goto Cleanup; } // Get the response header from the TPM index = 0; #ifdef TPM_TIS_DEBUG_OUTPUT printf("Tis.ReadResponseHeader\r\n"); #endif if(!GetBurstCount(&tisBurstCount) || (tisBurstCount < (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t))) || !SPIFullDuplex(true, TIS_DATA_FIFO, &pbRsp[index], (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t)))) { goto Cleanup; } index += (sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t)); rspSize = BYTEARRAY_TO_UINT32(pbRsp, sizeof(uint16_t)); #ifdef TPM_TIS_DEBUG_OUTPUT printf("Tis.ResponseSize = %d\r\n", rspSize); #endif if(rspSize > index) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("Tis.ReadResponse\r\n"); #endif do { uint16_t cbIteration = 0; // Check to make sure the TPM has still data for us if(!GetStatus(&tisStatus) || ((tisStatus & TIS_STS_DATA_AVAIL) == 0)) { goto Cleanup; } // Get the number of available bytes for reading in this iteration if(!GetBurstCount(&tisBurstCount)) { goto Cleanup; } #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.GetBurstCount = %d\r\n", tisBurstCount); #endif cbIteration = min((rspSize - index), min((cbRsp - index), min(tisBurstCount, TIS_MAX_HW_FRAME_SIZE))); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.ReceivingBurst = %d\r\n", cbIteration); #endif // Read the data for this iteration if(!SPIFullDuplex(true, TIS_DATA_FIFO, &pbRsp[index], cbIteration)) { goto Cleanup; } index += cbIteration; #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Remaining = %d\r\n", (min(rspSize, cbRsp) - index)); #endif } while(index < min(rspSize, cbRsp)); } result = index; Cleanup: // Always leave the TPM in a clean state if somethign fishy happened if(result == 0) { #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.Abort\r\n"); #endif Abort(); } // Release the locality again #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS.ReleaseLocality\r\n"); #endif ReleaseLocality(); return result; } bool TISTPM20::SPIFullDuplex( bool readCycle, uint8_t tisRegister, uint8_t* pbBuffer, uint16_t cbBuffer ) { bool result = false; uint8_t dataByteIn; uint8_t dataByteOut; // Lock the bus for this operation *m_SPICSTpmDev = 0; // Send the TIS header uint32_t tisHdr = TIS_HEADER(m_Locality, readCycle, tisRegister, cbBuffer); #ifdef TPM_TIS_DEBUG_OUTPUT printf("TIS(LC:%d,RG:%02x,SZ:%02x,%s):", m_Locality, tisRegister, cbBuffer, (readCycle) ? "RD" : "WR"); #endif for(uint8_t n = 0; n < sizeof(tisHdr); n++) { dataByteOut = tisHdr >> (8 * (3 - n)); dataByteIn = m_SPITpmDev->write(dataByteOut); } // The last read bit is the wait state indicator if((dataByteIn & 0x01) == 0) { do { #ifdef TPM_TIS_DEBUG_OUTPUT printf("."); #endif // Do we still have to wait? if((dataByteIn = m_SPITpmDev->write(0xFF)) != 0x01) { wait_us(10); } } while((dataByteIn != 0x01) && (!m_TimeoutTriggered)); // Check if we timed out if((dataByteIn != 0x01) && (m_TimeoutTriggered)) { goto Cleanup; } } // Do the remaining bytes now for(uint8_t n = 0; n < cbBuffer; n++) { dataByteOut = (readCycle) ? 0xFF : pbBuffer[n]; dataByteIn = m_SPITpmDev->write(dataByteOut); if(readCycle) pbBuffer[n] = dataByteIn; #ifdef TPM_TIS_DEBUG_OUTPUT printf("0x%02x ", (readCycle) ? dataByteIn : dataByteOut); #endif } result = true; #ifdef TPM_TIS_DEBUG_OUTPUT printf("\r\n"); #endif Cleanup: // Make sure to release the bus before we leave *m_SPICSTpmDev = 1; return result; } bool TISTPM20::RequestLocality() { do { // Do we have access already? uint8_t dataByte = 0xFF; if(!SPIFullDuplex(true, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) { return false; } if((dataByte & TIS_ACCESS_ACTIVE_LOCALITY) && (dataByte & TIS_ACCESS_VALID)) { break; } // Request access dataByte = TIS_ACCESS_REQUEST_USE; if(!SPIFullDuplex(false, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) { return false; } if(m_TimeoutTriggered) { // We give up eventually return false; } wait_us(10); } while(1); return true; } bool TISTPM20::ReleaseLocality() { do { // Do we even have access? uint8_t dataByte = 0xFF; if(!SPIFullDuplex(true, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) { return false; } if(!(dataByte & TIS_ACCESS_ACTIVE_LOCALITY) && (dataByte & TIS_ACCESS_VALID)) { break; } // Release access dataByte = TIS_ACCESS_ACTIVE_LOCALITY; if(!SPIFullDuplex(false, TIS_ACCESS_REGISTER, &dataByte, sizeof(dataByte))) { return false; } if(m_TimeoutTriggered) { // We give up eventually return false; } wait_us(10); } while(1); return true; } bool TISTPM20::GetBurstCount( uint16_t* pBurstCount ) { uint8_t dataBytes[sizeof(*pBurstCount)] = {0}; do { if(!SPIFullDuplex(true, TIS_BURSTCOUNT_REGISTER, dataBytes, sizeof(dataBytes))) { return false; } *pBurstCount = (uint16_t)dataBytes[0] | (uint16_t)(dataBytes[1] << 8); // Burst count can be 0 if we are too fast if(*pBurstCount != 0) { break; } if(m_TimeoutTriggered) { // We give up eventually return false; } wait_us(10); } while(1); return true; } bool TISTPM20::GetStatus( uint8_t* pStatus ) { bool result = SPIFullDuplex(true, TIS_STATUS_REGISTER, pStatus, sizeof(*pStatus)); return result; } bool TISTPM20::WaitForStatus( uint8_t statusMask ) { bool result = false; uint8_t tisStatus = 0xFF; do { if(!GetStatus(&tisStatus)) { goto Cleanup; } if((tisStatus & statusMask) == statusMask) { result = true; break; } wait_us(10); } while(!m_TimeoutTriggered); Cleanup: return result; } bool TISTPM20::Abort() { uint8_t dataByte = TIS_STS_COMMAND_READY; return SPIFullDuplex(false, TIS_STATUS_REGISTER, &dataByte, sizeof(dataByte)); } bool TISTPM20::Go() { uint8_t dataByte = TIS_STS_GO; return SPIFullDuplex(false, TIS_STATUS_REGISTER, &dataByte, sizeof(dataByte)); }