Merge remote-tracking branch 'midgard/main'

This commit is contained in:
redfast00 2021-09-19 04:09:54 +02:00
commit e070010401
No known key found for this signature in database
GPG key ID: 5946E0E34FD0553C
4 changed files with 468 additions and 6 deletions

218
frontend/index.html Normal file
View file

@ -0,0 +1,218 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>LAP</title>
<style type="text/css">
html, body {
background-color: #222;
color: #fff;
}
body {
font-family: monospace;
}
input, button, textarea {
color: inherit;
background-color: #222;
padding: 1ex;
border-radius: 1ex;
border: 1px solid #777;
font-family: inherit;
font-size: inherit;
box-sizing: border-box;
box-shadow: 0.4em 0.4em 1em #0d0d0d inset;
}
input:focus, button:focus, textarea:focus {
border-color: #6688ff;
outline: none;
}
button {
padding: 0.5ex 1ex;
box-shadow: -0.4em -0.4em 1em #0d0d0d inset, 0.2em 0.2em 0.5em #1d1d1d;
cursor: pointer;
}
button:hover {
border-color: #656565;
}
button:active {
box-shadow: 0.4em 0.4em 1em #0d0d0d inset, 0.2em 0.2em 0.5em #1d1d1d;
}
input[disabled], button[disabled], textarea[disabled] {
box-shadow: none;
border-color: #777;
}
button[disabled] {
color: #777;
cursor: default;
}
svg {
width: 100%;
height: 50px;
}
h1 {
text-align: center;
}
.yesscript {
display: none;
}
.segment {
font-size: 70%;
display: inline-block;
height: 1em;
line-height: 1em;
cursor: pointer;
border: 1px solid transparent;
margin: 1px;
margin-bottom: 2em;
padding: 2px;
box-shadow: 0 0.2em 0.5em #1d1d1d;
position: relative;
z-index: 100;
}
.segment:first-child {
border-top-left-radius: 0.75em;
border-bottom-left-radius: 0.75em;
}
.segment:last-child {
border-top-right-radius: 0.75em;
border-bottom-right-radius: 0.75em;
}
.segment.active {
border-color: #fff;
z-index: 101;
}
.segment:focus, .segment:hover {
border-color: #6688ff;
}
#owner_label {
position: absolute;
display: none;
z-index: 300;
background-color: #4466dd;
border-radius: 0.5em;
padding: 0.2em 0.4em;
color: white;
font-size: 1em;
line-height: 1em;
}
.led {
display: inline-block;
height: 6px;
width: 6px;
border-radius: 6px;
margin-left: 2px;
margin-right: 2px;
background-color: #fff;
opacity: 0.5;
}
.segment.active .led {
opacity: 0.75;
}
#segment-control, #program {
display: none;
}
#owner_line {
line-height: 3em;
}
#lua_editor {
width: 100%;
height: 200px;
}
</style>
<script type="application/javascript">
(function() {
"use strict";
var styleObject = document.createElement("style");
styleObject.innerHTML = ".yesscript { display: block; }";
document.head.appendChild(styleObject);
})();
</script>
</head>
<body>
<div id="owner_label"></div>
<h1>Zeus WPI LED-Automaten-Programmatie</h1>
<p class="noscript">Voor deze applicatie is helaas JavaScript vereist.</p>
<div id="configuration" class="yesscript">
<h2>Configuratie</h2>
Je schuilnaam: <input type="text" name="us" id="us" onchange="ledStripControl.updateUs()">
</div>
<div id="led-strip" class="yesscript">
<h2>LED-strip</h2>
<div id="segments">
LED-strip wordt geladen...
</div>
</div>
<div id="segment-control">
<h2>Segmentcontrole</h2>
<div>
Segment <b id="active_segment_id"></b>
van LED <b id="active_segment_begin"></b>
tot <b id="active_segment_end"></b>
</div>
<div id="owner_line">Toegewezen aan: <b id="active_segment_owner"></b> <button id="claim_button"></button> <button id="release_button"></button></div>
</div>
<div id="program">
<h2>Programma</h2>
<p id="not-your-own">Dit segment is niet van jou. Je kunt de code enkel bekijken.</p>
<textarea id="lua_editor" spellcheck="false"></textarea>
<div id="program-controls">
<button id="publish-button">Publiceren</button>
<p>De code wordt niet bestendig bewaard. <strong>Sla ze zelf op op je computer.</strong> Gebruik dit veld bij voorkeur enkel om naar te kopiëren-en-plakken.</p>
</div>
<div id="program-instructions">
<p>Programmeer je segment in Lua. Voor je code lijkt het alsof je LED 0 tot <span id="active_segment_last_virtual">x</span> hebt. Extra beschikbare functies:</p>
<dl>
<dt>led(led_nr, r, g, b)</dt>
<dd>Stel LED <i>led_nr</i> in op de kleur met gegeven RGB-waarden (0255)</dd>
<dt>ledamount(something, probably)</dt>
<dd>Uhh</dd>
<dt>delay(ms)</dt>
<dd>Wacht gedurende <i>ms</i> milliseconden</dd>
<dt>waitframes(frames)</dt>
<dd>Wacht gedurende <i>frames</i> frames</dd>
<dt>print(message)</dt>
<dd>Stuur <i>message</i> naar de console</dd>
</dl>
</div>
</div>
<script type="application/javascript">
(function() {
"use strict";
var objects = document.getElementsByClassName("noscript");
for (var i in objects) {
if (objects.hasOwnProperty(i)) {
objects[i].parentElement.removeChild(objects[i]);
}
}
})();
</script>
<script type="application/javascript" src="main.js"></script>
</body>
</html>

231
frontend/main.js Normal file
View file

@ -0,0 +1,231 @@
var ledStripControl = (function() {
"use strict";
var HOST = "http://localhost:8080";
var segments = null;
var activeSegmentId = null;
var us = null;
function xhr(url, method, data, callback) {
var oReq = new XMLHttpRequest();
if (callback) {
function reqListener() {
var json = null;
try { json = JSON.parse(this.responseText); } catch(e) {}
callback(json);
}
oReq.addEventListener("load", reqListener);
}
oReq.open(method, url);
oReq.send(data);
}
function getJson(url, callback) {
xhr(url, "GET", "", callback);
}
function putJson(url, data, callback) {
xhr(url, "PUT", JSON.stringify(data), callback);
}
function updateUs() {
us = document.getElementById("us").value;
showSegments();
}
updateUs();
function saveAndShowSegments(segs) {
segments = {};
for (var i in segs) {
segments[segs[i].id] = segs[i];
}
showSegments();
}
function fetchSegments() {
getJson(HOST + "/api/segments.json", saveAndShowSegments);
}
function activateSegment(segment) {
activeSegmentId = segment.id;
getJson(HOST + "/api/segments.json", saveAndShowSegments);
showSegments();
document.getElementById("segment-control").style.display = "block";
}
function repeatString(text, amount) {
var result = "";
for (var i = 0; i < amount; i++) {
result += text;
}
return result;
}
function showSegmentEventListener(e) {
if (e.currentTarget.dataset["segment"] !== "true") return;
var id = e.currentTarget.dataset["id"];
activateSegment(segments[id]);
e.stopPropagation();
}
function showOwnerEventListener(e) {
if (e.currentTarget.dataset["segment"] !== "true") return;
var owner = e.currentTarget.dataset["owner"];
if (owner) {
document.getElementById("owner_label").innerText = owner;
} else {
document.getElementById("owner_label").innerHTML = "<i>Vrij</i>";
}
document.getElementById("owner_label").style.display = "block";
document.getElementById("owner_label").style.left = (e.currentTarget.clientWidth/2 + e.currentTarget.offsetLeft - document.getElementById("owner_label").clientWidth/2) + "px";
document.getElementById("owner_label").style.top = (e.currentTarget.offsetTop - document.getElementById("owner_label").clientHeight - 2) + "px";
e.stopPropagation();
}
function hideOwnerEventListener(e) {
if (e.currentTarget.dataset["segment"] !== "true") return;
document.getElementById("owner_label").innerHTML = "";
document.getElementById("owner_label").style.display = "none";
}
function updatePublishButton() {
var activeSegment = activeSegmentId !== null ? segments[activeSegmentId] : null;
if (document.getElementById("lua_editor").value == activeSegment.code) {
document.getElementById("publish-button").innerText = "Gepubliceerd";
document.getElementById("publish-button").setAttribute("disabled", "disabled");
} else {
document.getElementById("publish-button").innerText = "Publiceren";
document.getElementById("publish-button").removeAttribute("disabled");
}
}
function showSegments() {
var segmentsContainer = document.getElementById("segments");
segmentsContainer.innerHTML = "";
var prevSegEnd = 0;
if (segments !== null) for (var i in segments) {
if (!segments.hasOwnProperty(i)) continue;
var seg = segments[i];
var color = seg.owner === "" ? "#555" : seg.owner === us ? "#050" : "#700";
var unsegmented = parseFloat(seg.begin) - prevSegEnd;
if (unsegmented > 0) {
var unsegmented_el = document.createElement("span");
unsegmented_el.className = "unsegmented";
unsegmented_el.innerHTML = repeatString("<span class='led'></span>", unsegmented);
segmentsContainer.append(unsegmented_el);
}
var rect = document.createElement("a");
rect.className = seg.id === activeSegmentId ? "active segment" : "segment";
rect.style.backgroundColor = color;
rect.id = "segment" + seg.id;
rect.href = "#segment" + seg.id;
rect.dataset["segment"] = "true";
rect.dataset["owner"] = seg.owner;
rect.dataset["id"] = seg.id;
rect.addEventListener("click", showSegmentEventListener);
rect.addEventListener("focus", showOwnerEventListener);
rect.addEventListener("blur", hideOwnerEventListener);
rect.addEventListener("mouseover", showOwnerEventListener);
rect.addEventListener("mouseout", hideOwnerEventListener);
rect.innerHTML = repeatString("<span class='led'></span>", seg.length);
segmentsContainer.appendChild(rect);
prevSegEnd = seg.begin + seg.length;
}
var activeSegment = activeSegmentId !== null ? segments[activeSegmentId] : null;
if (activeSegment !== null) {
document.getElementById("active_segment_id").innerText = activeSegmentId;
document.getElementById("active_segment_begin").innerText = activeSegment.begin;
document.getElementById("active_segment_end").innerText = activeSegment.begin + activeSegment.length - 1;
document.getElementById("active_segment_last_virtual").innerText = activeSegment.length - 1;
updatePublishButton();
document.getElementById("lua_editor").value = activeSegment.code;
if (activeSegment.owner !== "" && activeSegment.owner === us) {
document.getElementById("release_button").style.display = "";
document.getElementById("release_button").innerText = "Onteigen";
document.getElementById("release_button").removeAttribute("disabled");
document.getElementById("lua_editor").removeAttribute("disabled");
document.getElementById("not-your-own").style.display = "none";
document.getElementById("program-controls").style.display = "block";
document.getElementById("program-instructions").style.display = "block";
} else {
document.getElementById("release_button").style.display = "none";
document.getElementById("lua_editor").setAttribute("disabled", "disabled");
document.getElementById("not-your-own").style.display = "block";
document.getElementById("program-controls").style.display = "none";
document.getElementById("program-instructions").style.display = "none";
}
if (activeSegment.owner !== "") {
document.getElementById("active_segment_owner").innerText = activeSegment.owner;
document.getElementById("claim_button").style.display = "none";
document.getElementById("program").style.display = "block";
} else {
document.getElementById("active_segment_owner").innerText = "nog niemand";
document.getElementById("claim_button").style.display = "";
document.getElementById("claim_button").innerText = "Eigen je toe";
document.getElementById("claim_button").removeAttribute("disabled");
document.getElementById("program").style.display = "none";
}
}
}
document.getElementById("claim_button").addEventListener("click", function() {
document.getElementById("claim_button").innerText = "Bezig met toe-eigenen...";
document.getElementById("claim_button").setAttribute("disabled", "disabled");
var activeSegment = segments[activeSegmentId];
if (!activeSegment) { throw new Error("Trying to claim segment but no segment active"); }
putJson(HOST + "/api/code.json", {
"id": activeSegmentId,
"owner": us,
"code": activeSegment.code
}, fetchSegments);
});
document.getElementById("release_button").addEventListener("click", function() {
document.getElementById("release_button").innerText = "Bezig met onteigenen...";
document.getElementById("release_button").setAttribute("disabled", "disabled");
var activeSegment = segments[activeSegmentId];
if (!activeSegment) { throw new Error("Trying to release segment but no segment active"); }
putJson(HOST + "/api/code.json", {
"id": activeSegmentId,
"owner": "",
"code": activeSegment.code
}, fetchSegments);
});
document.getElementById("publish-button").addEventListener("click", function() {
document.getElementById("publish-button").innerText = "Bezig met publiceren...";
document.getElementById("publish-button").setAttribute("disabled", "disabled");
var activeSegment = segments[activeSegmentId];
if (!activeSegment) { throw new Error("Trying to update code of segment but no segment active"); }
putJson(HOST + "/api/code.json", {
"id": activeSegmentId,
"owner": activeSegment.owner,
"code": document.getElementById("lua_editor").value
}, fetchSegments);
});
document.getElementById("lua_editor").addEventListener("keyup", updatePublishButton);
document.getElementById("lua_editor").addEventListener("change", updatePublishButton);
fetchSegments();
return {
updateUs: updateUs,
};
})();

View file

@ -280,6 +280,8 @@ int main(int argc, char** argv)
}
svr.Get("/api/segments.json", [](const httplib::Request &, httplib::Response &res) {
res.set_header("Access-Control-Allow-Origin", "*");
res.set_header("Access-Control-Allow-Methods", "GET");
json j;
int i = 0;
for (LedSegment* ledsegment : ledsegments) {
@ -296,6 +298,8 @@ int main(int argc, char** argv)
});
svr.Put("/api/code.json", [](const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) {
res.set_header("Access-Control-Allow-Origin", "*");
res.set_header("Access-Control-Allow-Methods", "PUT");
if (req.is_multipart_form_data()) {
res.set_content("No multipart forms allowed", "text/plain");
return true;
@ -319,6 +323,12 @@ int main(int argc, char** argv)
return true;
});
svr.Options("/api/code.json", [](const httplib::Request &req, httplib::Response &res) {
res.set_header("Access-Control-Allow-Origin", "*");
res.set_header("Access-Control-Allow-Methods", "PUT");
return true;
});
std::thread httpserverthread(starthttpserver);
ws2811_return_t ret;

11
submit.py Normal file → Executable file
View file

@ -1,10 +1,12 @@
#!/usr/bin/env python3
import os
import json
import requests
import time
SERVER = os.getenv("LEDSTRIP_SERVER", "http://10.1.0.212:8080")
for i in range(10):
@ -13,11 +15,12 @@ for i in range(10):
c = codefile.read()
except:
continue
j = {
payload = {
"code": c,
"owner": "j",
"id": i
}
r = requests.put('http://10.1.0.212:8080/api/code.json', json=j)
r = requests.put(SERVER + '/api/code.json', json=payload)
print(r)
print(r.text)