Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Console Functionality #4

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion CNAME

This file was deleted.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

# [Try PestoLink-Online here!](http://pestol.ink/)
# [Try this fork of PestoLink-Online here!](https://benpark20.github.io/PestoLink-test/)

## PestoLink-Online
*v1.0.0*
*This is a fork of the PestoLink-Online website created to add a console*

PestoLink-Online is a web app designed to run in any browser with Bluetooth Low Energy (BLE) and gamepad support, for example Google Chrome. If you set up an MCU with [PestoLink-Receive](https://github.com/AlfredoSystems/PestoLink-Receive), you can then open PestoLink-Online in a browser, connect to your MCU with BLE, and send gamepad data to the MCU.

Expand Down
252 changes: 146 additions & 106 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,127 +1,167 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline';"
/>
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>

<title>PestoLink-Online</title>
<link rel="stylesheet" href="styles.css">
</head>

<body>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
<div id="user-container">
<div class="container mobile-only" id="mobile-joystick">
<div id="joystick-background">
<div id="joystick-container"></div>
</div>
</div>

<div class="container desktop-only" id="desktop-axis">
<div class="slider-non">Axis 0</div>
<div class="slider-non" id="axisValue0">127</div>
<div class="slider-bar" id="bar0"></div>

<div class="slider-non">Axis 1</div>
<div class="slider-non" id="axisValue1">127</div>
<div class="slider-bar" id="bar1"></div>

<div class="slider-non">Axis 2</div>
<div class="slider-non" id="axisValue2">127</div>
<div class="slider-bar" id="bar2"></div>

<div class="slider-non">Axis 3</div>
<div class="slider-non" id="axisValue3">127</div>
<div class="slider-bar" id="bar3"></div>
<div class="container mobile-only" id="mobile-joystick">
<div id="joystick-background">
<div id="joystick-container"></div>
</div>
</div>

<div class="container desktop-only" id="desktop-axis">
<div class="slider-non">Axis 0</div>
<div class="slider-non" id="axisValue0">127</div>
<div class="slider-bar" id="bar0"></div>

<div class="slider-non">Axis 1</div>
<div class="slider-non" id="axisValue1">127</div>
<div class="slider-bar" id="bar1"></div>

<div class="slider-non">Axis 2</div>
<div class="slider-non" id="axisValue2">127</div>
<div class="slider-bar" id="bar2"></div>

<div class="slider-non">Axis 3</div>
<div class="slider-non" id="axisValue3">127</div>
<div class="slider-bar" id="bar3"></div>
</div>

<div class="container" id="interface">
<button id="ble-button">🔗</button>
<button id="telemetry">no data</button>
<button id="ble-status">not connected</button>
<div id="settings-grid">
<div class="settings-label">Mobile Layout</div>

<div class="settings-toggle">
<div id="toggle-mobile-layout" class="toggle-round">
<div class="toggle-nub"></div>
</div>
</div>

<div class="container" id="interface">
<button id="ble-button">🔗</button>
<button id="telemetry">no data</button>
<button id="ble-status">not connected</button>

<div id="settings-grid">

<div class="settings-label">Mobile Layout</div>

<div class="settings-toggle">
<div id="toggle-mobile-layout" class="toggle-round"><div class="toggle-nub"></div></div>
</div>

<div class="settings-label help-row">Override axes <br> with WASD</div>

<div class="settings-toggle help-row">
<div id="toggle-keyboard-style" class="toggle-round"><div class="toggle-nub"></div></div>
</div>
<div class="settings-label help-row">
Override axes <br />
with WASD
</div>

<div class="settings-label help-row">Help/Info!</div>
<div class="settings-toggle help-row">
<div id="toggle-keyboard-style" class="toggle-round">
<div class="toggle-nub"></div>
</div>
</div>

<div class="settings-toggle help-row">
<div id="toggle-info" class="toggle-round"><div class="toggle-nub"></div></div>
</div>
<div class="settings-label help-row">Help/Info!</div>

<div class="settings-toggle help-row">
<div id="toggle-info" class="toggle-round">
<div class="toggle-nub"></div>
</div>
</div>
</div>
</div>

<div class="container mobile-only" id="mobile-button">
<div></div>
<button id="button-3">3</button>
<div></div>
<button id="button-2">2</button>
<div></div>
<button id="button-1">1</button>
<div></div>
<button id="button-0">0</button>
<div></div>
</div>

<div class="container desktop-only" id="desktop-button">
<button id="buttonDesktop0">0</button>
<button id="buttonDesktop1">1</button>
<button id="buttonDesktop2">2</button>
<button id="buttonDesktop3">3</button>
<button id="buttonDesktop4">4</button>
<button id="buttonDesktop5">5</button>
<button id="buttonDesktop6">6</button>
<button id="buttonDesktop7">7</button>
<button id="buttonDesktop8">8</button>
<button id="buttonDesktop9">9</button>
<button id="buttonDesktop10">10</button>
<button id="buttonDesktop11">11</button>
<button id="buttonDesktop12">12</button>
<button id="buttonDesktop13">13</button>
<button id="buttonDesktop14">14</button>
<button id="buttonDesktop15">15</button>
</div>
</div>

<div class="container mobile-only" id="mobile-button">
<div></div>
<button id="button-3">3</button>
<div></div>
<button id="button-2">2</button>
<div></div>
<button id="button-1">1</button>
<div></div>
<button id="button-0">0</button>
<div></div>
</div>

<div class="container desktop-only" id="desktop-button">
<button id="buttonDesktop0">0</button>
<button id="buttonDesktop1">1</button>
<button id="buttonDesktop2">2</button>
<button id="buttonDesktop3">3</button>
<button id="buttonDesktop4">4</button>
<button id="buttonDesktop5">5</button>
<button id="buttonDesktop6">6</button>
<button id="buttonDesktop7">7</button>
<button id="buttonDesktop8">8</button>
<button id="buttonDesktop9">9</button>
<button id="buttonDesktop10">10</button>
<button id="buttonDesktop11">11</button>
<button id="buttonDesktop12">12</button>
<button id="buttonDesktop13">13</button>
<button id="buttonDesktop14">14</button>
<button id="buttonDesktop15">15</button>
</div>
<div
id="terminal-container"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the terminal-container div is the only real change to this file.

style="height: 25%; width: 80%; overflow: auto"
>
<p id="terminal">PestoLink Console:</p>
</div>

<div id="info-container">
<p>
<u>Embedded Platform Support</u>
<br> <a href="https://github.com/AlfredoSystems/PestoLink-MicroPython">PestoLink</a> currently supports two embedded platforms, MicroPython and Arduino
(designed for <a href="https://www.sparkfun.com/products/22230">RP2040 on XRP Kits</a> and <a href="https://www.alfredosys.com/products/alfredo-nou2/">ESP32</a> respectively).
<br> MicroPython based robots use the module <a href="https://github.com/AlfredoSystems/PestoLink-MicroPython/tree/main">PestoLink-MicroPython</a>.
,Arduino based robots use the library <a href="https://github.com/AlfredoSystems/PestoLink-Receive">PestoLink-Receive</a>.

<br><br> <u>Browser Support</u>
<br> PestoLink works with Google Chrome on Windows, Android, Mac, Linux, and ChromeOS.
<br>On iOS very few web browsers support webBluetooth. Google Chrome has worked for some people, but <a href="https://apps.apple.com/us/app/bluefy-web-ble-browser/id1492822055">Bluefy</a> is the best option found so far.

<br><br> <u>What does "Override axes with WASD" do?</u>
<br> By default, keyboard data is sent seperatly from axis/button data. If you would like to drive your robot using your keyboard,
you can enable this switch to override the axis/button data with keyboard input. 'WASD' wil override Axis 0 and 1, 'IJKL' will override Axis 2 and 3.
'ZXCVBNM,' will overide buttons 0 through 7.

<br><br> If you have any questions, feel free to reach out! ([email protected])
</p>
<p>
<u>Embedded Platform Support</u>
<br />
<a href="https://github.com/AlfredoSystems/PestoLink-MicroPython"
>PestoLink</a
>
currently supports two embedded platforms, MicroPython and Arduino
(designed for
<a href="https://www.sparkfun.com/products/22230">RP2040 on XRP Kits</a>
and
<a href="https://www.alfredosys.com/products/alfredo-nou2/">ESP32</a>
respectively). <br />
MicroPython based robots use the module
<a
href="https://github.com/AlfredoSystems/PestoLink-MicroPython/tree/main"
>PestoLink-MicroPython</a
>. ,Arduino based robots use the library
<a href="https://github.com/AlfredoSystems/PestoLink-Receive"
>PestoLink-Receive</a
>.

<br /><br />
<u>Browser Support</u> <br />
PestoLink works with Google Chrome on Windows, Android, Mac, Linux, and
ChromeOS. <br />On iOS very few web browsers support webBluetooth.
Google Chrome has worked for some people, but
<a
href="https://apps.apple.com/us/app/bluefy-web-ble-browser/id1492822055"
>Bluefy</a
>
is the best option found so far.

<br /><br />
<u>What does "Override axes with WASD" do?</u> <br />
By default, keyboard data is sent seperatly from axis/button data. If
you would like to drive your robot using your keyboard, you can enable
this switch to override the axis/button data with keyboard input. 'WASD'
wil override Axis 0 and 1, 'IJKL' will override Axis 2 and 3. 'ZXCVBNM,'
will overide buttons 0 through 7.

<br /><br />
If you have any questions, feel free to reach out! ([email protected])
</p>
</div>

<div id="hack-spacer"></div>
<script src="index.js"></script>
</body>

</html>
</body>
</html>
31 changes: 26 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,12 @@ function createBleAgent() {
let buttonBLE = document.getElementById('ble-button')
let statusBLE = document.getElementById('ble-status')
let telemetryDisplay = document.getElementById('telemetry')
let terminalDisplay = document.getElementById('terminal')

const SERVICE_UUID_PESTOBLE = '27df26c5-83f4-4964-bae0-d7b7cb0a1f54';
const CHARACTERISTIC_UUID_GAMEPAD = '452af57e-ad27-422c-88ae-76805ea641a9';
const CHARACTERISTIC_UUID_TELEMETRY = '266d9d74-3e10-4fcd-88d2-cb63b5324d0c';
const CHARACTERISTIC_UUID_TERMINAL = '433ec275-a494-40ab-98c2-4785a19bf830';

if (isMobile){
buttonBLE.ontouchend = updateBLE;
Expand All @@ -199,6 +201,7 @@ function createBleAgent() {
let service;
let characteristic_gamepad;
let characteristic_telemetry;
let characteristic_terminal;
let isConnectedBLE = false;
let bleUpdateInProgress = false;

Expand Down Expand Up @@ -228,6 +231,9 @@ function createBleAgent() {
characteristic_telemetry = await service.getCharacteristic(CHARACTERISTIC_UUID_TELEMETRY);
await characteristic_telemetry.startNotifications()
await characteristic_telemetry.addEventListener('characteristicvaluechanged', handleTelemetryCharacteristic);
characteristic_terminal = await service.getCharacteristic(CHARACTERISTIC_UUID_TERMINAL);
await characteristic_terminal.startNotifications()
await characteristic_terminal.addEventListener('characteristicvaluechanged', handleTerminal);
}catch{
console.log("Pestolink version on robot is real old :(")
}
Expand Down Expand Up @@ -263,6 +269,7 @@ function createBleAgent() {
//console.log('Received ASCII string:', asciiString);
telemetryDisplay.innerHTML = asciiString;


// Parse the last three bytes as an RGB hex color code
if (value.byteLength >= 9) {
const r = value.getUint8(8).toString(16).padStart(2, '0'); // Red
Expand All @@ -279,6 +286,25 @@ function createBleAgent() {

//batteryDisplay.innerHTML = "&#x1F50B;&#xFE0E; " + voltage.toFixed(1) + "V";
}
function handleTerminal(event){

const value = event.target.value; // DataView of the characteristic's value

let asciiString = '';
for (let i = 0; i < Math.min(64, value.byteLength); i++) {
asciiString += String.fromCharCode(value.getUint8(i));
}
console.log('Received ASCII string:', asciiString);
if(asciiString == "CLEAR"){
terminalDisplay.innerHTML = "";
} else {
console.log(terminal.innerHTML);
terminalDisplay.innerHTML = terminalDisplay.innerHTML + "<br>>" + asciiString;
console.log(terminal.innerHTML);
var textarea = document.getElementById('terminal-container');
textarea.scrollTop = textarea.scrollHeight;
}
}

async function disconnectBLE() {
displayBleStatus('Disconnecting');
Expand Down Expand Up @@ -532,16 +558,13 @@ function createGamepadAgent() {
function getButtonBytes() {
const gamepad = getSelectedGamepad();
let buttonStates = 0; // Single integer to hold all 16 button states

if (gamepad) {
const buttonCount = Math.min(gamepad.buttons.length, 16); // Limit to 16 buttons

for (let i = 0; i < buttonCount; i++) {
const button = gamepad.buttons[i];
if (button && button.pressed) {
buttonStates |= (1 << i); // Set the corresponding bit if the button is pressed
}

// Update button visuals if DOM element exists
if (buttonElements[i]) {
const newColor = button && button.pressed ? 'var(--alf-green)' : 'grey';
Expand All @@ -551,11 +574,9 @@ function createGamepadAgent() {
}
}
}

// Separate the 16-bit integer into two bytes
const firstByte = buttonStates & 0xFF; // Lower 8 bits
const secondByte = (buttonStates >> 8) & 0xFF; // Upper 8 bits

return { byte0: firstByte, byte1: secondByte };
}

Expand Down
Loading