Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
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 Fri Jul 22 2022 04:53:50 by
1.7.2
