mirror of
https://github.com/espressif/openthread.git
synced 2026-08-31 06:19:54 +00:00
[posix-app] check RCP capabilities and add support for stream log (#3215)
This commit contains the following changes: - It adds code to `RadioSpinel::Init()` to get and check the RCP capabilities (`SPINEL_PROP_CAPS`) ensuring RCP supports radio/raw mode (`SPINEL_CAP_MAC_RAW`). - It adds support for handling stream log `SPINEL_PROP_STREAM_LOG` property from RCP. - It moves the existing code checking spinel version and radio capabilities of RCP into helper methods `CheckSpinelVersion()` and `CheckRadioCapabilities()`.
This commit is contained in:
committed by
Jonathan Hui
parent
a1a67fd2b6
commit
9f2c56e620
@@ -508,6 +508,7 @@ RadioSpinel::RadioSpinel(void)
|
||||
, mIsDecoding(false)
|
||||
, mIsPromiscuous(false)
|
||||
, mIsReady(false)
|
||||
, mSupportsLogStream(false)
|
||||
#if OPENTHREAD_ENABLE_DIAG
|
||||
, mDiagMode(false)
|
||||
, mDiagOutput(NULL)
|
||||
@@ -544,41 +545,15 @@ void RadioSpinel::Init(const char *aRadioFile, const char *aRadioConfig)
|
||||
SuccessOrExit(error = WaitResponse());
|
||||
VerifyOrExit(mIsReady, error = OT_ERROR_FAILED);
|
||||
|
||||
SuccessOrExit(error = CheckSpinelVersion());
|
||||
SuccessOrExit(error = CheckCapabilities());
|
||||
SuccessOrExit(error = CheckRadioCapabilities());
|
||||
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_NCP_VERSION, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion)));
|
||||
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_UINT64_S, &gNodeId));
|
||||
gNodeId = ot::Encoding::BigEndian::HostSwap64(gNodeId);
|
||||
|
||||
{
|
||||
unsigned int versionMajor;
|
||||
unsigned int versionMinor;
|
||||
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_PROTOCOL_VERSION,
|
||||
(SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S), &versionMajor,
|
||||
&versionMinor));
|
||||
|
||||
if ((versionMajor != SPINEL_PROTOCOL_VERSION_THREAD_MAJOR) ||
|
||||
(versionMinor != SPINEL_PROTOCOL_VERSION_THREAD_MINOR))
|
||||
{
|
||||
otLogCritPlat("Spinel version mismatch - PosixApp:%d.%d, RCP:%d.%d", SPINEL_PROTOCOL_VERSION_THREAD_MAJOR,
|
||||
SPINEL_PROTOCOL_VERSION_THREAD_MINOR, versionMajor, versionMinor);
|
||||
exit(OT_EXIT_INCOMPATIBLE_RADIO_SPINEL);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const otRadioCaps kRequiredRadioCaps =
|
||||
OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_TRANSMIT_RETRIES | OT_RADIO_CAPS_CSMA_BACKOFF;
|
||||
unsigned int caps;
|
||||
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &caps));
|
||||
mRadioCaps = static_cast<otRadioCaps>(caps);
|
||||
if ((mRadioCaps & kRequiredRadioCaps) != kRequiredRadioCaps)
|
||||
{
|
||||
exit(OT_EXIT_INCOMPATIBLE_RADIO_SPINEL);
|
||||
}
|
||||
}
|
||||
|
||||
mRxRadioFrame.mPsdu = mRxPsdu;
|
||||
mTxRadioFrame.mPsdu = mTxPsdu;
|
||||
|
||||
@@ -586,6 +561,95 @@ exit:
|
||||
SuccessOrDie(error);
|
||||
}
|
||||
|
||||
otError RadioSpinel::CheckSpinelVersion(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
unsigned int versionMajor;
|
||||
unsigned int versionMinor;
|
||||
|
||||
SuccessOrExit(error =
|
||||
Get(SPINEL_PROP_PROTOCOL_VERSION, (SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S),
|
||||
&versionMajor, &versionMinor));
|
||||
|
||||
if ((versionMajor != SPINEL_PROTOCOL_VERSION_THREAD_MAJOR) ||
|
||||
(versionMinor != SPINEL_PROTOCOL_VERSION_THREAD_MINOR))
|
||||
{
|
||||
otLogCritPlat("Spinel version mismatch - PosixApp:%d.%d, RCP:%d.%d", SPINEL_PROTOCOL_VERSION_THREAD_MAJOR,
|
||||
SPINEL_PROTOCOL_VERSION_THREAD_MINOR, versionMajor, versionMinor);
|
||||
exit(OT_EXIT_INCOMPATIBLE_RADIO_SPINEL);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError RadioSpinel::CheckCapabilities(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t capsBuffer[kCapsBufferSize];
|
||||
const uint8_t *capsData = capsBuffer;
|
||||
spinel_size_t capsLength = sizeof(capsBuffer);
|
||||
bool supportsRawRadio = false;
|
||||
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength));
|
||||
|
||||
while (capsLength > 0)
|
||||
{
|
||||
unsigned int capability;
|
||||
spinel_ssize_t unpacked;
|
||||
|
||||
unpacked = spinel_datatype_unpack(capsData, capsLength, SPINEL_DATATYPE_UINT_PACKED_S, &capability);
|
||||
VerifyOrExit(unpacked > 0, error = OT_ERROR_FAILED);
|
||||
|
||||
if (capability == SPINEL_CAP_OPENTHREAD_LOG_METADATA)
|
||||
{
|
||||
mSupportsLogStream = true;
|
||||
}
|
||||
|
||||
if (capability == SPINEL_CAP_MAC_RAW)
|
||||
{
|
||||
supportsRawRadio = true;
|
||||
}
|
||||
|
||||
capsData += unpacked;
|
||||
capsLength -= static_cast<spinel_size_t>(unpacked);
|
||||
}
|
||||
|
||||
if (!supportsRawRadio)
|
||||
{
|
||||
otLogCritPlat("RCP capability list does not include support for radio/raw mode");
|
||||
exit(OT_EXIT_INCOMPATIBLE_RADIO_SPINEL);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError RadioSpinel::CheckRadioCapabilities(void)
|
||||
{
|
||||
const otRadioCaps kRequiredRadioCaps =
|
||||
OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_TRANSMIT_RETRIES | OT_RADIO_CAPS_CSMA_BACKOFF;
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
unsigned int caps;
|
||||
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &caps));
|
||||
mRadioCaps = static_cast<otRadioCaps>(caps);
|
||||
|
||||
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");
|
||||
|
||||
exit(OT_EXIT_INCOMPATIBLE_RADIO_SPINEL);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void RadioSpinel::Deinit(void)
|
||||
{
|
||||
// this function is only allowed after successfully initialized.
|
||||
@@ -817,7 +881,48 @@ void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer,
|
||||
assert(len < sizeof(logStream));
|
||||
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
|
||||
logStream[len] = '\0';
|
||||
otLogDebgPlat("RCP DEBUG INFO: %s", logStream);
|
||||
otLogDebgPlat("RCP => %s", logStream);
|
||||
}
|
||||
else if ((aKey == SPINEL_PROP_STREAM_LOG) && mSupportsLogStream)
|
||||
{
|
||||
const char * logString;
|
||||
spinel_ssize_t unpacked;
|
||||
uint8_t logLevel;
|
||||
|
||||
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, &logString);
|
||||
VerifyOrExit(unpacked >= 0, error = OT_ERROR_PARSE);
|
||||
aBuffer += unpacked;
|
||||
aLength -= unpacked;
|
||||
|
||||
unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S, &logLevel);
|
||||
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
|
||||
|
||||
switch (logLevel)
|
||||
{
|
||||
case SPINEL_NCP_LOG_LEVEL_EMERG:
|
||||
case SPINEL_NCP_LOG_LEVEL_ALERT:
|
||||
case SPINEL_NCP_LOG_LEVEL_CRIT:
|
||||
otLogCritPlat("RCP => %s", logString);
|
||||
break;
|
||||
|
||||
case SPINEL_NCP_LOG_LEVEL_ERR:
|
||||
case SPINEL_NCP_LOG_LEVEL_WARN:
|
||||
otLogWarnPlat("RCP => %s", logString);
|
||||
break;
|
||||
|
||||
case SPINEL_NCP_LOG_LEVEL_NOTICE:
|
||||
otLogNotePlat("RCP => %s", logString);
|
||||
break;
|
||||
|
||||
case SPINEL_NCP_LOG_LEVEL_INFO:
|
||||
otLogInfoPlat("RCP => %s", logString);
|
||||
break;
|
||||
|
||||
case SPINEL_NCP_LOG_LEVEL_DEBUG:
|
||||
default:
|
||||
otLogDebgPlat("RCP => %s", logString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
@@ -445,8 +445,12 @@ private:
|
||||
kMaxSpinelFrame = 2048, ///< Max size in bytes for transferring spinel frames.
|
||||
kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds.
|
||||
kVersionStringSize = 128, ///< Max size of version string.
|
||||
kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value.
|
||||
};
|
||||
|
||||
otError CheckSpinelVersion(void);
|
||||
otError CheckCapabilities(void);
|
||||
otError CheckRadioCapabilities(void);
|
||||
void DecodeHdlc(const uint8_t *aData, uint16_t aLength);
|
||||
void ReadAll(void);
|
||||
otError WriteAll(const uint8_t *aBuffer, uint16_t aLength);
|
||||
@@ -591,10 +595,11 @@ private:
|
||||
|
||||
int mSockFd;
|
||||
otRadioState mState;
|
||||
bool mIsAckRequested : 1; ///< Ack requested.
|
||||
bool mIsDecoding : 1; ///< Decoding hdlc frames.
|
||||
bool mIsPromiscuous : 1; ///< Promiscuous mode.
|
||||
bool mIsReady : 1; ///< NCP ready.
|
||||
bool mIsAckRequested : 1; ///< Ack requested.
|
||||
bool mIsDecoding : 1; ///< Decoding hdlc frames.
|
||||
bool mIsPromiscuous : 1; ///< Promiscuous mode.
|
||||
bool mIsReady : 1; ///< NCP ready.
|
||||
bool mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
|
||||
|
||||
#if OPENTHREAD_ENABLE_DIAG
|
||||
bool mDiagMode;
|
||||
|
||||
@@ -170,6 +170,14 @@
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_LOG_SUFFIX ""
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_LOG_PLATFORM
|
||||
*
|
||||
* Define to enable platform region logging.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_LOG_PLATFORM 1
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user