Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
greentea_test_env.cpp
00001 /* 00002 * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include <ctype.h> 00019 #include <cstdio> 00020 #include <string.h> 00021 #include "mbed.h" 00022 #include "greentea-client/test_env.h" 00023 #include "greentea-client/greentea_serial.h" 00024 #include "greentea-client/greentea_metrics.h" 00025 00026 00027 /** 00028 * Generic test suite transport protocol keys 00029 */ 00030 const char* GREENTEA_TEST_ENV_END = "end"; 00031 const char* GREENTEA_TEST_ENV_EXIT = "__exit"; 00032 const char* GREENTEA_TEST_ENV_SYNC = "__sync"; 00033 const char* GREENTEA_TEST_ENV_TIMEOUT = "__timeout"; 00034 const char* GREENTEA_TEST_ENV_HOST_TEST_NAME = "__host_test_name"; 00035 const char* GREENTEA_TEST_ENV_HOST_TEST_VERSION = "__version"; 00036 00037 /** 00038 * Test suite success code strings 00039 */ 00040 const char* GREENTEA_TEST_ENV_SUCCESS = "success"; 00041 const char* GREENTEA_TEST_ENV_FAILURE = "failure"; 00042 00043 /** 00044 * Test case transport protocol start/finish keys 00045 */ 00046 const char* GREENTEA_TEST_ENV_TESTCASE_NAME = "__testcase_name"; 00047 const char* GREENTEA_TEST_ENV_TESTCASE_COUNT = "__testcase_count"; 00048 const char* GREENTEA_TEST_ENV_TESTCASE_START = "__testcase_start"; 00049 const char* GREENTEA_TEST_ENV_TESTCASE_FINISH = "__testcase_finish"; 00050 const char* GREENTEA_TEST_ENV_TESTCASE_SUMMARY = "__testcase_summary"; 00051 // Code Coverage (LCOV) transport protocol keys 00052 const char* GREENTEA_TEST_ENV_LCOV_START = "__coverage_start"; 00053 00054 /** 00055 * Auxilary functions 00056 */ 00057 static void greentea_notify_timeout(const int); 00058 static void greentea_notify_hosttest(const char *); 00059 static void greentea_notify_completion(const int); 00060 static void greentea_notify_version(); 00061 static void greentea_write_string(const char *str); 00062 00063 /** \brief Handle the handshake with the host 00064 * \details This is contains the shared handhshake functionality that is used between 00065 * GREENTEA_SETUP and GREENTEA_SETUP_UUID. 00066 * This function is blocking. 00067 */ 00068 void _GREENTEA_SETUP_COMMON(const int timeout, const char *host_test_name, char *buffer, size_t size) { 00069 greentea_metrics_setup(); 00070 // Key-value protocol handshake function. Waits for {{__sync;...}} message 00071 // Sync preamble: "{{__sync;0dad4a9d-59a3-4aec-810d-d5fb09d852c1}}" 00072 // Example value of sync_uuid == "0dad4a9d-59a3-4aec-810d-d5fb09d852c1" 00073 00074 char _key[8] = {0}; 00075 00076 while (1) { 00077 greentea_parse_kv(_key, buffer, sizeof(_key), size); 00078 greentea_write_string("mbedmbedmbedmbedmbedmbedmbedmbed\r\n"); 00079 if (strcmp(_key, GREENTEA_TEST_ENV_SYNC) == 0) { 00080 // Found correct __sync message 00081 greentea_send_kv(_key, buffer); 00082 break; 00083 } 00084 } 00085 00086 greentea_notify_version(); 00087 greentea_notify_timeout(timeout); 00088 greentea_notify_hosttest(host_test_name); 00089 } 00090 00091 /** \brief Handshake with host and send setup data (timeout and host test name) 00092 * \details This function will send preamble to master. 00093 * After host test name is received master will invoke host test script 00094 * and add host test's callback handlers to main event loop 00095 * This function is blocking. 00096 */ 00097 extern "C" void GREENTEA_SETUP(const int timeout, const char *host_test_name) { 00098 char _value[GREENTEA_UUID_LENGTH] = {0}; 00099 _GREENTEA_SETUP_COMMON(timeout, host_test_name, _value, GREENTEA_UUID_LENGTH); 00100 } 00101 00102 /** \brief Handshake with host and send setup data (timeout and host test name). Allows you to preserve sync UUID. 00103 * \details This function will send preamble to master. 00104 * After host test name is received master will invoke host test script 00105 * and add host test's callback handlers to main event loop 00106 * This function is blocking. 00107 * This function differs from GREENTEA_SETUP because it allows you to 00108 * preserve the UUID sent during the sync process. 00109 */ 00110 void GREENTEA_SETUP_UUID(const int timeout, const char *host_test_name, char *buffer, size_t size) { 00111 _GREENTEA_SETUP_COMMON(timeout, host_test_name, buffer, size); 00112 } 00113 00114 /** \brief Notify host (__exit message) side that test suite execution was complete 00115 * \result Test suite result 00116 * \details If __exit is not received by host side we will assume TIMEOUT 00117 */ 00118 void GREENTEA_TESTSUITE_RESULT(const int result) { 00119 greentea_notify_completion(result); 00120 } 00121 00122 /** 00123 * Test Case support 00124 */ 00125 00126 /** \brief Notify host side that test case started 00127 * \details test_case_name Test case name 00128 */ 00129 void GREENTEA_TESTCASE_START(const char *test_case_name) { 00130 greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_START, test_case_name); 00131 } 00132 00133 /** \brief Notify host side that test case finished 00134 * \details test_case_name Test case name 00135 * \details result Test case result (0 -OK, non zero...) 00136 */ 00137 void GREENTEA_TESTCASE_FINISH(const char *test_case_name, const size_t passes, const size_t failed) { 00138 greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_FINISH, test_case_name, passes, failed); 00139 } 00140 00141 /** 00142 ***************************************************************************** 00143 * Auxilary functions and key-value protocol support 00144 ***************************************************************************** 00145 */ 00146 00147 00148 /** 00149 ***************************************************************************** 00150 * LCOV support 00151 ***************************************************************************** 00152 */ 00153 #ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE 00154 extern "C" void __gcov_flush(void); 00155 extern bool coverage_report; 00156 00157 /** 00158 * \brief Send code coverage (gcov/LCOV) notification to master 00159 * 00160 * Generates preamble of message sent to notify host about code coverage data dump. 00161 * 00162 * This function is used by mbedOS software 00163 * (see: mbed-drivers/source/retarget.cpp file) to generate code coverage 00164 * messages to host. When code coverage feature is turned on slave will 00165 * print-out code coverage data in form of key-value protocol. 00166 * Message with code coverage data will contain message name, path to code 00167 * coverage output file host will touch and fill with code coverage binary 00168 * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X"). 00169 * 00170 * \param path to file with code coverage payload (set by gcov instrumentation) 00171 * 00172 */ 00173 void greentea_notify_coverage_start(const char *path) { 00174 printf("{{%s;%s;", GREENTEA_TEST_ENV_LCOV_START, path); 00175 } 00176 00177 /** 00178 * \brief Sufix for code coverage message to master (closing statement) 00179 * 00180 * This function is used by mbedOS software 00181 * (see: mbed-drivers/source/retarget.cpp file) to generate code coverage 00182 * messages to host. When code coverage feature is turned on slave will 00183 * print-out code coverage data in form of key-value protocol. 00184 * Message with code coverage data will contain message name, path to code 00185 * coverage output file host will touch and fill with code coverage binary 00186 * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X"). 00187 * 00188 * Companion function greentea_notify_coverage_start() defines code coverage message structure 00189 * 00190 */ 00191 void greentea_notify_coverage_end() { 00192 printf("}}" NL); 00193 } 00194 00195 #endif 00196 00197 /** 00198 ***************************************************************************** 00199 * Key-value protocol support 00200 ***************************************************************************** 00201 */ 00202 00203 /** 00204 * \brief Write the preamble characters to the serial port 00205 * 00206 * This function writes the preamble "{{" which is required 00207 * for key-value comunication between the target and the host. 00208 * This uses a Rawserial object, greentea_serial, which provides 00209 * a direct interface to the USBTX and USBRX serial pins and allows 00210 * the direct writing of characters using the putc() method. 00211 * This suite of functions are provided to allow for serial communication 00212 * to the host from within a thread/ISR. 00213 * 00214 */ 00215 inline void greentea_write_preamble() 00216 { 00217 greentea_serial->putc('{'); 00218 greentea_serial->putc('{'); 00219 } 00220 00221 /** 00222 * \brief Write the postamble characters to the serial port 00223 * 00224 * This function writes the postamble "{{\n" which is required 00225 * for key-value comunication between the target and the host. 00226 * This uses a Rawserial object, greentea_serial, which provides 00227 * a direct interface to the USBTX and USBRX serial pins and allows 00228 * the direct writing of characters using the putc() method. 00229 * This suite of functions are provided to allow for serial communication 00230 * to the host from within a thread/ISR. 00231 * 00232 */ 00233 inline void greentea_write_postamble() 00234 { 00235 greentea_serial->putc('}'); 00236 greentea_serial->putc('}'); 00237 greentea_serial->putc('\r'); 00238 greentea_serial->putc('\n'); 00239 } 00240 00241 /** 00242 * \brief Write a string to the serial port 00243 * 00244 * This function writes a '\0' terminated string from the target 00245 * to the host. It writes directly to the serial port using the 00246 * greentea_serial, Rawserial object. 00247 * 00248 * \param str - string value 00249 * 00250 */ 00251 inline void greentea_write_string(const char *str) 00252 { 00253 while (*str != '\0') { 00254 greentea_serial->putc(*str); 00255 str ++; 00256 } 00257 } 00258 00259 00260 /** 00261 * \brief Write an int to the serial port 00262 * 00263 * This function writes an integer value from the target 00264 * to the host. The integer value is converted to a string and 00265 * and then written character by character directly to the serial 00266 * port using the greentea_serial, Rawserial object. 00267 * sprintf() is used to convert the int to a string. Sprintf if 00268 * inherently thread safe so can be used. 00269 * 00270 * \param val - integer value 00271 * 00272 */ 00273 #define MAX_INT_STRING_LEN 15 00274 inline void greentea_write_int(const int val) 00275 { 00276 char intval[MAX_INT_STRING_LEN]; 00277 unsigned int i = 0; 00278 sprintf(intval, "%d", val); 00279 while (intval[i] != '\0') { 00280 greentea_serial->putc(intval[i]); 00281 i++; 00282 } 00283 } 00284 00285 /** 00286 * \brief Encapsulate and send key-value message from DUT to host 00287 * 00288 * This function uses underlying functions to write directly 00289 * to the serial port, (USBTX). This allows KVs to be used 00290 * from within interrupt context. 00291 * 00292 * \param key Message key (message/event name) 00293 * \param value Message payload, string value 00294 * 00295 */ 00296 extern "C" void greentea_send_kv(const char *key, const char *val) { 00297 if (key && val) { 00298 greentea_write_preamble(); 00299 greentea_write_string(key); 00300 greentea_serial->putc(';'); 00301 greentea_write_string(val); 00302 greentea_write_postamble(); 00303 } 00304 } 00305 00306 /** 00307 * \brief Encapsulate and send key-value message from DUT to host 00308 * 00309 * This function uses underlying functions to write directly 00310 * to the serial port, (USBTX). This allows KVs to be used 00311 * from within interrupt context. 00312 * Last value is an integer to avoid integer to string conversion 00313 * made by the user. 00314 * 00315 * \param key Message key (message/event name) 00316 * \param value Message payload, integer value 00317 * 00318 */ 00319 void greentea_send_kv(const char *key, const int val) { 00320 if (key) { 00321 greentea_write_preamble(); 00322 greentea_write_string(key); 00323 greentea_serial->putc(';'); 00324 greentea_write_int(val); 00325 greentea_write_postamble(); 00326 } 00327 } 00328 00329 /** 00330 * \brief Encapsulate and send key-value-value message from DUT to host 00331 * 00332 * This function uses underlying functions to write directly 00333 * to the serial port, (USBTX). This allows KVs to be used 00334 * from within interrupt context. 00335 * Last value is an integer to avoid integer to string conversion 00336 * made by the user. 00337 * 00338 * \param key Message key (message/event name) 00339 * \param value Message payload, string value 00340 * \param result Send additional integer formatted data 00341 * 00342 */ 00343 void greentea_send_kv(const char *key, const char *val, const int result) { 00344 if (key) { 00345 greentea_write_preamble(); 00346 greentea_write_string(key); 00347 greentea_serial->putc(';'); 00348 greentea_write_string(val); 00349 greentea_serial->putc(';'); 00350 greentea_write_int(result); 00351 greentea_write_postamble(); 00352 00353 } 00354 } 00355 00356 /** 00357 * \brief Encapsulate and send key-value-value-value message from DUT to host 00358 * 00359 * This function uses underlying functions to write directly 00360 * to the serial port, (USBTX). This allows KVs to be used 00361 * from within interrupt context. 00362 * Last 2 values are integers to avoid integer to string conversion 00363 * made by the user. 00364 * 00365 * Names of the parameters: this function is used to send test case 00366 * name with number of passes and failures to host. But it can be used 00367 * to send any key-value-value-value (string-string-integer-integer) 00368 * set to host. 00369 * 00370 * \param key Message key (message/event name) 00371 * \param value Message payload, string value 00372 * \param passes Send additional integer formatted data 00373 * \param failures Send additional integer formatted data 00374 * 00375 */ 00376 void greentea_send_kv(const char *key, const char *val, const int passes, const int failures) { 00377 if (key) { 00378 greentea_write_preamble(); 00379 greentea_write_string(key); 00380 greentea_serial->putc(';'); 00381 greentea_write_string(val); 00382 greentea_serial->putc(';'); 00383 greentea_write_int(passes); 00384 greentea_serial->putc(';'); 00385 greentea_write_int(failures); 00386 greentea_write_postamble(); 00387 } 00388 } 00389 00390 /** 00391 * \brief Encapsulate and send key-value-value message from DUT to host 00392 * 00393 * This function uses underlying functions to write directly 00394 * to the serial port, (USBTX). This allows key-value-value to be used 00395 * from within interrupt context. 00396 * Both values are integers to avoid integer to string conversion 00397 * made by the user. 00398 * 00399 * Names of the parameters: this function is used to send number 00400 * of passes and failures to host. But it can be used to send any 00401 * key-value-value (string-integer-integer) message to host. 00402 * 00403 * \param key Message key (message/event name) 00404 * \param value Message payload, integer value 00405 * \param passes Send additional integer formatted data 00406 * \param failures Send additional integer formatted data 00407 * 00408 */ 00409 void greentea_send_kv(const char *key, const int passes, const int failures) { 00410 if (key) { 00411 greentea_write_preamble(); 00412 greentea_write_string(key); 00413 greentea_serial->putc(';'); 00414 greentea_write_int(passes); 00415 greentea_serial->putc(';'); 00416 greentea_write_int(failures); 00417 greentea_write_postamble(); 00418 } 00419 } 00420 00421 /** 00422 * \brief Send message with timeout to master in seconds 00423 * 00424 * GREENTEA_TEST_ENV_TIMEOUT message is part of preamble 00425 * sent from DUT to host during synchronisation (beginning of test 00426 * suite execution). 00427 * 00428 * Notification about total test suite timeout. Timeout is measured 00429 * from the moment of GREENTEA_TEST_ENV_TIMEOUT reception by host. 00430 * If timeout is reached host (and host test) will be stopped and 00431 * control will return to Greentea. 00432 * 00433 * \param timeout Test suite timeout in seconds 00434 * 00435 */ 00436 static void greentea_notify_timeout(const int timeout) { 00437 greentea_send_kv(GREENTEA_TEST_ENV_TIMEOUT, timeout); 00438 } 00439 00440 /** 00441 * \brief Send host test name to master 00442 * 00443 * GREENTEA_TEST_ENV_HOST_TEST_NAME message is part of preamble 00444 * sent from DUT to host during synchronisation (beginning of test 00445 * suite execution). 00446 * 00447 * Host test Python script implements host side callbacks 00448 * for key-value events sent from DUT to host. Host test's 00449 * callbacks are registered after GREENTEA_TEST_ENV_HOST_TEST_NAME 00450 * message reaches host. 00451 * 00452 * \param host_test_name Host test name, host test will be loaded by mbedhtrun 00453 */ 00454 static void greentea_notify_hosttest(const char *host_test_name) { 00455 greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_NAME, host_test_name); 00456 } 00457 00458 /** 00459 * \brief Send to master information that test suite finished its execution 00460 * 00461 * GREENTEA_TEST_ENV_END and GREENTEA_TEST_ENV_EXIT messages 00462 * are sent just before test suite execution finishes (noting 00463 * else to do). You can place it just before you return from your 00464 * main() function. 00465 * 00466 * Code coverage: If MEBD_CFG_DEBUG_OPTIONS_COVERAGE is set in the 00467 * project via build configuration function will output series 00468 * of code coverage messages GREENTEA_TEST_ENV_LCOV_START with code 00469 * coverage binary data. This data is captured by Greentea and can 00470 * be used to generate LCOV reports. 00471 * 00472 * \param result Test suite result from DUT (0 - FAIl, !0 - SUCCESS) 00473 * 00474 */ 00475 static void greentea_notify_completion(const int result) { 00476 const char *val = result ? GREENTEA_TEST_ENV_SUCCESS : GREENTEA_TEST_ENV_FAILURE; 00477 #ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE 00478 coverage_report = true; 00479 __gcov_flush(); 00480 coverage_report = false; 00481 #endif 00482 greentea_metrics_report(); 00483 greentea_send_kv(GREENTEA_TEST_ENV_END, val); 00484 greentea_send_kv(GREENTEA_TEST_ENV_EXIT, 0); 00485 } 00486 00487 /** 00488 * \brief Send to master greentea-client version 00489 */ 00490 static void greentea_notify_version() { 00491 greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_VERSION, MBED_GREENTEA_CLIENT_VERSION_STRING); 00492 } 00493 00494 /** 00495 ***************************************************************************** 00496 * Parse engine for KV values which replaces scanf 00497 ***************************************************************************** 00498 * 00499 * Example usage: 00500 * 00501 * char key[10]; 00502 * char value[48]; 00503 * 00504 * greentea_parse_kv(key, value, 10, 48); 00505 * greentea_parse_kv(key, value, 10, 48); 00506 * 00507 */ 00508 00509 00510 static int gettok(char *, const int); 00511 static int getNextToken(char *, const int); 00512 static int HandleKV(char *, char *, const int, const int); 00513 static int isstring(int); 00514 00515 /** 00516 * \brief Current token of key-value protocol's tokenizer 00517 */ 00518 static int CurTok = 0; 00519 00520 /** 00521 * \enum Token enumeration for key-value protocol tokenizer 00522 * 00523 * This enum is used by key-value protocol tokenizer 00524 * to detect parts of protocol in stream. 00525 * 00526 * tok_eof ::= EOF (end of file) 00527 * tok_open ::= "{{" 00528 * tok_close ::= "}}" 00529 * tok_semicolon ::= ";" 00530 * tok_string ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function 00531 * 00532 */ 00533 enum Token { 00534 tok_eof = -1, 00535 tok_open = -2, 00536 tok_close = -3, 00537 tok_semicolon = -4, 00538 tok_string = -5 00539 }; 00540 00541 /** 00542 * \brief Read character from stream of data 00543 * 00544 * Closure for default "get character" function. 00545 * This function is used to read characters from the stream 00546 * (default is serial port RX). Key-value protocol tokenizer 00547 * will build stream of tokes used by key-value protocol to 00548 * detect valid messages. 00549 * 00550 * If EOF is received parser finishes parsing and stops. In 00551 * situation where we have serial port stream of data parsing 00552 * goes forever. 00553 * 00554 * \return Next character from the stream or EOF if stream has ended. 00555 * 00556 */ 00557 extern "C" int greentea_getc() { 00558 return greentea_serial->getc(); 00559 } 00560 00561 /** 00562 * \brief parse input string for key-value pairs: {{key;value}} 00563 * This function should replace scanf() used to 00564 * check for incoming messages from master. All data 00565 * parsed and rejected is discarded. 00566 * 00567 * \param out_key Ouput data with key 00568 * \param out_value Ouput data with value 00569 * \param out_key_size out_key total size 00570 * \param out_value_size out_value total data 00571 * 00572 * success != 0 when key-value pair was found 00573 * success == 0 when end of the stream was found 00574 * 00575 */ 00576 extern "C" int greentea_parse_kv(char *out_key, 00577 char *out_value, 00578 const int out_key_size, 00579 const int out_value_size) { 00580 getNextToken(0, 0); 00581 while (1) { 00582 switch (CurTok) { 00583 case tok_eof: 00584 return 0; 00585 00586 case tok_open: 00587 if (HandleKV(out_key, out_value, out_key_size, out_value_size)) { 00588 // We've found {{ KEY ; VALUE }} expression 00589 return 1; 00590 } 00591 break; 00592 00593 default: 00594 // Load next token and pray... 00595 getNextToken(0, 0); 00596 break; 00597 } 00598 } 00599 } 00600 00601 /** 00602 * \brief Get next token from stream 00603 * 00604 * Key-value TOKENIZER feature 00605 * 00606 * This function is used by key-value parser determine 00607 * if key-value message is embedded in stream data. 00608 * 00609 * \param str Output parameters to store token string value 00610 * \param str_size Size of 'str' parameter in bytes (characters) 00611 * 00612 */ 00613 static int getNextToken(char *str, const int str_size) { 00614 return CurTok = gettok(str, str_size); 00615 } 00616 00617 /** 00618 * \brief Check if character is punctuation character 00619 * 00620 * Auxilary key-value TOKENIZER function 00621 * 00622 * Defines if character is in subset of allowed punctuation 00623 * characters which can be part of a key or value string. 00624 * Not allowed characters are: ";{}" 00625 * 00626 * \param c Input character to check 00627 * \return Return 1 if character is allowed punctuation character, otherwise return false 00628 * 00629 */ 00630 static int ispunctuation(int c) { 00631 static const char punctuation[] = "_-!@#$%^&*()=+:<>,./?\\\"'"; // No ";{}" 00632 for (size_t i=0; i< sizeof(punctuation); ++i) { 00633 if (c == punctuation[i]) { 00634 return 1; 00635 } 00636 } 00637 return 0; 00638 } 00639 00640 /** 00641 * \brief Check if character is string token character 00642 * 00643 * Auxilary key-value TOKENIZER function 00644 * 00645 * Defines if character is in subset of allowed string 00646 * token characters. 00647 * String defines set of characters which can be a key or value string. 00648 * 00649 * Allowed subset includes: 00650 * - Alphanumerical characters 00651 * - Digits 00652 * - White spaces and 00653 * - subset of punctuation characters. 00654 * 00655 * \param c Input character to check 00656 * \return Return 1 if character is allowed punctuation character, otherwise return false 00657 * 00658 */ 00659 static int isstring(int c) { 00660 return (isalpha(c) || 00661 isdigit(c) || 00662 isspace(c) || 00663 ispunctuation(c)); 00664 } 00665 00666 /** 00667 * \brief TOKENIZER of key-value protocol 00668 * 00669 * Actual key-value TOKENIZER engine 00670 * 00671 * TOKENIZER defines #Token enum to map recognized tokens to integer values. 00672 * 00673 * <TOK_EOF> ::= EOF (end of file) 00674 * <TOK_OPEN> ::= "{{" 00675 * <TOK_CLOSE> ::= "}}" 00676 * <TOK_SEMICOLON> ::= ";" 00677 * <TOK_STRING> ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function * 00678 * 00679 * \param out_str Output string with parsed token (string) 00680 * \param str_size Size of str buffer we can use 00681 * 00682 * \return Return #Token enum value used by parser to check for key-value occurrences 00683 * 00684 */ 00685 static int gettok(char *out_str, const int str_size) { 00686 static int LastChar = '!'; 00687 static int str_idx = 0; 00688 00689 // whitespace ::= 00690 while (isspace(LastChar)) { 00691 LastChar = greentea_getc(); 00692 } 00693 00694 // string ::= [a-zA-Z0-9_-!@#$%^&*()]+ 00695 if (isstring(LastChar)) { 00696 str_idx = 0; 00697 if (out_str && str_idx < str_size - 1) { 00698 out_str[str_idx++] = LastChar; 00699 } 00700 00701 while (isstring((LastChar = greentea_getc()))) 00702 if (out_str && str_idx < str_size - 1) { 00703 out_str[str_idx++] = LastChar; 00704 } 00705 if (out_str && str_idx < str_size) { 00706 out_str[str_idx] = '\0'; 00707 } 00708 00709 return tok_string; 00710 } 00711 00712 // semicolon ::= ';' 00713 if (LastChar == ';') { 00714 LastChar = greentea_getc(); 00715 return tok_semicolon; 00716 } 00717 00718 // open ::= '{{' 00719 if (LastChar == '{') { 00720 LastChar = greentea_getc(); 00721 if (LastChar == '{') { 00722 LastChar = greentea_getc(); 00723 return tok_open; 00724 } 00725 } 00726 00727 // close ::= '}' 00728 if (LastChar == '}') { 00729 LastChar = greentea_getc(); 00730 if (LastChar == '}') { 00731 return tok_close; 00732 } 00733 } 00734 00735 if (LastChar == EOF) 00736 return tok_eof; 00737 00738 // Otherwise, just return the character as its ascii value. 00739 int ThisChar = LastChar; 00740 LastChar = greentea_getc(); 00741 return ThisChar; 00742 } 00743 00744 /** 00745 * \brief Key-value parser 00746 * 00747 * Key-value message grammar 00748 * 00749 * <MESSAGE>: <TOK_OPEN> <TOK_STRING> <TOK_SEMICOLON> <TOK_STRING> <TOK_CLOSE> 00750 * 00751 * Examples: 00752 * message: "{{__timeout; 1000}}" 00753 * "{{__sync; 12345678-1234-5678-1234-567812345678}}" 00754 * 00755 * \param out_key Output buffer to store key string value 00756 * \param out_value Output buffer to store value string value 00757 * \param out_key_size Buffer 'out_key' buffer size 00758 * \param out_value_size Buffer 'out_value_size' buffer size 00759 * \return Returns 1 if key-value message was parsed successfully in stream of tokens from tokenizer 00760 * 00761 */ 00762 static int HandleKV(char *out_key, 00763 char *out_value, 00764 const int out_key_size, 00765 const int out_value_size) { 00766 // We already started with <open> 00767 if (getNextToken(out_key, out_key_size) == tok_string) { 00768 if (getNextToken(0, 0) == tok_semicolon) { 00769 if (getNextToken(out_value, out_value_size) == tok_string) { 00770 if (getNextToken(0, 0) == tok_close) { 00771 // <open> <string> <semicolon> <string> <close> 00772 // Found "{{KEY;VALUE}}" expression 00773 return 1; 00774 } 00775 } 00776 } 00777 } 00778 getNextToken(0, 0); 00779 return 0; 00780 }
Generated on Sun Jul 17 2022 08:25:23 by 1.7.2