76 setup_errors.token_overflow =
true;
79 size_t token_size = strlen(token);
81 if (token[token_size - 1] ==
'?')
85 if ((strncmp(token,
tokens_[i], token_size) == 0) and (token_size == strlen(
tokens_[i])))
87 char *stored_token =
new char[token_size + 1];
88 strncpy(stored_token, token, token_size);
89 stored_token[token_size] =
'\0';
115 if (commands.
Size() == 0)
118 for (uint8_t i = 0; i < commands.
Size(); i++)
121 size_t header_length = strlen(commands[i]);
123 bool is_query =
false;
124 if (i == commands.
Size() - 1)
126 is_query = (commands[i][header_length - 1] ==
'?');
135 size_t short_length = 0;
136 while (isupper(
tokens_[j][short_length]))
138 size_t long_length = strlen(
tokens_[j]);
142 if ((
tokens_[j][long_length - 1] ==
'#') and (commands[i][header_length - 1] !=
'#'))
145 while (isdigit(commands[i][header_length - 1]))
151 if (header_length == short_length)
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;
157 else if (header_length == long_length)
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;
165 goto no_header_token_match;
174 no_header_token_match:;
207 if (tree_tokens.
Size() == 0)
213 for (uint8_t i = 0; i < tree_tokens.
Size(); i++)
220 setup_errors.branch_overflow =
true;
281 setup_errors.command_overflow =
true;
285 for (uint8_t i = 0; i < command_tokens.
Size(); i++)
294 setup_errors.command_overflow |= overflow_error;
378 while (message != NULL)
381 char *multicomands = strpbrk(message,
";");
382 if (multicomands != NULL)
384 multicomands[0] =
'\0';
390 message = multicomands;
403 (*
callers_[i])(commands, parameters, interface);
426 char *message = this->
GetMessage(interface, term_chars);
429 this->
Execute(message, interface);
446 while (interface.available())
462#if SCPI_MAX_SPECIAL_COMMANDS
470 for (uint8_t i = 0; i < special_codes_size_; i++)
471 if (valid_special_codes_[i] == code)
473 (*special_callers_[i])(commands, interface);
479 for (uint8_t i = 0; i < commands.
Size() - 1; i++)
480 commands[i][strlen(commands[i])] =
':';
531 interface.println(F(
"*** DEBUG INFO ***\n"));
532 interface.print(F(
"Max command tree branches: "));
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: "));
539 interface.println(F(
" (SCPI_ARRAY_SYZE)"));
540 interface.print(F(
"Message buffer size: "));
542 interface.println(F(
" (SCPI_BUFFER_LENGTH)\n"));
544 interface.print(F(
"TOKENS : "));
546 interface.print(F(
" / "));
548 interface.println(F(
" (SCPI_MAX_TOKENS)"));
549 if (setup_errors.token_overflow)
550 interface.println(F(
" **ERROR** Max tokens exceeded."));
553 interface.print(F(
" "));
554 interface.print(i + 1);
555 interface.print(F(
":\t"));
556 interface.println(String(
tokens_[i]));
561 bool hash_crash =
false;
562 bool unknown_error =
false;
563 bool invalid_error =
false;
564 interface.print(F(
"VALID CODES : "));
566 interface.print(F(
" / "));
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"));
574 interface.print(F(
" "));
575 interface.print(i + 1);
576 interface.print(F(
":\t"));
580 interface.print(F(
"!*"));
581 unknown_error =
true;
585 interface.print(F(
"!%"));
586 invalid_error =
true;
589 for (uint8_t j = 0; j < i; j++)
592 interface.print(
"!!");
596 interface.print(F(
"\t\t0x"));
597 interface.print(
long(
callers_[i]), HEX);
602 interface.println(F(
" **ERROR** Tried to register ukwnonk tokens. (!*)"));
604 interface.println(F(
" **ERROR** Tried to register invalid commands. (!%)"));
606 interface.println(F(
" **ERROR** Hash crashes found. (!!)"));
608#if SCPI_MAX_SPECIAL_COMMANDS
610 unknown_error =
false;
611 invalid_error =
false;
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++)
623 interface.print(F(
" "));
624 interface.print(i + 1);
625 interface.print(F(
":\t"));
626 interface.print(valid_special_codes_[i], HEX);
629 interface.print(F(
"!*"));
630 unknown_error =
true;
634 interface.print(F(
"!%"));
635 invalid_error =
true;
638 for (uint8_t j = 0; j < i; j++)
639 if (valid_special_codes_[i] == valid_special_codes_[j])
641 interface.print(
"!!");
645 interface.print(F(
"\t\t0x"));
646 interface.print(
long(special_callers_[i]), HEX);
651 interface.println(F(
" **ERROR** Tried to register ukwnonk tokens. (!*)"));
653 interface.println(F(
" **ERROR** Tried to register invalid commands. (!%)"));
655 interface.println(F(
" **ERROR** Hash crashes found. (!!)"));
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: "));
664 interface.print(F(
" Hash magic offset: "));
666 interface.println(F(
"\n*******************\n"));
669#if SCPI_MAX_SPECIAL_COMMANDS
689void SCPI_Parser::RegisterSpecialCommand(
char *command,
692 if (special_codes_size_ >= max_special_commands)
697 SCPI_Commands command_tokens(command);
698 for (uint8_t i = 0; i < command_tokens.Size(); i++)
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;
711 valid_special_codes_[special_codes_size_] = code;
712 special_callers_[special_codes_size_] = caller;
713 special_codes_size_++;
729void SCPI_Parser::RegisterSpecialCommand(
const char *command,
750void SCPI_Parser::RegisterSpecialCommand(
const __FlashStringHelper *command,
Stores parsed command tokens.
char * not_processed_message
Remaining message text after token parsing.
Stores parsed command parameters.
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.
scpi_hash_t GetCommandCode_(SCPI_Commands &commands)
Get a hash from a command.
unsigned long timeout
Timeout, in miliseconds, for GetMessage and ProcessInput.
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.
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.
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.
const uint8_t storage_size
Max number of entries allowed.
#define SCPI_ARRAY_SYZE
Maximum branch size of the command tree and the maximum number of parameters that can be parsed from ...
void DefaultErrorHandler(SCPI_C c, SCPI_P p, Stream &interface)
A no-operation function. No error handling is performed when this function is called.
void(*)(SCPI_Commands, SCPI_Parameters, Stream &) SCPI_caller_t
Void template used with SCPI_Parser::RegisterCommand.
void(*)(SCPI_Commands, Stream &) SCPI_special_caller_t
Void template used with SCPI_Parser::RegisterSpecialCommand.
uint8_t scpi_hash_t
Alias for SCPI integer hash type defined in SCPI_HASH_TYPE.
@ BufferOverflow
The message buffer was exceeded during message reception.
@ Timeout
A timeout occurred before receiving the expected termination characters.
@ UnknownCommand
An unknown command was received that could not be matched to a known handler.
SCPI_Parameters SCPI_P
Alias for SCPI_Parameters.
SCPI_Commands SCPI_C
Alias for SCPI_Commands.
bool special_command_overflow
Special command storage overflow error.