-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
172 lines (164 loc) · 11.9 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=0.95, user-scalable=no">
<title>CircuitCubesRemote</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=League+Spartan:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<script src="interface.js"></script>
<script src="ble_nus.js"></script>
<script src="ble_lwp.js"></script>
<script>
var pressTime = 0;
var lastDirection = 0;
var touchScreen = false;
async function run_motor(direction, motor) {
const speed = getValue(motor + "_speed");
const channel = getChannel(motor + "_channel");
const invert = getInversion(motor + "_invert");
await sendMotorCmd(speed*direction*invert, channel);
}
async function steer(direction, touch=true) {
if (alreadyTouched(touch)) return;
if (direction == 0) {
const centering = document.getElementById("centering").checked;
const elapsed = performance.now() - pressTime;
terminal_writeln("steer pressed for " + parseInt(elapsed) + "ms");
if (centering && lastDirection) {
const interval = getValue("interval");
run_motor(-lastDirection, "steer");
await delay(Math.min(interval, elapsed));
run_motor(0, "steer");
//avoid calling return to center more than once per steering key press (due to accidental press&release of left stop button)
lastDirection = 0;
terminal_writeln("returned to center for " + parseInt(performance.now() - pressTime - elapsed) + "ms");
} else {
run_motor(0, "steer");
}
} else {
lastDirection = direction;
run_motor(direction, "steer");
pressTime = performance.now();
}
}
function drive(direction, touch=true) {
if (alreadyTouched(touch)) return;
run_motor(direction, "drive");
}
async function sendMotorCmd(speed, channel){
let cmd = (speed >= 0) ? "+" : ""
cmd += String(speed).padStart(3, '0') + channel;
while (bleBusy == true) {
await delay(1);
}
nusSendString(cmd, true);
}
function getValue(id){
return parseInt(document.getElementById(id).value);
}
function getChannel(name){
return document.querySelector('input[name="' + name + '"]:checked').value;
}
function getInversion(id){
return (document.getElementById(id).checked) ? -1 : 1;
}
handlers["onleftpluspress"] = () => steer(1);
handlers["onleftminuspress"] = () => steer(-1);
handlers["onleftrelease"] = () => steer(0);
handlers["onrightpluspress"] = () => drive(1);
handlers["onrightminuspress"] = () => drive(-1);
handlers["onrightrelease"] = () => drive(0);
</script>
<style>
</style>
</head>
<body onload="onLoad()">
<div class="app">
<div class="title-container">
<span id="cc">CIRCUIT</span><span id="cb">CUBES</span><span id="wr">REMOTE</span>
</div>
<div class="controls">
<div class="control-btns">
<div>
<button id="left" ontouchstart="steer(1)" ontouchend="steer(0)" onmousedown="steer(1, false)" onmouseup="steer(0, false)">↑</button>
</div>
<div>
<button id="right" ontouchstart="steer(-1)" ontouchend="steer(0)" onmousedown="steer(-1, false)" onmouseup="steer(0, false)">↓</button>
</div>
</div>
<div class="control-btns" style="flex-direction: column;">
<div>
<button id="accelerate" ontouchstart="drive(1)" ontouchend="drive(0)" onmousedown="drive(1, false)" onmouseup="drive(0, false)">↑</button>
</div>
<div>
<button id="reverse" ontouchstart="drive(-1)" ontouchend="drive(0)" onmousedown="drive(-1, false)" onmouseup="drive(0, false)">↓</button>
</div>
</div>
</div>
<div class="actions">
<div><button id="clientConnectButton" onclick="connectionToggle()">Connect</button></div>
<div><button id="remoteConnectButton" onclick="remoteConnectionToggle()">Connect</button></div>
<div><button id="settingsButton" onclick="toggleSettings()">Settings</button></div>
</div>
<div id="settings">
Settings will be saved in cookies, when changed.
<br>
Drive:
<div class="group">
<div class="set">
Speed: <input type="text" id="drive_speed" value="255" disabled>
<button onclick="inc('drive_speed')" id="inc">+</button><button onclick="dec('drive_speed')" id="dec">-</button>
</div>
<div class="set">
<label for="drive_invert"><input id="drive_invert" name="drive_invert" type="checkbox">Revert</label>
</div>
<div class="set">
Channel:
<label for="drive_channel_a"><input type="radio" name="drive_channel" id="drive_channel_a" value="a" checked />A</label>
<label for="drive_channel_b"><input type="radio" name="drive_channel" id="drive_channel_b" value="b" />B</label>
<label for="drive_channel_c"><input type="radio" name="drive_channel" id="drive_channel_c" value="c" />C</label>
</div>
</div>
Steering:
<div class="group">
<div class="set">
Speed: <input type="text" id="steer_speed" value="125" disabled>
<button onclick="inc('steer_speed')" id="inc">+</button><button onclick="dec('steer_speed')" id="dec">-</button>
</div>
<div class="set">
<label for="steer_invert"><input id="steer_invert" name="steer_invert" type="checkbox">Revert</label>
</div>
<div class="set">
Channel:
<label for="steer_channel_a"><input type="radio" name="steer_channel" id="steer_channel_a" value="a" />A</label>
<label for="steer_channel_b"><input type="radio" name="steer_channel" id="steer_channel_b" value="b" checked />B</label>
<label for="steer_channel_c"><input type="radio" name="steer_channel" id="steer_channel_c" value="c" />C</label>
</div>
</div>
Return to center steering:
<div class="group">
<div class="set">
<label for="centering"><input id="centering" name="centering" type="checkbox" checked>Enabled</label>
</div>
<div class="set">
Return time: <input type="text" id="interval" value="90" disabled>ms
<button onclick="inc('interval')" id="inc">+</button><button onclick="dec('interval')" id="dec">-</button>
</div>
<button class="set" onclick="toggleTerminal()">Console</button>
</div>
<textarea id="terminal" rows="10" cols="50" readonly></textarea>
</div>
<div class="about">
v0.2.3 | <a href="https://github.com/repkovsky/CircuitCubesRemote">About</a>
</div>
</div>
<video loop id="sleep_lock" style="width:1px;">
<!-- playing video with audio (!) avoids disabling screen and limiting activity of browser, which spoils Bluetooth communication -->
<source type="video/mp4" src="data:@video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAvFtZGF03gIATGF2YzU5LjUxLjEwMQBCIAjBGDgAAAKuBgX//6rcRem95tlIt5Ys2CDZI+7veDI2NCAtIGNvcmUgMTY0IHIzMTAxIGIwOTNiYmUgLSBILjI2NC9NUEVHLTQgQVZDIGNvZGVjIC0gQ29weWxlZnQgMjAwMy0yMDIyIC0gaHR0cDovL3d3dy52aWRlb2xhbi5vcmcveDI2NC5odG1sIC0gb3B0aW9uczogY2FiYWM9MSByZWY9MyBkZWJsb2NrPTE6MDowIGFuYWx5c2U9MHgzOjB4MTEzIG1lPWhleCBzdWJtZT03IHBzeT0xIHBzeV9yZD0xLjAwOjAuMDAgbWl4ZWRfcmVmPTEgbWVfcmFuZ2U9MTYgY2hyb21hX21lPTEgdHJlbGxpcz0xIDh4OGRjdD0xIGNxbT0wIGRlYWR6b25lPTIxLDExIGZhc3RfcHNraXA9MSBjaHJvbWFfcXBfb2Zmc2V0PS0yIHRocmVhZHM9MSBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MiBrZXlpbnQ9MjUwIGtleWludF9taW49MjUgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIzLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3JhdGlvPTEuNDAgYXE9MToxLjAwAIAAAAAWZYiEACv//vZzfAprRzOVLgVtVUmJzyEQBGCMHAAABVRtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAKAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAACQXRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAKAAAAB4AAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAACgAAAAAAAEAAAAAAbltZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAADIAAAACAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAFkbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABJHN0YmwAAADAc3RzZAAAAAAAAAABAAAAsGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAKAAeAEgAAABIAAAAAAAAAAEVTGF2YzU5LjUxLjEwMSBsaWJ4MjY0AAAAAAAAAAAAAAAY//8AAAA2YXZjQwFkAAr/4QAZZ2QACqzZTXlrARAAAAMAEAAAAwMg8SJZYAEABmjr48siwP34+AAAAAAQcGFzcAAAAAEAAAABAAAAFGJ0cnQAAAAAAAIvYAACL2AAAAAYc3R0cwAAAAAAAAABAAAAAQAAAgAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAACzAAAAAEAAAAUc3RjbwAAAAAAAAABAAAARwAAAj10cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAACAAAAAAAAABgAAAAAAAAAAAAAAAEBAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAAXAAAEAAABAAAAAAG1bWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAACsRAAACABVxAAAAAAALWhkbHIAAAAAAAAAAHNvdW4AAAAAAAAAAAAAAABTb3VuZEhhbmRsZXIAAAABYG1pbmYAAAAQc21oZAAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABJHN0YmwAAAB+c3RzZAAAAAAAAAABAAAAbm1wNGEAAAAAAAAAAQAAAAAAAAAAAAIAEAAAAACsRAAAAAAANmVzZHMAAAAAA4CAgCUAAgAEgICAF0AVAAAAAAH0AAAAE4MFgICABRIQVuUABoCAgAECAAAAFGJ0cnQAAAAAAAH0AAAAE4MAAAAYc3R0cwAAAAAAAAABAAAAAgAABAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAHHN0c3oAAAAAAAAAAAAAAAIAAAAXAAAABgAAABhzdGNvAAAAAAAAAAIAAAAwAAADEwAAABpzZ3BkAQAAAHJvbGwAAAACAAAAAf//AAAAHHNiZ3AAAAAAcm9sbAAAAAEAAAACAAAAAQAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNTkuMzQuMTAx">
<source type="video/webm" src="data:@video/webm;base64,GkXfo59ChoEBQveBAULygQRC84EIQoKEd2VibUKHgQRChYECGFOAZwEAAAAAAAKoEU2bdLpNu4tTq4QVSalmU6yBoU27i1OrhBZUrmtTrIHYTbuMU6uEElTDZ1OsggGETbuMU6uEHFO7a1OsggKS7AEAAAAAAABZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmsirXsYMPQkBNgI1MYXZmNTkuMzQuMTAxV0GNTGF2ZjU5LjM0LjEwMUSJiEBEAAAAAAAAFlSua0CmrgEAAAAAAAA414EBc8WI0b0gJBIayqecgQAitZyDdW5kiIEAhoVWX1ZQOYOBASPjg4QCYloA4ImwgSi6gR6agQKuAQAAAAAAAFzXgQJzxYg7+hiGsqEbAZyBACK1nIN1bmSIgQCGhkFfT1BVU1aqg2MuoFa7hATEtACDgQLhkZ+BArWIQOdwAAAAAABiZIEQY6KTT3B1c0hlYWQBAjgBgLsAAAAAABJUw2dA3HNzoGPAgGfImkWjh0VOQ09ERVJEh41MYXZmNTkuMzQuMTAxc3PbY8CLY8WI0b0gJBIayqdnyKVFo4dFTkNPREVSRIeYTGF2YzU5LjUxLjEwMSBsaWJ2cHgtdnA5Z8iiRaOIRFVSQVRJT05Eh5QwMDowMDowMC4wNDAwMDAwMDAAAHNz2GPAi2PFiDv6GIayoRsBZ8iiRaOHRU5DT0RFUkSHlUxhdmM1OS41MS4xMDEgbGlib3B1c2fIokWjiERVUkFUSU9ORIeUMDA6MDA6MDAuMDAwMDAwMDAwAAAfQ7Z1p+eBAKOigQAAgIJJg0IAAnAB1gA4JBwYSgAAMGAAAAQP//9SEQAAABxTu2uRu4+zgQC3iveBAfGCAmbwgQM=">
</video>
</body>
</html>