-
-
Notifications
You must be signed in to change notification settings - Fork 213
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from Spooks4576/dev
JS: Add BLE Beacon, Keyboard, Math modules
- Loading branch information
Showing
9 changed files
with
867 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
applications/system/js_app/examples/apps/Scripts/blebeacon.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
let blebeacon = require("blebeacon"); | ||
let math = require("math"); | ||
|
||
let currentIndex = 0; | ||
let watchValues = [ | ||
0x1A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, | ||
0x09, 0x0A, 0x0B, 0x0C, 0x11, 0x12, 0x13, 0x14, 0x15, | ||
0x16, 0x17, 0x18, 0xE4, 0xE5, 0x1B, 0x1C, 0x1D, 0x1E, | ||
0x20, 0xEC, 0xEF | ||
]; | ||
|
||
function generateRandomMac() { | ||
let mac = []; | ||
for (let i = 0; i < 6; i++) { | ||
mac.push(math.floor(math.random() * 256)); | ||
} | ||
return Uint8Array(mac); | ||
} | ||
|
||
function sendRandomModelAdvertisement() { | ||
let model = watchValues[currentIndex]; | ||
|
||
let packet = [ | ||
14, 0xFF, 0x75, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0xFF, 0x00, 0x00, 0x43, | ||
model | ||
]; | ||
|
||
let intervalMs = 50; | ||
|
||
// Power level, min interval and max interval are optional | ||
blebeacon.setConfig(generateRandomMac(), 0x1F, intervalMs, intervalMs * 3); | ||
|
||
blebeacon.setData(Uint8Array(packet)); | ||
|
||
blebeacon.start(); | ||
|
||
print("Sent data for model ID " + to_string(model)); | ||
|
||
currentIndex = (currentIndex + 1) % watchValues.length; | ||
|
||
delay(intervalMs); | ||
|
||
blebeacon.stop(); | ||
} | ||
|
||
// Make sure it resets at script exit, true will keep advertising in background | ||
blebeacon.keepAlive(true); | ||
|
||
while (true) { | ||
sendRandomModelAdvertisement(); | ||
} |
19 changes: 19 additions & 0 deletions
19
applications/system/js_app/examples/apps/Scripts/keyboard.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
let keyboard = require("keyboard"); | ||
|
||
keyboard.setHeader("Example Text Input"); | ||
|
||
// Default text is optional | ||
let text = keyboard.text(100, "Default text", true); | ||
print("Got text:", text); | ||
|
||
keyboard.setHeader("Example Byte Input"); | ||
|
||
// Default data is optional | ||
let data = keyboard.byte(6, Uint8Array([1, 2, 3, 4, 5, 6])); | ||
data = Uint8Array(data); | ||
let result = "0x"; | ||
for (let i = 0; i < data.byteLength; i++) { | ||
if (data[i] < 0x10) result += "0"; | ||
result += to_hex_string(data[i]); | ||
} | ||
print("Got data:", result); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
let math = require("math"); | ||
|
||
let absResult = math.abs(-5); | ||
let acosResult = math.acos(0.5); | ||
let acoshResult = math.acosh(2); | ||
let asinResult = math.asin(0.5); | ||
let asinhResult = math.asinh(2); | ||
let atanResult = math.atan(1); | ||
let atan2Result = math.atan2(1, 1); | ||
let atanhResult = math.atanh(0.5); | ||
let cbrtResult = math.cbrt(27); | ||
let ceilResult = math.ceil(5.3); | ||
let clz32Result = math.clz32(1); | ||
let cosResult = math.cos(math.PI); | ||
let expResult = math.exp(1); | ||
let floorResult = math.floor(5.7); | ||
let maxResult = math.max(3, 5); | ||
let minResult = math.min(3, 5); | ||
let powResult = math.pow(2, 3); | ||
let randomResult = math.random(); | ||
let signResult = math.sign(-5); | ||
let sinResult = math.sin(math.PI / 2); | ||
let sqrtResult = math.sqrt(25); | ||
let truncResult = math.trunc(5.7); | ||
|
||
print("math.abs(-5):", absResult); | ||
print("math.acos(0.5):", acosResult); | ||
print("math.acosh(2):", acoshResult); | ||
print("math.asin(0.5):", asinResult); | ||
print("math.asinh(2):", asinhResult); | ||
print("math.atan(1):", atanResult); | ||
print("math.atan2(1, 1):", atan2Result); | ||
print("math.atanh(0.5):", atanhResult); | ||
print("math.cbrt(27):", cbrtResult); | ||
print("math.ceil(5.3):", ceilResult); | ||
print("math.clz32(1):", clz32Result); | ||
print("math.cos(math.PI):", cosResult); | ||
print("math.exp(1):", expResult); | ||
print("math.floor(5.7):", floorResult); | ||
print("math.max(3, 5):", maxResult); | ||
print("math.min(3, 5):", minResult); | ||
print("math.pow(2, 3):", powResult); | ||
print("math.random():", randomResult); | ||
print("math.sign(-5):", signResult); | ||
print("math.sin(math.PI/2):", sinResult); | ||
print("math.sqrt(25):", sqrtResult); | ||
print("math.trunc(5.7):", truncResult); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
#include "../js_modules.h" | ||
#include <furi_hal_bt.h> | ||
#include <extra_beacon.h> | ||
|
||
typedef struct { | ||
bool saved_prev_cfg; | ||
bool prev_cfg_set; | ||
GapExtraBeaconConfig prev_cfg; | ||
|
||
bool saved_prev_data; | ||
uint8_t prev_data[EXTRA_BEACON_MAX_DATA_SIZE]; | ||
uint8_t prev_data_len; | ||
|
||
bool saved_prev_active; | ||
bool prev_active; | ||
|
||
bool keep_alive; | ||
} JsBlebeaconInst; | ||
|
||
static JsBlebeaconInst* get_this_ctx(struct mjs* mjs) { | ||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0); | ||
JsBlebeaconInst* storage = mjs_get_ptr(mjs, obj_inst); | ||
furi_assert(storage); | ||
return storage; | ||
} | ||
|
||
static void ret_bad_args(struct mjs* mjs, const char* error) { | ||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "%s", error); | ||
mjs_return(mjs, MJS_UNDEFINED); | ||
} | ||
|
||
static bool check_arg_count(struct mjs* mjs, size_t count) { | ||
size_t num_args = mjs_nargs(mjs); | ||
if(num_args != count) { | ||
ret_bad_args(mjs, "Wrong argument count"); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
static bool get_int_arg(struct mjs* mjs, size_t index, uint8_t* value, bool error) { | ||
mjs_val_t int_obj = mjs_arg(mjs, index); | ||
if(!mjs_is_number(int_obj)) { | ||
if(error) ret_bad_args(mjs, "Argument must be a number"); | ||
return false; | ||
} | ||
*value = mjs_get_int(mjs, int_obj); | ||
return true; | ||
} | ||
|
||
static void js_blebeacon_set_config(struct mjs* mjs) { | ||
JsBlebeaconInst* blebeacon = get_this_ctx(mjs); | ||
if(mjs_nargs(mjs) < 1 || mjs_nargs(mjs) > 4) { | ||
ret_bad_args(mjs, "Wrong argument count"); | ||
return; | ||
} | ||
|
||
char* mac = NULL; | ||
size_t mac_len = 0; | ||
mjs_val_t mac_arg = mjs_arg(mjs, 0); | ||
if(mjs_is_typed_array(mac_arg)) { | ||
if(mjs_is_data_view(mac_arg)) { | ||
mac_arg = mjs_dataview_get_buf(mjs, mac_arg); | ||
} | ||
mac = mjs_array_buf_get_ptr(mjs, mac_arg, &mac_len); | ||
} | ||
if(!mac || mac_len != EXTRA_BEACON_MAC_ADDR_SIZE) { | ||
ret_bad_args(mjs, "Wrong MAC address"); | ||
return; | ||
} | ||
|
||
uint8_t power = GapAdvPowerLevel_0dBm; | ||
get_int_arg(mjs, 1, &power, false); | ||
power = CLAMP(power, GapAdvPowerLevel_6dBm, GapAdvPowerLevel_Neg40dBm); | ||
|
||
uint8_t intv_min = 50; | ||
get_int_arg(mjs, 2, &intv_min, false); | ||
intv_min = MAX(intv_min, 20); | ||
|
||
uint8_t intv_max = 150; | ||
get_int_arg(mjs, 3, &intv_max, false); | ||
intv_max = MAX(intv_max, intv_min); | ||
|
||
GapExtraBeaconConfig config = { | ||
.min_adv_interval_ms = intv_min, | ||
.max_adv_interval_ms = intv_max, | ||
.adv_channel_map = GapAdvChannelMapAll, | ||
.adv_power_level = power, | ||
.address_type = GapAddressTypePublic, | ||
}; | ||
memcpy(config.address, (uint8_t*)mac, sizeof(config.address)); | ||
|
||
if(!blebeacon->saved_prev_cfg) { | ||
blebeacon->saved_prev_cfg = true; | ||
const GapExtraBeaconConfig* prev_cfg_ptr = furi_hal_bt_extra_beacon_get_config(); | ||
if(prev_cfg_ptr) { | ||
blebeacon->prev_cfg_set = true; | ||
memcpy(&blebeacon->prev_cfg, prev_cfg_ptr, sizeof(blebeacon->prev_cfg)); | ||
} else { | ||
blebeacon->prev_cfg_set = false; | ||
} | ||
} | ||
furi_check(furi_hal_bt_extra_beacon_set_config(&config)); | ||
} | ||
|
||
static void js_blebeacon_set_data(struct mjs* mjs) { | ||
JsBlebeaconInst* blebeacon = get_this_ctx(mjs); | ||
if(!check_arg_count(mjs, 1)) return; | ||
|
||
char* data = NULL; | ||
size_t data_len = 0; | ||
mjs_val_t data_arg = mjs_arg(mjs, 0); | ||
if(mjs_is_typed_array(data_arg)) { | ||
if(mjs_is_data_view(data_arg)) { | ||
data_arg = mjs_dataview_get_buf(mjs, data_arg); | ||
} | ||
data = mjs_array_buf_get_ptr(mjs, data_arg, &data_len); | ||
} | ||
if(!data) { | ||
ret_bad_args(mjs, "Data must be a Uint8Array"); | ||
return; | ||
} | ||
|
||
if(!blebeacon->saved_prev_data) { | ||
blebeacon->saved_prev_data = true; | ||
blebeacon->prev_data_len = furi_hal_bt_extra_beacon_get_data(blebeacon->prev_data); | ||
} | ||
furi_check(furi_hal_bt_extra_beacon_set_data((uint8_t*)data, data_len)); | ||
|
||
mjs_return(mjs, MJS_UNDEFINED); | ||
} | ||
|
||
static void js_blebeacon_start(struct mjs* mjs) { | ||
JsBlebeaconInst* blebeacon = get_this_ctx(mjs); | ||
if(!check_arg_count(mjs, 0)) return; | ||
|
||
if(!blebeacon->saved_prev_active) { | ||
blebeacon->saved_prev_active = true; | ||
blebeacon->prev_active = furi_hal_bt_extra_beacon_is_active(); | ||
} | ||
furi_check(furi_hal_bt_extra_beacon_start()); | ||
|
||
mjs_return(mjs, MJS_UNDEFINED); | ||
} | ||
|
||
static void js_blebeacon_stop(struct mjs* mjs) { | ||
JsBlebeaconInst* blebeacon = get_this_ctx(mjs); | ||
if(!check_arg_count(mjs, 0)) return; | ||
UNUSED(blebeacon); | ||
|
||
furi_hal_bt_extra_beacon_stop(); | ||
|
||
mjs_return(mjs, MJS_UNDEFINED); | ||
} | ||
|
||
static void js_blebeacon_keep_alive(struct mjs* mjs) { | ||
JsBlebeaconInst* blebeacon = get_this_ctx(mjs); | ||
if(!check_arg_count(mjs, 1)) return; | ||
|
||
mjs_val_t bool_obj = mjs_arg(mjs, 0); | ||
blebeacon->keep_alive = mjs_get_bool(mjs, bool_obj); | ||
|
||
mjs_return(mjs, MJS_UNDEFINED); | ||
} | ||
|
||
static void* js_blebeacon_create(struct mjs* mjs, mjs_val_t* object) { | ||
JsBlebeaconInst* blebeacon = malloc(sizeof(JsBlebeaconInst)); | ||
mjs_val_t blebeacon_obj = mjs_mk_object(mjs); | ||
mjs_set(mjs, blebeacon_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, blebeacon)); | ||
mjs_set(mjs, blebeacon_obj, "setConfig", ~0, MJS_MK_FN(js_blebeacon_set_config)); | ||
mjs_set(mjs, blebeacon_obj, "setData", ~0, MJS_MK_FN(js_blebeacon_set_data)); | ||
mjs_set(mjs, blebeacon_obj, "start", ~0, MJS_MK_FN(js_blebeacon_start)); | ||
mjs_set(mjs, blebeacon_obj, "stop", ~0, MJS_MK_FN(js_blebeacon_stop)); | ||
mjs_set(mjs, blebeacon_obj, "keepAlive", ~0, MJS_MK_FN(js_blebeacon_keep_alive)); | ||
*object = blebeacon_obj; | ||
return blebeacon; | ||
} | ||
|
||
static void js_blebeacon_destroy(void* inst) { | ||
JsBlebeaconInst* blebeacon = inst; | ||
if(!blebeacon->keep_alive) { | ||
if(furi_hal_bt_extra_beacon_is_active()) { | ||
furi_hal_bt_extra_beacon_stop(); | ||
} | ||
if(blebeacon->saved_prev_cfg && blebeacon->prev_cfg_set) { | ||
furi_check(furi_hal_bt_extra_beacon_set_config(&blebeacon->prev_cfg)); | ||
} | ||
if(blebeacon->saved_prev_data) { | ||
furi_check( | ||
furi_hal_bt_extra_beacon_set_data(blebeacon->prev_data, blebeacon->prev_data_len)); | ||
} | ||
if(blebeacon->prev_active) { | ||
furi_check(furi_hal_bt_extra_beacon_start()); | ||
} | ||
} | ||
free(blebeacon); | ||
} | ||
|
||
static const JsModuleDescriptor js_blebeacon_desc = { | ||
"blebeacon", | ||
js_blebeacon_create, | ||
js_blebeacon_destroy, | ||
}; | ||
|
||
static const FlipperAppPluginDescriptor plugin_descriptor = { | ||
.appid = PLUGIN_APP_ID, | ||
.ep_api_version = PLUGIN_API_VERSION, | ||
.entry_point = &js_blebeacon_desc, | ||
}; | ||
|
||
const FlipperAppPluginDescriptor* js_blebeacon_ep(void) { | ||
return &plugin_descriptor; | ||
} |
Oops, something went wrong.