Motor Driver Evaluation Kit NEVB-MTR1-t01-1.0.0
Firmware for NEVB-MTR1-KIT1 for trapezoidal control of BLDC motors using Hall-effect sensors
Loading...
Searching...
No Matches
scpi_parser.cpp
Go to the documentation of this file.
1/* This file has been prepared for Doxygen automatic documentation generation.*/
33
34#include "scpi_parser.h"
35
43void DefaultErrorHandler(SCPI_C c, SCPI_P p, Stream &interface) {}
44
60
72void SCPI_Parser::AddToken_(char *token)
73{
75 {
76 setup_errors.token_overflow = true;
77 return;
78 }
79 size_t token_size = strlen(token);
80 // Remove query symbols
81 if (token[token_size - 1] == '?')
82 token_size--;
83 for (uint8_t i = 0; i < tokens_size_; i++)
84 // Check if the token is already added
85 if ((strncmp(token, tokens_[i], token_size) == 0) and (token_size == strlen(tokens_[i])))
86 return;
87 char *stored_token = new char[token_size + 1];
88 strncpy(stored_token, token, token_size);
89 stored_token[token_size] = '\0';
90 tokens_[tokens_size_] = stored_token;
92}
93
110{
112 return invalid_hash;
113 scpi_hash_t code;
114 code = (tree_code_ == 0) ? hash_magic_offset : tree_code_;
115 if (commands.Size() == 0)
116 return unknown_hash;
117 // Loop all keywords in the command
118 for (uint8_t i = 0; i < commands.Size(); i++)
119 {
120 // Get keywords's length
121 size_t header_length = strlen(commands[i]);
122 // For the last keyword remove the query symbol if needed
123 bool is_query = false;
124 if (i == commands.Size() - 1)
125 {
126 is_query = (commands[i][header_length - 1] == '?');
127 if (is_query)
128 header_length--;
129 }
130
131 // Loop over all the known tokens
132 for (uint8_t j = 0; j < tokens_size_; j++)
133 {
134 // Get the token's short and long lengths
135 size_t short_length = 0;
136 while (isupper(tokens_[j][short_length]))
137 short_length++;
138 size_t long_length = strlen(tokens_[j]);
139
140 // If the token allows numeric suffixes
141 // remove the trailing digits from the keyword
142 if ((tokens_[j][long_length - 1] == '#') and (commands[i][header_length - 1] != '#'))
143 {
144 long_length--;
145 while (isdigit(commands[i][header_length - 1]))
146 header_length--;
147 }
148
149 // Test if the keyword match with the token
150 // otherwise test next token
151 if (header_length == short_length)
152 {
153 for (uint8_t k = 0; k < short_length; k++)
154 if (not(toupper(commands[i][k]) == tokens_[j][k]))
155 goto no_header_token_match;
156 }
157 else if (header_length == long_length)
158 {
159 for (uint8_t k = 0; k < long_length; k++)
160 if (not(toupper(commands[i][k]) == toupper(tokens_[j][k])))
161 goto no_header_token_match;
162 }
163 else
164 {
165 goto no_header_token_match;
166 }
167
168 // Apply the hashing step using token number j
169 // hash(i) = hash(i - 1) * hash_magic_number + j
170 code *= hash_magic_number;
171 code += j;
172 break;
173
174 no_header_token_match:;
175 // If the keyword does not match any token return unknown_hash
176 if (j == (tokens_size_ - 1))
177 return unknown_hash;
178 }
179 // If last keyword is a query, add a hashing step
180 if (is_query)
181 {
182 code *= hash_magic_number;
183 code -= 1;
184 }
185 }
186 return code;
187}
188
205{
206 SCPI_Commands tree_tokens(tree_base);
207 if (tree_tokens.Size() == 0)
208 {
209 tree_code_ = 0;
210 tree_length_ = 0;
211 return;
212 }
213 for (uint8_t i = 0; i < tree_tokens.Size(); i++)
214 AddToken_(tree_tokens[i]);
215 tree_code_ = 0;
216 tree_code_ = this->GetCommandCode_(tree_tokens);
217 tree_length_ = tree_tokens.Size();
218 if (tree_tokens.overflow_error)
219 {
220 setup_errors.branch_overflow = true;
222 }
223}
224
237void SCPI_Parser::SetCommandTreeBase(const char *tree_base)
238{
239 strcpy(msg_buffer_, tree_base);
241}
242
255void SCPI_Parser::SetCommandTreeBase(const __FlashStringHelper *tree_base)
256{
257 strcpy_P(msg_buffer_, (const char *)tree_base);
259}
260
278{
280 {
281 setup_errors.command_overflow = true;
282 return;
283 }
284 SCPI_Commands command_tokens(command);
285 for (uint8_t i = 0; i < command_tokens.Size(); i++)
286 this->AddToken_(command_tokens[i]);
287 scpi_hash_t code = this->GetCommandCode_(command_tokens);
288
289 // Check for errors
290 if (code == unknown_hash)
291 code = invalid_hash;
292 bool overflow_error = command_tokens.overflow_error;
293 overflow_error |= (tree_length_ + command_tokens.Size()) > command_tokens.storage_size;
294 setup_errors.command_overflow |= overflow_error;
295 if (overflow_error)
296 code = invalid_hash;
297
299 callers_[codes_size_] = caller;
300 codes_size_++;
301}
302
316void SCPI_Parser::RegisterCommand(const char *command, SCPI_caller_t caller)
317{
318 strcpy(msg_buffer_, command);
319 this->RegisterCommand(msg_buffer_, caller);
320}
321
335void SCPI_Parser::RegisterCommand(const __FlashStringHelper *command,
336 SCPI_caller_t caller)
337{
338 strcpy_P(msg_buffer_, (const char *)command);
339 this->RegisterCommand(msg_buffer_, caller);
340}
341
359
376void SCPI_Parser::Execute(char *message, Stream &interface)
377{
378 while (message != NULL)
379 {
380 // Save multicomands for later
381 char *multicomands = strpbrk(message, ";");
382 if (multicomands != NULL)
383 {
384 multicomands[0] = '\0';
385 multicomands++;
386 }
387
388 tree_code_ = 0;
389 SCPI_Commands commands(message);
390 message = multicomands;
391 SCPI_Parameters parameters(commands.not_processed_message);
392 scpi_hash_t code = this->GetCommandCode_(commands);
393 if (code == unknown_hash)
394 {
395 // Call ErrorHandler UnknownCommand
397 (*callers_[max_commands])(commands, parameters, interface);
398 continue;
399 }
400 for (uint8_t i = 0; i < codes_size_; i++)
401 if (valid_codes_[i] == code)
402 {
403 (*callers_[i])(commands, parameters, interface);
404 break;
405 }
406 }
407}
408
424void SCPI_Parser::ProcessInput(Stream &interface, const char *term_chars)
425{
426 char *message = this->GetMessage(interface, term_chars);
427 if (message != NULL)
428 {
429 this->Execute(message, interface);
430 }
431}
432
444char *SCPI_Parser::GetMessage(Stream &interface, const char *term_chars)
445{
446 while (interface.available())
447 {
448 // Read the new char
449 msg_buffer_[message_length_] = interface.read();
451 time_checker_ = millis();
452
454 {
455 // Call ErrorHandler due BufferOverflow
457 (*callers_[max_commands])(SCPI_C(), SCPI_P(), interface);
458 message_length_ = 0;
459 return NULL;
460 }
461
462#if SCPI_MAX_SPECIAL_COMMANDS
463 // For the first space only.
464 if (strcspn(msg_buffer_, " ") == message_length_ - 1)
465 {
466 msg_buffer_[message_length_ - 1] = '\0';
467 tree_code_ = 0;
468 SCPI_Commands commands(msg_buffer_);
469 scpi_hash_t code = this->GetCommandCode_(commands);
470 for (uint8_t i = 0; i < special_codes_size_; i++)
471 if (valid_special_codes_[i] == code)
472 {
473 (*special_callers_[i])(commands, interface);
474 message_length_ = 0;
475 return msg_buffer_;
476 }
477 // restore original message.
478 msg_buffer_[message_length_ - 1] = ' ';
479 for (uint8_t i = 0; i < commands.Size() - 1; i++)
480 commands[i][strlen(commands[i])] = ':';
481 commands.not_processed_message--;
482 commands.not_processed_message[0] = ' ';
483 }
484#endif
485
486 // Test for termination chars (end of the message)
488 if (strstr(msg_buffer_, term_chars) != NULL)
489 {
490 // Return the received message
491 msg_buffer_[message_length_ - strlen(term_chars)] = '\0';
492 message_length_ = 0;
493 return msg_buffer_;
494 }
495 }
496 // No more chars available yet
497
498 // Return NULL if no message is incoming
499 if (message_length_ == 0)
500 return NULL;
501
502 // Check for communication timeout
503 if ((millis() - time_checker_) > timeout)
504 {
505 // Call ErrorHandler due Timeout
507 (*callers_[max_commands])(SCPI_C(), SCPI_P(), interface);
508 message_length_ = 0;
509 return NULL;
510 }
511
512 // No errors, be sure to return NULL
513 return NULL;
514}
515
529void SCPI_Parser::PrintDebugInfo(Stream &interface)
530{
531 interface.println(F("*** DEBUG INFO ***\n"));
532 interface.print(F("Max command tree branches: "));
533 interface.print(SCPI_ARRAY_SYZE);
534 interface.println(F(" (SCPI_ARRAY_SYZE)"));
535 if (setup_errors.branch_overflow)
536 interface.println(F(" **ERROR** Max branch size exceeded."));
537 interface.print(F("Max number of parameters: "));
538 interface.print(SCPI_ARRAY_SYZE);
539 interface.println(F(" (SCPI_ARRAY_SYZE)"));
540 interface.print(F("Message buffer size: "));
541 interface.print(buffer_length);
542 interface.println(F(" (SCPI_BUFFER_LENGTH)\n"));
543
544 interface.print(F("TOKENS : "));
545 interface.print(tokens_size_);
546 interface.print(F(" / "));
547 interface.print(max_tokens);
548 interface.println(F(" (SCPI_MAX_TOKENS)"));
549 if (setup_errors.token_overflow)
550 interface.println(F(" **ERROR** Max tokens exceeded."));
551 for (uint8_t i = 0; i < tokens_size_; i++)
552 {
553 interface.print(F("  "));
554 interface.print(i + 1);
555 interface.print(F(":\t"));
556 interface.println(String(tokens_[i]));
557 interface.flush();
558 }
559 interface.println();
560
561 bool hash_crash = false;
562 bool unknown_error = false;
563 bool invalid_error = false;
564 interface.print(F("VALID CODES : "));
565 interface.print(codes_size_);
566 interface.print(F(" / "));
567 interface.print(max_commands);
568 interface.println(F(" (SCPI_MAX_COMMANDS)"));
569 if (setup_errors.command_overflow)
570 interface.println(F(" **ERROR** Max commands exceeded."));
571 interface.println(F("  #\tHash\t\tHandler"));
572 for (uint8_t i = 0; i < codes_size_; i++)
573 {
574 interface.print(F("  "));
575 interface.print(i + 1);
576 interface.print(F(":\t"));
577 interface.print(valid_codes_[i], HEX);
578 if (valid_codes_[i] == unknown_hash)
579 {
580 interface.print(F("!*"));
581 unknown_error = true;
582 }
583 else if (valid_codes_[i] == invalid_hash)
584 {
585 interface.print(F("!%"));
586 invalid_error = true;
587 }
588 else
589 for (uint8_t j = 0; j < i; j++)
590 if (valid_codes_[i] == valid_codes_[j])
591 {
592 interface.print("!!");
593 hash_crash = true;
594 break;
595 }
596 interface.print(F("\t\t0x"));
597 interface.print(long(callers_[i]), HEX);
598 interface.println();
599 interface.flush();
600 }
601 if (unknown_error)
602 interface.println(F(" **ERROR** Tried to register ukwnonk tokens. (!*)"));
603 if (invalid_error)
604 interface.println(F(" **ERROR** Tried to register invalid commands. (!%)"));
605 if (hash_crash)
606 interface.println(F(" **ERROR** Hash crashes found. (!!)"));
607
608#if SCPI_MAX_SPECIAL_COMMANDS
609 hash_crash = false;
610 unknown_error = false;
611 invalid_error = false;
612 interface.println();
613 interface.print(F("VALID SPECIAL CODES : "));
614 interface.print(special_codes_size_);
615 interface.print(F(" / "));
616 interface.print(max_special_commands);
617 interface.println(F(" (SCPI_MAX_SPECIAL_COMMANDS)"));
618 if (setup_errors.special_command_overflow)
619 interface.println(F(" **ERROR** Max special commands exceeded."));
620 interface.println(F("  #\tHash\t\tHandler"));
621 for (uint8_t i = 0; i < special_codes_size_; i++)
622 {
623 interface.print(F("  "));
624 interface.print(i + 1);
625 interface.print(F(":\t"));
626 interface.print(valid_special_codes_[i], HEX);
627 if (valid_special_codes_[i] == unknown_hash)
628 {
629 interface.print(F("!*"));
630 unknown_error = true;
631 }
632 else if (valid_special_codes_[i] == invalid_hash)
633 {
634 interface.print(F("!%"));
635 invalid_error = true;
636 }
637 else
638 for (uint8_t j = 0; j < i; j++)
639 if (valid_special_codes_[i] == valid_special_codes_[j])
640 {
641 interface.print("!!");
642 hash_crash = true;
643 break;
644 }
645 interface.print(F("\t\t0x"));
646 interface.print(long(special_callers_[i]), HEX);
647 interface.println();
648 interface.flush();
649 }
650 if (unknown_error)
651 interface.println(F(" **ERROR** Tried to register ukwnonk tokens. (!*)"));
652 if (invalid_error)
653 interface.println(F(" **ERROR** Tried to register invalid commands. (!%)"));
654 if (hash_crash)
655 interface.println(F(" **ERROR** Hash crashes found. (!!)"));
656#endif
657
658 interface.println(F("\nHASH Configuration:"));
659 interface.print(F("  Hash size: "));
660 interface.print((uint8_t)(sizeof(scpi_hash_t) * 8));
661 interface.println(F("bits (SCPI_HASH_TYPE)"));
662 interface.print(F("  Hash magic number: "));
663 interface.println(hash_magic_number);
664 interface.print(F("  Hash magic offset: "));
665 interface.println(hash_magic_offset);
666 interface.println(F("\n*******************\n"));
667}
668
669#if SCPI_MAX_SPECIAL_COMMANDS
670
689void SCPI_Parser::RegisterSpecialCommand(char *command,
691{
692 if (special_codes_size_ >= max_special_commands)
693 {
694 setup_errors.special_command_overflow = true;
695 return;
696 }
697 SCPI_Commands command_tokens(command);
698 for (uint8_t i = 0; i < command_tokens.Size(); i++)
699 this->AddToken_(command_tokens[i]);
700 scpi_hash_t code = this->GetCommandCode_(command_tokens);
701
702 // Check for errors
703 if (code == unknown_hash)
704 code = invalid_hash;
705 bool overflow_error = command_tokens.overflow_error;
706 overflow_error |= (tree_length_ + command_tokens.Size()) > command_tokens.storage_size;
707 setup_errors.branch_overflow |= overflow_error;
708 if (overflow_error)
709 code = invalid_hash;
710
711 valid_special_codes_[special_codes_size_] = code;
712 special_callers_[special_codes_size_] = caller;
713 special_codes_size_++;
714}
715
729void SCPI_Parser::RegisterSpecialCommand(const char *command,
731{
732 strcpy(msg_buffer_, command);
733 this->RegisterSpecialCommand(msg_buffer_, caller);
734}
735
750void SCPI_Parser::RegisterSpecialCommand(const __FlashStringHelper *command,
752{
753 strcpy_P(msg_buffer_, (const char *)command);
754 this->RegisterSpecialCommand(msg_buffer_, caller);
755}
756
757#endif
Stores parsed command tokens.
Definition scpi_types.h:75
char * not_processed_message
Remaining message text after token parsing.
Definition scpi_types.h:79
Stores parsed command parameters.
Definition scpi_types.h:93
void PrintDebugInfo(Stream &interface)
Prints debug information about the SCPI parser configuration and status to a Stream interface.
ErrorCode last_error
Variable that holds the last error code.
Definition scpi_parser.h:75
scpi_hash_t GetCommandCode_(SCPI_Commands &commands)
Get a hash from a command.
unsigned long timeout
Timeout, in miliseconds, for GetMessage and ProcessInput.
Definition scpi_parser.h:89
void SetErrorHandler(SCPI_caller_t caller)
Sets the function to be used as the error handler.
const uint8_t buffer_length
Length of the message buffer.
uint8_t tokens_size_
Number of stored tokens.
void RegisterCommand(char *command, SCPI_caller_t caller)
Registers a new valid SCPI command and associates a callback function with it.
scpi_hash_t hash_magic_number
Magic number used for hashing the commands.
Definition scpi_parser.h:85
uint8_t tree_length_
TreeBase branch's length (0 for root)
unsigned long time_checker_
Varible used for checking timeout errors.
scpi_hash_t valid_codes_[20]
Registered commands' hash storage.
SCPI_Parser()
SCPI_Parser class constructor.
char msg_buffer_[64]
Message buffer.
const uint8_t max_commands
Max number of registered commands.
void AddToken_(char *token)
Add a token to the tokens' storage.
void SetCommandTreeBase(char *tree_base)
Changes the base of the command tree for subsequent RegisterCommand calls.
const scpi_hash_t invalid_hash
Hash reserved for invalid commands.
const scpi_hash_t unknown_hash
Hash result for unknown commands.
void ProcessInput(Stream &interface, const char *term_chars)
Reads a message from a Stream interface and executes it.
char * GetMessage(Stream &interface, const char *term_chars)
Reads a message from a Stream interface until termination characters are found.
scpi_hash_t hash_magic_offset
Magic offset used for hashing the commands.
Definition scpi_parser.h:87
SCPI_caller_t callers_[20+1]
Pointers to the functions to be called when a valid command is received.
uint8_t codes_size_
Number of registered commands.
scpi_hash_t tree_code_
TreeBase branch's hash used when calculating hashes (0 for root)
const uint8_t max_tokens
Max number of valid tokens.
char * tokens_[20]
Storage for tokens.
void Execute(char *message, Stream &interface)
Processes an incoming SCPI message and executes the associated command if found.
uint8_t message_length_
Length of the readed message.
uint8_t Size() const
Get the number of stored strings.
bool overflow_error
Flag set when exceeding storage_size.
Definition scpi_types.h:58
const uint8_t storage_size
Max number of entries allowed.
Definition scpi_types.h:59
#define SCPI_ARRAY_SYZE
Maximum branch size of the command tree and the maximum number of parameters that can be parsed from ...
Definition scpi_config.h:94
void DefaultErrorHandler(SCPI_C c, SCPI_P p, Stream &interface)
A no-operation function. No error handling is performed when this function is called.
SCPI parser header file.
void(*)(SCPI_Commands, SCPI_Parameters, Stream &) SCPI_caller_t
Void template used with SCPI_Parser::RegisterCommand.
Definition scpi_parser.h:41
void(*)(SCPI_Commands, Stream &) SCPI_special_caller_t
Void template used with SCPI_Parser::RegisterSpecialCommand.
Definition scpi_parser.h:43
uint8_t scpi_hash_t
Alias for SCPI integer hash type defined in SCPI_HASH_TYPE.
Definition scpi_types.h:110
@ BufferOverflow
The message buffer was exceeded during message reception.
Definition scpi_types.h:129
@ Timeout
A timeout occurred before receiving the expected termination characters.
Definition scpi_types.h:126
@ UnknownCommand
An unknown command was received that could not be matched to a known handler.
Definition scpi_types.h:123
SCPI_Parameters SCPI_P
Alias for SCPI_Parameters.
Definition scpi_types.h:106
SCPI_Commands SCPI_C
Alias for SCPI_Commands.
Definition scpi_types.h:102
bool special_command_overflow
Special command storage overflow error.