diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 53a0e488cb0e6b..8ee3ea7e957aa1 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -48,6 +48,8 @@ CHIP_ERROR InteractionModelEngine::Init(Messaging::ExchangeManager * apExchangeM mMagic++; + StatusIB::RegisterErrorFormatter(); + return CHIP_NO_ERROR; } diff --git a/src/app/MessageDef/StatusIB.cpp b/src/app/MessageDef/StatusIB.cpp index cedf3946bf2d53..2e3e85c0dea06e 100644 --- a/src/app/MessageDef/StatusIB.cpp +++ b/src/app/MessageDef/StatusIB.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include using namespace chip; using namespace chip::TLV; @@ -183,5 +185,49 @@ void StatusIB::InitFromChipError(CHIP_ERROR aError) mStatus = Status::Failure; } +namespace { +bool FormatStatusIBError(char * buf, uint16_t bufSize, CHIP_ERROR err) +{ + if (!err.IsIMStatus()) + { + return false; + } + + const char * desc = nullptr; +#if !CHIP_CONFIG_SHORT_ERROR_STR + constexpr char generalFormat[] = "General error: 0x%02" PRIx8; + constexpr char clusterFormat[] = "Cluster-specific error: 0x%02" PRIx8; + + // Formatting an 8-bit int will take at most 2 chars, and replace the '%' + // and the format letter(s) for PRIx8, so a buffer big enough to hold our + // format string will also hold our formatted string. + constexpr size_t formattedSize = max(sizeof(generalFormat), sizeof(clusterFormat)); + char formattedString[formattedSize]; + + StatusIB status; + status.InitFromChipError(err); + if (status.mClusterStatus.HasValue()) + { + snprintf(formattedString, formattedSize, clusterFormat, status.mClusterStatus.Value()); + } + else + { + snprintf(formattedString, formattedSize, generalFormat, status.mStatus); + } + desc = formattedString; +#endif // !CHIP_CONFIG_SHORT_ERROR_STR + FormatError(buf, bufSize, "IM", err, desc); + + return true; +} +} // anonymous namespace + +void StatusIB::RegisterErrorFormatter() +{ + static ErrorFormatter sStatusIBErrorFormatter = { FormatStatusIBError, nullptr }; + + ::RegisterErrorFormatter(&sStatusIBErrorFormatter); +} + }; // namespace app }; // namespace chip diff --git a/src/app/MessageDef/StatusIB.h b/src/app/MessageDef/StatusIB.h index 7df3b0ce5a46f8..0f9a72bc07d1b6 100644 --- a/src/app/MessageDef/StatusIB.h +++ b/src/app/MessageDef/StatusIB.h @@ -110,6 +110,11 @@ struct StatusIB */ void InitFromChipError(CHIP_ERROR aError); + /** + * Register the StatusIB error formatter. + */ + static void RegisterErrorFormatter(); + Protocols::InteractionModel::Status mStatus = Protocols::InteractionModel::Status::Success; Optional mClusterStatus = Optional::Missing(); diff --git a/src/app/tests/TestStatusIB.cpp b/src/app/tests/TestStatusIB.cpp index 3438a34df5e74e..82da6dfd53d14a 100644 --- a/src/app/tests/TestStatusIB.cpp +++ b/src/app/tests/TestStatusIB.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -88,10 +89,30 @@ void TestStatusIBToFromChipError(nlTestSuite * aSuite, void * aContext) } } +#if !CHIP_CONFIG_SHORT_ERROR_STR +void TestStatusIBErrorToString(nlTestSuite * aSuite, void * aContext) +{ + StatusIB status; + status.mStatus = Status::InvalidAction; + CHIP_ERROR err = status.ToChipError(); + const char * str = ErrorStr(err); + NL_TEST_ASSERT(aSuite, strcmp(str, "IM Error 0x00000580: General error: 0x80") == 0); + + status.mStatus = Status::Failure; + status.mClusterStatus = MakeOptional(static_cast(5)); + err = status.ToChipError(); + str = ErrorStr(err); + NL_TEST_ASSERT(aSuite, strcmp(str, "IM Error 0x00000605: Cluster-specific error: 0x05") == 0); +} +#endif // !CHIP_CONFIG_SHORT_ERROR_STR + // clang-format off const nlTest sTests[] = { NL_TEST_DEF("StatusIBToFromChipError", TestStatusIBToFromChipError), +#if !CHIP_CONFIG_SHORT_ERROR_STR + NL_TEST_DEF("StatusIBErrorToString", TestStatusIBErrorToString), +#endif // !CHIP_CONFIG_SHORT_ERROR_STR NL_TEST_SENTINEL() }; // clang-format on @@ -105,6 +126,9 @@ static int TestSetup(void * inContext) CHIP_ERROR error = chip::Platform::MemoryInit(); if (error != CHIP_NO_ERROR) return FAILURE; + // Hand-register the error formatter. Normally it's registered by + // InteractionModelEngine::Init, but we don't want to mess with that here. + StatusIB::RegisterErrorFormatter(); return SUCCESS; }