AlbaniGang / Mbed 2 deprecated Rome_P3

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
stollpa1
Date:
Wed Apr 08 09:13:33 2020 +0000
Parent:
0:0a667cdbf4c1
Commit message:
P4 init;

Changed in this revision

HTTPScript.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPScript.h Show annotated file Show diff for this revision Revisions of this file
HTTPScriptIMU.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPScriptIMU.h Show annotated file Show diff for this revision Revisions of this file
HTTPServer.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPServer.h Show annotated file Show diff for this revision Revisions of this file
IMU.cpp Show annotated file Show diff for this revision Revisions of this file
IMU.h Show annotated file Show diff for this revision Revisions of this file
Main.cpp Show annotated file Show diff for this revision Revisions of this file
ThreadFlag.cpp Show annotated file Show diff for this revision Revisions of this file
ThreadFlag.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPScript.cpp	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,29 @@
+/*
+ * HTTPScript.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include "HTTPScript.h"
+
+using namespace std;
+
+HTTPScript::HTTPScript() {}
+
+HTTPScript::~HTTPScript() {}
+
+/**
+ * This method must be implemented by derived classes.
+ * It gets called by the http server, when an object of this class is
+ * registered with the server, and the corresponding script is called
+ * by an http client.
+ * @param names a vector of the names of arguments passed to the server by
+ * the client with a URL.
+ * @param values a vector of the corresponding values of arguments passed
+ * to the server.
+ */
+string HTTPScript::call(vector<string> names, vector<string> values) {
+    
+    return "";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPScript.h	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,28 @@
+/*
+ * HTTPScript.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef HTTP_SCRIPT_H_
+#define HTTP_SCRIPT_H_
+
+#include <string>
+#include <vector>
+
+/**
+ * This is the abstract http script superclass that needs to be derived
+ * by application specific http scripts.
+ * @see HTTPServer
+ */
+class HTTPScript {
+    
+    public:
+        
+                            HTTPScript();
+        virtual             ~HTTPScript();
+        virtual std::string call(std::vector<std::string> names, std::vector<std::string> values);
+};
+
+#endif /* HTTP_SCRIPT_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPScriptIMU.cpp	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,56 @@
+/*
+ * HTTPScriptIMU.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include "HTTPScriptIMU.h"
+
+using namespace std;
+
+inline string float2String(float f) {
+    
+    char buffer[32];
+    sprintf(buffer, "%.3f", f);
+    
+    return string(buffer);
+}
+
+/**
+ * Create and initialize this http script.
+ * @param imu a reference to the imu to read data from.
+ */
+HTTPScriptIMU::HTTPScriptIMU(IMU& imu) : imu(imu) {}
+
+HTTPScriptIMU::~HTTPScriptIMU() {}
+
+/**
+ * This method gets called by the http server, when an object of this class is
+ * registered with the server, and the corresponding script is called
+ * by an http client.
+ */
+string HTTPScriptIMU::call(vector<string> names, vector<string> values) {
+    
+    string response;
+    
+    response += "  <imu>\r\n";
+    response += "    <acceleration>\r\n";
+    response += "      <x><float>"+float2String(imu.readAccelerationX())+"</float></x>\r\n";
+    response += "      <y><float>"+float2String(imu.readAccelerationY())+"</float></y>\r\n";
+    response += "      <z><float>"+float2String(imu.readAccelerationZ())+"</float></z>\r\n";
+    response += "    </acceleration>\r\n";
+    response += "    <gyro>\r\n";
+    response += "      <x><float>"+float2String(imu.readGyroX())+"</float></x>\r\n";
+    response += "      <y><float>"+float2String(imu.readGyroY())+"</float></y>\r\n";
+    response += "      <z><float>"+float2String(imu.readGyroZ())+"</float></z>\r\n";
+    response += "    </gyro>\r\n";
+    response += "    <magnetometer>\r\n";
+    response += "      <x><float>"+float2String(imu.readMagnetometerX())+"</float></x>\r\n";
+    response += "      <y><float>"+float2String(imu.readMagnetometerY())+"</float></y>\r\n";
+    response += "      <z><float>"+float2String(imu.readMagnetometerZ())+"</float></z>\r\n";
+    response += "    </magnetometer>\r\n";
+    response += "  </imu>\r\n";
+    
+    return response;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPScriptIMU.h	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,33 @@
+/*
+ * HTTPScriptIMU.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef HTTP_SCRIPT_IMU_H_
+#define HTTP_SCRIPT_IMU_H_
+
+#include <string>
+#include <vector>
+#include "HTTPScript.h"
+#include "IMU.h"
+
+/**
+ * This is a specific http script to read sensor data from an imu.
+ * @see HTTPServer
+ */
+class HTTPScriptIMU : public HTTPScript {
+    
+    public:
+        
+                            HTTPScriptIMU(IMU& imu);
+        virtual             ~HTTPScriptIMU();
+        virtual std::string call(std::vector<std::string> names, std::vector<std::string> values);
+        
+    private:
+        
+        IMU&    imu;
+};
+
+#endif /* HTTP_SCRIPT_IMU_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer.cpp	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,433 @@
+/*
+ * HTTPServer.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include <algorithm>
+#include "HTTPScript.h"
+#include "HTTPServer.h"
+
+using namespace std;
+
+inline string int2String(int i) {
+    
+    char buffer[32];
+    sprintf(buffer, "%d", i);
+    
+    return string(buffer);
+}
+
+const unsigned int HTTPServer::INPUT_BUFFER_SIZE = 1024;    // size of receive buffer, given in [bytes]
+const int HTTPServer::SOCKET_TIMEOUT = 1000;                // timeout of socket, given in [ms]
+
+/**
+ * Create and initialize an http server object.
+ * @param ethernet a reference to the embedded TCP/IP stack to use.
+ */
+HTTPServer::HTTPServer(EthernetInterface& ethernet) : ethernet(ethernet), thread(osPriorityNormal, STACK_SIZE) {
+    
+    // start thread
+    
+    thread.start(callback(this, &HTTPServer::run));
+}
+
+/**
+ * Delete the http server object.
+ */
+HTTPServer::~HTTPServer() {}
+
+/**
+ * Registers the given script with the http server.
+ * This allows to call a method of this script object
+ * through virtual cgi-bin requests from a remote system.
+ */
+void HTTPServer::add(string name, HTTPScript* httpScript) {
+    
+    httpScriptNames.push_back(name);
+    httpScripts.push_back(httpScript);
+}
+
+/**
+ * Decodes a given URL string into a standard text string.
+ */
+string HTTPServer::urlDecoder(string url) {
+    
+    size_t pos = 0;
+    while ((pos = url.find("+")) != string::npos) url = url.substr(0, pos)+" "+url.substr(pos+1);
+    while ((pos = url.find("%08")) != string::npos) url = url.substr(0, pos)+"\b"+url.substr(pos+3);
+    while ((pos = url.find("%09")) != string::npos) url = url.substr(0, pos)+"\t"+url.substr(pos+3);
+    while ((pos = url.find("%0A")) != string::npos) url = url.substr(0, pos)+"\n"+url.substr(pos+3);
+    while ((pos = url.find("%0D")) != string::npos) url = url.substr(0, pos)+"\r"+url.substr(pos+3);
+    while ((pos = url.find("%20")) != string::npos) url = url.substr(0, pos)+" "+url.substr(pos+3);
+    while ((pos = url.find("%22")) != string::npos) url = url.substr(0, pos)+"\""+url.substr(pos+3);
+    while ((pos = url.find("%23")) != string::npos) url = url.substr(0, pos)+"#"+url.substr(pos+3);
+    while ((pos = url.find("%24")) != string::npos) url = url.substr(0, pos)+"$"+url.substr(pos+3);
+    while ((pos = url.find("%25")) != string::npos) url = url.substr(0, pos)+"%"+url.substr(pos+3);
+    while ((pos = url.find("%26")) != string::npos) url = url.substr(0, pos)+"&"+url.substr(pos+3);
+    while ((pos = url.find("%2B")) != string::npos) url = url.substr(0, pos)+"+"+url.substr(pos+3);
+    while ((pos = url.find("%2C")) != string::npos) url = url.substr(0, pos)+","+url.substr(pos+3);
+    while ((pos = url.find("%2F")) != string::npos) url = url.substr(0, pos)+"/"+url.substr(pos+3);
+    while ((pos = url.find("%3A")) != string::npos) url = url.substr(0, pos)+":"+url.substr(pos+3);
+    while ((pos = url.find("%3B")) != string::npos) url = url.substr(0, pos)+";"+url.substr(pos+3);
+    while ((pos = url.find("%3C")) != string::npos) url = url.substr(0, pos)+"<"+url.substr(pos+3);
+    while ((pos = url.find("%3D")) != string::npos) url = url.substr(0, pos)+"="+url.substr(pos+3);
+    while ((pos = url.find("%3E")) != string::npos) url = url.substr(0, pos)+">"+url.substr(pos+3);
+    while ((pos = url.find("%3F")) != string::npos) url = url.substr(0, pos)+"?"+url.substr(pos+3);
+    while ((pos = url.find("%40")) != string::npos) url = url.substr(0, pos)+"@"+url.substr(pos+3);
+    
+    return url;
+}
+
+/**
+ * This <code>run()</code> method binds the TCP/IP server to a given port number
+ * and enters an infinite loop that waits for http requests and then processes
+ * these requests and returns a response.
+ */
+void HTTPServer::run() {
+    
+    // bind the server to a given port number
+    
+    server.open(&ethernet);
+    server.bind(PORT_NUMBER);
+    server.listen();
+    
+    // enter infinite loop
+    
+    while (true) {
+        
+        TCPSocket* client = server.accept();
+        if (client != NULL) {
+            
+            client->set_blocking(true);
+            client->set_timeout(SOCKET_TIMEOUT); // set timeout of socket
+            
+            // read input
+            
+            char buffer[INPUT_BUFFER_SIZE];
+            int size = client->recv(buffer, sizeof(buffer));
+            
+            if (size > 0) {
+                
+                string input(buffer, size);
+                string header;
+                string output;
+                
+                // parse input
+                
+                if ((input.find("GET") == 0) || (input.find("HEAD") == 0)) {
+                    
+                    if (input.find("cgi-bin") != string::npos) {
+                        
+                        // process script request with arguments
+                        
+                        string script = input.substr(input.find("cgi-bin/")+8, input.find(" ", input.find("cgi-bin/")+8)-input.find("cgi-bin/")-8);
+                        string name;
+                        vector<string> names;
+                        vector<string> values;
+                        
+                        if (script.find("?") != string::npos) {
+                            
+                            name = script.substr(0, script.find("?"));
+                            script = script.substr(script.find("?")+1);
+                            
+                            vector<string> arguments;
+                            while (script.find("&") != string::npos) {
+                                arguments.push_back(script.substr(0, script.find("&")));
+                                script = script.substr(script.find("&")+1);
+                            }
+                            arguments.push_back(script);
+                            
+                            for (int i = 0; i < arguments.size(); i++) {
+                                
+                                if (arguments[i].find("=") != string::npos) {
+                                    
+                                    names.push_back(arguments[i].substr(0, arguments[i].find("=")));
+                                    values.push_back(urlDecoder(arguments[i].substr(arguments[i].find("=")+1)));
+                                    
+                                } else {
+                                    
+                                    names.push_back(arguments[i]);
+                                    values.push_back("");
+                                }
+                            }
+                            
+                        } else {
+                            
+                            name = script;
+                        }
+                        
+                        // look for corresponding script
+                        
+                        for (int i = 0; i < min(httpScriptNames.size(), httpScripts.size()); i++) {
+                            
+                            if (httpScriptNames[i].compare(name) == 0) {
+                                
+                                output  = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
+                                output += "<!DOCTYPE html>\r\n";
+                                output += "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\r\n";
+                                output += "<body>\r\n";
+                                output += httpScripts[i]->call(names, values);
+                                output += "</body>\r\n";
+                                output += "</html>\r\n";
+                                
+                                header  = "HTTP/1.1 200 OK\r\n";
+                                header += "Content-Length: "+int2String(output.size())+"\r\n";
+                                header += "Content-Type: text/xml\r\n";
+                                header += "Expires: 0\r\n";
+                                header += "\r\n";
+                                
+                                output = header+output;
+                            }
+                        }
+                        
+                        // requested script was not found on this server
+                        
+                        if ((output).size() == 0) {
+                            
+                            output  = "<!DOCTYPE html>\r\n";
+                            output += "<html lang=\"en\">\r\n";
+                            output += "<head>\r\n";
+                            output += "  <title>404 Not Found</title>\r\n";
+                            output += "  <style type=\"text/css\">\r\n";
+                            output += "    h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n";
+                            output += "    p {font-family:Helvetica,Arial,sans-serif; font-size: 14; color:#444444;}\r\n";
+                            output += "  </style>\r\n";
+                            output += "</head>\r\n";
+                            output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n";
+                            output += "  <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"0\" cellpadding=\"20\">\r\n";
+                            output += "    <tr>\r\n";
+                            output += "      <th width=\"100%\" height=\"30\" bgcolor=\"#0064A6\"><h2>400 Bad Request</h2></th>\r\n";
+                            output += "    </tr>\r\n";
+                            output += "    <tr>\r\n";
+                            output += "      <td valign=\"top\">\r\n";
+                            output += "      <p>The requested script could not be found on this server!</p>\r\n";
+                            output += "      </td>\r\n";
+                            output += "    </tr>\r\n";
+                            output += "  </table>\r\n";
+                            output += "</body>\r\n";
+                            output += "</html>\r\n";
+                            
+                            header  = "HTTP/1.1 404 Not Found\r\n";
+                            header += "Content-Length: "+int2String(output.size())+"\r\n";
+                            header += "Content-Type: text/html\r\n";
+                            header += "\r\n";
+                            
+                            output = header+output;
+                        }
+                        
+                        // write output
+                        
+                        void* address = (void*)(output).c_str();
+                        int offset = 0;
+                        while (offset < (output).size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), (output).size()-offset);
+                        
+                    } else {
+                        
+                        // transmit static file
+                        
+                        output  = "<!DOCTYPE html>\r\n";
+                        output += "<html lang=\"en\">\r\n";
+                        output += "<head>\r\n";
+                        output += "  <meta charset=\"utf-8\"/>\r\n";
+                        output += "  <title>IMU Sensor Data</title>\r\n";
+                        output += "  <style type=\"text/css\">\r\n";
+                        output += "    html {background-color: #223344;}\r\n";
+                        output += "    h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n";
+                        output += "    p, td {font-family:Helvetica,Arial,sans-serif; font-size: 16; color:#EEEEEE;}\r\n";
+                        output += "  </style>\r\n";
+                        output += "</head>\r\n";
+                        output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n";
+                        output += "  <script type=\"text/javascript\">\r\n";
+                        output += "  var ax = [];\r\n";
+                        output += "  var ay = [];\r\n";
+                        output += "  var az = [];\r\n";
+                        output += "  var gx = [];\r\n";
+                        output += "  var gy = [];\r\n";
+                        output += "  var gz = [];\r\n";
+                        output += "  var mx = [];\r\n";
+                        output += "  var my = [];\r\n";
+                        output += "  var mz = [];\r\n";
+                        output += "  var xmlhttp = null;\r\n";
+                        output += "  var task = window.setInterval(\"update()\", 50);\r\n";
+                        output += "  function update() {\r\n";
+                        output += "    if (window.XMLHttpRequest) {\r\n";
+                        output += "      xmlhttp = new XMLHttpRequest();\r\n";
+                        output += "    } else if (window.ActiveXObject) {\r\n";
+                        output += "      try {\r\n";
+                        output += "        xmlhttp = new ActiveXObject(\"Msxml2.XMLHTTP\");\r\n";
+                        output += "      } catch (exception) {\r\n";
+                        output += "        try {\r\n";
+                        output += "          xmlhttp = new ActiveXObject(\"Microsoft.XMLHTTP\");\r\n";
+                        output += "        } catch (exception) {}\r\n";
+                        output += "      }\r\n";
+                        output += "    }\r\n";
+                        output += "    xmlhttp.onreadystatechange = refresh;\r\n";
+                        output += "    xmlhttp.open(\"GET\", \"/cgi-bin/imu\");\r\n";
+                        output += "    xmlhttp.send(null);\r\n";
+                        output += "  }\r\n";
+                        output += "  function refresh() {\r\n";
+                        output += "    if (xmlhttp.readyState == 4) {\r\n";
+                        output += "      var xml = xmlhttp.responseXML;\r\n";
+                        output += "      var floatValues = xml.getElementsByTagName(\"float\");\r\n";
+                        output += "      ax.push(floatValues[0].childNodes[0].nodeValue); if (ax.length > 200) ax.shift();\r\n";
+                        output += "      ay.push(floatValues[1].childNodes[0].nodeValue); if (ay.length > 200) ay.shift();\r\n";
+                        output += "      az.push(floatValues[2].childNodes[0].nodeValue); if (az.length > 200) az.shift();\r\n";
+                        output += "      gx.push(floatValues[3].childNodes[0].nodeValue); if (gx.length > 200) gx.shift();\r\n";
+                        output += "      gy.push(floatValues[4].childNodes[0].nodeValue); if (gy.length > 200) gy.shift();\r\n";
+                        output += "      gz.push(floatValues[5].childNodes[0].nodeValue); if (gz.length > 200) gz.shift();\r\n";
+                        output += "      mx.push(floatValues[6].childNodes[0].nodeValue); if (mx.length > 200) mx.shift();\r\n";
+                        output += "      my.push(floatValues[7].childNodes[0].nodeValue); if (my.length > 200) my.shift();\r\n";
+                        output += "      mz.push(floatValues[8].childNodes[0].nodeValue); if (mz.length > 200) mz.shift();\r\n";
+                        output += "      drawPlot(\"ax\", 300, 200, ax, \"m/s2\");\r\n";
+                        output += "      drawPlot(\"ay\", 300, 200, ay, \"m/s2\");\r\n";
+                        output += "      drawPlot(\"az\", 300, 200, az, \"m/s2\");\r\n";
+                        output += "      drawPlot(\"gx\", 300, 200, gx, \"rad/s\");\r\n";
+                        output += "      drawPlot(\"gy\", 300, 200, gy, \"rad/s\");\r\n";
+                        output += "      drawPlot(\"gz\", 300, 200, gz, \"rad/s\");\r\n";
+                        output += "      drawPlot(\"mx\", 300, 200, mx, \"gauss\");\r\n";
+                        output += "      drawPlot(\"my\", 300, 200, my, \"gauss\");\r\n";
+                        output += "      drawPlot(\"mz\", 300, 200, mz, \"gauss\");\r\n";
+                        output += "    }\r\n";
+                        output += "  }\r\n";
+                        output += "  function drawPlot(id, width, height, value, valueUnit) {\r\n";
+                        output += "    var canvas = document.getElementById(id);\r\n";
+                        output += "    canvas.width = 2*width;\r\n";
+                        output += "    canvas.height = 2*height;\r\n";
+                        output += "    canvas.style.width = width+\"px\";\r\n";
+                        output += "    canvas.style.height = height+\"px\";\r\n";
+                        output += "    var ctx = canvas.getContext(\"2d\");\r\n";
+                        output += "    ctx.scale(2,2);\r\n";
+                        output += "    ctx.fillStyle = \"#FFFFFF11\";\r\n";
+                        output += "    ctx.fillRect(0.5, 0.5, width-1, height-1);\r\n";
+                        output += "    var valueMin = value[0];\r\n";
+                        output += "    var valueMax = value[0];\r\n";
+                        output += "    for (i = 0; i < value.length; i++) {\r\n";
+                        output += "      valueMin = Math.min(valueMin, value[i]);\r\n";
+                        output += "      valueMax = Math.max(valueMax, value[i]);\r\n";
+                        output += "    }\r\n";
+                        output += "    if (valueMax-valueMin < 2.0/Math.pow(10.0, 3)) {\r\n";
+                        output += "      var valueMean = (valueMin+valueMax)/2.0;\r\n";
+                        output += "      valueMin = valueMean-1.0/Math.pow(10.0, 3);\r\n";
+                        output += "      valueMax = valueMean+1.0/Math.pow(10.0, 3);\r\n";
+                        output += "    }\r\n";
+                        output += "    var valueStep = (valueMax-valueMin)/(height/100); if (valueStep < 1.0/Math.pow(10.0, 3)) valueStep = 1.0/Math.pow(10.0, 3);\r\n";
+                        output += "    var valueGain = Math.pow(10.0, Math.floor(Math.log(valueStep)/Math.log(10.0)));\r\n";
+                        output += "    valueStep = valueStep/valueGain;\r\n";
+                        output += "    if (valueStep > 5.0) valueStep = 5.0*valueGain; else if (valueStep > 2.0) valueStep = 2.0*valueGain; else valueStep = valueGain;\r\n";
+                        output += "    valueMin = Math.floor(valueMin/valueStep-0.25)*valueStep;\r\n";
+                        output += "    valueMax = Math.ceil(valueMax/valueStep+0.25)*valueStep;\r\n";
+                        output += "    ctx.strokeStyle = \"#EEEEEE\";\r\n";
+                        output += "    ctx.lineWidth = 1;\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    for (valueCurrent = valueMin+valueStep; valueCurrent < valueMax-valueStep/2.0; valueCurrent += valueStep) {\r\n";
+                        output += "      ctx.moveTo(0, (valueMax-valueCurrent)/(valueMax-valueMin)*height+0.5);\r\n";
+                        output += "      ctx.lineTo(width, (valueMax-valueCurrent)/(valueMax-valueMin)*height+0.5);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.stroke();\r\n";
+                        output += "    ctx.font = \"normal 14px sans-serif\";\r\n";
+                        output += "    ctx.textBaseline = \"bottom\";\r\n";
+                        output += "    ctx.fillStyle = \"white\";\r\n";
+                        output += "    for (valueCurrent = valueMin+valueStep; valueCurrent < valueMax-valueStep/2.0; valueCurrent += valueStep) {\r\n";
+                        output += "      ctx.fillText(valueCurrent.toFixed(2), 10.0, (valueMax-valueCurrent)/(valueMax-valueMin)*height-5.0);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.fillText((value[value.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, (valueMax-valueCurrent+valueStep)/(valueMax-valueMin)*height-5.0);\r\n";
+                        output += "    ctx.strokeStyle = \"#FF0000\";\r\n";
+                        output += "    ctx.lineWidth = 1;\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    ctx.moveTo(0, (valueMax-value[0])/(valueMax-valueMin)*height+0.5);\r\n";
+                        output += "    for (i = 1; i < value.length; i++) {\r\n";
+                        output += "      ctx.lineTo(i/(value.length-1)*width, (valueMax-value[i])/(valueMax-valueMin)*height+0.5);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.stroke();\r\n";
+                        output += "    ctx.strokeStyle = \"white\";\r\n";
+                        output += "    ctx.lineWidth = 1;\r\n";
+                        output += "    ctx.strokeRect(0.5, 0.5, width-1, height-1);\r\n";
+                        output += "  }\r\n";
+                        output += "  </script>";
+                        output += "  <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"20\" cellpadding=\"0\">\r\n";
+                        output += "    <tr>\r\n";
+                        output += "      <th colspan=\"3\" width=\"100%\" height=\"20\"><h2>IMU Sensor Data</h2></th>\r\n";
+                        output += "    </tr>\r\n";
+                        output += "    <tr>\r\n";
+                        output += "      <td>Acceleration X [m/s&sup2;]<br/><br/><canvas id=\"ax\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "      <td>Gyro X [rad/s]<br/><br/><canvas id=\"gx\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "      <td>Magnetometer X [gauss]<br/><br/><canvas id=\"mx\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "    </tr>\r\n";
+                        output += "    <tr>\r\n";
+                        output += "      <td>Acceleration Y [m/s&sup2;]<br/><br/><canvas id=\"ay\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "      <td>Gyro Y [rad/s]<br/><br/><canvas id=\"gy\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "      <td>Magnetometer Y [gauss]<br/><br/><canvas id=\"my\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "    </tr>\r\n";
+                        output += "    <tr>\r\n";
+                        output += "      <td>Acceleration Z [m/s&sup2;]<br/><br/><canvas id=\"az\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "      <td>Gyro Z [rad/s]<br/><br/><canvas id=\"gz\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "      <td>Magnetometer Z [gauss]<br/><br/><canvas id=\"mz\" width=\"300\" height=\"200\"></canvas></td>\r\n";
+                        output += "    </tr>\r\n";
+                        output += "  </table>\r\n";
+                        output += "</body>\r\n";
+                        output += "</html>\r\n";
+                        
+                        header  = "HTTP/1.1 404 Not Found\r\n";
+                        header += "Content-Length: "+int2String(output.size())+"\r\n";
+                        header += "Content-Type: text/html\r\n";
+                        header += "\r\n";
+                        
+                        output = header+output;
+                        
+                        // write output
+                        
+                        void* address = (void*)output.c_str();
+                        int offset = 0;
+                        while (offset < output.size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), output.size()-offset);
+                    }
+                    
+                } else {
+                    
+                    // the http method is not known
+                    
+                    output  = "<!DOCTYPE html>\r\n";
+                    output += "<html lang=\"en\">\r\n";
+                    output += "<head>\r\n";
+                    output += "  <title>400 Bad Request</title>\r\n";
+                    output += "  <style type=\"text/css\">\r\n";
+                    output += "    h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n";
+                    output += "    p {font-family:Helvetica,Arial,sans-serif; font-size: 14; color:#444444;}\r\n";
+                    output += "  </style>\r\n";
+                    output += "</head>\r\n";
+                    output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n";
+                    output += "  <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"0\" cellpadding=\"20\">\r\n";
+                    output += "    <tr>\r\n";
+                    output += "      <th width=\"100%\" height=\"30\" bgcolor=\"#0064A6\"><h2>400 Bad Request</h2></th>\r\n";
+                    output += "    </tr>\r\n";
+                    output += "    <tr>\r\n";
+                    output += "      <td valign=\"top\">\r\n";
+                    output += "      <p>The requested method is not supported by this server!</p>\r\n";
+                    output += "      </td>\r\n";
+                    output += "    </tr>\r\n";
+                    output += "  </table>\r\n";
+                    output += "</body>\r\n";
+                    output += "</html>\r\n";
+                    
+                    header  = "HTTP/1.1 400 Bad Request\r\n";
+                    header += "Content-Length: "+int2String(output.size())+"\r\n";
+                    header += "Content-Type: text/html\r\n";
+                    header += "\r\n";
+                    
+                    output = header+output;
+                    
+                    // write output
+                    
+                    void* address = (void*)output.c_str();
+                    int offset = 0;
+                    while (offset < output.size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), output.size()-offset);
+                }
+            }
+            
+            client->close();
+            
+        } // client != NULL
+        
+    } // infinite while loop
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer.h	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,105 @@
+/*
+ * HTTPServer.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef HTTP_SERVER_H_
+#define HTTP_SERVER_H_
+
+#include <string>
+#include <vector>
+#include <mbed.h>
+#include <EthernetInterface.h>
+
+class HTTPScript;
+
+/**
+ * The <code>HTTPServer</code> class implements a simple webserver that is able to
+ * transmit files over an ethernet connection and allows to call scripts that are
+ * registered with the server.
+ * <br/>
+ * An http server can be created and started as follows:
+ * <pre><code>
+ *   EthernetInterface* ethernet = new EthernetInterface();  <span style="color:#008000">// init the TCP/IP stack</span>
+ *   ethernet->set_network("192.168.0.10", "255.255.255.0", "192.168.0.1");
+ *   ethernet->connect();
+ *
+ *   HTTPServer* httpServer = new HTTPServer(ethernet); <span style="color:#008000">// creates an http server</span>
+ *   ...
+ * </code></pre>
+ * This http server allows to execute application specific code implemented as http
+ * scripts. These scripts are objects derived from the <code>HTTPScript</code> superclass.
+ * <br/>
+ * An example of an application specific script is given below:
+ * <pre><code>
+ * class MyHTTPScript : public HTTPScript {
+ *     public:
+ *                  MyHTTPScript();
+ *         virtual  ~MyHTTPScript();
+ *         string   call(vector<string> names, vector<string> values);
+ * };
+ * 
+ * string MyHTTPScript::call(vector<string> names, vector<string> values) {
+ *   
+ *   string response;
+ *   
+ *   response += "  <h2>";
+ *   for (uint32_t i = 0; i < min(names.size(), values.size()); i++) {
+ *     response += "  <p>"+names[i]+"="+values[i]+"</p>";
+ *   }
+ *   response += "  </h2>";
+ * 
+ *   return response;
+ * }
+ * </code></pre>
+ * This script returns the parameters that were passed to it by the http server.
+ * <br/>
+ * Before this script can be used, it needs to be registered with the http server
+ * with the <code>add()</code> method as follows:
+ * <pre><code>
+ *   httpServer->add("myScript", new MyHTTPScript());
+ * </code></pre>
+ * When the <code>call()</code> method of the script is called by the http server,
+ * it receives two string vectors: a vector with the names of the arguments passed
+ * in the URL, and a vector with the corresponding values of the arguments.
+ * <br/>
+ * An example of an http request calling this script is as follows:
+ * <pre><code>
+ *   http://192.168.1.10/cgi-bin/myScript?x=0.5&y=-0.1&z=0.2
+ * </code></pre>
+ * The vectors of arguments passed to the <code>call()</code> method are then
+ * {'x', 'y', 'z'} for the names and {'0.5', '-0.1', '0.2'} for the values.
+ * <br/>
+ * The response of the <code>call()</code> method is a <code>string</code> object
+ * which is placed within an xhtml page, which in turn is returned by the http
+ * server to the requesting http client.
+ * @see HTTPScript
+ */
+class HTTPServer {
+    
+    public:
+    
+                    HTTPServer(EthernetInterface& ethernet);
+        virtual     ~HTTPServer();
+        void        add(std::string name, HTTPScript* httpScript);
+        
+    private:
+        
+        static const unsigned int   STACK_SIZE = 16384; // stack size of thread, given in [bytes]
+        static const int            PORT_NUMBER = 80;   // port number of server to use
+        static const unsigned int   INPUT_BUFFER_SIZE;  // size of receive buffer, given in [bytes]
+        static const int            SOCKET_TIMEOUT;     // timeout of socket, given in [ms]
+        
+        EthernetInterface&          ethernet;
+        TCPSocket                   server;
+        std::vector<std::string>    httpScriptNames;
+        std::vector<HTTPScript*>    httpScripts;
+        Thread                      thread;
+        
+        string      urlDecoder(std::string url);
+        void        run();
+};
+
+#endif /* HTTP_SERVER_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IMU.cpp	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,267 @@
+/*
+ * IMU.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include "IMU.h"
+
+using namespace std;
+
+const float IMU::PERIOD = 0.002f;                   // the period of the timer interrupt, given in [s]
+const float IMU::M_PI = 3.14159265358979323846f;    // the mathematical constant PI
+
+/**
+ * Creates an IMU object.
+ * @param spi a reference to an spi controller to use.
+ * @param csAG the chip select output for the accelerometer and the gyro sensor.
+ * @param csM the chip select output for the magnetometer.
+ */
+IMU::IMU(SPI& spi, DigitalOut& csAG, DigitalOut& csM) : spi(spi), csAG(csAG), csM(csM), thread(osPriorityHigh, STACK_SIZE) {
+    
+    // initialize SPI interface
+    
+    spi.format(8, 3);
+    spi.frequency(1000000);
+    
+    // reset chip select lines to logical high
+    
+    csAG = 1;
+    csM = 1;
+    
+    // initialize accelerometer and gyro
+    
+    writeRegister(csAG, CTRL_REG1_G, 0xC3);     // ODR 952 Hz, full scale 245 deg/s
+    writeRegister(csAG, CTRL_REG2_G, 0x00);     // disable interrupt generation
+    writeRegister(csAG, CTRL_REG3_G, 0x00);     // disable low power mode, disable high pass filter, high pass cutoff frequency 57 Hz
+    writeRegister(csAG, CTRL_REG4, 0x38);       // enable gyro in all 3 axis
+    writeRegister(csAG, CTRL_REG5_XL, 0x38);    // no decimation, enable accelerometer in all 3 axis
+    writeRegister(csAG, CTRL_REG6_XL, 0xC0);    // ODR 952 Hz, full scale 2g
+    writeRegister(csAG, CTRL_REG7_XL, 0x00);    // high res mode disabled, filter bypassed
+    writeRegister(csAG, CTRL_REG8, 0x00);       // 4-wire SPI interface, LSB at lower address
+    writeRegister(csAG, CTRL_REG9, 0x04);       // disable gyro sleep mode, disable I2C interface, disable FIFO
+    writeRegister(csAG, CTRL_REG10, 0x00);      // self test disabled
+    
+    // initialize magnetometer
+    
+    writeRegister(csM, CTRL_REG1_M, 0x10);      // temperature not compensated, low power mode for x & y axis, data rate 10 Hz
+    writeRegister(csM, CTRL_REG2_M, 0x00);      // full scale 4 gauss
+    writeRegister(csM, CTRL_REG3_M, 0x80);      // disable I2C interface, low power mode, SPI write only, continuous conversion mode
+    writeRegister(csM, CTRL_REG4_M, 0x00);      // low power mode for z axis, LSB at lower address
+    writeRegister(csM, CTRL_REG5_M, 0x00);      // fast read disabled
+    
+    // start thread and timer interrupt
+    
+    thread.start(callback(this, &IMU::run));
+    ticker.attach(callback(this, &IMU::sendThreadFlag), PERIOD);
+}
+
+/**
+ * Deletes the IMU object.
+ */
+IMU::~IMU() {
+    
+    ticker.detach();
+}
+
+/**
+ * This private method allows to write a register value.
+ * @param cs the chip select output to use, either csAG or csM.
+ * @param address the 7 bit address of the register.
+ * @param value the value to write into the register.
+ */
+void IMU::writeRegister(DigitalOut& cs, char address, char value) {
+    
+    cs = 0;
+    
+    spi.write(0x7F & address);
+    spi.write(value & 0xFF);
+    
+    cs = 1;
+}
+
+/**
+ * This private method allows to read a register value.
+ * @param cs the chip select output to use, either csAG or csM.
+ * @param address the 7 bit address of the register.
+ * @return the value read from the register.
+ */
+char IMU::readRegister(DigitalOut& cs, char address) {
+    
+    cs = 0;
+    
+    spi.write(0x80 | address);
+    int value = spi.write(0xFF);
+    
+    cs = 1;
+    
+    return (char)(value & 0xFF);
+}
+
+/**
+ * Reads the acceleration in x-direction.
+ * @return the acceleration in x-direction, given in [m/s2].
+ */
+float IMU::readAccelerationX() {
+    
+    mutex.lock();
+    
+    char low = readRegister(csAG, OUT_X_L_XL);
+    char high = readRegister(csAG, OUT_X_H_XL);
+    
+    short value = (short)(((unsigned short)high << 8) | (unsigned short)low);
+    
+    mutex.unlock();
+    
+    return (float)value/32768.0f*2.0f*9.81f;
+}
+
+/**
+ * Reads the acceleration in y-direction.
+ * @return the acceleration in y-direction, given in [m/s2].
+ */
+float IMU::readAccelerationY() {
+    
+    mutex.lock();
+    
+    char low = readRegister(csAG, OUT_Y_L_XL);
+    char high = readRegister(csAG, OUT_Y_H_XL);
+    
+    short value = (short)(((unsigned short)high << 8) | (unsigned short)low);
+    
+    mutex.unlock();
+    
+    return (float)value/32768.0f*2.0f*9.81f;
+}
+
+/**
+ * Reads the acceleration in z-direction.
+ * @return the acceleration in z-direction, given in [m/s2].
+ */
+float IMU::readAccelerationZ() {
+    
+    mutex.lock();
+    
+    char low = readRegister(csAG, OUT_Z_L_XL);
+    char high = readRegister(csAG, OUT_Z_H_XL);
+    
+    short value = (short)(((unsigned short)high << 8) | (unsigned short)low);
+    
+    mutex.unlock();
+    
+    return (float)value/32768.0f*2.0f*9.81f;
+}
+
+/**
+ * Reads the gyroscope about the x-axis.
+ * @return the rotational speed about the x-axis given in [rad/s].
+ */
+float IMU::readGyroX() {
+    
+    mutex.lock();
+    
+    char low = readRegister(csAG, OUT_X_L_G);
+    char high = readRegister(csAG, OUT_X_H_G);
+    
+    short value = (short)(((unsigned short)high << 8) | (unsigned short)low);
+    
+    mutex.unlock();
+    
+    return (float)value/32768.0f*245.0f*M_PI/180.0f;
+}
+
+/**
+ * Reads the gyroscope about the y-axis.
+ * @return the rotational speed about the y-axis given in [rad/s].
+ */
+float IMU::readGyroY() {
+    
+    mutex.lock();
+    
+    char low = readRegister(csAG, OUT_Y_L_G);
+    char high = readRegister(csAG, OUT_Y_H_G);
+    
+    short value = (short)(((unsigned short)high << 8) | (unsigned short)low);
+    
+    mutex.unlock();
+    
+    return (float)value/32768.0f*245.0f*M_PI/180.0f;
+}
+
+/**
+ * Reads the gyroscope about the z-axis.
+ * @return the rotational speed about the z-axis given in [rad/s].
+ */
+float IMU::readGyroZ() {
+    
+    mutex.lock();
+    
+    char low = readRegister(csAG, OUT_Z_L_G);
+    char high = readRegister(csAG, OUT_Z_H_G);
+    
+    short value = (short)(((unsigned short)high << 8) | (unsigned short)low);
+    
+    mutex.unlock();
+    
+    return (float)value/32768.0f*245.0f*M_PI/180.0f;
+}
+
+/**
+ * Reads the magnetic field in x-direction.
+ * @return the magnetic field in x-direction, given in [Gauss].
+ */
+float IMU::readMagnetometerX() {
+    
+    // bitte implementieren!
+    
+    return 0.0f;
+}
+
+/**
+ * Reads the magnetic field in y-direction.
+ * @return the magnetic field in y-direction, given in [Gauss].
+ */
+float IMU::readMagnetometerY() {
+    
+    // bitte implementieren!
+    
+    return 0.0f;
+}
+
+/**
+ * Reads the magnetic field in z-direction.
+ * @return the magnetic field in z-direction, given in [Gauss].
+ */
+float IMU::readMagnetometerZ() {
+    
+    // bitte implementieren!
+    
+    return 0.0f;
+}
+
+/**
+ * This method is called by the ticker timer interrupt service routine.
+ * It sends a flag to the thread to make it run again.
+ */
+void IMU::sendThreadFlag() {
+    
+    thread.flags_set(threadFlag);
+}
+
+/**
+ * This <code>run()</code> method contains an infinite loop with the run logic.
+ */
+void IMU::run() {
+    
+    while (true) {
+        
+        // wait for the periodic thread flag
+        
+        ThisThread::flags_wait_any(threadFlag);
+        
+        // filter and process sensor data...
+        
+        
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IMU.h	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,91 @@
+/*
+ * IMU.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef IMU_H_
+#define IMU_H_
+
+#include <cstdlib>
+#include <mbed.h>
+#include "ThreadFlag.h"
+
+/**
+ * This is a device driver class for the ST LSM9DS1 inertial measurement unit.
+ */
+class IMU {
+
+    public:
+        
+                    IMU(SPI& spi, DigitalOut& csAG, DigitalOut& csM);
+        virtual     ~IMU();
+        float       readAccelerationX();
+        float       readAccelerationY();
+        float       readAccelerationZ();
+        float       readGyroX();
+        float       readGyroY();
+        float       readGyroZ();
+        float       readMagnetometerX();
+        float       readMagnetometerY();
+        float       readMagnetometerZ();
+        
+    private:
+        
+        static const char   WHO_AM_I = 0x0F;
+        static const char   CTRL_REG1_G = 0x10;
+        static const char   CTRL_REG2_G = 0x11;
+        static const char   CTRL_REG3_G = 0x12;
+        static const char   OUT_X_L_G = 0x18;
+        static const char   OUT_X_H_G = 0x19;
+        static const char   OUT_Y_L_G = 0x1A;
+        static const char   OUT_Y_H_G = 0x1B;
+        static const char   OUT_Z_L_G = 0x1C;
+        static const char   OUT_Z_H_G = 0x1D;
+        static const char   CTRL_REG4 = 0x1E;
+        static const char   CTRL_REG5_XL = 0x1F;
+        static const char   CTRL_REG6_XL = 0x20;
+        static const char   CTRL_REG7_XL = 0x21;
+        static const char   CTRL_REG8 = 0x22;
+        static const char   CTRL_REG9 = 0x23;
+        static const char   CTRL_REG10 = 0x24;
+        static const char   OUT_X_L_XL = 0x28;
+        static const char   OUT_X_H_XL = 0x29;
+        static const char   OUT_Y_L_XL = 0x2A;
+        static const char   OUT_Y_H_XL = 0x2B;
+        static const char   OUT_Z_L_XL = 0x2C;
+        static const char   OUT_Z_H_XL = 0x2D;
+        
+        static const char   WHO_AM_I_M = 0x0F;
+        static const char   CTRL_REG1_M = 0x20;
+        static const char   CTRL_REG2_M = 0x21;
+        static const char   CTRL_REG3_M = 0x22;
+        static const char   CTRL_REG4_M = 0x23;
+        static const char   CTRL_REG5_M = 0x24;
+        static const char   OUT_X_L_M = 0x28;
+        static const char   OUT_X_H_M = 0x29;
+        static const char   OUT_Y_L_M = 0x2A;
+        static const char   OUT_Y_H_M = 0x2B;
+        static const char   OUT_Z_L_M = 0x2C;
+        static const char   OUT_Z_H_M = 0x2D;
+        
+        static const unsigned int   STACK_SIZE = 4096;          // stack size of thread, given in [bytes]
+        static const float          PERIOD;                     // the period of the timer interrupt, given in [s]
+        static const float          M_PI;                       // the mathematical constant PI
+        
+        SPI&            spi;
+        DigitalOut&     csAG;
+        DigitalOut&     csM;
+        Mutex           mutex;
+        ThreadFlag      threadFlag;
+        Thread          thread;
+        Ticker          ticker;
+        
+        void    writeRegister(DigitalOut& cs, char address, char value);
+        char    readRegister(DigitalOut& cs, char address);
+        void    sendThreadFlag();
+        void    run();
+};
+
+#endif /* IMU_H_ */
+
--- a/Main.cpp	Wed Mar 25 12:22:47 2020 +0000
+++ b/Main.cpp	Wed Apr 08 09:13:33 2020 +0000
@@ -5,15 +5,23 @@
  */
 
 #include <mbed.h>
+#include <EthernetInterface.h>
+#include "IMU.h"
+#include "HTTPServer.h"
+#include "HTTPScriptIMU.h"
 #include "IRSensor.h"
 #include "EncoderCounter.h"
 #include "Controller.h"
 #include "StateMachine.h"
+#include "ThreadFlag.h"
 
 int main() {
+
     
     // initialise digital inputs and outputs
     
+    printf("Initialise digital inputs and outputs...\r\n");
+    
     DigitalIn button(USER_BUTTON);
     
     DigitalOut ledGreen(LED1);
@@ -26,71 +34,93 @@
     DigitalOut led3(PD_2);
     DigitalOut led4(PD_7);
     DigitalOut led5(PD_5);
-    
+
     // create distance sensor objects
-    
+
     AnalogIn distance(PA_0);
     DigitalOut enable(PG_1);
     DigitalOut bit0(PF_0);
     DigitalOut bit1(PF_1);
     DigitalOut bit2(PF_2);
-    
+
     enable = 1;
-    
+
     IRSensor irSensor0(distance, bit0, bit1, bit2, 0);
     IRSensor irSensor1(distance, bit0, bit1, bit2, 1);
     IRSensor irSensor2(distance, bit0, bit1, bit2, 2);
     IRSensor irSensor3(distance, bit0, bit1, bit2, 3);
     IRSensor irSensor4(distance, bit0, bit1, bit2, 4);
     IRSensor irSensor5(distance, bit0, bit1, bit2, 5);
-    
+
     // create motor controller objects
-    
-    DigitalOut enableMotorDriver(PG_0); 
+
+    DigitalOut enableMotorDriver(PG_0);
     DigitalIn motorDriverFault(PD_1);
     DigitalIn motorDriverWarning(PD_0);
-    
+
     PwmOut pwmLeft(PF_9);
     PwmOut pwmRight(PF_8);
-    
+
     // create encoder counter objects
-    
+
     EncoderCounter counterLeft(PD_12, PD_13);
     EncoderCounter counterRight(PB_4, PC_7);
-    
+
     // create robot controller objects
-    
+
     Controller controller(pwmLeft, pwmRight, counterLeft, counterRight);
     StateMachine stateMachine(controller, enableMotorDriver, led0, led1, led2, led3, led4, led5, button, irSensor0, irSensor1, irSensor2, irSensor3, irSensor4, irSensor5);
     
+    // create inertial measurement unit object
+    
+    printf("Create inertial measurement unit object...\r\n");
+    
+    SPI spi(PC_12, PC_11, PC_10);
+    DigitalOut csAG(PC_8);
+    DigitalOut csM(PC_9);
+    
+    IMU imu(spi, csAG, csM);
+    
+    // create ethernet interface and webserver
+    
+    printf("Create ethernet interface and webserver (please wait!)...\r\n");
+    
+    EthernetInterface* ethernet = new EthernetInterface();
+    ethernet->set_network("192.168.0.10", "255.255.255.0", "192.168.0.1"); // configure IP address, netmask and gateway address
+    ethernet->connect();
+    
+    HTTPServer* httpServer = new HTTPServer(*ethernet);
+    httpServer->add("imu", new HTTPScriptIMU(imu));
+    
     // enter main loop
     
+    printf("Enter main loop...\r\n");
+    
     while (true) {
         
-        if (stateMachine.getState() == StateMachine::MOVE_FORWARD) {
-            
-            ledGreen = 1;
-            ledBlue = 0;
-            ledRed = 0;
-            
-        } else if ((stateMachine.getState() == StateMachine::TURN_LEFT) || (stateMachine.getState() == StateMachine::TURN_RIGHT)) {
-            
-            ledGreen = 1;
-            ledBlue = 1;
-            ledRed = 0;
-            
-        } else {
-            
-            ledGreen = 0;
-            ledBlue = 0;
-            ledRed = 1;
-        }
+        // set LEDs on microcontroller
+        
+        ledGreen = 1;
+        ledBlue = 0;
+        ledRed = 0;
+        
+        ThisThread::sleep_for(100);
+        
+        ledGreen = 0;
+        ledBlue = 1;
+        ledRed = 0;
         
-        // print robot pose into terminal
+        ThisThread::sleep_for(100);
+        
+        ledGreen = 0;
+        ledBlue = 0;
+        ledRed = 1;
         
-        printf("%.3f %.3f %.3f\r\n", controller.getX(), controller.getY(), controller.getAlpha());
+        // print sensor data into terminal
         
-        wait(0.1);
+        printf("Gyro: %.3f / %.3f / %.3f\r\n", imu.readGyroX(), imu.readGyroY(), imu.readGyroZ());
+        printf("Acceleration: %.3f / %.3f / %.3f\r\n", imu.readAccelerationX(), imu.readAccelerationY(), imu.readAccelerationZ());
+        printf("Magnetometer: %.3f / %.3f / %.3f\r\n", imu.readMagnetometerX(), imu.readMagnetometerY(), imu.readMagnetometerZ());
     }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ThreadFlag.cpp	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,54 @@
+/*
+ * ThreadFlag.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include "ThreadFlag.h"
+
+using namespace std;
+
+unsigned int ThreadFlag::threadFlags = 0;
+
+/**
+ * Creates a signal object and assignes a unique flag.
+ */
+ThreadFlag::ThreadFlag() {
+    
+    mutex.lock();
+    
+    unsigned int n = 0;
+    while ((((1 << n) & threadFlags) > 0) && (n < 30)) n++;
+    threadFlag = (1 << n);
+    
+    mutex.unlock();
+}
+
+/**
+ * Deletes the signal object and releases the assigned flag.
+ */
+ThreadFlag::~ThreadFlag() {
+    
+    mutex.lock();
+    
+    threadFlags &= ~threadFlag;
+    
+    mutex.unlock();
+}
+
+/**
+ * Gets the assigned thread flag.
+ */
+unsigned int ThreadFlag::read() {
+    
+    return threadFlag;
+}
+
+/**
+ * The empty operator is a shorthand notation of the <code>read()</code> method.
+ */
+ThreadFlag::operator unsigned int() {
+    
+    return read();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ThreadFlag.h	Wed Apr 08 09:13:33 2020 +0000
@@ -0,0 +1,33 @@
+/*
+ * ThreadFlag.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef THREAD_FLAG_H_
+#define THREAD_FLAG_H_
+
+#include <cstdlib>
+#include <mbed.h>
+
+/**
+ * This class manages the handling of unique thread flags to trigger rtos threads.
+ */
+class ThreadFlag {
+    
+    public:
+        
+                                ThreadFlag();
+        virtual                 ~ThreadFlag();
+        virtual unsigned int    read();
+                                operator unsigned int();
+        
+    private:
+        
+        static unsigned int threadFlags;    // variable that holds all assigned thread flags
+        unsigned int        threadFlag;     // thread flag of this object
+        Mutex               mutex;          // mutex to lock critical sections
+};
+
+#endif /* THREAD_FLAG_H_ */
+