Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers greentea_test_env.cpp Source File

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 }