aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjakobst1n <jakob.stendahl@outlook.com>2025-12-01 20:48:06 +0100
committerjakobst1n <jakob@jakobstendahl.no>2025-12-01 20:48:06 +0100
commitefb0359655d5ab554afe10e5d193bb28eb865b6e (patch)
tree43a6439430e1ab7bdfd1dc223cfa340017264fac
parent8822f73d4eebb90a20bb54def27ceb47a9d693d6 (diff)
downloadLINSC-master.tar.gz
LINSC-master.zip
Add testing files for UIHEADmaster
-rw-r--r--simplehttp.py11
-rw-r--r--ui.html444
2 files changed, 455 insertions, 0 deletions
diff --git a/simplehttp.py b/simplehttp.py
new file mode 100644
index 0000000..18fc054
--- /dev/null
+++ b/simplehttp.py
@@ -0,0 +1,11 @@
+from http.server import HTTPServer, SimpleHTTPRequestHandler, test
+import sys
+
+class CORSRequestHandler(SimpleHTTPRequestHandler):
+ def end_headers(self):
+ self.send_header("Access-Control-Allow-Origin", "*")
+ self.send_header("Access-Control-Allow-Methods", "*")
+ SimpleHTTPRequestHandler.end_headers(self)
+
+if __name__ == "__main__":
+ test(CORSRequestHandler, HTTPServer, port=8000)
diff --git a/ui.html b/ui.html
new file mode 100644
index 0000000..c8e5b77
--- /dev/null
+++ b/ui.html
@@ -0,0 +1,444 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Microscope UI</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <style>
+body {
+ font-family: 'Segoe UI', Arial, sans-serif;
+ background-color: #1a1a1a;
+ color: #e0e0e0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 100vh;
+ margin: 0;
+}
+
+.main-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+ padding: 25px;
+ background-color: #2b2b2b;
+ border-radius: 12px;
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);
+ justify-content: center;
+ width: fit-content;
+ max-width: 90%;
+}
+
+.status-indicators-container {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ /* No background here, the children have their own */
+}
+
+.command-controls {
+ flex: 1 1 300px;
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ padding: 15px;
+ background-color: #3c3c3c;
+ border-radius: 8px;
+}
+
+.display-box {
+ background-color: #3c3c3c; /* This is what makes each box visually separate */
+ border-radius: 8px;
+ padding: 15px 20px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+}
+
+/* The rest of the CSS for labels, values, buttons, etc. remains the same */
+
+.label {
+ text-transform: uppercase;
+ font-size: 0.7em;
+ letter-spacing: 1px;
+ color: #999;
+ margin-bottom: 5px;
+}
+
+.operation-mode .value {
+ font-size: 1.5em;
+ font-weight: 600;
+ color: #88ff88;
+}
+
+.busy {
+ background-color: #734b00;
+}
+
+.busy .value {
+ color: #ffbf00;
+}
+
+.error {
+ background-color: #712f20;
+}
+
+.error .value {
+ color: #f93c3c;
+}
+
+.coordinate-display {
+ flex: 1;
+ position: relative;
+}
+
+.coord-label {
+ font-size: 2em;
+ font-weight: bold;
+ color: #66bbff;
+ margin-bottom: 5px;
+}
+
+.current-value {
+ font-size: 2.5em;
+ font-weight: 700;
+ color: #fff;
+ margin: 5px 0;
+}
+
+.details {
+ font-size: 0.9em;
+ color: #aaa;
+ margin-top: 10px;
+ line-height: 1.4;
+}
+
+.limit-status {
+ position: absolute;
+ top: -10px;
+ right: -10px;
+ background-color: #ff3333;
+ color: #fff;
+ padding: 4px 8px;
+ border-radius: 20px;
+ font-size: 0.7em;
+ font-weight: bold;
+ text-transform: uppercase;
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity 0.3s;
+}
+
+.limit-status.active {
+ visibility: visible;
+ opacity: 1;
+}
+
+.image-info .image-value {
+ display: flex;
+ align-items: baseline;
+ gap: 5px;
+ font-weight: bold;
+}
+
+.image-number {
+ font-size: 2em;
+ color: #ffd700;
+}
+
+.degree-value {
+ font-size: 1.2em;
+ color: #ffd700;
+}
+
+.directional-pad {
+ display: grid;
+ grid-template-areas:
+ ". y-plus ."
+ "x-minus . x-plus"
+ ". y-minus .";
+gap: 10px;
+max-width: 200px;
+margin: 0 auto;
+}
+
+.d-pad-x-minus { grid-area: x-minus; }
+.d-pad-x-plus { grid-area: x-plus; }
+.d-pad-y-plus { grid-area: y-plus; }
+.d-pad-y-minus { grid-area: y-minus; }
+
+.arrow-btn {
+ background-color: #555;
+ color: #fff;
+ border: none;
+ padding: 10px 15px;
+ font-size: 1.2em;
+ font-weight: bold;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.arrow-btn:hover {
+ background-color: #666;
+}
+
+.options-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ justify-content: center;
+}
+
+.option-btn {
+ background-color: #555;
+ color: #fff;
+ border: none;
+ padding: 8px 12px;
+ font-size: 0.9em;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.option-btn:hover {
+ background-color: #666;
+}
+
+.image-options {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+}
+
+.image-select,
+.image-pos-input,
+.command-input {
+ background-color: #444;
+ color: #fff;
+ border: 1px solid #555;
+ padding: 6px 10px;
+ border-radius: 6px;
+ font-size: 0.9em;
+}
+
+.image-pos-input {
+ width: 60px;
+}
+
+.command-line-box {
+ display: flex;
+ gap: 10px;
+}
+
+.command-input {
+ flex-grow: 1;
+}
+
+.send-btn {
+ background-color: #66bbff;
+ color: #fff;
+ border: none;
+ padding: 8px 15px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-weight: bold;
+ transition: background-color 0.2s;
+}
+
+.send-btn:hover {
+ background-color: #55aaff;
+}
+ </style>
+ </head>
+
+ <body>
+
+ <div class="main-container">
+ <div class="status-indicators-container">
+ <div class="display-box operation-mode">
+ <span class="label">Operation Mode <span id="time-remaining"></span></span>
+ <span class="value" id="operation">MANUAL</span>
+ </div>
+
+ <div class="display-box coordinate-display">
+ <div class="coord-label">X</div>
+ <span class="current-value" id="xPos">-</span>
+ <div class="details">
+ <span class="home-coord">Home: <span id="xHome">-</span></span>
+ <span class="range">Range: <span id="xLower">-</span>-<span id="xUpper">-</span></span>
+ </div>
+ <div class="limit-status" id="xLimit">Limit Active</div>
+ </div>
+
+ <div class="display-box coordinate-display">
+ <div class="coord-label">Y</div>
+ <span class="current-value" id="yPos">-</span>
+ <div class="details">
+ <span class="home-coord">Home: <span id="yHome">-</span></span>
+ <span class="range">Range: <span id="yLower">-</span>-<span id="yUpper">-</span></span>
+ </div>
+ <div class="limit-status" id="yLimit">Limit Active</div>
+ </div>
+
+ <div class="display-box image-info">
+ <span class="label">Image</span>
+ <div class="image-value">
+ <span class="image-number">3</span>
+ <span class="degree-value">180°</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="command-controls">
+ <div class="directional-pad">
+ <button class="arrow-btn d-pad-y-plus" id="btnIncY">Y+</button>
+ <button class="arrow-btn d-pad-x-minus" id="btnDecX">X-</button>
+ <button class="arrow-btn d-pad-x-plus" id="btnIncX">X+</button>
+ <button class="arrow-btn d-pad-y-minus" id="btnDecY">Y-</button>
+ </div>
+
+ <div class="options-row">
+ <button class="option-btn" id="btnCancel">CANCEL</button>
+ <button class="option-btn" id="btnHome">Home</button>
+ <button class="option-btn" id="btnCenter">Center</button>
+ <button class="option-btn" id="btnCalibrate">Calibrate</button>
+ <button class="option-btn" id="btnDismantle">Dismantle</button>
+ <button class="option-btn" id="btnToPos">Go to Position</button>
+ <div class="image-options">
+ <select class="image-select">
+ <option value="1">Image 1</option>
+ <option value="2">Image 2</option>
+ <option value="3">Image 3</option>
+ <option value="4">Image 4</option>
+ <option value="5">Image 5</option>
+ <option value="6">Image 6</option>
+ </select>
+ <button class="option-btn go-image-btn" id="btnSelectImg">Go</button>
+ <input type="number" class="image-pos-input" placeholder="°" min="0" max="360">
+ <button class="option-btn go-pos-btn" id="btnSelectDeg">Go</button>
+ </div>
+ </div>
+
+ <div class="command-line-box">
+ <input type="text" class="command-input" placeholder="Enter command...">
+ <button class="send-btn">Send</button>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ let server_address = "http://10.42.0.1:8000"
+
+ function updateState(stage) {
+ document.querySelector("#operation").innerHTML = stage.operation;
+ document.querySelector(".operation-mode").classList.remove("error");
+ if (stage.operation != "MANUAL") {
+ document.querySelector(".operation-mode").classList.add("busy");
+ } else {
+ document.querySelector(".operation-mode").classList.remove("busy");
+ }
+
+ if (stage.time_remaining > 0) {
+ document.querySelector("#time-remaining").innerHTML = `(~${Math.round(stage.time_remaining)}s)`;
+ } else {
+ document.querySelector("#time-remaining").innerHTML = ``;
+ }
+
+ document.querySelector("#xPos").innerHTML = stage.x.pos;
+ document.querySelector("#xLower").innerHTML = stage.x.lower;
+ document.querySelector("#xUpper").innerHTML = stage.x.upper;
+ document.querySelector("#xHome").innerHTML = stage.x.home;
+ if (stage.x.limit) {
+ document.querySelector("#xLimit").classList.add("active");
+ } else {
+ document.querySelector("#xLimit").classList.remove("active");
+ }
+
+ document.querySelector("#yPos").innerHTML = stage.y.pos;
+ document.querySelector("#yLower").innerHTML = stage.y.lower;
+ document.querySelector("#yUpper").innerHTML = stage.y.upper;
+ document.querySelector("#yHome").innerHTML = stage.y.home;
+ if (stage.y.limit) {
+ document.querySelector("#yLimit").classList.add("active");
+ } else {
+ document.querySelector("#yLimit").classList.remove("active");
+ }
+
+ }
+
+ const intervalId = setInterval(async function() {
+ try {
+ let res = await fetch(`${server_address}/state`);
+ let data = await res.json();
+ updateState(data)
+ } catch (e) {
+ document.querySelector("#operation").innerHTML = "CON ERR";
+ document.querySelector(".operation-mode").classList.add("error");
+ console.error(e);
+ }
+ }, 500);
+
+ document.querySelector("#btnCancel").onmousedown = function() {
+ fetch(`${server_address}/cancel`, {
+ "method": "PUT",
+ });
+ };
+ document.querySelector("#btnHome").onmousedown = function() {
+ fetch(`${server_address}/home`, {
+ "method": "PUT",
+ });
+ };
+ document.querySelector("#btnCenter").onmousedown = function() {
+ fetch(`${server_address}/center`, {
+ "method": "PUT",
+ });
+ };
+
+ document.querySelector("#btnIncX").onmousedown = function() {
+ fetch(`${server_address}/set_signal?signal=xInc&value=1`, {
+ "method": "PUT",
+ });
+ };
+ document.querySelector("#btnIncX").onmouseup = function() {
+ fetch(`${server_address}/set_signal?signal=xInc&value=0`, {
+ "method": "PUT",
+ });
+ };
+
+ document.querySelector("#btnDecX").onmousedown = function() {
+ fetch(`${server_address}/set_signal?signal=xDec&value=1`, {
+ "method": "PUT",
+ });
+ };
+ document.querySelector("#btnDecX").onmouseup = function() {
+ fetch(`${server_address}/set_signal?signal=xDec&value=0`, {
+ "method": "PUT",
+ });
+ };
+
+ document.querySelector("#btnIncY").onmousedown = function() {
+ fetch(`${server_address}/set_signal?signal=yInc&value=1`, {
+ "method": "PUT",
+ });
+ };
+ document.querySelector("#btnIncY").onmouseup = function() {
+ fetch(`${server_address}/set_signal?signal=yInc&value=0`, {
+ "method": "PUT",
+ });
+ };
+
+ document.querySelector("#btnDecY").onmousedown = function() {
+ fetch(`${server_address}/set_signal?signal=yDec&value=1`, {
+ "method": "PUT",
+ });
+ };
+ document.querySelector("#btnDecY").onmouseup = function() {
+ fetch(`${server_address}/set_signal?signal=yDec&value=0`, {
+ "method": "PUT",
+ });
+ };
+ </script>
+ </body>
+</html>