From 0944982ee0191d3e2aed8a3d3770c0b49cf3943e Mon Sep 17 00:00:00 2001 From: Erwin Pan Date: Wed, 28 Aug 2024 07:44:56 +0800 Subject: [PATCH] [Chef] BasicVideoPlayer: Fix MediaInput and MediaPlayback not reporting attribute changes due to using AttributeAccessInterface (#35122) * Fix media-input accessinterface 1. SelectInput command won't call reportData since MatterReportingAttributeChangeCallback isn't called 2. PW RPC Writing CurrentInput attribute of MediaInput cluster through won't reportData. The value is also mismatch with PW RPC Read. (But this is still under WIP and not working) * Not writing the MediaInput cluster through RPC * Remove unused function HandleSetCurrentInput * Move all attributes logic to Chef application * Fix typo * Fix CurrentState(Playback Cluster) not report data * Restyled by whitespace * Restyled by clang-format * Set CurrentState & PlaybackSpeed in MediaPlayback cluster * Set some attributes to persist (NVM) * Remove mPlaybackSpeed/mCurrentState/mCurrentInput * modify playSpeed from 1.0 to 1 * Restyled by clang-format * Fix type in error messages * Restyled by clang-format --------- Co-authored-by: Restyled.io --- .../media-input/MediaInputManager.cpp | 51 ++++++-- .../clusters/media-input/MediaInputManager.h | 4 +- .../media-playback/MediaPlaybackManager.cpp | 114 +++++++++++++----- .../media-playback/MediaPlaybackManager.h | 11 +- examples/chef/common/stubs.cpp | 21 ---- ...ootnode_basicvideoplayer_0ff86e943b.matter | 16 +-- .../rootnode_basicvideoplayer_0ff86e943b.zap | 16 +-- 7 files changed, 149 insertions(+), 84 deletions(-) diff --git a/examples/chef/common/clusters/media-input/MediaInputManager.cpp b/examples/chef/common/clusters/media-input/MediaInputManager.cpp index f7e853cc46a40b..53cc22cd65cce8 100644 --- a/examples/chef/common/clusters/media-input/MediaInputManager.cpp +++ b/examples/chef/common/clusters/media-input/MediaInputManager.cpp @@ -15,27 +15,26 @@ * limitations under the License. */ +#include #include +#include + #ifdef MATTER_DM_PLUGIN_MEDIA_INPUT_SERVER #include "MediaInputManager.h" using namespace std; using namespace chip; using namespace chip::app::Clusters::MediaInput; +using Protocols::InteractionModel::Status; -MediaInputManager::MediaInputManager() +MediaInputManager::MediaInputManager(chip::EndpointId endpoint) : mEndpoint(endpoint) { - struct InputData inputData1(1, chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi, "HDMI 1", - "High-Definition Multimedia Interface"); + struct InputData inputData1(1, InputTypeEnum::kHdmi, "HDMI 1", "High-Definition Multimedia Interface"); mInputs.push_back(inputData1); - struct InputData inputData2(2, chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi, "HDMI 2", - "High-Definition Multimedia Interface"); + struct InputData inputData2(2, InputTypeEnum::kHdmi, "HDMI 2", "High-Definition Multimedia Interface"); mInputs.push_back(inputData2); - struct InputData inputData3(3, chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi, "HDMI 3", - "High-Definition Multimedia Interface"); + struct InputData inputData3(3, InputTypeEnum::kHdmi, "HDMI 3", "High-Definition Multimedia Interface"); mInputs.push_back(inputData3); - - mCurrentInput = 1; } CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) @@ -51,16 +50,32 @@ CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncode uint8_t MediaInputManager::HandleGetCurrentInput() { - return mCurrentInput; + uint8_t currentInput = 1; + Status status = Attributes::CurrentInput::Get(mEndpoint, ¤tInput); + if (Status::Success != status) + { + ChipLogError(Zcl, "Unable to get CurrentInput attribute, err:0x%x", to_underlying(status)); + } + return currentInput; } bool MediaInputManager::HandleSelectInput(const uint8_t index) { + if (HandleGetCurrentInput() == index) + { + ChipLogProgress(Zcl, "CurrentInput is same as new value: %u", index); + return true; + } for (auto const & inputData : mInputs) { if (inputData.index == index) { - mCurrentInput = index; + // Sync the CurrentInput to attribute storage while reporting changes + Status status = Attributes::CurrentInput::Set(mEndpoint, index); + if (Status::Success != status) + { + ChipLogError(Zcl, "CurrentInput is not stored successfully, err:0x%x", to_underlying(status)); + } return true; } } @@ -70,11 +85,12 @@ bool MediaInputManager::HandleSelectInput(const uint8_t index) bool MediaInputManager::HandleShowInputStatus() { + uint8_t currentInput = HandleGetCurrentInput(); ChipLogProgress(Zcl, " MediaInputManager::HandleShowInputStatus()"); for (auto const & inputData : mInputs) { ChipLogProgress(Zcl, " [%d] type=%d selected=%d name=%s desc=%s", inputData.index, - static_cast(inputData.inputType), (mCurrentInput == inputData.index ? 1 : 0), + static_cast(inputData.inputType), (currentInput == inputData.index ? 1 : 0), inputData.name.c_str(), inputData.description.c_str()); } return true; @@ -99,4 +115,15 @@ bool MediaInputManager::HandleRenameInput(const uint8_t index, const chip::CharS return false; } + +static std::map> gMediaInputManagerInstance{}; + +void emberAfMediaInputClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: MediaInput::SetDefaultDelegate, endpoint=%x", endpoint); + + gMediaInputManagerInstance[endpoint] = std::make_unique(endpoint); + + SetDefaultDelegate(endpoint, gMediaInputManagerInstance[endpoint].get()); +} #endif // MATTER_DM_PLUGIN_MEDIA_INPUT_SERVER diff --git a/examples/chef/common/clusters/media-input/MediaInputManager.h b/examples/chef/common/clusters/media-input/MediaInputManager.h index e5b88c5a7a67d5..d922d5aa650b59 100644 --- a/examples/chef/common/clusters/media-input/MediaInputManager.h +++ b/examples/chef/common/clusters/media-input/MediaInputManager.h @@ -29,7 +29,7 @@ class MediaInputManager : public chip::app::Clusters::MediaInput::Delegate using InputInfoType = chip::app::Clusters::MediaInput::Structs::InputInfoStruct::Type; public: - MediaInputManager(); + MediaInputManager(chip::EndpointId endpoint); CHIP_ERROR HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) override; uint8_t HandleGetCurrentInput() override; @@ -63,7 +63,7 @@ class MediaInputManager : public chip::app::Clusters::MediaInput::Delegate }; protected: - uint8_t mCurrentInput; + chip::EndpointId mEndpoint; std::vector mInputs; private: diff --git a/examples/chef/common/clusters/media-playback/MediaPlaybackManager.cpp b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.cpp index 14be124252a7c0..db3af119c5b286 100644 --- a/examples/chef/common/clusters/media-playback/MediaPlaybackManager.cpp +++ b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.cpp @@ -15,26 +15,34 @@ * limitations under the License. */ -#include -#ifdef MATTER_DM_PLUGIN_MEDIA_PLAYBACK_SERVER -#include "MediaPlaybackManager.h" #include #include - +#include #include +#ifdef MATTER_DM_PLUGIN_MEDIA_PLAYBACK_SERVER +#include "MediaPlaybackManager.h" using namespace std; +using namespace chip; +using namespace chip::app; using namespace chip::app::DataModel; using namespace chip::app::Clusters::MediaPlayback; -using namespace chip::Uint8; using chip::CharSpan; using chip::app::AttributeValueEncoder; using chip::app::CommandResponseHelper; +using chip::Protocols::InteractionModel::Status; PlaybackStateEnum MediaPlaybackManager::HandleGetCurrentState() { - return mCurrentState; + PlaybackStateEnum currentState = PlaybackStateEnum::kPlaying; + + Status status = Attributes::CurrentState::Get(mEndpoint, ¤tState); + if (Status::Success != status) + { + ChipLogError(Zcl, "Unable to get CurrentStage attribute, err:0x%x", to_underlying(status)); + } + return currentState; } uint64_t MediaPlaybackManager::HandleGetStartTime() @@ -54,7 +62,14 @@ CHIP_ERROR MediaPlaybackManager::HandleGetSampledPosition(AttributeValueEncoder float MediaPlaybackManager::HandleGetPlaybackSpeed() { - return mPlaybackSpeed; + float playbackSpeed = 1.0; + + Status status = Attributes::PlaybackSpeed::Get(mEndpoint, &playbackSpeed); + if (Status::Success != status) + { + ChipLogError(Zcl, "Unable to get PlaybackSpeed attribute, err:0x%x", to_underlying(status)); + } + return playbackSpeed; } uint64_t MediaPlaybackManager::HandleGetSeekRangeStart() @@ -99,10 +114,34 @@ CHIP_ERROR MediaPlaybackManager::HandleGetAvailableTextTracks(AttributeValueEnco }); } +CHIP_ERROR MediaPlaybackManager::HandleSetCurrentState(PlaybackStateEnum currentState) +{ + Status status = Attributes::CurrentState::Set(mEndpoint, currentState); + + if (Status::Success != status) + { + ChipLogError(Zcl, "Unable to set CurrentState attribute, 0x%x", to_underlying(status)); + } + + return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status); +} + +CHIP_ERROR MediaPlaybackManager::HandleSetPlaybackSpeed(float playbackSpeed) +{ + Status status = Attributes::PlaybackSpeed::Set(mEndpoint, playbackSpeed); + + if (Status::Success != status) + { + ChipLogError(Zcl, "Unable to set PlaybackSpeed attribute, 0x%x", to_underlying(status)); + } + + return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status); +} + void MediaPlaybackManager::HandlePlay(CommandResponseHelper & helper) { - mCurrentState = PlaybackStateEnum::kPlaying; - mPlaybackSpeed = 1; + HandleSetCurrentState(PlaybackStateEnum::kPlaying); + HandleSetPlaybackSpeed(1); Commands::PlaybackResponse::Type response; response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); @@ -112,8 +151,8 @@ void MediaPlaybackManager::HandlePlay(CommandResponseHelper & helper) { - mCurrentState = PlaybackStateEnum::kPaused; - mPlaybackSpeed = 0; + HandleSetCurrentState(PlaybackStateEnum::kPaused); + HandleSetPlaybackSpeed(0); Commands::PlaybackResponse::Type response; response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); @@ -123,8 +162,8 @@ void MediaPlaybackManager::HandlePause(CommandResponseHelper & helper) { - mCurrentState = PlaybackStateEnum::kNotPlaying; - mPlaybackSpeed = 0; + HandleSetCurrentState(PlaybackStateEnum::kNotPlaying); + HandleSetPlaybackSpeed(0); mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; Commands::PlaybackResponse::Type response; @@ -136,7 +175,9 @@ void MediaPlaybackManager::HandleStop(CommandResponseHelper & helper, const chip::Optional & audioAdvanceUnmuted) { - if (mPlaybackSpeed == kPlaybackMaxForwardSpeed) + float playbackSpeed = HandleGetPlaybackSpeed(); + + if (playbackSpeed == kPlaybackMaxForwardSpeed) { // if already at max speed, return error Commands::PlaybackResponse::Type response; @@ -146,13 +187,14 @@ void MediaPlaybackManager::HandleFastForward(CommandResponseHelper kPlaybackMaxForwardSpeed) + HandleSetCurrentState(PlaybackStateEnum::kPlaying); + // Normalize to correct range + playbackSpeed = (playbackSpeed <= 0 ? 1 : playbackSpeed * 2); + if (playbackSpeed > kPlaybackMaxForwardSpeed) { - // don't exceed max speed - mPlaybackSpeed = kPlaybackMaxForwardSpeed; + playbackSpeed = kPlaybackMaxForwardSpeed; } + HandleSetPlaybackSpeed(playbackSpeed); Commands::PlaybackResponse::Type response; response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); @@ -162,8 +204,8 @@ void MediaPlaybackManager::HandleFastForward(CommandResponseHelper & helper) { - mCurrentState = PlaybackStateEnum::kPlaying; - mPlaybackSpeed = 1; + HandleSetCurrentState(PlaybackStateEnum::kPlaying); + HandleSetPlaybackSpeed(1); mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; Commands::PlaybackResponse::Type response; @@ -175,7 +217,9 @@ void MediaPlaybackManager::HandlePrevious(CommandResponseHelper & helper, const chip::Optional & audioAdvanceUnmuted) { - if (mPlaybackSpeed == kPlaybackMaxRewindSpeed) + float playbackSpeed = HandleGetPlaybackSpeed(); + + if (playbackSpeed == kPlaybackMaxRewindSpeed) { // if already at max speed in reverse, return error Commands::PlaybackResponse::Type response; @@ -185,13 +229,14 @@ void MediaPlaybackManager::HandleRewind(CommandResponseHelper= 0 ? -1 : mPlaybackSpeed * 2); - if (mPlaybackSpeed < kPlaybackMaxRewindSpeed) + HandleSetCurrentState(PlaybackStateEnum::kPlaying); + // Normalize to correct range + playbackSpeed = (playbackSpeed >= 0 ? -1 : playbackSpeed * 2); + if (playbackSpeed < kPlaybackMaxRewindSpeed) { - // don't exceed max rewind speed - mPlaybackSpeed = kPlaybackMaxRewindSpeed; + playbackSpeed = kPlaybackMaxRewindSpeed; } + HandleSetPlaybackSpeed(playbackSpeed); Commands::PlaybackResponse::Type response; response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); @@ -249,8 +294,8 @@ void MediaPlaybackManager::HandleSeek(CommandResponseHelper & helper) { - mCurrentState = PlaybackStateEnum::kPlaying; - mPlaybackSpeed = 1; + HandleSetCurrentState(PlaybackStateEnum::kPlaying); + HandleSetPlaybackSpeed(1); mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; Commands::PlaybackResponse::Type response; @@ -338,4 +383,15 @@ uint16_t MediaPlaybackManager::GetClusterRevision(chip::EndpointId endpoint) return clusterRevision; } +static std::map> gMediaPlaybackManagerInstance{}; + +void emberAfMediaPlaybackClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Linux App: MediaPlayback::SetDefaultDelegate, endpoint=%x", endpoint); + + gMediaPlaybackManagerInstance[endpoint] = std::make_unique(endpoint); + + SetDefaultDelegate(endpoint, gMediaPlaybackManagerInstance[endpoint].get()); +} + #endif /// MATTER_DM_PLUGIN_MEDIA_PLAYBACK_SERVER diff --git a/examples/chef/common/clusters/media-playback/MediaPlaybackManager.h b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.h index 79bca10a3c8fb6..3f436b70a4b9ae 100644 --- a/examples/chef/common/clusters/media-playback/MediaPlaybackManager.h +++ b/examples/chef/common/clusters/media-playback/MediaPlaybackManager.h @@ -30,6 +30,8 @@ class MediaPlaybackManager : public chip::app::Clusters::MediaPlayback::Delegate using Feature = chip::app::Clusters::MediaPlayback::Feature; public: + MediaPlaybackManager(chip::EndpointId endpoint) : mEndpoint(endpoint){}; + chip::app::Clusters::MediaPlayback::PlaybackStateEnum HandleGetCurrentState() override; uint64_t HandleGetStartTime() override; uint64_t HandleGetDuration() override; @@ -42,6 +44,9 @@ class MediaPlaybackManager : public chip::app::Clusters::MediaPlayback::Delegate CHIP_ERROR HandleGetActiveTextTrack(chip::app::AttributeValueEncoder & aEncoder) override; CHIP_ERROR HandleGetAvailableTextTracks(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleSetCurrentState(chip::app::Clusters::MediaPlayback::PlaybackStateEnum currentState); + CHIP_ERROR HandleSetPlaybackSpeed(float playbackSpeed); + void HandlePlay(chip::app::CommandResponseHelper & helper) override; void HandlePause(chip::app::CommandResponseHelper & helper) override; void HandleStop(chip::app::CommandResponseHelper & helper) override; @@ -66,10 +71,9 @@ class MediaPlaybackManager : public chip::app::Clusters::MediaPlayback::Delegate uint16_t GetClusterRevision(chip::EndpointId endpoint) override; protected: + chip::EndpointId mEndpoint; // NOTE: it does not make sense to have default state of playing with a speed of 0, but // the CI test cases expect these values, and need to be fixed. - chip::app::Clusters::MediaPlayback::PlaybackStateEnum mCurrentState = - chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kPlaying; PlaybackPositionType mPlaybackPosition = { 0, chip::app::DataModel::Nullable(0) }; TrackType mActiveAudioTrack = { chip::CharSpan("activeAudioTrackId_0", 20), chip::app::DataModel::Nullable( @@ -101,8 +105,7 @@ class MediaPlaybackManager : public chip::app::Clusters::MediaPlayback::Delegate chip::Optional>( { chip::app::DataModel::MakeNullable(chip::CharSpan("displayName2", 12)) }) }) } }; - float mPlaybackSpeed = 1.0; - uint64_t mStartTime = 0; + uint64_t mStartTime = 0; // Magic number for testing. uint64_t mDuration = 80000; bool mAudioAdvanceMuted = false; diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp index 8771bf78dccaf5..f7b4b491451b0e 100644 --- a/examples/chef/common/stubs.cpp +++ b/examples/chef/common/stubs.cpp @@ -238,27 +238,6 @@ void emberAfLowPowerClusterInitCallback(EndpointId endpoint) } #endif -#ifdef MATTER_DM_PLUGIN_MEDIA_INPUT_SERVER -#include "media-input/MediaInputManager.h" -static MediaInputManager mediaInputManager; -void emberAfMediaInputClusterInitCallback(EndpointId endpoint) -{ - ChipLogProgress(Zcl, "TV Linux App: MediaInput::SetDefaultDelegate"); - MediaInput::SetDefaultDelegate(endpoint, &mediaInputManager); -} -#endif - -#ifdef MATTER_DM_PLUGIN_MEDIA_PLAYBACK_SERVER -#include "media-playback/MediaPlaybackManager.h" -static MediaPlaybackManager mediaPlaybackManager; - -void emberAfMediaPlaybackClusterInitCallback(EndpointId endpoint) -{ - ChipLogProgress(Zcl, "TV Linux App: MediaPlayback::SetDefaultDelegate"); - MediaPlayback::SetDefaultDelegate(endpoint, &mediaPlaybackManager); -} -#endif - #ifdef MATTER_DM_PLUGIN_TARGET_NAVIGATOR_SERVER #include "target-navigator/TargetNavigatorManager.h" static TargetNavigatorManager targetNavigatorManager; diff --git a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter index 84f789e40a1110..f76efbed02e901 100644 --- a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter +++ b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter @@ -2522,7 +2522,7 @@ endpoint 1 { server cluster OnOff { - ram attribute onOff default = 0; + persist attribute onOff default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2578,7 +2578,7 @@ endpoint 1 { server cluster TargetNavigator { emits event TargetUpdated; callback attribute targetList; - ram attribute currentTarget default = 0; + persist attribute currentTarget default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2592,11 +2592,11 @@ endpoint 1 { server cluster MediaPlayback { emits event StateChanged; - ram attribute currentState default = 0x00; + persist attribute currentState default = 0x00; ram attribute startTime default = 0x00; ram attribute duration default = 0; callback attribute sampledPosition; - ram attribute playbackSpeed default = 0; + ram attribute playbackSpeed default = 1; ram attribute seekRangeEnd; ram attribute seekRangeStart; callback attribute generatedCommandList; @@ -2622,7 +2622,7 @@ endpoint 1 { server cluster MediaInput { callback attribute inputList; - ram attribute currentInput default = 0x00; + persist attribute currentInput default = 0x00; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2661,7 +2661,7 @@ endpoint 1 { server cluster AudioOutput { callback attribute outputList; - ram attribute currentOutput default = 0x00; + persist attribute currentOutput default = 0x00; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2692,7 +2692,7 @@ endpoint 2 { } server cluster OnOff { - ram attribute onOff default = 0; + persist attribute onOff default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -2706,7 +2706,7 @@ endpoint 2 { } server cluster LevelControl { - ram attribute currentLevel default = 0x00; + persist attribute currentLevel default = 0x00; ram attribute minLevel default = 0x00; ram attribute maxLevel default = 0xFE; ram attribute options default = 0x00; diff --git a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap index 6a4517c2962607..8a6e75210fa6b5 100644 --- a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap +++ b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.zap @@ -2444,7 +2444,7 @@ "side": "server", "type": "boolean", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0", @@ -3080,7 +3080,7 @@ "side": "server", "type": "int8u", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0", @@ -3309,7 +3309,7 @@ "side": "server", "type": "PlaybackStateEnum", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x00", @@ -3376,7 +3376,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3586,7 +3586,7 @@ "side": "server", "type": "int8u", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x00", @@ -3982,7 +3982,7 @@ "side": "server", "type": "int8u", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x00", @@ -4315,7 +4315,7 @@ "side": "server", "type": "boolean", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0", @@ -4503,7 +4503,7 @@ "side": "server", "type": "int8u", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "0x00",