Marco Oehler / Mbed OS Lab5

Files at this revision

API Documentation at this revision

Comitter:
oehlemar
Date:
Tue Apr 28 13:59:27 2020 +0000
Child:
1:5201940a41c1
Commit message:
initial publish

Changed in this revision

.gitignore Show annotated file Show diff for this revision Revisions of this file
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
HTTPScriptLIDAR.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPScriptLIDAR.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
LIDAR.cpp Show annotated file Show diff for this revision Revisions of this file
LIDAR.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
Point.cpp Show annotated file Show diff for this revision Revisions of this file
Point.h 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
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
resources/official_armmbed_example_badge.png Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.gitignore	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,4 @@
+.build
+.mbed
+projectfiles
+*.py*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPScript.cpp	Tue Apr 28 13:59:27 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	Tue Apr 28 13:59:27 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/HTTPScriptLIDAR.cpp	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,65 @@
+/*
+ * HTTPScriptLIDAR.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include <deque>
+#include "HTTPScriptLIDAR.h"
+
+using namespace std;
+
+inline string int2String(int i) {
+    
+    char buffer[32];
+    sprintf(buffer, "%d", i);
+    
+    return string(buffer);
+}
+
+inline string float2String(float f) {
+    
+    char buffer[32];
+    sprintf(buffer, "%.3f", f);
+    
+    return string(buffer);
+}
+
+/**
+ * Create and initialize this http script.
+ * @param lidar a reference to the lidar to read scans from.
+ */
+HTTPScriptLIDAR::HTTPScriptLIDAR(LIDAR& lidar) : lidar(lidar) {}
+
+HTTPScriptLIDAR::~HTTPScriptLIDAR() {}
+
+/**
+ * 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 HTTPScriptLIDAR::call(vector<string> names, vector<string> values) {
+    
+    string response;
+    
+    deque<Point> scan = lidar.getScan();
+    deque<Point> beacons = lidar.getBeacons();
+    
+    response += "  <lidar>\r\n";
+    response += "    <scan>\r\n";
+    response += "      <size><int>"+int2String(scan.size())+"</int></size>\r\n";
+    for (unsigned short i = 0; i < scan.size(); i++) {
+        response += "      <point><x><float>"+float2String(scan[i].x)+"</float></x><y><float>"+float2String(scan[i].y)+"</float></y></point>\r\n";
+    }
+    response += "    </scan>\r\n";
+    response += "    <beacons>\r\n";
+    response += "      <size><int>"+int2String(beacons.size())+"</int></size>\r\n";
+    for (unsigned short i = 0; i < beacons.size(); i++) {
+        response += "      <point><x><float>"+float2String(beacons[i].x)+"</float></x><y><float>"+float2String(beacons[i].y)+"</float></y></point>\r\n";
+    }
+    response += "    </beacons>\r\n";
+    response += "  </lidar>\r\n";
+    
+    return response;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPScriptLIDAR.h	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,33 @@
+/*
+ * HTTPScriptLIDAR.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef HTTP_SCRIPT_LIDAR_H_
+#define HTTP_SCRIPT_LIDAR_H_
+
+#include <string>
+#include <vector>
+#include "HTTPScript.h"
+#include "LIDAR.h"
+
+/**
+ * This is a specific http script to read scans from a LIDAR.
+ * @see HTTPServer
+ */
+class HTTPScriptLIDAR : public HTTPScript {
+    
+    public:
+        
+                            HTTPScriptLIDAR(LIDAR& lidar);
+        virtual             ~HTTPScriptLIDAR();
+        virtual std::string call(std::vector<std::string> names, std::vector<std::string> values);
+        
+    private:
+        
+        LIDAR&  lidar;
+};
+
+#endif /* HTTP_SCRIPT_LIDAR_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer.cpp	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,444 @@
+/*
+ * 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>LIDAR Scan</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 {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 xmlhttp = null;\r\n";
+                        output += "  var task = window.setInterval(\"update()\", 100);\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/lidar\");\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 intValues = xml.getElementsByTagName(\"int\");\r\n";
+                        output += "      var floatValues = xml.getElementsByTagName(\"float\");\r\n";
+                        output += "      var sizeScan = intValues[0].childNodes[0].nodeValue;\r\n";
+                        output += "      var sizeBeacons = intValues[1].childNodes[0].nodeValue;\r\n";
+                        output += "      var x = [];\r\n";
+                        output += "      var y = [];\r\n";
+                        output += "      var xBeacon = [];\r\n";
+                        output += "      var yBeacon = [];\r\n";
+                        output += "      for (i = 0; i < sizeScan; i++) {\r\n";
+                        output += "        x.push(-floatValues[2*i+1].childNodes[0].nodeValue);\r\n";
+                        output += "        y.push(floatValues[2*i].childNodes[0].nodeValue);\r\n";
+                        output += "      }\r\n";
+                        output += "      for (i = 0; i < sizeBeacons; i++) {\r\n";
+                        output += "        xBeacon.push(-floatValues[2*i+2*sizeScan+1].childNodes[0].nodeValue);\r\n";
+                        output += "        yBeacon.push(floatValues[2*i+2*sizeScan].childNodes[0].nodeValue);\r\n";
+                        output += "      }\r\n";
+                        output += "      drawScan(\"lidar\", x, y, xBeacon, yBeacon);\r\n";
+                        output += "    }\r\n";
+                        output += "  }\r\n";
+                        output += "  function drawScan(id, x, y, xBeacon, yBeacon) {\r\n";
+                        output += "    var canvas = document.getElementById(id);\r\n";
+                        output += "    var width = window.innerWidth-50;\r\n";
+                        output += "    var height = window.innerHeight-50;\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 = \"#334455\";\r\n";
+                        output += "    ctx.fillRect(0.5, 0.5, width-1, height-1);\r\n";
+                        output += "    var xMax = 3.0;\r\n";
+                        output += "    var yMax = 3.0;\r\n";
+                        output += "    if (width > height) {\r\n";
+                        output += "      xMax = yMax*width/height;\r\n";
+                        output += "    } else {\r\n";
+                        output += "      yMax = xMax*height/width;\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.strokeStyle = \"#445566\";\r\n";
+                        output += "    ctx.lineWidth = 1;\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    for (xGrid = 0.0; xGrid < xMax; xGrid += 0.1) {\r\n";
+                        output += "      ctx.moveTo(width/2.0+xGrid/xMax*width/2.0, 0.0);\r\n";
+                        output += "      ctx.lineTo(width/2.0+xGrid/xMax*width/2.0, height);\r\n";
+                        output += "      ctx.moveTo(width/2.0-xGrid/xMax*width/2.0, 0.0);\r\n";
+                        output += "      ctx.lineTo(width/2.0-xGrid/xMax*width/2.0, height);\r\n";
+                        output += "    }\r\n";
+                        output += "    for (yGrid = 0.0; yGrid < yMax; yGrid += 0.1) {\r\n";
+                        output += "      ctx.moveTo(0.0, height/2.0+yGrid/yMax*height/2.0);\r\n";
+                        output += "      ctx.lineTo(width, height/2.0+yGrid/yMax*height/2.0);\r\n";
+                        output += "      ctx.moveTo(0.0, height/2.0-yGrid/yMax*height/2.0);\r\n";
+                        output += "      ctx.lineTo(width, height/2.0-yGrid/yMax*height/2.0);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.stroke();\r\n";
+                        output += "    ctx.strokeStyle = \"#667788\";\r\n";
+                        output += "    ctx.lineWidth = 1;\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    for (xGrid = 0.0; xGrid < xMax; xGrid += 1.0) {\r\n";
+                        output += "      ctx.moveTo(width/2.0+xGrid/xMax*width/2.0, 0.0);\r\n";
+                        output += "      ctx.lineTo(width/2.0+xGrid/xMax*width/2.0, height);\r\n";
+                        output += "      ctx.moveTo(width/2.0-xGrid/xMax*width/2.0, 0.0);\r\n";
+                        output += "      ctx.lineTo(width/2.0-xGrid/xMax*width/2.0, height);\r\n";
+                        output += "    }\r\n";
+                        output += "    for (yGrid = 0.0; yGrid < yMax; yGrid += 1.0) {\r\n";
+                        output += "      ctx.moveTo(0.0, height/2.0+yGrid/yMax*height/2.0);\r\n";
+                        output += "      ctx.lineTo(width, height/2.0+yGrid/yMax*height/2.0);\r\n";
+                        output += "      ctx.moveTo(0.0, height/2.0-yGrid/yMax*height/2.0);\r\n";
+                        output += "      ctx.lineTo(width, height/2.0-yGrid/yMax*height/2.0);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.stroke();\r\n";
+                        output += "    ctx.strokeStyle = \"white\";\r\n";
+                        output += "    ctx.lineWidth = 0;\r\n";
+                        output += "    ctx.fillStyle = \"white\";\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    ctx.moveTo(width/2.0, height/2.0);\r\n";
+                        output += "    ctx.arc(width/2.0, height/2.0, 8, 0, 2*Math.PI, false);\r\n";
+                        output += "    ctx.moveTo(width/2.0, height/2.0+8);\r\n";
+                        output += "    ctx.arc(width/2.0, height/2.0+8, 5, 0, 2*Math.PI, false);\r\n";
+                        output += "    ctx.fill();\r\n";
+                        output += "    ctx.stroke();\r\n";
+                        output += "    ctx.strokeStyle = \"#FF0000\";\r\n";
+                        output += "    ctx.fillStyle = \"#FF0000\";\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    for (i = 0; i < Math.min(xBeacon.length, yBeacon.length); i++) {\r\n";
+                        output += "      ctx.moveTo(width/2.0+xBeacon[i]/xMax*width/2.0, height/2.0-yBeacon[i]/yMax*height/2.0);\r\n";
+                        output += "      ctx.arc(width/2.0+xBeacon[i]/xMax*width/2.0, height/2.0-yBeacon[i]/yMax*height/2.0, 5, 0, 2*Math.PI, false);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.fill();\r\n";
+                        output += "    ctx.stroke();\r\n";
+                        output += "    ctx.strokeStyle = \"#FFFF00\";\r\n";
+                        output += "    ctx.lineWidth = 0.5;\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    ctx.moveTo(width/2.0+x[0]/xMax*width/2.0, height/2.0-y[0]/yMax*height/2.0);\r\n";
+                        output += "    for (i = 1; i < Math.min(x.length, y.length); i++) {\r\n";
+                        output += "      ctx.lineTo(width/2.0+x[i]/xMax*width/2.0, height/2.0-y[i]/yMax*height/2.0);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.lineTo(width/2.0+x[0]/xMax*width/2.0, height/2.0-y[0]/yMax*height/2.0);\r\n";
+                        output += "    ctx.stroke();\r\n";
+                        output += "    ctx.fillStyle = \"#FFFF00\";\r\n";
+                        output += "    ctx.beginPath();\r\n";
+                        output += "    for (i = 0; i < Math.min(x.length, y.length); i++) {\r\n";
+                        output += "      ctx.moveTo(width/2.0+x[i]/xMax*width/2.0, height/2.0-y[i]/yMax*height/2.0);\r\n";
+                        output += "      ctx.arc(width/2.0+x[i]/xMax*width/2.0, height/2.0-y[i]/yMax*height/2.0, 2, 0, 2*Math.PI, false);\r\n";
+                        output += "    }\r\n";
+                        output += "    ctx.fill();\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>\r\n";
+                        output += "  <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"20\" cellpadding=\"0\">\r\n";
+                        output += "    <tr>\r\n";
+                        output += "      <th><canvas id=\"lidar\"></canvas></th>\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	Tue Apr 28 13:59:27 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/LIDAR.cpp	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,160 @@
+/*
+ * LIDAR.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include <cmath>
+#include "LIDAR.h"
+
+using namespace std;
+
+const float LIDAR::DISTANCE_THRESHOLD = 0.01f;  // threshold for measured distance, given in [m]
+const float LIDAR::DEFAULT_DISTANCE = 10.0f;    // default distance > range of sensor, given in [m]
+const float LIDAR::M_PI = 3.1415926535897932f;  // the mathematical constant PI
+const float LIDAR::DISTANCES[] = {10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 1.702465271f, 1.699141254f, 1.69632544f, 1.692140952f, 1.689068974f, 1.68018005f, 1.676267878f, 1.666183663f, 1.671424841f, 1.66193261f, 1.655635528f, 1.653413439f, 1.653517463f, 1.657246512f, 1.655132925f, 1.650946698f, 1.65257254f, 1.66468045f, 1.23646674f, 1.236336928f, 1.251003597f, 1.353653575f, 1.322500662f, 1.304577326f, 1.299988461f, 1.314887448f, 1.320968206f, 1.320374568f, 1.251579003f, 1.235510016f, 1.233241663f, 1.243382483f, 1.314194811f, 1.318788838f, 1.438384163f, 1.419872177f, 1.368804223f, 1.347354445f, 1.342721118f, 1.354318279f, 1.366872708f, 1.369305298f, 1.383822604f, 1.508895291f, 1.493255504f, 1.475824515f, 1.435599178f, 1.445460826f, 1.462035909f, 1.654100964f, 1.644884494f, 1.707480307f, 1.701130213f, 1.660187941f, 1.634974006f, 1.61723344f, 1.620856564f, 1.798737613f, 1.779742116f, 1.77366344f, 1.77661504f, 1.777926039f, 1.920203375f, 1.935389367f, 2.291142292f, 2.328650253f, 2.363611643f, 2.448420103f, 2.487483266f, 2.57330313f, 2.545476969f, 2.040235771f, 2.028301999f, 2.014f, 1.98730823f, 1.972207393f, 1.955661781f, 1.944761168f, 1.923351242f, 1.909502815f, 1.903193369f, 1.875251983f, 1.874046424f, 1.857301806f, 1.845873235f, 1.837153505f, 1.817614371f, 1.803495495f, 1.796232168f, 1.784177401f, 1.781868963f, 1.775984797f, 1.764001134f, 1.761087448f, 1.753326267f, 1.75371748f, 1.745729933f, 1.742740658f, 1.737636613f, 1.741089889f, 1.735240617f, 1.735295076f, 1.728695462f, 1.720377865f, 1.657877257f, 1.727796574f, 1.734111011f, 1.729579429f, 1.736116356f, 1.743193908f, 1.745805545f, 1.750349965f, 1.750429662f, 1.754628166f, 1.760757223f, 1.766661541f, 1.766717012f, 1.776524697f, 1.161069335f, 1.148512081f, 1.14054373f, 1.135753494f, 1.134139321f, 1.147087617f, 1.168199041f, 1.17903223f, 1.18040205f, 1.183327934f, 1.147416228f, 1.210927331f, 1.217378331f, 1.203945597f, 1.227244067f, 1.237879235f, 0.547902364f, 0.544882556f, 0.548745843f, 0.548314691f, 0.553859188f, 0.558237405f, 0.562782374f, 0.572875205f, 0.577382023f, 0.587456381f, 0.593270596f, 0.595157122f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 1.826932128f, 1.764292776f, 1.757409742f, 1.728041956f, 1.704264064f, 1.688f, 1.679250428f, 1.66501051f, 1.644250589f, 1.634979205f, 1.626211548f, 1.608795823f, 1.589880499f, 1.58137788f, 1.575325998f, 1.560708173f, 1.550516043f, 1.54374253f, 1.532342651f, 1.520213472f, 1.512674783f, 1.507533416f, 1.497487229f, 1.494217186f, 1.48919072f, 1.232154617f, 1.358305194f, 1.313616382f, 1.260025397f, 1.133025154f, 1.117565658f, 1.100202254f, 1.100181803f, 1.169824773f, 1.168748476f, 1.164819729f, 1.220040983f, 1.203097669f, 1.200735191f, 1.189294329f, 1.186247866f, 1.195532517f, 1.229603188f, 1.472497538f, 1.474618595f, 1.479985473f, 1.480043918f, 1.484135439f, 1.490767923f, 1.496454476f, 1.501894803f, 1.511313667f, 1.516939682f, 1.525908582f, 1.535359893f, 1.544518695f, 1.549271119f, 1.555904881f, 1.575204114f, 1.580785248f, 0.959320593f, 0.920540059f, 0.905058009f, 0.900680298f, 0.898481497f, 0.902731965f, 0.918059911f, 1.718295085f, 1.721370675f, 1.735719159f, 1.763130455f, 1.775434595f, 1.817423726f, 1.836723441f, 1.847665825f, 1.884798663f, 1.897461462f, 1.83701742f, 1.811276898f, 1.759177649f, 1.740189932f, 1.702600364f, 1.687345845f, 1.637890411f, 1.604450373f, 1.589151031f, 1.55510289f, 1.544042098f, 1.516327801f, 1.502226681f, 1.479634076f, 1.483579792f, 1.518056982f, 1.568964308f, 1.602244675f, 1.663f, 1.700264685f, 1.771085543f, 1.812491379f, 1.888618543f, 1.937385093f, 2.032088827f, 2.089617429f, 2.205471605f, 2.275026373f, 2.345580738f, 2.499928999f, 2.581471286f, 2.784285366f, 2.885689519f, 2.858447306f, 2.850508025f, 2.832713364f, 2.828422882f, 2.812354352f, 2.808188206f, 2.789411407f, 2.789161343f, 2.77675368f, 2.765194568f, 1.967565247f, 1.958f, 2.397585661f, 2.75211991f, 2.743884108f, 2.743676366f, 2.746035688f, 2.735854528f, 10.0f, 10.0f, 10.0f, 2.76492206f, 2.761207888f, 2.762739582f, 2.766510618f, 2.788146338f, 2.786430153f, 2.801847426f, 2.811054073f, 2.691653024f, 2.664378352f, 2.401709391f, 2.204667775f, 2.12351713f, 2.141373625f, 2.14578121f, 2.165700349f, 2.171425799f, 2.185005721f, 2.197850768f, 2.21938122f, 2.229375025f, 2.23809964f, 2.265003532f, 2.644680132f, 2.54522003f, 2.527676008f, 2.480120158f, 2.52638279f, 2.386449455f, 2.36217802f, 2.291129198f, 2.094351451f, 2.007193314f, 2.009421807f, 2.047382719f, 2.035974951f, 1.865168089f, 1.820468346f, 1.800660157f, 1.80447721f, 1.836480329f, 1.730293906f, 1.678679541f, 1.66250203f, 1.677434052f, 1.719175675f, 1.720679226f, 1.622129465f, 1.618845576f, 1.634181141f, 10.0f, 10.0f, 10.0f, 10.0f};
+
+/**
+ * Creates a LIDAR object.
+ * @param serial a reference to a serial interface to communicate with the laser scanner.
+ */
+LIDAR::LIDAR(RawSerial& serial) : serial(serial) {
+    
+    // initialize serial interface
+    
+    serial.baud(115200);
+    serial.format(8, SerialBase::None, 1);
+    
+    // initialize local values
+    
+    headerCounter = 0;
+    dataCounter = 0;
+    
+    for (unsigned short i = 0; i < 360; i++) distances[i] = DEFAULT_DISTANCE;
+    
+    simulation = true;
+    
+    // start serial interrupt
+    
+    serial.attach(callback(this, &LIDAR::receive), RawSerial::RxIrq);
+    
+    // start the continuous operation of the LIDAR
+    
+    serial.putc(START_FLAG);
+    serial.putc(SCAN);
+}
+
+/**
+ * Stops the lidar and deletes this object.
+ */
+LIDAR::~LIDAR() {
+    
+    // stop the LIDAR
+    
+    serial.putc(START_FLAG);
+    serial.putc(STOP);
+}
+
+/**
+ * Get a list of points of a full 360 degree scan.
+ * @return a deque vector of 360 point objects.
+ */
+deque<Point> LIDAR::getScan() {
+    
+    deque<Point> scan;
+    
+    for (unsigned short i = 0; i < 360; i++) {
+        
+        if (simulation) {
+            
+            // use simulated distances, because LIDAR is not available
+            
+            scan.push_back(Point(DISTANCES[i]-0.002f*(rand()%10), (float)i*M_PI/180.0f));
+            
+        } else {
+            
+            // use latest measurements from actual LIDAR
+            
+            scan.push_back(Point(distances[i], (float)i*M_PI/180.0f));
+        }
+    }
+    
+    return scan;
+}
+
+/**
+ * Get a list of points which are part of beacons.
+ * @return a deque vector of points that are beacons.
+ */
+deque<Point> LIDAR::getBeacons() {
+    
+    // get a list of all points of a scan
+    
+    deque<Point> scan = getScan();
+    
+    // create a list of points of beacons
+    
+    deque<Point> beacons;
+    
+    // bitte implementieren!
+    for (unsigned short i = 0; i < 358; i++) {
+        
+        if ((DISTANCES[i] < 1) && ((((DISTANCES[i+1]-DISTANCES[i])<0.1)&&(DISTANCES[i+2]-DISTANCES[i+1])<0.1))) { //||((DISTANCES[i+1]-DISTANCES[i])>0.5))
+             
+             beacons.push_back(Point(distances[i], (float)i*M_PI/180.0f));
+        
+        }  
+
+    }
+    
+    return beacons;
+}
+
+/**
+ * This method is called by the serial interrupt service routine.
+ * It handles the reception of measurements from the LIDAR.
+ */
+void LIDAR::receive() {
+    
+    // read received characters while input buffer is full
+    
+    if (serial.readable()) {
+        
+        // read single character from serial interface
+        
+        char c = serial.getc();
+        
+        // add this character to the header or to the data buffer
+        
+        if (headerCounter < HEADER_SIZE) {
+            headerCounter++;
+        } else {
+            if (dataCounter < DATA_SIZE) {
+                data[dataCounter] = c;
+                dataCounter++;
+            }
+            if (dataCounter >= DATA_SIZE) {
+                
+                // data buffer is full, process measurement
+                
+                char quality = data[0] >> 2;
+                short angle = 360-(((unsigned short)data[1] | ((unsigned short)data[2] << 8)) >> 1)/64;
+                float distance = (float)((unsigned short)data[3] | ((unsigned short)data[4] << 8))/4000.0f;
+                
+                if ((quality < QUALITY_THRESHOLD) || (distance < DISTANCE_THRESHOLD)) distance = DEFAULT_DISTANCE;
+                
+                // store distance in [m] into array of full scan
+                
+                while (angle < 0) angle += 360;
+                while (angle >= 360) angle -= 360;
+                distances[angle] = distance;
+                
+                // reset data counter and simulation flag
+                
+                dataCounter = 0;
+                simulation = false;
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LIDAR.h	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,54 @@
+/*
+ * LIDAR.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef LIDAR_H_
+#define LIDAR_H_
+
+#include <cstdlib>
+#include <deque>
+#include <mbed.h>
+#include "Point.h"
+
+/**
+ * This is a device driver class for the Slamtec RP LIDAR A1.
+ */
+class LIDAR {
+    
+    public:
+        
+                        LIDAR(RawSerial& serial);
+        virtual         ~LIDAR();
+        deque<Point>    getScan();
+        deque<Point>    getBeacons();
+        
+    private:
+        
+        static const unsigned short HEADER_SIZE = 7;
+        static const unsigned short DATA_SIZE = 5;
+        
+        static const char   START_FLAG = 0xA5;
+        static const char   SCAN = 0x20;
+        static const char   STOP = 0x25;
+        static const char   RESET = 0x40;
+        
+        static const char   QUALITY_THRESHOLD = 10;     // quality threshold used for accepting measurements
+        static const float  DISTANCE_THRESHOLD;         // threshold for measured distance, given in [m]
+        static const float  DEFAULT_DISTANCE;           // default distance > range of sensor, given in [m]
+        static const float  M_PI;                       // the mathematical constant PI
+        static const float  DISTANCES[];                // simulated distance for every angle value, given in [m]
+        
+        RawSerial&  serial;             // reference to serial interface for communication
+        char        headerCounter;
+        char        dataCounter;
+        char        data[DATA_SIZE];
+        float       distances[360];     // measured distance for every angle value, given in [m]
+        bool        simulation;         // flag to indicate if scans are only simulated
+        
+        void        receive();
+};
+
+#endif /* LIDAR_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Main.cpp	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,76 @@
+/*
+ * Main.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include <mbed.h>
+#include <EthernetInterface.h>
+#include "LIDAR.h"
+#include "HTTPServer.h"
+#include "HTTPScriptLIDAR.h"
+
+int main() {
+    
+    // initialise digital inputs and outputs
+    
+    printf("Initialise digital inputs and outputs...\r\n");
+    
+    DigitalIn button(USER_BUTTON);
+    
+    DigitalOut ledGreen(LED1);
+    DigitalOut ledBlue(LED2);
+    DigitalOut ledRed(LED3);
+    
+    // create LIDAR device driver
+    
+    printf("Create LIDAR device driver...\r\n");
+    
+    PwmOut pwm(PE_9);
+    pwm.period(0.00005f);
+    pwm.write(0.5f);
+    
+    ThisThread::sleep_for(500);
+    
+    RawSerial serial(PG_14, PG_9);
+    LIDAR lidar(serial);
+    
+    // create ethernet interface and webserver
+    
+    printf("Create ethernet interface and webserver (please wait!)...\r\n");
+    
+    EthernetInterface* ethernet = new EthernetInterface();
+    ethernet->set_network("169.254.20.110", "255.255.0.0", "0.0.0.0"); // configure IP address, netmask and gateway address
+    ethernet->connect();
+    
+    HTTPServer* httpServer = new HTTPServer(*ethernet);
+    httpServer->add("lidar", new HTTPScriptLIDAR(lidar));
+    
+    // enter main loop
+    
+    printf("Enter main loop...\r\n");
+    
+    while (true) {
+        
+        // set LEDs on microcontroller
+        
+        ledGreen = 1;
+        ledBlue = 0;
+        ledRed = 0;
+        
+        ThisThread::sleep_for(100);
+        
+        ledGreen = 0;
+        ledBlue = 1;
+        ledRed = 0;
+        
+        ThisThread::sleep_for(100);
+        
+        ledGreen = 0;
+        ledBlue = 0;
+        ledRed = 1;
+        
+        ThisThread::sleep_for(100);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Point.cpp	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,77 @@
+/*
+ * Point.cpp
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#include <cmath>
+#include "Point.h"
+
+using namespace std;
+
+/**
+ * Creates a Point object.
+ */
+Point::Point() {
+    
+    x = 0.0f;
+    y = 0.0f;
+    r = 0.0f;
+    alpha = 0.0f;
+}
+
+/**
+ * Creates a Point object from given polar coordinates.
+ * @param r the radius of a point.
+ * @param alpha the angle of a point.
+ */
+Point::Point(float r, float alpha) {
+    
+    x = r*cos(alpha);
+    y = r*sin(alpha);
+    
+    this->r = r;
+    this->alpha = alpha;
+}
+
+/**
+ * Deletes this object.
+ */
+Point::~Point() {}
+
+/**
+ * Calculates the distance of this point from the origin.
+ */
+float Point::distance() {
+    
+    return sqrt(x*x+y*y);
+}
+
+/**
+ * Calculates the distance between this point and a given point.
+ * @param point another point to calculate the distance to.
+ */
+float Point::distance(Point& point) {
+    
+    return sqrt((x-point.x)*(x-point.x)+(y-point.y)*(y-point.y));
+}
+
+/**
+ * Calculates the manhattan distance of this point from the origin.
+ * This calculation is only an approximation, but a lot faster to compute.
+ */
+float Point::manhattanDistance() {
+    
+    return fabs(x)+fabs(y);
+}
+
+/**
+ * Calculates the manhattan distance between this point and a given point.
+ * This calculation is only an approximation, but a lot faster to compute.
+ * @param point another point to calculate the distance to.
+ */
+float Point::manhattanDistance(Point& point) {
+    
+    return fabs(x-point.x)+fabs(y-point.y);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Point.h	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,34 @@
+/*
+ * Point.h
+ * Copyright (c) 2020, ZHAW
+ * All rights reserved.
+ */
+
+#ifndef POINT_H_
+#define POINT_H_
+
+#include <cstdlib>
+
+/**
+ * This class stores the coordinates of a point in two dimensions.
+ */
+class Point {
+    
+    public:
+        
+        float           x;
+        float           y;
+        float           r;
+        float           alpha;
+        
+                        Point();
+                        Point(float r, float alpha);
+        virtual         ~Point();
+        float           distance();
+        float           distance(Point& point);
+        float           manhattanDistance();
+        float           manhattanDistance(Point& point);
+};
+
+#endif /* POINT_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ThreadFlag.cpp	Tue Apr 28 13:59:27 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	Tue Apr 28 13:59:27 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_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Tue Apr 28 13:59:27 2020 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#cf4f12a123c05fcae83fc56d76442015cb8a39e9
Binary file resources/official_armmbed_example_badge.png has changed