APIs, concepts, guides, and more
RecordPerformance.cpp
1
10#include <iomanip>
11
12#include "SampleAppsHelper.h" // Import our helper functions.
13#include "rsi.h" // Import our RapidCode Library.
14
15using namespace RSI::RapidCode; // Import the RapidCode namespace
16
17// Helper function to calculate the minimum, maximum, and average of a vector of integers
18static std::vector<int> MinMaxAvg(std::vector<int> data)
19{
20 int min = data[0];
21 int max = data[0];
22 int sum = 0;
23
24 for (int i = 0; i < data.size(); i++)
25 {
26 if (data[i] < min)
27 {
28 min = data[i];
29 }
30 if (data[i] > max)
31 {
32 max = data[i];
33 }
34 sum += data[i];
35 }
36
37 int avg = sum / data.size();
38 return {min, max, avg};
39}
40
41int main()
42{
43 const std::string SAMPLE_APP_NAME = "Utilities: Record Performance";
44
45 // Print a start message to indicate that the sample app has started
46 SampleAppsHelper::PrintHeader(SAMPLE_APP_NAME);
47
48 /* CONSTANTS */
49 const int RECORD_PERIOD_SAMPLES = 1; // Number of samples between each record.
50 const int RECORD_TIME = 1000; // Time in milliseconds to record for.
51
52 /* RAPIDCODE INITIALIZATION */
53
54 // Create the controller
56 MotionController *controller = MotionController::Create(&params);
57
58 int exitCode = -1; // Set the exit code to an error value.
59 try // Ensure that the controller is deleted if an error occurs.
60 {
62
63 /* SAMPLE APP BODY */
64
65 // Check if the network is started
66 int valuesPerRecord;
67 bool networkTimingEnabled = false;
68 if (controller->NetworkStateGet() != RSINetworkState::RSINetworkStateOPERATIONAL)
69 {
70 std::cout << "Network is not operational. Only Firmware Timing Deltas will be recorded." << std::endl;
71 valuesPerRecord = 1;
72 }
73 else
74 {
75 // Enable network timing
76 controller->NetworkTimingEnableSet(true);
77 networkTimingEnabled = true;
78 valuesPerRecord = 3;
79 }
80
81 // Add a recorder
82 int recorderIndex = controller->RecorderCountGet();
83 controller->RecorderCountSet(recorderIndex + 1);
84
85 // Check if the recorder is running already, if it is then stop it
86 if (controller->RecorderEnabledGet(recorderIndex))
87 {
88 controller->RecorderStop(recorderIndex);
89 controller->RecorderReset(recorderIndex);
90 }
91
92 // Configure the recorder
93 controller->RecorderPeriodSet(RECORD_PERIOD_SAMPLES);
94 controller->RecorderCircularBufferSet(false);
95 controller->RecorderDataCountSet(valuesPerRecord);
96 controller->RecorderDataAddressSet(0, controller->AddressGet(RSIControllerAddressType::RSIControllerAddressTypeFIRMWARE_TIMING_DELTA));
97
98 if (networkTimingEnabled)
99 {
100 controller->RecorderDataAddressSet(1, controller->AddressGet(RSIControllerAddressType::RSIControllerAddressTypeNETWORK_TIMING_DELTA));
101 controller->RecorderDataAddressSet(2, controller->AddressGet(RSIControllerAddressType::RSIControllerAddressTypeNETWORK_TIMING_RECEIVE_DELTA));
102 }
103
104 // Start the recorder
105 controller->RecorderStart(recorderIndex);
106 controller->OS->Sleep(RECORD_TIME);
107 controller->RecorderStop(recorderIndex);
108
109 int recordCount = controller->RecorderRecordCountGet(recorderIndex);
110 std::cout << "There are " << recordCount << " records available." << std::endl;
111
112 // Read the records
113 std::vector<int> firmawareTimingDeltas(recordCount);
114 std::vector<int> networkTimingDeltas(recordCount);
115 std::vector<int> networkTimingReceiveDeltas(recordCount);
116
117 for (int i = 0; i < recordCount; i++)
118 {
119 controller->RecorderRecordDataRetrieve(recorderIndex);
120 firmawareTimingDeltas[i] = controller->RecorderRecordDataValueGet(recorderIndex, 0);
121
122 if (networkTimingEnabled)
123 {
124 networkTimingDeltas[i] = controller->RecorderRecordDataValueGet(recorderIndex, 1);
125 networkTimingReceiveDeltas[i] = controller->RecorderRecordDataValueGet(recorderIndex, 2);
126 }
127 }
128
129 // Calculate the statistics
130 std::vector<int> firmwareTimingStats = MinMaxAvg(firmawareTimingDeltas);
131 std::cout << "Firmware Timing Deltas (us): ";
132 std::cout << " Min = " << std::setw(4) << firmwareTimingStats[0];
133 std::cout << " Max = " << std::setw(4) << firmwareTimingStats[1];
134 std::cout << " Avg = " << std::setw(4) << firmwareTimingStats[2] << std::endl;
135
136 if (networkTimingEnabled)
137 {
138 std::vector<int> networkTimingStats = MinMaxAvg(networkTimingDeltas);
139 std::cout << "Network Timing Deltas (us): ";
140 std::cout << " Min = " << std::setw(4) << networkTimingStats[0];
141 std::cout << " Max = " << std::setw(4) << networkTimingStats[1];
142 std::cout << " Avg = " << std::setw(4) << networkTimingStats[2] << std::endl;
143
144 std::vector<int> networkTimingReceiveStats = MinMaxAvg(networkTimingReceiveDeltas);
145 std::cout << "Network Timing Receive Deltas (us):";
146 std::cout << " Min = " << std::setw(4) << networkTimingReceiveStats[0];
147 std::cout << " Max = " << std::setw(4) << networkTimingReceiveStats[1];
148 std::cout << " Avg = " << std::setw(4) << networkTimingReceiveStats[2] << std::endl;
149 }
150
151 // Delete the recorder
152 controller->RecorderCountSet(recorderIndex);
153
154 exitCode = 0; // Set the exit code to success.
155 }
156 catch (const std::exception &ex)
157 {
158 std::cerr << ex.what() << std::endl;
159 exitCode = -1;
160 }
161 // Delete the controller as the program exits to ensure memory is deallocated in the correct order
162 controller->Delete();
163
164 // Print a message to indicate the sample app has finished and if it was successful or not
165 SampleAppsHelper::PrintFooter(SAMPLE_APP_NAME, exitCode);
166
167 return exitCode;
168}
int32_t RecorderRecordCountGet()
Get the number of records that are stored and ready for reading.
void RecorderStart()
Start recording data.
void RecorderCircularBufferSet(bool enable)
Configure recorder as circular buffer (or not).
RSINetworkState NetworkStateGet()
void RecorderRecordDataRetrieve()
Retrieve one record of recorded data.
void RecorderDataCountSet(int32_t count)
Set the number of data values to be recorded.
uint64_t AddressGet(RSIControllerAddressType type)
Get the an address for some location on the MotionController.
static MotionController * Create()
Initialize and start the RMP EtherCAT controller.
int32_t RecorderRecordDataValueGet(int32_t index)
Get one value from a retrieved record.
void RecorderStop()
Stop recording data.
void Delete(void)
Delete the MotionController and all its objects.
void RecorderReset()
Reset the recorder.
int32_t RecorderCountGet()
Get the number of Recorder available in the firmware.
void RecorderDataAddressSet(int32_t index, uint64_t address)
Setup the addresses to be recorded.
void RecorderPeriodSet(uint32_t samples)
Set the number of samples between records.
void RecorderCountSet(int32_t recorderCount)
Set the number of processed Recorders in the controller.
bool RecorderEnabledGet()
Determine if the recorder is recording.
Represents the RMP soft motion controller. This class provides an interface to general controller con...
Definition rsi.h:795
RapidCodeOS * OS
Provides access to operating system (Windows) features.
Definition rsi.h:3665
void NetworkTimingEnableSet(bool enable)
Enable or disable the firmware to start timing the network packets.
void Sleep(int32_t milliseconds)
Put the current thread to sleep.
static void PrintFooter(std::string sampleAppName, int exitCode)
Print a message to indicate the sample app has finished and if it was successful or not.
static void CheckErrors(RapidCodeObject *rsiObject)
Checks for errors in the given RapidCodeObject and throws an exception if any non-warning errors are ...
static void PrintHeader(std::string sampleAppName)
Print a start message to indicate that the sample app has started.
static MotionController::CreationParameters GetCreationParameters()
Returns a MotionController::CreationParameters object with user-defined parameters.
CreationParameters for MotionController::Create.
Definition rsi.h:856