/****************************************************************************** * \attention * *

© COPYRIGHT 2020 STMicroelectronics

* * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * www.st.com/myliberty * * 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, * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /* * PROJECT: ST25R391x firmware * Revision: * LANGUAGE: ISO C99 */ /*! \file rfal_analogConfig.c * * \author bkam * * \brief Funcitons to manage and set analog settings. * */ /* ****************************************************************************** * INCLUDES ****************************************************************************** */ #include "rfal_analogConfig.h" #include "rfal_chip.h" #include "st_errno.h" #include "platform.h" #include "utils.h" /* Check whether the Default Analog settings are to be used or custom ones */ #ifdef RFAL_ANALOG_CONFIG_CUSTOM extern const uint8_t* rfalAnalogConfigCustomSettings; extern const uint16_t rfalAnalogConfigCustomSettingsLength; #else #include "rfal_analogConfigTbl.h" #endif /* ****************************************************************************** * DEFINES ****************************************************************************** */ #define RFAL_TEST_REG 0x0080U /*!< Test Register indicator */ /* ****************************************************************************** * MACROS ****************************************************************************** */ /* ****************************************************************************** * LOCAL DATA TYPES ****************************************************************************** */ #if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG static uint8_t gRfalAnalogConfig[RFAL_ANALOG_CONFIG_TBL_SIZE]; /*!< Analog Configuration Settings List */ #endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ /*! Struct for Analog Config Look Up Table Update */ typedef struct { const uint8_t* currentAnalogConfigTbl; /*!< Reference to start of current Analog Configuration */ uint16_t configTblSize; /*!< Total size of Analog Configuration */ bool ready; /*!< Indicate if Look Up Table is complete and ready for use */ } rfalAnalogConfigMgmt; static rfalAnalogConfigMgmt gRfalAnalogConfigMgmt; /*!< Analog Configuration LUT management */ /* ****************************************************************************** * LOCAL TABLES ****************************************************************************** */ /* ****************************************************************************** * LOCAL FUNCTION PROTOTYPES ****************************************************************************** */ static rfalAnalogConfigNum rfalAnalogConfigSearch(rfalAnalogConfigId configId, uint16_t* configOffset); #if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG static void rfalAnalogConfigPtrUpdate(const uint8_t* analogConfigTbl); #endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ /* ****************************************************************************** * GLOBAL VARIABLE DEFINITIONS ****************************************************************************** */ /* ****************************************************************************** * GLOBAL FUNCTIONS ****************************************************************************** */ void rfalAnalogConfigInitialize(void) { /* Use default Analog configuration settings in Flash by default. */ /* Check whether the Default Analog settings are to be used or custom ones */ #ifdef RFAL_ANALOG_CONFIG_CUSTOM gRfalAnalogConfigMgmt.currentAnalogConfigTbl = (const uint8_t*)&rfalAnalogConfigCustomSettings; gRfalAnalogConfigMgmt.configTblSize = rfalAnalogConfigCustomSettingsLength; #else gRfalAnalogConfigMgmt.currentAnalogConfigTbl = (const uint8_t*)&rfalAnalogConfigDefaultSettings; gRfalAnalogConfigMgmt.configTblSize = sizeof(rfalAnalogConfigDefaultSettings); #endif gRfalAnalogConfigMgmt.ready = true; } /* rfalAnalogConfigInitialize() */ bool rfalAnalogConfigIsReady(void) { return gRfalAnalogConfigMgmt.ready; } ReturnCode rfalAnalogConfigListWriteRaw(const uint8_t* configTbl, uint16_t configTblSize) { #if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG /* Check if the Configuration Table exceed the Table size */ if(configTblSize >= RFAL_ANALOG_CONFIG_TBL_SIZE) { rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */ return ERR_NOMEM; } /* Check for invalid parameters */ if((configTbl == NULL) || (configTblSize == 0U)) { return ERR_PARAM; } /* NOTE: Function does not check for the validity of the Table contents (conf IDs, conf sets, register address) */ ST_MEMCPY(gRfalAnalogConfig, configTbl, configTblSize); /* Update the total size of configuration settings */ gRfalAnalogConfigMgmt.configTblSize = configTblSize; rfalAnalogConfigPtrUpdate(gRfalAnalogConfig); return ERR_NONE; #else // If Analog Configuration Update is to be disabled NO_WARNING(configTbl); NO_WARNING(configTblSize); return ERR_REQUEST; #endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ } ReturnCode rfalAnalogConfigListWrite(uint8_t more, const rfalAnalogConfig* config) { #if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG rfalAnalogConfigId configId; rfalAnalogConfigNum numConfig; uint8_t configSize; if(true == gRfalAnalogConfigMgmt.ready) { /* First Update to the Configuration list. */ gRfalAnalogConfigMgmt.ready = false; // invalidate the config List gRfalAnalogConfigMgmt.configTblSize = 0; // Clear the config List } configId = GETU16(config->id); /* Check validity of the Configuration ID. */ if((RFAL_ANALOG_CONFIG_TECH_RFU <= RFAL_ANALOG_CONFIG_ID_GET_TECH(configId)) || ((RFAL_ANALOG_CONFIG_BITRATE_6780 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId)) && (RFAL_ANALOG_CONFIG_BITRATE_1OF4 > RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId))) || (RFAL_ANALOG_CONFIG_BITRATE_1OF256 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId))) { rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */ return ERR_PARAM; } numConfig = config->num; configSize = (uint8_t)(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) + (numConfig * sizeof(rfalAnalogConfigRegAddrMaskVal))); /* Check if the Configuration Set exceed the Table size. */ if(RFAL_ANALOG_CONFIG_TBL_SIZE <= (gRfalAnalogConfigMgmt.configTblSize + configSize)) { rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */ return ERR_NOMEM; } /* NOTE: Function does not check for the validity of the Register Address. */ ST_MEMCPY( &gRfalAnalogConfig[gRfalAnalogConfigMgmt.configTblSize], (const uint8_t*)config, configSize); /* Increment the total size of configuration settings. */ gRfalAnalogConfigMgmt.configTblSize += configSize; /* Check if it is the last Analog Configuration to load. */ if(RFAL_ANALOG_CONFIG_UPDATE_LAST == more) { /* Update the Analog Configuration to the new settings. */ rfalAnalogConfigPtrUpdate(gRfalAnalogConfig); } return ERR_NONE; #else // If Analog Configuration Update is to be disabled NO_WARNING(config); NO_WARNING(more); return ERR_DISABLED; #endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ } /* rfalAnalogConfigListUpdate() */ ReturnCode rfalAnalogConfigListReadRaw(uint8_t* tblBuf, uint16_t tblBufLen, uint16_t* configTblSize) { /* Check if the the current table will fit into the given buffer */ if(tblBufLen < gRfalAnalogConfigMgmt.configTblSize) { return ERR_NOMEM; } /* Check for invalid parameters */ if(configTblSize == NULL) { return ERR_PARAM; } /* Copy the whole Table to the given buffer */ if(gRfalAnalogConfigMgmt.configTblSize > 0U) /* MISRA 21.18 */ { ST_MEMCPY( tblBuf, gRfalAnalogConfigMgmt.currentAnalogConfigTbl, gRfalAnalogConfigMgmt.configTblSize); } *configTblSize = gRfalAnalogConfigMgmt.configTblSize; return ERR_NONE; } ReturnCode rfalAnalogConfigListRead( rfalAnalogConfigOffset* configOffset, uint8_t* more, rfalAnalogConfig* config, rfalAnalogConfigNum numConfig) { uint16_t configSize; rfalAnalogConfigOffset offset = *configOffset; rfalAnalogConfigNum numConfigSet; /* Check if the number of register-mask-value settings for the respective Configuration ID will fit into the buffer passed in. */ if(gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)] > numConfig) { return ERR_NOMEM; } /* Get the number of Configuration set */ numConfigSet = gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)]; /* Pass Configuration Register-Mask-Value sets */ configSize = (sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) + (uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal))); ST_MEMCPY((uint8_t*)config, &gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset], configSize); *configOffset = offset + configSize; /* Check if it is the last Analog Configuration in the Table.*/ *more = (uint8_t)((*configOffset >= gRfalAnalogConfigMgmt.configTblSize) ? RFAL_ANALOG_CONFIG_UPDATE_LAST : RFAL_ANALOG_CONFIG_UPDATE_MORE); return ERR_NONE; } /* rfalAnalogConfigListRead() */ ReturnCode rfalSetAnalogConfig(rfalAnalogConfigId configId) { rfalAnalogConfigOffset configOffset = 0; rfalAnalogConfigNum numConfigSet; const rfalAnalogConfigRegAddrMaskVal* configTbl; ReturnCode retCode = ERR_NONE; rfalAnalogConfigNum i; if(true != gRfalAnalogConfigMgmt.ready) { return ERR_REQUEST; } /* Search LUT for the specific Configuration ID. */ while(true) { numConfigSet = rfalAnalogConfigSearch(configId, &configOffset); if(RFAL_ANALOG_CONFIG_LUT_NOT_FOUND == numConfigSet) { break; } configTbl = (rfalAnalogConfigRegAddrMaskVal*)((uint32_t)gRfalAnalogConfigMgmt.currentAnalogConfigTbl + (uint32_t)configOffset); /* Increment the offset to the next index to search from. */ configOffset += (uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal)); if((gRfalAnalogConfigMgmt.configTblSize + 1U) < configOffset) { /* Error check make sure that the we do not access outside the configuration Table Size */ return ERR_NOMEM; } for(i = 0; i < numConfigSet; i++) { if((GETU16(configTbl[i].addr) & RFAL_TEST_REG) != 0U) { EXIT_ON_ERR( retCode, rfalChipChangeTestRegBits( (GETU16(configTbl[i].addr) & ~RFAL_TEST_REG), configTbl[i].mask, configTbl[i].val)); } else { EXIT_ON_ERR( retCode, rfalChipChangeRegBits( GETU16(configTbl[i].addr), configTbl[i].mask, configTbl[i].val)); } } } /* while(found Analog Config Id) */ return retCode; } /* rfalSetAnalogConfig() */ uint16_t rfalAnalogConfigGenModeID(rfalMode md, rfalBitRate br, uint16_t dir) { uint16_t id; /* Assign Poll/Listen Mode */ id = ((md >= RFAL_MODE_LISTEN_NFCA) ? RFAL_ANALOG_CONFIG_LISTEN : RFAL_ANALOG_CONFIG_POLL); /* Assign Technology */ switch(md) { case RFAL_MODE_POLL_NFCA: case RFAL_MODE_POLL_NFCA_T1T: case RFAL_MODE_LISTEN_NFCA: id |= RFAL_ANALOG_CONFIG_TECH_NFCA; break; case RFAL_MODE_POLL_NFCB: case RFAL_MODE_POLL_B_PRIME: case RFAL_MODE_POLL_B_CTS: case RFAL_MODE_LISTEN_NFCB: id |= RFAL_ANALOG_CONFIG_TECH_NFCB; break; case RFAL_MODE_POLL_NFCF: case RFAL_MODE_LISTEN_NFCF: id |= RFAL_ANALOG_CONFIG_TECH_NFCF; break; case RFAL_MODE_POLL_NFCV: case RFAL_MODE_POLL_PICOPASS: id |= RFAL_ANALOG_CONFIG_TECH_NFCV; break; case RFAL_MODE_POLL_ACTIVE_P2P: case RFAL_MODE_LISTEN_ACTIVE_P2P: id |= RFAL_ANALOG_CONFIG_TECH_AP2P; break; default: id = RFAL_ANALOG_CONFIG_TECH_CHIP; break; } /* Assign Bitrate */ id |= (((((uint16_t)(br) >= (uint16_t)RFAL_BR_52p97) ? (uint16_t)(br) : ((uint16_t)(br) + 1U)) << RFAL_ANALOG_CONFIG_BITRATE_SHIFT) & RFAL_ANALOG_CONFIG_BITRATE_MASK); /* Assign Direction */ id |= ((dir << RFAL_ANALOG_CONFIG_DIRECTION_SHIFT) & RFAL_ANALOG_CONFIG_DIRECTION_MASK); return id; } /* rfalAnalogConfigGenModeID() */ /* ****************************************************************************** * LOCAL FUNCTIONS ****************************************************************************** */ /*! ***************************************************************************** * \brief Update the link to Analog Configuration LUT * * Update the link to the Analog Configuration LUT for the subsequent search * of Analog Settings. * * \param[in] analogConfigTbl: reference to the start of the new Analog Configuration Table * ***************************************************************************** */ #if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG static void rfalAnalogConfigPtrUpdate(const uint8_t* analogConfigTbl) { gRfalAnalogConfigMgmt.currentAnalogConfigTbl = analogConfigTbl; gRfalAnalogConfigMgmt.ready = true; } /* rfalAnalogConfigPtrUpdate() */ #endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */ /*! ***************************************************************************** * \brief Search the Analog Configuration LUT for a specific Configuration ID. * * Search the Analog Configuration LUT for the Configuration ID. * * \param[in] configId: Configuration ID to search for. * \param[in] configOffset: Configuration Offset in Table * * \return number of Configuration Sets * \return #RFAL_ANALOG_CONFIG_LUT_NOT_FOUND in case Configuration ID is not found. ***************************************************************************** */ static rfalAnalogConfigNum rfalAnalogConfigSearch(rfalAnalogConfigId configId, uint16_t* configOffset) { rfalAnalogConfigId foundConfigId; rfalAnalogConfigId configIdMaskVal; const uint8_t* configTbl; const uint8_t* currentConfigTbl; uint16_t i; currentConfigTbl = gRfalAnalogConfigMgmt.currentAnalogConfigTbl; configIdMaskVal = ((RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK | RFAL_ANALOG_CONFIG_BITRATE_MASK) | ((RFAL_ANALOG_CONFIG_TECH_CHIP == RFAL_ANALOG_CONFIG_ID_GET_TECH(configId)) ? (RFAL_ANALOG_CONFIG_TECH_MASK | RFAL_ANALOG_CONFIG_CHIP_SPECIFIC_MASK) : configId) | ((RFAL_ANALOG_CONFIG_NO_DIRECTION == RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId)) ? RFAL_ANALOG_CONFIG_DIRECTION_MASK : configId)); /* When specific ConfigIDs are to be used, override search mask */ if((RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId) == RFAL_ANALOG_CONFIG_DPO)) { configIdMaskVal = (RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK | RFAL_ANALOG_CONFIG_TECH_MASK | RFAL_ANALOG_CONFIG_BITRATE_MASK | RFAL_ANALOG_CONFIG_DIRECTION_MASK); } i = *configOffset; while(i < gRfalAnalogConfigMgmt.configTblSize) { configTbl = ¤tConfigTbl[i]; foundConfigId = GETU16(configTbl); if(configId == (foundConfigId & configIdMaskVal)) { *configOffset = (uint16_t)(i + sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum)); return configTbl[sizeof(rfalAnalogConfigId)]; } /* If Config Id does not match, increment to next Configuration Id */ i += (uint16_t)(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) + (configTbl[sizeof(rfalAnalogConfigId)] * sizeof(rfalAnalogConfigRegAddrMaskVal))); } /* for */ return RFAL_ANALOG_CONFIG_LUT_NOT_FOUND; } /* rfalAnalogConfigSearch() */