API Documentation
Loading...
Searching...
No Matches
HardwareCommandQueue.h
Go to the documentation of this file.
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Hardware
28File: HardwareCommandQueue
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include "DLLInfo.h"
34#include <NDEVR/BaseValues.h>
35#include <NDEVR/String.h>
36#include <NDEVR/Dictionary.h>
37#include <NDEVR/RWLock.h>
38#include <NDEVR/Time.h>
39#include <NDEVR/TimeSpan.h>
40#include <NDEVR/Thread.h>
41#include <NDEVR/JSONNode.h>
42#include <NDEVR/ProgressInfo.h>
43#include <NDEVR/LogMessage.h>
44#include <NDEVR/Exception.h>
45namespace NDEVR
46{
47 /**--------------------------------------------------------------------------------------------------
48 \brief Describes whether a HardwareCommandQueue supports certain commands. This is usually firmware.
49 **/
50 enum class CommandSupport
51 {
55 };
56 /**--------------------------------------------------------------------------------------------------
57 \brief Stores long-term statistics for commands executed using HardwareCommandQueue.
58 **/
75 /**--------------------------------------------------------------------------------------------------
76 \brief A base class for communicating with Hardware, typically firmware by the software.
77 Commands a queued up and sent, before waiting for a response for each command.
78 **/
79 template<class t_type>
81 {
82 public:
84 {
85 t_type command = t_type(0);
88 void clear()
89 {
90 command = t_type(0);
91 args.clear();
92 regex.clear();
93 }
94 };
101 bool hasPendingCommand(t_type command) const
102 {
103 return m_pending_commands.hasKey(command);
104 }
105 static const uint04 s_buffer_size = 256000;
106 void postCommand(t_type command, const String& args = String(), const String& regex = String())
107 {
109 if (allowMultipleCommandsInStream(command, args) || !m_pending_commands.hasKey(command))
110 {
111 m_ordered_commands.add({ command, args, regex });
112 if (!m_pending_commands.hasKey(command))
113 m_pending_commands[command] = 0;
114 m_pending_commands[command]++;
115 }
116 else
117 {
118 for (uint04 i = 0; i < m_ordered_commands.size(); i++)
119 {
120 if (m_ordered_commands[i].command == command)
121 {
122 m_ordered_commands[i].args = args;
123 m_ordered_commands[i].regex = regex;
124 }
125 }
126 }
127 }
128 void removeCommand(t_type command)
129 {
131 if (m_pending_commands.hasKey(command))
132 {
133 for (uint04 i = m_ordered_commands.size() - 1; !IsInvalid(i); i--)
134 {
135 if (m_ordered_commands[i].command == command)
136 {
137 m_ordered_commands.removeIndex(i);
138 }
139 }
140 m_pending_commands.erase(command);
141 }
142 }
143 void addCommandToFront(t_type command, const String& args = String(), const String& regex = String())
144 {
146 if (allowMultipleCommandsInStream(command, args) || !m_pending_commands.hasKey(command))
147 {
148 m_ordered_commands.add(0, { command, args, regex });
149 if (!m_pending_commands.hasKey(command))
150 m_pending_commands[command] = 0;
151 m_pending_commands[command]++;
152 }
153 else
154 {
155 for (uint04 i = 0; i < m_ordered_commands.size(); i++)
156 {
157 if (m_ordered_commands[i].command == command)
158 {
159 m_ordered_commands[i].args = args;
160 m_ordered_commands[i].regex = args;
161 if (i != 0)
162 m_ordered_commands.swapIndices(0, i);
163 }
164
165 }
166 }
167 }
168 virtual bool allowMultipleCommandsInStream(t_type command, const String& args) const
169 {
170 UNUSED(command);
171 UNUSED(args);
172 return false;
173 }
175 {
176 //WLock current_command_lock(&m_current_command);
177 if (m_current_command.command == t_type(0))
178 {
179 {
181 if (m_pending_block_command.command != t_type(0))
182 {
187 return true;
188 }
189 }
190 {
192 if (m_ordered_commands.size() > 0)
193 {
195 m_ordered_commands.removeIndex(0);
199 }
200 else
201 {
202 return false;
203 }
204 }
207 return true;
208 }
209 return false;
210 }
212 {
213 if (m_current_command.command != t_type(0))
214 {
215 //WLock lock(&m_current_command);
216 //if (m_current_command != t_type(0))
217 {
218 CommandRecord record;
220 record.end_time = Time::SystemTime();
222 m_records.add(record);
223 m_command_info[m_current_command.command].total_time += (record.end_time - record.start_time);
224 m_command_info[m_current_command.command].number_of_attempts++;
225#ifdef _DEBUG
226 m_command_info[m_current_command.command].average_time = m_command_info[m_current_command.command].total_time.elapsedSeconds() / m_command_info[m_current_command.command].number_of_attempts;
227#endif
230
231
232 }
233 }
234 }
235 virtual void retryCommand()
236 {
237 if (m_current_command.command != t_type(0))
238 {
239 const CommandQueueItem command = m_current_command;
241 addCommandToFront(command.command, command.args, command.regex);
242 }
243 }
244 virtual void cancelCommand()
245 {
246 if (m_current_command.command != t_type(0))
247 {
248 CommandRecord record;
250 record.end_time = Time::SystemTime();
252 m_records.add(record);
253 m_command_info[m_current_command.command].total_time += (record.end_time - record.start_time);
254 m_command_info[m_current_command.command].number_of_attempts++;
255#ifdef _DEBUG
256 m_command_info[m_current_command.command].average_time = m_command_info[m_current_command.command].total_time.elapsedSeconds() / m_command_info[m_current_command.command].number_of_attempts;
257#endif
260 }
261 }
262 virtual void onFailure(const t_type& command)
263 {
264 if (m_command_info[command].supports_command == CommandSupport::e_not_known)
265 m_command_info[command].supports_command = CommandSupport::e_not_supported;
266 m_command_info[command].number_of_failures++;
267 }
269 {
271 m_pending_commands.clear();
272 m_ordered_commands.clear();
273 WLock block_lock(&m_pending_block_command);
275 }
276 virtual void executeCommand(const t_type& command, const String& args) = 0;
277 void executeCommandBlocking(const t_type& command, const String& args = String())
278 {
279 bool finished = false;
280 for (;;)//wait to write pending command
281 {
282 {
283 WLock lock(&m_pending_block_command);//prevent new commands from being issued
284 if (m_pending_block_command.command == t_type(0))
285 {
288 finished = true;
289 }
290 }
291 if (finished)
292 break;
293 else
295 }
296 finished = false;
297 for (;;)//Wait for command to be executed
298 {
299 {
300 RLock lock(&m_pending_block_command);//prevent new commands from being issued
301 finished = m_pending_block_command.command != command;
302 }
303 if (finished)
304 break;
305 else
307 }
308 finished = false;
309 for (;;)//Wait for command execution to complete
310 {
311 {
312 //RLock lock(&m_current_command);//prevent new commands from being issued
313 finished = m_current_command.command != command;
314 }
315 if (finished)
316 break;
317 else
319 }
320 }
322 {
323 if (m_command_info.contains(command))
324 return m_command_info.get(command);
325 return CommandInformation();
326 }
327 virtual bool supportsCommand(t_type command) const
328 {
329 if (m_command_info.contains(command))
330 return m_command_info.get(command).supports_command != CommandSupport::e_not_supported;
331 return true;
332 }
333 void disableCommand(t_type command)
334 {
335 if (!m_command_info.contains(command))
336 {
337 m_command_info.add(command, CommandInformation());
338 }
339 for (uint04 i = 0; i < m_ordered_commands.size(); i++)
340 {
341 if (m_ordered_commands[i].command == command)
342 {
343 m_ordered_commands.removeIndex(i--);
344 m_pending_commands[command]--;
345 if (m_pending_commands[command] == 0)
346 m_pending_commands.erase(command);
347 }
348 }
349 m_command_info.get(command).supports_command = CommandSupport::e_not_supported;
350 }
351 void setSupport(t_type command, CommandSupport support)
352 {
353 m_command_info[command].supports_command = support;
354 }
355 void setSupported(t_type command, bool supported)
356 {
357 if (supported)
358 m_command_info[command].supports_command = CommandSupport::e_supported;
359 else
360 m_command_info[command].supports_command = CommandSupport::e_not_supported;
361 }
362 virtual void endCommandQueue()
363 {
364
365 }
367 {
369 return m_command_info.get(m_current_command.command).response_timeout;
370 return TimeSpan(0);
371 }
373 {
375 return m_command_info.get(m_current_command.command).tx_delay;
376 return TimeSpan(0);
377 }
379 {
381 return m_command_info.get(m_current_command.command).rx_delay;
382 return TimeSpan(0);
383 }
384 void setFromJSONInfo(const JSONNode& root, bool allow_command_override, ProgressInfo* log)
385 {
386 for (uint04 i = 0; i < Constant<uint04>::Invalid; i++)
387 {
388 t_type command = cast<t_type>(i);
390 if (display.size() == 0)
391 break;
392 try
393 {
395 if (m_command_info.contains(command))
396 {
397 info = m_command_info.get(command);
398 }
399 if (root.hasNode(display))
400 {
401 const JSONNode& node = root[display];
402 if (node.hasNode("Attempt Count"))
403 info.number_of_attempts = node["Attempt Count"].getAs<uint04>();
404 if (node.hasNode("Failure Count"))
405 info.number_of_failures = node["Failure Count"].getAs<uint04>();
406 if (node.hasNode("Total Response Time"))
407 info.total_time = TimeSpan(node["Total Response Time"].getAs<fltp08>());
408 if (allow_command_override)
409 {
410 if (node.hasNode("Supported"))
411 info.supports_command = node["Supported"].getAs<String>().getAs<CommandSupport>();
412 if (node.hasNode("Command"))
413 info.command = node["Command"].getAs<String>();
414 if (node.hasNode("Validation Regex"))
415 info.validation_regex = node["Validation Regex"].getAs<String>();
416 if (node.hasNode("Default Args"))
417 info.default_argument = node["Default Args"].getAs<String>();
418 if (node.hasNode("Transmission Delay"))
419 info.tx_delay = TimeSpan(node["Transmission Delay"].getAs<fltp08>());
420 if (node.hasNode("Receive Delay"))
421 info.rx_delay = TimeSpan(node["Receive Delay"].getAs<fltp08>());
422 if (node.hasNode("Response Timeout"))
423 info.response_timeout = TimeSpan(node["Response Timeout"].getAs<fltp08>());
424 }
425 }
426 m_command_info[command] = info;
427 }
428 catch (Exception& e)
429 {
430 if (log) log->addMessage(e.getMessage(), LogMessage::e_error);
431 }
432 }
433 }
434 JSONNode getCommandJSONInfo(bool only_supported) const
435 {
436 JSONNode root;
437 for (uint04 i = 0; i < Constant<uint04>::Invalid; i++)
438 {
439 t_type command = cast<t_type>(i);
440
442 if (display.size() == 0)
443 break;
445 if (m_command_info.contains(command))
446 {
447 info = m_command_info.get(command);
448 }
449 if (only_supported && info.supports_command == CommandSupport::e_not_supported)
450 continue;
451 JSONNode& node = root[display];
452 node["Command"] = info.command;
453 if (!only_supported)
454 node["Supported"] = String(info.supports_command);
455 node["Attempt Count"] = info.number_of_attempts;
456 node["Failure Count"] = info.number_of_failures;
457 node["Total Response Time"] = info.total_time.elapsedSeconds();
458 if (info.number_of_attempts > 0)
459 node["Average Response Time"] = info.total_time.elapsedSeconds() / info.number_of_attempts;
460 else
461 node["Average Response Time"] = 0;
462 node["Default Args"] = info.default_argument;
463 node["Transmission Delay"] = info.tx_delay;
464 node["Receive Delay"] = info.rx_delay;
465 node["Response Timeout"] = info.response_timeout;
466 node["Validation Regex"] = info.validation_regex;
467 }
468 return root;
469 }
470 String getCommandCSVInfo(bool only_supported, bool include_identity_info, char deliminator = ',') const
471 {
472 String del(deliminator);
473 String root;
474 root += "Command" + del;
475 if (!only_supported)
476 root += "Supported" + del;
477 root += "Attempt Count" + del;
478 root += "Failure Count" + del;
479 root += "Total Response Time" + del;
480 root += "Average Response Time" + del;
481 if (include_identity_info)
482 {
483 root += "Default Args" + del;
484 root += "Transmission Delay" + del;
485 root += "Receive Delay" + del;
486 root += "Response Timeout" + del;
487 root += "Validation Regex" + del;
488 }
489 for (uint04 i = 0; i < Constant<uint04>::Invalid; i++)
490 {
491 root.last() = '\n';
492 t_type command = cast<t_type>(i);
493
495 if (display.size() == 0)
496 break;
498 if (m_command_info.contains(command))
499 {
500 info = m_command_info.get(command);
501 }
502 if (only_supported && info.supports_command == CommandSupport::e_not_supported)
503 continue;
504 root += display + del;
505 if (!only_supported)
506 root += String(info.supports_command) + del;
507 root += String(info.number_of_attempts) + del;
508 root += String(info.number_of_failures) + del;
509 root += String(info.total_time.elapsedSeconds()) + del;
510 if (info.number_of_attempts > 0)
511 root += String(info.total_time.elapsedSeconds() / info.number_of_attempts) + del;
512 else
513 root += "0" + del;
514 if (include_identity_info)
515 {
516 root += info.default_argument + del;
517 root += String(info.tx_delay) + del;
518 root += String(info.rx_delay) + del;
519 root += String(info.response_timeout) + del;
520 root += info.validation_regex + del;
521 }
522 }
523 return root;
524 }
525 bool hasPending() const { return m_current_command.command != t_type(0) || m_pending_commands.size() > 0; };
526
527 t_type currentCommand() const { return m_current_command.command; }
528 const String& currentArgs() const { return m_current_command.args; }
529 const String& currentRegex() const { return m_current_command.regex; }
531 void setBufferOffset(uint04 buffer_offset) { m_buffer_offset = buffer_offset; }
532 protected:
541 };
543}
#define UNUSED(expr)
Definition BaseValues.hpp:409
#define HARDWARE_API
Definition DLLInfo.h:56
The equivelent of std::vector but with a bit more control. The basic array unit of the library.
Definition Buffer.hpp:56
constexpr t_index_type size() const
Definition Buffer.hpp:823
decltype(auto) last()
Definition Buffer.hpp:588
void clear()
Definition Buffer.hpp:422
A hash-based key-value store, useful for quick associative lookups. Key features include:
Definition Dictionary.h:61
bool hasKey(const t_key &key) const
Definition Dictionary.h:66
uint04 size() const
Definition Dictionary.h:144
Provides consistent interface to handle errors through the throw expression. All exceptions generated...
Definition Exception.hpp:47
virtual TranslatedString getMessage() const
Definition Exception.hpp:71
A base class for communicating with Hardware, typically firmware by the software. Commands a queued u...
Definition HardwareCommandQueue.h:81
JSONNode getCommandJSONInfo(bool only_supported) const
Definition HardwareCommandQueue.h:434
CommandInformation commandInformation(t_type command)
Definition HardwareCommandQueue.h:321
CommandQueueItem m_pending_block_command
Definition HardwareCommandQueue.h:539
CommandQueueItem m_current_command
Definition HardwareCommandQueue.h:538
TimeSpan commandTimeout() const
Definition HardwareCommandQueue.h:366
void finishCommand()
Definition HardwareCommandQueue.h:211
void removeCommand(t_type command)
Definition HardwareCommandQueue.h:128
void disableCommand(t_type command)
Definition HardwareCommandQueue.h:333
Time m_current_command_start_time
Definition HardwareCommandQueue.h:537
virtual bool allowMultipleCommandsInStream(t_type command, const String &args) const
Definition HardwareCommandQueue.h:168
virtual bool supportsCommand(t_type command) const
Definition HardwareCommandQueue.h:327
void setFromJSONInfo(const JSONNode &root, bool allow_command_override, ProgressInfo *log)
Definition HardwareCommandQueue.h:384
bool popCommandAndExecute()
Definition HardwareCommandQueue.h:174
virtual void cancelCommand()
Definition HardwareCommandQueue.h:244
virtual void retryCommand()
Definition HardwareCommandQueue.h:235
uint04 bufferOffset() const
Definition HardwareCommandQueue.h:530
bool hasPendingCommand(t_type command) const
Definition HardwareCommandQueue.h:101
void executeCommandBlocking(const t_type &command, const String &args=String())
Definition HardwareCommandQueue.h:277
bool hasPending() const
Definition HardwareCommandQueue.h:525
uint04 m_buffer_offset
Definition HardwareCommandQueue.h:540
void postCommand(t_type command, const String &args=String(), const String &regex=String())
Definition HardwareCommandQueue.h:106
Dictionary< t_type, uint04 > m_pending_commands
Definition HardwareCommandQueue.h:534
const String & currentRegex() const
Definition HardwareCommandQueue.h:529
t_type currentCommand() const
Definition HardwareCommandQueue.h:527
void addCommandToFront(t_type command, const String &args=String(), const String &regex=String())
Definition HardwareCommandQueue.h:143
Buffer< CommandRecord > m_records
Definition HardwareCommandQueue.h:536
virtual void executeCommand(const t_type &command, const String &args)=0
TimeSpan rxDelay() const
Definition HardwareCommandQueue.h:378
virtual void endCommandQueue()
Definition HardwareCommandQueue.h:362
String getCommandCSVInfo(bool only_supported, bool include_identity_info, char deliminator=',') const
Definition HardwareCommandQueue.h:470
Dictionary< t_type, CommandInformation > m_command_info
Definition HardwareCommandQueue.h:533
void clearCommands()
Definition HardwareCommandQueue.h:268
void setSupported(t_type command, bool supported)
Definition HardwareCommandQueue.h:355
Buffer< CommandQueueItem > m_ordered_commands
Definition HardwareCommandQueue.h:535
virtual void onFailure(const t_type &command)
Definition HardwareCommandQueue.h:262
void setBufferOffset(uint04 buffer_offset)
Definition HardwareCommandQueue.h:531
void setSupport(t_type command, CommandSupport support)
Definition HardwareCommandQueue.h:351
static const uint04 s_buffer_size
Definition HardwareCommandQueue.h:105
TimeSpan txDelay() const
Definition HardwareCommandQueue.h:372
const String & currentArgs() const
Definition HardwareCommandQueue.h:528
JavaScript Object Notation or JSON is an open - standard file format that uses human - readable text ...
Definition JSONParser.h:60
decltype(auto) getAs() const
Definition JSONParser.h:201
bool hasNode(const String &child_node) const
Definition JSONParser.h:249
@ e_error
Definition LogMessage.h:53
A light-weight base class for Log that allows processes to update, without the need for additional in...
Definition ProgressInfo.hpp:48
virtual bool addMessage(const LogMessage &message)=0
Used to lock a particular variable for reading. Any number of readers can be created when no write lo...
Definition RWLock.h:91
The core String class for the NDEVR API.
Definition String.h:69
static TranslatedString DisplayString(const t_type &value)
Converts an object into a TranslatedString. To use this function an object must have overwritten Stri...
Definition TranslatedString.h:54
Logic for reading or writing to a string or a user friendly, TranslatedString.
Definition StringStream.h:230
static void RequestSleep(const TimeSpan &interval)
Represents a timestamp with utilities for manipulation and conversion.
Definition Time.h:54
static Time SystemTime()
Retrieves the current system time.
Stores a time span, or difference between two times, with an optional start time.
Definition TimeSpan.h:46
constexpr fltp08 elapsedSeconds() const
Definition TimeSpan.h:111
const String & englishTranslation() const
Used to lock a particular variable for writing. Only one write lock can be created when no read locks...
Definition RWLock.h:115
Definition ACIColor.h:37
constexpr bool IsInvalid(const t_type &value)
Query if 'value' is valid or invalid. Invalid values should return invalid if used for calculations o...
Definition BaseFunctions.hpp:170
float fltp04
Defines an alias representing a 4 byte floating-point number Bit layout is as follows: -Sign: 1 bit a...
Definition BaseValues.hpp:127
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:96
constexpr t_to cast(const Angle< t_from > &value)
Definition Angle.h:375
CommandSupport
Describes whether a HardwareCommandQueue supports certain commands. This is usually firmware.
Definition HardwareCommandQueue.h:51
Stores long-term statistics for commands executed using HardwareCommandQueue.
Definition HardwareCommandQueue.h:60
TimeSpan response_timeout
Definition HardwareCommandQueue.h:72
uint04 number_of_failures
Definition HardwareCommandQueue.h:69
CommandSupport supports_command
Definition HardwareCommandQueue.h:73
TimeSpan tx_delay
Definition HardwareCommandQueue.h:70
uint04 number_of_attempts
Definition HardwareCommandQueue.h:68
String default_argument
Definition HardwareCommandQueue.h:63
String validation_regex
Definition HardwareCommandQueue.h:62
TimeSpan total_time
Definition HardwareCommandQueue.h:64
String command
Definition HardwareCommandQueue.h:61
TimeSpan rx_delay
Definition HardwareCommandQueue.h:71
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...
Definition BaseValues.hpp:233
Definition HardwareCommandQueue.h:84
t_type command
Definition HardwareCommandQueue.h:85
String regex
Definition HardwareCommandQueue.h:87
String args
Definition HardwareCommandQueue.h:86
void clear()
Definition HardwareCommandQueue.h:88
Definition HardwareCommandQueue.h:96
t_type command
Definition HardwareCommandQueue.h:99
Time start_time
Definition HardwareCommandQueue.h:97
Time end_time
Definition HardwareCommandQueue.h:98