diff --git a/examples/platforms/nrf528xx/src/radio.c b/examples/platforms/nrf528xx/src/radio.c index 795a91994..2fda984c8 100644 --- a/examples/platforms/nrf528xx/src/radio.c +++ b/examples/platforms/nrf528xx/src/radio.c @@ -107,6 +107,7 @@ static otRadioFrame sAckFrame; static bool sAckedWithFramePending; static int8_t sDefaultTxPower; +static int8_t sLnaGain = 0; static uint32_t sEnergyDetectionTime; static uint8_t sEnergyDetectionChannel; @@ -687,7 +688,7 @@ otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aT { nrf_802154_cca_cfg_get(&ccaConfig); // The radio driver has no function to convert ED threshold to dBm - *aThreshold = (int8_t)ccaConfig.ed_threshold + NRF528XX_MIN_CCA_ED_THRESHOLD; + *aThreshold = (int8_t)ccaConfig.ed_threshold + NRF528XX_MIN_CCA_ED_THRESHOLD - sLnaGain; } return error; @@ -700,6 +701,8 @@ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aTh otError error = OT_ERROR_NONE; nrf_802154_cca_cfg_t ccaConfig; + aThreshold += sLnaGain; + // The minimum value of ED threshold for radio driver is -94 dBm if (aThreshold < NRF528XX_MIN_CCA_ED_THRESHOLD) { @@ -717,6 +720,43 @@ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aTh return error; } +otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + + otError error = OT_ERROR_NONE; + + if (aGain == NULL) + { + error = OT_ERROR_INVALID_ARGS; + } + else + { + *aGain = sLnaGain; + } + + return error; +} + +otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + + int8_t threshold; + int8_t oldLnaGain = sLnaGain; + otError error = OT_ERROR_NONE; + + error = otPlatRadioGetCcaEnergyDetectThreshold(aInstance, &threshold); + otEXPECT(error == OT_ERROR_NONE); + + sLnaGain = aGain; + error = otPlatRadioSetCcaEnergyDetectThreshold(aInstance, threshold); + otEXPECT_ACTION(error == OT_ERROR_NONE, sLnaGain = oldLnaGain); + +exit: + return error; +} + void nrf5RadioProcess(otInstance *aInstance) { bool isEventPending = false; diff --git a/examples/platforms/simulation/radio.c b/examples/platforms/simulation/radio.c index d39534c49..9279bd3f6 100644 --- a/examples/platforms/simulation/radio.c +++ b/examples/platforms/simulation/radio.c @@ -111,6 +111,7 @@ static bool sPromiscuous = false; static bool sTxWait = false; static int8_t sTxPower = 0; static int8_t sCcaEdThresh = -74; +static int8_t sLnaGain = 0; static bool sSrcMatchEnabled = false; @@ -983,6 +984,28 @@ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aTh return OT_ERROR_NONE; } +otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + + assert(aInstance != NULL && aGain != NULL); + + *aGain = sLnaGain; + + return OT_ERROR_NONE; +} + +otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + + assert(aInstance != NULL); + + sLnaGain = aGain; + + return OT_ERROR_NONE; +} + int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); diff --git a/include/openthread/platform/radio.h b/include/openthread/platform/radio.h index c5d5b39b2..9d41b1b4c 100644 --- a/include/openthread/platform/radio.h +++ b/include/openthread/platform/radio.h @@ -431,7 +431,7 @@ otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower); otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower); /** - * Get the radio's CCA ED threshold in dBm. + * Get the radio's CCA ED threshold in dBm measured at antenna connector per IEEE 802.15.4 - 2015 section 10.1.4. * * @param[in] aInstance The OpenThread instance structure. * @param[out] aThreshold The CCA ED threshold in dBm. @@ -444,7 +444,7 @@ otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower); otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold); /** - * Set the radio's CCA ED threshold in dBm. + * Set the radio's CCA ED threshold in dBm measured at antenna connector per IEEE 802.15.4 - 2015 section 10.1.4. * * @param[in] aInstance The OpenThread instance structure. * @param[in] aThreshold The CCA ED threshold in dBm. @@ -456,6 +456,31 @@ otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aT */ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold); +/** + * Get the external FEM's Rx LNA gain in dBm. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[out] aGain The external FEM's Rx LNA gain in dBm. + * + * @retval OT_ERROR_NONE Successfully retrieved the external FEM's LNA gain. + * @retval OT_ERROR_INVALID_ARGS @p aGain was NULL. + * @retval OT_ERROR_NOT_IMPLEMENTED External FEM's LNA setting is not implemented. + * + */ +otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain); + +/** + * Set the external FEM's Rx LNA gain in dBm. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aGain The external FEM's Rx LNA gain in dBm. + * + * @retval OT_ERROR_NONE Successfully set the external FEM's LNA gain. + * @retval OT_ERROR_NOT_IMPLEMENTED External FEM's LNA gain setting is not implemented. + * + */ +otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain); + /** * Get the status of promiscuous mode. * diff --git a/src/cli/README.md b/src/cli/README.md index eef19b4a9..7da9da0bb 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -49,6 +49,7 @@ Done - [extpanid](#extpanid) - [factoryreset](#factoryreset) - [fake](#fake) +- [fem](#fem) - [ifconfig](#ifconfig) - [ipaddr](#ipaddr) - [ipmaddr](#ipmaddr) @@ -330,7 +331,7 @@ Done ### ccathreshold -Get the CCA threshold in dBm. +Get the CCA threshold in dBm measured at antenna connector per IEEE 802.15.4 - 2015 section 10.1.4. ```bash > ccathreshold @@ -340,7 +341,7 @@ Done ### ccathreshold \ -Set the CCA threshold. +Set the CCA threshold measured at antenna connector per IEEE 802.15.4 - 2015 section 10.1.4. ```bash > ccathreshold -62 @@ -868,6 +869,35 @@ Note: Only for certification test. Done ``` +### fem + +Get external FEM parameters. + +```bash +> fem +LNA gain 11 dBm +Done +``` + +### fem lnagain + +Get the Rx LNA gain in dBm of the external FEM. + +```bash +> fem lnagain +11 +Done +``` + +### fem lnagain \ + +Set the Rx LNA gain in dBm of the external FEM. + +```bash +> fem lnagain 8 +Done +``` + ### ifconfig Show the status of the IPv6 interface. @@ -1945,7 +1975,7 @@ Done ### txpower \ -Set the transmit power. +Set the transmit power in dBm. ```bash > txpower -10 diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index eb5a29acf..342fa5747 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -1547,6 +1547,43 @@ exit: } #endif +otError Interpreter::ProcessFem(uint8_t aArgsLength, char *aArgs[]) +{ + otError error = OT_ERROR_NONE; + + if (aArgsLength == 0) + { + int8_t lnaGain; + + SuccessOrExit(error = otPlatRadioGetFemLnaGain(mInstance, &lnaGain)); + OutputLine("LNA gain %d dBm", lnaGain); + } + else if (strcmp(aArgs[0], "lnagain") == 0) + { + if (aArgsLength == 1) + { + int8_t lnaGain; + + SuccessOrExit(error = otPlatRadioGetFemLnaGain(mInstance, &lnaGain)); + OutputLine("%d", lnaGain); + } + else + { + int8_t lnaGain; + + SuccessOrExit(error = ParseAsInt8(aArgs[1], lnaGain)); + SuccessOrExit(error = otPlatRadioSetFemLnaGain(mInstance, lnaGain)); + } + } + else + { + error = OT_ERROR_INVALID_ARGS; + } + +exit: + return error; +} + otError Interpreter::ProcessIfconfig(uint8_t aArgsLength, char *aArgs[]) { otError error = OT_ERROR_NONE; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index b8896529a..85dc8f66c 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -332,6 +332,7 @@ private: #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE otError ProcessFake(uint8_t aArgsLength, char *aArgs[]); #endif + otError ProcessFem(uint8_t aArgsLength, char *aArgs[]); otError ProcessIfconfig(uint8_t aArgsLength, char *aArgs[]); otError ProcessIpAddr(uint8_t aArgsLength, char *aArgs[]); otError ProcessIpAddrAdd(uint8_t aArgsLength, char *aArgs[]); @@ -601,6 +602,7 @@ private: #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE {"fake", &Interpreter::ProcessFake}, #endif + {"fem", &Interpreter::ProcessFem}, {"help", &Interpreter::ProcessHelp}, {"ifconfig", &Interpreter::ProcessIfconfig}, {"ipaddr", &Interpreter::ProcessIpAddr}, diff --git a/src/core/radio/radio_platform.cpp b/src/core/radio/radio_platform.cpp index a88b72999..bc9853033 100644 --- a/src/core/radio/radio_platform.cpp +++ b/src/core/radio/radio_platform.cpp @@ -165,3 +165,19 @@ OT_TOOL_WEAK uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance) return 0; } + +OT_TOOL_WEAK otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aGain); + + return OT_ERROR_NOT_IMPLEMENTED; +} + +OT_TOOL_WEAK otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aGain); + + return OT_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index 8048abf9f..d81845178 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -243,6 +243,30 @@ public: */ otError SetCcaEnergyDetectThreshold(int8_t aThreshold); + /** + * This method gets the FEM's Rx LNA gain in dBm. + * + * @param[out] aGain The FEM's Rx LNA gain in dBm. + * + * @retval OT_ERROR_NONE Succeeded. + * @retval OT_ERROR_BUSY Failed due to another operation is on going. + * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. + * + */ + otError GetFemLnaGain(int8_t &aGain); + + /** + * This method sets the FEM's Rx LNA gain in dBm. + * + * @param[in] aGain The FEM's Rx LNA gain in dBm. + * + * @retval OT_ERROR_NONE Succeeded. + * @retval OT_ERROR_BUSY Failed due to another operation is on going. + * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. + * + */ + otError SetFemLnaGain(int8_t aGain); + /** * This method returns the radio sw version string. * diff --git a/src/lib/spinel/radio_spinel_impl.hpp b/src/lib/spinel/radio_spinel_impl.hpp index ddaa2ebb4..3ca4217d6 100644 --- a/src/lib/spinel/radio_spinel_impl.hpp +++ b/src/lib/spinel/radio_spinel_impl.hpp @@ -1168,6 +1168,15 @@ otError RadioSpinel::GetCcaEnergyDetectThresh return error; } +template +otError RadioSpinel::GetFemLnaGain(int8_t &aGain) +{ + otError error = Get(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, &aGain); + + LogIfFail("Get FEM LNA gain failed", error); + return error; +} + template int8_t RadioSpinel::GetRssi(void) { @@ -1252,6 +1261,14 @@ otError RadioSpinel::SetCcaEnergyDetectThresh return error; } +template +otError RadioSpinel::SetFemLnaGain(int8_t aGain) +{ + otError error = Set(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, aGain); + LogIfFail("Set FEM LNA gain failed", error); + return error; +} + template otError RadioSpinel::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration) { diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index f82178934..b4fe53ac5 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1379,6 +1379,10 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "PHY_TX_POWER"; break; + case SPINEL_PROP_PHY_FEM_LNA_GAIN: + ret = "PHY_FEM_LNA_GAIN"; + break; + case SPINEL_PROP_PHY_RSSI: ret = "PHY_RSSI"; break; diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index a08c824fb..fd0722e55 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -1506,16 +1506,17 @@ enum SPINEL_PROP_BASE_EXT__END = 0x1100, SPINEL_PROP_PHY__BEGIN = 0x20, - SPINEL_PROP_PHY_ENABLED = SPINEL_PROP_PHY__BEGIN + 0, ///< [b] - SPINEL_PROP_PHY_CHAN = SPINEL_PROP_PHY__BEGIN + 1, ///< [C] - SPINEL_PROP_PHY_CHAN_SUPPORTED = SPINEL_PROP_PHY__BEGIN + 2, ///< [A(C)] - SPINEL_PROP_PHY_FREQ = SPINEL_PROP_PHY__BEGIN + 3, ///< kHz [L] - SPINEL_PROP_PHY_CCA_THRESHOLD = SPINEL_PROP_PHY__BEGIN + 4, ///< dBm [c] - SPINEL_PROP_PHY_TX_POWER = SPINEL_PROP_PHY__BEGIN + 5, ///< [c] - SPINEL_PROP_PHY_RSSI = SPINEL_PROP_PHY__BEGIN + 6, ///< dBm [c] - SPINEL_PROP_PHY_RX_SENSITIVITY = SPINEL_PROP_PHY__BEGIN + 7, ///< dBm [c] - SPINEL_PROP_PHY_PCAP_ENABLED = SPINEL_PROP_PHY__BEGIN + 8, ///< [b] - SPINEL_PROP_PHY_CHAN_PREFERRED = SPINEL_PROP_PHY__BEGIN + 9, ///< [A(C)] + SPINEL_PROP_PHY_ENABLED = SPINEL_PROP_PHY__BEGIN + 0, ///< [b] + SPINEL_PROP_PHY_CHAN = SPINEL_PROP_PHY__BEGIN + 1, ///< [C] + SPINEL_PROP_PHY_CHAN_SUPPORTED = SPINEL_PROP_PHY__BEGIN + 2, ///< [A(C)] + SPINEL_PROP_PHY_FREQ = SPINEL_PROP_PHY__BEGIN + 3, ///< kHz [L] + SPINEL_PROP_PHY_CCA_THRESHOLD = SPINEL_PROP_PHY__BEGIN + 4, ///< dBm [c] + SPINEL_PROP_PHY_TX_POWER = SPINEL_PROP_PHY__BEGIN + 5, ///< [c] + SPINEL_PROP_PHY_RSSI = SPINEL_PROP_PHY__BEGIN + 6, ///< dBm [c] + SPINEL_PROP_PHY_RX_SENSITIVITY = SPINEL_PROP_PHY__BEGIN + 7, ///< dBm [c] + SPINEL_PROP_PHY_PCAP_ENABLED = SPINEL_PROP_PHY__BEGIN + 8, ///< [b] + SPINEL_PROP_PHY_CHAN_PREFERRED = SPINEL_PROP_PHY__BEGIN + 9, ///< [A(C)] + SPINEL_PROP_PHY_FEM_LNA_GAIN = SPINEL_PROP_PHY__BEGIN + 10, ///< dBm [c] SPINEL_PROP_PHY__END = 0x30, SPINEL_PROP_PHY_EXT__BEGIN = 0x1200, diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 570979ea4..784f4e3bb 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -2205,6 +2205,37 @@ exit: return error; } +template <> otError NcpBase::HandlePropertyGet(void) +{ + int8_t gain; + otError error = OT_ERROR_NONE; + + error = otPlatRadioGetFemLnaGain(mInstance, &gain); + + if (error == OT_ERROR_NONE) + { + error = mEncoder.WriteInt8(gain); + } + else + { + error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error)); + } + + return error; +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + int8_t gain = 0; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadInt8(gain)); + error = otPlatRadioSetFemLnaGain(mInstance, gain); + +exit: + return error; +} + template <> otError NcpBase::HandlePropertyGet(void) { #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index c92c72d18..8b3dbb859 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -74,6 +74,7 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_PHY_PCAP_ENABLED), #endif OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_PHY_CHAN_PREFERRED), + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_PHY_FEM_LNA_GAIN), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_STATE), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_MASK), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_PERIOD), @@ -361,6 +362,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) #if OPENTHREAD_MTD || OPENTHREAD_FTD OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_PHY_PCAP_ENABLED), #endif + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_PHY_FEM_LNA_GAIN), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_STATE), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_MASK), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_PERIOD), diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index d2a1bfb24..4d30f54e2 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -356,6 +356,19 @@ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aTh return sRadioSpinel.SetCcaEnergyDetectThreshold(aThreshold); } +otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + assert(aGain != nullptr); + return sRadioSpinel.GetFemLnaGain(*aGain); +} + +otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.SetFemLnaGain(aGain); +} + int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); diff --git a/tests/scripts/expect/cli-misc.exp b/tests/scripts/expect/cli-misc.exp index ccdb9f3e7..999efd1e5 100755 --- a/tests/scripts/expect/cli-misc.exp +++ b/tests/scripts/expect/cli-misc.exp @@ -66,6 +66,15 @@ send "delaytimermin 1 2\n" send "counters mac 1\n" expect "Error 7: InvalidArgs" +send "fem lnagain 11\n" +expect "Done" +send "fem lnagain\n" +expect -- "11" +expect "Done" +send "fem\n" +expect -- "LNA gain 11 dBm" +expect "Done" + send "ifconfig down\n" expect "Done" send "ifconfig\n"