Xively C library

Dependents:   Application-xively-jumpstart-demo Application-xively-jumpstart-demo Modified_Xively_Jumpstart HW7-1_Xively_Thermostat

This is Xively C library, the code lives on GitHub.

See our example program and the tutorial, documentation can bee found here.

Files at this revision

API Documentation at this revision

Comitter:
xively
Date:
Wed Jun 26 10:40:43 2013 +0000
Commit message:
libxively v0.1.1-rc0 (34c8b32)

Changed in this revision

src/libxively/comm_layer.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/comm_layers/mbed/mbed_comm.cpp Show annotated file Show diff for this revision Revisions of this file
src/libxively/comm_layers/mbed/mbed_comm.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/comm_layers/mbed/mbed_comm_layer.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/comm_layers/mbed/mbed_comm_layer_data_specific.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/connection.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/csv_data.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/csv_data.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/csv_data_layer.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/csv_data_layer.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/data_layer.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_consts.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_layer_parser.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_layer_parser.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_layer_queries.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_layer_queries.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_transport.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_transport.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_transport_layer.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/http_transport_layer.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/transport_layer.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_allocator.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_allocator.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_consts.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_debug.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_err.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_err.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_globals.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_globals.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_helpers.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_helpers.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_macros.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_printf.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/xi_printf.h Show annotated file Show diff for this revision Revisions of this file
src/libxively/xively.c Show annotated file Show diff for this revision Revisions of this file
src/libxively/xively.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 82702e998d3f src/libxively/comm_layer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/comm_layer.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,85 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    comm_layer.h
+ * \author  Olgierd Humenczuk
+ * \brief   Defines _communication layer_ abstraction interface
+ *
+ *    The design of _communication layer_ was based on Berkley/POSIX socket API.
+ */
+
+#ifndef __POSIX_COMM_LAYER_H__
+#define __POSIX_COMM_LAYER_H__
+
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "connection.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief   _The communication layer interface_ - contains function pointers,
+ *          that's what we expose to the layers above and below
+ *
+ *    It is effectively a class that holds declarations of pure virtual functions.
+ *
+ *   The interface contain methods related to connecting/disconnecting as well as
+ *   reading/writing data to/from the remote endpoint.
+ *
+ *   This interface uses abstract `connection_t` class to hold information
+ *   about the connection in a platform-independent fashion.
+ */
+typedef struct {
+    /**
+     * \brief   Connect to a given host using it's address and port
+     * \note    It should not reset an existing connection.
+     *
+     * \return Pointer to `connection_t` or `0` in case of an error.
+     */
+    connection_t* ( *open_connection )( const char* address, int32_t port );
+
+    /**
+     * \brief   Send data over the connection
+     *
+     * \return  Number of bytes sent or `-1` in case of an error.
+     */
+    int ( *send_data )( connection_t* conn, const char* data, size_t size );
+
+    /**
+     * \brief   Read data from a connection
+     *
+     * \return  Number of bytes read or `-1` in case of an error.
+     */
+    int ( *read_data )( connection_t* conn, char* buffer, size_t buffer_size );
+
+    /**
+     * \brief   Close connection and free all allocated memory (if any)
+     * \note    Some implementations may be stack-based as only limited
+     *          number of connections is expected in a typical use-case.
+     */
+    void ( *close_connection )( connection_t* conn );
+} comm_layer_t;
+
+
+ /**
+  * \brief   Initialise an implementation of the _communication layer_
+  *
+  *    This intialiser assigns function pointers to the actual implementations
+  *    using  static function variable trick, hence the intialisation should
+  *    not give any overhead.
+  *
+  * \return  Structure with function pointers for platform-specific communication
+  *          methods (see `mbed_comm.h` and `posix_comm.h` for how it's done).
+  */
+const comm_layer_t* get_comm_layer( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __POSIX_COMM_LAYER_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/comm_layers/mbed/mbed_comm.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/comm_layers/mbed/mbed_comm.cpp	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,184 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    mbed_comm.cpp
+ * \author  Olgierd Humenczuk
+ * \brief   Implements mbed _communication layer_ abstraction interface using [TCPSocketConnection](http://mbed.org/users/mbed_official/code/Socket/docs/tip/classTCPSocketConnection.html) [see comm_layer.h]
+ */
+ 
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "mbed_comm.h"
+#include "comm_layer.h"
+#include "xi_helpers.h"
+#include "xi_allocator.h"
+#include "mbed_comm_layer_data_specific.h"
+#include "xi_err.h"
+#include "xi_macros.h"
+#include "xi_printf.h"
+#include "xi_globals.h"
+
+extern "C" {
+
+connection_t* mbed_open_connection( const char* address, int32_t port )
+{
+    // PRECONDITIONS
+    assert( address != 0 );
+
+    // variables
+    mbed_comm_layer_data_specific_t* pos_comm_data = 0;
+    connection_t* conn                             = 0;
+
+    // allocation of the socket connector
+    TCPSocketConnection* socket_ptr                = new TCPSocketConnection();
+    XI_CHECK_MEMORY( socket_ptr );
+
+    // set the timeout for blocking operations
+    socket_ptr->set_blocking( true, xi_globals.network_timeout );
+
+    // allocate memory for the mbed data specific structure
+    pos_comm_data = ( mbed_comm_layer_data_specific_t* )
+            xi_alloc( sizeof( mbed_comm_layer_data_specific_t ) );
+    XI_CHECK_MEMORY( pos_comm_data );
+
+    // allocate memory for the connection layer
+    conn = ( connection_t* ) xi_alloc(
+                sizeof( connection_t ) );
+    XI_CHECK_MEMORY( conn );
+
+    // clean the memory before the usage
+    memset( conn, 0, sizeof( connection_t ) );
+
+    // make copy of an address
+    conn->address = xi_str_dup( address );
+    conn->port = port;
+
+    XI_CHECK_MEMORY( conn->address );
+
+    { // to prevent the skip initializtion warning
+        pos_comm_data->socket_ptr = socket_ptr;
+
+        // assign the layer specific data
+        conn->layer_specific = pos_comm_data;
+
+        // try to connect
+        int s = pos_comm_data->socket_ptr->connect( address, port );
+
+        // check if not failed
+        if( s == -1 )
+        {
+            xi_set_err( XI_SOCKET_CONNECTION_ERROR );
+            goto err_handling;
+        }
+    }
+
+    // POSTCONDITIONS
+    assert( conn != 0 );
+    assert( pos_comm_data->socket_ptr != 0 );
+
+    return conn;
+
+    // cleanup the memory
+err_handling:
+    // safely destroy the object
+    if ( pos_comm_data && pos_comm_data->socket_ptr )
+    {
+        delete pos_comm_data->socket_ptr;
+        pos_comm_data->socket_ptr = 0;
+    }
+    if( pos_comm_data ) { XI_SAFE_FREE( pos_comm_data ); }
+    if( conn ) { XI_SAFE_FREE( conn->address ); }
+    XI_SAFE_FREE( conn );
+
+    return 0;
+}
+
+int mbed_send_data( connection_t* conn, const char* data, size_t size )
+{
+    // PRECONDITIONS
+    assert( conn != 0 );
+    assert( conn->layer_specific != 0 );
+    assert( data != 0 );
+    assert( size != 0 );
+
+    // extract the layer specific data
+    mbed_comm_layer_data_specific_t* pos_comm_data
+        = ( mbed_comm_layer_data_specific_t* ) conn->layer_specific;
+
+    // Why not const char* ???
+    int bytes_written = pos_comm_data->socket_ptr->send_all( ( char* ) data, size );
+
+    if( bytes_written == - 1 )
+    {
+        xi_set_err( XI_SOCKET_WRITE_ERROR );
+    }
+
+    // store the value
+    conn->bytes_sent += bytes_written;
+
+    return bytes_written;
+}
+
+int mbed_read_data( connection_t* conn, char* buffer, size_t buffer_size )
+{
+    // PRECONDITIONS
+    assert( conn != 0 );
+    assert( conn->layer_specific != 0 );
+    assert( buffer != 0 );
+    assert( buffer_size != 0 );
+
+    // extract the layer specific data
+    mbed_comm_layer_data_specific_t* pos_comm_data
+        = ( mbed_comm_layer_data_specific_t* ) conn->layer_specific;
+
+    memset( buffer, 0, buffer_size );
+    pos_comm_data->socket_ptr->set_blocking(true, 10);
+    int bytes_read = pos_comm_data->socket_ptr->receive( buffer, buffer_size );
+
+    if( bytes_read == -1 )
+    {
+        xi_set_err( XI_SOCKET_READ_ERROR );
+    }
+
+    // store the value
+    conn->bytes_received += bytes_read;
+
+    return bytes_read;
+}
+
+void mbed_close_connection( connection_t* conn )
+{
+    // PRECONDITIONS
+    assert( conn != 0 );
+    assert( conn->layer_specific != 0 );
+
+    // extract the layer specific data
+    mbed_comm_layer_data_specific_t* pos_comm_data
+        = ( mbed_comm_layer_data_specific_t* ) conn->layer_specific;
+
+    // close the connection & the socket
+    if( pos_comm_data->socket_ptr->close() == -1 )
+    {
+        xi_set_err( XI_SOCKET_CLOSE_ERROR );
+        goto err_handling;
+    }
+
+    // cleanup the memory
+err_handling:
+    // safely destroy the object
+    if ( pos_comm_data && pos_comm_data->socket_ptr )
+    {
+        delete pos_comm_data->socket_ptr;
+        pos_comm_data->socket_ptr = 0;
+    }
+    if( conn ) { XI_SAFE_FREE( conn->address ); }
+    if( conn ) { XI_SAFE_FREE( conn->layer_specific ); }
+    XI_SAFE_FREE( conn );
+    return;
+}
+
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/comm_layers/mbed/mbed_comm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/comm_layers/mbed/mbed_comm.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,31 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file     mbed_comm.h
+ * \author     Olgierd Humenczuk
+ * \brief   Implements mbed _communication layer_ functions [see comm_layer.h and mbed_comm.cpp]
+ */
+
+#ifndef __MBED_COMM_H__
+#define __MBED_COMM_H__
+
+#include "connection.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+connection_t* mbed_open_connection( const char* address, int32_t port );
+
+int mbed_send_data( connection_t* conn, const char* data, size_t size );
+
+int mbed_read_data( connection_t* conn, char* buffer, size_t buffer_size );
+
+void mbed_close_connection( connection_t* conn );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __MBED_COMM_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/comm_layers/mbed/mbed_comm_layer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/comm_layers/mbed/mbed_comm_layer.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,27 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file     mbed_comm_layer.c
+ * \author     Olgierd Humenczuk
+ * \brief   Implements mbed _communication layer_ abstraction interface [see comm_layer.h]
+ */
+
+#include "comm_layer.h"
+#include "mbed_comm.h"
+
+ /**
+  * \brief   Initialise POSIX implementation of the _communication layer_
+  */
+const comm_layer_t* get_comm_layer()
+{
+    static comm_layer_t __mbed_comm_layer =
+    {
+          &mbed_open_connection
+        , &mbed_send_data
+        , &mbed_read_data
+        , &mbed_close_connection
+    };
+
+    return &__mbed_comm_layer;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/comm_layers/mbed/mbed_comm_layer_data_specific.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/comm_layers/mbed/mbed_comm_layer_data_specific.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,19 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    mbed_comm_layer_data_specific.h
+ * \author  Olgierd Humenczuk
+ * \brief   Declares layer-specific data structure
+ */
+
+#ifndef __MBED_COMM_LAYER_DATA_SPECIFIC_H__
+#define __MBED_COMM_LAYER_DATA_SPECIFIC_H__
+
+#include "EthernetInterface.h"
+
+typedef struct {
+    TCPSocketConnection* socket_ptr;
+} mbed_comm_layer_data_specific_t;
+
+#endif // __MBED_COMM_LAYER_DATA_SPECIFIC_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/connection.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/connection.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,49 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    connection.h
+ * \author  Olgierd Humenczuk
+ * \brief   Defines `connection_t`, which is used by the _communication layer_
+ *
+ *    It is designed to abstract from implementation- and/or platform- specific
+ *    ways of storing connection info, such as host and port, as well as simple
+ *    statistics counters. It also provides arbitary pointer to implementation's
+ *    own strucutre.
+ */
+
+#ifndef __CONNECTION_H__
+#define __CONNECTION_H__
+
+#include "stdlib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief   _The connection structure_ - holds data needed for further processing
+ *          and error handling
+ * 
+ * It also contain `layer_specific` field which should point at the platform's
+ * structure, according to the implementation of that specific _communication_
+ * _layer_ and other implementation don't need to care about what that is.
+ *
+ * The purpose of that class is to give the abstract interface of a connection
+ * that can be easly used with the `comm_layer_t` interface, so that it's possible
+ * to send/receive data to/from the server through different communication layer
+ * using the same interface.
+ */
+typedef struct {
+    void    *layer_specific; //!< here the layer can hide some layer specific data
+    char    *address;        //!< here we store server's address
+    int      port;           //!< here we store server's port
+    size_t   bytes_sent;     //!< the data sent counter, just for testing and statistics
+    size_t   bytes_received; //!< the data receive counter, just for tests and statistics
+} connection_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CONNECTION_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/csv_data.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/csv_data.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,389 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    csv_data.c
+ * \author  Olgierd Humenczuk
+ * \brief   Implements CSV _data layer_ encoders and decoders specific to Xively CSV data format [see csv_data.h]
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "csv_data.h"
+#include "xi_macros.h"
+#include "xi_helpers.h"
+#include "xi_err.h"
+#include "xi_consts.h"
+
+static char XI_CSV_LOCAL_BUFFER[ XI_CSV_BUFFER_SIZE ];
+
+inline static int csv_encode_value(
+      char* buffer
+    , size_t buffer_size
+    , const xi_datapoint_t* p )
+{
+    // PRECONDITION
+    assert( buffer != 0 );
+    assert( buffer_size != 0 );
+    assert( p != 0 );
+
+    switch( p->value_type )
+    {
+        case XI_VALUE_TYPE_I32:
+            return snprintf( buffer, buffer_size, "%d", p->value.i32_value );
+        case XI_VALUE_TYPE_F32:
+            return snprintf( buffer, buffer_size, "%f", p->value.f32_value );
+        case XI_VALUE_TYPE_STR:
+            return snprintf( buffer, buffer_size, "%s", p->value.str_value );
+        default:
+            return -1;
+    }
+}
+
+typedef enum
+{
+    XI_CHAR_UNKNOWN = 0,
+    XI_CHAR_NUMBER,
+    XI_CHAR_LETTER,
+    XI_CHAR_DOT,
+    XI_CHAR_SPACE,
+    XI_CHAR_NEWLINE,
+    XI_CHAR_TAB,
+    XI_CHAR_MINUS
+} xi_char_type_t;
+
+inline static xi_char_type_t csv_classify_char( char c )
+{
+    switch( c )
+    {
+        case 13:
+        case 11:
+            return XI_CHAR_NEWLINE;
+        case 9:
+            return XI_CHAR_TAB;
+        case 32:
+            return XI_CHAR_SPACE;
+        case 33: case 34: case 35: case 36: case 37: case 38: case 39:
+        case 40: case 41: case 42: case 43: case 44:
+            return XI_CHAR_UNKNOWN;
+        case 45:
+            return XI_CHAR_MINUS;
+        case 46:
+            return XI_CHAR_DOT;
+        case 47:
+            return XI_CHAR_UNKNOWN;
+        case 48: case 49: case 50: case 51: case 52: case 53: case 54:
+        case 55: case 56:
+        case 57:
+            return XI_CHAR_NUMBER;
+        case 58: case 59: case 60: case 61: case 62: case 63:
+        case 64:
+            return XI_CHAR_UNKNOWN;
+        case 65: case 66: case 67: case 68: case 69: case 70: case 71:
+        case 72: case 73: case 74: case 75: case 76: case 77: case 78:
+        case 79: case 80: case 81: case 82: case 83: case 84: case 85:
+        case 86: case 87: case 88: case 89:
+        case 90:
+            return XI_CHAR_LETTER;
+        case 91: case 92: case 93: case 94: case 95:
+        case 96:
+            return XI_CHAR_UNKNOWN;
+        case 97: case 98: case 99: case 100: case 101: case 102: case 103:
+        case 104: case 105: case 106: case 107: case 108: case 109: case 110:
+        case 111: case 112: case 113: case 114: case 115: case 116: case 117:
+        case 118: case 119: case 120: case 121:
+        case 122:
+            return XI_CHAR_LETTER;
+        case 123:
+        case 124:
+        case 125:
+            return XI_CHAR_UNKNOWN;
+        default:
+            return XI_CHAR_UNKNOWN;
+    }
+}
+
+typedef enum
+{
+    XI_STATE_INITIAL = 0,
+    XI_STATE_MINUS,
+    XI_STATE_NUMBER,
+    XI_STATE_FLOAT,
+    XI_STATE_DOT,
+    XI_STATE_STRING
+} xi_dfa_state_t;
+
+xi_datapoint_t* csv_decode_value(
+    const char* buffer, xi_datapoint_t* p )
+{
+    // PRECONDITION
+    assert( buffer != 0 );
+    assert( p != 0 );
+
+    // secure the output buffer
+    XI_GUARD_EOS( p->value.str_value, XI_VALUE_STRING_MAX_SIZE );
+
+    // clean the counter
+    size_t  counter = 0;
+
+    // the transition function
+    static const short states[][6][2] =
+    {
+          // state initial                          // state minus                            // state number                           // state float                            // state dot                              // string
+        { { XI_CHAR_UNKNOWN   , XI_STATE_STRING  }, { XI_CHAR_UNKNOWN   , XI_STATE_STRING  }, { XI_CHAR_UNKNOWN   , XI_STATE_STRING  }, { XI_CHAR_UNKNOWN   , XI_STATE_STRING  }, { XI_CHAR_UNKNOWN   , XI_STATE_STRING  }, { XI_CHAR_UNKNOWN   , XI_STATE_STRING  } },
+        { { XI_CHAR_NUMBER    , XI_STATE_NUMBER  }, { XI_CHAR_NUMBER    , XI_STATE_NUMBER  }, { XI_CHAR_NUMBER    , XI_STATE_NUMBER  }, { XI_CHAR_NUMBER    , XI_STATE_FLOAT   }, { XI_CHAR_NUMBER    , XI_STATE_FLOAT   }, { XI_CHAR_NUMBER    , XI_STATE_STRING  } },
+        { { XI_CHAR_LETTER    , XI_STATE_STRING  }, { XI_CHAR_LETTER    , XI_STATE_STRING  }, { XI_CHAR_LETTER    , XI_STATE_STRING  }, { XI_CHAR_LETTER    , XI_STATE_STRING  }, { XI_CHAR_LETTER    , XI_STATE_STRING  }, { XI_CHAR_LETTER    , XI_STATE_STRING  } },
+        { { XI_CHAR_DOT       , XI_STATE_DOT     }, { XI_CHAR_DOT       , XI_STATE_DOT     }, { XI_CHAR_DOT       , XI_STATE_DOT     }, { XI_CHAR_DOT       , XI_STATE_STRING  }, { XI_CHAR_DOT       , XI_STATE_STRING  }, { XI_CHAR_DOT       , XI_STATE_STRING  } },
+        { { XI_CHAR_SPACE     , XI_STATE_STRING  }, { XI_CHAR_SPACE     , XI_STATE_STRING  }, { XI_CHAR_SPACE     , XI_STATE_STRING  }, { XI_CHAR_SPACE     , XI_STATE_STRING  }, { XI_CHAR_SPACE     , XI_STATE_STRING  }, { XI_CHAR_SPACE     , XI_STATE_STRING  } },
+        { { XI_CHAR_NEWLINE   , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE   , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE   , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE   , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE   , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE   , XI_STATE_INITIAL } },
+        { { XI_CHAR_TAB       , XI_STATE_STRING  }, { XI_CHAR_TAB       , XI_STATE_STRING  }, { XI_CHAR_TAB       , XI_STATE_STRING  }, { XI_CHAR_TAB       , XI_STATE_STRING  }, { XI_CHAR_TAB       , XI_STATE_STRING  }, { XI_CHAR_TAB       , XI_STATE_STRING  } },
+        { { XI_CHAR_MINUS     , XI_STATE_MINUS   }, { XI_CHAR_MINUS     , XI_STATE_STRING  }, { XI_CHAR_MINUS     , XI_STATE_STRING  }, { XI_CHAR_MINUS     , XI_STATE_STRING  }, { XI_CHAR_MINUS     , XI_STATE_STRING  }, { XI_CHAR_MINUS     , XI_STATE_STRING  } }
+    };
+
+    char    c = *buffer;
+    short   s = XI_STATE_INITIAL;
+
+    while( c != '\n' && c !='\0' && c!='\r' )
+    {
+        if( counter >= XI_VALUE_STRING_MAX_SIZE - 1 )
+        {
+            xi_set_err( XI_DATAPOINT_VALUE_BUFFER_OVERFLOW );
+            return 0;
+        }
+
+        xi_char_type_t ct = csv_classify_char( c );
+        s = states[ ct ][ s ][ 1 ];
+
+        switch( s )
+        {
+            case XI_STATE_MINUS:
+            case XI_STATE_NUMBER:
+            case XI_STATE_FLOAT:
+            case XI_STATE_DOT:
+            case XI_STATE_STRING:
+                p->value.str_value[ counter ] = c;
+                break;
+        }
+
+        c = *( ++buffer );
+        ++counter;
+    }
+
+    // set the guard
+    p->value.str_value[ counter ] = '\0';
+
+    // update of the state for loose states...
+    switch( s )
+    {
+        case XI_STATE_MINUS:
+        case XI_STATE_DOT:
+        case XI_STATE_INITIAL:
+            s = XI_STATE_STRING;
+            break;
+    }
+
+    switch( s )
+    {
+        case XI_STATE_NUMBER:
+            p->value.i32_value  = atoi( p->value.str_value );
+            p->value_type       = XI_VALUE_TYPE_I32;
+            break;
+        case XI_STATE_FLOAT:
+            p->value.f32_value  = atof( p->value.str_value );
+            p->value_type       = XI_VALUE_TYPE_F32;
+            break;
+        case XI_STATE_STRING:
+        default:
+            p->value_type       = XI_VALUE_TYPE_STR;
+    }
+
+    return p;
+}
+
+const char* csv_encode_datapoint( const xi_datapoint_t* data )
+{
+
+    // PRECONDITIONS
+    assert( data != 0 );
+
+    return csv_encode_datapoint_in_place( XI_CSV_LOCAL_BUFFER, sizeof( XI_CSV_LOCAL_BUFFER ), data ) == -1 ? 0 : XI_CSV_LOCAL_BUFFER;
+}
+
+int csv_encode_datapoint_in_place(
+      char* in, size_t in_size
+    , const xi_datapoint_t* datapoint )
+{
+    // PRECONDITIONS
+    assert( in != 0 );
+    assert( datapoint != 0 );
+
+    int s       = 0;
+    int size    = in_size;
+    int offset  = 0;
+
+    if( datapoint->timestamp.timestamp != 0 )
+    {
+        time_t stamp = datapoint->timestamp.timestamp;
+        struct tm* gmtinfo = xi_gmtime( &stamp );
+
+        s = snprintf( in, size
+            , "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ,"
+            , gmtinfo->tm_year + 1900
+            , gmtinfo->tm_mon + 1
+            , gmtinfo->tm_mday
+            , gmtinfo->tm_hour
+            , gmtinfo->tm_min
+            , gmtinfo->tm_sec
+            , ( int ) datapoint->timestamp.micro );
+
+        XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN );
+    }
+
+    s = csv_encode_value( in + offset, size - offset, datapoint );
+    XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN );
+
+    s = snprintf( in + offset, size - offset, "%s", "\n" );
+    XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN );
+
+    return offset;
+
+err_handling:
+    return -1;
+}
+
+const char* csv_encode_create_datastream(
+          const char* datastream_id
+        , const xi_datapoint_t* data )
+{
+    // PRECONDITIONS
+    assert( data != 0 );
+
+    int s       = 0;
+    int size    = sizeof( XI_CSV_LOCAL_BUFFER );
+    int offset  = 0;
+
+    s = snprintf( XI_CSV_LOCAL_BUFFER + offset, size - offset
+            , "%s,", datastream_id );
+    XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN );
+
+    s = csv_encode_value( XI_CSV_LOCAL_BUFFER + offset, size - offset, data );
+    XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN );
+
+    s = snprintf( XI_CSV_LOCAL_BUFFER + offset, size - offset, "\n" );
+    XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN );
+
+    return XI_CSV_LOCAL_BUFFER;
+
+err_handling:
+    return 0;
+}
+
+xi_feed_t* csv_decode_feed(
+      const char* buffer
+    , xi_feed_t* feed )
+{
+    const char* current     = buffer;
+    int32_t counter         = 0;
+
+    // find occurence of newline
+    char* end_of_line = ( char* ) 1;
+
+    // while we didn't jump out of the buffer
+    while( end_of_line )
+    {
+        // get current datapoint
+        xi_datastream_t* d    = &feed->datastreams[ counter ];
+        d->datapoint_count    = 0;
+        xi_datapoint_t* p     = &d->datapoints[ 0 ];
+        memset( p, 0, sizeof( xi_datapoint_t ) );
+
+        end_of_line = strstr( current, "\n" );
+
+        const char* end_of_datastream_id  = strstr( current, "," );
+        const char* beg_of_datapoint      = end_of_datastream_id + 1;
+
+        XI_CHECK_ZERO( beg_of_datapoint, XI_CSV_DECODE_FEED_PARSER_ERROR );
+        XI_CHECK_ZERO( end_of_datastream_id, XI_CSV_DECODE_FEED_PARSER_ERROR );
+
+        int size = sizeof( d->datastream_id );
+
+        int s = xi_str_copy_untiln( d->datastream_id, size
+            , current, ',' );
+        XI_CHECK_SIZE( s, size, XI_CSV_DECODE_FEED_PARSER_ERROR );
+
+        xi_datapoint_t* ret = csv_decode_datapoint( beg_of_datapoint, p );
+        XI_CHECK_ZERO( ret, XI_CSV_DECODE_FEED_PARSER_ERROR )
+
+        d->datapoint_count = 1;
+        current = end_of_line + 1;
+
+        XI_CHECK_CND( ++counter == XI_MAX_DATASTREAMS
+            , XI_CSV_DECODE_FEED_PARSER_ERROR );
+    }
+
+    feed->datastream_count = counter;
+    return feed;
+
+err_handling:
+    return 0;
+}
+
+xi_datapoint_t* csv_decode_datapoint(
+      const char* buffer
+    , xi_datapoint_t* datapoint )
+{
+    // PRECONDITIONS
+    assert( buffer != 0 );
+    assert( datapoint != 0 );
+
+    int ye, mo, da, h, m, s, ms;
+
+    const char* beg_of_value = strstr( buffer, "," );
+
+    // check continuation condition
+    XI_CHECK_ZERO( beg_of_value, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR );
+
+    // move to pointer to the proper position
+    beg_of_value += 1;
+
+    {
+        int n = sscanf( buffer
+            , "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ"
+            , &ye, &mo, &da, &h, &m, &s, &ms );
+
+        // check if the parser worked correctly
+        XI_CHECK_CND( n != 7, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR );
+
+        // copy parsed data
+        {
+            struct tm timeinfo;
+
+            timeinfo.tm_year   = ye - 1900;
+            timeinfo.tm_mon    = mo - 1;
+            timeinfo.tm_mday   = da;
+            timeinfo.tm_hour   = h;
+            timeinfo.tm_min    = m;
+            timeinfo.tm_sec    = s;
+
+            time_t timestamp = xi_mktime( &timeinfo );
+
+            XI_CHECK_CND( ( int )timestamp == -1, XI_CSV_TIME_CONVERTION_ERROR );
+
+            datapoint->timestamp.timestamp  = timestamp;
+            datapoint->timestamp.micro      = ms;
+        }
+    }
+
+    xi_datapoint_t* r = csv_decode_value( beg_of_value
+        , datapoint );
+
+
+    XI_CHECK_ZERO( r, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR );
+
+    return datapoint;
+
+err_handling:
+    return 0;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/csv_data.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/csv_data.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,40 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    csv_data.h
+ * \author  Olgierd Humenczuk
+ * \brief   Implements CSV _data layer_ encoders and decoders specific to Xively CSV data format
+ */
+ 
+#ifndef __CSV_DATA_H__
+#define __CSV_DATA_H__
+
+#include "xively.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char* csv_encode_datapoint( const xi_datapoint_t* dp );
+
+
+int csv_encode_datapoint_in_place(
+      char* buffer, size_t buffer_size
+    , const xi_datapoint_t* datapoint );
+
+const char* csv_encode_create_datastream(
+          const char* buffer
+        , const xi_datapoint_t* dp );
+
+xi_feed_t* csv_decode_feed(
+      const char* buffer
+    , xi_feed_t* feed );
+
+xi_datapoint_t* csv_decode_datapoint( const char* data, xi_datapoint_t* dp );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CSV_DATA_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/csv_data_layer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/csv_data_layer.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,23 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    csv_data_layer.c
+ * \author  Olgierd Humenczuk
+ * \brief     Implements CSV _data layer_ abstration interface [see csv_data_layer.h and data_layer.h]
+ */
+
+#include "csv_data_layer.h"
+
+const data_layer_t* get_csv_data_layer()
+{
+    static const data_layer_t __csv_data_layer = {
+          csv_encode_datapoint
+        , csv_encode_datapoint_in_place
+        , csv_encode_create_datastream
+        , csv_decode_feed
+        , csv_decode_datapoint
+    };
+
+    return &__csv_data_layer;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/csv_data_layer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/csv_data_layer.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,37 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    csv_data_layer.h
+ * \author  Olgierd Humenczuk
+ * \brief   Implements CSV _data layer_ abstration interface
+ */
+
+#ifndef __CSV_DATA_LAYER_H__
+#define __CSV_DATA_LAYER_H__
+
+#include "xively.h"
+#include "data_layer.h"
+#include "csv_data.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /**
+ * \brief   Initialise CSV implementation of the _data layer_
+ *
+ *    This intialiser assigns function pointers to the actual implementations
+ *    using  static function variable trick, hence the intialisation should
+ *    not give any overhead.
+ *
+ * \return  Structure with function pointers for CSV encoders and decoders
+ *          which had been implemented in `csv_data.c`.
+ */
+const data_layer_t* get_csv_data_layer( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CSV_DATA_LAYER_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/data_layer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/data_layer.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,86 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    data_layer.h
+ * \author  Olgierd Humenczuk
+ * \brief   Defines _data layer_ abstraction interface
+ */
+
+#ifndef __DATA_LAYER_H__
+#define __DATA_LAYER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief   _The data layer interface_ - contains function pointers,
+ *          that's what we expose to the layers above and below
+ *
+ *    It is effectively a class that holds declarations of pure virtual functions.
+ *    * All encoders take a given data type (e.g. `xi_feed_t`, `xi_datapoint_t`) and produce
+ *    an encoded string in a buffer, which can be wrapped as payload to _transport layer_
+ *    or any other layer, such as _gzip_.
+ *    * All decoders take a given data buffer and convert to an appropriate data type.
+ *
+ * \note    The encoders and decoders do not have to be paired, e.g. `encode_feed` is actually
+ *          implemented using `encode_datapoint_in_place` in a loop (see `http_encode_update_feed`),
+ *          so we only need `decode_feed`. However, this presumption had been made with CSV _data_
+ *          _layer_ implementation and the interface may need to change if other data formats are
+ *          to be implemented, but it is currently more important to have it the way it is.
+ *          The layering model should allow for simple way of integrating anything, even if there
+ *          might seem to be some inconsistency right now.
+ */
+typedef struct {
+    /**
+     * \brief   This function converts `xi_datapoint_t` into an implementation-specific format
+     *          for a datapoint.
+     *
+     * \return  Pointer to the buffer where encoded string resides.
+     */
+    const char* ( *encode_datapoint )( const xi_datapoint_t* dp );
+
+    /**
+     * \brief   This function converts `xi_datapoint_t` into an implementation-specific format
+     *          for a datapoint with output buffer given as an argument.
+     *
+     * \return  Offset or -1 if an error occurred.
+     */
+    int ( *encode_datapoint_in_place )(
+          char* buffer, size_t buffer_size
+        , const xi_datapoint_t* dp );
+
+    /**
+     * \brief   This function converts `xi_datapoint_t` and a given datastream ID string
+     *          into an implementation-specific format for creating datastreams.
+
+     * \return  Pointer to the buffer where encoded string resides.
+     */
+    const char* ( *encode_create_datastream )(
+          const char* data
+        , const xi_datapoint_t* dp );
+
+    /**
+     * \brief   This function converts from an implementation-specific format for a feed
+     *          into `xi_feed_t` that is given as an argument.
+     *
+     * \return  Pointer to feed structure or null if an error occurred.
+     */
+    xi_feed_t* ( *decode_feed )( const char* data, xi_feed_t* feed );
+
+    /**
+     * \brief   This function converts from an implementation-specific format for a datapoint
+     *          into `xi_datapoint_t` that is given as an argument.
+     *
+     * \return  Pointer to datastream structure or null if an error occurred.
+
+     */
+    xi_datapoint_t* ( *decode_datapoint )( const char* data, xi_datapoint_t* dp );
+} data_layer_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DATA_LAYER_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/http_consts.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_consts.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,20 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_consts.h
+ * \author  Olgierd Humenczuk
+ * \brief   Constants used by our HTTP parser.
+ */
+
+#ifndef __HTTP_CONSTS_H__
+#define __HTTP_CONSTS_H__
+
+static const char XI_HTTP_CRLF[]           = "\r\n";
+static const char XI_HTTP_CRLFX2[]         = "\r\n\r\n";
+static const char XI_HTTP_QUERY_GET[]      = "GET";
+static const char XI_HTTP_QUERY_PUT[]      = "PUT";
+static const char XI_HTTP_QUERY_POST[]     = "POST";
+static const char XI_HTTP_QUERY_DELETE[]   = "DELETE";
+
+#endif // __HTTP_CONSTS_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/http_layer_parser.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_layer_parser.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,196 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_layer_parser.c
+ * \author  Olgierd Humenczuk
+ * \brief   Our simple HTTP parser [see http_layer_parser.h]
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "xively.h"
+#include "xi_macros.h"
+#include "http_consts.h"
+#include "http_layer_parser.h"
+#include "xi_debug.h"
+#include "xi_err.h"
+
+static const char XI_HTTP_STATUS_PATTERN[] =
+    "HTTP/%d.%d %d %" XI_STR(XI_HTTP_STATUS_STRING_SIZE) "[^\r\n]\r\n"; //!< the match pattern
+
+#define SET_HTTP_STATUS_PATTERN(a,b,c,d) XI_HTTP_STATUS_PATTERN, &a, &b, &c, d
+
+static const char XI_HTTP_TOKEN_NAMES[ XI_HTTP_HEADERS_COUNT ][ XI_HTTP_HEADER_NAME_MAX_SIZE ] =
+    {
+          "date"            // XI_HTTP_HEADER_DATE
+        , "content-type"    // XI_HTTP_HEADER_CONTENT_TYPE
+        , "content-length"  // XI_HTTP_HEADER_CONTENT_LENGTH
+        , "connection"      // XI_HTTP_HEADER_CONNECTION
+        , "x-request-id"    // XI_HTTP_HEADER_X_REQUEST_ID
+        , "cache-control"   // XI_HTTP_HEADER_CACHE_CONTROL
+        , "age"             // XI_HTTP_HEADER_AGE
+        , "vary"            // XI_HTTP_HEADER_VARY
+        , "unknown"         // XI_HTTP_HEADER_UNKNOWN, //!< !!!! this must be always on the last position
+    };
+
+static inline http_header_type_t classify_header( const char* header )
+{
+    for( unsigned short i = 0; i < XI_HTTP_HEADER_COUNT - 1; ++i )
+    {
+        if( strcasecmp( header, XI_HTTP_TOKEN_NAMES[ i ] ) == 0 )
+            return ( http_header_type_t ) i;
+    }
+
+    return XI_HTTP_HEADER_UNKNOWN;
+}
+
+const char* parse_http_status( http_response_t* response, const char* content )
+{
+    // variables
+    int c = 0;
+
+    // find the first occurrence of CRLF
+    const char* header_end_ptr = strstr( content, XI_HTTP_CRLF );
+
+    // check continuation condition
+    XI_CHECK_ZERO( header_end_ptr, XI_HTTP_STATUS_PARSE_ERROR );
+
+    // update the pointer
+    header_end_ptr += 2;
+
+    // parse
+    c = sscanf( content
+        , SET_HTTP_STATUS_PATTERN(
+              response->http_version1
+            , response->http_version2
+            , response->http_status
+            , response->http_status_string ) );
+
+    // check if all arguments found
+    XI_CHECK_CND( c != 4, XI_HTTP_STATUS_PARSE_ERROR );
+
+    // return updated ptr
+    return header_end_ptr;
+
+err_handling:
+    return 0;
+}
+
+const char* parse_http_header( http_response_t* response
+    , const char* content )
+{
+    // find the first occurrence of CRLF
+    const char* header_end_ptr      = strstr( content, XI_HTTP_CRLF );
+    const char* header_name_end_ptr = strstr( content, ":" );
+
+    // check continuation condition
+    XI_CHECK_ZERO( header_end_ptr, XI_HTTP_HEADER_PARSE_ERROR );
+    XI_CHECK_ZERO( header_name_end_ptr, XI_HTTP_HEADER_PARSE_ERROR );
+    XI_CHECK_CND( header_name_end_ptr > header_end_ptr, XI_HTTP_HEADER_PARSE_ERROR );
+
+    {
+        int size = sizeof( response->http_headers[ response->http_headers_size ].name );
+
+        XI_CHECK_CND( header_name_end_ptr - content > size - 1, XI_HTTP_HEADER_PARSE_ERROR );
+
+        memcpy( response->http_headers[ response->http_headers_size ].name
+            , content, XI_MIN( size - 1, header_name_end_ptr - content ) );
+
+        // set the guard
+        XI_GUARD_EOS( response->http_headers[ response->http_headers_size ].name, size );
+    }
+
+    // update the pointer
+    header_name_end_ptr += 2;
+
+    {
+        int size = sizeof( response->http_headers[ response->http_headers_size ].value );
+
+        XI_CHECK_CND( header_end_ptr - header_name_end_ptr > size - 1, XI_HTTP_HEADER_PARSE_ERROR );
+
+        memcpy( response->http_headers[ response->http_headers_size ].value
+            , header_name_end_ptr, XI_MIN( size - 1, header_end_ptr - header_name_end_ptr ) );
+
+        // set the guard
+        XI_GUARD_EOS( response->http_headers[ response->http_headers_size ].value, size );
+    }
+
+    // @TODO change the complexity of the classify header
+    // implementation now it's O( n*m ) it can be done in O( n )
+    // using some sort of simple DFA
+    // I'm working on a very simple Python DFA generator for C
+    // but still this is a w.i.p. at the moment
+
+    // parse the header name
+    {
+        http_header_type_t ht = classify_header(
+            response->http_headers[ response->http_headers_size ].name );
+
+        // accept headers that differs from unknown
+        if( ht != XI_HTTP_HEADER_UNKNOWN )
+        {
+            response->http_headers_checklist[ ht ] =
+                &response->http_headers[ response->http_headers_size ];
+        }
+
+        // set header type
+        response->http_headers[ response->http_headers_size ].header_type = ht;
+
+        // increment headers size and check if it's okay
+        response->http_headers_size += 1;
+
+        XI_CHECK_CND( response->http_headers_size >= XI_HTTP_MAX_HEADERS
+            , XI_HTTP_HEADER_PARSE_ERROR );
+
+        // update the pointer
+        header_end_ptr += sizeof( XI_HTTP_CRLF ) - 1;
+    }
+
+    return header_end_ptr;
+
+err_handling:
+    return 0;
+}
+
+http_response_t* parse_http( http_response_t* response, const char* content )
+{
+    memset( response, 0, sizeof( http_response_t ) );
+
+    // remember where is the end of header section
+    const char* ptr_to_headers_end = strstr( content, XI_HTTP_CRLFX2 );
+
+    // check the continuation condition
+    XI_CHECK_ZERO( ptr_to_headers_end, XI_HTTP_PARSE_ERROR );
+
+    // update the pointer
+    ptr_to_headers_end += sizeof( XI_HTTP_CRLF ) - 1;
+
+    const char* payload_begin = ptr_to_headers_end + sizeof( XI_HTTP_CRLF ) - 1;
+
+    XI_CHECK_ZERO( payload_begin, XI_HTTP_PARSE_ERROR );
+
+    // parse status
+    const char* ptr = parse_http_status( response, content );
+
+    // check the continuation condition
+    XI_CHECK_ZERO( ptr, XI_HTTP_PARSE_ERROR );
+
+    // read the headers
+    while( ( ptr = parse_http_header( response, ptr ) ) != '\0'
+        && ptr != ptr_to_headers_end );
+
+    // if there was an error, forward it
+    xi_err_t e = xi_get_last_error();
+    XI_CHECK_CND( e != XI_NO_ERR, e );
+
+    // just copy the content
+    strncpy( response->http_content, payload_begin, sizeof( response->http_content ) );
+
+    return response;
+
+err_handling:
+    return 0;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/http_layer_parser.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_layer_parser.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,36 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_layer_parser.h
+ * \author  Olgierd Humenczuk
+ * \brief   Our simple HTTP parser
+ */
+
+#ifndef __HTTP_LAYER_PARSER_H__
+#define __HTTP_LAYER_PARSER_H__
+
+#include "xi_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief  This function takes the pointer to the `http_response_t` structure and
+ *         fills it with parsed data from the give buffer.
+ *
+ *    While the parser looks at headers, satus line and content, it populates given
+ *    pointer to `http_response_t`.
+ *
+ * \return Pointer or null if an error occurred.
+ *
+ * \note   It currently won't work against partial data.
+ */
+http_response_t* parse_http( http_response_t* response, const char* data );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r 000000000000 -r 82702e998d3f src/libxively/http_layer_queries.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_layer_queries.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,276 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_layer_queries.h
+ * \author  Olgierd Humenczuk
+ * \brief   Helpers for making HTTP requests (specific to Xively REST/HTTP API) [see http_layer_queries.h]
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "http_layer_queries.h"
+#include "xi_macros.h"
+#include "xi_err.h"
+#include "xi_consts.h"
+
+
+static const char XI_HTTP_TEMPLATE_FEED[] = "%s /v2/feeds%s.csv%s HTTP/1.1\r\n"
+                                  "Host: %s\r\n"
+                                  "User-Agent: %s\r\n"
+                                  "Accept: */*\r\n"
+                                  "X-ApiKey: %s\r\n";
+
+static const char XI_HTTP_ID_TEMPLATE[]    = "/%s";
+static const char XI_HTTP_ID_TEMPLATE_D[]  = "/%d";
+
+static const char XI_HTTP_CONTENT_TEMPLATE[] = "Content-Type: text/plain\r\n"
+                                            "Content-Length: %d\r\n";
+
+static char XI_QUERY_BUFFER[ XI_QUERY_BUFFER_SIZE ];
+static char XI_CONTENT_BUFFER[ XI_CONTENT_BUFFER_SIZE ];
+static char XI_ID_BUFFER[ XI_ID_BUFFER_SIZE ];
+
+inline static int http_construct_string(
+      char* buffer, size_t buffer_size
+    , const char* string_id )
+{
+    // PRECONDITIONS
+    assert( buffer      != 0 );
+    assert( buffer_size != 0 );
+
+    int s       = 0;
+    int size    = buffer_size;
+
+    if( string_id )
+    {
+        s = snprintf( buffer, size
+            , XI_HTTP_ID_TEMPLATE, string_id );
+
+        XI_CHECK_SIZE( s, size, XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN );
+    }
+
+    return s;
+
+err_handling:
+    return -1;
+}
+
+inline static int http_construct_int(
+      char* buffer, size_t buffer_size
+    , const int32_t* int_id )
+{
+    // PRECONDITIONS
+    assert( buffer      != 0 );
+    assert( buffer_size != 0 );
+
+    int s = 0;
+    int size = buffer_size;
+
+    if( int_id )
+    {
+        s = snprintf( buffer, size
+            , XI_HTTP_ID_TEMPLATE_D, *int_id );
+
+        XI_CHECK_SIZE( s, size, XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN )
+    }
+
+    return s;
+
+err_handling:
+    return -1;
+}
+
+inline static int http_construct_feed(
+      char* buffer, size_t buffer_size
+    , const int32_t* feed_id )
+{
+    // PRECONDITIONS
+    assert( buffer != 0 );
+    assert( buffer_size != 0 );
+
+    if( feed_id )
+    {
+        return http_construct_int( buffer
+            , buffer_size, feed_id );
+    }
+
+    return 0;
+}
+
+inline static int http_construct_datastream(
+      char* buffer, size_t buffer_size
+    , const int32_t* feed_id
+    , const char* datastream_id )
+{
+    // PRECONDITIONS
+    assert( buffer != 0 );
+    assert( buffer_size != 0 );
+
+    int s       = http_construct_feed( buffer, buffer_size, feed_id );
+    int offset  = 0;
+    int size    = buffer_size;
+
+    XI_CHECK_S( s, size, offset, XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN );
+
+    s = http_construct_string( buffer + offset, buffer_size - offset
+        , "datastreams" );
+
+    XI_CHECK_S( s, size, offset, XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN );
+
+    if( datastream_id )
+    {
+        return http_construct_string( buffer + offset, buffer_size - offset
+            , datastream_id == 0 ? "" : datastream_id );
+    }
+
+    return offset;
+
+err_handling:
+    return -1;
+}
+
+inline static int http_construct_datapoint(
+      char* buffer, size_t buffer_size
+    , const int32_t* feed_id
+    , const char* datastream_id
+    , const char* datapoint )
+{
+    // PRECONDITIONS
+    assert( buffer != 0 );
+    assert( buffer_size != 0 );
+
+    int s       = http_construct_datastream( buffer, buffer_size
+        , feed_id, datastream_id );
+    int offset  = 0;
+    int size    = buffer_size;
+
+    XI_CHECK_S( s, size, offset
+        , XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN );
+
+    s = http_construct_string( buffer + offset, buffer_size - offset
+        , "datapoints" );
+
+    XI_CHECK_S( s, size, offset
+        , XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN );
+
+    if( datapoint )
+    {
+        return http_construct_string( buffer + offset, buffer_size - offset
+            , datapoint == 0 ? "" : datapoint );
+    }
+
+    return offset;
+
+err_handling:
+    return -1;
+}
+
+inline static const char* http_construct_http_query(
+      const char* http_method
+    , const char* id
+    , const char* query_suffix
+    , const char* x_api_key )
+{
+    // PRECONDITIONS
+    assert( http_method     != 0 );
+    assert( x_api_key   != 0 );
+
+    int s = snprintf( XI_QUERY_BUFFER, XI_QUERY_BUFFER_SIZE, XI_HTTP_TEMPLATE_FEED
+        , http_method, id == 0 ? "" : id, query_suffix == 0 ? "" : query_suffix
+        , XI_HOST, XI_USER_AGENT, x_api_key );
+
+    XI_CHECK_SIZE( s, XI_QUERY_BUFFER_SIZE
+        , XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN );
+
+    return XI_QUERY_BUFFER;
+
+err_handling:
+    return 0;
+}
+
+const char* http_construct_request_datapoint(
+          const char* http_method
+        , const int32_t* feed_id
+        , const char* datastream
+        , const char* datapoint
+        , const char* x_api_key )
+{
+    // PRECONDITIONS
+    assert( http_method != 0 );
+    assert( feed_id != 0 );
+    assert( datastream != 0 );
+    assert( x_api_key != 0 );
+
+    int s = http_construct_datapoint( XI_ID_BUFFER, XI_ID_BUFFER_SIZE
+        , feed_id, datastream, datapoint );
+
+    XI_CHECK_SIZE( s, XI_ID_BUFFER_SIZE
+        , XI_HTTP_CONSTRUCT_CONTENT_BUFFER_OVERRUN );
+
+    return http_construct_http_query( http_method, XI_ID_BUFFER, 0, x_api_key );
+
+err_handling:
+    return 0;
+}
+
+const char* http_construct_request_datastream(
+          const char* http_method
+        , const int32_t* feed_id
+        , const char* datastream
+        , const char* x_api_key )
+{
+    // PRECONDITIONS
+    assert( http_method != 0 );
+    assert( feed_id != 0 );
+    assert( x_api_key != 0 );
+
+    int s = http_construct_datastream( XI_ID_BUFFER, XI_ID_BUFFER_SIZE
+        , feed_id, datastream );
+
+    XI_CHECK_SIZE( s, XI_ID_BUFFER_SIZE
+        , XI_HTTP_CONSTRUCT_CONTENT_BUFFER_OVERRUN )
+
+    return http_construct_http_query( http_method, XI_ID_BUFFER, 0, x_api_key );
+
+err_handling:
+    return 0;
+}
+
+const char* http_construct_request_feed(
+          const char* http_method
+        , const int32_t* feed_id
+        , const char* x_api_key
+        , const char* query_suffix )
+{
+    // PRECONDITIONS
+    assert( http_method != 0 );
+    assert( x_api_key != 0 );
+
+    int s = http_construct_feed( XI_ID_BUFFER, XI_ID_BUFFER_SIZE, feed_id );
+
+    XI_CHECK_SIZE( s, XI_ID_BUFFER_SIZE
+        , XI_HTTP_CONSTRUCT_CONTENT_BUFFER_OVERRUN );
+
+    return http_construct_http_query( http_method, XI_ID_BUFFER, query_suffix, x_api_key );
+
+err_handling:
+    return 0;
+}
+
+const char* http_construct_content(
+          int32_t content_size )
+{
+
+    int s = snprintf( XI_CONTENT_BUFFER, XI_CONTENT_BUFFER_SIZE
+      , XI_HTTP_CONTENT_TEMPLATE, content_size );
+
+    XI_CHECK_SIZE( s, XI_CONTENT_BUFFER_SIZE
+        , XI_HTTP_CONSTRUCT_CONTENT_BUFFER_OVERRUN );
+
+    return XI_CONTENT_BUFFER;
+
+err_handling:
+    return 0;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/http_layer_queries.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_layer_queries.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,50 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_layer_queries.c
+ * \author  Olgierd Humenczuk
+ * \brief   Helpers for making HTTP requests (specific to Xively REST/HTTP API)
+ *
+ *    * All functions return pointer to the buffer with request string or null in case of any error.
+
+ * \warning The buffer is managed by the library, so it's forbidden to free the pointer.
+ */
+
+#ifndef __HTTP_LAYERS_QUERIES_H__
+#define __HTTP_LAYERS_QUERIES_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char* http_construct_request_datapoint(
+          const char* http_method
+        , const int32_t* feed_id
+        , const char* datastream_id
+        , const char* dp_ts_str
+        , const char* x_api_key );
+
+const char* http_construct_request_datastream(
+          const char* http_method
+        , const int32_t* feed_id
+        , const char* datastream_id
+        , const char* x_api_key );
+
+const char* http_construct_request_feed(
+          const char* http_method
+        , const int32_t* feed_id
+        , const char* x_api_key
+        , const char* query_suffix );
+
+const char* http_construct_content(
+          int32_t content_size );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __HTTP_LAYERS_QUERIES_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/http_transport.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_transport.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,29 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_transport.c
+ * \author  Olgierd Humenczuk
+ * \brief   Implements HTTP _transport layer_ abstraction interface [see http_transport.h and transport_layer.h]
+ */
+
+#include "http_transport_layer.h"
+#include "http_transport.h"
+
+transport_layer_t* get_http_transport_layer( void )
+{
+    static transport_layer_t __http_transport_layer =
+    {
+          &http_encode_update_feed
+        , &http_encode_get_feed
+        , &http_encode_create_datastream
+        , &http_encode_update_datastream
+        , &http_encode_get_datastream
+        , &http_encode_delete_datastream
+        , &http_encode_delete_datapoint
+        , &http_encode_datapoint_delete_range
+        , &http_decode_reply
+    };
+
+    return &__http_transport_layer;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/http_transport.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_transport.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,35 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_transport.h
+ * \author  Olgierd Humenczuk
+ * \brief   Implements HTTP _transport layer_ abstraction interface
+ */
+
+#ifndef __HTTP_TRANSPORT_H__
+#define __HTTP_TRANSPORT_H__
+
+#include "transport_layer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /**
+ * \brief   Initialise HTTP implementation of the _transport layer_
+ *
+ *    This intialiser assigns function pointers to the actual implementations
+ *    using  static function variable trick, hence the intialisation should
+ *    not give any overhead.
+ *
+ * \return  Structure with function pointers for HTTP encoders and decoders
+ *          which had been implemented in `http_transport_layer.c`.
+ */
+transport_layer_t* get_http_transport_layer( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __HTTP_TRANSPORT_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/http_transport_layer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_transport_layer.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,432 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_transport_layer.c
+ * \author  Olgierd Humenczuk
+ * \brief   Implements HTTP _transport layer_ encoders and decoders specific to Xively REST/HTTP API [see http_transport_layer.h]
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "http_transport.h"
+#include "http_layer_queries.h"
+#include "http_consts.h"
+#include "http_layer_parser.h"
+#include "xi_macros.h"
+#include "xi_helpers.h"
+#include "xi_err.h"
+
+static char XI_HTTP_QUERY_BUFFER[ XI_QUERY_BUFFER_SIZE + XI_CONTENT_BUFFER_SIZE ];
+static char XI_HTTP_QUERY_DATA[ XI_CONTENT_BUFFER_SIZE ];
+
+
+inline static char* http_encode_concat( char* buffer, size_t buffer_size
+    , const char* query, const char* content, const char* data )
+{
+    int offset  = 0;
+    int size    = ( int ) buffer_size;
+    int s       = 0;
+
+    s = snprintf( buffer, size, "%s", query );
+    XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM );
+
+    if( content != 0 )
+    {
+        s = snprintf( buffer + offset
+                          , XI_MAX( size - offset, 0 )
+                          , "%s", content );
+        XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM );
+    }
+
+    s = snprintf( buffer + offset
+                      , XI_MAX( size - offset, 0 )
+                      , "%s", XI_HTTP_CRLF );
+    XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM );
+
+
+    if( content != 0 && data != 0 )
+    {
+        s = snprintf( buffer + offset
+                          , XI_MAX( size - offset, 0 )
+                          , "%s", data );
+        XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM );
+    }
+
+    s = snprintf( buffer + offset
+                      , XI_MAX( size - offset, 0 )
+                      , "%s", XI_HTTP_CRLF );
+
+    XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM );
+
+    return buffer;
+
+err_handling:
+    return 0;
+}
+
+const char* http_encode_create_datastream(
+          const data_layer_t* data_transport
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id
+        , const xi_datapoint_t* datapoint )
+{
+    // prepare parts
+    const char* data = data_transport->encode_create_datastream(
+        datastream_id, datapoint );
+
+    if( data == 0 ) { return 0; }
+
+    const char* query = http_construct_request_datastream(
+              XI_HTTP_QUERY_POST, &feed_id
+            , 0, x_api_key
+    );
+
+    if( query == 0 ) { return 0; }
+
+    const char* content = http_construct_content( strlen( data ) );
+
+    return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+        , query, content, data );
+}
+
+const char* http_encode_update_datastream(
+          const data_layer_t* data_layer
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id
+        , const xi_datapoint_t* datapoint )
+{
+    // prepare parts
+    const char* data = data_layer->encode_datapoint( datapoint );
+
+    if( data == 0 ) { return 0; }
+
+    const char* query = http_construct_request_datastream(
+              XI_HTTP_QUERY_PUT
+            , &feed_id
+            , datastream_id
+            , x_api_key
+    );
+
+    if( query == 0 ) { return 0; }
+
+    const char* content = http_construct_content( strlen( data ) );
+
+    return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+        , query, content, data );
+}
+
+const char* http_encode_get_datastream(
+          const data_layer_t* data_layer
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id )
+{
+    XI_UNUSED( data_layer );
+
+    // prepare parts
+    const char* query = http_construct_request_datastream(
+              XI_HTTP_QUERY_GET
+            , &feed_id
+            , datastream_id
+            , x_api_key );
+
+    if( query == 0 ) { return 0; }
+
+    return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+        , query, 0, 0 );
+}
+
+const char* http_encode_delete_datastream(
+          const data_layer_t* data_layer
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id )
+{
+    XI_UNUSED( data_layer );
+
+    // prepare parts
+    const char* query = http_construct_request_datastream(
+              XI_HTTP_QUERY_DELETE
+            , &feed_id
+            , datastream_id
+            , x_api_key );
+
+    if( query == 0 ) { return 0; }
+
+    return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+        , query, 0, 0 );
+}
+
+const char* http_encode_delete_datapoint(
+          const data_layer_t* data_transport
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id
+        , const xi_datapoint_t* o )
+{
+    XI_UNUSED( data_transport );
+
+    struct tm* ptm = xi_gmtime(
+        ( time_t* ) &o->timestamp.timestamp );
+
+    int s = snprintf( XI_HTTP_QUERY_BUFFER
+        , sizeof( XI_HTTP_QUERY_BUFFER )
+        , "%s/datapoints/%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ"
+        , datastream_id
+        , ptm->tm_year + 1900
+        , ptm->tm_mon + 1
+        , ptm->tm_mday
+        , ptm->tm_hour
+        , ptm->tm_min
+        , ptm->tm_sec
+        , o->timestamp.micro );
+
+    XI_CHECK_SIZE( s, ( int ) sizeof( XI_HTTP_QUERY_BUFFER )
+        , XI_HTTP_ENCODE_DELETE_DATAPOINT );
+
+    {
+        // prepare parts
+        const char* query = http_construct_request_datastream(
+                  XI_HTTP_QUERY_DELETE
+                , &feed_id
+                , XI_HTTP_QUERY_BUFFER
+                , x_api_key );
+
+        if( query == 0 ) { return 0; }
+
+        return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+            , query, 0, 0 );
+    }
+
+err_handling:
+    return 0;
+}
+
+const char* http_encode_update_feed(
+          const data_layer_t* data_layer
+        , const char* x_api_key
+        , const xi_feed_t* feed )
+{
+    // prepare buffer
+    XI_CLEAR_STATIC_BUFFER( XI_HTTP_QUERY_DATA );
+
+    // PRECONDITIONS
+    assert( data_layer != 0 );
+    assert( x_api_key != 0 );
+    assert( feed != 0 );
+
+    // variables initialization
+    const char* content = 0;
+    const char* query = 0;
+
+    { // data part preparation
+        int offset  = 0;
+        int size    = sizeof( XI_HTTP_QUERY_DATA );
+        int s       = 0;
+
+        // for each datastream
+        //      generate the list of datapoints that you want to update
+        for( size_t i = 0; i < feed->datastream_count; ++i )
+        {
+            const xi_datastream_t* curr_datastream = &feed->datastreams[ i ];
+
+            // for each datapoint
+            for( size_t j = 0; j < curr_datastream->datapoint_count; ++j )
+            {
+                const xi_datapoint_t* curr_datapoint
+                    = &curr_datastream->datapoints[ j ];
+
+                // add the datastream id to the buffer
+                s = snprintf(
+                      XI_HTTP_QUERY_DATA + offset, XI_MAX( size - offset, 0 ), "%s,"
+                    , curr_datastream->datastream_id );
+
+                XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_UPDATE_FEED );
+
+                // add the datapoint data to the buffer
+                s = data_layer->encode_datapoint_in_place(
+                      XI_HTTP_QUERY_DATA + offset, XI_MAX( size - offset, 0 )
+                    , curr_datapoint );
+
+                XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_UPDATE_FEED );
+            }
+        }
+    }
+
+    query = http_construct_request_feed(
+          XI_HTTP_QUERY_PUT
+        , &feed->feed_id
+        , x_api_key
+        , 0
+    );
+
+    if( query == 0 ) { goto err_handling; }
+
+    content = http_construct_content( strlen( XI_HTTP_QUERY_DATA ) );
+
+    return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+        , query, content, XI_HTTP_QUERY_DATA );
+
+err_handling:
+    return 0;
+}
+
+const char* http_encode_get_feed(
+        const data_layer_t* data_layer
+      , const char* x_api_key
+      , const xi_feed_t* feed )
+{
+    // prepare buffer
+    XI_CLEAR_STATIC_BUFFER( XI_HTTP_QUERY_DATA );
+
+    // PRECONDITIONS
+    assert( data_layer != 0 );
+    assert( x_api_key != 0 );
+    assert( feed != 0 );
+
+    // variables initialization
+    const char* query = 0;
+
+    { // data part preparation
+        int offset  = 0;
+        int size    = sizeof( XI_HTTP_QUERY_DATA );
+        int s       = 0;
+
+        // for each datastream
+        //      generate the list of datastreams that you want to get
+        for( size_t i = 0; i < feed->datastream_count; ++i )
+        {
+            const xi_datastream_t* curr_datastream = &feed->datastreams[ i ];
+
+            // add the datastream id to the buffer
+            s = snprintf(
+                  XI_HTTP_QUERY_DATA + offset, XI_MAX( size - offset, 0 ), i == 0 ? "?datastreams=%s" : ",%s"
+                , curr_datastream->datastream_id );
+
+            XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_UPDATE_FEED );
+        }
+    }
+
+    query = http_construct_request_feed(
+          XI_HTTP_QUERY_GET
+        , &feed->feed_id
+        , x_api_key
+        , XI_HTTP_QUERY_DATA
+    );
+
+    if( query == 0 ) { goto err_handling; }
+
+    return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+        , query, 0, 0 );
+
+err_handling:
+    return 0;
+}
+
+const char* http_encode_datapoint_delete_range(
+        const data_layer_t* data_layer
+      , const char* x_api_key
+      , int32_t feed_id
+      , const char* datastream_id
+      , const xi_timestamp_t* start
+      , const xi_timestamp_t* end )
+{
+    XI_UNUSED( data_layer );
+
+    struct tm stm;
+    struct tm etm;
+
+    {
+        struct tm* tmp = start ? xi_gmtime(
+            ( time_t* ) &start->timestamp ) : 0;
+        memcpy( &stm, tmp, sizeof( struct tm ) );
+    }
+
+    {
+        struct tm* tmp = end ? xi_gmtime(
+            ( time_t* ) &end->timestamp ) : 0;
+        memcpy( &etm, tmp, sizeof( struct tm ) );
+    }
+
+    int s = 0;
+
+    if( start && end )
+    {
+        s = snprintf( XI_HTTP_QUERY_BUFFER
+            , sizeof( XI_HTTP_QUERY_BUFFER )
+            , "%s/datapoints?start=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ&end=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ"
+            , datastream_id
+            , stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday
+            , stm.tm_hour, stm.tm_min, stm.tm_sec, start->micro
+            , etm.tm_year + 1900, etm.tm_mon + 1, etm.tm_mday
+            , etm.tm_hour, etm.tm_min, etm.tm_sec, end->micro );
+    }
+    else if( start )
+    {
+        s = snprintf( XI_HTTP_QUERY_BUFFER
+            , sizeof( XI_HTTP_QUERY_BUFFER )
+            , "%s/datapoints?start=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ"
+            , datastream_id
+            , stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday
+            , stm.tm_hour, stm.tm_min, stm.tm_sec, start->micro );
+    }
+    else if( end )
+    {
+        s = snprintf( XI_HTTP_QUERY_BUFFER
+            , sizeof( XI_HTTP_QUERY_BUFFER )
+            , "%s/datapoints?end=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ"
+            , datastream_id
+            , etm.tm_year + 1900, etm.tm_mon + 1, etm.tm_mday
+            , etm.tm_hour, etm.tm_min, etm.tm_sec, end->micro );
+    }
+    else
+    {
+        // just set an error
+        XI_CHECK_CND( 1 == 0, XI_HTTP_ENCODE_DELETE_RANGE_DATAPOINT );
+    }
+
+    XI_CHECK_SIZE( s, ( int ) sizeof( XI_HTTP_QUERY_BUFFER )
+        , XI_HTTP_ENCODE_DELETE_RANGE_DATAPOINT );
+
+    {
+        // prepare parts
+        const char* query = http_construct_request_datastream(
+                  XI_HTTP_QUERY_DELETE
+                , &feed_id
+                , XI_HTTP_QUERY_BUFFER
+                , x_api_key );
+
+        if( query == 0 ) { return 0; }
+
+        return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER )
+            , query, 0, 0 );
+    }
+
+err_handling:
+    return 0;
+}
+
+
+const xi_response_t* http_decode_reply(
+          const data_layer_t* data_layer
+        , const char* response )
+{
+    XI_UNUSED( data_layer );
+
+    static xi_response_t  __tmp;
+    static http_response_t* __response = &__tmp.http;
+
+    // just pass it further
+    if( parse_http( __response, response ) == 0 )
+    {
+        return 0;
+    }
+
+    // pass it to the data_layer
+    return &__tmp;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/http_transport_layer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/http_transport_layer.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,79 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    http_transport_layer.h
+ * \author  Olgierd Humenczuk
+ * \brief   Implements HTTP _transport layer_ encoders and decoders specific to Xively REST/HTTP API
+ */
+
+#ifndef __HTTP_TRANSPORT_LAYER_H__
+#define __HTTP_TRANSPORT_LAYER_H__
+
+#include "xively.h"
+#include "data_layer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char* http_encode_create_datastream(
+          const data_layer_t*
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id
+        , const xi_datapoint_t* value );
+
+const char* http_encode_update_datastream(
+          const data_layer_t*
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id
+        , const xi_datapoint_t* value );
+
+const char* http_encode_get_datastream(
+          const data_layer_t*
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id );
+
+const char* http_encode_delete_datastream(
+          const data_layer_t*
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id );
+
+const char* http_encode_delete_datapoint(
+          const data_layer_t*
+        , const char* x_api_key
+        , int32_t feed_id
+        , const char *datastream_id
+        , const xi_datapoint_t* o );
+
+const char* http_encode_update_feed(
+          const data_layer_t*
+        , const char* x_api_key
+        , const xi_feed_t* feed );
+
+const char* http_encode_get_feed(
+        const data_layer_t*
+      , const char* x_api_key
+      , const xi_feed_t* feed );
+
+const char* http_encode_datapoint_delete_range(
+        const data_layer_t*
+      , const char* x_api_key
+      , int feed_id
+      , const char* datastream_id
+      , const xi_timestamp_t* start
+      , const xi_timestamp_t* end );
+
+const xi_response_t* http_decode_reply(
+          const data_layer_t*
+        , const char* data );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __HTTP_TRANSPORT_LAYER_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/transport_layer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/transport_layer.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,82 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    transport_layer.h
+ * \author  Olgierd Humenczuk
+ * \brief   Defines _transport layer_ abstraction interface
+ */
+
+#ifndef __TRANSPORT_LAYER_H__
+#define __TRANSPORT_LAYER_H__
+
+#include "xively.h"
+#include "data_layer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief   _The transport layer interface_ - contains function pointers,
+ *          that's what we expose to the layers above and below
+ *
+ *    It is effectively a class that holds declarations of pure virtual functions.
+ *    * All functions take `data_layer_t` as the first argument.
+ *    * Most encoders convert the result from data layer to an implementation-specific representaion.
+ *
+ * \note    It depends on the implementation whether any given _transport layer_ method will call upon
+ *          the _data layer_. In `http_transport_layer.c` you can see that `http_encode_datapoint_delete_range()`
+ *          only needs to generate request headers and no body needs to be posted, neither it gets any
+ *          response body as it is doing a `DELETE` request. One should use `XI_UNUSED(data_layer)` at the
+ *          top of the function definition, that is a macro that casts the pointer to unused _data layer_ to void.
+ * \note    Similarly to the _data layer_ (see notes in `data_layer.h`), there no symmetry needed and we only have
+ *          one decoder.
+ */
+typedef struct {
+    const char* ( *encode_update_feed )(
+          const data_layer_t*, const char* api_key
+        , const xi_feed_t* feed );
+
+    const char* ( *encode_get_feed )(
+          const data_layer_t*, const char* api_key
+        , const xi_feed_t* feed );
+
+    const char* ( *encode_create_datastream )(
+          const data_layer_t*, const char* api_key, int32_t feed_id
+        , const char* datastream_id
+        , const xi_datapoint_t* dp );
+
+    const char* ( *encode_update_datastream )(
+          const data_layer_t*, const char* api_key, int32_t feed_id
+        , const char* datastream_id
+        , const xi_datapoint_t* value );
+
+    const char* ( *encode_get_datastream )(
+          const data_layer_t*, const char* api_key, int32_t feed_id
+        , const char* datastream_id );
+
+    const char* ( *encode_delete_datastream )(
+          const data_layer_t*, const char* api_key, int32_t feed_id
+        , const char* datastream_id );
+
+    const char* ( *encode_delete_datapoint )(
+          const data_layer_t*, const char* api_key, int32_t feed_id
+        , const char* datastream_id
+        , const xi_datapoint_t* datapoint );
+
+    const char* ( *encode_datapoint_delete_range )(
+          const data_layer_t*, const char* api_key, int32_t feed_id
+        , const char* datastream_id
+        , const xi_timestamp_t* start
+        , const xi_timestamp_t* end );
+
+    const xi_response_t* ( *decode_reply )(
+        const data_layer_t*, const char* data );
+} transport_layer_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __TRANSPORT_LAYER_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_allocator.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_allocator.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,21 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_allocator.c
+ * \author  Olgierd Humenczuk
+ * \brief   Our custom `alloc()` and `free()` [see xi_allocator.h]
+ */
+
+#include <stdlib.h>
+#include "xi_allocator.h"
+
+void* xi_alloc( size_t b )
+{
+    return ( void* ) malloc( b );
+}
+
+void xi_free( void* p )
+{
+    free( p );
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_allocator.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_allocator.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,38 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_allocator.h
+ * \author  Olgierd Humenczuk
+ * \brief   Our custom `alloc()` and `free()`
+ *
+ *    This is a faced built for future use when limitation of certain embedded
+ *    devices require custom memory management, e.g. pooling and leak detection.
+ */
+
+#ifndef __XI_ALLOCATOR_H__
+#define __XI_ALLOCATOR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief   Behaves like usual `malloc()`, which is supposed to allocate a chunk
+ *             of memory and return the pointer to it.
+ *
+ * \return  Pointer to allocated memory or null in case of any error.
+ */
+void* xi_alloc( size_t bytes );
+
+/**
+ * \brief   Behaves like usual `free()`, it frees previously allocated chunk of
+ *             of memory.
+ */
+void xi_free( void* pointer );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_consts.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_consts.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,82 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_consts.h
+ * \author  Olgierd Humenczuk
+ * \brief   Constants that user may wish to override based on their needs
+ *
+ * \warning The meaning of each of these constants below is undocumented,
+ *          so the user actually goes to read the source code and figure
+ *          out what exactly they are doing.
+ */
+
+#ifndef __XI_CONSTST_H__
+#define __XI_CONSTST_H__
+
+#ifndef XI_HTTP_MAX_HEADERS
+#define XI_HTTP_MAX_HEADERS                16
+#endif
+
+#ifndef XI_HTTP_STATUS_STRING_SIZE
+#define XI_HTTP_STATUS_STRING_SIZE         32
+#endif
+
+#ifndef XI_HTTP_HEADER_NAME_MAX_SIZE
+#define XI_HTTP_HEADER_NAME_MAX_SIZE       64
+#endif
+
+#ifndef XI_HTTP_HEADER_VALUE_MAX_SIZE
+#define XI_HTTP_HEADER_VALUE_MAX_SIZE      64
+#endif
+
+#ifndef XI_HTTP_MAX_CONTENT_SIZE
+#define XI_HTTP_MAX_CONTENT_SIZE           512
+#endif
+
+#ifndef XI_MAX_DATASTREAMS
+#define XI_MAX_DATASTREAMS                 16
+#endif
+
+#ifndef XI_MAX_DATAPOINTS
+#define XI_MAX_DATAPOINTS                  16
+#endif
+
+#ifndef XI_MAX_DATASTREAM_NAME
+#define XI_MAX_DATASTREAM_NAME             16
+#endif
+
+#ifndef XI_VALUE_STRING_MAX_SIZE
+#define XI_VALUE_STRING_MAX_SIZE           32
+#endif
+
+#ifndef XI_PRINTF_BUFFER_SIZE
+#define XI_PRINTF_BUFFER_SIZE              512
+#endif
+
+#ifndef XI_QUERY_BUFFER_SIZE
+#define XI_QUERY_BUFFER_SIZE               512
+#endif
+
+#ifndef XI_ID_BUFFER_SIZE
+#define XI_ID_BUFFER_SIZE                  256
+#endif
+
+#ifndef XI_CONTENT_BUFFER_SIZE
+#define XI_CONTENT_BUFFER_SIZE             256
+#endif
+
+#ifndef XI_CSV_BUFFER_SIZE
+#define XI_CSV_BUFFER_SIZE                 128
+#endif
+
+#ifndef XI_HOST
+#define XI_HOST                            "api.xively.com"
+#endif
+
+#ifndef XI_PORT
+#define XI_PORT                            80
+#endif
+
+#endif // __XI_CONSTST_H__
+#define XI_USER_AGENT "libxively-mbed/0.1.x-6eca970"
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_debug.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_debug.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,27 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_debug.h
+ * \author  Olgierd Humenczuk
+ * \brief   Macros to use for debugging (relies on `xi_printf()`)
+ */
+
+#ifndef __XI_DEBUG_H__
+#define __XI_DEBUG_H__
+
+#include "xi_printf.h"
+
+#ifdef XI_DEBUG_OUTPUT
+    #define xi_debug_log_str(...) xi_printf( "[%d@%s] - %s", __LINE__, __FILE__, __VA_ARGS__ )
+    #define xi_debug_log_data(...) xi_printf( "%s", __VA_ARGS__ )
+    #define xi_debug_log_int(...) xi_printf( "%d", __VA_ARGS__ )
+    #define xi_debug_log_endl(...) xi_printf( "\n" )
+#else
+    #define xi_debug_log_str(...)
+    #define xi_debug_log_data(...)
+    #define xi_debug_log_int(...)
+    #define xi_debug_log_endl(...)
+#endif
+
+#endif
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_err.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_err.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,61 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_err.c
+ * \author  Olgierd Humenczuk
+ * \brief   Error handling (POSIX-like) [see xi_err.h]
+ */
+
+#include "xi_err.h"
+#include "xi_macros.h"
+
+static xi_err_t xi_err = XI_NO_ERR;
+
+const char* xi_err_string[ XI_ERR_COUNT ] =
+{
+          "XI_NO_ERR"
+        , "XI_OUT_OF_MEMORY"                           // XI_OUT_OF_MEMORY
+        , "XI_HTTP_STATUS_PARSE_ERROR"                 // XI_HTTP_STATUS_PARSE_ERROR
+        , "XI_HTTP_HEADER_PARSE_ERROR"                 // XI_HTTP_HEADER_PARSE_ERROR
+        , "XI_HTTP_PARSE_ERROR"                        // XI_HTTP_PARSE_ERROR
+        , "XI_HTTP_ENCODE_CREATE_DATASTREAM"           // XI_HTTP_ENCODE_CREATE_DATASTREAM
+        , "XI_HTTP_ENCODE_UPDATE_DATASTREAM"           // XI_HTTP_ENCODE_UPDATE_DATASTREAM
+        , "XI_HTTP_ENCODE_GET_DATASTREAM"              // XI_HTTP_ENCODE_GET_DATASTREAM
+        , "XI_HTTP_ENCODE_DELETE_DATASTREAM"           // XI_HTTP_ENCODE_DELETE_DATASTREAM
+        , "XI_HTTP_ENCODE_DELETE_DATAPOINT"            // XI_HTTP_ENCODE_DELETE_DATAPOINT
+        , "XI_HTTP_ENCODE_DELETE_RANGE_DATAPOINT"      // XI_HTTP_ENCODE_DELETE_RANGE_DATAPOINT
+        , "XI_HTTP_ENCODE_UPDATE_FEED"                 // XI_HTTP_ENCODE_UPDATE_FEED
+        , "XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN"   // XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN
+        , "XI_HTTP_CONSTRUCT_CONTENT_BUFFER_OVERRUN"   // XI_HTTP_CONSTRUCT_CONTENT_BUFFER_OVERRUN
+        , "XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN"     // XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN
+        , "XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN"    // XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN
+        , "XI_CSV_DECODE_FEED_PARSER_ERROR"            // XI_CSV_DECODE_FEED_PARSER_ERROR
+        , "XI_CSV_DECODE_DATAPOINT_PARSER_ERROR"       // XI_CSV_DECODE_DATAPOINT_PARSER_ERROR
+        , "XI_CSV_TIME_CONVERTION_ERROR"               // XI_CSV_TIME_CONVERTION_ERROR
+        , "XI_SOCKET_INITIALIZATION_ERROR"             // XI_SOCKET_INITIALIZATION_ERROR
+        , "XI_SOCKET_GETHOSTBYNAME_ERROR"              // XI_SOCKET_GETHOSTBYNAME_ERROR
+        , "XI_SOCKET_CONNECTION_ERROR"                 // XI_SOCKET_CONNECTION_ERROR
+        , "XI_SOCKET_SHUTDOWN_ERROR"                   // XI_SOCKET_SHUTDOWN_ERROR
+        , "XI_SOCKET_WRITE_ERROR"                      // XI_SOCKET_WRITE_ERROR
+        , "XI_SOCKET_READ_ERROR"                       // XI_SOCKET_READ_ERROR
+        , "XI_SOCKET_CLOSE_ERROR"                      // XI_SOCKET_CLOSE_ERROR
+        , "XI_DATAPOINT_VALUE_BUFFER_OVERFLOW"         // XI_DATAPOINT_VALUE_BUFFER_OVERFLOW
+};
+
+xi_err_t xi_get_last_error()
+{
+    xi_err_t ret = xi_err;
+    xi_set_err( XI_NO_ERR );
+    return ret;
+}
+
+void xi_set_err( xi_err_t e )
+{
+    xi_err = e;
+}
+
+const char* xi_get_error_string( xi_err_t e )
+{
+    return xi_err_string[ XI_CLAMP( ( short ) e, 0, XI_ERR_COUNT - 1 ) ];
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_err.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_err.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,84 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_err.h
+ * \author  Olgierd Humenczuk
+ * \brief   Error handling (POSIX-like)
+ *
+ *     * Every function should return a value
+ *     * There are special values (usually `0` or `-1`) which indicate occurrence of an error
+ *     * User can detect and lookup errors using declarations below
+ */
+
+#ifndef __XI_ERR_H__
+#define __XI_ERR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+      XI_NO_ERR = 0
+    , XI_OUT_OF_MEMORY
+    , XI_HTTP_STATUS_PARSE_ERROR
+    , XI_HTTP_HEADER_PARSE_ERROR
+    , XI_HTTP_PARSE_ERROR
+    , XI_HTTP_ENCODE_CREATE_DATASTREAM
+    , XI_HTTP_ENCODE_UPDATE_DATASTREAM
+    , XI_HTTP_ENCODE_GET_DATASTREAM
+    , XI_HTTP_ENCODE_DELETE_DATASTREAM
+    , XI_HTTP_ENCODE_DELETE_DATAPOINT
+    , XI_HTTP_ENCODE_DELETE_RANGE_DATAPOINT
+    , XI_HTTP_ENCODE_UPDATE_FEED
+    , XI_HTTP_CONSTRUCT_REQUEST_BUFFER_OVERRUN
+    , XI_HTTP_CONSTRUCT_CONTENT_BUFFER_OVERRUN
+    , XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN
+    , XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN
+    , XI_CSV_DECODE_FEED_PARSER_ERROR
+    , XI_CSV_DECODE_DATAPOINT_PARSER_ERROR
+    , XI_CSV_TIME_CONVERTION_ERROR
+    , XI_SOCKET_INITIALIZATION_ERROR
+    , XI_SOCKET_GETHOSTBYNAME_ERROR
+    , XI_SOCKET_CONNECTION_ERROR
+    , XI_SOCKET_SHUTDOWN_ERROR
+    , XI_SOCKET_WRITE_ERROR
+    , XI_SOCKET_READ_ERROR
+    , XI_SOCKET_CLOSE_ERROR
+    , XI_DATAPOINT_VALUE_BUFFER_OVERFLOW
+    , XI_ERR_COUNT
+} xi_err_t;
+
+#define XI_MAX_ERR_STRING 64
+
+/**
+ * \brief   Error description lookup table
+ */
+extern const char* xi_err_string[ XI_ERR_COUNT ];
+
+/**
+ * \brief   Error getter for the user
+ * \return  The `xi_err_t` structure which can be converted to a string using `xi_get_error_string()` method.
+ *
+ * \warning It resets the last error value, so it's always a good idea to make a copy of it!
+ */
+extern xi_err_t xi_get_last_error( void );
+
+/**
+ * \brief   Error setter for the library itself
+ * \note    Current implementation used a global state variable (_errno_), which is not thread-safe.
+ *          If thread-safety is required, than _errno_ should be made thread-local.
+ */
+extern void xi_set_err( xi_err_t e );
+
+/**
+ * \brief   Error description string getter for a given value of `xi_err_t`
+ */
+extern const char* xi_get_error_string( xi_err_t e );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __XI_ERR_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_globals.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_globals.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,12 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_globals.c
+ * \author  Olgierd Humenczuk
+ * \brief   Global run-time settings used by the library [see xi_globals.h]
+ */
+
+#include "xi_globals.h"
+
+xi_globals_t xi_globals = { 1500 };
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_globals.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_globals.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,34 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_globals.h
+ * \author  Olgierd Humenczuk
+ * \brief   Global run-time settings used by the library
+ */
+
+#ifndef __XI_GLOBALS_H__
+#define __XI_GLOBALS_H__
+
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief  Global run-time settings structure
+ */
+typedef struct
+{
+    uint32_t network_timeout; //!< the network timeout (default: 1500 milliseconds)
+} xi_globals_t;
+
+extern xi_globals_t xi_globals; //!< global instance of `xi_globals_t`
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __XI_GLOBALS_H__
\ No newline at end of file
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_helpers.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_helpers.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,184 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+// This file also containes code from MINIX C library, which is under MINIX license
+// Copyright (c) 1987, 1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands
+
+/**
+ * \file    xi_helpers.c
+ * \author  Olgierd Humenczuk
+ * \brief   General helpers used by the library [see xi_helpers.h]
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include "xi_helpers.h"
+#include "xi_allocator.h"
+
+char* xi_str_dup( const char* s )
+{
+    // PRECONDITIONS
+    assert( s != 0 );
+
+    size_t len = strlen( s );
+    char * ret = xi_alloc( len + 1 );
+    if( ret == 0 ) { return 0; }
+    memcpy( ret, s, len + 1 );
+    return ret;
+}
+
+int xi_str_copy_untiln( char* dst, size_t dst_size, const char* src, char delim )
+{
+    // PRECONDITIONS
+    assert( dst != 0 );
+    assert( dst_size > 1 );
+    assert( src != 0 );
+
+    size_t counter = 0;
+    size_t real_size = dst_size - 1;
+
+    while( *src != delim && counter < real_size && *src != '\0' )
+    {
+        *dst++ = *src++;
+        counter++;
+    }
+
+    *dst = '\0';
+    return counter;
+}
+
+// used by the xi_mktime
+#define YEAR0               1900  /* the first year */
+#define EPOCH_YR            1970  /* EPOCH = Jan 1 1970 00:00:00 */
+#define SECS_DAY            (24L * 60L * 60L)
+#define LEAPYEAR(year)      (!((year) % 4) && (((year) % 100) || !((year) % 400)))
+#define YEARSIZE(year)      (LEAPYEAR(year) ? 366 : 365)
+#define FIRSTSUNDAY(timp)    (((timp)->tm_yday - (timp)->tm_wday + 420) % 7)
+#define FIRSTDAYOF(timp)    (((timp)->tm_wday - (timp)->tm_yday + 420) % 7)
+#define TIME_MAX            ULONG_MAX
+#define ABB_LEN             3
+
+// used by the xi_mktime
+static const int _ytab[2][12] = {
+    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+      { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
+
+time_t xi_mktime(register struct tm *timep)
+{
+    register long day, year;
+    register int tm_year;
+    int yday, month;
+    register signed long seconds;
+    int overflow;
+
+    timep->tm_min += timep->tm_sec / 60;
+    timep->tm_sec %= 60;
+    if (timep->tm_sec < 0) {
+         timep->tm_sec += 60;
+         timep->tm_min--;
+    }
+    timep->tm_hour += timep->tm_min / 60;
+    timep->tm_min = timep->tm_min % 60;
+    if (timep->tm_min < 0) {
+         timep->tm_min += 60;
+         timep->tm_hour--;
+    }
+    day = timep->tm_hour / 24;
+    timep->tm_hour= timep->tm_hour % 24;
+    if (timep->tm_hour < 0) {
+         timep->tm_hour += 24;
+         day--;
+    }
+    timep->tm_year += timep->tm_mon / 12;
+    timep->tm_mon %= 12;
+    if (timep->tm_mon < 0) {
+         timep->tm_mon += 12;
+         timep->tm_year--;
+    }
+    day += (timep->tm_mday - 1);
+    while (day < 0) {
+         if(--timep->tm_mon < 0) {
+                 timep->tm_year--;
+                 timep->tm_mon = 11;
+         }
+         day += _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon];
+    }
+    while (day >= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon]) {
+         day -= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon];
+         if (++(timep->tm_mon) == 12) {
+                 timep->tm_mon = 0;
+                 timep->tm_year++;
+         }
+    }
+    timep->tm_mday = day + 1;
+    year = EPOCH_YR;
+    if (timep->tm_year < year - YEAR0) return (time_t)-1;
+    seconds = 0;
+    day = 0;
+    overflow = 0;
+
+    /*
+     * Assume that when day becomes negative, there will certainly be overflow on seconds.
+     * The check for overflow needs not to be done for leapyears divisible by 400.
+     * The code only works when year (1970) is not a leapyear.
+     */
+    #if EPOCH_YR != 1970
+    #error EPOCH_YR != 1970
+    #endif
+
+    tm_year = timep->tm_year + YEAR0;
+
+    if (LONG_MAX / 365 < tm_year - year) overflow++;
+    day = (tm_year - year) * 365;
+    if (LONG_MAX - day < (tm_year - year) / 4 + 1) overflow++;
+    day += (tm_year - year) / 4
+         + ((tm_year % 4) && tm_year % 4 < year % 4);
+    day -= (tm_year - year) / 100
+         + ((tm_year % 100) && tm_year % 100 < year % 100);
+    day += (tm_year - year) / 400
+         + ((tm_year % 400) && tm_year % 400 < year % 400);
+
+    yday = month = 0;
+    while (month < timep->tm_mon) {
+         yday += _ytab[LEAPYEAR(tm_year)][month];
+         month++;
+    }
+    yday += (timep->tm_mday - 1);
+    if (day + yday < 0) overflow++;
+    day += yday;
+
+    timep->tm_yday = yday;
+    timep->tm_wday = (day + 4) % 7;
+
+    seconds = ( ( timep->tm_hour * 60L ) + timep->tm_min ) * 60L + timep->tm_sec;
+
+    if ( ( TIME_MAX - seconds ) / SECS_DAY < ( unsigned long ) day ) overflow++;
+    seconds += day * SECS_DAY;
+
+    if ( overflow ) return ( time_t ) - 1;
+
+    if ( ( time_t ) seconds != seconds) return ( time_t ) - 1;
+    return ( time_t ) seconds;
+}
+
+struct tm* xi_gmtime( time_t* t )
+{
+    return gmtime( t );
+}
+
+char* xi_replace_with(
+      char p, char r
+    , char* buffer
+    , size_t max_chars )
+{
+    char* c = buffer;
+
+    while( *c != '\0' && max_chars-- )
+    {
+        if( *c == p ) { *c = r; }
+        c++;
+    }
+
+    return c;
+}
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_helpers.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_helpers.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,71 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_helpers.h
+ * \author  Olgierd Humenczuk
+ * \brief   General helpers used by the library
+ */
+
+#ifndef __XI_HELPERS_H__
+#define __XI_HELPERS_H__
+
+#include <stdlib.h>
+#include <time.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \note    Needed to avoid using `strdup()` which can cause some problems with `free()`,
+ *          because of buggy `realloc()` implementations.
+ *
+ * \return  Duplicated string or null in case of memory allocation problem.
+ */
+char* xi_str_dup( const char* s );
+
+/**
+ * \brief   Copies `src` string into `dst`, but stops whenever `delim` is reached or the `dst_size` is exceeded
+ *
+ * \return  Number of copied characters or -1 if an error occurred.
+ */
+int xi_str_copy_untiln( char* dst, size_t dst_size, const char* src, char delim );
+
+/**
+ * \brief   Converts from `tm` to `time_t`
+ *
+ * \note    This code assumes that unsigned long can be converted to `time_t`.
+ *          A `time_t` should not be wider than `unsigned long`, since this
+ *          would mean that the check for overflow at the end could fail.
+ *
+ * \note    This implementation had been copied from MINIX C library.
+ *          Which is 100% compatible with our license.
+ *
+ * \note    This function does not take into account the timezone or the `dst`,
+ *          it just converts `tm` structure using date and time fields (i.e. UTC).
+ */
+time_t xi_mktime( struct tm* t );
+
+/**
+ * \brief   This just wraps system's `gmtime()`, it a facade for future use
+ */
+struct tm* xi_gmtime( time_t* t );
+
+/**
+ * \brief   Replaces `p` with `r` for every `p` in `buffer`
+ *
+ * \return  Pointer to converted buffer.
+ * \note    This function assumes that the buffer is terminated with `\0`.
+ */
+char* xi_replace_with(
+      char p, char r
+    , char* buffer
+    , size_t max_chars );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __XI_HELPERS_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_macros.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_macros.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,40 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_macros.h
+ * \author  Olgierd Humenczuk
+ * \brief   General macros used by the library
+ */
+
+#ifndef __XI_MACROS_H__
+#define __XI_MACROS_H__
+
+#include <string.h>
+
+#define XI_STR_EXPAND(tok) #tok
+#define XI_STR(tok) XI_STR_EXPAND(tok)
+#define XI_MIN(a,b) (a)<(b)?(a):(b)
+#define XI_MAX(a,b) (a)<(b)?(b):(a)
+#define XI_UNUSED(x) (void)(x)
+
+#define XI_GUARD_EOS(s,size) { (s)[ (size) - 1 ] = '\0'; }
+
+#define XI_CLAMP(a,b,t) XI_MIN( XI_MAX( (a), (b) ), (t) )
+
+#define XI_CHECK_CND(cnd,e) if( (cnd) ) { xi_set_err( (e) ); goto err_handling; }
+#define XI_CHECK_ZERO(a,e) XI_CHECK_CND((a) == 0,(e))
+#define XI_CHECK_NEG(a) if( (a) < 0 ) )
+#define XI_CHECK_PTR(a,b) if( (a) == (b) )
+#define XI_SAFE_FREE(a) if( (a) ) { xi_free(a); (a) = 0; }
+#define XI_CHECK_MEMORY(a) XI_CHECK_CND((a) == 0,XI_OUT_OF_MEMORY)
+#define XI_CHECK_SIZE(a,b,e) XI_CHECK_CND(((a) >= (b) || (a) < 0 ),e)
+#define XI_CLEAR_STATIC_BUFFER(a) memset( (a), 0, sizeof(a) )
+#define XI_CHECK_S(s,size,o,e) {\
+    XI_CHECK_SIZE(s,size-o,e)\
+    else\
+    {\
+        (o) += (s);\
+    }}
+
+#endif //__XI_MACROS_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_printf.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_printf.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,47 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_printf.c
+ * \author  Olgierd Humenczuk
+ * \brief   Our custom `printf()` hook [see xi_printf.h]
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "xi_printf.h"
+#include "xi_consts.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+user_print_t USER_PRINT = 0;
+
+int xi_printf( const char *fmt, ... )
+{
+    char buffer[ XI_PRINTF_BUFFER_SIZE ];
+    int n = 0;
+
+    va_list ap;
+    va_start( ap, fmt );
+    vsnprintf( buffer, XI_PRINTF_BUFFER_SIZE, fmt, ap );
+    va_end( ap );
+
+
+    if( USER_PRINT )
+    {
+        USER_PRINT( buffer );
+    }
+    else
+    {
+        printf( "%s", buffer );
+    }
+
+    return n;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff -r 000000000000 -r 82702e998d3f src/libxively/xi_printf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xi_printf.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,33 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xi_printf.h
+ * \author  Olgierd Humenczuk
+ * \brief   Our custom `printf()` hook
+ *
+ *    This is needed on embedded devices, as there is no way to redirect
+ *    the output neither it has any logging facilities out of the box.
+ *    We currently use a function pointer (`user_print_t`) and and the
+ *    user can assign to an external variable (`USER_PRINTF`) to call
+ *    whatever device platform may have available.
+ */
+
+#ifndef __XI_PRINTF_H__
+#define __XI_PRINTF_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void ( *user_print_t )( const char* );
+
+extern user_print_t USER_PRINT;
+
+int xi_printf( const char *fmt, ... );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__XI_PRINTF_H__
diff -r 000000000000 -r 82702e998d3f src/libxively/xively.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xively.c	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,367 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xively.c
+ * \brief   Xively C library [see xively.h]
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "xi_allocator.h"
+#include "xively.h"
+#include "http_transport.h"
+#include "csv_data_layer.h"
+#include "xi_macros.h"
+#include "xi_debug.h"
+#include "xi_helpers.h"
+#include "xi_err.h"
+#include "xi_globals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief   Get instance of _communication layer_
+ *
+ * \note    Although the interface is of the _communication layer_ should
+ *          stay the same, some implemantation may differ.
+ *
+ * \return  Pointer to the communication layer interface
+ */
+const comm_layer_t* get_comm_layer( void );
+
+#include "comm_layer.h"
+
+//-----------------------------------------------------------------------
+// HELPER MACROS
+//-----------------------------------------------------------------------
+
+#define XI_FUNCTION_VARIABLES connection_t* conn = 0;\
+    const comm_layer_t* comm_layer = 0;\
+    const transport_layer_t* transport_layer = 0;\
+    const data_layer_t* data_layer = 0;\
+    char  buffer[ XI_HTTP_MAX_CONTENT_SIZE ];\
+    const xi_response_t* response = 0;\
+    int sent = 0;\
+    int recv = 0;
+
+#define XI_FUNCTION_PROLOGUE  XI_FUNCTION_VARIABLES\
+    xi_debug_log_str( "Getting the comm layer...\n" );\
+    comm_layer = get_comm_layer();\
+    xi_debug_log_str( "Getting the transport layer...\n" );\
+    transport_layer = get_http_transport_layer();\
+    xi_debug_log_str( "Getting the data layer...\n");\
+    data_layer = get_csv_data_layer();\
+
+#define XI_FUNCTION_GET_RESPONSE if( data == 0 ) { goto err_handling; }\
+    xi_debug_log_str( "Connecting to the endpoint...\n" );\
+    conn = comm_layer->open_connection( XI_HOST, XI_PORT );\
+    if( conn == 0 ) { goto err_handling; }\
+    xi_debug_log_str( "Sending data:\n" );\
+    xi_debug_log_data( data );\
+    sent = comm_layer->send_data( conn, data, strlen( data ) );\
+    if( sent == -1 ) { goto err_handling; }\
+    xi_debug_log_str( "Sent: " );\
+    xi_debug_log_int( ( int ) sent );\
+    xi_debug_log_endl();\
+    xi_debug_log_str( "Reading data...\n" );\
+    recv = comm_layer->read_data( conn, buffer, XI_HTTP_MAX_CONTENT_SIZE );\
+    if( recv == -1 ) { goto err_handling; }\
+    xi_debug_log_str( "Received: " );\
+    xi_debug_log_int( ( int ) recv );\
+    xi_debug_log_endl();\
+    xi_debug_log_str( "Response:\n" );\
+    xi_debug_log_data( buffer );\
+    xi_debug_log_endl();\
+    response = transport_layer->decode_reply(\
+        data_layer, buffer );\
+    if( response == 0 ) { goto err_handling; }\
+
+#define XI_FUNCTION_EPILOGUE xi_debug_log_str( "Closing connection...\n" );\
+err_handling:\
+    if( conn )\
+    {\
+        comm_layer->close_connection( conn );\
+    }\
+    return response;\
+
+//-----------------------------------------------------------------------
+// HELPER FUNCTIONS
+//-----------------------------------------------------------------------
+
+xi_datapoint_t* xi_set_value_i32( xi_datapoint_t* p, int32_t value )
+{
+    // PRECONDITION
+    assert( p != 0 );
+
+    p->value.i32_value  = value;
+    p->value_type       = XI_VALUE_TYPE_I32;
+
+    return p;
+}
+
+xi_datapoint_t* xi_set_value_f32( xi_datapoint_t* p, float value )
+{
+    // PRECONDITION
+    assert( p != 0 );
+
+    p->value.f32_value  = value;
+    p->value_type       = XI_VALUE_TYPE_F32;
+
+    return p;
+}
+
+xi_datapoint_t* xi_set_value_str( xi_datapoint_t* p, const char* value )
+{
+    // PRECONDITION
+    assert( p != 0 );
+
+    int s = xi_str_copy_untiln( p->value.str_value
+        , XI_VALUE_STRING_MAX_SIZE, value, '\0' );
+
+    XI_CHECK_SIZE( s, XI_VALUE_STRING_MAX_SIZE, XI_DATAPOINT_VALUE_BUFFER_OVERFLOW );
+
+    p->value_type = XI_VALUE_TYPE_STR;
+
+    return p;
+
+err_handling:
+    return 0;
+}
+
+void xi_set_network_timeout( uint32_t timeout )
+{
+    xi_globals.network_timeout = timeout;
+}
+
+uint32_t xi_get_network_timeout( void )
+{
+    return xi_globals.network_timeout;
+}
+
+//-----------------------------------------------------------------------
+// MAIN LIBRARY FUNCTIONS
+//-----------------------------------------------------------------------
+
+xi_context_t* xi_create_context(
+      xi_protocol_t protocol, const char* api_key
+    , int32_t feed_id )
+{
+    // allocate the structure to store new context
+    xi_context_t* ret = ( xi_context_t* ) xi_alloc( sizeof( xi_context_t ) );
+
+    XI_CHECK_MEMORY( ret );
+
+    // copy given numeric parameters as is
+    ret->protocol       = protocol;
+    ret->feed_id        = feed_id;
+
+    // copy string parameters carefully
+    if( api_key )
+    {
+        // duplicate the string
+        ret->api_key  = xi_str_dup( api_key );
+
+        XI_CHECK_MEMORY( ret->api_key );
+    }
+    else
+    {
+        ret->api_key  = 0;
+    }
+
+    return ret;
+
+err_handling:
+    if( ret )
+    {
+        XI_SAFE_FREE( ret );
+    }
+
+    return 0;
+}
+
+void xi_delete_context( xi_context_t* context )
+{
+    if( context )
+    {
+        XI_SAFE_FREE( context->api_key );
+    }
+    XI_SAFE_FREE( context );
+}
+
+const xi_response_t* xi_feed_get(
+          xi_context_t* xi
+        , xi_feed_t* feed )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_get_feed(
+              data_layer
+            , xi->api_key
+            , feed );
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+
+    feed = data_layer->decode_feed( response->http.http_content, feed );
+    if( feed == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_EPILOGUE
+}
+
+const xi_response_t* xi_feed_update(
+          xi_context_t* xi
+        , const xi_feed_t* feed )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_update_feed(
+              data_layer
+            , xi->api_key
+            , feed );
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+
+    XI_FUNCTION_EPILOGUE
+}
+
+const xi_response_t* xi_datastream_get(
+            xi_context_t* xi, int32_t feed_id
+          , const char * datastream_id, xi_datapoint_t* o )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_get_datastream(
+              data_layer
+            , xi->api_key
+            , feed_id
+            , datastream_id );
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+
+    o = data_layer->decode_datapoint(
+        response->http.http_content, o );
+
+    if( o == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_EPILOGUE
+}
+
+
+const xi_response_t* xi_datastream_create(
+            xi_context_t* xi, int32_t feed_id
+          , const char * datastream_id
+          , const xi_datapoint_t* datapoint )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_create_datastream(
+              data_layer
+            , xi->api_key
+            , feed_id
+            , datastream_id
+            , datapoint );
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+    XI_FUNCTION_EPILOGUE
+}
+
+const xi_response_t* xi_datastream_update(
+          xi_context_t* xi, int32_t feed_id
+        , const char * datastream_id
+        , const xi_datapoint_t* datapoint )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_update_datastream(
+              data_layer
+            , xi->api_key
+            , feed_id
+            , datastream_id
+            , datapoint );
+
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+
+
+    XI_FUNCTION_EPILOGUE
+}
+const xi_response_t* xi_datastream_delete(
+            xi_context_t* xi, int32_t feed_id
+          , const char * datastream_id )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_delete_datastream(
+              data_layer
+            , xi->api_key
+            , feed_id
+            , datastream_id );
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+
+    XI_FUNCTION_EPILOGUE
+}
+
+const xi_response_t* xi_datapoint_delete(
+          const xi_context_t* xi, int feed_id
+        , const char * datastream_id
+        , const xi_datapoint_t* o )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_delete_datapoint(
+              data_layer
+            , xi->api_key
+            , feed_id
+            , datastream_id
+            , o );
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+    XI_FUNCTION_EPILOGUE
+}
+
+extern const xi_response_t* xi_datapoint_delete_range(
+            const xi_context_t* xi, int feed_id
+          , const char * datastream_id
+          , const xi_timestamp_t* start
+          , const xi_timestamp_t* end )
+{
+    XI_FUNCTION_PROLOGUE
+
+    const char* data = transport_layer->encode_datapoint_delete_range(
+              data_layer
+            , xi->api_key
+            , feed_id
+            , datastream_id
+            , start
+            , end );
+
+    if( data == 0 ) { goto err_handling; }
+
+    XI_FUNCTION_GET_RESPONSE
+    XI_FUNCTION_EPILOGUE
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff -r 000000000000 -r 82702e998d3f src/libxively/xively.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libxively/xively.h	Wed Jun 26 10:40:43 2013 +0000
@@ -0,0 +1,307 @@
+// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
+// This is part of Xively C library, it is under the BSD 3-Clause license.
+
+/**
+ * \file    xively.h
+ * \brief   Xively C library
+ */
+
+#ifndef __XI_H__
+#define __XI_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <time.h>
+
+#include "comm_layer.h"
+#include "xi_consts.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------
+// TYPES AND STRUCTURES
+//-----------------------------------------------------------------------
+
+/**
+ * \brief    The protocols currently supported by Xively
+ * \note     See source code for details of what's implemented.
+ */
+typedef enum {
+    /** `http://api.xively.com` */
+    XI_HTTP,
+    /** `https://api.xively.com` */
+    XI_HTTPS,
+    /** `telnet api.xively.com 8081` */
+    XI_TCP,
+    /** `openssl s_client -host api.xively.com -port 8091 -tls1` */
+    XI_TCPS,
+    /** `ws://api.xively.com:8080` */
+    XI_WS,
+    /** `wss://api.xively.com:8090` */
+    XI_WSS,
+} xi_protocol_t;
+
+/**
+ * \brief   _The context structure_ - it's the first agument for all functions
+ *          that communicate with Xively API (_i.e. not helpers or utilities_)
+ */
+typedef struct {
+    char *api_key; /** Xively API key */
+    xi_protocol_t protocol; /** Xively protocol */
+    int32_t feed_id; /** Xively feed ID */
+} xi_context_t;
+
+/**
+ * \brief HTTP headers
+ */
+typedef enum
+{
+    /** `Date` */
+    XI_HTTP_HEADER_DATE = 0,
+    /** `Content-Type` */
+    XI_HTTP_HEADER_CONTENT_TYPE,
+    /** `Content-Length` */
+    XI_HTTP_HEADER_CONTENT_LENGTH,
+    /** `Connection` */
+    XI_HTTP_HEADER_CONNECTION,
+    /** `X-Request-Id` */
+    XI_HTTP_HEADER_X_REQUEST_ID,
+    /** `Cache-Control` */
+    XI_HTTP_HEADER_CACHE_CONTROL,
+    /** `Vary` */
+    XI_HTTP_HEADER_VARY,
+    /** `Count` */
+    XI_HTTP_HEADER_COUNT,
+    /** `Age` */
+    XI_HTTP_HEADER_AGE,
+    // must go before the last here
+    XI_HTTP_HEADER_UNKNOWN,
+    // must be the last here
+    XI_HTTP_HEADERS_COUNT
+} http_header_type_t;
+
+/** Datapoint value types */
+typedef enum
+{   /** 32-bit signed integer */
+    XI_VALUE_TYPE_I32 = 0,
+    /** 32-bit floating point number */
+    XI_VALUE_TYPE_F32,
+    /** any string-econded data */
+    XI_VALUE_TYPE_STR,
+    XI_VALUE_TYPE_COUNT
+} xi_value_type_t;
+
+typedef struct {
+    http_header_type_t  header_type;
+    char                name[ XI_HTTP_HEADER_NAME_MAX_SIZE ];
+    char                value[ XI_HTTP_HEADER_VALUE_MAX_SIZE ];
+} http_header_t;
+
+typedef struct {
+    int             http_version1;
+    int             http_version2;
+    int             http_status;
+    char            http_status_string[ XI_HTTP_STATUS_STRING_SIZE ];
+    http_header_t*  http_headers_checklist[ XI_HTTP_HEADERS_COUNT ];
+    http_header_t   http_headers[ XI_HTTP_MAX_HEADERS ];
+    size_t          http_headers_size;
+    char            http_content[ XI_HTTP_MAX_CONTENT_SIZE ];
+} http_response_t;
+
+/**
+ * \brief   _The response structure_ - it's the return type for all functions
+ *          that communicate with Xively API (_i.e. not helpers or utilities_)
+ */
+typedef struct {
+    http_response_t http;
+} xi_response_t;
+
+/**
+ * \brief   The datapoint value union
+ */
+typedef union {
+    int32_t i32_value;
+    float   f32_value;
+    char    str_value[ XI_VALUE_STRING_MAX_SIZE ];
+} xi_datapoint_value_t;
+
+/**
+ * \brief   The datapoint timestamp
+ */
+typedef struct {
+    time_t timestamp;
+    time_t micro;
+} xi_timestamp_t;
+
+/**
+ * \brief   _Xively datapoint structure_ - it contains value and timestamp
+ * \note    A zero-valued timestamp is used by most functions as a convention
+ *          to opt for server-side timestamps.
+ */
+typedef struct {
+    xi_datapoint_value_t  value;
+    xi_value_type_t       value_type;
+    xi_timestamp_t        timestamp;
+} xi_datapoint_t;
+
+typedef struct {
+    char              datastream_id[ XI_MAX_DATASTREAM_NAME ];
+    size_t            datapoint_count;
+    xi_datapoint_t    datapoints[ XI_MAX_DATAPOINTS ];
+} xi_datastream_t;
+
+/**
+ * \brief   _Xively feed structure_ - it contains a fixed array of datastream
+ * \note    The implementation is such that user will need to know in advance
+ *          how many datastreams there can be, which should be sufficent for
+ *          a real-world application. It's also undesired to have some devices
+ *          create dozens of datastreams due to a bug.
+ */
+typedef struct {
+    int32_t           feed_id;
+    size_t            datastream_count;
+    xi_datastream_t   datastreams[ XI_MAX_DATASTREAMS ];
+} xi_feed_t;
+
+//-----------------------------------------------------------------------
+// HELPER FUNCTIONS
+//-----------------------------------------------------------------------
+
+/**
+ * \brief   Sets the xi_datapoint_t value field to `int32_t` value
+ *
+ * \return  Pointer or `0` if an error occurred.
+ */
+extern xi_datapoint_t* xi_set_value_i32( xi_datapoint_t* dp, int32_t v );
+
+/**
+ * \brief   Sets the `xi_datapoint_t` value field to `float` value
+ * \return  Pointer or `0` if an error occurred.
+ */
+extern xi_datapoint_t* xi_set_value_f32( xi_datapoint_t* dp, float v );
+
+/**
+ * \brief   Sets the `xi_datapoint_t` value field to zero-terminated string value
+ *
+ * \return  Pointer or `0` if an error occurred.
+ */
+extern xi_datapoint_t* xi_set_value_str( xi_datapoint_t* dp, const char* v );
+
+/**
+ * \brief   Sets the timeout for network operations
+ *
+ * \note    The timeout is used by the comunication layer
+ *          to determine whenever it should treat the lag
+ *          in a connection as an error, so if your device
+ *          or your connection is slow, you can try to increase
+ *          the timeout for network operations. It only affects the
+ *          send/recv operations it does not work with connect but that
+ *          behaviour may differ between platforms and communication
+ *          layer imlementations.
+ */
+extern void xi_set_network_timeout( uint32_t milliseconds );
+
+/**
+ * \brief   Gets the current network timeout
+ */
+extern uint32_t xi_get_network_timeout( void );
+
+//-----------------------------------------------------------------------
+// MAIN LIBRARY FUNCTIONS
+//-----------------------------------------------------------------------
+
+/**
+ * \brief   Library context constructor
+ *
+ *   The purpose of this function is to allocate memory and initialise the
+ *   data structures needed in order to use any other library functions.
+ *
+ * \return  Initialised context structure or `0` if an error occurred
+ */
+extern xi_context_t* xi_create_context(
+          xi_protocol_t protocol, const char* api_key
+        , int32_t feed_id );
+
+/**
+ * \brief   Library context destructor
+ *
+ *   The purpose of this fucntion is to free all allocated resources
+ *   when the application is intending to terminate or stop using the library.
+ */
+extern void xi_delete_context( xi_context_t* context );
+
+
+/**
+ * \brief   Update Xively feed
+ */
+extern const xi_response_t* xi_feed_update(
+          xi_context_t* xi
+        , const xi_feed_t* value );
+
+/**
+ * \brief   Retrieve Xively feed
+ */
+extern const xi_response_t* xi_feed_get(
+          xi_context_t* xi
+        , xi_feed_t* value );
+
+/**
+ * \brief   Create a datastream with given value using server timestamp
+ */
+extern const xi_response_t* xi_datastream_create(
+          xi_context_t* xi, int32_t feed_id
+        , const char * datastream_id
+        , const xi_datapoint_t* value);
+
+/**
+ * \brief   Update a datastream with given datapoint using server or local timestamp
+ */
+extern const xi_response_t* xi_datastream_update(
+          xi_context_t* xi, int32_t feed_id
+        , const char * datastream_id
+        , const xi_datapoint_t* value );
+
+/**
+ * \brief   Retrieve latest datapoint from a given datastream
+ */
+extern const xi_response_t* xi_datastream_get(
+          xi_context_t* xi, int32_t feed_id
+        , const char * datastream_id, xi_datapoint_t* dp );
+
+/**
+ * \brief   Delete datastream
+ * \warning This function destroys the data in Xively and there is no way to restore it!
+ */
+extern const xi_response_t* xi_datastream_delete(
+          xi_context_t* xi, int feed_id
+          , const char* datastream_id );
+
+/**
+ * \brief   Delete datapoint at a given timestamp
+ * \warning This function destroys the data in Xively and there is no way to restore it!
+ * \note    You need to provide exact timestamp value to guarantee successful response
+ *          from the API, i.e. it will respond with error 404 if datapoint didn't exist.
+ *          If you need to determine the exact timestamp, it may be easier to call
+ *          `xi_datapoint_delete_range()` with short range instead.
+ */
+extern const xi_response_t* xi_datapoint_delete(
+          const xi_context_t* xi, int feed_id
+        , const char * datastream_id
+        , const xi_datapoint_t* dp );
+
+/**
+ * \brief   Delete all datapoints in given time range
+ * \warning This function destroys the data in Xively and there is no way to restore it!
+ */
+extern const xi_response_t* xi_datapoint_delete_range(
+          const xi_context_t* xi, int feed_id, const char * datastream_id
+        , const xi_timestamp_t* start, const xi_timestamp_t* end );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __XI_H__