mbed-os test code generator
diff --git a/tests/suites/embedded_test.function b/tests/suites/embedded_test.function
new file mode 100644
index 0000000..21a5cab
--- /dev/null
+++ b/tests/suites/embedded_test.function
@@ -0,0 +1,364 @@
+#line 2 "embedded_test.function"
+
+#include "greentea-client/test_env_c.h"
+
+/**
+ * \brief       Increments pointer and asserts that it does not overflow.
+ *
+ * \param p     Pointer to byte array
+ * \param start Pointer to start of byte array
+ * \param len   Length of byte array
+ * \param step  Increment size
+ *
+ */
+#define INCR_ASSERT(p, start, len, step) do                     \
+{                                                               \
+    assert( p >= start );                                       \
+    assert( sizeof( *p ) == sizeof( *start ) );                 \
+    /* <= is checked to support use inside a loop where         \
+       pointer is incremented after reading data.       */      \
+    assert( (uint32_t)( (p - start) + step ) <= len );          \
+    p += step;                                                  \
+}                                                               \
+while( 0 )
+
+
+/**
+ * \brief       4 byte align unsigned char pointer
+ *
+ * \param p     Pointer to byte array
+ * \param start Pointer to start of byte array
+ * \param len   Length of byte array
+ *
+ */
+#define ALIGN_32BIT(p, start, len) do           \
+{                                               \
+    uint32_t align = ( - (uintptr_t)p ) % 4;    \
+    INCR_ASSERT(p, start, len, align);          \
+}                                               \
+while( 0 )
+
+
+/**
+ * \brief       Verify dependencies. Dependency identifiers are
+ *              encoded in the buffer as 8 bit unsigned integers.
+ *
+ * \param count     Number of dependencies.
+ * \param dep_p     Pointer to buffer.
+ *
+ * \return          DEPENDENCY_SUPPORTED if success else DEPENDENCY_NOT_SUPPORTED.
+ */
+int verify_dependencies( uint8_t count, uint8_t * dep_p )
+{
+    uint8_t i;
+    for ( i = 0; i < count; i++ )
+    {
+        if ( dep_check( (int)(dep_p[i]) ) != DEPENDENCY_SUPPORTED )
+            return( DEPENDENCY_NOT_SUPPORTED );
+    }
+    return( DEPENDENCY_SUPPORTED );
+}
+
+
+/**
+ * \brief       Receives unsigned integer on serial interface.
+ *              Integers are encoded in network order.
+ *
+ * \param none
+ *
+ * \return      unsigned int
+ */
+uint32_t receive_uint32()
+{
+    uint32_t value;
+    value =  (uint8_t)greentea_getc() << 24;
+    value |= (uint8_t)greentea_getc() << 16;
+    value |= (uint8_t)greentea_getc() << 8;
+    value |= (uint8_t)greentea_getc();
+    return( (uint32_t)value );
+}
+
+/**
+ * \brief       Parses out an unsigned 32 int value from the byte array.
+ *              Integers are encoded in network order.
+ *
+ * \param p     Pointer to byte array
+ *
+ * \return      unsigned int
+ */
+uint32_t parse_uint32( uint8_t * p )
+{
+    uint32_t value;
+    value =  *p++ << 24;
+    value |= *p++ << 16;
+    value |= *p++ << 8;
+    value |= *p;
+    return( value );
+}
+
+
+/**
+ * \brief       Receives test data on serial as greentea key,value pair:
+ *              {{<length>;<byte array>}}
+ *
+ * \param data_len  Out pointer to hold received data length.
+ *
+ * \return      Byte array.
+ */
+uint8_t * receive_data( uint32_t * data_len )
+{
+    uint32_t i = 0, errors = 0;
+    char c;
+    uint8_t * data = NULL;
+
+    /* Read opening braces */
+    i = 0;
+    while ( i < 2 )
+    {
+        c = greentea_getc();
+        /* Ignore any prevous CR LF characters */
+        if ( c == '\n' || c == '\r' )
+            continue;
+        i++;
+        if ( c != '{' )
+            return( NULL );
+    }
+
+    /* Read data length */
+    *data_len = receive_uint32();
+    data = (uint8_t *)malloc( *data_len );
+    assert( data != NULL );
+
+    greentea_getc(); // read ';' received after key i.e. *data_len
+
+    for( i = 0; i < *data_len; i++ )
+        data[i] = greentea_getc();
+
+    /* Read closing braces */
+    for( i = 0; i < 2; i++ )
+    {
+        c = greentea_getc();
+        if ( c != '}' )
+        {
+            errors++;
+            break;
+        }
+    }
+
+    if ( errors )
+    {
+        free( data );
+        data = NULL;
+        *data_len = 0;
+    }
+
+    return( data );
+}
+
+/**
+ * \brief       Parses received byte array for test parameters.
+ *
+ * \param count     Parameter count
+ * \param data      Received Byte array
+ * \param data_len  Byte array length
+ * \param error     Parsing error out variable.
+ *
+ * \return      Array of parsed parameters allocated on heap.
+ *              Note: Caller has the responsibility to delete
+ *                    the memory after use.
+ */
+void ** parse_parameters( uint8_t count, uint8_t * data, uint32_t data_len,
+                            int * error )
+{
+    uint32_t i = 0;
+    char c;
+    void ** params = NULL;
+    void ** cur = NULL;
+    uint8_t * p = NULL;
+
+    params = (void **)malloc( sizeof( void *) * ( count + 1 ) );
+    assert( params != NULL );
+    params[count] = NULL;
+    cur = params;
+
+    p = data;
+
+    /* Parameters */
+    for( i = 0; i < count; i++ )
+    {
+        c = (char)*p;
+        INCR_ASSERT( p, data, data_len, 1 );
+
+        /* Align p to 4 bytes for int, expression, string len or hex length */
+        ALIGN_32BIT( p, data, data_len );
+
+        /* Network to host conversion */
+        *( (int32_t *)p ) = (int32_t)parse_uint32( p );
+
+        switch( c )
+        {
+            case 'E':
+                {
+                    if ( get_expression( *( (int32_t *)p ), (int32_t *)p ) )
+                    {
+                        *error = KEY_VALUE_MAPPING_NOT_FOUND;
+                        goto exit;
+                    }
+                } /* Intentional fall through */
+            case 'I':
+                {
+                    *cur++ = (void *)p;
+                    INCR_ASSERT( p, data, data_len, sizeof( int32_t ) );
+                }
+                break;
+            case 'H':
+                {
+                    *cur++ = (void *)p;
+                } /* Intentional fall through */
+            case 'S':
+                {
+                    uint32_t sz = *( (int32_t *)p );
+                    INCR_ASSERT( p, data, data_len, sizeof( int32_t ) );
+                    *cur++ = (void *)p;
+                    INCR_ASSERT( p, data, data_len, sz );
+                }
+                break;
+            default:
+                    {
+                        *error = DISPATCH_INVALID_TEST_DATA;
+                        goto exit;
+                    }
+                break;
+        }
+    }
+
+exit:
+    if ( *error )
+    {
+        free( params );
+        params = NULL;
+    }
+
+    return( params );
+}
+
+/**
+ * \brief       Sends greentea key and int value pair to host.
+ *
+ * \param key   key string
+ * \param value integer value
+ *
+ * \return      void
+ */
+void send_key_integer( char * key, int value )
+{
+    char str[50];
+    snprintf( str, sizeof( str ), "%d", value );
+    greentea_send_kv_c( key, str );
+}
+
+/**
+ * \brief       Sends test setup failure to the host.
+ *
+ * \param failure   Test set failure
+ *
+ * \return      void
+ */
+void send_failure( int failure )
+{
+    send_key_integer( "F", failure );
+}
+
+/**
+ * \brief       Sends test status to the host.
+ *
+ * \param status    Test status (PASS=0/FAIL=!0)
+ *
+ * \return      void
+ */
+void send_status( int status )
+{
+    send_key_integer( "R", status );
+}
+
+
+/**
+ * \brief       Embedded implementation of execute_tests().
+ *              Ignores command line and received test data
+ *              on serial.
+ *
+ * \param argc  not used
+ * \param argv  not used
+ *
+ * \return      Program exit status.
+ */
+int execute_tests( int args, const char ** argv )
+{
+    int ret = 0;
+    uint32_t data_len = 0;
+    uint8_t count = 0, function_id;
+    void ** params = NULL;
+    uint8_t * data = NULL, * p = NULL;
+
+    GREENTEA_SETUP_C( 180, "mbedtls_test" );
+    greentea_send_kv_c( "GO", " " );
+
+    while ( 1 )
+    {
+        ret = 0;
+        test_info.failed = 0;
+        data_len = 0;
+
+        data = receive_data( &data_len );
+        if ( data == NULL )
+            continue;
+        p = data;
+
+        do
+        {
+            /* Read dependency count */
+            count = *p;
+            assert( count < data_len );
+            INCR_ASSERT( p, data, data_len, sizeof( uint8_t ) );
+            ret = verify_dependencies( count, p );
+            if ( ret != DEPENDENCY_SUPPORTED )
+                break;
+
+            INCR_ASSERT( p, data, data_len, count );
+
+            /* Read function id */
+            function_id = *p;
+            INCR_ASSERT( p, data, data_len, sizeof( uint8_t ) );
+
+            /* Read number of parameters */
+            count = *p;
+            INCR_ASSERT( p, data, data_len, sizeof( uint8_t ) );
+
+            params = parse_parameters( count, p, data_len - (p - data), &ret );
+            if ( ret )
+                break;
+
+            ret = dispatch_test( function_id, params );
+        }
+        while ( 0 );
+
+        if ( data )
+        {
+            free(data);
+            data = NULL;
+        }
+
+        if ( params )
+        {
+            free( params );
+            params = NULL;
+        }
+
+        if ( ret )
+            send_failure( ret );
+        else
+            send_status( test_info.failed );
+    }
+    return( 0 );
+}
+