Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:893a1e710078, committed 2020-04-28
- Comitter:
- oehlemar
- Date:
- Tue Apr 28 13:59:27 2020 +0000
- Child:
- 1:5201940a41c1
- Commit message:
- initial publish
Changed in this revision
--- /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(ðernet);
+ 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