/****************************************************************************** * * Copyright (C) 2018 ST Microelectronics S.A. * * 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. * * ******************************************************************************/ #define LOG_TAG "NfcHalFd" #include "hal_fd.h" #include #include #include #include #include #include "android_logmsg.h" #include "halcore.h" /* Initialize fw info structure pointer used to access fw info structure */ FWInfo *mFWInfo = NULL; FILE *mFwFileBin; FILE *mCustomFileBin; fpos_t mPos; fpos_t mPosInit; uint8_t mBinData[260]; bool mRetry = true; bool mCustomParamFailed = false; bool mCustomParamDone = false; bool mUwbConfigDone = false; bool mUwbConfigNeeded = false; bool mGetCustomerField = false; uint8_t *pCmd; int mFWRecovCount = 0; const char *FwType = "generic"; char mApduAuthent[24]; static const uint8_t propNfcModeSetCmdOn[] = {0x2f, 0x02, 0x02, 0x02, 0x01}; static const uint8_t coreInitCmd[] = {0x20, 0x01, 0x02, 0x00, 0x00}; static const uint8_t NciPropNfcFwUpdate[] = {0x2F, 0x02, 0x05, 0x06, 0x00, 0x01, 0x02, 0x03}; static uint8_t ApduEraseNfcKeepAppliAndNdef[] = { 0x2F, 0x04, 0x16, 0x80, 0x0C, 0x00, 0x00, 0x11, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x23, 0xDF, 0xFF, 0x00, 0x23, 0xE0, 0x00, 0x00, 0x23, 0xFF, 0xFF}; static const uint8_t ApduExitLoadMode[] = {0x2F, 0x04, 0x06, 0x80, 0xA0, 0x00, 0x00, 0x01, 0x01}; // APDUs for ST54L const int UK_NB = 2; const int UK_SIZE = 12; static uint8_t UserKeys[UK_NB][UK_SIZE] = { {0x00, 0x00, 0xFD, 0x0F, 0x87, 0x7D, 0x31, 0xE3, 0xCF, 0x0C, 0xD3, 0x68}, // Test {0x00, 0x00, 0xFD, 0x00, 0x87, 0x7D, 0x31, 0xE3, 0xCF, 0x0C, 0xD3, 0x68}}; // Production static uint8_t ApduPutKeyUser1[UK_NB][50] = { {0x2F, 0x04, 0x2F, 0x84, 0x11, 0x00, 0x00, 0x2A, 0x01, 0xB3, 0x56, 0x01, // Test 0x00, 0x00, 0xFD, 0x20, 0x20, 0xEC, 0x7D, 0x47, 0xAE, 0xF3, 0x23, 0x2E, 0x00, 0x00, 0x34, 0x78, 0x82, 0xEC, 0x6b, 0xA5, 0x83, 0xAF, 0x68, 0xC7, 0x1F, 0x9F, 0xB0, 0xD7, 0x9D, 0x33, 0xB0, 0xDA, 0xC6, 0x2C, 0xAB, 0x8A, 0x10, 0xEA}, {0x2F, 0x04, 0x2F, 0x84, 0x11, 0x00, 0x00, 0x2A, 0x01, 0xB3, 0x56, 0x01, // Production 0x00, 0x00, 0xFD, 0x20, 0x20, 0xEC, 0x7D, 0x47, 0xAE, 0xF3, 0x23, 0x2E, 0x00, 0x00, 0xE1, 0xA2, 0x78, 0xA9, 0x71, 0x14, 0x46, 0x6D, 0x73, 0x86, 0x4C, 0x3B, 0x0F, 0x51, 0x71, 0x8E, 0xE4, 0x1D, 0x54, 0x02, 0x3A, 0xE3, 0x18, 0x55}}; static uint8_t ApduEraseUpgradeStart[] = { 0x2F, 0x04, 0x12, 0x84, 0x35, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB2, 0x51, 0x42, 0xB0, 0x27, 0x92, 0xAA, 0xAB}; static uint8_t ApduEraseNfcArea[] = {0x2F, 0x04, 0x17, 0x84, 0x36, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x04, 0x5E, 0x00, 0x4D, 0x83, 0xE1, 0x59, 0x62, 0xDC, 0x14, 0x64}; static uint8_t ApduEraseUpgradeStop[] = {0x2F, 0x04, 0x0F, 0x80, 0x33, 0x00, 0x00, 0x0A, 0x00, 0x02, 0x97, 0x22, 0xC2, 0x5A, 0x2D, 0xA4, 0x09, 0x1A}; static uint8_t ApduSetVariousConfig[] = { 0x2F, 0x04, 0x11, 0x84, 0x74, 0x00, 0x00, 0x0C, 0x06, 0x02, 0x80, 0x80, 0xD4, 0x29, 0xEC, 0x9A, 0xFB, 0xC8, 0x4B, 0x2A}; static uint8_t ApduSwitchToUser[] = {0x2F, 0x04, 0x0F, 0x84, 0xA0, 0x00, 0x00, 0x0A, 0x20, 0x01, 0xFC, 0x63, 0x2A, 0xE1, 0xFD, 0xAA, 0xD1, 0x9B}; static const uint8_t nciHeaderPropSetUwbConfig[9] = { 0x2F, 0x02, 0x00, 0x04, 0x00, 0x16, 0x01, 0x00, 0x00}; static const uint8_t nciGetPropConfig[8] = {0x2F, 0x02, 0x05, 0x03, 0x00, 0x06, 0x01, 0x00}; static const uint8_t nciSetPropConfig[9] = {0x2F, 0x02, 0x00, 0x04, 0x00, 0x06, 0x01, 0x00, 0x00}; static uint8_t nciPropSetUwbConfig[128]; static uint8_t nciPropSetConfig_CustomField[64]; hal_fd_state_e mHalFDState = HAL_FD_STATE_AUTHENTICATE; hal_fd_st54l_state_e mHalFD54LState = HAL_FD_ST54L_STATE_PUY_KEYUSER; void SendExitLoadMode(HALHANDLE mmHalHandle); void SendSwitchToUserMode(HALHANDLE mmHalHandle); extern void hal_wrapper_update_complete(); typedef size_t (*STLoadUwbParams)(void *out_buff, size_t buf_size); /*********************************************************************** * Determine UserKey * * @return mode: -1 : not supported * 0 : Test sample * 1 : Product sample ***********************************************************************/ static int GetProdType(uint8_t* UserKey) { int i, j; int status; for (i = 0; i < UK_NB; i++) { status = 1; for (j = 0; j < UK_SIZE; j++) { if (UserKey[j] != UserKeys[i][j]) { STLOG_HAL_D( " No match between UserKey[%d]=0x%02X and \ UserKeys[%d][%d]=0x%02X", j, UserKey[j], i, j, UserKeys[i][j]); status = 0; break; } } if (1 == status) { return i; } } return (-1); } /** * Send a HW reset and decode NCI_CORE_RESET_NTF information * @param pHwVersion is used to return HW version, part of NCI_CORE_RESET_NTF * @param pFwVersion is used to return FW version, part of NCI_CORE_RESET_NTF * @param pLoaderVersion is used to return Loader version, part of * NCI_CORE_RESET_NTF * @param pCustVersion si used to return Customer field value, part of * NCI_CORE_RESET_NTF when in router mode * * @return mode: FT_CLF_MODE_ROUTER if router mode * FT_CLF_MODE_LOADER if loader mode * FT_CLF_MODE_ERROR if Error */ int hal_fd_init() { uint8_t result = 0; char FwPath[256]; char ConfPath[256]; char fwBinName[256]; char fwConfName[256]; int ret; STLOG_HAL_D(" %s - enter", __func__); if (!GetStrValue(NAME_STNFC_FW_PATH_STORAGE, (char *)FwPath, sizeof(FwPath))) { STLOG_HAL_D( "%s - FW path not found in conf. use default location /vendor/firmware " "\n", __func__); strcpy(FwPath, "/vendor/firmware"); } if (!GetStrValue(NAME_STNFC_FW_BIN_NAME, (char *)fwBinName, sizeof(fwBinName))) { STLOG_HAL_D( "%s - FW binary file name not found in conf. use default name " "/st21nfc_fw.bin \n", __func__); strcpy(fwBinName, "/st21nfc_fw.bin"); } if (!GetStrValue(NAME_STNFC_FW_CONF_NAME, (char *)fwConfName, sizeof(fwConfName))) { STLOG_HAL_D( "%s - FW config file name not found in conf. use default name " "/st21nfc_conf.bin \n", __func__); strcpy(fwConfName, "/st21nfc_conf.bin"); } // Getting information about FW patch, if any strcpy(ConfPath, FwPath); strncat(FwPath, fwBinName, sizeof(FwPath) - strlen(FwPath) - 1); strncat(ConfPath, fwConfName, sizeof(ConfPath) - strlen(ConfPath) - 1); STLOG_HAL_D("%s - FW update binary file = %s", __func__, FwPath); STLOG_HAL_D("%s - FW config binary file = %s", __func__, ConfPath); // Initializing structure holding FW patch details mFWInfo = (FWInfo *)malloc(sizeof(FWInfo)); if (mFWInfo == NULL) { result = 0; } memset(mFWInfo, 0, sizeof(FWInfo)); mFwFileBin = NULL; mCustomFileBin = NULL; // Check if FW patch binary file is present // If not, get recovery FW patch file if ((mFwFileBin = fopen((char *)FwPath, "r")) == NULL) { STLOG_HAL_D("%s - %s not detected", __func__, fwBinName); } else { STLOG_HAL_D("%s - %s file detected\n", __func__, fwBinName); result |= FW_PATCH_AVAILABLE; ret = fread(mBinData, sizeof(uint8_t), 4, mFwFileBin); if (ret != 4) { STLOG_HAL_E("%s did not read 4 bytes \n", __func__); } mFWInfo->fileFwVersion = mBinData[0] << 24 | mBinData[1] << 16 | mBinData[2] << 8 | mBinData[3]; fgetpos(mFwFileBin, &mPosInit); ret = fread(mBinData, sizeof(uint8_t), 5, mFwFileBin); if (ret != 5) { STLOG_HAL_E("%s did not read 5 bytes \n", __func__); } fsetpos(mFwFileBin, &mPosInit); // reset pos in stream if (mBinData[4] == 0x35) { mFWInfo->fileHwVersion = HW_ST54L; } else { ret = fread(mApduAuthent, sizeof(uint8_t), 24, mFwFileBin); if (ret != 24) { STLOG_HAL_E("%s Wrong read nb \n", __func__); } // We use the last byte of the auth command to discriminate at the moment. // it can be extended in case of conflict later. switch (mApduAuthent[23]) { case 0x43: case 0xC7: mFWInfo->fileHwVersion = HW_NFCD; break; case 0xE9: mFWInfo->fileHwVersion = HW_ST54J; break; } } if (mFWInfo->fileHwVersion == 0) { STLOG_HAL_E("%s --> %s integrates unknown patch NFC FW -- rejected\n", __func__, FwPath); fclose(mFwFileBin); mFwFileBin = NULL; } else { fgetpos(mFwFileBin, &mPosInit); STLOG_HAL_D("%s --> %s integrates patch NFC FW version 0x%08X (r:%d)\n", __func__, FwPath, mFWInfo->fileFwVersion, mFWInfo->fileHwVersion); } } if ((mCustomFileBin = fopen((char *)ConfPath, "r")) == NULL) { STLOG_HAL_D("%s - st21nfc custom configuration not detected\n", __func__); } else { STLOG_HAL_D("%s - %s file detected\n", __func__, ConfPath); fread(mBinData, sizeof(uint8_t), 2, mCustomFileBin); mFWInfo->fileCustVersion = mBinData[0] << 8 | mBinData[1]; STLOG_HAL_D("%s --> st21nfc_custom configuration version 0x%04X \n", __func__, mFWInfo->fileCustVersion); result |= FW_CUSTOM_PARAM_AVAILABLE; } if (ft_CheckUWBConf()) { result |= FW_UWB_PARAM_AVAILABLE; } return result; } void hal_fd_close() { STLOG_HAL_D(" %s -enter", __func__); mCustomParamFailed = false; if (mFWInfo != NULL) { free(mFWInfo); mFWInfo = NULL; } if (mFwFileBin != NULL) { fclose(mFwFileBin); mFwFileBin = NULL; } if (mCustomFileBin != NULL) { fclose(mCustomFileBin); mCustomFileBin = NULL; } } FWInfo* hal_fd_getFwInfo() { STLOG_HAL_D(" %s -enter", __func__); return mFWInfo; } /** * Send a HW reset and decode NCI_CORE_RESET_NTF information * @param pHwVersion is used to return HW version, part of NCI_CORE_RESET_NTF * @param pFwVersion is used to return FW version, part of NCI_CORE_RESET_NTF * @param pLoaderVersion is used to return Loader version, part of * NCI_CORE_RESET_NTF * @param pCustVersion si used to return Customer field value, part of * NCI_CORE_RESET_NTF when in router mode * * @return mode: FT_CLF_MODE_ROUTER if router mode * FT_CLF_MODE_LOADER if loader mode * FT_CLF_MODE_ERROR if Error */ uint8_t ft_cmd_HwReset(uint8_t *pdata, uint8_t *clf_mode) { uint8_t result = 0; STLOG_HAL_D(" %s - execution", __func__); if ((pdata[1] == 0x0) && (pdata[3] == 0x1)) { STLOG_HAL_D("-> Router Mode NCI_CORE_RESET_NTF received after HW Reset"); /* retrieve HW Version from NCI_CORE_RESET_NTF */ mFWInfo->chipHwVersion = pdata[8]; STLOG_HAL_D(" HwVersion = 0x%02X", mFWInfo->chipHwVersion); /* retrieve FW Version from NCI_CORE_RESET_NTF */ mFWInfo->chipFwVersion = (pdata[10] << 24) | (pdata[11] << 16) | (pdata[12] << 8) | pdata[13]; STLOG_HAL_D(" FwVersion = 0x%08X", mFWInfo->chipFwVersion); /* retrieve Loader Version from NCI_CORE_RESET_NTF */ mFWInfo->chipLoaderVersion = (pdata[14] << 16) | (pdata[15] << 8) | pdata[16]; STLOG_HAL_D(" LoaderVersion = 0x%06X", mFWInfo->chipLoaderVersion); /* retrieve Customer Version from NCI_CORE_RESET_NTF */ mFWInfo->chipCustVersion = (pdata[31] << 8) | pdata[32]; STLOG_HAL_D(" CustomerVersion = 0x%04X", mFWInfo->chipCustVersion); /* retrieve Uwb param Version from NCI_CORE_RESET_NTF */ mFWInfo->chipUwbVersion = (pdata[29] << 8) | pdata[30]; STLOG_HAL_D(" uwbVersion = 0x%04X", mFWInfo->chipUwbVersion); *clf_mode = FT_CLF_MODE_ROUTER; } else if ((pdata[2] == 0x39) && (pdata[3] == 0xA1)) { STLOG_HAL_D("-> Loader Mode NCI_CORE_RESET_NTF received after HW Reset"); /* deduce HW Version from Factory Loader version */ if (pdata[16] == 0x01) { mFWInfo->chipHwVersion = 0x05; // ST54J } else if (pdata[16] == 0x02) { mFWInfo->chipHwVersion = 0x04; // ST21NFCD } else { mFWInfo->chipHwVersion = 0x03; // ST21NFCD } STLOG_HAL_D(" HwVersion = 0x%02X", mFWInfo->chipHwVersion); /* Identify the Active loader. Normally only one should be detected*/ if (pdata[11] == 0xA0) { mFWInfo->chipLoaderVersion = (pdata[8] << 16) | (pdata[9] << 8) | pdata[10]; STLOG_HAL_D(" - Most recent loader activated, revision 0x%06X", mFWInfo->chipLoaderVersion); } if (pdata[15] == 0xA0) { mFWInfo->chipLoaderVersion = (pdata[12] << 16) | (pdata[13] << 8) | pdata[14]; STLOG_HAL_D(" - Least recent loader activated, revision 0x%06X", mFWInfo->chipLoaderVersion); } if (pdata[19] == 0xA0) { mFWInfo->chipLoaderVersion = (pdata[16] << 16) | (pdata[17] << 8) | pdata[18]; STLOG_HAL_D(" - Factory loader activated, revision 0x%06X", mFWInfo->chipLoaderVersion); } *clf_mode = FT_CLF_MODE_LOADER; } else if ((pdata[2] == 0x41) && (pdata[3] == 0xA2)) { STLOG_HAL_D("-> Loader V3 Mode NCI_CORE_RESET_NTF received after HW Reset"); mFWInfo->chipHwVersion = HW_ST54L; STLOG_HAL_D(" HwVersion = 0x%02X", mFWInfo->chipHwVersion); mFWInfo->chipFwVersion = 0; // make sure FW will be updated. /* retrieve Production type* from NCI_CORE_RESET_NTF */ mFWInfo->chipProdType = GetProdType(&pdata[44]); *clf_mode = FT_CLF_MODE_LOADER; } else { STLOG_HAL_E( "%s --> ERROR: wrong NCI_CORE_RESET_NTF received after HW Reset", __func__); *clf_mode = FT_CLF_MODE_ERROR; } if ((mFWInfo->chipHwVersion == HW_ST54J) || (mFWInfo->chipHwVersion == HW_ST54L)) { if ((mFwFileBin != NULL) && (mFWInfo->fileFwVersion != mFWInfo->chipFwVersion)) { STLOG_HAL_D("---> Firmware update needed\n"); result |= FW_UPDATE_NEEDED; } else { STLOG_HAL_D("---> No Firmware update needed\n"); } if ((mFWInfo->fileCustVersion != 0) && (mFWInfo->chipCustVersion != mFWInfo->fileCustVersion)) { STLOG_HAL_D( "%s - Need to apply new st21nfc custom configuration settings\n", __func__); if (!mCustomParamFailed) result |= CONF_UPDATE_NEEDED; } else { STLOG_HAL_D("%s - No need to apply custom configuration settings\n", __func__); } } if ((mFWInfo->fileUwbVersion != 0) && (mFWInfo->fileUwbVersion != mFWInfo->chipUwbVersion)) { result |= UWB_CONF_UPDATE_NEEDED; STLOG_HAL_D("%s - Need to apply new uwb param configuration \n", __func__); mUwbConfigNeeded = true; } return result; } /* ft_cmd_HwReset */ void ExitHibernateHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t *p_data) { STLOG_HAL_D("%s - Enter", __func__); if (data_len < 3) { STLOG_HAL_E("%s - Error, too short data (%d)", __func__, data_len); return; } switch (p_data[0]) { case 0x40: // STLOG_HAL_D("%s - hibernate_exited = %d ", __func__, mFWInfo->hibernate_exited); // CORE_INIT_RSP if ((p_data[1] == 0x1) && (p_data[3] == 0x0) && (mFWInfo->hibernate_exited == 0)) { // Send PROP_NFC_MODE_SET_CMD(ON) if (!HalSendDownstream(mHalHandle, propNfcModeSetCmdOn, sizeof(propNfcModeSetCmdOn))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else if ((p_data[1] == 0x1) && (p_data[3] == 0x0) && (mFWInfo->hibernate_exited == 1)) { STLOG_HAL_D( "%s - send NCI_PROP_NFC_FW_UPDATE_CMD and use 100 ms timer for " "each cmd from here", __func__); if (!HalSendDownstreamTimer(mHalHandle, NciPropNfcFwUpdate, sizeof(NciPropNfcFwUpdate), FW_TIMER_DURATION)) { STLOG_HAL_E("%s SendDownstream failed", __func__); } } else if (p_data[3] != 0x00) { STLOG_HAL_D("%s - Wrong response. Retry HW reset", __func__); I2cResetPulse(); hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN); } break; case 0x4f: // if ((p_data[1] == 0x02) && (p_data[3] == 0x00) && (mFWInfo->hibernate_exited == 1)) { STLOG_HAL_D("%s - NCI_PROP_NFC_FW_RSP : loader mode", __func__); I2cResetPulse(); hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN); } else if (p_data[3] != 0x00) { STLOG_HAL_D("%s - Wrong response. Retry HW reset", __func__); I2cResetPulse(); hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN); } break; case 0x60: // if (p_data[3] == 0x2) { STLOG_HAL_D("%s - CORE_RESET_NTF : after core_reset_cmd", __func__); if (!HalSendDownstream(mHalHandle, coreInitCmd, sizeof(coreInitCmd))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else if (p_data[3] == 0xa0) { mFWInfo->hibernate_exited = 1; STLOG_HAL_D("%s - hibernate_exited = %d ", __func__, mFWInfo->hibernate_exited); if (!HalSendDownstream(mHalHandle, coreInitCmd, sizeof(coreInitCmd))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } break; } } bool ft_CheckUWBConf() { char uwbLibName[256]; STLOG_HAL_D("%s", __func__); if (!GetStrValue(NAME_STNFC_UWB_LIB_NAME, (char *)uwbLibName, sizeof(uwbLibName))) { STLOG_HAL_D( "%s - UWB conf library name not found in conf. use default name ", __func__); strcpy(uwbLibName, "/vendor/lib64/libqorvo_uwb_params_nfcc.so"); } STLOG_HAL_D("%s - UWB conf library = %s", __func__, uwbLibName); void *stdll = dlopen(uwbLibName, RTLD_NOW); if (stdll) { STLoadUwbParams fn = (STLoadUwbParams)dlsym(stdll, "load_uwb_params_from_files"); if (fn) { size_t lengthOutput = fn(nciPropSetUwbConfig + 9, 100); STLOG_HAL_D("%s: lengthOutput = %zu", __func__, lengthOutput); if (lengthOutput > 0) { memcpy(nciPropSetUwbConfig, nciHeaderPropSetUwbConfig, 9); nciPropSetUwbConfig[2] = lengthOutput + 6; nciPropSetUwbConfig[8] = lengthOutput; mFWInfo->fileUwbVersion = nciPropSetUwbConfig[9] << 8 | nciPropSetUwbConfig[10]; STLOG_HAL_D("%s --> uwb configuration version 0x%04X \n", __func__, mFWInfo->fileUwbVersion); return true; } else { STLOG_HAL_D("%s: lengthOutput null", __func__); } } } else { STLOG_HAL_D("libqorvo_uwb_params_nfcc not found, do nothing."); } return false; } /******************************************************************************* ** ** Function resetHandlerState ** ** Description Reset FW update state. ** ** Parameters void ** ** *******************************************************************************/ void resetHandlerState() { STLOG_HAL_D("%s", __func__); mHalFDState = HAL_FD_STATE_AUTHENTICATE; mHalFD54LState = HAL_FD_ST54L_STATE_PUY_KEYUSER; } /******************************************************************************* ** ** Function UpdateHandler ** ** Description Handler to update ST54J NFCC FW. ** ** Parameters mHalHandle - HAL handle ** data_len - Buffer length ** p_data - Data buffer from NFCC ** ** *******************************************************************************/ void UpdateHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t *p_data) { HalSendDownstreamStopTimer(mHalHandle); switch (mHalFDState) { case HAL_FD_STATE_AUTHENTICATE: STLOG_HAL_D("%s - mHalFDState = HAL_FD_STATE_AUTHENTICATE", __func__); if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) { STLOG_HAL_D("%s - send APDU_AUTHENTICATION_CMD", __func__); if (!HalSendDownstreamTimer(mHalHandle, (uint8_t *)mApduAuthent, sizeof(mApduAuthent), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFDState = HAL_FD_STATE_ERASE_FLASH; } else { STLOG_HAL_D("%s - FW flash not succeeded", __func__); SendExitLoadMode(mHalHandle); } break; case HAL_FD_STATE_ERASE_FLASH: // 1 STLOG_HAL_D("%s - mHalFDState = HAL_FD_STATE_ERASE_FLASH", __func__); if ((p_data[0] == 0x4f) && (p_data[1] == 0x04)) { if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) { STLOG_HAL_D( " %s - send APDU_ERASE_FLASH_CMD (keep appli and NDEF areas)", __func__); if (!HalSendDownstreamTimer(mHalHandle, ApduEraseNfcKeepAppliAndNdef, sizeof(ApduEraseNfcKeepAppliAndNdef), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } fsetpos(mFwFileBin, &mPosInit); // reset pos in stream mHalFDState = HAL_FD_STATE_SEND_RAW_APDU; } else { STLOG_HAL_D("%s - FW flash not succeeded", __func__); SendExitLoadMode(mHalHandle); } } break; case HAL_FD_STATE_SEND_RAW_APDU: // 3 STLOG_HAL_D("%s - mHalFDState = HAL_FD_STATE_SEND_RAW_APDU", __func__); if ((p_data[0] == 0x4f) && (p_data[1] == 0x04)) { if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) { mRetry = true; fgetpos(mFwFileBin, &mPos); // save current position in stream if ((fread(mBinData, sizeof(uint8_t), 3, mFwFileBin) == 3) && (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mFwFileBin) == mBinData[2])) { if (!HalSendDownstreamTimer(mHalHandle, mBinData, mBinData[2] + 3, FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else { STLOG_HAL_D("%s - EOF of FW binary", __func__); SendExitLoadMode(mHalHandle); } } else if (mRetry == true) { STLOG_HAL_D("%s - Last Tx was NOK. Retry", __func__); mRetry = false; fsetpos(mFwFileBin, &mPos); if ((fread(mBinData, sizeof(uint8_t), 3, mFwFileBin) == 3) && (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mFwFileBin) == mBinData[2])) { if (!HalSendDownstreamTimer(mHalHandle, mBinData, mBinData[2] + 3, FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } fgetpos(mFwFileBin, &mPos); // save current position in stream } else { STLOG_HAL_D("%s - EOF of FW binary", __func__); SendExitLoadMode(mHalHandle); } } else { STLOG_HAL_D("%s - FW flash not succeeded.", __func__); I2cResetPulse(); SendExitLoadMode(mHalHandle); } } break; case HAL_FD_STATE_EXIT_APDU: // 2 STLOG_HAL_D("%s - mHalFDState = HAL_FD_STATE_EXIT_APDU", __func__); if ((p_data[data_len - 2] != 0x90) || (p_data[data_len - 1] != 0x00)) { STLOG_HAL_D( "%s - Error exiting loader mode, i.e. a problem occurred" "during FW update", __func__); } I2cResetPulse(); hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN); mHalFDState = HAL_FD_STATE_AUTHENTICATE; break; default: STLOG_HAL_D("%s - mHalFDState = unknown", __func__); STLOG_HAL_D("%s - FW flash not succeeded", __func__); SendExitLoadMode(mHalHandle); break; } } /******************************************************************************* ** ** Function UpdateHandlerST54L ** ** Description Handler to update ST54L NFCC FW. ** ** Parameters mHalHandle - HAL handle ** data_len - Buffer length ** p_data - Data buffer from NFCC ** ** *******************************************************************************/ static void UpdateHandlerST54L(HALHANDLE mHalHandle, uint16_t data_len, uint8_t* p_data) { STLOG_HAL_D("%s : Enter state = %d", __func__, mHalFD54LState); switch (mHalFD54LState) { case HAL_FD_ST54L_STATE_PUY_KEYUSER: if (!HalSendDownstreamTimer( mHalHandle, (uint8_t*)ApduPutKeyUser1[mFWInfo->chipProdType], sizeof(ApduPutKeyUser1[mFWInfo->chipProdType]), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFD54LState = HAL_FD_ST54L_STATE_ERASE_UPGRADE_START; break; case HAL_FD_ST54L_STATE_ERASE_UPGRADE_START: if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) { if (!HalSendDownstreamTimer(mHalHandle, (uint8_t*)ApduEraseUpgradeStart, sizeof(ApduEraseUpgradeStart), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFD54LState = HAL_FD_ST54L_STATE_ERASE_NFC_AREA; } else { STLOG_HAL_D("%s - FW flash not succeeded", __func__); SendSwitchToUserMode(mHalHandle); } break; case HAL_FD_ST54L_STATE_ERASE_NFC_AREA: if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) { if (!HalSendDownstreamTimer(mHalHandle, (uint8_t*)ApduEraseNfcArea, sizeof(ApduEraseNfcArea), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFD54LState = HAL_FD_ST54L_STATE_ERASE_UPGRADE_STOP; } else { STLOG_HAL_D("%s - FW flash not succeeded", __func__); SendSwitchToUserMode(mHalHandle); } break; case HAL_FD_ST54L_STATE_ERASE_UPGRADE_STOP: if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) { if (!HalSendDownstreamTimer(mHalHandle, (uint8_t*)ApduEraseUpgradeStop, sizeof(ApduEraseUpgradeStop), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFD54LState = HAL_FD_ST54L_STATE_SEND_RAW_APDU; } else { STLOG_HAL_D("%s - FW flash not succeeded", __func__); SendSwitchToUserMode(mHalHandle); } break; case HAL_FD_ST54L_STATE_SEND_RAW_APDU: STLOG_HAL_D("%s - mHalFDState = HAL_FD_ST54L_STATE_SEND_RAW_APDU", __func__); if ((p_data[0] == 0x4f) && (p_data[1] == 0x04)) { if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) { mRetry = true; fgetpos(mFwFileBin, &mPos); // save current position in stream if ((fread(mBinData, sizeof(uint8_t), 3, mFwFileBin) == 3) && (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mFwFileBin) == mBinData[2])) { if (!HalSendDownstreamTimer(mHalHandle, mBinData, mBinData[2] + 3, FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else { STLOG_HAL_D("%s - EOF of FW binary", __func__); if (!HalSendDownstreamTimer( mHalHandle, (uint8_t*)ApduSetVariousConfig, sizeof(ApduSetVariousConfig), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFD54LState = HAL_FD_ST54L_STATE_SET_CONFIG; } } else if (mRetry == true) { STLOG_HAL_D("%s - Last Tx was NOK. Retry", __func__); mRetry = false; fsetpos(mFwFileBin, &mPos); if ((fread(mBinData, sizeof(uint8_t), 3, mFwFileBin) == 3) && (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mFwFileBin) == mBinData[2])) { if (!HalSendDownstreamTimer(mHalHandle, mBinData, mBinData[2] + 3, FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } fgetpos(mFwFileBin, &mPos); // save current position in stream } else { STLOG_HAL_D("%s - EOF of FW binary", __func__); if (!HalSendDownstreamTimer( mHalHandle, (uint8_t*)ApduSetVariousConfig, sizeof(ApduSetVariousConfig), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFD54LState = HAL_FD_ST54L_STATE_SET_CONFIG; } } else { STLOG_HAL_D("%s - FW flash not succeeded.", __func__); I2cResetPulse(); SendSwitchToUserMode(mHalHandle); } } break; case HAL_FD_ST54L_STATE_SET_CONFIG: if ((p_data[0] == 0x4f) && (p_data[1] == 0x04)) { SendSwitchToUserMode(mHalHandle); } break; case HAL_FD_ST54L_STATE_SWITCH_TO_USER: if ((p_data[data_len - 2] != 0x90) || (p_data[data_len - 1] != 0x00)) { STLOG_HAL_D( "%s - Error exiting loader mode, i.e. a problem occurred during FW " "update", __func__); } I2cResetPulse(); hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN); mHalFD54LState = HAL_FD_ST54L_STATE_PUY_KEYUSER; break; default: STLOG_HAL_D("%s - mHalFD54LState = unknown", __func__); STLOG_HAL_D("%s - FW flash not succeeded", __func__); SendSwitchToUserMode(mHalHandle); break; } } /******************************************************************************* ** ** Function FwUpdateHandler ** ** Description Handler to update NFCC FW. ** ** Parameters mHalHandle - HAL handle ** data_len - Buffer length ** p_data - Data buffer from NFCC ** ** *******************************************************************************/ void FwUpdateHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t* p_data) { if (mFWInfo->chipHwVersion == HW_ST54L) { UpdateHandlerST54L(mHalHandle, data_len, p_data); } else { UpdateHandler(mHalHandle, data_len, p_data); } } void ApplyCustomParamHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t *p_data) { STLOG_HAL_D("%s - Enter ", __func__); if (data_len < 3) { STLOG_HAL_E("%s : Error, too short data (%d)", __func__, data_len); return; } switch (p_data[0]) { case 0x40: // // CORE_RESET_RSP if ((p_data[1] == 0x0) && (p_data[3] == 0x0)) { // do nothing } else if ((p_data[1] == 0x1) && (p_data[3] == 0x0)) { if (mFWInfo->hibernate_exited == 0) { // Send a NFC mode on . if (!HalSendDownstream(mHalHandle, propNfcModeSetCmdOn, sizeof(propNfcModeSetCmdOn))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } // CORE_INIT_RSP } else if (mFWInfo->hibernate_exited == 1) { if ((fread(mBinData, sizeof(uint8_t), 3, mCustomFileBin)) && (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mCustomFileBin))) { if (!HalSendDownstream(mHalHandle, mBinData, mBinData[2] + 3)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } } } else { STLOG_HAL_D("%s - Error in custom param application", __func__); mCustomParamFailed = true; I2cResetPulse(); hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN); } break; case 0x4f: if (mFWInfo->hibernate_exited == 1) { if ((fread(mBinData, sizeof(uint8_t), 3, mCustomFileBin) == 3) && (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mCustomFileBin) == mBinData[2])) { if (!HalSendDownstream(mHalHandle, mBinData, mBinData[2] + 3)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else { STLOG_HAL_D("%s - mCustomParamDone = %d", __func__, mCustomParamDone); if (!mGetCustomerField) { mGetCustomerField = true; if (!HalSendDownstream(mHalHandle, nciGetPropConfig, sizeof(nciGetPropConfig))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mGetCustomerField = true; } else if (!mCustomParamDone) { STLOG_HAL_D("%s - EOF of custom file.", __func__); memset(nciPropSetConfig_CustomField, 0x0, sizeof(nciPropSetConfig_CustomField)); memcpy(nciPropSetConfig_CustomField, nciSetPropConfig, 9); nciPropSetConfig_CustomField[8] = p_data[6]; nciPropSetConfig_CustomField[2] = p_data[6] + 6; memcpy(nciPropSetConfig_CustomField + 9, p_data + 7, p_data[6]); nciPropSetConfig_CustomField[13] = mFWInfo->chipUwbVersion >> 8; nciPropSetConfig_CustomField[14] = mFWInfo->chipUwbVersion; if (!HalSendDownstream(mHalHandle, nciPropSetConfig_CustomField, nciPropSetConfig_CustomField[2] + 3)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mCustomParamDone = true; } else { I2cResetPulse(); if (mUwbConfigNeeded) { mCustomParamDone = false; mGetCustomerField = false; hal_wrapper_set_state(HAL_WRAPPER_STATE_APPLY_UWB_PARAM); } } } } // Check if an error has occurred for PROP_SET_CONFIG_CMD // Only log a warning, do not exit code if (p_data[3] != 0x00) { STLOG_HAL_D("%s - Error in custom file, continue anyway", __func__); } break; case 0x60: // if (p_data[1] == 0x0) { if (p_data[3] == 0xa0) { mFWInfo->hibernate_exited = 1; } if (!HalSendDownstream(mHalHandle, coreInitCmd, sizeof(coreInitCmd))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else if ((p_data[1] == 0x6) && mCustomParamDone) { mCustomParamDone = false; mGetCustomerField = false; hal_wrapper_update_complete(); } break; } } void ApplyUwbParamHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t *p_data) { STLOG_HAL_D("%s - Enter ", __func__); if (data_len < 3) { STLOG_HAL_E("%s : Error, too short data (%d)", __func__, data_len); return; } switch (p_data[0]) { case 0x40: // // CORE_RESET_RSP if ((p_data[1] == 0x0) && (p_data[3] == 0x0)) { // do nothing } else if ((p_data[1] == 0x1) && (p_data[3] == 0x0)) { if (mFWInfo->hibernate_exited == 0) { // Send a NFC mode on . if (!HalSendDownstream(mHalHandle, propNfcModeSetCmdOn, sizeof(propNfcModeSetCmdOn))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } // CORE_INIT_RSP } else if ((mFWInfo->hibernate_exited == 1) && !mUwbConfigDone) { if (!HalSendDownstream(mHalHandle, nciPropSetUwbConfig, nciPropSetUwbConfig[2] + 3)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } } else { STLOG_HAL_D("%s - Error in uwb param application", __func__); I2cResetPulse(); hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN); } break; case 0x4f: if (mFWInfo->hibernate_exited == 1) { if (!mUwbConfigDone) { mUwbConfigDone = true; // Check if an error has occurred for PROP_SET_CONFIG_CMD // Only log a warning, do not exit code if (p_data[3] != 0x00) { STLOG_HAL_D("%s - Error in uwb file, continue anyway", __func__); } if (!HalSendDownstream(mHalHandle, nciGetPropConfig, sizeof(nciGetPropConfig))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else if ((p_data[1] == 0x2) && (p_data[2] == 0x0c)) { memset(nciPropSetConfig_CustomField, 0x0, sizeof(nciPropSetConfig_CustomField)); memcpy(nciPropSetConfig_CustomField, nciSetPropConfig, 9); nciPropSetConfig_CustomField[8] = p_data[6]; nciPropSetConfig_CustomField[2] = p_data[6] + 6; memcpy(nciPropSetConfig_CustomField + 9, p_data + 7, p_data[6]); nciPropSetConfig_CustomField[13] = mFWInfo->fileUwbVersion >> 8; nciPropSetConfig_CustomField[14] = mFWInfo->fileUwbVersion; if (!HalSendDownstream(mHalHandle, nciPropSetConfig_CustomField, nciPropSetConfig_CustomField[2] + 3)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else { I2cResetPulse(); } } break; case 0x60: // if (p_data[1] == 0x0) { if (p_data[3] == 0xa0) { mFWInfo->hibernate_exited = 1; } if (!HalSendDownstream(mHalHandle, coreInitCmd, sizeof(coreInitCmd))) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } } else if ((p_data[1] == 0x6) && mUwbConfigDone) { mUwbConfigNeeded = false; mUwbConfigDone = false; hal_wrapper_update_complete(); } break; } } void SendExitLoadMode(HALHANDLE mmHalHandle) { STLOG_HAL_D("%s - Send APDU_EXIT_LOAD_MODE_CMD", __func__); if (!HalSendDownstreamTimer(mmHalHandle, ApduExitLoadMode, sizeof(ApduExitLoadMode), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFDState = HAL_FD_STATE_EXIT_APDU; } void SendSwitchToUserMode(HALHANDLE mmHalHandle) { STLOG_HAL_D("%s: enter", __func__); if (!HalSendDownstreamTimer(mmHalHandle, ApduSwitchToUser, sizeof(ApduSwitchToUser), FW_TIMER_DURATION)) { STLOG_HAL_E("%s - SendDownstream failed", __func__); } mHalFD54LState = HAL_FD_ST54L_STATE_SWITCH_TO_USER; }