mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

UserRevisionLine numberNew contents of line
be_bryan 0:b74591d5ab33 1 /*
be_bryan 0:b74591d5ab33 2 * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
be_bryan 0:b74591d5ab33 3 * SPDX-License-Identifier: Apache-2.0
be_bryan 0:b74591d5ab33 4 *
be_bryan 0:b74591d5ab33 5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
be_bryan 0:b74591d5ab33 6 * not use this file except in compliance with the License.
be_bryan 0:b74591d5ab33 7 * You may obtain a copy of the License at
be_bryan 0:b74591d5ab33 8 *
be_bryan 0:b74591d5ab33 9 * http://www.apache.org/licenses/LICENSE-2.0
be_bryan 0:b74591d5ab33 10 *
be_bryan 0:b74591d5ab33 11 * Unless required by applicable law or agreed to in writing, software
be_bryan 0:b74591d5ab33 12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
be_bryan 0:b74591d5ab33 13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
be_bryan 0:b74591d5ab33 14 * See the License for the specific language governing permissions and
be_bryan 0:b74591d5ab33 15 * limitations under the License.
be_bryan 0:b74591d5ab33 16 */
be_bryan 0:b74591d5ab33 17
be_bryan 0:b74591d5ab33 18 #include <ctype.h>
be_bryan 0:b74591d5ab33 19 #include <cstdio>
be_bryan 0:b74591d5ab33 20 #include <string.h>
be_bryan 0:b74591d5ab33 21 #include "mbed.h"
be_bryan 0:b74591d5ab33 22 #include "greentea-client/test_env.h"
be_bryan 0:b74591d5ab33 23 #include "greentea-client/greentea_serial.h"
be_bryan 0:b74591d5ab33 24 #include "greentea-client/greentea_metrics.h"
be_bryan 0:b74591d5ab33 25
be_bryan 0:b74591d5ab33 26
be_bryan 0:b74591d5ab33 27 /**
be_bryan 0:b74591d5ab33 28 * Generic test suite transport protocol keys
be_bryan 0:b74591d5ab33 29 */
be_bryan 0:b74591d5ab33 30 const char* GREENTEA_TEST_ENV_END = "end";
be_bryan 0:b74591d5ab33 31 const char* GREENTEA_TEST_ENV_EXIT = "__exit";
be_bryan 0:b74591d5ab33 32 const char* GREENTEA_TEST_ENV_SYNC = "__sync";
be_bryan 0:b74591d5ab33 33 const char* GREENTEA_TEST_ENV_TIMEOUT = "__timeout";
be_bryan 0:b74591d5ab33 34 const char* GREENTEA_TEST_ENV_HOST_TEST_NAME = "__host_test_name";
be_bryan 0:b74591d5ab33 35 const char* GREENTEA_TEST_ENV_HOST_TEST_VERSION = "__version";
be_bryan 0:b74591d5ab33 36
be_bryan 0:b74591d5ab33 37 /**
be_bryan 0:b74591d5ab33 38 * Test suite success code strings
be_bryan 0:b74591d5ab33 39 */
be_bryan 0:b74591d5ab33 40 const char* GREENTEA_TEST_ENV_SUCCESS = "success";
be_bryan 0:b74591d5ab33 41 const char* GREENTEA_TEST_ENV_FAILURE = "failure";
be_bryan 0:b74591d5ab33 42
be_bryan 0:b74591d5ab33 43 /**
be_bryan 0:b74591d5ab33 44 * Test case transport protocol start/finish keys
be_bryan 0:b74591d5ab33 45 */
be_bryan 0:b74591d5ab33 46 const char* GREENTEA_TEST_ENV_TESTCASE_NAME = "__testcase_name";
be_bryan 0:b74591d5ab33 47 const char* GREENTEA_TEST_ENV_TESTCASE_COUNT = "__testcase_count";
be_bryan 0:b74591d5ab33 48 const char* GREENTEA_TEST_ENV_TESTCASE_START = "__testcase_start";
be_bryan 0:b74591d5ab33 49 const char* GREENTEA_TEST_ENV_TESTCASE_FINISH = "__testcase_finish";
be_bryan 0:b74591d5ab33 50 const char* GREENTEA_TEST_ENV_TESTCASE_SUMMARY = "__testcase_summary";
be_bryan 0:b74591d5ab33 51 // Code Coverage (LCOV) transport protocol keys
be_bryan 0:b74591d5ab33 52 const char* GREENTEA_TEST_ENV_LCOV_START = "__coverage_start";
be_bryan 0:b74591d5ab33 53
be_bryan 0:b74591d5ab33 54 /**
be_bryan 0:b74591d5ab33 55 * Auxilary functions
be_bryan 0:b74591d5ab33 56 */
be_bryan 0:b74591d5ab33 57 static void greentea_notify_timeout(const int);
be_bryan 0:b74591d5ab33 58 static void greentea_notify_hosttest(const char *);
be_bryan 0:b74591d5ab33 59 static void greentea_notify_completion(const int);
be_bryan 0:b74591d5ab33 60 static void greentea_notify_version();
be_bryan 0:b74591d5ab33 61 static void greentea_write_string(const char *str);
be_bryan 0:b74591d5ab33 62
be_bryan 0:b74591d5ab33 63 /** \brief Handle the handshake with the host
be_bryan 0:b74591d5ab33 64 * \details This is contains the shared handhshake functionality that is used between
be_bryan 0:b74591d5ab33 65 * GREENTEA_SETUP and GREENTEA_SETUP_UUID.
be_bryan 0:b74591d5ab33 66 * This function is blocking.
be_bryan 0:b74591d5ab33 67 */
be_bryan 0:b74591d5ab33 68 void _GREENTEA_SETUP_COMMON(const int timeout, const char *host_test_name, char *buffer, size_t size) {
be_bryan 0:b74591d5ab33 69 greentea_metrics_setup();
be_bryan 0:b74591d5ab33 70 // Key-value protocol handshake function. Waits for {{__sync;...}} message
be_bryan 0:b74591d5ab33 71 // Sync preamble: "{{__sync;0dad4a9d-59a3-4aec-810d-d5fb09d852c1}}"
be_bryan 0:b74591d5ab33 72 // Example value of sync_uuid == "0dad4a9d-59a3-4aec-810d-d5fb09d852c1"
be_bryan 0:b74591d5ab33 73
be_bryan 0:b74591d5ab33 74 char _key[8] = {0};
be_bryan 0:b74591d5ab33 75
be_bryan 0:b74591d5ab33 76 while (1) {
be_bryan 0:b74591d5ab33 77 greentea_parse_kv(_key, buffer, sizeof(_key), size);
be_bryan 0:b74591d5ab33 78 greentea_write_string("mbedmbedmbedmbedmbedmbedmbedmbed\r\n");
be_bryan 0:b74591d5ab33 79 if (strcmp(_key, GREENTEA_TEST_ENV_SYNC) == 0) {
be_bryan 0:b74591d5ab33 80 // Found correct __sync message
be_bryan 0:b74591d5ab33 81 greentea_send_kv(_key, buffer);
be_bryan 0:b74591d5ab33 82 break;
be_bryan 0:b74591d5ab33 83 }
be_bryan 0:b74591d5ab33 84 }
be_bryan 0:b74591d5ab33 85
be_bryan 0:b74591d5ab33 86 greentea_notify_version();
be_bryan 0:b74591d5ab33 87 greentea_notify_timeout(timeout);
be_bryan 0:b74591d5ab33 88 greentea_notify_hosttest(host_test_name);
be_bryan 0:b74591d5ab33 89 }
be_bryan 0:b74591d5ab33 90
be_bryan 0:b74591d5ab33 91 /** \brief Handshake with host and send setup data (timeout and host test name)
be_bryan 0:b74591d5ab33 92 * \details This function will send preamble to master.
be_bryan 0:b74591d5ab33 93 * After host test name is received master will invoke host test script
be_bryan 0:b74591d5ab33 94 * and add host test's callback handlers to main event loop
be_bryan 0:b74591d5ab33 95 * This function is blocking.
be_bryan 0:b74591d5ab33 96 */
be_bryan 0:b74591d5ab33 97 extern "C" void GREENTEA_SETUP(const int timeout, const char *host_test_name) {
be_bryan 0:b74591d5ab33 98 char _value[GREENTEA_UUID_LENGTH] = {0};
be_bryan 0:b74591d5ab33 99 _GREENTEA_SETUP_COMMON(timeout, host_test_name, _value, GREENTEA_UUID_LENGTH);
be_bryan 0:b74591d5ab33 100 }
be_bryan 0:b74591d5ab33 101
be_bryan 0:b74591d5ab33 102 /** \brief Handshake with host and send setup data (timeout and host test name). Allows you to preserve sync UUID.
be_bryan 0:b74591d5ab33 103 * \details This function will send preamble to master.
be_bryan 0:b74591d5ab33 104 * After host test name is received master will invoke host test script
be_bryan 0:b74591d5ab33 105 * and add host test's callback handlers to main event loop
be_bryan 0:b74591d5ab33 106 * This function is blocking.
be_bryan 0:b74591d5ab33 107 * This function differs from GREENTEA_SETUP because it allows you to
be_bryan 0:b74591d5ab33 108 * preserve the UUID sent during the sync process.
be_bryan 0:b74591d5ab33 109 */
be_bryan 0:b74591d5ab33 110 void GREENTEA_SETUP_UUID(const int timeout, const char *host_test_name, char *buffer, size_t size) {
be_bryan 0:b74591d5ab33 111 _GREENTEA_SETUP_COMMON(timeout, host_test_name, buffer, size);
be_bryan 0:b74591d5ab33 112 }
be_bryan 0:b74591d5ab33 113
be_bryan 0:b74591d5ab33 114 /** \brief Notify host (__exit message) side that test suite execution was complete
be_bryan 0:b74591d5ab33 115 * \result Test suite result
be_bryan 0:b74591d5ab33 116 * \details If __exit is not received by host side we will assume TIMEOUT
be_bryan 0:b74591d5ab33 117 */
be_bryan 0:b74591d5ab33 118 void GREENTEA_TESTSUITE_RESULT(const int result) {
be_bryan 0:b74591d5ab33 119 greentea_notify_completion(result);
be_bryan 0:b74591d5ab33 120 }
be_bryan 0:b74591d5ab33 121
be_bryan 0:b74591d5ab33 122 /**
be_bryan 0:b74591d5ab33 123 * Test Case support
be_bryan 0:b74591d5ab33 124 */
be_bryan 0:b74591d5ab33 125
be_bryan 0:b74591d5ab33 126 /** \brief Notify host side that test case started
be_bryan 0:b74591d5ab33 127 * \details test_case_name Test case name
be_bryan 0:b74591d5ab33 128 */
be_bryan 0:b74591d5ab33 129 void GREENTEA_TESTCASE_START(const char *test_case_name) {
be_bryan 0:b74591d5ab33 130 greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_START, test_case_name);
be_bryan 0:b74591d5ab33 131 }
be_bryan 0:b74591d5ab33 132
be_bryan 0:b74591d5ab33 133 /** \brief Notify host side that test case finished
be_bryan 0:b74591d5ab33 134 * \details test_case_name Test case name
be_bryan 0:b74591d5ab33 135 * \details result Test case result (0 -OK, non zero...)
be_bryan 0:b74591d5ab33 136 */
be_bryan 0:b74591d5ab33 137 void GREENTEA_TESTCASE_FINISH(const char *test_case_name, const size_t passes, const size_t failed) {
be_bryan 0:b74591d5ab33 138 greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_FINISH, test_case_name, passes, failed);
be_bryan 0:b74591d5ab33 139 }
be_bryan 0:b74591d5ab33 140
be_bryan 0:b74591d5ab33 141 /**
be_bryan 0:b74591d5ab33 142 *****************************************************************************
be_bryan 0:b74591d5ab33 143 * Auxilary functions and key-value protocol support
be_bryan 0:b74591d5ab33 144 *****************************************************************************
be_bryan 0:b74591d5ab33 145 */
be_bryan 0:b74591d5ab33 146
be_bryan 0:b74591d5ab33 147
be_bryan 0:b74591d5ab33 148 /**
be_bryan 0:b74591d5ab33 149 *****************************************************************************
be_bryan 0:b74591d5ab33 150 * LCOV support
be_bryan 0:b74591d5ab33 151 *****************************************************************************
be_bryan 0:b74591d5ab33 152 */
be_bryan 0:b74591d5ab33 153 #ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE
be_bryan 0:b74591d5ab33 154 extern "C" void __gcov_flush(void);
be_bryan 0:b74591d5ab33 155 extern bool coverage_report;
be_bryan 0:b74591d5ab33 156
be_bryan 0:b74591d5ab33 157 /**
be_bryan 0:b74591d5ab33 158 * \brief Send code coverage (gcov/LCOV) notification to master
be_bryan 0:b74591d5ab33 159 *
be_bryan 0:b74591d5ab33 160 * Generates preamble of message sent to notify host about code coverage data dump.
be_bryan 0:b74591d5ab33 161 *
be_bryan 0:b74591d5ab33 162 * This function is used by mbedOS software
be_bryan 0:b74591d5ab33 163 * (see: mbed-drivers/source/retarget.cpp file) to generate code coverage
be_bryan 0:b74591d5ab33 164 * messages to host. When code coverage feature is turned on slave will
be_bryan 0:b74591d5ab33 165 * print-out code coverage data in form of key-value protocol.
be_bryan 0:b74591d5ab33 166 * Message with code coverage data will contain message name, path to code
be_bryan 0:b74591d5ab33 167 * coverage output file host will touch and fill with code coverage binary
be_bryan 0:b74591d5ab33 168 * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X").
be_bryan 0:b74591d5ab33 169 *
be_bryan 0:b74591d5ab33 170 * \param path to file with code coverage payload (set by gcov instrumentation)
be_bryan 0:b74591d5ab33 171 *
be_bryan 0:b74591d5ab33 172 */
be_bryan 0:b74591d5ab33 173 void greentea_notify_coverage_start(const char *path) {
be_bryan 0:b74591d5ab33 174 printf("{{%s;%s;", GREENTEA_TEST_ENV_LCOV_START, path);
be_bryan 0:b74591d5ab33 175 }
be_bryan 0:b74591d5ab33 176
be_bryan 0:b74591d5ab33 177 /**
be_bryan 0:b74591d5ab33 178 * \brief Sufix for code coverage message to master (closing statement)
be_bryan 0:b74591d5ab33 179 *
be_bryan 0:b74591d5ab33 180 * This function is used by mbedOS software
be_bryan 0:b74591d5ab33 181 * (see: mbed-drivers/source/retarget.cpp file) to generate code coverage
be_bryan 0:b74591d5ab33 182 * messages to host. When code coverage feature is turned on slave will
be_bryan 0:b74591d5ab33 183 * print-out code coverage data in form of key-value protocol.
be_bryan 0:b74591d5ab33 184 * Message with code coverage data will contain message name, path to code
be_bryan 0:b74591d5ab33 185 * coverage output file host will touch and fill with code coverage binary
be_bryan 0:b74591d5ab33 186 * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X").
be_bryan 0:b74591d5ab33 187 *
be_bryan 0:b74591d5ab33 188 * Companion function greentea_notify_coverage_start() defines code coverage message structure
be_bryan 0:b74591d5ab33 189 *
be_bryan 0:b74591d5ab33 190 */
be_bryan 0:b74591d5ab33 191 void greentea_notify_coverage_end() {
be_bryan 0:b74591d5ab33 192 printf("}}" NL);
be_bryan 0:b74591d5ab33 193 }
be_bryan 0:b74591d5ab33 194
be_bryan 0:b74591d5ab33 195 #endif
be_bryan 0:b74591d5ab33 196
be_bryan 0:b74591d5ab33 197 /**
be_bryan 0:b74591d5ab33 198 *****************************************************************************
be_bryan 0:b74591d5ab33 199 * Key-value protocol support
be_bryan 0:b74591d5ab33 200 *****************************************************************************
be_bryan 0:b74591d5ab33 201 */
be_bryan 0:b74591d5ab33 202
be_bryan 0:b74591d5ab33 203 /**
be_bryan 0:b74591d5ab33 204 * \brief Write the preamble characters to the serial port
be_bryan 0:b74591d5ab33 205 *
be_bryan 0:b74591d5ab33 206 * This function writes the preamble "{{" which is required
be_bryan 0:b74591d5ab33 207 * for key-value comunication between the target and the host.
be_bryan 0:b74591d5ab33 208 * This uses a Rawserial object, greentea_serial, which provides
be_bryan 0:b74591d5ab33 209 * a direct interface to the USBTX and USBRX serial pins and allows
be_bryan 0:b74591d5ab33 210 * the direct writing of characters using the putc() method.
be_bryan 0:b74591d5ab33 211 * This suite of functions are provided to allow for serial communication
be_bryan 0:b74591d5ab33 212 * to the host from within a thread/ISR.
be_bryan 0:b74591d5ab33 213 *
be_bryan 0:b74591d5ab33 214 */
be_bryan 0:b74591d5ab33 215 inline void greentea_write_preamble()
be_bryan 0:b74591d5ab33 216 {
be_bryan 0:b74591d5ab33 217 greentea_serial->putc('{');
be_bryan 0:b74591d5ab33 218 greentea_serial->putc('{');
be_bryan 0:b74591d5ab33 219 }
be_bryan 0:b74591d5ab33 220
be_bryan 0:b74591d5ab33 221 /**
be_bryan 0:b74591d5ab33 222 * \brief Write the postamble characters to the serial port
be_bryan 0:b74591d5ab33 223 *
be_bryan 0:b74591d5ab33 224 * This function writes the postamble "{{\n" which is required
be_bryan 0:b74591d5ab33 225 * for key-value comunication between the target and the host.
be_bryan 0:b74591d5ab33 226 * This uses a Rawserial object, greentea_serial, which provides
be_bryan 0:b74591d5ab33 227 * a direct interface to the USBTX and USBRX serial pins and allows
be_bryan 0:b74591d5ab33 228 * the direct writing of characters using the putc() method.
be_bryan 0:b74591d5ab33 229 * This suite of functions are provided to allow for serial communication
be_bryan 0:b74591d5ab33 230 * to the host from within a thread/ISR.
be_bryan 0:b74591d5ab33 231 *
be_bryan 0:b74591d5ab33 232 */
be_bryan 0:b74591d5ab33 233 inline void greentea_write_postamble()
be_bryan 0:b74591d5ab33 234 {
be_bryan 0:b74591d5ab33 235 greentea_serial->putc('}');
be_bryan 0:b74591d5ab33 236 greentea_serial->putc('}');
be_bryan 0:b74591d5ab33 237 greentea_serial->putc('\r');
be_bryan 0:b74591d5ab33 238 greentea_serial->putc('\n');
be_bryan 0:b74591d5ab33 239 }
be_bryan 0:b74591d5ab33 240
be_bryan 0:b74591d5ab33 241 /**
be_bryan 0:b74591d5ab33 242 * \brief Write a string to the serial port
be_bryan 0:b74591d5ab33 243 *
be_bryan 0:b74591d5ab33 244 * This function writes a '\0' terminated string from the target
be_bryan 0:b74591d5ab33 245 * to the host. It writes directly to the serial port using the
be_bryan 0:b74591d5ab33 246 * greentea_serial, Rawserial object.
be_bryan 0:b74591d5ab33 247 *
be_bryan 0:b74591d5ab33 248 * \param str - string value
be_bryan 0:b74591d5ab33 249 *
be_bryan 0:b74591d5ab33 250 */
be_bryan 0:b74591d5ab33 251 inline void greentea_write_string(const char *str)
be_bryan 0:b74591d5ab33 252 {
be_bryan 0:b74591d5ab33 253 while (*str != '\0') {
be_bryan 0:b74591d5ab33 254 greentea_serial->putc(*str);
be_bryan 0:b74591d5ab33 255 str ++;
be_bryan 0:b74591d5ab33 256 }
be_bryan 0:b74591d5ab33 257 }
be_bryan 0:b74591d5ab33 258
be_bryan 0:b74591d5ab33 259
be_bryan 0:b74591d5ab33 260 /**
be_bryan 0:b74591d5ab33 261 * \brief Write an int to the serial port
be_bryan 0:b74591d5ab33 262 *
be_bryan 0:b74591d5ab33 263 * This function writes an integer value from the target
be_bryan 0:b74591d5ab33 264 * to the host. The integer value is converted to a string and
be_bryan 0:b74591d5ab33 265 * and then written character by character directly to the serial
be_bryan 0:b74591d5ab33 266 * port using the greentea_serial, Rawserial object.
be_bryan 0:b74591d5ab33 267 * sprintf() is used to convert the int to a string. Sprintf if
be_bryan 0:b74591d5ab33 268 * inherently thread safe so can be used.
be_bryan 0:b74591d5ab33 269 *
be_bryan 0:b74591d5ab33 270 * \param val - integer value
be_bryan 0:b74591d5ab33 271 *
be_bryan 0:b74591d5ab33 272 */
be_bryan 0:b74591d5ab33 273 #define MAX_INT_STRING_LEN 15
be_bryan 0:b74591d5ab33 274 inline void greentea_write_int(const int val)
be_bryan 0:b74591d5ab33 275 {
be_bryan 0:b74591d5ab33 276 char intval[MAX_INT_STRING_LEN];
be_bryan 0:b74591d5ab33 277 unsigned int i = 0;
be_bryan 0:b74591d5ab33 278 sprintf(intval, "%d", val);
be_bryan 0:b74591d5ab33 279 while (intval[i] != '\0') {
be_bryan 0:b74591d5ab33 280 greentea_serial->putc(intval[i]);
be_bryan 0:b74591d5ab33 281 i++;
be_bryan 0:b74591d5ab33 282 }
be_bryan 0:b74591d5ab33 283 }
be_bryan 0:b74591d5ab33 284
be_bryan 0:b74591d5ab33 285 /**
be_bryan 0:b74591d5ab33 286 * \brief Encapsulate and send key-value message from DUT to host
be_bryan 0:b74591d5ab33 287 *
be_bryan 0:b74591d5ab33 288 * This function uses underlying functions to write directly
be_bryan 0:b74591d5ab33 289 * to the serial port, (USBTX). This allows KVs to be used
be_bryan 0:b74591d5ab33 290 * from within interrupt context.
be_bryan 0:b74591d5ab33 291 *
be_bryan 0:b74591d5ab33 292 * \param key Message key (message/event name)
be_bryan 0:b74591d5ab33 293 * \param value Message payload, string value
be_bryan 0:b74591d5ab33 294 *
be_bryan 0:b74591d5ab33 295 */
be_bryan 0:b74591d5ab33 296 extern "C" void greentea_send_kv(const char *key, const char *val) {
be_bryan 0:b74591d5ab33 297 if (key && val) {
be_bryan 0:b74591d5ab33 298 greentea_write_preamble();
be_bryan 0:b74591d5ab33 299 greentea_write_string(key);
be_bryan 0:b74591d5ab33 300 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 301 greentea_write_string(val);
be_bryan 0:b74591d5ab33 302 greentea_write_postamble();
be_bryan 0:b74591d5ab33 303 }
be_bryan 0:b74591d5ab33 304 }
be_bryan 0:b74591d5ab33 305
be_bryan 0:b74591d5ab33 306 /**
be_bryan 0:b74591d5ab33 307 * \brief Encapsulate and send key-value message from DUT to host
be_bryan 0:b74591d5ab33 308 *
be_bryan 0:b74591d5ab33 309 * This function uses underlying functions to write directly
be_bryan 0:b74591d5ab33 310 * to the serial port, (USBTX). This allows KVs to be used
be_bryan 0:b74591d5ab33 311 * from within interrupt context.
be_bryan 0:b74591d5ab33 312 * Last value is an integer to avoid integer to string conversion
be_bryan 0:b74591d5ab33 313 * made by the user.
be_bryan 0:b74591d5ab33 314 *
be_bryan 0:b74591d5ab33 315 * \param key Message key (message/event name)
be_bryan 0:b74591d5ab33 316 * \param value Message payload, integer value
be_bryan 0:b74591d5ab33 317 *
be_bryan 0:b74591d5ab33 318 */
be_bryan 0:b74591d5ab33 319 void greentea_send_kv(const char *key, const int val) {
be_bryan 0:b74591d5ab33 320 if (key) {
be_bryan 0:b74591d5ab33 321 greentea_write_preamble();
be_bryan 0:b74591d5ab33 322 greentea_write_string(key);
be_bryan 0:b74591d5ab33 323 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 324 greentea_write_int(val);
be_bryan 0:b74591d5ab33 325 greentea_write_postamble();
be_bryan 0:b74591d5ab33 326 }
be_bryan 0:b74591d5ab33 327 }
be_bryan 0:b74591d5ab33 328
be_bryan 0:b74591d5ab33 329 /**
be_bryan 0:b74591d5ab33 330 * \brief Encapsulate and send key-value-value message from DUT to host
be_bryan 0:b74591d5ab33 331 *
be_bryan 0:b74591d5ab33 332 * This function uses underlying functions to write directly
be_bryan 0:b74591d5ab33 333 * to the serial port, (USBTX). This allows KVs to be used
be_bryan 0:b74591d5ab33 334 * from within interrupt context.
be_bryan 0:b74591d5ab33 335 * Last value is an integer to avoid integer to string conversion
be_bryan 0:b74591d5ab33 336 * made by the user.
be_bryan 0:b74591d5ab33 337 *
be_bryan 0:b74591d5ab33 338 * \param key Message key (message/event name)
be_bryan 0:b74591d5ab33 339 * \param value Message payload, string value
be_bryan 0:b74591d5ab33 340 * \param result Send additional integer formatted data
be_bryan 0:b74591d5ab33 341 *
be_bryan 0:b74591d5ab33 342 */
be_bryan 0:b74591d5ab33 343 void greentea_send_kv(const char *key, const char *val, const int result) {
be_bryan 0:b74591d5ab33 344 if (key) {
be_bryan 0:b74591d5ab33 345 greentea_write_preamble();
be_bryan 0:b74591d5ab33 346 greentea_write_string(key);
be_bryan 0:b74591d5ab33 347 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 348 greentea_write_string(val);
be_bryan 0:b74591d5ab33 349 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 350 greentea_write_int(result);
be_bryan 0:b74591d5ab33 351 greentea_write_postamble();
be_bryan 0:b74591d5ab33 352
be_bryan 0:b74591d5ab33 353 }
be_bryan 0:b74591d5ab33 354 }
be_bryan 0:b74591d5ab33 355
be_bryan 0:b74591d5ab33 356 /**
be_bryan 0:b74591d5ab33 357 * \brief Encapsulate and send key-value-value-value message from DUT to host
be_bryan 0:b74591d5ab33 358 *
be_bryan 0:b74591d5ab33 359 * This function uses underlying functions to write directly
be_bryan 0:b74591d5ab33 360 * to the serial port, (USBTX). This allows KVs to be used
be_bryan 0:b74591d5ab33 361 * from within interrupt context.
be_bryan 0:b74591d5ab33 362 * Last 2 values are integers to avoid integer to string conversion
be_bryan 0:b74591d5ab33 363 * made by the user.
be_bryan 0:b74591d5ab33 364 *
be_bryan 0:b74591d5ab33 365 * Names of the parameters: this function is used to send test case
be_bryan 0:b74591d5ab33 366 * name with number of passes and failures to host. But it can be used
be_bryan 0:b74591d5ab33 367 * to send any key-value-value-value (string-string-integer-integer)
be_bryan 0:b74591d5ab33 368 * set to host.
be_bryan 0:b74591d5ab33 369 *
be_bryan 0:b74591d5ab33 370 * \param key Message key (message/event name)
be_bryan 0:b74591d5ab33 371 * \param value Message payload, string value
be_bryan 0:b74591d5ab33 372 * \param passes Send additional integer formatted data
be_bryan 0:b74591d5ab33 373 * \param failures Send additional integer formatted data
be_bryan 0:b74591d5ab33 374 *
be_bryan 0:b74591d5ab33 375 */
be_bryan 0:b74591d5ab33 376 void greentea_send_kv(const char *key, const char *val, const int passes, const int failures) {
be_bryan 0:b74591d5ab33 377 if (key) {
be_bryan 0:b74591d5ab33 378 greentea_write_preamble();
be_bryan 0:b74591d5ab33 379 greentea_write_string(key);
be_bryan 0:b74591d5ab33 380 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 381 greentea_write_string(val);
be_bryan 0:b74591d5ab33 382 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 383 greentea_write_int(passes);
be_bryan 0:b74591d5ab33 384 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 385 greentea_write_int(failures);
be_bryan 0:b74591d5ab33 386 greentea_write_postamble();
be_bryan 0:b74591d5ab33 387 }
be_bryan 0:b74591d5ab33 388 }
be_bryan 0:b74591d5ab33 389
be_bryan 0:b74591d5ab33 390 /**
be_bryan 0:b74591d5ab33 391 * \brief Encapsulate and send key-value-value message from DUT to host
be_bryan 0:b74591d5ab33 392 *
be_bryan 0:b74591d5ab33 393 * This function uses underlying functions to write directly
be_bryan 0:b74591d5ab33 394 * to the serial port, (USBTX). This allows key-value-value to be used
be_bryan 0:b74591d5ab33 395 * from within interrupt context.
be_bryan 0:b74591d5ab33 396 * Both values are integers to avoid integer to string conversion
be_bryan 0:b74591d5ab33 397 * made by the user.
be_bryan 0:b74591d5ab33 398 *
be_bryan 0:b74591d5ab33 399 * Names of the parameters: this function is used to send number
be_bryan 0:b74591d5ab33 400 * of passes and failures to host. But it can be used to send any
be_bryan 0:b74591d5ab33 401 * key-value-value (string-integer-integer) message to host.
be_bryan 0:b74591d5ab33 402 *
be_bryan 0:b74591d5ab33 403 * \param key Message key (message/event name)
be_bryan 0:b74591d5ab33 404 * \param value Message payload, integer value
be_bryan 0:b74591d5ab33 405 * \param passes Send additional integer formatted data
be_bryan 0:b74591d5ab33 406 * \param failures Send additional integer formatted data
be_bryan 0:b74591d5ab33 407 *
be_bryan 0:b74591d5ab33 408 */
be_bryan 0:b74591d5ab33 409 void greentea_send_kv(const char *key, const int passes, const int failures) {
be_bryan 0:b74591d5ab33 410 if (key) {
be_bryan 0:b74591d5ab33 411 greentea_write_preamble();
be_bryan 0:b74591d5ab33 412 greentea_write_string(key);
be_bryan 0:b74591d5ab33 413 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 414 greentea_write_int(passes);
be_bryan 0:b74591d5ab33 415 greentea_serial->putc(';');
be_bryan 0:b74591d5ab33 416 greentea_write_int(failures);
be_bryan 0:b74591d5ab33 417 greentea_write_postamble();
be_bryan 0:b74591d5ab33 418 }
be_bryan 0:b74591d5ab33 419 }
be_bryan 0:b74591d5ab33 420
be_bryan 0:b74591d5ab33 421 /**
be_bryan 0:b74591d5ab33 422 * \brief Send message with timeout to master in seconds
be_bryan 0:b74591d5ab33 423 *
be_bryan 0:b74591d5ab33 424 * GREENTEA_TEST_ENV_TIMEOUT message is part of preamble
be_bryan 0:b74591d5ab33 425 * sent from DUT to host during synchronisation (beginning of test
be_bryan 0:b74591d5ab33 426 * suite execution).
be_bryan 0:b74591d5ab33 427 *
be_bryan 0:b74591d5ab33 428 * Notification about total test suite timeout. Timeout is measured
be_bryan 0:b74591d5ab33 429 * from the moment of GREENTEA_TEST_ENV_TIMEOUT reception by host.
be_bryan 0:b74591d5ab33 430 * If timeout is reached host (and host test) will be stopped and
be_bryan 0:b74591d5ab33 431 * control will return to Greentea.
be_bryan 0:b74591d5ab33 432 *
be_bryan 0:b74591d5ab33 433 * \param timeout Test suite timeout in seconds
be_bryan 0:b74591d5ab33 434 *
be_bryan 0:b74591d5ab33 435 */
be_bryan 0:b74591d5ab33 436 static void greentea_notify_timeout(const int timeout) {
be_bryan 0:b74591d5ab33 437 greentea_send_kv(GREENTEA_TEST_ENV_TIMEOUT, timeout);
be_bryan 0:b74591d5ab33 438 }
be_bryan 0:b74591d5ab33 439
be_bryan 0:b74591d5ab33 440 /**
be_bryan 0:b74591d5ab33 441 * \brief Send host test name to master
be_bryan 0:b74591d5ab33 442 *
be_bryan 0:b74591d5ab33 443 * GREENTEA_TEST_ENV_HOST_TEST_NAME message is part of preamble
be_bryan 0:b74591d5ab33 444 * sent from DUT to host during synchronisation (beginning of test
be_bryan 0:b74591d5ab33 445 * suite execution).
be_bryan 0:b74591d5ab33 446 *
be_bryan 0:b74591d5ab33 447 * Host test Python script implements host side callbacks
be_bryan 0:b74591d5ab33 448 * for key-value events sent from DUT to host. Host test's
be_bryan 0:b74591d5ab33 449 * callbacks are registered after GREENTEA_TEST_ENV_HOST_TEST_NAME
be_bryan 0:b74591d5ab33 450 * message reaches host.
be_bryan 0:b74591d5ab33 451 *
be_bryan 0:b74591d5ab33 452 * \param host_test_name Host test name, host test will be loaded by mbedhtrun
be_bryan 0:b74591d5ab33 453 */
be_bryan 0:b74591d5ab33 454 static void greentea_notify_hosttest(const char *host_test_name) {
be_bryan 0:b74591d5ab33 455 greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_NAME, host_test_name);
be_bryan 0:b74591d5ab33 456 }
be_bryan 0:b74591d5ab33 457
be_bryan 0:b74591d5ab33 458 /**
be_bryan 0:b74591d5ab33 459 * \brief Send to master information that test suite finished its execution
be_bryan 0:b74591d5ab33 460 *
be_bryan 0:b74591d5ab33 461 * GREENTEA_TEST_ENV_END and GREENTEA_TEST_ENV_EXIT messages
be_bryan 0:b74591d5ab33 462 * are sent just before test suite execution finishes (noting
be_bryan 0:b74591d5ab33 463 * else to do). You can place it just before you return from your
be_bryan 0:b74591d5ab33 464 * main() function.
be_bryan 0:b74591d5ab33 465 *
be_bryan 0:b74591d5ab33 466 * Code coverage: If MEBD_CFG_DEBUG_OPTIONS_COVERAGE is set in the
be_bryan 0:b74591d5ab33 467 * project via build configuration function will output series
be_bryan 0:b74591d5ab33 468 * of code coverage messages GREENTEA_TEST_ENV_LCOV_START with code
be_bryan 0:b74591d5ab33 469 * coverage binary data. This data is captured by Greentea and can
be_bryan 0:b74591d5ab33 470 * be used to generate LCOV reports.
be_bryan 0:b74591d5ab33 471 *
be_bryan 0:b74591d5ab33 472 * \param result Test suite result from DUT (0 - FAIl, !0 - SUCCESS)
be_bryan 0:b74591d5ab33 473 *
be_bryan 0:b74591d5ab33 474 */
be_bryan 0:b74591d5ab33 475 static void greentea_notify_completion(const int result) {
be_bryan 0:b74591d5ab33 476 const char *val = result ? GREENTEA_TEST_ENV_SUCCESS : GREENTEA_TEST_ENV_FAILURE;
be_bryan 0:b74591d5ab33 477 #ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE
be_bryan 0:b74591d5ab33 478 coverage_report = true;
be_bryan 0:b74591d5ab33 479 __gcov_flush();
be_bryan 0:b74591d5ab33 480 coverage_report = false;
be_bryan 0:b74591d5ab33 481 #endif
be_bryan 0:b74591d5ab33 482 greentea_metrics_report();
be_bryan 0:b74591d5ab33 483 greentea_send_kv(GREENTEA_TEST_ENV_END, val);
be_bryan 0:b74591d5ab33 484 greentea_send_kv(GREENTEA_TEST_ENV_EXIT, 0);
be_bryan 0:b74591d5ab33 485 }
be_bryan 0:b74591d5ab33 486
be_bryan 0:b74591d5ab33 487 /**
be_bryan 0:b74591d5ab33 488 * \brief Send to master greentea-client version
be_bryan 0:b74591d5ab33 489 */
be_bryan 0:b74591d5ab33 490 static void greentea_notify_version() {
be_bryan 0:b74591d5ab33 491 greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_VERSION, MBED_GREENTEA_CLIENT_VERSION_STRING);
be_bryan 0:b74591d5ab33 492 }
be_bryan 0:b74591d5ab33 493
be_bryan 0:b74591d5ab33 494 /**
be_bryan 0:b74591d5ab33 495 *****************************************************************************
be_bryan 0:b74591d5ab33 496 * Parse engine for KV values which replaces scanf
be_bryan 0:b74591d5ab33 497 *****************************************************************************
be_bryan 0:b74591d5ab33 498 *
be_bryan 0:b74591d5ab33 499 * Example usage:
be_bryan 0:b74591d5ab33 500 *
be_bryan 0:b74591d5ab33 501 * char key[10];
be_bryan 0:b74591d5ab33 502 * char value[48];
be_bryan 0:b74591d5ab33 503 *
be_bryan 0:b74591d5ab33 504 * greentea_parse_kv(key, value, 10, 48);
be_bryan 0:b74591d5ab33 505 * greentea_parse_kv(key, value, 10, 48);
be_bryan 0:b74591d5ab33 506 *
be_bryan 0:b74591d5ab33 507 */
be_bryan 0:b74591d5ab33 508
be_bryan 0:b74591d5ab33 509
be_bryan 0:b74591d5ab33 510 static int gettok(char *, const int);
be_bryan 0:b74591d5ab33 511 static int getNextToken(char *, const int);
be_bryan 0:b74591d5ab33 512 static int HandleKV(char *, char *, const int, const int);
be_bryan 0:b74591d5ab33 513 static int isstring(int);
be_bryan 0:b74591d5ab33 514
be_bryan 0:b74591d5ab33 515 /**
be_bryan 0:b74591d5ab33 516 * \brief Current token of key-value protocol's tokenizer
be_bryan 0:b74591d5ab33 517 */
be_bryan 0:b74591d5ab33 518 static int CurTok = 0;
be_bryan 0:b74591d5ab33 519
be_bryan 0:b74591d5ab33 520 /**
be_bryan 0:b74591d5ab33 521 * \enum Token enumeration for key-value protocol tokenizer
be_bryan 0:b74591d5ab33 522 *
be_bryan 0:b74591d5ab33 523 * This enum is used by key-value protocol tokenizer
be_bryan 0:b74591d5ab33 524 * to detect parts of protocol in stream.
be_bryan 0:b74591d5ab33 525 *
be_bryan 0:b74591d5ab33 526 * tok_eof ::= EOF (end of file)
be_bryan 0:b74591d5ab33 527 * tok_open ::= "{{"
be_bryan 0:b74591d5ab33 528 * tok_close ::= "}}"
be_bryan 0:b74591d5ab33 529 * tok_semicolon ::= ";"
be_bryan 0:b74591d5ab33 530 * tok_string ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function
be_bryan 0:b74591d5ab33 531 *
be_bryan 0:b74591d5ab33 532 */
be_bryan 0:b74591d5ab33 533 enum Token {
be_bryan 0:b74591d5ab33 534 tok_eof = -1,
be_bryan 0:b74591d5ab33 535 tok_open = -2,
be_bryan 0:b74591d5ab33 536 tok_close = -3,
be_bryan 0:b74591d5ab33 537 tok_semicolon = -4,
be_bryan 0:b74591d5ab33 538 tok_string = -5
be_bryan 0:b74591d5ab33 539 };
be_bryan 0:b74591d5ab33 540
be_bryan 0:b74591d5ab33 541 /**
be_bryan 0:b74591d5ab33 542 * \brief Read character from stream of data
be_bryan 0:b74591d5ab33 543 *
be_bryan 0:b74591d5ab33 544 * Closure for default "get character" function.
be_bryan 0:b74591d5ab33 545 * This function is used to read characters from the stream
be_bryan 0:b74591d5ab33 546 * (default is serial port RX). Key-value protocol tokenizer
be_bryan 0:b74591d5ab33 547 * will build stream of tokes used by key-value protocol to
be_bryan 0:b74591d5ab33 548 * detect valid messages.
be_bryan 0:b74591d5ab33 549 *
be_bryan 0:b74591d5ab33 550 * If EOF is received parser finishes parsing and stops. In
be_bryan 0:b74591d5ab33 551 * situation where we have serial port stream of data parsing
be_bryan 0:b74591d5ab33 552 * goes forever.
be_bryan 0:b74591d5ab33 553 *
be_bryan 0:b74591d5ab33 554 * \return Next character from the stream or EOF if stream has ended.
be_bryan 0:b74591d5ab33 555 *
be_bryan 0:b74591d5ab33 556 */
be_bryan 0:b74591d5ab33 557 extern "C" int greentea_getc() {
be_bryan 0:b74591d5ab33 558 return greentea_serial->getc();
be_bryan 0:b74591d5ab33 559 }
be_bryan 0:b74591d5ab33 560
be_bryan 0:b74591d5ab33 561 /**
be_bryan 0:b74591d5ab33 562 * \brief parse input string for key-value pairs: {{key;value}}
be_bryan 0:b74591d5ab33 563 * This function should replace scanf() used to
be_bryan 0:b74591d5ab33 564 * check for incoming messages from master. All data
be_bryan 0:b74591d5ab33 565 * parsed and rejected is discarded.
be_bryan 0:b74591d5ab33 566 *
be_bryan 0:b74591d5ab33 567 * \param out_key Ouput data with key
be_bryan 0:b74591d5ab33 568 * \param out_value Ouput data with value
be_bryan 0:b74591d5ab33 569 * \param out_key_size out_key total size
be_bryan 0:b74591d5ab33 570 * \param out_value_size out_value total data
be_bryan 0:b74591d5ab33 571 *
be_bryan 0:b74591d5ab33 572 * success != 0 when key-value pair was found
be_bryan 0:b74591d5ab33 573 * success == 0 when end of the stream was found
be_bryan 0:b74591d5ab33 574 *
be_bryan 0:b74591d5ab33 575 */
be_bryan 0:b74591d5ab33 576 extern "C" int greentea_parse_kv(char *out_key,
be_bryan 0:b74591d5ab33 577 char *out_value,
be_bryan 0:b74591d5ab33 578 const int out_key_size,
be_bryan 0:b74591d5ab33 579 const int out_value_size) {
be_bryan 0:b74591d5ab33 580 getNextToken(0, 0);
be_bryan 0:b74591d5ab33 581 while (1) {
be_bryan 0:b74591d5ab33 582 switch (CurTok) {
be_bryan 0:b74591d5ab33 583 case tok_eof:
be_bryan 0:b74591d5ab33 584 return 0;
be_bryan 0:b74591d5ab33 585
be_bryan 0:b74591d5ab33 586 case tok_open:
be_bryan 0:b74591d5ab33 587 if (HandleKV(out_key, out_value, out_key_size, out_value_size)) {
be_bryan 0:b74591d5ab33 588 // We've found {{ KEY ; VALUE }} expression
be_bryan 0:b74591d5ab33 589 return 1;
be_bryan 0:b74591d5ab33 590 }
be_bryan 0:b74591d5ab33 591 break;
be_bryan 0:b74591d5ab33 592
be_bryan 0:b74591d5ab33 593 default:
be_bryan 0:b74591d5ab33 594 // Load next token and pray...
be_bryan 0:b74591d5ab33 595 getNextToken(0, 0);
be_bryan 0:b74591d5ab33 596 break;
be_bryan 0:b74591d5ab33 597 }
be_bryan 0:b74591d5ab33 598 }
be_bryan 0:b74591d5ab33 599 }
be_bryan 0:b74591d5ab33 600
be_bryan 0:b74591d5ab33 601 /**
be_bryan 0:b74591d5ab33 602 * \brief Get next token from stream
be_bryan 0:b74591d5ab33 603 *
be_bryan 0:b74591d5ab33 604 * Key-value TOKENIZER feature
be_bryan 0:b74591d5ab33 605 *
be_bryan 0:b74591d5ab33 606 * This function is used by key-value parser determine
be_bryan 0:b74591d5ab33 607 * if key-value message is embedded in stream data.
be_bryan 0:b74591d5ab33 608 *
be_bryan 0:b74591d5ab33 609 * \param str Output parameters to store token string value
be_bryan 0:b74591d5ab33 610 * \param str_size Size of 'str' parameter in bytes (characters)
be_bryan 0:b74591d5ab33 611 *
be_bryan 0:b74591d5ab33 612 */
be_bryan 0:b74591d5ab33 613 static int getNextToken(char *str, const int str_size) {
be_bryan 0:b74591d5ab33 614 return CurTok = gettok(str, str_size);
be_bryan 0:b74591d5ab33 615 }
be_bryan 0:b74591d5ab33 616
be_bryan 0:b74591d5ab33 617 /**
be_bryan 0:b74591d5ab33 618 * \brief Check if character is punctuation character
be_bryan 0:b74591d5ab33 619 *
be_bryan 0:b74591d5ab33 620 * Auxilary key-value TOKENIZER function
be_bryan 0:b74591d5ab33 621 *
be_bryan 0:b74591d5ab33 622 * Defines if character is in subset of allowed punctuation
be_bryan 0:b74591d5ab33 623 * characters which can be part of a key or value string.
be_bryan 0:b74591d5ab33 624 * Not allowed characters are: ";{}"
be_bryan 0:b74591d5ab33 625 *
be_bryan 0:b74591d5ab33 626 * \param c Input character to check
be_bryan 0:b74591d5ab33 627 * \return Return 1 if character is allowed punctuation character, otherwise return false
be_bryan 0:b74591d5ab33 628 *
be_bryan 0:b74591d5ab33 629 */
be_bryan 0:b74591d5ab33 630 static int ispunctuation(int c) {
be_bryan 0:b74591d5ab33 631 static const char punctuation[] = "_-!@#$%^&*()=+:<>,./?\\\"'"; // No ";{}"
be_bryan 0:b74591d5ab33 632 for (size_t i=0; i< sizeof(punctuation); ++i) {
be_bryan 0:b74591d5ab33 633 if (c == punctuation[i]) {
be_bryan 0:b74591d5ab33 634 return 1;
be_bryan 0:b74591d5ab33 635 }
be_bryan 0:b74591d5ab33 636 }
be_bryan 0:b74591d5ab33 637 return 0;
be_bryan 0:b74591d5ab33 638 }
be_bryan 0:b74591d5ab33 639
be_bryan 0:b74591d5ab33 640 /**
be_bryan 0:b74591d5ab33 641 * \brief Check if character is string token character
be_bryan 0:b74591d5ab33 642 *
be_bryan 0:b74591d5ab33 643 * Auxilary key-value TOKENIZER function
be_bryan 0:b74591d5ab33 644 *
be_bryan 0:b74591d5ab33 645 * Defines if character is in subset of allowed string
be_bryan 0:b74591d5ab33 646 * token characters.
be_bryan 0:b74591d5ab33 647 * String defines set of characters which can be a key or value string.
be_bryan 0:b74591d5ab33 648 *
be_bryan 0:b74591d5ab33 649 * Allowed subset includes:
be_bryan 0:b74591d5ab33 650 * - Alphanumerical characters
be_bryan 0:b74591d5ab33 651 * - Digits
be_bryan 0:b74591d5ab33 652 * - White spaces and
be_bryan 0:b74591d5ab33 653 * - subset of punctuation characters.
be_bryan 0:b74591d5ab33 654 *
be_bryan 0:b74591d5ab33 655 * \param c Input character to check
be_bryan 0:b74591d5ab33 656 * \return Return 1 if character is allowed punctuation character, otherwise return false
be_bryan 0:b74591d5ab33 657 *
be_bryan 0:b74591d5ab33 658 */
be_bryan 0:b74591d5ab33 659 static int isstring(int c) {
be_bryan 0:b74591d5ab33 660 return (isalpha(c) ||
be_bryan 0:b74591d5ab33 661 isdigit(c) ||
be_bryan 0:b74591d5ab33 662 isspace(c) ||
be_bryan 0:b74591d5ab33 663 ispunctuation(c));
be_bryan 0:b74591d5ab33 664 }
be_bryan 0:b74591d5ab33 665
be_bryan 0:b74591d5ab33 666 /**
be_bryan 0:b74591d5ab33 667 * \brief TOKENIZER of key-value protocol
be_bryan 0:b74591d5ab33 668 *
be_bryan 0:b74591d5ab33 669 * Actual key-value TOKENIZER engine
be_bryan 0:b74591d5ab33 670 *
be_bryan 0:b74591d5ab33 671 * TOKENIZER defines #Token enum to map recognized tokens to integer values.
be_bryan 0:b74591d5ab33 672 *
be_bryan 0:b74591d5ab33 673 * <TOK_EOF> ::= EOF (end of file)
be_bryan 0:b74591d5ab33 674 * <TOK_OPEN> ::= "{{"
be_bryan 0:b74591d5ab33 675 * <TOK_CLOSE> ::= "}}"
be_bryan 0:b74591d5ab33 676 * <TOK_SEMICOLON> ::= ";"
be_bryan 0:b74591d5ab33 677 * <TOK_STRING> ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function *
be_bryan 0:b74591d5ab33 678 *
be_bryan 0:b74591d5ab33 679 * \param out_str Output string with parsed token (string)
be_bryan 0:b74591d5ab33 680 * \param str_size Size of str buffer we can use
be_bryan 0:b74591d5ab33 681 *
be_bryan 0:b74591d5ab33 682 * \return Return #Token enum value used by parser to check for key-value occurrences
be_bryan 0:b74591d5ab33 683 *
be_bryan 0:b74591d5ab33 684 */
be_bryan 0:b74591d5ab33 685 static int gettok(char *out_str, const int str_size) {
be_bryan 0:b74591d5ab33 686 static int LastChar = '!';
be_bryan 0:b74591d5ab33 687 static int str_idx = 0;
be_bryan 0:b74591d5ab33 688
be_bryan 0:b74591d5ab33 689 // whitespace ::=
be_bryan 0:b74591d5ab33 690 while (isspace(LastChar)) {
be_bryan 0:b74591d5ab33 691 LastChar = greentea_getc();
be_bryan 0:b74591d5ab33 692 }
be_bryan 0:b74591d5ab33 693
be_bryan 0:b74591d5ab33 694 // string ::= [a-zA-Z0-9_-!@#$%^&*()]+
be_bryan 0:b74591d5ab33 695 if (isstring(LastChar)) {
be_bryan 0:b74591d5ab33 696 str_idx = 0;
be_bryan 0:b74591d5ab33 697 if (out_str && str_idx < str_size - 1) {
be_bryan 0:b74591d5ab33 698 out_str[str_idx++] = LastChar;
be_bryan 0:b74591d5ab33 699 }
be_bryan 0:b74591d5ab33 700
be_bryan 0:b74591d5ab33 701 while (isstring((LastChar = greentea_getc())))
be_bryan 0:b74591d5ab33 702 if (out_str && str_idx < str_size - 1) {
be_bryan 0:b74591d5ab33 703 out_str[str_idx++] = LastChar;
be_bryan 0:b74591d5ab33 704 }
be_bryan 0:b74591d5ab33 705 if (out_str && str_idx < str_size) {
be_bryan 0:b74591d5ab33 706 out_str[str_idx] = '\0';
be_bryan 0:b74591d5ab33 707 }
be_bryan 0:b74591d5ab33 708
be_bryan 0:b74591d5ab33 709 return tok_string;
be_bryan 0:b74591d5ab33 710 }
be_bryan 0:b74591d5ab33 711
be_bryan 0:b74591d5ab33 712 // semicolon ::= ';'
be_bryan 0:b74591d5ab33 713 if (LastChar == ';') {
be_bryan 0:b74591d5ab33 714 LastChar = greentea_getc();
be_bryan 0:b74591d5ab33 715 return tok_semicolon;
be_bryan 0:b74591d5ab33 716 }
be_bryan 0:b74591d5ab33 717
be_bryan 0:b74591d5ab33 718 // open ::= '{{'
be_bryan 0:b74591d5ab33 719 if (LastChar == '{') {
be_bryan 0:b74591d5ab33 720 LastChar = greentea_getc();
be_bryan 0:b74591d5ab33 721 if (LastChar == '{') {
be_bryan 0:b74591d5ab33 722 LastChar = greentea_getc();
be_bryan 0:b74591d5ab33 723 return tok_open;
be_bryan 0:b74591d5ab33 724 }
be_bryan 0:b74591d5ab33 725 }
be_bryan 0:b74591d5ab33 726
be_bryan 0:b74591d5ab33 727 // close ::= '}'
be_bryan 0:b74591d5ab33 728 if (LastChar == '}') {
be_bryan 0:b74591d5ab33 729 LastChar = greentea_getc();
be_bryan 0:b74591d5ab33 730 if (LastChar == '}') {
be_bryan 0:b74591d5ab33 731 return tok_close;
be_bryan 0:b74591d5ab33 732 }
be_bryan 0:b74591d5ab33 733 }
be_bryan 0:b74591d5ab33 734
be_bryan 0:b74591d5ab33 735 if (LastChar == EOF)
be_bryan 0:b74591d5ab33 736 return tok_eof;
be_bryan 0:b74591d5ab33 737
be_bryan 0:b74591d5ab33 738 // Otherwise, just return the character as its ascii value.
be_bryan 0:b74591d5ab33 739 int ThisChar = LastChar;
be_bryan 0:b74591d5ab33 740 LastChar = greentea_getc();
be_bryan 0:b74591d5ab33 741 return ThisChar;
be_bryan 0:b74591d5ab33 742 }
be_bryan 0:b74591d5ab33 743
be_bryan 0:b74591d5ab33 744 /**
be_bryan 0:b74591d5ab33 745 * \brief Key-value parser
be_bryan 0:b74591d5ab33 746 *
be_bryan 0:b74591d5ab33 747 * Key-value message grammar
be_bryan 0:b74591d5ab33 748 *
be_bryan 0:b74591d5ab33 749 * <MESSAGE>: <TOK_OPEN> <TOK_STRING> <TOK_SEMICOLON> <TOK_STRING> <TOK_CLOSE>
be_bryan 0:b74591d5ab33 750 *
be_bryan 0:b74591d5ab33 751 * Examples:
be_bryan 0:b74591d5ab33 752 * message: "{{__timeout; 1000}}"
be_bryan 0:b74591d5ab33 753 * "{{__sync; 12345678-1234-5678-1234-567812345678}}"
be_bryan 0:b74591d5ab33 754 *
be_bryan 0:b74591d5ab33 755 * \param out_key Output buffer to store key string value
be_bryan 0:b74591d5ab33 756 * \param out_value Output buffer to store value string value
be_bryan 0:b74591d5ab33 757 * \param out_key_size Buffer 'out_key' buffer size
be_bryan 0:b74591d5ab33 758 * \param out_value_size Buffer 'out_value_size' buffer size
be_bryan 0:b74591d5ab33 759 * \return Returns 1 if key-value message was parsed successfully in stream of tokens from tokenizer
be_bryan 0:b74591d5ab33 760 *
be_bryan 0:b74591d5ab33 761 */
be_bryan 0:b74591d5ab33 762 static int HandleKV(char *out_key,
be_bryan 0:b74591d5ab33 763 char *out_value,
be_bryan 0:b74591d5ab33 764 const int out_key_size,
be_bryan 0:b74591d5ab33 765 const int out_value_size) {
be_bryan 0:b74591d5ab33 766 // We already started with <open>
be_bryan 0:b74591d5ab33 767 if (getNextToken(out_key, out_key_size) == tok_string) {
be_bryan 0:b74591d5ab33 768 if (getNextToken(0, 0) == tok_semicolon) {
be_bryan 0:b74591d5ab33 769 if (getNextToken(out_value, out_value_size) == tok_string) {
be_bryan 0:b74591d5ab33 770 if (getNextToken(0, 0) == tok_close) {
be_bryan 0:b74591d5ab33 771 // <open> <string> <semicolon> <string> <close>
be_bryan 0:b74591d5ab33 772 // Found "{{KEY;VALUE}}" expression
be_bryan 0:b74591d5ab33 773 return 1;
be_bryan 0:b74591d5ab33 774 }
be_bryan 0:b74591d5ab33 775 }
be_bryan 0:b74591d5ab33 776 }
be_bryan 0:b74591d5ab33 777 }
be_bryan 0:b74591d5ab33 778 getNextToken(0, 0);
be_bryan 0:b74591d5ab33 779 return 0;
be_bryan 0:b74591d5ab33 780 }