2020
2121#include < cyphal++/cyphal++.h>
2222
23+ #include " kv_host.h"
2324#include " socketcan.h"
2425
2526/* *************************************************************************************
2627 * CONSTANT
2728 **************************************************************************************/
2829
29- static CanardPortID const DEFAULT_COUNTER_PORT_ID = 1001U ;
30- static uint16_t const DEFAULT_COUNTER_UPDATE_PERIOD_ms = 5 * 1000UL ;
30+ static uint16_t const COUNTER_UPDATE_PERIOD_ms = 5 * 1000UL ;
31+ static uint16_t const HEARTBEAT_UPDATE_PERIOD_ms = 1000UL ;
3132
3233/* *************************************************************************************
3334 * TYPEDEF
@@ -41,6 +42,14 @@ typedef uavcan::primitive::scalar::Integer8_1_0 CounterMsg;
4142
4243extern " C" CanardMicrosecond micros ();
4344extern " C" unsigned long millis ();
45+ uavcan::node::ExecuteCommand::Response_1_1 onExecuteCommand_1_1_Request_Received (uavcan::node::ExecuteCommand::Request_1_1 const &);
46+
47+ /* *************************************************************************************
48+ * GLOBAL VARIABLES
49+ **************************************************************************************/
50+
51+ static cyphal::support::platform::storage::host::KeyValueStorage kv_storage;
52+ static std::shared_ptr<cyphal::registry::Registry> node_registry;
4453
4554/* *************************************************************************************
4655 * MAIN
@@ -58,25 +67,45 @@ int main(int argc, char ** argv)
5867 cyphal::Node node_hdl (node_heap.data (), node_heap.size (), micros, [socket_can_fd] (CanardFrame const & frame) { return (socketcanPush (socket_can_fd, &frame, 1000 *1000UL ) > 0 ); });
5968 std::mutex node_mtx;
6069
61- cyphal::Publisher<uavcan::node::Heartbeat_1_0> heartbeat_pub = node_hdl.create_publisher <uavcan::node::Heartbeat_1_0>
62- (1 *1000 *1000UL /* = 1 sec in usecs. */ );
70+ cyphal::Publisher<uavcan::node::Heartbeat_1_0> heartbeat_pub = node_hdl.create_publisher <uavcan::node::Heartbeat_1_0>(1 *1000 *1000UL /* = 1 sec in usecs. */ );
6371
64- cyphal::Publisher<CounterMsg> counter_pub = node_hdl.create_publisher <CounterMsg>
65- (DEFAULT_COUNTER_PORT_ID, 1 *1000 *1000UL /* = 1 sec in usecs. */ );
72+ cyphal::Publisher<CounterMsg> counter_pub;
6673
6774 /* REGISTER ***************************************************************************/
6875
6976 CanardNodeID node_id = node_hdl.getNodeId ();
70- CanardPortID counter_port_id = DEFAULT_COUNTER_PORT_ID;
71- uint16_t counter_update_period_ms = DEFAULT_COUNTER_UPDATE_PERIOD_ms;
77+ CanardPortID counter_port_id = std::numeric_limits<CanardPortID>::max ();
7278
73- const auto node_registry = node_hdl.create_registry ();
79+ node_registry = node_hdl.create_registry ();
7480
7581 const auto reg_ro_node_description = node_registry->route (" cyphal.node.description" , {true }, []() { return " basic-cyphal-node" ; });
7682 const auto reg_ro_pub_counter_type = node_registry->route (" cyphal.pub.counter.type" , {true }, []() { return " uavcan.primitive.scalar.Integer8.1.0" ; });
77- const auto reg_rw_node_id = node_registry->expose (" cyphal.node.id" , {}, node_id);
78- const auto reg_rw_pub_counter_id = node_registry->expose (" cyphal.pub.counter.id" , {}, counter_port_id);
79- const auto reg_rw_pub_counter_update_period_ms = node_registry->expose (" cyphal.pub.counter.update_period_ms" , {}, counter_update_period_ms);
83+ const auto reg_rw_node_id = node_registry->expose (" cyphal.node.id" , {true }, node_id);
84+ const auto reg_rw_pub_counter_id = node_registry->expose (" cyphal.pub.counter.id" , {true }, counter_port_id);
85+
86+ /* Configure service server for storing persistent
87+ * states upon command request.
88+ */
89+ auto const rc_load = cyphal::support::load (kv_storage, *node_registry);
90+ if (rc_load.has_value ()) {
91+ std::cerr << " cyphal::support::load failed with " << static_cast <int >(rc_load.value ()) << std::endl;
92+ return EXIT_FAILURE;
93+ }
94+
95+ cyphal::ServiceServer execute_command_srv = node_hdl.create_service_server <
96+ uavcan::node::ExecuteCommand::Request_1_1,
97+ uavcan::node::ExecuteCommand::Response_1_1>(
98+ 2 *1000 *1000UL ,
99+ onExecuteCommand_1_1_Request_Received);
100+
101+ /* Update node configuration from register value.
102+ */
103+ node_hdl.setNodeId (node_id);
104+ if (counter_port_id != std::numeric_limits<CanardPortID>::max ())
105+ counter_pub = node_hdl.create_publisher <CounterMsg>(counter_port_id, 1 *1000 *1000UL /* = 1 sec in usecs. */ );
106+
107+ std::cout << " Node #" << static_cast <int >(node_id) << std::endl
108+ << " \t Counter Port ID: " << counter_port_id << std::endl;
80109
81110 /* NODE INFO **************************************************************************/
82111 const auto node_info = node_hdl.create_node_info
@@ -131,17 +160,14 @@ int main(int argc, char ** argv)
131160
132161 for (;;)
133162 {
134- /* Update node configuration from register values. */
135- node_hdl.setNodeId (node_id);
136-
137163 {
138164 std::lock_guard<std::mutex> lock (node_mtx);
139165 node_hdl.spinSome ();
140166 }
141167
142168 auto const now = millis ();
143169
144- if ((now - prev_heartbeat) > 1000UL )
170+ if ((now - prev_heartbeat) > HEARTBEAT_UPDATE_PERIOD_ms )
145171 {
146172 prev_heartbeat = now;
147173
@@ -155,10 +181,13 @@ int main(int argc, char ** argv)
155181 heartbeat_pub->publish (msg);
156182 }
157183
158- if ((now - prev_counter) > counter_update_period_ms )
184+ if ((now - prev_counter) > COUNTER_UPDATE_PERIOD_ms )
159185 {
160186 prev_counter = now;
161- counter_pub->publish (counter_msg);
187+
188+ if (counter_pub)
189+ counter_pub->publish (counter_msg);
190+
162191 counter_msg.value ++;
163192 }
164193
@@ -193,3 +222,30 @@ unsigned long millis()
193222{
194223 return micros () / 1000 ;
195224}
225+
226+ uavcan::node::ExecuteCommand::Response_1_1 onExecuteCommand_1_1_Request_Received (uavcan::node::ExecuteCommand::Request_1_1 const & req)
227+ {
228+ uavcan::node::ExecuteCommand::Response_1_1 rsp;
229+
230+ if (req.command == uavcan::node::ExecuteCommand::Request_1_1::COMMAND_RESTART)
231+ {
232+ rsp.status = uavcan::node::ExecuteCommand::Response_1_1::STATUS_SUCCESS;
233+ exit (0 );
234+ }
235+ else if (req.command == uavcan::node::ExecuteCommand::Request_1_1::COMMAND_STORE_PERSISTENT_STATES)
236+ {
237+ auto const rc_save = cyphal::support::save (kv_storage, *node_registry, []() { /* watchdog function */ });
238+ if (rc_save.has_value ())
239+ {
240+ std::cerr << " cyphal::support::save failed with " << static_cast <int >(rc_save.value ()) << std::endl;
241+ rsp.status = uavcan::node::ExecuteCommand::Response_1_1::STATUS_FAILURE;
242+ return rsp;
243+ }
244+ rsp.status = uavcan::node::ExecuteCommand::Response_1_1::STATUS_SUCCESS;
245+ }
246+ else {
247+ rsp.status = uavcan::node::ExecuteCommand::Response_1_1::STATUS_BAD_COMMAND;
248+ }
249+
250+ return rsp;
251+ }
0 commit comments