diff --git a/.github/workflows/simulation-1.2.yml b/.github/workflows/simulation-1.2.yml index d0d5fc4fc..06eb8c152 100644 --- a/.github/workflows/simulation-1.2.yml +++ b/.github/workflows/simulation-1.2.yml @@ -98,3 +98,29 @@ jobs: - name: Codecov run: | bash <(curl -s https://codecov.io/bash) -x "${{ matrix.compiler.gcov }}" -Z + + expects: + runs-on: ubuntu-18.04 + env: + COVERAGE: 1 + THREAD_VERSION: 1.2 + VIRTUAL_TIME: 0 + steps: + - uses: actions/checkout@v2 + - name: Bootstrap + run: | + sudo apt-get --no-install-recommends install -y expect ninja-build + - name: Run RCP Mode + run: | + OT_OPTIONS=-DOT_READLINE=OFF NODE_MODE=rcp ./script/test build expect + - name: Keep-1-2-only + run: | + ./script/test tar posix 1.2-bbr + ./script/test tar simulation 1.2-bbr + - name: Keep POSIX Only + run: | + ./script/test tar simulation 1.2 + - name: Codecov + uses: codecov/codecov-action@v1 + with: + fail_ci_if_error: true diff --git a/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h b/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h index 47854e8a1..c4cfa9a24 100644 --- a/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h +++ b/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h @@ -150,6 +150,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE + * + * Define to 1 to enable software transmission target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE * diff --git a/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h b/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h index d61579d0b..e037cd9d0 100644 --- a/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h +++ b/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h @@ -172,6 +172,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE + * + * Define to 1 to enable software transmission target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE * diff --git a/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h b/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h index a312d84bb..23c10ac95 100644 --- a/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h +++ b/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h @@ -172,6 +172,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE + * + * Define to 1 to enable software transmission target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE * diff --git a/examples/platforms/simulation/openthread-core-simulation-config.h b/examples/platforms/simulation/openthread-core-simulation-config.h index e8c0c6fbb..89def7712 100644 --- a/examples/platforms/simulation/openthread-core-simulation-config.h +++ b/examples/platforms/simulation/openthread-core-simulation-config.h @@ -117,6 +117,16 @@ #ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #endif + +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE + * + * Define to 1 to enable software transmission target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#endif #endif // OPENTHREAD_RADIO /** diff --git a/include/openthread/platform/radio.h b/include/openthread/platform/radio.h index 7b0c039a3..c5d5b39b2 100644 --- a/include/openthread/platform/radio.h +++ b/include/openthread/platform/radio.h @@ -125,6 +125,7 @@ enum OT_RADIO_CAPS_CSMA_BACKOFF = 1 << 3, ///< Radio supports CSMA backoff for frame transmission (but no retry). OT_RADIO_CAPS_SLEEP_TO_TX = 1 << 4, ///< Radio supports direct transition from sleep to TX with CSMA. OT_RADIO_CAPS_TRANSMIT_SEC = 1 << 5, ///< Radio supports tx security. + OT_RADIO_CAPS_TRANSMIT_TIMING = 1 << 6, ///< Radio supports tx at specific time. }; #define OT_PANID_BROADCAST 0xffff ///< IEEE 802.15.4 Broadcast PAN ID @@ -516,6 +517,17 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun */ uint64_t otPlatRadioGetNow(otInstance *aInstance); +/** + * Get the bus speed in bits/second between the host and the radio chip. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The bus speed in bits/second between the host and the radio chip. + * Return 0 when the MAC and above layer and Radio layer resides on the same chip. + * + */ +uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance); + /** * @} * diff --git a/script/test b/script/test index 050770bd7..ae8e5a1d7 100755 --- a/script/test +++ b/script/test @@ -233,12 +233,16 @@ do_expect() { local ot_command local rcp_command= + local mtd_command= local test_patterns if [[ ${NODE_MODE} == rcp ]]; then ot_command="${OT_CLI_PATH}" rcp_command="${RADIO_DEVICE}" - if [[ ${OT_NATIVE_IP} == 1 ]]; then + if [[ ${THREAD_VERSION} == "1.2" ]]; then + mtd_command="${OT_BUILDDIR}/cmake/openthread-simulation-${THREAD_VERSION}/examples/apps/cli/ot-cli-mtd" + test_patterns=(-name 'v1_2-*.exp') + elif [[ ${OT_NATIVE_IP} == 1 ]]; then test_patterns=(-name 'tun-*.exp') else test_patterns=(-name 'posix-*.exp' -o -name 'cli-*.exp') @@ -254,9 +258,9 @@ do_expect() mkdir tmp { if [[ ${OT_NATIVE_IP} == 1 ]]; then - OT_COMMAND="${ot_command}" RCP_COMMAND="${rcp_command}" sudo -E expect -df "${script}" 2>"${log_file}" + OT_COMMAND="${ot_command}" RCP_COMMAND="${rcp_command}" MTD_COMMAND="${mtd_command}" sudo -E expect -df "${script}" 2>"${log_file}" else - OT_COMMAND="${ot_command}" RCP_COMMAND="${rcp_command}" expect -df "${script}" 2>"${log_file}" + OT_COMMAND="${ot_command}" RCP_COMMAND="${rcp_command}" MTD_COMMAND="${mtd_command}" expect -df "${script}" 2>"${log_file}" fi } || { local exit_code=$? diff --git a/src/core/config/mac.h b/src/core/config/mac.h index 6f4be094e..0aeb921b3 100644 --- a/src/core/config/mac.h +++ b/src/core/config/mac.h @@ -139,6 +139,16 @@ #define OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS 4 #endif +/** + * @def OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US + * + * Define how many microseconds ahead should MAC deliver CSL frame to SubMac. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US +#define OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US 2000 +#endif + /** * @def OPENTHREAD_CONFIG_MAC_FILTER_ENABLE * @@ -295,6 +305,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE 0 #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE + * + * Define to 1 to enable software transmission target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE 0 +#endif + /** * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_ENERGY_SCAN_ENABLE * @@ -312,7 +332,7 @@ * */ #define OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE \ - (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && OPENTHREAD_FTD + (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && (OPENTHREAD_FTD || OPENTHREAD_RADIO) /** * @def OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE diff --git a/src/core/config/openthread-core-config-check.h b/src/core/config/openthread-core-config-check.h index 788c10edc..5b537aaaf 100644 --- a/src/core/config/openthread-core-config-check.h +++ b/src/core/config/openthread-core-config-check.h @@ -506,8 +506,8 @@ #if (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2) #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE" #endif -#if (!OPENTHREAD_FTD) -#error "FTD is required for OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE" +#if (!OPENTHREAD_FTD && !OPENTHREAD_RADIO) +#error "FTD or RADIO is required for OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE" #endif #endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE diff --git a/src/core/mac/sub_mac.cpp b/src/core/mac/sub_mac.cpp index 03d04c45e..790426cc8 100644 --- a/src/core/mac/sub_mac.cpp +++ b/src/core/mac/sub_mac.cpp @@ -105,9 +105,13 @@ otRadioCaps SubMac::GetCaps(void) const caps |= OT_RADIO_CAPS_TRANSMIT_SEC; #endif +#if OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE + caps |= OT_RADIO_CAPS_TRANSMIT_TIMING; +#endif + #else caps = OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES | - OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_TRANSMIT_SEC; + OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING; #endif return caps; @@ -341,18 +345,26 @@ void SubMac::StartCsmaBackoff(void) #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE if (mTransmitFrame.mInfo.mTxInfo.mPeriod != 0) { - uint32_t phaseNow = (otPlatTimeGet() / kUsPerTenSymbols) % mTransmitFrame.mInfo.mTxInfo.mPeriod; - uint32_t phaseDesired = mTransmitFrame.mInfo.mTxInfo.mPhase; - SetState(kStateCslTransmit); - if (phaseNow < phaseDesired) + if (ShouldHandleTransmitTargetTime()) { - mTimer.Start((phaseDesired - phaseNow) * kUsPerTenSymbols); - } - else if (phaseNow > phaseDesired) - { - mTimer.Start((phaseDesired + mTransmitFrame.mInfo.mTxInfo.mPeriod - phaseNow) * kUsPerTenSymbols); + uint32_t phaseNow = + (otPlatRadioGetNow(&GetInstance()) / kUsPerTenSymbols) % mTransmitFrame.mInfo.mTxInfo.mPeriod; + uint32_t phaseDesired = mTransmitFrame.mInfo.mTxInfo.mPhase; + + if (phaseNow < phaseDesired) + { + mTimer.Start((phaseDesired - phaseNow) * kUsPerTenSymbols); + } + else if (phaseNow > phaseDesired) + { + mTimer.Start((phaseDesired + mTransmitFrame.mInfo.mTxInfo.mPeriod - phaseNow) * kUsPerTenSymbols); + } + else + { + BeginTransmit(); + } } else { @@ -759,6 +771,24 @@ exit: return swEnergyScan; } +bool SubMac::ShouldHandleTransmitTargetTime(void) const +{ + bool swTxDelay = true; + + VerifyOrExit(!RadioSupportsTransmitTiming(), swTxDelay = false); + +#if OPENTHREAD_CONFIG_LINK_RAW_ENABLE + VerifyOrExit(Get().IsEnabled(), OT_NOOP); +#endif + +#if OPENTHREAD_CONFIG_LINK_RAW_ENABLE || OPENTHREAD_RADIO + swTxDelay = OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE; +#endif + +exit: + return swTxDelay; +} + void SubMac::SetState(State aState) { if (mState != aState) diff --git a/src/core/mac/sub_mac.hpp b/src/core/mac/sub_mac.hpp index b00579a70..3ec42a9dd 100644 --- a/src/core/mac/sub_mac.hpp +++ b/src/core/mac/sub_mac.hpp @@ -549,12 +549,14 @@ private: bool RadioSupportsRetries(void) const { return ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) != 0); } bool RadioSupportsAckTimeout(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) != 0); } bool RadioSupportsEnergyScan(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN) != 0); } + bool RadioSupportsTransmitTiming(void) const { return ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_TIMING) != 0); } bool ShouldHandleTransmitSecurity(void) const; bool ShouldHandleCsmaBackOff(void) const; bool ShouldHandleAckTimeout(void) const; bool ShouldHandleRetries(void) const; bool ShouldHandleEnergyScan(void) const; + bool ShouldHandleTransmitTargetTime(void) const; void ProcessTransmitSecurity(void); void UpdateFrameCounter(uint32_t aFrameCounter); diff --git a/src/core/radio/radio_platform.cpp b/src/core/radio/radio_platform.cpp index 06d8b1b0d..a88b72999 100644 --- a/src/core/radio/radio_platform.cpp +++ b/src/core/radio/radio_platform.cpp @@ -158,3 +158,10 @@ OT_TOOL_WEAK uint64_t otPlatRadioGetNow(otInstance *aInstance) return UINT64_MAX; } + +OT_TOOL_WEAK uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return 0; +} diff --git a/src/core/thread/csl_tx_scheduler.cpp b/src/core/thread/csl_tx_scheduler.cpp index cf0d5327d..61cc73f6d 100644 --- a/src/core/thread/csl_tx_scheduler.cpp +++ b/src/core/thread/csl_tx_scheduler.cpp @@ -66,6 +66,18 @@ CslTxScheduler::CslTxScheduler(Instance &aInstance) , mFrameContext() , mCallbacks(aInstance) { + InitFrameRequestAhead(); +} + +void CslTxScheduler::InitFrameRequestAhead(void) +{ + uint32_t busSpeedHz = otPlatRadioGetBusSpeed(&GetInstance()); + // longest frame on bus is 127 bytes with some metadata, use 150 bytes for bus Tx time estimation + uint32_t busTxTimeUs = ((busSpeedHz == 0) ? 0 : (150 * 8 * 1000000 + busSpeedHz - 1) / busSpeedHz); + + // Use ceiling to get next closest integer + mCslFrameRequestAhead = + (OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US + busTxTimeUs + kUsPerTenSymbols - 1) / kUsPerTenSymbols; } void CslTxScheduler::Update(void) @@ -144,15 +156,14 @@ uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const Child &aChild, uint64 uint32_t delay; uint16_t period_offset = (aRadioNow / kUsPerTenSymbols) % aChild.GetCslPeriod(); - if (aChild.GetCslPhase() > period_offset + kCslFrameRequestAheadThreshold) + if (aChild.GetCslPhase() > period_offset + mCslFrameRequestAhead) { - delay = static_cast(aChild.GetCslPhase() - period_offset - kCslFrameRequestAheadThreshold) * - kUsPerTenSymbols; + delay = static_cast(aChild.GetCslPhase() - period_offset - mCslFrameRequestAhead) * kUsPerTenSymbols; } else { delay = static_cast(aChild.GetCslPeriod() + aChild.GetCslPhase() - period_offset - - kCslFrameRequestAheadThreshold) * + mCslFrameRequestAhead) * kUsPerTenSymbols; } diff --git a/src/core/thread/csl_tx_scheduler.hpp b/src/core/thread/csl_tx_scheduler.hpp index d534dcd22..bc16d2979 100644 --- a/src/core/thread/csl_tx_scheduler.hpp +++ b/src/core/thread/csl_tx_scheduler.hpp @@ -65,8 +65,7 @@ class CslTxScheduler : public InstanceLocator public: enum { - kMaxCslTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS, - kCslFrameRequestAheadThreshold = 2000 / kUsPerTenSymbols, + kMaxCslTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS, }; /** @@ -187,6 +186,7 @@ public: void Clear(void); private: + void InitFrameRequestAhead(void); void RescheduleCslTx(void); uint32_t GetNextCslTransmissionDelay(const Child &aChild, uint64_t aRadioNow); @@ -197,6 +197,7 @@ private: void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError, Child &aChild); + uint32_t mCslFrameRequestAhead; Child * mCslTxChild; Message * mCslTxMessage; Callbacks::FrameContext mFrameContext; diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index c228a5a14..8048abf9f 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -669,6 +669,14 @@ public: */ uint64_t GetNow(void); + /** + * This method returns the bus speed between the host and the radio. + * + * @returns bus speed in bits/second. + * + */ + uint32_t GetBusSpeed(void) const; + private: enum { diff --git a/src/lib/spinel/radio_spinel_impl.hpp b/src/lib/spinel/radio_spinel_impl.hpp index b8f795696..8bd741b6f 100644 --- a/src/lib/spinel/radio_spinel_impl.hpp +++ b/src/lib/spinel/radio_spinel_impl.hpp @@ -304,6 +304,9 @@ template otError RadioSpinel::CheckRadioCapabilities(void) { const otRadioCaps kRequiredRadioCaps = +#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE + OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING | +#endif OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_TRANSMIT_RETRIES | OT_RADIO_CAPS_CSMA_BACKOFF; otError error = OT_ERROR_NONE; @@ -317,10 +320,14 @@ otError RadioSpinel::CheckRadioCapabilities(v if ((mRadioCaps & kRequiredRadioCaps) != kRequiredRadioCaps) { - otLogCritPlat("RCP does not support required capabilities: ack-timeout:%s, tx-retries:%s, CSMA-backoff:%s", - (mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) ? "yes" : "no", - (mRadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) ? "yes" : "no", - (mRadioCaps & OT_RADIO_CAPS_CSMA_BACKOFF) ? "yes" : "no"); + otRadioCaps missingCaps = (mRadioCaps & kRequiredRadioCaps) ^ kRequiredRadioCaps; + + otLogCritPlat("RCP is missing required capabilities: %s%s%s%s%s", + (missingCaps & OT_RADIO_CAPS_ACK_TIMEOUT) ? "ack-timeout " : "", + (missingCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) ? "tx-retries " : "", + (missingCaps & OT_RADIO_CAPS_CSMA_BACKOFF) ? "CSMA-backoff " : "", + (missingCaps & OT_RADIO_CAPS_TRANSMIT_SEC) ? "tx-security " : "", + (missingCaps & OT_RADIO_CAPS_TRANSMIT_TIMING) ? "tx-timing " : ""); DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); } @@ -1555,17 +1562,20 @@ otError RadioSpinel::Transmit(otRadioFrame &a otPlatRadioTxStarted(mInstance, mTransmitFrame); error = Request(true, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_STREAM_RAW, - SPINEL_DATATYPE_DATA_WLEN_S // Frame data - SPINEL_DATATYPE_UINT8_S // Channel - SPINEL_DATATYPE_UINT8_S // MaxCsmaBackoffs - SPINEL_DATATYPE_UINT8_S // MaxFrameRetries - SPINEL_DATATYPE_BOOL_S // CsmaCaEnabled - SPINEL_DATATYPE_BOOL_S // IsARetx - SPINEL_DATATYPE_BOOL_S, // SkipAes + SPINEL_DATATYPE_DATA_WLEN_S // Frame data + SPINEL_DATATYPE_UINT8_S // Channel + SPINEL_DATATYPE_UINT8_S // MaxCsmaBackoffs + SPINEL_DATATYPE_UINT8_S // MaxFrameRetries + SPINEL_DATATYPE_BOOL_S // CsmaCaEnabled + SPINEL_DATATYPE_BOOL_S // IsARetx + SPINEL_DATATYPE_BOOL_S // SkipAes + SPINEL_DATATYPE_UINT16_S // Period + SPINEL_DATATYPE_UINT16_S, // Phase mTransmitFrame->mPsdu, mTransmitFrame->mLength, mTransmitFrame->mChannel, mTransmitFrame->mInfo.mTxInfo.mMaxCsmaBackoffs, mTransmitFrame->mInfo.mTxInfo.mMaxFrameRetries, mTransmitFrame->mInfo.mTxInfo.mCsmaCaEnabled, mTransmitFrame->mInfo.mTxInfo.mIsARetx, - mTransmitFrame->mInfo.mTxInfo.mIsSecurityProcessed); + mTransmitFrame->mInfo.mTxInfo.mIsSecurityProcessed, mTransmitFrame->mInfo.mTxInfo.mPeriod, + mTransmitFrame->mInfo.mTxInfo.mPhase); if (error == OT_ERROR_NONE) { @@ -1806,5 +1816,11 @@ uint64_t RadioSpinel::GetNow(void) return mIsTimeSynced ? (otPlatTimeGet() + static_cast(mRadioTimeOffset)) : UINT64_MAX; } +template +uint32_t RadioSpinel::GetBusSpeed(void) const +{ + return mSpinelInterface.GetBusSpeed(); +} + } // namespace Spinel } // namespace ot diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp index 8d3d4499d..25a349ec8 100644 --- a/src/ncp/ncp_base_radio.cpp +++ b/src/ncp/ncp_base_radio.cpp @@ -398,6 +398,8 @@ otError NcpBase::DecodeStreamRawTxRequest(otRadioFrame &aFrame) aFrame.mInfo.mTxInfo.mCsmaCaEnabled = true; aFrame.mInfo.mTxInfo.mIsARetx = false; aFrame.mInfo.mTxInfo.mIsSecurityProcessed = false; + aFrame.mInfo.mTxInfo.mPeriod = 0; + aFrame.mInfo.mTxInfo.mPhase = 0; // All the next parameters are optional. Note that even if the // decoder fails to parse any of optional parameters we still want to @@ -409,6 +411,8 @@ otError NcpBase::DecodeStreamRawTxRequest(otRadioFrame &aFrame) SuccessOrExit(mDecoder.ReadBool(csmaEnable)); SuccessOrExit(mDecoder.ReadBool(isARetx)); SuccessOrExit(mDecoder.ReadBool(isSecurityProcessed)); + SuccessOrExit(mDecoder.ReadUint16(aFrame.mInfo.mTxInfo.mPeriod)); + SuccessOrExit(mDecoder.ReadUint16(aFrame.mInfo.mTxInfo.mPhase)); aFrame.mInfo.mTxInfo.mCsmaCaEnabled = csmaEnable; aFrame.mInfo.mTxInfo.mIsARetx = isARetx; aFrame.mInfo.mTxInfo.mIsSecurityProcessed = isSecurityProcessed; diff --git a/src/posix/platform/hdlc_interface.cpp b/src/posix/platform/hdlc_interface.cpp index 9ae3573b4..586678af7 100644 --- a/src/posix/platform/hdlc_interface.cpp +++ b/src/posix/platform/hdlc_interface.cpp @@ -134,6 +134,7 @@ HdlcInterface::HdlcInterface(SpinelInterface::ReceiveFrameCallback aCallback, , mReceiveFrameContext(aCallbackContext) , mReceiveFrameBuffer(aFrameBuffer) , mSockFd(-1) + , mBaudRate(0) , mHdlcDecoder(aFrameBuffer, HandleHdlcFrame, this) { } @@ -563,6 +564,8 @@ int HdlcInterface::OpenFile(const RadioUrl &aRadioUrl) break; } + mBaudRate = baudrate; + if (aRadioUrl.GetValue("uart-flow-control") != nullptr) { tios.c_cflag |= CRTSCTS; diff --git a/src/posix/platform/hdlc_interface.hpp b/src/posix/platform/hdlc_interface.hpp index 2db2400e2..ef93a669c 100644 --- a/src/posix/platform/hdlc_interface.hpp +++ b/src/posix/platform/hdlc_interface.hpp @@ -148,6 +148,14 @@ public: void Process(const VirtualTimeEvent &aEvent) { Decode(aEvent.mData, aEvent.mDataLength); } #endif + /** + * This method returns the bus speed between the host and the radio. + * + * @returns Bus speed in bits/second. + * + */ + uint32_t GetBusSpeed(void) const { return mBaudRate; } + private: /** * This method instructs `HdlcInterface` to read and decode data from radio over the socket. @@ -198,7 +206,7 @@ private: static void HandleHdlcFrame(void *aContext, otError aError); void HandleHdlcFrame(otError aError); - static int OpenFile(const RadioUrl &aRadioUrl); + int OpenFile(const RadioUrl &aRadioUrl); #if OPENTHREAD_POSIX_CONFIG_RCP_PTY_ENABLE static int ForkPty(const char *aCommand, const char *aRadioUrl); #endif @@ -214,6 +222,7 @@ private: Spinel::SpinelInterface::RxFrameBuffer & mReceiveFrameBuffer; int mSockFd; + uint32_t mBaudRate; Hdlc::Decoder mHdlcDecoder; // Non-copyable, intentionally not implemented. diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index 721f71100..d2a1bfb24 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -508,3 +508,9 @@ uint64_t otPlatRadioGetNow(otInstance *aInstance) OT_UNUSED_VARIABLE(aInstance); return sRadioSpinel.GetNow(); } + +uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetBusSpeed(); +} diff --git a/src/posix/platform/spi_interface.hpp b/src/posix/platform/spi_interface.hpp index de3414530..06cdca7b4 100644 --- a/src/posix/platform/spi_interface.hpp +++ b/src/posix/platform/spi_interface.hpp @@ -138,6 +138,14 @@ public: */ void Process(const RadioProcessContext &aContext); + /** + * This method returns the bus speed between the host and the radio. + * + * @returns Bus speed in bits/second. + * + */ + uint32_t GetBusSpeed(void) const { return ((mSpiDevFd >= 0) ? mSpiSpeedHz : 0); } + private: int SetupGpioHandle(int aFd, uint8_t aLine, uint32_t aHandleFlags, const char *aLabel); int SetupGpioEvent(int aFd, uint8_t aLine, uint32_t aHandleFlags, uint32_t aEventFlags, const char *aLabel); diff --git a/tests/scripts/expect/v1_2-rcp.exp b/tests/scripts/expect/v1_2-rcp.exp new file mode 100755 index 000000000..9edac4937 --- /dev/null +++ b/tests/scripts/expect/v1_2-rcp.exp @@ -0,0 +1,73 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2020, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +source "tests/scripts/expect/_common.exp" + +set node_1 [spawn_node 1] +set spawn_id $node_1 + +send "panid 0xface\n" +expect "Done" +send "ifconfig up\n" +expect "Done" +send "thread start\n" +expect "Done" +wait_for "state" "leader" +expect "Done" + +send "ipaddr\n" +expect -re {(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4})} +set addr $expect_out(1,string) +expect "Done" + +spawn $env(MTD_COMMAND) "2" +set node_2 $spawn_id +expect_after { + timeout { exit 1 } +} + +send "panid 0xface\n" +expect "Done" +send "mode s\n" +expect "Done" +send "csl period 5000\n" +expect "Done" +send "ifconfig up\n" +expect "Done" +send "thread start\n" +expect "Done" +wait_for "state" "child" +expect "Done" +send "ping $addr\n" +expect "16 bytes from $addr: icmp_seq=1" + +dispose + +set spawn_id $node_1 +dispose diff --git a/tests/toranj/openthread-core-toranj-config.h b/tests/toranj/openthread-core-toranj-config.h index 15c6ff36f..989033c75 100644 --- a/tests/toranj/openthread-core-toranj-config.h +++ b/tests/toranj/openthread-core-toranj-config.h @@ -462,4 +462,12 @@ * */ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE 1 + +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE + * + * Define to 1 to enable software transmission target time logic. + * + */ +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE 1 #endif // OPENTHREAD_RADIO