dhgdh

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by joey shelton

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers test_env.cpp Source File

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