Skip to content

Commit 46ffb60

Browse files
Added support for explicit current state request
1 parent f22c749 commit 46ffb60

14 files changed

+157
-32
lines changed
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"activityId": "random-uuid-as-string",
3+
"timestamp": 123456789
4+
}

src/FSM/States/SendCurrentState.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2022 Contributors to the Eclipse Foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
#include "FSM/States/SendCurrentState.h"
18+
#include "FSM/FSM.h"
19+
#include "Context.h"
20+
#include "FotaEvent.h"
21+
22+
namespace sua {
23+
24+
SendCurrentState::SendCurrentState()
25+
: SendCurrentState("SendCurrentState")
26+
{ }
27+
28+
SendCurrentState::SendCurrentState(const std::string& name)
29+
: State(name)
30+
{ }
31+
32+
void SendCurrentState::onEnter(Context& ctx)
33+
{
34+
send(ctx, IMqttProcessor::TOPIC_STATE, "systemVersion", true);
35+
ctx.stateMachine->handleEvent(FotaEvent::Waiting);
36+
}
37+
38+
} // namespace sua

src/FSM/States/SendCurrentState.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2022 Contributors to the Eclipse Foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
#ifndef SDV_SUA_SENDCURRENTSTATE_H
18+
#define SDV_SUA_SENDCURRENTSTATE_H
19+
20+
#include "FSM/State.h"
21+
22+
namespace sua {
23+
24+
class SendCurrentState : public State {
25+
public:
26+
SendCurrentState();
27+
SendCurrentState(const std::string& name);
28+
29+
void onEnter(Context& ctx) override;
30+
};
31+
32+
} // namespace sua
33+
34+
#endif

src/FotaEvent.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace sua {
2828
{ ConnectivityEstablished , "ConnectivityEstablished" },
2929
{ ConnectivityLost , "ConnectivityLost" },
3030
{ Start , "Start" },
31+
{ GetCurrentState , "GetCurrentState" },
3132
{ BundleVersionOK , "BundleVersionOK" },
3233
{ BundleVersionUnchanged , "BundleVersionUnchanged" },
3334
{ BundleVersionInconsistent , "BundleVersionInconsistent" },

src/FotaEvent.h

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace sua {
2626
ConnectivityEstablished,
2727
ConnectivityLost,
2828
Start,
29+
GetCurrentState,
2930
BundleVersionOK,
3031
BundleVersionUnchanged,
3132
BundleVersionInconsistent,

src/Mqtt/IMqttMessagingProtocol.h

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ namespace sua {
2727

2828
virtual class DesiredState readDesiredState(const std::string & input) = 0;
2929

30+
virtual class DesiredState readCurrentStateRequest(const std::string & input) = 0;
31+
3032
virtual std::string createMessage(const class Context& ctx, const std::string& name) = 0;
3133
};
3234

src/Mqtt/IMqttProcessor.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ namespace sua {
2323

2424
class IMqttProcessor {
2525
public:
26-
static constexpr const char * TOPIC_START = "selfupdate/desiredstate";
27-
static constexpr const char * TOPIC_FEEDBACK = "selfupdate/desiredstatefeedback";
28-
static constexpr const char * TOPIC_STATE = "selfupdate/currentstate";
26+
static constexpr const char * TOPIC_START = "selfupdate/desiredstate";
27+
static constexpr const char * TOPIC_FEEDBACK = "selfupdate/desiredstatefeedback";
28+
static constexpr const char * TOPIC_STATE = "selfupdate/currentstate";
29+
static constexpr const char * TOPIC_STATE_GET = "selfupdate/currentstate/get";
2930

3031
virtual ~IMqttProcessor() = default;
3132

src/Mqtt/MqttMessagingProtocolJSON.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,23 @@ namespace sua {
6767
// clang-format on
6868
}
6969

70+
DesiredState MqttMessagingProtocolJSON::readCurrentStateRequest(const std::string & input)
71+
{
72+
// clang-format off
73+
DesiredState s;
74+
std::stringstream ss(input);
75+
nlohmann::json json = nlohmann::json::parse(ss);
76+
s.activityId = json["activityId"];
77+
return s;
78+
// clang-format on
79+
}
80+
7081
std::string MqttMessagingProtocolJSON::createMessage(const class Context& ctx, const std::string& name)
7182
{
7283
if(name == "systemVersion") {
7384
// clang-format off
7485
const std::string tpl = jsonTemplate(R"(
7586
{
76-
"activityId": "{}",
7787
"timestamp": {},
7888
"payload": {
7989
"domains": [
@@ -92,7 +102,7 @@ namespace sua {
92102
)");
93103
// clang-format on
94104

95-
return fmt::format(tpl, ctx.desiredState.activityId, epochTime(), ctx.currentState.version);
105+
return fmt::format(tpl, epochTime(), ctx.currentState.version);
96106
}
97107

98108
if(name == "identifying") {

src/Mqtt/MqttMessagingProtocolJSON.h

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ namespace sua {
2525
public:
2626
DesiredState readDesiredState(const std::string & input) override;
2727

28+
DesiredState readCurrentStateRequest(const std::string & input) override;
29+
2830
std::string createMessage(const class Context& ctx, const std::string& name) override;
2931

3032
protected:

src/Mqtt/MqttMessagingProtocolYAML.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ namespace sua {
8181
// clang-format on
8282
}
8383

84+
DesiredState MqttMessagingProtocolYAML::readCurrentStateRequest(const std::string & input)
85+
{
86+
// ignored, no activity id needed, simply pass empty result and trigger response
87+
return {};
88+
}
89+
8490
std::string MqttMessagingProtocolYAML::createMessage(const class Context& ctx, const std::string& name)
8591
{
8692
Yaml::Node root;

src/Mqtt/MqttMessagingProtocolYAML.h

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ namespace sua {
2525
public:
2626
DesiredState readDesiredState(const std::string & input) override;
2727

28+
DesiredState readCurrentStateRequest(const std::string & input) override;
29+
2830
std::string createMessage(const class Context& ctx, const std::string& name) override;
2931
};
3032

src/Mqtt/MqttProcessor.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ namespace {
8484
{
8585
sua::Logger::trace("MqttCallback::connected");
8686
_mqttClient.subscribe(sua::IMqttProcessor::TOPIC_START, QUALITY, nullptr, _actionListener);
87+
_mqttClient.subscribe(sua::IMqttProcessor::TOPIC_STATE_GET, QUALITY, nullptr, _actionListener);
8788
_context.stateMachine->handleEvent(sua::FotaEvent::ConnectivityEstablished);
8889
}
8990

@@ -100,7 +101,9 @@ namespace {
100101
if(msg->get_topic() == sua::IMqttProcessor::TOPIC_START) {
101102
_context.desiredState = _context.messagingProtocol->readDesiredState(msg->get_payload_str());
102103
_context.stateMachine->handleEvent(sua::FotaEvent::Start);
103-
return;
104+
} if(msg->get_topic() == sua::IMqttProcessor::TOPIC_STATE_GET) {
105+
_context.desiredState = _context.messagingProtocol->readCurrentStateRequest(msg->get_payload_str());
106+
_context.stateMachine->handleEvent(sua::FotaEvent::GetCurrentState);
104107
}
105108
}
106109

src/SelfUpdateAgent.cpp

+31-25
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "FSM/States/Idle.h"
2222
#include "FSM/States/Installed.h"
2323
#include "FSM/States/Installing.h"
24+
#include "FSM/States/SendCurrentState.h"
2425
#include "FSM/States/Uninitialized.h"
2526
#include "FotaEvent.h"
2627
#include "Logger.h"
@@ -35,43 +36,48 @@ namespace sua {
3536
{
3637
// clang-format off
3738
auto factory = std::make_shared<StateFactory>();
38-
factory->addStateT<Connected >("Connected" );
39-
factory->addStateT<Downloading >("Downloading" );
40-
factory->addStateT<Failed >("Failed" );
41-
factory->addStateT<Idle >("Idle" );
42-
factory->addStateT<Installed >("Installed" );
43-
factory->addStateT<Installing >("Installing" );
44-
factory->addStateT<Uninitialized>("Uninitialized");
39+
factory->addStateT<Connected >("Connected" );
40+
factory->addStateT<Downloading >("Downloading" );
41+
factory->addStateT<Failed >("Failed" );
42+
factory->addStateT<Idle >("Idle" );
43+
factory->addStateT<Installed >("Installed" );
44+
factory->addStateT<Installing >("Installing" );
45+
factory->addStateT<SendCurrentState>("SendCurrentState");
46+
factory->addStateT<Uninitialized >("Uninitialized" );
4547
_context.stateMachine->setFactory(factory);
4648
// clang-format-on
4749

4850
// clang-format off
4951
_context.stateMachine->setTransitions({
5052
// from "Uninitialized"
51-
{ FotaEvent::ConnectivityEstablished , "Uninitialized", "Connected" },
53+
{ FotaEvent::ConnectivityEstablished, "Uninitialized" , "Connected" },
5254
// from "Connected"
53-
{ FotaEvent::ConnectivityLost , "Connected" , "Uninitialized" },
54-
{ FotaEvent::Start , "Connected" , "Failed" , FotaEvent::BundleVersionUnchanged },
55-
{ FotaEvent::Start , "Connected" , "Downloading" , FotaEvent::BundleVersionOK },
55+
{ FotaEvent::ConnectivityLost , "Connected" , "Uninitialized" },
56+
{ FotaEvent::Start , "Connected" , "Failed" , FotaEvent::BundleVersionUnchanged },
57+
{ FotaEvent::Start , "Connected" , "Downloading" , FotaEvent::BundleVersionOK },
58+
{ FotaEvent::GetCurrentState , "Connected" , "SendCurrentState"},
5659
// from "Failed"
57-
{ FotaEvent::ConnectivityLost , "Failed" , "Uninitialized" },
58-
{ FotaEvent::Waiting , "Failed" , "Idle" },
60+
{ FotaEvent::ConnectivityLost , "Failed" , "Uninitialized" },
61+
{ FotaEvent::Waiting , "Failed" , "Idle" },
5962
// from "Downloading"
60-
{ FotaEvent::ConnectivityLost , "Downloading" , "Uninitialized" },
61-
{ FotaEvent::DownloadStart , "Downloading" , "Installing" , FotaEvent::BundleVersionOK },
62-
{ FotaEvent::DownloadStart , "Downloading" , "Failed" , FotaEvent::BundleVersionInconsistent },
63-
{ FotaEvent::DownloadStart , "Downloading" , "Failed" , FotaEvent::DownloadFailed },
63+
{ FotaEvent::ConnectivityLost , "Downloading" , "Uninitialized" },
64+
{ FotaEvent::DownloadStart , "Downloading" , "Installing" , FotaEvent::BundleVersionOK },
65+
{ FotaEvent::DownloadStart , "Downloading" , "Failed" , FotaEvent::BundleVersionInconsistent },
66+
{ FotaEvent::DownloadStart , "Downloading" , "Failed" , FotaEvent::DownloadFailed },
6467
// from "Installing"
65-
{ FotaEvent::ConnectivityLost , "Installing" , "Uninitialized" },
66-
{ FotaEvent::InstallStart , "Installing" , "Installed" , FotaEvent::InstallCompleted },
67-
{ FotaEvent::InstallStart , "Installing" , "Failed" , FotaEvent::InstallFailed },
68+
{ FotaEvent::ConnectivityLost , "Installing" , "Uninitialized" },
69+
{ FotaEvent::InstallStart , "Installing" , "Installed" , FotaEvent::InstallCompleted },
70+
{ FotaEvent::InstallStart , "Installing" , "Failed" , FotaEvent::InstallFailed },
6871
// from "Installed"
69-
{ FotaEvent::ConnectivityLost , "Installed" , "Uninitialized" },
70-
{ FotaEvent::Waiting , "Installed" , "Idle" },
72+
{ FotaEvent::ConnectivityLost , "Installed" , "Uninitialized" },
73+
{ FotaEvent::Waiting , "Installed" , "Idle" },
7174
// from "Idle"
72-
{ FotaEvent::ConnectivityLost , "Idle" , "Uninitialized" },
73-
{ FotaEvent::Start , "Idle" , "Failed" , FotaEvent::BundleVersionUnchanged },
74-
{ FotaEvent::Start , "Idle" , "Downloading" , FotaEvent::BundleVersionOK },
75+
{ FotaEvent::ConnectivityLost , "Idle" , "Uninitialized" },
76+
{ FotaEvent::Start , "Idle" , "Failed" , FotaEvent::BundleVersionUnchanged },
77+
{ FotaEvent::Start , "Idle" , "Downloading" , FotaEvent::BundleVersionOK },
78+
// from "SendCurrentState"
79+
{ FotaEvent::ConnectivityLost , "SendCurrentState", "Uninitialized" },
80+
{ FotaEvent::Waiting , "SendCurrentState", "Idle" },
7581
});
7682
_context.stateMachine->transitTo("Uninitialized");
7783
// clang-format on

utest/TestMqttMessagingProtocolJSON.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,29 @@ namespace {
6666
EXPECT_EQ(s.bundleVersion, "1.1");
6767
}
6868

69+
TEST_F(TestMessagingProtocolJSON, readCurrentStateRequest)
70+
{
71+
// clang-format off
72+
const std::string input = R"(
73+
{
74+
"activityId": "random-uuid-as-string",
75+
"timestamp": 123456789
76+
}
77+
)";
78+
// clang-format on
79+
80+
const sua::DesiredState s = ProtocolJSON().readCurrentStateRequest(input);
81+
82+
EXPECT_EQ(s.activityId, "random-uuid-as-string");
83+
}
84+
6985
TEST_F(TestMessagingProtocolJSON, createMessage_systemVersion)
7086
{
7187
const std::string result = ProtocolJSON().createMessage(ctx, "systemVersion");
7288

7389
// clang-format off
7490
const std::string expected = R"(
7591
{
76-
"activityId": "id",
7792
"timestamp": 42,
7893
"payload": {
7994
"domains": [

0 commit comments

Comments
 (0)