Skip to content

Commit

Permalink
TC-SWTCH-2.5: Add
Browse files Browse the repository at this point in the history
Also adds a non-AS implementation in the button simulator.
  • Loading branch information
cecille committed Jul 27, 2024
1 parent 99fc7fe commit f33ae78
Show file tree
Hide file tree
Showing 4 changed files with 545 additions and 49 deletions.
50 changes: 31 additions & 19 deletions examples/all-clusters-app/linux/AllClustersCommandDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,23 @@ bool HasNumericField(Json::Value & jsonValue, const std::string & field)
}

/**
* Named pipe handler for simulated long press on an action switch.
* Named pipe handler for simulated long press
*
* Usage example:
* echo '{"Name": "SimulateActionSwitchLongPress", "EndpointId": 3, "ButtonId": 1, "LongPressDelayMillis": 800,
* echo '{"Name": "SimulateLongPress", "EndpointId": 3, "ButtonId": 1, "LongPressDelayMillis": 800,
* "LongPressDurationMillis": 1000}' > /tmp/chip_all_clusters_fifo_1146610
*
* JSON Arguments:
* - "Name": Must be "SimulateActionSwitchLongPress"
* - "Name": Must be "SimulateLongPress"
* - "EndpointId": number of endpoint having a switch cluster
* - "ButtonId": switch position in the switch cluster for "down" button (not idle)
* - "LongPressDelayMillis": Time in milliseconds before the LongPress
* - "LongPressDurationMillis": Total duration in milliseconds from start of the press to LongRelease
* - "FeatureMap": The feature map to simulate
*
* @param jsonValue - JSON payload from named pipe
*/
void HandleSimulateActionSwitchLongPress(Json::Value & jsonValue)
void HandleSimulateLongPress(Json::Value & jsonValue)
{
if (sButtonSimulatorInstance != nullptr)
{
Expand All @@ -83,20 +84,22 @@ void HandleSimulateActionSwitchLongPress(Json::Value & jsonValue)
bool hasButtonId = HasNumericField(jsonValue, "ButtonId");
bool hasLongPressDelayMillis = HasNumericField(jsonValue, "LongPressDelayMillis");
bool hasLongPressDurationMillis = HasNumericField(jsonValue, "LongPressDurationMillis");
if (!hasEndpointId || !hasButtonId || !hasLongPressDelayMillis || !hasLongPressDurationMillis)
bool hasFeatureMap = HasNumericField(jsonValue, "FeatureMap");
if (!hasEndpointId || !hasButtonId || !hasLongPressDelayMillis || !hasLongPressDurationMillis || !hasFeatureMap)
{
std::string inputJson = jsonValue.toStyledString();
ChipLogError(
NotSpecified,
"Missing or invalid value for one of EndpointId, ButtonId, LongPressDelayMillis or LongPressDurationMillis in %s",
inputJson.c_str());
ChipLogError(NotSpecified,
"Missing or invalid value for one of EndpointId, ButtonId, LongPressDelayMillis, LongPressDurationMillis or "
"FeatureMap in %s",
inputJson.c_str());
return;
}

EndpointId endpointId = static_cast<EndpointId>(jsonValue["EndpointId"].asUInt());
uint8_t buttonId = static_cast<uint8_t>(jsonValue["ButtonId"].asUInt());
System::Clock::Milliseconds32 longPressDelayMillis{ static_cast<unsigned>(jsonValue["LongPressDelayMillis"].asUInt()) };
System::Clock::Milliseconds32 longPressDurationMillis{ static_cast<unsigned>(jsonValue["LongPressDurationMillis"].asUInt()) };
uint32_t featureMap = static_cast<uint32_t>(jsonValue["FeatureMap"].asUInt());
auto buttonSimulator = std::make_unique<ButtonEventsSimulator>();

bool success = buttonSimulator->SetMode(ButtonEventsSimulator::Mode::kModeLongPress)
Expand All @@ -105,6 +108,7 @@ void HandleSimulateActionSwitchLongPress(Json::Value & jsonValue)
.SetIdleButtonId(0)
.SetPressedButtonId(buttonId)
.SetEndpointId(endpointId)
.SetFeatureMap(featureMap)
.Execute([]() { sButtonSimulatorInstance.reset(); });

if (!success)
Expand All @@ -117,11 +121,11 @@ void HandleSimulateActionSwitchLongPress(Json::Value & jsonValue)
}

/**
* Named pipe handler for simulated multi-press on an action switch.
* Named pipe handler for simulated multi-press.
*
* Usage example:
* echo '{"Name": "SimulateActionSwitchMultiPress", "EndpointId": 3, "ButtonId": 1, "MultiPressPressedTimeMillis": 100,
* "MultiPressReleasedTimeMillis": 350, "MultiPressNumPresses": 2}' > /tmp/chip_all_clusters_fifo_1146610
* echo '{"Name": "SimulateMultiPress", "EndpointId": 3, "ButtonId": 1, "MultiPressPressedTimeMillis": 100,
* "MultiPressReleasedTimeMillis": 350, "MultiPressNumPresses": 2, "FeatureMap": 58}' > /tmp/chip_all_clusters_fifo_1146610
*
* JSON Arguments:
* - "Name": Must be "SimulateActionSwitchMultiPress"
Expand All @@ -130,10 +134,12 @@ void HandleSimulateActionSwitchLongPress(Json::Value & jsonValue)
* - "MultiPressPressedTimeMillis": Pressed time in milliseconds for each press
* - "MultiPressReleasedTimeMillis": Released time in milliseconds after each press
* - "MultiPressNumPresses": Number of presses to simulate
* - "FeatureMap": The feature map to simulate
* - "MultiPressMax": max number of presses (from attribute).
*
* @param jsonValue - JSON payload from named pipe
*/
void HandleSimulateActionSwitchMultiPress(Json::Value & jsonValue)
void HandleSimulateMultiPress(Json::Value & jsonValue)
{
if (sButtonSimulatorInstance != nullptr)
{
Expand All @@ -146,13 +152,15 @@ void HandleSimulateActionSwitchMultiPress(Json::Value & jsonValue)
bool hasMultiPressPressedTimeMillis = HasNumericField(jsonValue, "MultiPressPressedTimeMillis");
bool hasMultiPressReleasedTimeMillis = HasNumericField(jsonValue, "MultiPressReleasedTimeMillis");
bool hasMultiPressNumPresses = HasNumericField(jsonValue, "MultiPressNumPresses");
bool hasFeatureMap = HasNumericField(jsonValue, "FeatureMap");
bool hasMultiPressMax = HasNumericField(jsonValue, "MultiPressMax");
if (!hasEndpointId || !hasButtonId || !hasMultiPressPressedTimeMillis || !hasMultiPressReleasedTimeMillis ||
!hasMultiPressNumPresses)
!hasMultiPressNumPresses || !hasFeatureMap || !hasMultiPressMax)
{
std::string inputJson = jsonValue.toStyledString();
ChipLogError(NotSpecified,
"Missing or invalid value for one of EndpointId, ButtonId, MultiPressPressedTimeMillis, "
"MultiPressReleasedTimeMillis or MultiPressNumPresses in %s",
"MultiPressReleasedTimeMillis, MultiPressNumPresses, FeatureMap or MultiPressMax in %s",
inputJson.c_str());
return;
}
Expand All @@ -164,6 +172,8 @@ void HandleSimulateActionSwitchMultiPress(Json::Value & jsonValue)
System::Clock::Milliseconds32 multiPressReleasedTimeMillis{ static_cast<unsigned>(
jsonValue["MultiPressReleasedTimeMillis"].asUInt()) };
uint8_t multiPressNumPresses = static_cast<uint8_t>(jsonValue["MultiPressNumPresses"].asUInt());
uint32_t featureMap = static_cast<uint32_t>(jsonValue["FeatureMap"].asUInt());
uint8_t multiPressMax = static_cast<uint8_t>(jsonValue["MultiPressMax"].asUInt());
auto buttonSimulator = std::make_unique<ButtonEventsSimulator>();

bool success = buttonSimulator->SetMode(ButtonEventsSimulator::Mode::kModeMultiPress)
Expand All @@ -173,6 +183,8 @@ void HandleSimulateActionSwitchMultiPress(Json::Value & jsonValue)
.SetIdleButtonId(0)
.SetPressedButtonId(buttonId)
.SetEndpointId(endpointId)
.SetFeatureMap(featureMap)
.SetMultiPressMax(multiPressMax)
.Execute([]() { sButtonSimulatorInstance.reset(); });

if (!success)
Expand Down Expand Up @@ -333,13 +345,13 @@ void AllClustersAppCommandHandler::HandleCommand(intptr_t context)
std::string operation = self->mJsonValue["Operation"].asString();
self->OnOperationalStateChange(device, operation, self->mJsonValue["Param"]);
}
else if (name == "SimulateActionSwitchLongPress")
else if (name == "SimulateLongPress")
{
HandleSimulateActionSwitchLongPress(self->mJsonValue);
HandleSimulateLongPress(self->mJsonValue);
}
else if (name == "SimulateActionSwitchMultiPress")
else if (name == "SimulateMultiPress")
{
HandleSimulateActionSwitchMultiPress(self->mJsonValue);
HandleSimulateMultiPress(self->mJsonValue);
}
else
{
Expand Down
90 changes: 86 additions & 4 deletions examples/all-clusters-app/linux/ButtonEventsSimulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,42 @@ void EmitMultiPressComplete(EndpointId endpointId, uint8_t previousPosition, uin
}
}

void EmitShortRelease(EndpointId endpointId, uint8_t previousPosition)
{
Clusters::Switch::Events::ShortRelease::Type event{};
event.previousPosition = previousPosition;
EventNumber eventNumber = 0;

CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to log ShortRelease event: %" CHIP_ERROR_FORMAT, err.Format());
}
else
{
ChipLogProgress(NotSpecified, "Logged ShortRelease on Endpoint %u", static_cast<unsigned>(endpointId));
}
}

void EmitMultiPressOngoing(EndpointId endpointId, uint8_t newPosition, uint8_t count)
{
Clusters::Switch::Events::MultiPressOngoing::Type event{};
event.newPosition = newPosition;
event.currentNumberOfPressesCounted = count;
EventNumber eventNumber = 0;

CHIP_ERROR err = LogEvent(event, endpointId, eventNumber);
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to log MultiPressOngoing event: %" CHIP_ERROR_FORMAT, err.Format());
}
else
{
ChipLogProgress(NotSpecified, "Logged MultiPressOngoing on Endpoint %u position %u, count %u",
static_cast<unsigned>(endpointId), newPosition, count);
}
}

} // namespace

void ButtonEventsSimulator::OnTimerDone(System::Layer * layer, void * appState)
Expand Down Expand Up @@ -186,19 +222,65 @@ void ButtonEventsSimulator::Next()
}
case ButtonEventsSimulator::State::kEmitLongRelease: {
SetButtonPosition(mEndpointId, mIdleButtonId);
EmitLongRelease(mEndpointId, mPressedButtonId);
if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kMomentarySwitchLongPress))
{
EmitLongRelease(mEndpointId, mPressedButtonId);
}
else if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kMomentarySwitchRelease))
{
EmitShortRelease(mEndpointId, mPressedButtonId);
}
SetState(ButtonEventsSimulator::State::kIdle);
mDoneCallback();
break;
}
case ButtonEventsSimulator::State::kEmitStartOfMultiPress: {
EmitInitialPress(mEndpointId, mPressedButtonId);
StartTimer(mMultiPressNumPresses * (mMultiPressPressedTimeMillis + mMultiPressReleasedTimeMillis));
SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress);
if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kActionSwitch))
{
StartTimer(mMultiPressNumPresses * (mMultiPressPressedTimeMillis + mMultiPressReleasedTimeMillis));
SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress);
}
else
{
SetState(ButtonEventsSimulator::State::kMultiPressButtonRelease);
StartTimer(mMultiPressPressedTimeMillis);
}
break;
}
case ButtonEventsSimulator::State::kMultiPressButtonRelease: {
++mMultiPressPressesDone;
if (mMultiPressPressesDone > 1)
{
EmitMultiPressOngoing(mEndpointId, mPressedButtonId, mMultiPressPressesDone);
}

if (mMultiPressPressesDone == mMultiPressNumPresses)
{
SetState(ButtonEventsSimulator::State::kEmitEndOfMultiPress);
}
else
{
SetState(ButtonEventsSimulator::State::kEmitStartOfMultiPress);
}

if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kMomentarySwitchRelease))
{
EmitShortRelease(mEndpointId, mPressedButtonId);
}
StartTimer(mMultiPressReleasedTimeMillis);
break;
}

case ButtonEventsSimulator::State::kEmitEndOfMultiPress: {
EmitMultiPressComplete(mEndpointId, mPressedButtonId, mMultiPressNumPresses);
if (mFeatureMap & static_cast<uint32_t>(Clusters::Switch::Feature::kActionSwitch) && mMultiPressNumPresses > mMultiPressMax)
{
EmitMultiPressComplete(mEndpointId, mPressedButtonId, 0);
}
else
{
EmitMultiPressComplete(mEndpointId, mPressedButtonId, mMultiPressNumPresses);
}
SetState(ButtonEventsSimulator::State::kIdle);
mDoneCallback();
break;
Expand Down
20 changes: 19 additions & 1 deletion examples/all-clusters-app/linux/ButtonEventsSimulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class ButtonEventsSimulator
enum class Mode
{
kModeLongPress,
kModeMultiPress
kModeMultiPress,
kModeMultiPressNonAs
};

using DoneCallback = std::function<void()>;
Expand Down Expand Up @@ -107,6 +108,18 @@ class ButtonEventsSimulator
return *this;
}

ButtonEventsSimulator & SetFeatureMap(uint32_t featureMap)
{
mFeatureMap = featureMap;
return *this;
}

ButtonEventsSimulator & SetMultiPressMax(uint8_t multiPressMax)
{
mMultiPressMax = multiPressMax;
return *this;
}

private:
enum class State
{
Expand All @@ -118,6 +131,8 @@ class ButtonEventsSimulator

kEmitStartOfMultiPress = 4,
kEmitEndOfMultiPress = 5,

kMultiPressButtonRelease = 6,
};

static void OnTimerDone(System::Layer * layer, void * appState);
Expand All @@ -131,9 +146,12 @@ class ButtonEventsSimulator
System::Clock::Milliseconds32 mMultiPressPressedTimeMillis{};
System::Clock::Milliseconds32 mMultiPressReleasedTimeMillis{};
uint8_t mMultiPressNumPresses{ 1 };
uint8_t mMultiPressPressesDone{ 0 };
uint8_t mIdleButtonId{ 0 };
uint8_t mPressedButtonId{ 1 };
EndpointId mEndpointId{ 1 };
uint32_t mFeatureMap{ 0 };
uint8_t mMultiPressMax{ 0 };

Mode mMode{ Mode::kModeLongPress };
State mState{ State::kIdle };
Expand Down
Loading

0 comments on commit f33ae78

Please sign in to comment.