blob: f6254515312d5bab232ec43dd3c9741a63a6f78a [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <platform/internal/CHIPDeviceLayerInternal.h>
#if CHIP_DEVICE_CONFIG_ENABLE_NFC
#include <platform/NFCManager.h>
#include <lib/support/CHIPPlatformMemory.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>
#include <lib/support/logging/CHIPLogging.h>
#include "FunctionLib.h"
namespace chip {
namespace DeviceLayer {
NFCManagerImpl NFCManagerImpl::sInstance;
CHIP_ERROR NFCManagerImpl::_Init()
{
return CHIP_NO_ERROR;
}
CHIP_ERROR NFCManagerImpl::_StartTagEmulation(const char * payload, size_t payloadLength)
{
ntagDriverHandleInstance = NTAG_InitDevice((NTAG_ID_T) 0, I2C2);
assert(ntagDriverHandleInstance);
CLOCK_EnableClock(kCLOCK_I2c0);
CLOCK_AttachClk(kOSC32M_to_I2C_CLK);
HAL_I2C_InitDevice(HAL_I2C_INIT_DEFAULT, kCLOCK_Fro32M, I2C2);
/* populate the NDEF structure */
sInstance.ndefUriRecord.recordType = NDEF_RECORD_TYPE;
sInstance.ndefUriRecord.recordTypeLen = NDEF_RECORD_TYPE_LEN;
sInstance.ndefUriRecord.payloadLen = payloadLength + sizeof(sInstance.ndefUriRecord.uriIdCode);
sInstance.ndefUriRecord.recordName = NFC_NDEF_RECORD_NAME;
sInstance.ndefUriRecord.uriIdCode = NDEF_URI_ID_CODE;
if (payloadLength > NDEF_URI_ID_MAX_LENGTH)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
else
{
memcpy(sInstance.ndefUriRecord.uriIdData, payload, payloadLength);
}
/* write the NDEF structure to the NTAG EEPROM */
if (AppNtagWrite(payload) != E_APP_NTAG_NO_ERROR)
{
return CHIP_ERROR_INTERNAL;
}
else
{
sInstance.mIsStarted = TRUE;
}
return CHIP_NO_ERROR;
}
CHIP_ERROR NFCManagerImpl::_StopTagEmulation()
{
uint8_t ndefUriRecordSize = AppNdefUriRecordGetSize(sInstance.ndefUriRecord);
memset(&sInstance.ndefUriRecord, 0, ndefUriRecordSize);
if (AppNtagEepromUnlockThenWrite(ndefUriRecordSize) != E_APP_NTAG_NO_ERROR)
{
return CHIP_ERROR_INTERNAL;
}
/* Stop I2C */
HAL_I2C_CloseDevice(I2C2);
NTAG_CloseDevice(sInstance.ntagDriverHandleInstance);
sInstance.ntagDriverHandleInstance = NULL;
sInstance.mIsStarted = FALSE;
return CHIP_NO_ERROR;
}
bool NFCManagerImpl::IsNtagConfigured(eAppNtagError * pNtagError, const char * payload)
{
uint32_t addrToRead = NTAG_I2C_BLOCK_SIZE;
uint8_t eepromDataBuf[NDEF_URI_ID_MAX_LENGTH + TERMINATOR_TLV_LEN] = { 0 };
uint16_t ndefUriRecordSize = AppNdefUriRecordGetSize(sInstance.ndefUriRecord);
uint8_t ndefUriLen = sInstance.ndefUriRecord.payloadLen - sizeof(sInstance.ndefUriRecord.uriIdCode);
if (NTAG_ReadBytes(sInstance.ntagDriverHandleInstance, addrToRead, eepromDataBuf, 2))
{
*pNtagError = E_APP_NTAG_READ_ERROR;
return FALSE;
}
/* see also http://apps4android.org/nfc-specifications/NFCForum-TS-Type-2-Tag_1.1.pdf, chapter 2.3 */
if (eepromDataBuf[0] != 0x03 || eepromDataBuf[1] != ndefUriRecordSize)
{
return FALSE;
}
/* read the NdefUriRecord from the EEPROM */
addrToRead += 2;
if (NTAG_ReadBytes(sInstance.ntagDriverHandleInstance, addrToRead, eepromDataBuf, ndefUriRecordSize))
{
*pNtagError = E_APP_NTAG_READ_ERROR;
return FALSE;
}
/* verify if the ndefUriRecord is the same as the one flashed in the the EEPROM:
* If it is, then the NTAG is already configured.
*/
return (payload && !memcmp(sInstance.ndefUriRecord.uriIdData, payload, ndefUriLen) &&
!memcmp((uint8_t *) &(sInstance.ndefUriRecord), eepromDataBuf, ndefUriRecordSize));
}
NFCManagerImpl::eAppNtagError NFCManagerImpl::AppNtagWrite(const char * payload)
{
eAppNtagError ntagErr = E_APP_NTAG_NO_ERROR;
uint8_t byte0 = 0;
uint8_t i = 0;
bool_t i2cAddrFound = FALSE;
bool_t isConfigured = FALSE;
do
{
/* Try to access the device at default I2C address */
if (NTAG_ReadBytes(sInstance.ntagDriverHandleInstance, 0, &byte0, sizeof(byte0)))
{
/* Try now with the 0x02 I2C address */
NTAG_SetNtagI2cAddress(sInstance.ntagDriverHandleInstance, 0x2);
if (!NTAG_ReadBytes(sInstance.ntagDriverHandleInstance, 0, &byte0, sizeof(byte0)))
{
i2cAddrFound = TRUE;
}
else
{
/* Loop to try to find a valid i2c address */
for (i = 0; i < 0xFF; i++)
{
if (i == 2 || i == 0x55) /* Skip default and 0x02 I2C address */
{
continue;
}
NTAG_SetNtagI2cAddress(sInstance.ntagDriverHandleInstance, i);
if (!NTAG_ReadBytes(sInstance.ntagDriverHandleInstance, 0, &byte0, sizeof(byte0)))
{
i2cAddrFound = TRUE;
break;
}
}
}
if (!i2cAddrFound)
{
ntagErr = E_APP_NTAG_READ_ERROR;
break;
}
}
isConfigured = IsNtagConfigured(&ntagErr, payload);
if (ntagErr != E_APP_NTAG_NO_ERROR)
{
break;
}
if (!isConfigured)
{
ntagErr = AppNtagEepromUnlockThenWrite(0);
}
} while (0);
return ntagErr;
}
bool NFCManagerImpl::AppNtagEepromWrite(uint8_t originalSize)
{
bool wasWritten = FALSE;
uint32_t ndefSize = AppNdefUriRecordGetSize(sInstance.ndefUriRecord);
uint32_t addrToWrite = NTAG_I2C_BLOCK_SIZE;
uint8_t buf[4];
uint8_t terminatorTLV = 0xFE;
do
{
if (!sInstance.ndefUriRecord.payloadLen)
{
if (NTAG_WriteBytes(sInstance.ntagDriverHandleInstance, addrToWrite, (uint8_t *) &(sInstance.ndefUriRecord),
originalSize + sizeof(terminatorTLV)))
{
break;
}
}
else
{
buf[0] = 0x3;
buf[1] = ndefSize;
if (NTAG_WriteBytes(sInstance.ntagDriverHandleInstance, addrToWrite, buf, 2))
{
break;
}
addrToWrite += 2;
if (NTAG_WriteBytes(sInstance.ntagDriverHandleInstance, addrToWrite, (uint8_t *) &(sInstance.ndefUriRecord), ndefSize))
{
break;
}
addrToWrite += ndefSize;
if (NTAG_WriteBytes(sInstance.ntagDriverHandleInstance, addrToWrite, &terminatorTLV, 1))
{
break;
}
}
wasWritten = TRUE;
} while (0);
return wasWritten;
}
NFCManagerImpl::eAppNtagError NFCManagerImpl::AppNtagEepromUnlockThenWrite(uint8_t originalSize)
{
eAppNtagError ntagErr = E_APP_NTAG_NO_ERROR;
do
{
/* Unlock write access */
ntagErr = AppNtagUnlockWriteAccess();
if (ntagErr != E_APP_NTAG_NO_ERROR)
{
break;
}
/* Write the NDEF URI */
if (!AppNtagEepromWrite(originalSize))
{
ntagErr = E_APP_NTAG_WRITE_ERROR;
}
/* Lock write access */
AppNtagLockWriteAccess();
} while (0);
return ntagErr;
}
uint8_t NFCManagerImpl::AppNdefUriRecordGetSize(NdefUriRecord_t ndefUriRecord)
{
return sizeof(sInstance.ndefUriRecord.recordType) + sizeof(sInstance.ndefUriRecord.recordTypeLen) +
sizeof(sInstance.ndefUriRecord.payloadLen) + sInstance.ndefUriRecord.payloadLen +
sizeof(sInstance.ndefUriRecord.recordName);
}
NFCManagerImpl::eAppNtagError NFCManagerImpl::AppNtagLockWriteAccess(void)
{
eAppNtagError ntagErr = E_APP_NTAG_NO_ERROR;
uint8_t bytes[NTAG_I2C_BLOCK_SIZE];
FLib_MemSet(bytes, 0x0, sizeof(bytes));
do
{
/* Try to read the block 0 */
if (NTAG_ReadBytes(sInstance.ntagDriverHandleInstance, 0, bytes, sizeof(bytes)))
{
ntagErr = E_APP_NTAG_READ_ERROR;
break;
}
/* Set the Capability Container (CC) */
bytes[3] = 0xE1; /* Indicates that NDEF data is present inside the tag */
bytes[4] = 0x10; /* Indicates to support the version 1.0 */
bytes[5] = 0xE9; /* Indicates 1864 bytes of memory size assigned to the data area */
bytes[6] = 0x0F; /* Indicates read only access granted */
if (NTAG_WriteBytes(sInstance.ntagDriverHandleInstance, 0, bytes, sizeof(bytes)))
{
ntagErr = E_APP_NTAG_WRITE_ERROR;
}
} while (0);
return ntagErr;
}
NFCManagerImpl::eAppNtagError NFCManagerImpl::AppNtagUnlockWriteAccess(void)
{
eAppNtagError ntagErr = E_APP_NTAG_NO_ERROR;
uint8_t bytes[NTAG_I2C_BLOCK_SIZE];
FLib_MemSet(bytes, 0x0, sizeof(bytes));
do
{
/* Try to read the block 0 */
if (NTAG_ReadBytes(sInstance.ntagDriverHandleInstance, 0, bytes, sizeof(bytes)))
{
ntagErr = E_APP_NTAG_READ_ERROR;
break;
}
/* Set the Capability Container (CC) */
bytes[12] = 0xE1; /* Indicates that NDEF data is present inside the tag */
bytes[13] = 0x10; /* Indicates to support the version 1.0 */
bytes[14] = 0xE9; /* Indicates 1864 bytes of memory size assigned to the data area */
bytes[15] = 0x00; /* Indicates read and write access granted without any security */
if (NTAG_WriteBytes(sInstance.ntagDriverHandleInstance, 0, bytes, sizeof(bytes)))
{
ntagErr = E_APP_NTAG_WRITE_ERROR;
}
} while (0);
return ntagErr;
}
} // namespace DeviceLayer
} // namespace chip
#endif