mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
* feat: js sdk * refactor: move js back where it belongs * docs: generate docs using typedoc * feat: sdk versioning scheme * ci: silence pvs warning * docs: bring back old incomplete js docs * style: readAnalog naming * fix: rename script compatibility screens Co-authored-by: あく <alleteam@gmail.com>
177 lines
5.6 KiB
JavaScript
177 lines
5.6 KiB
JavaScript
#!/usr/bin/env node
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { SerialPort } from "serialport";
|
|
import prompts from "prompts";
|
|
import esbuild from "esbuild";
|
|
import json5 from "json5";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
async function build(config) {
|
|
await esbuild.build({
|
|
entryPoints: ["./dist/index.js"],
|
|
outfile: config.output,
|
|
tsconfig: "./tsconfig.json",
|
|
format: "cjs",
|
|
bundle: true,
|
|
minify: config.minify,
|
|
external: [
|
|
"@flipperdevices/fz-sdk/*"
|
|
],
|
|
supported: {
|
|
"array-spread": false,
|
|
"arrow": false,
|
|
"async-await": false,
|
|
"async-generator": false,
|
|
"bigint": false,
|
|
"class": false,
|
|
"const-and-let": true,
|
|
"decorators": false,
|
|
"default-argument": false,
|
|
"destructuring": false,
|
|
"dynamic-import": false,
|
|
"exponent-operator": false,
|
|
"export-star-as": false,
|
|
"for-await": false,
|
|
"for-of": false,
|
|
"function-name-configurable": false,
|
|
"function-or-class-property-access": false,
|
|
"generator": false,
|
|
"hashbang": false,
|
|
"import-assertions": false,
|
|
"import-meta": false,
|
|
"inline-script": false,
|
|
"logical-assignment": false,
|
|
"nested-rest-binding": false,
|
|
"new-target": false,
|
|
"node-colon-prefix-import": false,
|
|
"node-colon-prefix-require": false,
|
|
"nullish-coalescing": false,
|
|
"object-accessors": false,
|
|
"object-extensions": false,
|
|
"object-rest-spread": false,
|
|
"optional-catch-binding": false,
|
|
"optional-chain": false,
|
|
"regexp-dot-all-flag": false,
|
|
"regexp-lookbehind-assertions": false,
|
|
"regexp-match-indices": false,
|
|
"regexp-named-capture-groups": false,
|
|
"regexp-set-notation": false,
|
|
"regexp-sticky-and-unicode-flags": false,
|
|
"regexp-unicode-property-escapes": false,
|
|
"rest-argument": false,
|
|
"template-literal": false,
|
|
"top-level-await": false,
|
|
"typeof-exotic-object-is-object": false,
|
|
"unicode-escapes": false,
|
|
"using": false,
|
|
},
|
|
});
|
|
|
|
let outContents = fs.readFileSync(config.output, "utf8");
|
|
outContents = "let exports = {};\n" + outContents;
|
|
|
|
if (config.enforceSdkVersion) {
|
|
const version = json5.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8")).version;
|
|
let [major, minor, _] = version.split(".");
|
|
outContents = `checkSdkCompatibility(${major}, ${minor});\n${outContents}`;
|
|
}
|
|
|
|
fs.writeFileSync(config.output, outContents);
|
|
}
|
|
|
|
async function upload(config) {
|
|
const appFile = fs.readFileSync(config.input, "utf8");
|
|
const flippers = (await SerialPort.list()).filter(x => x.serialNumber?.startsWith("flip_"));
|
|
|
|
if (!flippers) {
|
|
console.error("No Flippers found");
|
|
process.exit(1);
|
|
}
|
|
|
|
let portPath = flippers[0].path;
|
|
if (flippers.length > 1) {
|
|
port = (await prompts([{
|
|
type: "select",
|
|
name: "port",
|
|
message: "Select Flipper to run the app on",
|
|
choices: flippers.map(x => ({ title: x.serialNumber.replace("flip_", ""), value: x.path })),
|
|
}])).port;
|
|
}
|
|
|
|
console.log(`Connecting to Flipper at ${portPath}`);
|
|
let port = new SerialPort({ path: portPath, baudRate: 230400 });
|
|
let received = "";
|
|
let lastMatch = 0;
|
|
async function waitFor(string, timeoutMs) {
|
|
return new Promise((resolve, _reject) => {
|
|
let timeout = undefined;
|
|
if (timeoutMs) {
|
|
timeout = setTimeout(() => {
|
|
console.error("Error: timeout");
|
|
process.exit(1);
|
|
}, timeoutMs);
|
|
}
|
|
setInterval(() => {
|
|
let idx = received.indexOf(string, lastMatch);
|
|
if (idx !== -1) {
|
|
lastMatch = idx;
|
|
if (timeoutMs)
|
|
clearTimeout(timeout);
|
|
resolve();
|
|
}
|
|
}, 50);
|
|
});
|
|
}
|
|
port.on("data", (data) => {
|
|
received += data.toString();
|
|
});
|
|
|
|
await waitFor(">: ", 1000);
|
|
console.log("Uploading application file");
|
|
port.write(`storage remove ${config.output}\x0d`);
|
|
port.drain();
|
|
await waitFor(">: ", 1000);
|
|
port.write(`storage write_chunk ${config.output} ${appFile.length}\x0d`);
|
|
await waitFor("Ready", 1000);
|
|
port.write(appFile);
|
|
port.drain();
|
|
await waitFor(">: ", 1000);
|
|
|
|
console.log("Launching application");
|
|
port.write(`js ${config.output}\x0d`);
|
|
port.drain();
|
|
|
|
await waitFor("Running", 1000);
|
|
process.stdout.write(received.slice(lastMatch));
|
|
port.on("data", (data) => {
|
|
process.stdout.write(data.toString());
|
|
});
|
|
process.on("exit", () => {
|
|
port.write("\x03");
|
|
});
|
|
|
|
await waitFor("Script done!", 0);
|
|
process.exit(0);
|
|
}
|
|
|
|
(async () => {
|
|
const commands = {
|
|
"build": build,
|
|
"upload": upload,
|
|
};
|
|
|
|
const config = json5.parse(fs.readFileSync("./fz-sdk.config.json5", "utf8"));
|
|
const command = process.argv[2];
|
|
|
|
if (!Object.keys(commands).includes(command)) {
|
|
console.error(`Unknown command ${command}. Supported: ${Object.keys(commands).join(", ")}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
await commands[command](config[command]);
|
|
})();
|