1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 12:42:30 +04:00

Merge remote-tracking branch 'OFW/dev' into dev

This commit is contained in:
MX
2025-04-01 16:16:07 +03:00
17 changed files with 670 additions and 40 deletions

View File

@@ -11,8 +11,9 @@ Start USB HID with optional parameters. Should be called before all other method
Configuration object *(optional)*:
- vid, pid (number): VID and PID values, both are mandatory
- mfr_name (string): Manufacturer name (32 ASCII characters max), optional
- prod_name (string): Product name (32 ASCII characters max), optional
- mfrName (string): Manufacturer name (32 ASCII characters max), optional
- prodName (string): Product name (32 ASCII characters max), optional
- layoutPath (string): Path to keyboard layout file, optional
**Examples**
```js
@@ -21,7 +22,7 @@ badusb.setup();
// Start USB HID with custom vid:pid = AAAA:BBBB, manufacturer and product strings not defined
badusb.setup({ vid: 0xAAAA, pid: 0xBBBB });
// Start USB HID with custom vid:pid = AAAA:BBBB, manufacturer string = "Flipper Devices", product string = "Flipper Zero"
badusb.setup({ vid: 0xAAAA, pid: 0xBBBB, mfr_name: "Flipper Devices", prod_name: "Flipper Zero" });
badusb.setup({ vid: 0xAAAA, pid: 0xBBBB, mfrName: "Flipper Devices", prodName: "Flipper Zero" });
```
<br>
@@ -122,6 +123,45 @@ badusb.println("Hello, world!"); // print "Hello, world!" and press "ENTER"
```
<br>
## altPrint()
Prints a string by Alt+Numpad method - works only on Windows!
**Parameters**
- A string to print
- *(optional)* delay between key presses
**Examples**
```js
badusb.altPrint("Hello, world!"); // print "Hello, world!"
badusb.altPrint("Hello, world!", 100); // Add 100ms delay between key presses
```
<br>
## altPrintln()
Same as `altPrint` but ended with "ENTER" press.
**Parameters**
- A string to print
- *(optional)* delay between key presses
**Examples**
```js
badusb.altPrintln("Hello, world!"); // print "Hello, world!" and press "ENTER"
```
<br>
## quit()
Releases usb, optional, but allows to interchange with usbdisk.
**Examples**
```js
badusb.quit();
usbdisk.start(...)
```
<br>
# Key names list {#js_badusb_keynames}
## Modifier keys
@@ -159,3 +199,4 @@ badusb.println("Hello, world!"); // print "Hello, world!" and press "ENTER"
| TAB | |
| MENU | Context menu key |
| Fx | F1-F24 keys |
| NUMx | NUM0-NUM9 keys |

View File

@@ -39,28 +39,277 @@ print("string1", "string2", 123);
```
<br>
## console.log()
<br>
## console.warn()
<br>
## console.error()
<br>
## console.debug()
## Console object
Same as `print`, but output to serial console only, with corresponding log level.
### console.log()
<br>
## to_string()
### console.warn()
<br>
### console.error()
<br>
### console.debug()
<br>
## load()
Runs a JS file and returns value from it.
**Parameters**
- The path to the file
- An optional object to use as the global scope while running this file
**Examples**
```js
load("/ext/apps/Scripts/script.js");
```
<br>
## chr()
Convert an ASCII character number to string.
**Examples**
```js
chr(65); // "A"
```
<br>
## die()
Exit JavaScript with given message.
**Examples**
```js
die("Some error occurred");
```
<br>
## parseInt()
Convert a string to number with an optional base.
**Examples**
```js
parseInt("123"); // 123
parseInt("7b", 16); // 123
```
<br>
## Number object
### Number.toString()
Convert a number to string with an optional base.
**Examples**
```js
to_string(123) // "123"
to_string(123, 16) // "0x7b"
let num = 123;
num.toString(); // "123"
num.toString(16); // "0x7b"
```
<br>
## ArrayBuffer object
**Fields**
- byteLength: The length of the buffer in bytes
<br>
### ArrayBuffer.slice()
Creates an `ArrayBuffer` that contains a sub-part of the buffer.
**Parameters**
- The index to start the new buffer at
- An optional non-inclusive index of where to stop the new buffer
**Examples**
```js
Uint8Array([1, 2, 3]).buffer.slice(0, 1) // ArrayBuffer([1])
```
<br>
## DataView objects
Wrappers around `ArrayBuffer` objects, with dedicated types such as:
- `Uint8Array`
- `Int8Array`
- `Uint16Array`
- `Int16Array`
- `Uint32Array`
- `Int32Array`
**Fields**
- byteLength: The length of the buffer in bytes
- length: The length of the buffer in typed elements
- buffer: The underlying `ArrayBuffer`
<br>
## Array object
**Fields**
- length: How many elements there are in the array
<br>
### Array.splice()
Removes elements from the array and returns them in a new array.
**Parameters**
- The index to start taking elements from
- An optional count of how many elements to take
**Examples**
```js
let arr = [1, 2, 3];
arr.splice(1); // [2, 3]
arr; // [1]
```
<br>
### Array.push()
Adds a value to the end of the array.
**Examples**
```js
let arr = [1, 2];
arr.push(3);
arr; // [1, 2, 3]
```
<br>
## String object
**Fields**
- length: How many characters there are in the string
<br>
### String.charCodeAt()
Returns the character code at an index in the string.
**Examples**
```js
"A".charCodeAt(0) // 65
```
<br>
### String.at()
Same as `String.charCodeAt()`.
<br>
### String.indexOf()
Return index of first occurrence of substr within the string or `-1` if not found.
**Parameters**
- Substring to search for
- Optional index to start searching from
**Examples**
```js
"Example".indexOf("amp") // 2
```
<br>
### String.slice()
Return a substring between two indices.
**Parameters**
- The index to start the new string at
- An optional non-inclusive index of where to stop the new string
**Examples**
```js
"Example".slice(2) // "ample"
```
<br>
### String.toUpperCase()
Transforms the string to upper case.
**Examples**
```js
"Example".toUpperCase() // "EXAMPLE"
```
<br>
### String.toLowerCase()
Transforms the string to lower case.
**Examples**
```js
"Example".toLowerCase() // "example"
```
<br>
## __dirname
Path to the directory containing the current script.
**Examples**
```js
print(__dirname); // /ext/apps/Scripts
```
<br>
## __filename
Path to the current script file.
**Examples**
```js
print(__filename); // /ext/apps/Scripts/path.js
```
<br>
# SDK compatibility methods {#js_builtin_sdk_compatibility}
## sdkCompatibilityStatus()
Checks compatibility between the script and the JS SDK that the firmware provides.
**Returns**
- `"compatible"` if the script and the JS SDK are compatible
- `"firmwareTooOld"` if the expected major version is larger than the version of the firmware, or if the expected minor version is larger than the version of the firmware
- `"firmwareTooNew"` if the expected major version is lower than the version of the firmware
**Examples**
```js
sdkCompatibilityStatus(0, 3); // "compatible"
```
<br>
## isSdkCompatible()
Checks compatibility between the script and the JS SDK that the firmware provides in a boolean fashion.
**Examples**
```js
isSdkCompatible(0, 3); // true
```
<br>
## checkSdkCompatibility()
Asks the user whether to continue executing the script if the versions are not compatible. Does nothing if they are.
**Examples**
```js
checkSdkCompatibility(0, 3);
```
<br>
## doesSdkSupport()
Checks whether all of the specified extra features are supported by the interpreter.
**Examples**
```js
doesSdkSupport(["gui-widget"]); // true
```
<br>
## checkSdkFeatures()
Checks whether all of the specified extra features are supported by the interpreter, asking the user if they want to continue running the script if they're not.
**Examples**
```js
checkSdkFeatures(["gui-widget"]);
```

View File

@@ -7,7 +7,7 @@ Here is a list of common data types used by mJS.
- foreign — C function or data pointer
- undefined
- null
- object — a data structure with named fields
- array — special type of object, all items have indexes and equal types
- Object — a data structure with named fields
- Array — special type of object, all items have indexes and equal types
- ArrayBuffer — raw data buffer
- DataView — provides interface for accessing ArrayBuffer contents

View File

@@ -70,6 +70,27 @@ The JS minifier reduces the size of JavaScript files by removing unnecessary cha
However, it has a drawback — it can make debugging harder, as error messages in minified files are harder to read in larger applications. For this reason, it's recommended to disable the JS minifier during debugging and it's disabled by default. To enable it, set the `minify` parameter to `true` in the `fz-sdk.config.json5` file in your app folder. This will minify your JavaScript app before loading it onto Flipper Zero.
## Differences with normal Flipper JavaScript
With the Flipper JavaScript SDK, you will be developing in **TypeScript**. This means that you get a better development experience, with more accurate code completion and warnings when variable types are incompatible, but it also means your code will be different from basic Flipper JS.
Some things to look out for:
- Importing modules:
- Instead of `let module = require("module");`
- You will use `import * as module from "@flipperdevices/fz-sdk/module";`
- Multiple source code files:
- The Flipper JavaScript SDK does not yet support having multiple `.ts` files and importing them
- You can use `load()`, but this will not benefit from TypeScript type checking
- Casting values:
- Some Flipper JavaScript functions will return generic types
- For example `eventLoop.subscribe()` will run your callback with a generic `Item` type
- In some cases you might need to cast these values before using them, you can do this by:
- Inline casting: `<string>item`
- Declare with new type: `let text = item as string;`
When you upload the script to Flipper with `npm start`, it gets transpiled to normal JavaScript and optionally minified (see below). If you're looking to share your script with others, this is what you should give them to run.
## What's next?
You've learned how to run and debug simple JavaScript apps. But how can you access Flipper Zero's hardware from your JS code? For that, you'll need to use JS modules — which we'll cover in the next guide.

View File

@@ -0,0 +1,52 @@
# Flipper module {#js_flipper}
The module contains methods and values to query device information and properties. Call the `require` function to load the module before first using its methods:
```js
let flipper = require("flipper");
```
# Values
## firmwareVendor
String representing the firmware installed on the device.
Original firmware reports `"flipperdevices"`.
Do **NOT** use this to check the presence or absence of features, refer to [other ways to check SDK compatibility](#js_builtin_sdk_compatibility).
## jsSdkVersion
Version of the JavaScript SDK.
Do **NOT** use this to check the presence or absence of features, refer to [other ways to check SDK compatibility](#js_builtin_sdk_compatibility).
<br>
---
# Methods
## getModel()
Returns the device model.
**Example**
```js
flipper.getModel(); // "Flipper Zero"
```
<br>
## getName()
Returns the name of the virtual dolphin.
**Example**
```js
flipper.getName(); // "Fur1pp44"
```
<br>
## getBatteryCharge()
Returns the battery charge percentage.
**Example**
```js
flipper.getBatteryCharge(); // 100
```

View File

@@ -24,7 +24,7 @@ delay(1000);
---
# API reference
## get
## get()
Gets a `Pin` object that can be used to manage a pin.
**Parameters**
@@ -89,3 +89,33 @@ Attaches an interrupt to a pin configured with `direction: "in"` and
An event loop `Contract` object that identifies the interrupt event source. The
event does not produce any extra data.
### Pin.isPwmSupported()
Determines whether this pin supports PWM.
If `false`, all other PWM-related methods on this pin will throw an error when called.
**Returns**
Boolean value.
### Pin.pwmWrite()
Sets PWM parameters and starts the PWM.
Configures the pin with `{ direction: "out", outMode: "push_pull" }`.
Throws an error if PWM is not supported on this pin.
**Parameters**
- `freq`: Frequency in Hz
- `duty`: Duty cycle in %
### Pin.isPwmRunning()
Determines whether PWM is running.
Throws an error if PWM is not supported on this pin.
**Returns**
Boolean value.
### Pin.pwmStop()
Stops PWM.
Does not restore previous pin configuration.
Throws an error if PWM is not supported on this pin.

View File

@@ -173,6 +173,11 @@ triggered when the back key is pressed.
<br>
### viewDispatcher.currentView
The `View` object currently being shown.
<br>
## ViewFactory
When you import a module implementing a view, a `ViewFactory` is instantiated. For example, in the example above, `loadingView`, `submenuView` and `emptyView` are view factories.
@@ -183,8 +188,40 @@ Creates an instance of a `View`.
<br>
### ViewFactory.make(props)
Creates an instance of a `View` and assigns initial properties from `props`.
### ViewFactory.makeWith(props, children)
Creates an instance of a `View` and assigns initial properties from `props` and optionally a list of children.
**Parameters**
- `props`: simple key-value object, e.g. `{ header: "Header" }`
- `children`: optional array of children, e.g. `[ { element: "button", button: "right", text: "Back" } ]`
## View
When you call `ViewFactory.make()` or `ViewFactory.makeWith()`, a `View` is instantiated. For example, in the example above, `views.loading`, `views.demos` and `views.empty` are views.
<br>
### View.set(property, value)
Assign value to property by name.
**Parameters**
- `property`: name of the property to change
- `value`: value to assign to the property
<br>
### View.addChild(child)
Adds a child to the `View`.
**Parameters**
- `child`: the child to add, e.g. `{ element: "button", button: "right", text: "Back" }`
The format of the `child` parameter depends on the type of View that you're working with. Look in the View documentation.
### View.resetChildren()
Removes all children from the `View`.
### View.setChildren(children)
Removes all previous children from the `View` and assigns new children.
**Parameters**
- `children`: the array of new children, e.g. `[ { element: "button", button: "right", text: "Back" } ]`

View File

@@ -0,0 +1,32 @@
# Byte input GUI view {#js_gui__byte_input}
Displays a hexadecimal keyboard.
<img src="byte_input.png" width="200" alt="Sample screenshot of the view" />
```js
let eventLoop = require("event_loop");
let gui = require("gui");
let byteInputView = require("gui/byte_input");
```
This module depends on the `gui` module, which in turn depends on the
`event_loop` module, so they **must** be imported in this order. It is also
recommended to conceptualize these modules first before using this one.
## Example
For an example refer to the `gui.js` example script.
## View props
| Prop | Type | Description |
|-------------|--------|--------------------------------------------------|
| `length` | `number` | The length in bytes of the buffer to modify. |
| `header` | `string` | A single line of text that appears above the keyboard. |
| `defaultData` | `string` | Data to show by default. |
## View events
| Item | Type | Description |
|-------------|--------|--------------------------------------------------|
| `input` | `ArrayBuffer` | Fires when the user selects the "Save" button. |

View File

@@ -0,0 +1,20 @@
# File Picker GUI prompt {#js_gui__file_picker}
Allows asking the user to select a file.
It is not GUI view like other JS GUI views, rather just a function that shows a prompt.
# Example
For an example, refer to the `gui.js` example script.
# API reference
## pickFile()
Displays a file picker and returns the selected file, or undefined if cancelled.
**Parameters**
- `basePath`: the path to start at
- `extension`: the file extension(s) to show (like `.sub`, `.iso|.img`, `*`)
**Returns**
A `string` path, or `undefined`.

View File

@@ -0,0 +1,32 @@
# GUI Icons {#js_gui__icon}
Retrieves and loads icons for use with GUI views such as [Dialog](#js_gui__dialog).
# Example
For an example, refer to the `gui.js` example script.
# API reference
## getBuiltin()
Gets a built-in firmware icon by its name.
Not all icons are supported, currently only `"DolphinWait_59x54"` and `"js_script_10px"` are available.
**Parameters**
- `icon`: name of the icon
**Returns**
An `IconData` object.
<br>
## loadFxbm()
Loads a `.fxbm` icon (XBM Flipper sprite, from `flipperzero-game-engine`) from file.
It will be automatically unloaded when the script exits.
**Parameters**
- `path`: path to the `.fxbm` file
**Returns**
An `IconData` object.

View File

@@ -21,4 +21,6 @@ For an example, refer to the `gui.js` example script.
| Prop | Type | Description |
|----------|---------|------------------------------------|
| `text` | `string`| Text to show in the text box. |
| `text` | `string`| Text to show in the text box. |
| `font` | `string`| The font to display the text in (`"text"` or `"hex"`). |
| `focus` | `string`| The initial focus of the text box (`"start"` or `"end"`). |

View File

@@ -21,9 +21,11 @@ For an example, refer to the `gui.js` example script.
| Prop | Type | Description |
|-------------|--------|--------------------------------------------------|
| `minLength` | `number` | The shortest allowed text length. |
| `maxLength` | `number` | The longest allowed text length. <br> Default: `32` |
| `header` | `string` | A single line of text that appears above the keyboard. |
| `minLength` | `number` | The shortest allowed text length. |
| `maxLength` | `number` | The longest allowed text length. <br> Default: `32` |
| `header` | `string` | A single line of text that appears above the keyboard. |
| `defaultText` | `string` | Text to show by default. |
| `defaultTextClear` | `boolean` | Whether to clear the default text on next character typed. |
## View events

View File

@@ -22,3 +22,16 @@ This view does not have any props.
## Children
This view has the elements as its children.
Elements are objects with properties to define them, in the form `{ element: "type", ...properties }` (e.g. `{ element: "button", button: "right", text: "Back" }`).
| **Element Type** | **Properties** | **Description** |
|------------------|----------------|------------------------------------------------|
| `string_multiline` | `x` (number), `y` (number) <br> `align` ((`"t"`, `"c"`, `"b"`) + (`"l"`, `"m"`, `"r"`)) <br> `font` (`"primary"`, `"secondary"`, `"keyboard"`, `"big_numbers"`) <br> `text` (string) | String of text that can span multiple lines. |
| `string` | `x` (number), `y` (number) <br> `align` ((`"t"`, `"c"`, `"b"`) + (`"l"`, `"m"`, `"r"`)) <br> `font` (`"primary"`, `"secondary"`, `"keyboard"`, `"big_numbers"`) <br> `text` (string) | String of text. |
| `text_box` | `x` (number), `y` (number) <br> `w` (number), `h` (number) <br> `align` ((`"t"`, `"c"`, `"b"`) + (`"l"`, `"m"`, `"r"`)) <br> `text` (string) <br> `stripToDots` (boolean) | Box of with text that can be scrolled vertically. |
| `text_scroll` | `x` (number), `y` (number) <br> `w` (number), `h` (number) <br> `text` (string) | Text that can be scrolled vertically. |
| `button` | `text` (string) <br> `button` (`"left"`, `"center"`, `"right"`) | Button at the bottom of the screen. |
| `icon` | `x` (number), `y` (number) <br> `iconData` ([IconData](#js_gui__icon)) | Display an icon. |
| `rect` | `x` (number), `y` (number) <br> `w` (number), `h` (number) <br> `radius` (number), `fill` (boolean) | Draw a rectangle, optionally rounded and filled. |
| `circle` | `x` (number), `y` (number) <br> `radius` (number), `fill` (boolean) | Draw a circle, optionally filled. |
| `line` | `x1` (number), `y1` (number) <br> `x2` (number), `y2` (number) | Draw a line between 2 points. |

View File

@@ -271,13 +271,29 @@ math.floor(45.95); // 45
<br>
## log()
Return the natural logarithm of x.
**Parameters**
- x: A number
**Returns**
The natural logarithm of `x`, as in `ln(x)` where `e` is the base of the natural logarithm.
**Example**
```js
math.log(1); // 0
math.log(3); // 1.0986122886681098
```
## isEqual()
Return true if the difference between numbers `a` and `b` is less than the specified parameter `e`.
Return true if the difference between numbers `a` and `b` is less than the specified `tolerance`.
**Parameters**
- a: A number a
- b: A number b
- e: An epsilon parameter
- tolerance: How much difference is allowed between the numbers to be considered equal
**Returns**

View File

@@ -10,8 +10,15 @@ Configure serial port. Should be called before all other methods.
**Parameters**
- Serial port name (usart, lpuart)
- Serial port name (`"usart"`, `"lpuart"`)
- Baudrate
- Optional framing configuration object (e.g. `{ dataBits: "8", parity: "even", stopBits: "1" }`):
- `dataBits`: `"6"`, `"7"`, `"8"`, `"9"`
- 6 data bits can only be selected when parity is enabled (even or odd)
- 9 data bits can only be selected when parity is disabled (none)
- `parity`: `"none"`, `"even"`, `"odd"`
- `stopBits`: `"0.5"`, `"1"`, `"1.5"`, `"2"`
- LPUART only supports whole stop bit lengths (i.e. 1 and 2 but not 0.5 and 1.5)
**Example**
@@ -69,7 +76,7 @@ Read from serial port until line break character.
**Parameters**
*(optional)* Timeout value in ms.
- *(optional)* Timeout value in ms.
**Returns**
@@ -84,6 +91,26 @@ serial.readln(5000); // Read with 5s timeout
<br>
## readAny()
Read any available amount of data from serial port, can help avoid starving your loop with small reads.
**Parameters**
- *(optional)* Timeout value in ms
**Returns**
A sting of received characters or undefined if nothing was received before timeout.
**Example**
```js
serial.readAny(); // Read without timeout
serial.readAny(5000); // Read with 5s timeout
```
<br>
## readBytes()
Read from serial port until line break character.
@@ -125,8 +152,21 @@ Index of matched pattern in input patterns list, undefined if nothing was found.
```js
// Wait for root shell prompt with 1s timeout, returns 0 if it was received before timeout, undefined if not
serial.expect("# ", 1000);
serial.expect("# ", 1000);
// Infinitely wait for one of two strings, should return 0 if the first string got matched, 1 if the second one
serial.expect([": not found", "Usage: "]);
```
<br>
## end()
Deinitializes serial port, allowing multiple initializations per script run.
**Example**
```js
serial.end();
// Configure LPUART port with baudrate = 115200
serial.setup("lpuart", 115200);
```

View File

@@ -52,7 +52,7 @@ File information structure.
## File
This class implements methods for working with file. To get an object of the File class, use the `OpenFile` method.
This class implements methods for working with file. To get an object of the File class, use the `openFile` method.
<br>
@@ -186,6 +186,36 @@ Copies bytes from the R/W pointer in the current file to the R/W pointer in anot
# Methods
## openFile()
Opens a file.
**Parameters**
- path: The path to the file
- accessMode: How to access the file (`"r"`, `"w"` or `"rw"`)
- openMode: How to open the file (`"open_existing"`, `"open_always"`, `"open_append"`, `"create_new"` or `"create_always"`)
**Returns**
A `File` object on success, `undefined` otherwise.
<br>
## fileExists()
Detects whether a file exists.
**Parameters**
- path: The path to the file
**Returns**
`true` if file exists, `false` otherwise.
<br>
## arePathsEqual()
Determines whether the two paths are equivalent. Respects filesystem-defined path equivalence rules.