Skip to content

Commit ced2f2b

Browse files
authored
Merge pull request #280 from edu-rossrobotics/feature/service_response_with_metadata
Feature/service response with metadata
2 parents d786624 + 2f330c1 commit ced2f2b

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* This example shows how to use the OpenCyphal library to request the performance of a
3+
* service from a service server.
4+
*/
5+
6+
/**************************************************************************************
7+
* INCLUDE
8+
**************************************************************************************/
9+
10+
#include <SPI.h>
11+
12+
#include <107-Arduino-Cyphal.h>
13+
#include <107-Arduino-MCP2515.h>
14+
#include <107-Arduino-CriticalSection.h>
15+
16+
/**************************************************************************************
17+
* NAMESPACE
18+
**************************************************************************************/
19+
20+
using namespace uavcan::node;
21+
22+
/**************************************************************************************
23+
* CONSTANTS
24+
**************************************************************************************/
25+
26+
static int const MKRCAN_MCP2515_CS_PIN = 3;
27+
static int const MKRCAN_MCP2515_INT_PIN = 7;
28+
29+
/**************************************************************************************
30+
* FUNCTION DECLARATION
31+
**************************************************************************************/
32+
33+
void onReceiveBufferFull(CanardFrame const &);
34+
void onExecuteCommand_1_1_Response_Received(ExecuteCommand::Response_1_1 const & rsp, cyphal::TransferMetadata const & metadata);
35+
36+
/**************************************************************************************
37+
* GLOBAL VARIABLES
38+
**************************************************************************************/
39+
40+
ArduinoMCP2515 mcp2515([]() { digitalWrite(MKRCAN_MCP2515_CS_PIN, LOW); },
41+
[]() { digitalWrite(MKRCAN_MCP2515_CS_PIN, HIGH); },
42+
[](uint8_t const data) { return SPI.transfer(data); },
43+
micros,
44+
onReceiveBufferFull,
45+
nullptr);
46+
47+
cyphal::Node::Heap<cyphal::Node::DEFAULT_O1HEAP_SIZE> node_heap;
48+
cyphal::Node node_hdl(node_heap.data(), node_heap.size(), micros, [] (CanardFrame const & frame) { return mcp2515.transmit(frame); }, 28);
49+
50+
cyphal::ServiceClient<ExecuteCommand::Request_1_1> srv_client = node_hdl.create_service_client<ExecuteCommand::Request_1_1, ExecuteCommand::Response_1_1>(
51+
2*1000*1000UL,
52+
onExecuteCommand_1_1_Response_Received);
53+
54+
/**************************************************************************************
55+
* SETUP/LOOP
56+
**************************************************************************************/
57+
58+
void setup()
59+
{
60+
Serial.begin(9600);
61+
while(!Serial) { }
62+
delay(1000);
63+
Serial.println("|---- OpenCyphal Service Client With Metadata Example ----|");
64+
65+
/* Setup SPI access */
66+
SPI.begin();
67+
pinMode(MKRCAN_MCP2515_CS_PIN, OUTPUT);
68+
digitalWrite(MKRCAN_MCP2515_CS_PIN, HIGH);
69+
70+
/* Attach interrupt handler to register MCP2515 signaled by taking INT low */
71+
pinMode(MKRCAN_MCP2515_INT_PIN, INPUT_PULLUP);
72+
attachInterrupt(digitalPinToInterrupt(MKRCAN_MCP2515_INT_PIN), []() { mcp2515.onExternalEventHandler(); }, LOW);
73+
74+
/* Initialize MCP2515 */
75+
mcp2515.begin();
76+
mcp2515.setBitRate(CanBitRate::BR_250kBPS_16MHZ);
77+
mcp2515.setNormalMode();
78+
79+
Serial.println("setup finished");
80+
}
81+
82+
void loop()
83+
{
84+
/* Process all pending OpenCyphal actions.
85+
*/
86+
{
87+
CriticalSection crit_sec;
88+
node_hdl.spinSome();
89+
}
90+
91+
/* Publish the request once/second */
92+
static unsigned long prev = 0;
93+
unsigned long const now = millis();
94+
if(now - prev > 1000)
95+
{
96+
prev = now;
97+
98+
/* Request some coffee. */
99+
Serial.println("Requesting some coffee");
100+
std::string const cmd_param("I want a double espresso with cream!");
101+
ExecuteCommand::Request_1_1 req;
102+
req.command = 0xCAFE;
103+
std::copy(cmd_param.begin(), cmd_param.end(), std::back_inserter(req.parameter));
104+
105+
106+
if (!srv_client->request(27 /* remote node id */, req)) {
107+
Serial.println("Coffee request failed.");
108+
}
109+
}
110+
}
111+
112+
/**************************************************************************************
113+
* FUNCTION DEFINITION
114+
**************************************************************************************/
115+
116+
void onReceiveBufferFull(CanardFrame const & frame)
117+
{
118+
node_hdl.onCanFrameReceived(frame);
119+
}
120+
121+
void onExecuteCommand_1_1_Response_Received(ExecuteCommand::Response_1_1 const & rsp, cyphal::TransferMetadata const & metadata)
122+
{
123+
if (rsp.status == ExecuteCommand::Response_1_1::STATUS_SUCCESS)
124+
Serial.printf("Coffee successfully retrieved from node %i", metadata.remote_node_id);
125+
else
126+
Serial.println("I should've suspected trouble when the coffee failed to arrive.");
127+
}

src/ServiceClient.ipp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ bool ServiceClient<T_REQ, T_RSP, OnResponseCb>::onTransferReceived(CanardRxTrans
7676
if (!rc) return false;
7777

7878
/* Invoke the user registered callback. */
79-
_on_response_cb(rsp);
79+
if constexpr (std::is_invocable_v<OnResponseCb, T_RSP, TransferMetadata>) {
80+
_on_response_cb(rsp, SubscriptionBase::fillMetadata(transfer));
81+
} else {
82+
_on_response_cb(rsp);
83+
}
8084

8185
return true;
8286
}

0 commit comments

Comments
 (0)