Skip to content

Commit

Permalink
figured out how to eval a compiled lua function!
Browse files Browse the repository at this point in the history
  • Loading branch information
jaames committed Oct 15, 2021
1 parent 84b4990 commit 8fdc4f5
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 6 deletions.
Binary file added examples/eval_payload.luac
Binary file not shown.
89 changes: 89 additions & 0 deletions examples/example-eval.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Playdate USB demo</title>
<link rel="stylesheet" href="./assets/styles.css">
<script src="./playdate-usb.js"></script>
</head>
<body>
<div class="wrapper">
<header>
<h1>Playdate USB demo - eval</h1>
</header>
<main>
<div class="panel">
<div class="row">
<div class="pull-left">
<button onclick="connect()" id="connectButton"> connect to playdate </button>
<span id="serial"></span>
</div>
</div>
</div>
<div class="panel" id="data">
<p>
This example uses evalLuaPayload() to send a compiled Lua payload over USB and execute it on your Playdate - as long as the current application is not a system app. This payload is designed to print all fo the global variables from the current app's lua runtime, the code is:
<pre>for n in pairs(_G) do print(n) end</pre>
</p>
</div>
</main>
<footer class="row">
<div class="pull-left">
<a href="//github.com/jaames/playdate-usb">playdate-usb</a> | <a href="//github.com/jaames/playdate-usb/blob/main/examples/example-basic.html">page source</a>
</div>
<div class="pull-right">
built by <a href="//github.com/jaames">james daniel</a>
</div>
</footer>
</div>

<script>
var device;

const data = document.getElementById('data');

// Check WebUSB support, display error if not supported
try {
playdateUsb.assertUsbSupported();
}
catch (e) {
document.getElementById('serial').innerHTML = e.message;
document.getElementById('connectButton').disabled = true;
}

async function runPayload(device) {
// fetch the payload - this is a PDC-compiled lua payload extracted from a .PDZ file
const resp = await fetch('./eval_payload.luac');
// get its contents as an ArrayBuffer
const payload = await resp.arrayBuffer();
// send it to the Playdate
return await device.evalLuaPayload(payload);
}

async function connect() {
try {
device = await playdateUsb.requestConnectPlaydate();
// device setup
await device.open();
const serial = await device.getSerial();
document.getElementById('serial').innerHTML = `Connected to Playdate ${ serial }`;
device.on('disconnect', () => {
document.getElementById('serial').innerHTML = 'Playdate disconnected';
});

const consoleData = await runPayload(device);
document.getElementById('data');
data.innerHTML += "<b>results:</b>";
data.innerHTML += consoleData.split('\n').join('</br>');
console.log(consoleData);
}
catch(e) {
console.warn(e.message);
document.getElementById('serial').innerHTML = 'Error connecting to Playdate, try again';
}
}
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ <h1>Playdate USB demos</h1>
<li>
<a href="./example-send-bitmap.html">send bitmap</a>
</li>
<li>
<a href="./example-eval.html">execute lua payload</a>
</li>
</ul>
</div>
</main>
Expand Down
20 changes: 16 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ JavaScript library for interacting with a [Panic Playdate](https://play.date/) co
## Features

- Get Playdate device stats such as its version info, serial, cpu stats, etc
- Take a screenshot of the Playdate's screen and draw it to a HTML5 canvas, or send an image to be previewed
- Read the Playdate's button and crank input state
- Grab a screenshot from the Playdate and draw it to a HTML5 canvas, or send an image to be previewed on the device
- Read the button and crank input state
- Execute secret commands!
- Send compiled Lua payloads over USB!
- Extensive error handling with helpful error messages
- Exports full Typescript types, has zero dependencies, and weighs less than 4kb minified and gzipped

Expand Down Expand Up @@ -214,7 +215,7 @@ const screenBuffer = new Uint8Array(12000);
await device.sendBitmap(screenBuffer);
```

#### `sendBitmapIndexed(pixiels: Uint8Array)`
#### `sendBitmapIndexed(pixels: Uint8Array)`

Send a indexed bitmap to display on the Playdate's screen. The input bitmap must be an [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) of bytes, each byte in the array will represent 1 pixel; `0x0` for black, `0x1` for white. The input bitmap must also contain 400 x 240 pixels.

Expand Down Expand Up @@ -286,6 +287,17 @@ Sends a plaintext command directly to the Playdate, and returns the response as

> ⚠️ The commands that this library wraps with functions (such as `getVersion()` or `getScreen()`) are known to be safe, are used by the Playdate Simulator, and have all been tested on actual Playdate hardware. However, some of the commands that you can potentially run with `sendCommand()` could be dangerous, and might even harm your favorite yellow handheld if you don't know what you're doing. *Please* don't execute any commands that you're unsure about!
#### `evalLuaPayload()`

Sends a compiled Lua function to the device to be evaluated. The payload must be a Playdate-compatible Lua function compiled with [`luaU_dump()`](https://github.com/lua/lua/blob/v5.4-alpha/ldump.c#L215) from luac. It will return anything printed to the device's console.

> ⚠️ This is pretty hardcore, you're probably not going to find this useable unless you really know what you're doing.
```js
const payloadData = new Uint8Array(... put your payload data here);
await device.evalLuaPayload(payloadData);
```

## Contributing

Contributions and ports to other languages are welcome! Here's a list of things I'd like to do, but haven't found the time yet:
Expand Down Expand Up @@ -315,6 +327,6 @@ To build the project, you'll need to have Node and NPM installed. Clone the repo

2021 James Daniel

If you have any questions or just want to say hi, you can reach me on Twitter ([@rakujira](https://twitter.com/rakujira)), on Discord (`@jaames#9860`), or via email (`mail at jamesdaniel dot dev`). I'm interested in joining any groups that are working on Playdate reverse-engineering!
If you have any questions or just want to say hi, you can reach me on Twitter ([@rakujira](https://twitter.com/rakujira)), on Discord (`@jaames#9860`), or via email (`mail at jamesdaniel dot dev`).

Playdate is © [Panic Inc.](https://panic.com/) This project isn't affiliated with or endorsed by them in any way
18 changes: 16 additions & 2 deletions src/PlaydateDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
splitLines,
parseKeyVal,
bytesToString,
stringToBytes
stringToBytes,
sleep
} from './utils';

// Playdate USB vendor and product IDs
Expand Down Expand Up @@ -333,6 +334,19 @@ export class PlaydateDevice {
assert(str === '\r\n', `Invalid run response, got ${ str }`);
}

/**
* Eval a pre-compiled lua function payload (has to be compiled with pdc) on the device
*/
async evalLuaPayload(payload: Uint8Array | ArrayBufferLike, waitTime = 200) {
const cmd = `eval ${ payload.byteLength }\n`;
const data = new Uint8Array(cmd.length + payload.byteLength);
data.set(stringToBytes(cmd), 0);
data.set(new Uint8Array(payload), cmd.length);
await this.serial.write(data);
await sleep(waitTime);
return await this.serial.readAscii();
}

// not quite working yet
// async startStreaming() {
// this.assertNotBusy();
Expand Down Expand Up @@ -450,7 +464,7 @@ export class PlaydateDevice {
// console.log(str);
// if (str.includes('OK') || str.includes('ERROR'))
// break;
// sleep(100);
// await sleep(100);
// i++;
// }
// }
Expand Down

0 comments on commit 8fdc4f5

Please sign in to comment.