diff --git a/js/intro/README.md b/js/intro/README.md new file mode 100644 index 0000000..f4820c5 --- /dev/null +++ b/js/intro/README.md @@ -0,0 +1,25 @@ +# JavaScript intro + +## Introduction +I created an introduction to JavaScript video at [https://youtu.be/33Xmn5rnisc](https://youtu.be/33Xmn5rnisc). + +In the video I walked thru the [a_js_intro.js](./a_js_intro.js) file. + +The `a_js_intro.js` script ends up covering a lot of topics! +- submenu : `setHeader`, `addItem`, `show` +- keyboard : `text` (first param is # of bytes to allocate, including null terminator) +- storage : `exists` +- usbdisk : `start`, `wasEjected`, `stop` +- textbox : `setConfig`, `emptyText`, `addText`, `show`, `isOpen` +- gpio : `init`, `read` +- badusb : `setup`, `isConnected`, `press`, `println`, `quit` +- subghz : `transmitFile` +- `let`, `=` (assignment), `for` (loop) +- `require`, `print`, `delay`, `parse_int`, `__dirpath` +- Strings, numbers, booleans +- Arrays, `.length` +- `+` (adding), `i++` (increment by 1), `!` (not) +- `if`, `else if`, `===` (compare equal), `!==` (compare not equal) +- calling functions, defining functions, `return` + +At the end of the video I ran [widget.js](./widget.js) to summarize what we learned. \ No newline at end of file diff --git a/js/intro/a_js_intro.js b/js/intro/a_js_intro.js new file mode 100644 index 0000000..c708531 --- /dev/null +++ b/js/intro/a_js_intro.js @@ -0,0 +1,148 @@ +// Description: This script demonstrates the usage of the Flipper JavaScript API. + +// For more information, please visit my Flipper Zero Wiki: +// https://www.github.com/jamisonderek/flipper-zero-tutorials/wiki/JavaScript + +// Only the "let" keyword is supported for variable declarations. + +// The "require" function is used to import modules. The list of available modules varies by firmware version. +let badusb = require("badusb"); +let gpio = require("gpio"); +let keyboard = require("keyboard"); +let storage = require("storage"); +let subghz = require("subghz"); +let submenu = require("submenu"); +let textbox = require("textbox"); +let usbdisk = require("usbdisk"); + +// Sub-GHz radio setup +subghz.setup(); + +// initialize GPIO pins as Input pins with internal pull-up resisters. +let buttons = ["PB2", "PB3", "PA4", "PA6"]; +for (let i = 0; i < buttons.length; i++) { + gpio.init(buttons[i], "input", "up"); +} + +// returns true if the button is pressed (e.g. pin is connected to ground). +function isPressed(button) { + return !gpio.read(buttons[button]); +} + +// Types the given text using the BadUSB module. +function typeText(text) { + badusb.setup({ vid: 0x1234, pid: 0x5678, mfr_name: "Apple", prod_name: "Keyboard" }); + + // We need to wait for up to 10 seconds for the BadUSB to connect. + for (let retry = 10; retry > 0; retry--) { + if (badusb.isConnected()) { + break; // Exit the loop if the BadUSB is connected + } + delay(1000); // Wait for 1 second + } + + if (badusb.isConnected()) { + badusb.press("GUI", "r"); // Win + R + delay(500); // Wait for the Run dialog to appear + badusb.println(text); // Type the text into the Run dialog and press Enter + } else { + print("BadUSB not connected", 1000); // Print an error message if the BadUSB is not connected and wait for 1 second + } + + badusb.quit(); // Disconnect the BadUSB device +} + +// Returns the list of button names. +function pinNames() { + let names = ""; + + for (let i = 0; i < buttons.length; i++) { + names += buttons[i] + " "; + } + + return names; +} + +// Use the FlipBoard module to bind GPIO buttons to actions. +function demoFlipBoard() { + + // Set the configuration for the textbox + textbox.setConfig("end", "text"); // Focus (start / end), Font (text / hex) + textbox.emptyText(); + textbox.addText("FlipBoard demo\nMonitoring button presses.\npins:" + pinNames() + "\nPress back to exit."); + textbox.show(); // non-blocking + + while (textbox.isOpen()) { // User can close the textbox by pressing the back button + if (isPressed(0)) { + typeText("https://github.com/jamisonderek/flipper-zero-tutorials/wiki/JavaScript"); + } else if (isPressed(1)) { + typeText("https://th.bing.com/th/id/OIG2.VuhdedoFVZRvTzl6FO4F?pid=ImgGn"); + } else if (isPressed(2)) { + typeText("https://youtu.be/xvFZjo5PgG0"); + } else if (isPressed(3)) { + let result = subghz.transmitFile("/ext/subghz/Light_on.sub"); + if (!result) { + print("Send failed"); + } + } + + delay(100); + } +} + +// Parses an integer from the given text and counts the next four numbers. +function demoCount() { + keyboard.setHeader("Starting count"); + let text = keyboard.text(100, "1337", false); + if (text === undefined) { + return; // User pressed the back button + } + + print("Text:", text); + let count = parse_int(text); + for (let i = 0; i < 4; i++) { + print("Count:", count + i); + } + print("Counting done!\n"); +} + +// Creates a 4MB image file and mounts it as a USB Mass Storage device. +function demoMassStorage() { + // NOTE: The __dirpath variable (is the location of the current script) but it may not be defined in your firmware. + let path = __dirpath + "/4MB.img"; + let size = 4 * 1024 * 1024; // 4MB + if (!storage.exists(path)) { + print("Creating image..."); + usbdisk.createImage(path, size); // Create a 4MB image file + } + print("Starting UsbDisk..."); + usbdisk.start(path); // Mount the image as a USB Mass Storage device + print("Started, waiting until ejected..."); + while (!usbdisk.wasEjected()) { // Wait until the USB Mass Storage device is ejected from the host + delay(1000); + } + print("Ejected, stopping UsbDisk..."); + usbdisk.stop(); // Unmount the USB Mass Storage device + print("Done"); +} + +while (true) { + submenu.setHeader("Select awesome demo:"); + submenu.addItem("Counting demo", 0); + submenu.addItem("FlipBoard GPIO demo", 1); + submenu.addItem("Mass Storage", 2); + let result = submenu.show(); + if (result === undefined) { // User pressed the back button + break; + } + + if (result === 0) { + demoCount(); + } else if (result === 1) { + demoFlipBoard(); + } else if (result === 2) { + demoMassStorage(); + } + + delay(4 * 1000); // Wait four seconds before showing the menu again +}; \ No newline at end of file diff --git a/js/intro/widget-js.fxbm b/js/intro/widget-js.fxbm new file mode 100644 index 0000000..9ba5783 Binary files /dev/null and b/js/intro/widget-js.fxbm differ diff --git a/js/intro/widget.js b/js/intro/widget.js new file mode 100644 index 0000000..c7239d9 --- /dev/null +++ b/js/intro/widget.js @@ -0,0 +1,32 @@ +let widget = require("widget"); + +print("Loading file", __filepath); +print("From directory", __dirpath); + +let logo = widget.loadImageXbm(__dirpath + "/widget-js.fxbm"); + +// addText supports "Primary" and "Secondary" font sizes. +widget.addText(10, 10, "Primary", "JavaScript on Flipper"); +widget.addText(10, 20, "Secondary", "- How to edit and run scripts"); +widget.addText(10, 30, "Secondary", "- Using 'let' and 'require'"); +widget.addText(10, 40, "Secondary", "- Different module support"); +widget.addText(10, 50, "Secondary", "- badusb, submenu, textbox,"); +widget.addText(10, 60, "Secondary", "- storage, keyboard, etc."); +// Show the widget (drawing the layers in the orderer they were added) +widget.show(); + +let i = 12; +let bitmap = undefined; +while (widget.isOpen()) { + bitmap = widget.addXbm(7, i, logo); + delay(500); + widget.remove(bitmap); + delay(100); + i += 10; + if (i > 60) { i = 12; } +} + +// If user did not press the back button, close the widget. +if (widget.isOpen()) { + widget.close(); +} \ No newline at end of file